location of shell script called from java application - java

I have a java application from which i am calling a shell script. Can any one tell where to keep the script file in my application and what is the path to access the file in whole application.
i m keeping my script in the java package but when i m trying to access using path like com.abc.script.sh by running my java application through unix i ma getting error
java.io.IOException: error=2, No such file or directory
i am calling the script file with some argument with the following code
private static final String command = "com.abc.script.sh -db abc -scm TEST_xyz -bcp com.abc.out.txt -log /var/tmp -tab abc_$TABLENAME";
Process process = Runtime.getRuntime().exec(command);
and i am running the application from unix.
i need to pass the parameter to shell script file as well . the parameters are like hostname , table name...

where to keep the script file in my application
Your wrote, I can interprete this like:
Storing the content of the file into the memory
Storing the file into your .jar file
I think you mean the second.
You can place it in your jar file in every folder you want. I prefer a subfolder (not the root)
First put the file in your jar. Then you have to extract it to a temporary file (See the link if you want to know how to make a tempfile).
Then create an inputstream from the file in your jar and copy the data to the temp-file.
InputStream is = getClass().getResourceAsStream("/path/script.sh");
OutputStream os = new FileOutputStream(tempFile);
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = is.read(buffer)) != -1)
{
os.write(buffer, 0, bytesRead);
}
buffer = null; // Clear the buffer
Then you have to execute your shellscript
Runtime.getRuntime().exec("terminalname " + tempFile.getAbsolutePath());
Maybe you can use this line to execute your script (I don't think this will work with your parameters):
java.awt.Desktop.getDestkop().open(tempFile);
I hope this is an answer for your question.

You could store your shell script as a resource (e.g. inside your jar file), then exec a shell and pipe the content of your script as standard input to the running shell.
Something like this (haven't tried it):
ProcessBuilder processBuilder = new ProcessBuilder( "/usr/bin/bash" );
Process process = processBuilder.start();
OutputStream outputStream = process.getOutputStream();
InputStream resourceStream = getClass().getResourceAsStream(
"/path/to/my/script.sh" );
IOUtils.copy( resourceStream, outputStream );

If you happen to be using the Spring framework for this project, a good and simple option is to store the shell script in a folder on your class path and use a ClassPathResource object to locate it.

Related

Executing a jar file, with code [duplicate]

How could I run a local jar file from a java program?
The jar file is not in the class-path of the Java caller program.
I suggest you use a ProcessBuilder and start a new JVM.
Here is something to get you started:
ProcessBuilder pb = new ProcessBuilder("/path/to/java", "-jar", "your.jar");
pb.directory(new File("preferred/working/directory"));
Process p = pb.start();
Process proc = Runtime.getRuntime().exec("java -jar Validate.jar");
proc.waitFor();
// Then retreive the process output
InputStream in = proc.getInputStream();
InputStream err = proc.getErrorStream();
byte b[]=new byte[in.available()];
in.read(b,0,b.length);
System.out.println(new String(b));
byte c[]=new byte[err.available()];
err.read(c,0,c.length);
System.out.println(new String(c));
First, the description of your problem is a bit unclear. I don't understand if you want to load the classes from the jar file to use in your application or the jar contains a main file you want to run. I will assume it is the second.
If so, you have a lot of options here.
The simplest one would be the following:
String filePath; //where your jar is located.
Runtime.exec(" java -jar " + filepath);
Voila...
If you don't need to run the jar file but rather load the classes out of it, let me know.
Could something like the following be useful?
http://download.oracle.com/javase/tutorial/deployment/jar/jarclassloader.html
Another way to do on windows is:
Runtime.getRuntime().exec("cmd /c start jarFile");
this way you can set priority of your process as well (normal/low/etc)
You can run a jar file from where ever you want by using only this one line code.
Desktop.getDesktop().open(new File("D:/FormsDesktop.jar"));
where
new File("your path to jar")
Hope it helps.
Thanks.
Add jar library to your project
Import main class (see manifest in jar file)
Invoke static method main with arguments
String args[] = {"-emaple","value"};
PortMapperStarter.main(args);
To run an executable jar from inside your java application, you can copy the JarClassLoader from https://docs.oracle.com/javase/tutorial/deployment/jar/examples/JarClassLoader.java
Use it like this. In this snippet, jarUrl is the URL to download the jar from, for example file:/tmp/my-jar.jar and args is the array of strings you want to pass as command line arguments to the jar.
JarClassLoader loader = new JarClassLoader(jarUrl);
String main = loader.getMainClassName();
loader.invokeClass(main, args);
Keep in mind that you're now inserting someone else's binary into your code. If it gets stuck in an infinite loop, your Thread hangs, if it calls System.exit(), your JVM exits.
This is my appriach, which I consider is more complete:
public static Process exec(String path, String filename) throws IOException {
String javaHome = System.getProperty("java.home");
String javaBin = javaHome +
File.separator + "bin" +
File.separator + "java";
ProcessBuilder pb = new ProcessBuilder(javaBin, "-jar", path+filename);
return pb.start();
}
1) Set the class path from environment variables
2) Go to the folder where your jar file exists
3) Run the following commands through command prompt
java -jar jarfilename

Error in Copying file of a system app into another location

I am developing a system app in which I have to copy the xml file belonging to another system app onto a known location of my rooted phone.
First I tried to do this in the command prompt , using adb shell and the command
cp /data/data/owner_app_pkg_name/shared_prefs/file.xml /storage/sdcard0/FOLDERNAME/file2.xml
It worked perfectly.
However, when I tried to do the same thing programmatically in my system app, using
Process p = Runtime.getRuntime().exec("cp /data/data/owner_app_pkg_name/shared_prefs/file.xml /storage/sdcard0/FOLDERNAME/file2.xml");
It does not work.
Moreover, if I created a copy of file.xml in the same directory through command prompt of the system and then executed the code in my app using the copied file's name, it works.
Can someone please tell me what I have to do to directly copy the file.xml used by the owner system app to the location I want, using the java code of my system app as I have mentioned above?
public void copyFile() throws IOException {
InputStream inStream = new FileInputStream(new File("/data/data/owner_app_pkg_name/shared_prefs/file.xml"));
OutputStream outStream= new FileOutputStream(new File("/storage/sdcard0/FOLDERNAME/file2.xml"));
// Transfer bytes from in to outStream
byte[] buf = new byte[1024];
int len;
while ((len = inStream.read(buf)) > 0) {
outStream.write(buf, 0, len);
}
inStream.close();
outStream.close();
}
Solved my problem by using the commands
adb shell
chmod 666 /data/data/owner_app_pkg_name/shared_prefs/file.xml
and then running my app. But how to run chmod command from the java code of my app itself?

Trying to execute a Java jar with Runtime.getRuntime().exec()

In the project I am working on, I need to execute a script that I have in a resources folder -- in the class path. I am simply testing the final script functionality, since I am on Windows, I needed a way to output a file to STDIN so I created a simple cat.jar program to clone unixs cat command.
So when I do "java -jar cat.jar someFile.txt" it will output the file to stdout. I'm sure there are different ways of doing what I did.
Anyways,
I want to run that JAR from my main java program.
I am doing
Runtime.getRuntime().exec("java -jar C:/cat.jar C:/test.txt");
I've tried switching the forward slash to a backward slash and escaping it -- didn't work.
Nothing is getting sent to standard out.
Where as, if I run the cat jar on its own, I get the file directed to standard out.
What am I doing wrong here?
Is this enough information?
Use the Process instance returned by exec()
Process cat = Runtime.getRuntime().exec("java -jar C:/cat.jar C:/test.txt");
BufferedInputStream catOutput= new BufferedInputStream(cat.getInputStream());
int read = 0;
byte[] output = new byte[1024];
while ((read = catOutput.read(output)) != -1) {
System.out.println(output[read]);
}
References:
http://docs.oracle.com/javase/7/docs/api/java/lang/Process.html
By default, the created subprocess does not have its own terminal or console. All its standard I/O (stdin, stdout, stderr) operations will be redirected to the parent process, where they can be accessed via the streams obtained using the methods getOutputStream(), getInputStream(), and getErrorStream().
http://docs.oracle.com/javase/7/docs/api/java/lang/Process.html#getInputStream()
getInputStream() returns the input stream connected to the normal output of the subprocess.

writing temporary files in Tomcat

I need to create temporary directory but I'm always getting access denied when I try to create a file into the temporary directory.
java.io.FileNotFoundException: C:\tmpDir7504230706415790917 (Access Denied)
here's my code:
public static File createTempDir() throws IOException {
File temp = File.createTempFile("tmpDir", "", new File("C:/"));
temp.delete();
temp.mkdir();
return temp;
}
public File createFile(InputStream inputStream, File tmpDir ) {
File file = null;
if (tmpDir.isDirectory()) {
try {
file = new File(tmpDir.getAbsolutePath());
// write the inputStream to a FileOutputStream
OutputStream out = new FileOutputStream(file);
int read = 0;
byte[] bytes = new byte[1024];
while ((read = inputStream.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
inputStream.close();
out.flush();
out.close();
System.out.println("New file created!");
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
return file;
}
I'm working on a web application and I'm using tomcat. Is there a way to create temporary file on tomcat server memory? I know that's bizarre, but I don't know ... maybe it's possible.
You could use Tomcat's temp folder.
If you use
<%=System.getProperty("java.io.tmpdir")%>
in a JSP you can get path to it.
This line in your code says create a file whose name starts with text "tmpDir" in the directory "C:\". That is not what you want.
File temp = File.createTempFile("tmpDir","",new File("C:/"));
The operating system is properly disallowing that because C:\ is a protected directory. Use the following instead:
File temp = File.createTempFile("tmp",null);
This will let Java determine the appropriate temporary directory. Your file will have the simple prefix "tmp" followed by some random text. You can change "tmp" to anything meaningful for your app, in case you need to manually clean out these temp files and you want to be able to quickly identify them.
You usually cannot write onto C:\ directly due to the default permission setting. I sometime have permission issue for doing so. However, you can write your temporary file in your user folder. Usually, this is C:\Documents and Settings\UserName\ on XP or C:\Users\UserName\ on vista and Windows 7. A tool called SystemUtils from Apache Lang can be very useful if you want to get the home directory depending on OS platform.
For example:
SystemUtils.getUserDir();
SystemUtils.getUserHome();
Update
Also, you create a temp file object but you call mkdir to make it into a directory and try to write your file to that directory object. You can only write a file into a directory but not on the directory itself. To solve this problem, either don't call temp.mkdir(); or change this file=new File(tmpDir.getAbsolutePath()); to file=new File(tmpDir, "sometempname");
On Linux with tomcat7 installation:
So if you are running web application this is the temp directory Tomcat uses for the creation of temporary files.
TOMCAT_HOME/temp
In my case TOMCAT_HOME => /usr/share/tomcat7
If you are running Java program without tomcat, by default it uses /tmp directory.
Not sure if it affects but i ran this command too.
chmod 777 on TOMCAT_HOME/temp

Hosting an executable within Android application

I am working on an Android application that depends on an ELF binary:
our Java code interacts with this binary to get things done. This
runtime needs to be started and terminated on Application startup and
application exit / on demand.
Questions:
I am assuming that we will be able to execute this binary using the
Runtime.exec() API. Is there any constraints as to where I
need to be putting my library in the folder structure? How would the system runtime locate this executable? Is there some sort of class path setting?
Since the application has dependencies on this Runtime, I was
thinking of wrapping it around a service so that it can be started or
stopped as required. What is the best way to handle such executables
in Android project?
What are other alternatives, assuming that I do not have source code for this executable?
Please advice.
Thanks.
1) No, there should be no constrains, besides those that access system files and thus require root. The best place would be straight to /data/data/[your_package_name] to avoid polluting elsewhere.
2) A very thorough discussion about compiling against native libraries can be found here: http://www.aton.com/android-native-libraries-for-java-applications/ . Another option is a cross-compiler for arm (here is the one used to compile the kernel, it's free: http://www.codesourcery.com/sgpp/lite/arm ). If you plan to maintain a service that executes your cammand, be warned that services can be stopped and restarted by android at any moment.
3) Now, if you don't have the source code, I hope that your file is at least compiled as an arm executable. If not, I don't see how you could even run it.
You will execute the file by running the following commands in your java class:
String myExec = "/data/data/APPNAME/FILENAME";
Process process = Runtime.getRuntime().exec(myExec);
DataOutputStream os = new DataOutputStream(process.getOutputStream());
DataInputStream osRes = new DataInputStream(process.getInputStream());
I know nothing about your executable, so you may or may not need to actually get the inputStream and outputStream.
I am assuming that running adb to push the binary file is out of the question, so
I was looking for a neat way to package it. I found a great post about including an executable in your app. Check it out here:
http://gimite.net/en/index.php?Run%20native%20executable%20in%20Android%20App
The important part is this one (emphasis mine):
From Android Java app, using assets folder
Include the binary in the assets folder.
Use getAssets().open(FILENAME) to get an InputStream.
Write it to /data/data/APPNAME (e.g. /data/data/net.gimite.nativeexe), where your application has access to write files and make it executable.
Run /system/bin/chmod 744 /data/data/APPNAME/FILENAME using the code above.
Run your executable using the code above.
The post uses the assets folder, insted of the raw folder that android suggests for static files:
Tip: If you want to save a static file in your application at compile time, save the file in your project res/raw/ directory. You can open it with openRawResource(), passing the R.raw. resource ID. This method returns an InputStream that you can use to read the file (but you cannot write to the original file).
To access the data folder, you can follow the instructions here:
http://developer.android.com/guide/topics/data/data-storage.html#filesInternal
Also, there's the File#setExecutable(boolean); method that should works instead of the shell command.
So, putting everything together, I would try:
InputStream ins = context.getResources().openRawResource (R.raw.FILENAME)
byte[] buffer = new byte[ins.available()];
ins.read(buffer);
ins.close();
FileOutputStream fos = context.openFileOutput(FILENAME, Context.MODE_PRIVATE);
fos.write(buffer);
fos.close();
File file = context.getFileStreamPath (FILENAME);
file.setExecutable(true);
Of course, all this should be done only once after installation. You can have a quick check inside onCreate() or whatever that checks for the presence of the file and executes all this commands if the file is not there.
Let me know if it works. Good luck!
Here is a complete guide for how to package and run the executable. I based it on what I found here and other links, as well as my own trial and error.
1.) In your SDK project, put the executable file in your /assets folder
2.) Programmatically get the String of that files directory (/data/data/your_app_name/files) like this
String appFileDirectory = getFilesDir().getPath();
String executableFilePath = appFileDirectory + "/executable_file";
3.) In your app's project Java code: copy the executable file from /assets folder into your app's "files" subfolder (usually /data/data/your_app_name/files) with a function like this:
private void copyAssets(String filename) {
AssetManager assetManager = getAssets();
InputStream in = null;
OutputStream out = null;
Log.d(TAG, "Attempting to copy this file: " + filename); // + " to: " + assetCopyDestination);
try {
in = assetManager.open(filename);
Log.d(TAG, "outDir: " + appFileDirectory);
File outFile = new File(appFileDirectory, filename);
out = new FileOutputStream(outFile);
copyFile(in, out);
in.close();
in = null;
out.flush();
out.close();
out = null;
} catch(IOException e) {
Log.e(TAG, "Failed to copy asset file: " + filename, e);
}
Log.d(TAG, "Copy success: " + filename);
}
4.) Change the file permissions on executable_file to actually make it executable. Do it with Java calls:
File execFile = new File(executableFilePath);
execFile.setExecutable(true);
5.) Execute the file like this:
Process process = Runtime.getRuntime().exec(executableFilePath);
Note that any files referred to here (such as input and output files) must have their full path Strings constructed. This is because this is a separate spawned process and it has no concept of what the "pwd" is.
If you want to read the command's stdout you can do this, but so far it's only working for me for system commands (like "ls"), not the executable file:
BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
int read;
char[] buffer = new char[4096];
StringBuffer output = new StringBuffer();
while ((read = reader.read(buffer)) > 0) {
output.append(buffer, 0, read);
}
reader.close();
process.waitFor();
Log.d(TAG, "output: " + output.toString());
For executing binary file starting from Android 10 it's only possible from read-only folder. It means that you should pack binary with your app. Android doc
Put android:extractNativeLibs="true" into AndroidManifest;
Put your binary to src/main/resources/lib/* directory, where * – stands for architecture of CPU, for instance armeabi-v7a;
Use code like this for executing:
private fun exec(command: String, params: String): String {
try {
val process = ProcessBuilder()
.directory(File(filesDir.parentFile!!, "lib"))
.command(command, params)
.redirectErrorStream(true)
.start()
val reader = BufferedReader(
InputStreamReader(process.inputStream)
)
val text = reader.readText()
reader.close()
process.waitFor()
return text
} catch (e: Exception) {
return e.message ?: "IOException"
}
}
Here is discussion with answer from android team on reddit.
I've done something like this using the NDK. My strategy was to recompile the program using the NDK and write some wrapper JNI code that called into the program's main function.
I'm not sure what the lifecycle of NDK code is like. Even services that are intended to be long-running can be started and stopped by the system when convenient. You would probably have to shutdown your NDK thread and restart it when necessary.

Categories