Open jar from another jar - java

The same old problem ... I want to run my jar on Mac or Linux with high memory allocation. I do not want the user to open the Terminal and write java -XMx512 -jar MainJar.jar manually.
I have seen a lot of solutions to fix this ... But i was wondering if this might work : "Executing the Terminal command java -XMx512 -jar MainJar.jar in Jar(B) to initialize Jar(A) with 512 MB memory allocation.".
In Jar(B) i have tried this code to run Jar(A) and it worked fine :
public static void main(String[] args) throws Exception{
String jarName = "MainJar.jar"; // Jar(A) name.
Desktop.getDesktop().open( new File( jarName ) );
}
But still i did not allocate memory for Jar(A) when initialized from Jar(B), so can i write a code in Jar(B) to run the Terminal and give it the command to execute it :
"java -XMx512 -jar MainJar.jar" ?
------------------------------ Edited as requested to be more clear.

You can use Runtime.exec() or a ProcessBuilder to accomplish this.
Process proc = new ProcessBuilder("java", "-XMx512M", "-jar", "MainJar.jar").start();
int result = proc.waitFor();
But honestly I think it's an awful solution. I would favour an installation package like InstallAnywhere. Failing that I would use a shell script to launch the Jar. Encapsulating it in a Jar where it can't be edited is annoying to users and now you have parallel dependencies rather than a single file.
If you were going to take this route, it would be possible to use the same Jar for both purposes. Add your class file to launch with the correct parameters to the Jar, say AppLauncher.class. We'll assume your program's real code starts at Main.class.
public class AppLauncher {
public static void main(String... args) {
Process proc = new ProcessBuilder("java", "-XMx512M", "-cp", "MyJar.jar", "Main").start();
int result = proc.waitFor();
}
}
Then you would have your Manifest file of the jar point to this main class:
Main-Class: AppLauncher
You would then execute this jar via
java -jar MyJar.jar
Or through file associations (double click).
When it runs, it executes the command java -Xmx512M -cp MyJar.jar Main which runs the main method of the Main class of your jar. The same jar is used in both invocations: the first time it automatically runs AppLauncher.main() via the manifest file, the second time Main.main() via an explicit process call.
This is still fragile of course. For one thing, it assumes that the working directory is set to the folder that contains your jar file. That's not always true.
Edit: Just in case you're not convinced to do otherwise, and actually take the ProcessBuilder route, there's more to it than just what I noted. There are pitfalls to avoid. For instance, I didn't read from the process's output stream (using Process.getInputStream()) so if child Java process outputs anything to stdout, it will freeze when the OS buffer is filled.

Related

executing bash commands from a specific directory

From my application I have to execute an external jar of which I do not have the source.
Given an input file, it processes it, creates an "output" directory and puts in it an mxml output file. Problem is: it creates said directory in tomcat/bin instead of inside the directory of the original file.
Here's what I've tried so far.
Initially
Process p = new ProcessBuilder("java -jar "+newfile.getParent()+"\\converter.jar "+newfile.getPath()+" -mxml").start();
Then, seeing how from console the "output" directory was created in the directory the command was called from, I tried:
String startSim[] = {"cd "+newfile.getParent()+"\\" , "java -jar converter.jar "+newfile.getName()+" -mxml"};
try {
Runtime.getRuntime().exec(startSim).waitFor();
} catch (Exception e) {
e.printStackTrace();
System.out.println("Log non creato.");
}
But with this I get the "file not found" exception for the first instruction. Does anyone know how to possibly solve this problem? I'd like to avoid having to reach for my output file all the way in my tomcat/bin directory.
Thanks for any suggestion!
Paolo
P.s.: by the way, before trying all this I tried simply calling the method I need from the library, but had the same exact problem. So I resolved to execute the jar, instead. And here we are. :)
You can set working directory using ProcessBuilder.directory() method:
ProcessBuilder pb = new ProcessBuilder();
pb.directory(new File("mydirectory"));
pb.command(......);
etc
This does not work for you when you are using Runtime.exec() because cd command is a functionality of shell. You could solve it using this technique but you have to create platform specific command with prefix like cmd /c on windows or /bin/sh on Linux. This way is definitely not recommended.
But in your specific case you do not neither first nor second solution. Actually you are starting one java process from another. Why? you can easily invoke the main() method of the second process directly.
Take a look on META-INF/MANIFEST.mf file from converter.jar. Field Main-Class contains the fully qualified name of main class. Let's say it is com.converters.Main (just for example). In this case you can invoke
com.converters.Main.main(new String[] {newFile.getPath(), "-mxml"});
directly from your code. Just add the jar to your classpath.
Concerning to changing working directory in this case. Check again whether you really need this or your converters.jar supports parameter that does this.
A lazy approach to this may be going to the root directory and descending from there to your tomcat bin directory .

file Path is not identified in java in linux

I have a simple java file in linux. I am executing another java program HelloWorld from my Parent Java class.
If I keep the class file in current directory it workds but if i keep in another directory it wont work. could you tell me what mistake I am doing here?
Working:
theProcess = Runtime.getRuntime().exec("java HelloWorld");
Notworking Below:
theProcess = Runtime.getRuntime().exec("java -cp \"/home/sss/public_html/Project/WekaMLWorkbench/src/m85/\" HelloWorld");
Many Thanks.
I understood your problem. It happens because of the regnoition problem in linux and java based environments.
Use this method in Runtime.
exec(String[] cmdArray)
Substituting the values.
theProcess = Runtime.getRuntime().exec(new String[]{"java", "-cp" ,"/home/sss/public_html/Project/WekaMLWorkbench/src/m85/HelloWorld");

How do I execute a Jar file in a new process and close the original Jar?

I have 2 jar files. I want Jar A to open Jar B then have jar A terminate, leaving Jar B running. How would I go about doing this?
EDIT: I meant I want JarA open in one instance of the JVM, then I want JarA to exectue JarB in a new instance of the JVM then JarA uses system.exit(0)
To start a new JVM you would start external java process just like any other OS command, look up the documentation on ProcessBuilder
ProcessBuilder pb = new ProcessBuilder("java", "-classpath", "B.jar", "B.BMain");
Process p = pb.start();
There are lot of caveats to starting external process in Java, you will find lot of material here on SO searching for Process and ProcessBuilder
jar files don't run or terminate; that is the jvm, started for example by the command java. For example when you run the following command:
java -classpath A.jar A.Main
A new jvm is started and it executes the main method of the class A.Main
Now that method Main.main(), can call methods of classes in B.jar, if it was in classpath. For example if the command was
java -classpath A.jar;B.jar pkg.A
Then in A.Main.main there can be
B.SomeClass.SomeMethod()
Where B is in B.jar
Is this what you mean when you say "open B.jar"? Note that this does not "close" the other "A.jar", whatever that may mean.
Do you want to launch a new JVM instance for running the other Jar, and then terminate? This is not so common.
Alternatively, you could just include Jar B into the classpath and use the classes it provides from within the code in Jar A.
Assuming, even after reading below answers, that you still want to invoke "JAR-B" in a separate JVM process which is not attached to parent process "JAR-A", your best bet perhaps is to use something similar to "cmd /start" (for windows) or using 'sh ... &' (for *nix) (from your java program in JAR-A)
I had a possible and partial answer:
So if you are using Java on Windows, then you can use
new ProcessBuilder("java", "-classpath", "B.jar", "B.Main").inheritIO().start();
This will not only start the process, but it will begin it in the same Command Prompt Window. For quitting JAR A, include a System.exit(0); in JAR A's main method right after creating process B.
For Linux builds, I'm not really sure, as I'm stuck in the same/similar issue for my program.
Create a new process in Java, exit the current process
EDIT: I did post my answer in the above question of mine. :)

Running .jar file within JSP page

I'm trying to develop a website that takes user input and converts to a text file. The text file is then used as an input for a .jar file. (e.g. java -jar encoder.jar -i text.txt), the jar then outputs a .bin file for the user to download.
This jar is designed to be run from command line and I really don't know the best way to implement it within a .jsp page. I have created a few java test classes but nothing has worked so far.
Does anyone have any suggestions on possible methods?
An alternative to running it as an external process is to invoke its main class in the current JVM:
Extract/open META-INF/MANIFEST.MF of the jar
Identify the Main-Class:. Say it is called EncoderMainClass
Invoke its main method: EncoderMainClass.main("-i", "text.txt")
This aught to be faster because a new OS process does not need to be created, but there may be security considerations.
Have you tried somrthing like this,
Create a java file
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", "thetextfile.txt");
pb.directory(new File("preferred/working/directory"));
Process p = pb.start();
ps: do handle to destroy process else it will eat up all memory
You can put this jar to the web application on the classpath and use it's class and methods. Better if you have javadoc if you don't have sources. But even if not in classpath you can try the example or this example.

Java respawn process

I'm making an editor-like program. If the user chooses File->Open in the main window I want to start a new copy of the editor process with the chosen filename as an argument. However, for that I need to know what command was used to start the first process:
java -jar myapp.jar blabalsomearguments // --- need this information
> Open File (fileUrl)
> exec("java -jar myapp.jar blabalsomearguments fileUrl");
I'm not looking for an in-process solution, I've already implemented that. I'd like to have the benefits that seperate processes bring.
Since you are launching Java -> Java, you can use the existing classpath to set the classpath on the command line. This type of thing works really nice in the dev environment too.
ProcessBuilder selfLauncher = new ProcessBuilder(
"java", "-cp", System.getProperty("java.class.path"),
"com.my.mainClass" );
selfLauncher.start();
Update:
For executable jar files, you will have a classpath which is simply the relative path to the jar file itself. If you want the command line arguments, you will have to save them from main, and re-apply them when launching.
You can see this by packing the following program into a jar. I'm not actually sure what happens if you have jars inside the executable jar file. They probably show up in the classpath.
public class TestJarPath {
public static void main(String args[]) throws Exception {
for (String s : args)
System.out.print("[" + s + "] ");
System.out.println();
String cp = System.getProperty("java.class.path");
for (String s : cp.split(";"))
System.out.println(s);
}
}
For java -jar ..\tst.jar X, you get output like:
[X]
..\tst.jar
If all else fails, try writing a batch/shell script to launch your app. In windows you can pass %CmdCmdLine% to Java to get the entire command line.
See http://www.robvanderwoude.com/parameters.php
As far as I know is there no portable way to get this info. I found a property in the gcj runtime but I doubt this will cover a large percentage of the users.
I think the accepted practice is "Try and Pray" :
Hope it is on the path, (the path IS available, so that can be checked)
if not, check if JAVA_HOME is defined, and use that to find java.
if not check in the most likely places on all OS's you have received bug reports for.
Well, it is messy... porbably best to check for JAVA_HOME and the path and ask the user to configure a JVL explicitely if that fails.

Categories