Java respawn process - java

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.

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 .

Running a .jar file in a command prompt from double click

I'll start of by saying Im on windows 7.
I have created a .jar file which executes fine from the command line using the - java -jar myJar.jar approach
But what I'm after is to be able to double click on the jar file and for it to open up the command prompt window and run in the command prompt as if i've just typed the java -jar myJar.jar line.
When I double click the jar file I do think it is running because a visual part of the java is appearing, but there is no command prompt window showing my console output.
After looking around I've come across people saying that javaw which is what the jar files are associated with don't have a console and that I need to associate jar files with java.exe instead of javaw.exe. I've tried this and it didn't seem to work.
Can anyone help? A step by step would be nice.
I had the same question and the bat file idea was genius and saved me a lot of time rewriting code. Thanks!(I would have upvoted,but apparently I don't have enough rep.)
Batch (or Bat) files are super easy to make.
Just put the java -jar YourFile.jar into notepad (if you're on windows), save as Title.bat, and put into the same folder as your jar.
presto! a program open-able by the general public.
This is IMHO not possible. You could open the console from the application itself, but that is OS-dependent. If you need the console open, you have to run the application from it as you already do.
If you want to display the command line you have to launch your jar with the command line.
java -jar MyJar.jar
I would do something like this:
(Tested in Widows XP with JRE 1.6, to support other OSs you should verify the path for each OS and select the appropriate console emulator (xterm, gnome-terminal... (check for existance and preference...)))
public static void main(String[] args) throws Exception {
if (args.length == 0) {
String path = Main.class.getProtectionDomain().getCodeSource().getLocation().getPath().substring(1);//Adds extra slash (??) didn't know why
String decodedPath = URLDecoder.decode(path, "UTF-8");
System.out.println(decodedPath);
Runtime.getRuntime().exec("cmd /c start java -jar \"" + decodedPath + "\" actual_run");
}
else {
System.out.println("Hello World");
JOptionPane.showMessageDialog(null, "Hello World");
System.in.read();
}
}
Alternatively I suggest creating a bat file with this content :
java -jar yourjar.jar
This will launch your jar as well as open the command prompt automatically, all from a simple double click on a bat file.
(The bat file needs to be in the same folder as your jar file, else you need to specify the path to the jar, not just the jar name)
This is the easiest solution for beginners:
Open any text editor
write this two lines:
java "yourmainclassname"
pause
save that file as "name".bat
Run it with double click from windows GUI
(of course this new created .bat file must be in the same folder as the .class)
..but there is no command prompt window showing my console output.
No there wouldn't be a console for an executable Jar. You'll need to put that output in the GUI.
Check your MANIFEST.MF
Extract your "executable" jar file into a folder
find MANIFEST.MF in META-INF folder
check presence of this field:
Main-Class: YourMainClassHere
If this field dissapeared then open your original MANIFEST.txt for this point:
Main-Class: YourMainClassHere must end with a new line or carriage return
Warning: The text file must end with a new line or carriage return. The last line will not be parsed properly if it does not end with a new line or carriage return.

Im getting "dig is not recognized as an internal or external command" when I try to run a batch file from java

import java.io.*;
public class Main {
public static void main(String[] args) throws IOException, StringIndexOutOfBoundsException
{
Runtime.getRuntime().exec("cmd /c start C:\\dig-files3\\query3.bat");
}
}
I'm trying to launch a batch file through a java program but I get a 'dig not recognized as an internal or external command ...' message in the cmd screen. However when I double click on the batch file in the window it runs fine. How can I fix this?
Here is the batch file's content:
SET /a VAR=0
:HOME
SET /a VAR=VAR+1
IF %VAR%==200000 goto :End
dig #10.3.1.166 6.4.0.3.5.5.5.9.9.9.com. naptr
goto :HOME
:END
This is probably happening because "dig" has not been added to your PATH variable. Try opening a new terminal window and typing "dig" and it will probably show the same error. You have to go to Control Panel -> System -> System Properties -> Advanced options tab -> Environment variables.
There you have to search for the PATH variable and add, at the end (and after adding ";" to the last command) the full path to "dig" executable (except for the executable itself e.g. c:\foo\bar). Then try again. This environment variable tells Windows to look on the list of paths contained in it, for the executable you are trying to run.
Another solution is to copy over your compiled java file to where the dig executable is located and run it from there.
You should create a file object for the working directory to prevent problems with whitespaces in the path and then use that object to start the batch script:
File workdir = new File("C:\\dig-files3");
Runtime.getRuntime().exec("query3.bat", null, workdir);
There's also a flaw in your batch script: You probably want to write SET /a VAR=%VAR%+1 so that %VAR% gets evaluated before incrementing it.
Your problem is that you do not have the batch file in the system PATH variable. Insert the path to your batch file into the system PATH and it should work fine
Ok, there may another way to fix this but this is how I did it. I am using Eclipse and I copied the dig application to the project directory C:\User\username\workspace\projectName

Launching CYGWIN-built executable from Java on Windows 7 fails with "error while loading shared libraries: ?: No such file or directory"

The code in question has worked in more or less the exact same configuration on earlier releases of Windows, however, it is not known to have run on Windows 7 YET! That's what I need to solve now.
Briefly, some C code performs some configuration and security checks before launching a java program, passing some data that would be neigh-into-impossible to do easily in Java. The Java in turn, at the appropriate time launches the same C code which then itself launches a different Java program. The second program launch needs to be completely independent, (think nohup) hence the second launch.
What's happening now is that the C program launches the Java program in the ordinary way, but when the Java tries to launch the C program, it errors out like this:
/cygdrive/c/opt/ST/v3.3/bin/ST.exe: error while loading shared
libraries: ?: cannot open shared object file: No such file or
directory
Because Windows has been such a bear over the years, the C code is written in the posix environment of Cygwin, but all it really does is ordinary C types of things (nothing about it is unique to Cygwin and, indeed, in the past it has been built with Microsoft's development tools, but that environ is not available at present). The Cygwin environ adds a lot of other great benefits, like command-line management of services (cygrunsrv) and a full-on 'nix-like environment (bash, etc). In fact, because Windows has changed how one launches a program from Java so many times, Cygwin helps standardize the Java launch code. Here's an excerpt:
if (ClientOS.indexOf("Windows") != -1)
{
if (ClientOS.equals("Windows 95"))
{
cmd = "command.com /C ";
} else if (ClientOS.equals("Windows 98"))
{
cmd = "command.com /C ";
//cmd = "cmd.exe /C ";
} else if (ClientOS.equals("Windows NT"))
{
cmd = "cmd.exe /C ";
} else if (ClientOS.equals("Windows 2000"))
{
cmd = "cmd.exe /C ";
} else if (ClientOS.equals("Windows XP"))
{
cmd = "cmd.exe /C ";
} else {
cmd = "cmd.exe /C ";
}
if (cygwin)
{
cmd += Shell+" '"+Command+"'";
} else {
cmd += Command;
}
} else {
cmd = Command;
}
(Yes, the if structure could be better optimized.)
In this case, "Shell" equals:
Shell=C:/cygwin/bin/bash -c
And, there's a test program to ensure the above and supporting code works OK - it runs a bit of shell program and ensures it got back what it thought it should. It says:
Checking the ability to run a program using a shell...
Yes, shell programs work fine.
The final contents of cmd look something like this:
cmd.exe /C C:/cygwin/bin/bash -c '/cygdrive/c/opt/ST/v3.3/bin/ST.exe'
WHAT I SUSPECT:
I suspect what's going on is that the Cygwin1.DLL file isn't being found properly. It lives in C:/cygwin/bin/cygwin1.dll
NOTE THAT both the system-level PATH and the Cygwin PATH include the path to the cygwin .dll files. Moving a copy of cygwin1.dll to the bin directory where the target executable lives didn't work either.
Would LD_LIBRARY_PATH lend any help here? If so, any idea how it is to be set?
Other ideas?
Thanks.
C:/cygwin/bin/bash -c '/cygdrive/c/opt/ST/v3.3/bin/ST.exe'
This won't work because your working directory is where you reside when you executed this command. You will have to copy the cygwin dependent dlls to the directory you execute this from. Othwerwise, you will have to place the cygwin bin directory in your system PATH variable, not sure you want to do that, can cause dll hell.
Also, if you're using anything in your profile, you need to add --login parameter to bash:
bash --login -c
Also, print the final command out at the end, before you spawn the process:
printf('%s\n',cmd)
Just to be sure it's exactly what you want.
You may also run the program with strace, if you're unsure about the dlls being referenced.
Several ways.
cygwin1.dll needs to be in %WINDIR%\system32 or equivalent.
or
you modify the PATH variable to add the path to cygwin1.dll in the caller's environment.
or
you call a .bat file that sets the environment before you call the cygwin built exe.
or
you build a standalone version of the .exe (i.e. no cygwin dependency).

Open jar from another jar

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.

Categories