I have developed a Java application. The application connects to an android device programmatically to transfer some files to connects Android devices.
In my application I have added the adb PATH so it can use it to connect to devices.
I was wondering if its possible to maybe package it within the application ? or just copying the adb into the application directory ? Because I want who ever to download this application, wouldn't need to also have download the adb or Android sdk for the application to work
Is it possible ?
After doing some research you can package an exe within a jar file but you have to extract the exe each run of the application. Following TofuBear's example here I was able to encapsulate adb within a jar file. You'll need to include the AdbWinApi.dll (or equivalent linux libraries).
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
public class Sandbox
{
public static void main(final String[] args)
throws URISyntaxException,
ZipException,
IOException
{
final URI uri;
final URI exe;
uri = getJarURI();
// Extract the adb application
exe = getFile(uri, "adb.exe");
// Extract the AdbWinApi dll file.
getFile(uri, "AdbWinApi.dll");
System.out.println(exe);
}
private static URI getJarURI()
throws URISyntaxException
{
final ProtectionDomain domain;
final CodeSource source;
final URL url;
final URI uri;
domain = Sandbox.class.getProtectionDomain();
source = domain.getCodeSource();
url = source.getLocation();
uri = url.toURI();
return (uri);
}
private static URI getFile(final URI where,
final String fileName)
throws ZipException,
IOException
{
final File location;
final URI fileURI;
location = new File(where);
// not in a JAR, just return the path on disk
if(location.isDirectory())
{
fileURI = URI.create(where.toString() + fileName);
}
else
{
final ZipFile zipFile;
zipFile = new ZipFile(location);
try
{
fileURI = extract(zipFile, fileName);
}
finally
{
zipFile.close();
}
}
return (fileURI);
}
private static URI extract(final ZipFile zipFile,
final String fileName)
throws IOException
{
final File tempFile;
final ZipEntry entry;
final InputStream zipStream;
OutputStream fileStream;
//tempFile = File.createTempFile(fileName, Long.toString(System.currentTimeMillis()));
tempFile = new File(System.getProperty("java.io.tmpdir") + File.separator + fileName);
tempFile.deleteOnExit();
entry = zipFile.getEntry(fileName);
if(entry == null)
{
throw new FileNotFoundException("cannot find file: " + fileName + " in archive: " + zipFile.getName());
}
zipStream = zipFile.getInputStream(entry);
fileStream = null;
try
{
final byte[] buf;
int i;
fileStream = new FileOutputStream(tempFile);
buf = new byte[1024];
i = 0;
while((i = zipStream.read(buf)) != -1)
{
fileStream.write(buf, 0, i);
}
}
finally
{
close(zipStream);
close(fileStream);
}
return (tempFile.toURI());
}
private static void close(final Closeable stream)
{
if(stream != null)
{
try
{
stream.close();
}
catch(final IOException ex)
{
ex.printStackTrace();
}
}
}
}
I had to change the file creation from TofuBear's example so that the file name of the exe would not be changed. It's still created in the temporary folder and will be deleted on exit. I left the original code as a comment.
Edit: Seems I got so caught up with the technical possiblity of it I forgot the legal ramifications. It's been stated here by Chris Stratton that the SDK Terms of Service prohibits redistribution of any part of the sdk. Which would include adb.
It should be easier to use the Java-native chimpchat to connect to the device.
Related
I have some Java code that does this (on a Windows 10 laptop with Windows Defender on):
unzip a .zip file into a folder (using a zip stream)
immediately list the folder's contents (using File#list)
There are ten files in the zip, from 100kB to 40MB. Normally only the first two files are listed -- the other 8 are silently lost. I know they actually make it to the directory because I can see them when I navigate to the directory myself.
I know there are better ways to implement this code, but I'm curious: is this expected? Is "write file into folder" and "file is listed when you list folder contents" not atomic on Windows? Is it a quirk of the underlying file system? Does Windows Defender make the file invisible for some period of time after it's written?
I am not facing the issue you mentioned and my code is able to list all the files correctly:
package com.test;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class ZipTest {
private static final int BUFFER_SIZE = 4096;
private static String INPUT_LOCATION = "C:/temp/zip/test.zip";
private static String OUTPUT_LOCATION = "C:/temp/unzip";
public static void main(String[] args) throws IOException {
unzip(INPUT_LOCATION, OUTPUT_LOCATION);
for (String s : new File(OUTPUT_LOCATION).list()) {
System.out.println(s);
}
}
public static void unzip(String zipFilePath, String destDirectory) throws IOException {
File destDir = new File(destDirectory);
if (!destDir.exists()) {
destDir.mkdir();
}
ZipInputStream zipIn = new ZipInputStream(new FileInputStream(zipFilePath));
ZipEntry entry = zipIn.getNextEntry();
while (entry != null) {
String filePath = destDirectory + File.separator + entry.getName();
if (!entry.isDirectory()) {
extractFile(zipIn, filePath);
} else {
File dir = new File(filePath);
dir.mkdir();
}
zipIn.closeEntry();
entry = zipIn.getNextEntry();
}
zipIn.close();
}
private static void extractFile(ZipInputStream zipIn, String filePath) throws IOException {
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath));
byte[] bytesIn = new byte[BUFFER_SIZE];
int read = 0;
while ((read = zipIn.read(bytesIn)) != -1) {
bos.write(bytesIn, 0, read);
}
bos.close();
}
}
I have been having an issue while downloading a file from a Web Ftp through a Java program using Apache Commons Net.
Let's say I want to download this file : webftp.vancouver.ca/opendata/bike_rack/BikeRackData.csv
This is not a file you will be able to download via an HTTP request. I can do it with my browser because I'm using a FTP plugin.
It appears that the traditionnal way to retrieve files from a FTP server doesn't work with that particuliar type (Web FTP). I can establish the connection, but the file retrieval doesn't work as the file is empty.
The code I used (classic way to retrieve a file using Apache Commons) is the following :
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.security.NoSuchAlgorithmException;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory;
public class FTPDownload {
final private FTPClient ftp = new FTPClient();
private String input;
private String server;
private String path;
private String destination;
private String fileName;
public FTPDownload(String input, String destination) {
this.input = input;
this.destination = destination;
if (input != null && input.contains("/")) {
String[] elts = input.split("/");
server = elts[0];
fileName = elts[elts.length - 1];
path = input.substring(server.length() - 1);
} else {
server = input;
path = null;
}
}
public FTPDownload(String server, String path, String destination) {
this.server = server;
this.path = path;
this.destination = destination;
if (path != null && path.contains("/")) {
String[] elts = path.split("/");
fileName = elts[elts.length - 1];
}
}
public boolean retrieveFile() throws IOException {
boolean error = false;
ftp.connect(server);
int reply = ftp.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
ftp.disconnect();
return false;
}
ftp.setFileType(FTP.BINARY_FILE_TYPE);
ftp.enterRemotePassiveMode();
File download = new File(destination + "/" + fileName);
OutputStream outputStream;
outputStream = new FileOutputStream(download);
ftp.changeWorkingDirectory(path.substring(0, path.length() - fileName.length()));
ftp.setParserFactory(new DefaultFTPFileEntryParserFactory());
String[] list = ftp.listNames();
ftp.retrieveFile(fileName, outputStream);
outputStream.close();
ftp.logout();
return error;
}
public static void main(String[] args) throws NoSuchAlgorithmException, IOException {
FTPDownload myFtp = new FTPDownload("webftp.vancouver.ca", "/opendata/bike_rack/BikeRackData.csv", "E:\\test");
myFtp.retrieveFile();
}
}
Hope the problem is understandable.
Thank you.
I have a very different situation to deal with. Something never seen before.
I have a codebase which is not a maven based project. It basically is set of Pig Script that are executed on Hadoop Cluster.
Now there is requirement to test these scripts using PigUnit, so I created a maven based project with all dependencies needed for the project.
Visually it looks like
user_mapper/
src/main/
user.pig
other.pig
test/
pom.xml
src/java/
/UserTest.java
/OtherTest.java
As you could see, test is a maven based project in itself.
What I need
In UserTest.java I want to refer to relative path of user.pig
How can I provide a relative path in UserTest.java?
Try the following code (internally uses commons-io jar)
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
public class FileReader {
Logger logger = Logger.getLogger(FileReader.class.getName());
static String webAppPath;
private static final boolean IS_WINDOWS = System.getProperty( "os.name" ).contains( "indow" );
private InputStream inputStream;
private static FileReader fileReader;
public String getAbsolutePath(Class appClass, String relativePath) {
try {
String parentPath = "";
if (StringUtils.isNotBlank(webAppPath)) {
parentPath = webAppPath;
} else {
parentPath = appClass.getProtectionDomain().getCodeSource().getLocation().getPath();
}
String osAppropriatePath = IS_WINDOWS ? parentPath.substring(1) : parentPath;
String absolutePath = osAppropriatePath + relativePath;
File file = new File(absolutePath);
if (!file.exists()) {
FileUtils.writeStringToFile(file, IOUtils.toString(readFile(relativePath), "UTF-8"));
}
return absolutePath;
} catch (IOException ioe) {
logger.log(Level.SEVERE, null, ioe);
return relativePath;
}
}
public void closeFileReader() {
synchronized (this) {
try {
inputStream.close();
} catch (IOException ex) {
Logger.getLogger(FileReader.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
private FileReader() {
}
public static FileReader getInstance() {
return new FileReader();
}
public static String getWebAppPath() {
return webAppPath;
}
public static void setWebAppPath(String webAppPath) {
FileReader.webAppPath = webAppPath;
}
}
And call the class to get the relative path as follows
FileReader.getInstance().getAbsolutePath(user.pig, "user.pig");
I solved this issue by using java.io.File as
final String filePath = new File("../src/user.pig").getAbsolutePath();
I have a code which runs absolutely fine on emulator but when I run it on Samsung Galaxy Tab, it gives Exception.
I am receiving one compressed zip file from server via socket and than I am extracting these file. If I compress and send two or three text files it runs fine on both i.e. emulator and Galaxy Tab.
But if I compress and send some small image file with text or two image files it gives: >java.util.zip.ZipException: Central Directory Entry not found < on Galaxy Tab but no error on emulator. Zip file size does not exceeds 32 KB and I am sure that file is being received correctly. Here is my uncompressor code
package com.vsi.vremote;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import android.content.Context;
import android.util.Log;
public class UnCompressor {
private static final String TAG = "UnCompressor";
Context context;
public UnCompressor(Context context) {
this.context = context;
}
private final void copyInputStream(InputStream in, OutputStream out)
throws IOException {
byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) >= 0)
out.write(buffer, 0, len);
in.close();
out.close();
}
public final String[] unCompress(String name) {
try {
Log.d(TAG, "Uncompress called");
ZipFile zipFile = new ZipFile(context.getFileStreamPath(name));
Log.d(TAG, "Zip file created");
Enumeration entries = zipFile.entries();
String fileNames[] = new String[zipFile.size()];
int counter = 0;
Log.d(TAG, "Loop strting");
while (entries.hasMoreElements()) {
Log.d(TAG, "Getting next entry");
ZipEntry entry = (ZipEntry) entries.nextElement();
Log.d(TAG, "Extracting file: " + entry.getName());
copyInputStream(
zipFile.getInputStream(entry),
new BufferedOutputStream(context.openFileOutput(
entry.getName(), Context.MODE_PRIVATE)));
fileNames[counter++] = entry.getName();
}
zipFile.close();
return fileNames;
} catch (IOException ioe) {
System.err.println("Unhandled exception:");
ioe.printStackTrace();
return null;
}
}
public final void delete(String fileName) {
context.deleteFile(fileName);
}
}
Note: I just checked it on my HTC WildFire, it is also working on this mobile but galaxy TAB :(
Its only adding those file into a zip file (see screenshow) but i have to make a zip file from those zip file parts. I simply devided my zip file into parts and uploaded on the server. now i want to download these files in the my app and rebuild the zip file into the app.
I am executing an exe through my java program. The path is hardcoded in Java.
I have packaged my the exe in the jar.
But am stuck as I have the path name hardcoded in the Java file, so I am not able to execute my jar as a stand alone program.
Any hints for packaging such jar i.e having an exe inside and able to
run it as a stand alone program?
This will extract the .exe to a local file on the local disk. The file will be deleted when the Java program exists.
import java.io.Closeable;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
public class Main
{
public static void main(final String[] args)
throws URISyntaxException,
ZipException,
IOException
{
final URI uri;
final URI exe;
uri = getJarURI();
exe = getFile(uri, "Main.class");
System.out.println(exe);
}
private static URI getJarURI()
throws URISyntaxException
{
final ProtectionDomain domain;
final CodeSource source;
final URL url;
final URI uri;
domain = Main.class.getProtectionDomain();
source = domain.getCodeSource();
url = source.getLocation();
uri = url.toURI();
return (uri);
}
private static URI getFile(final URI where,
final String fileName)
throws ZipException,
IOException
{
final File location;
final URI fileURI;
location = new File(where);
// not in a JAR, just return the path on disk
if(location.isDirectory())
{
fileURI = URI.create(where.toString() + fileName);
}
else
{
final ZipFile zipFile;
zipFile = new ZipFile(location);
try
{
fileURI = extract(zipFile, fileName);
}
finally
{
zipFile.close();
}
}
return (fileURI);
}
private static URI extract(final ZipFile zipFile,
final String fileName)
throws IOException
{
final File tempFile;
final ZipEntry entry;
final InputStream zipStream;
OutputStream fileStream;
tempFile = File.createTempFile(fileName, Long.toString(System.currentTimeMillis()));
tempFile.deleteOnExit();
entry = zipFile.getEntry(fileName);
if(entry == null)
{
throw new FileNotFoundException("cannot find file: " + fileName + " in archive: " + zipFile.getName());
}
zipStream = zipFile.getInputStream(entry);
fileStream = null;
try
{
final byte[] buf;
int i;
fileStream = new FileOutputStream(tempFile);
buf = new byte[1024];
i = 0;
while((i = zipStream.read(buf)) != -1)
{
fileStream.write(buf, 0, i);
}
}
finally
{
close(zipStream);
close(fileStream);
}
return (tempFile.toURI());
}
private static void close(final Closeable stream)
{
if(stream != null)
{
try
{
stream.close();
}
catch(final IOException ex)
{
ex.printStackTrace();
}
}
}
}
The operating system doesn't care or know about .jar file, so you'll have to unpack the .exe file to some temporary location before you execute it.
//gets program.exe from inside the JAR file as an input stream
InputStream is = getClass().getResource("program.exe").openStream();
//sets the output stream to a system folder
OutputStream os = new FileOutputStream("program.exe");
//2048 here is just my preference
byte[] b = new byte[2048];
int length;
while ((length = is.read(b)) != -1) {
os.write(b, 0, length);
}
is.close();
os.close();
Whilst the other users have answered the question correctly, extract and run then cleanup. Another point to consider is going fully native.
You are already using a native binary to achieve a specific task. Why not also create a native installer which will install your application, and install the binary to the OS specific location (Program Files on Win32) and create suitable shortcuts.
This way your application will feel more native and means you don't need to write or manage code to get around this fact. At the moment the Jar looks like a cross platform piece of code (Jar runs anywhere right?) but packs a native binary which will not run everywhere. This feels like a contradiction.
For installers I can recommend Nullsoft Installation System (NSIS) as they have many excellent tutorials and code samples to learn from.
Use
getClass().getResource(what).openStream()
and copy to another file in the disk.
You could write a simple java program to launch the exe using Runtime.exec(). You could then set the "Main-Class" attribute of the jar to be that launcher class. Users could then run your jar and it would run the exe.