Java self-contained package wait for completion - java

I have an application that I need to be a self-contained app, installable, on computers that may not have Java. I'm using javapackager command to create an EXE that can be sent out to the users, containing all the parts needed. The app, in a simple sense, reads in a file referenced by the first param, does transformations on it, and writes back out next to the source file a result. All of that works when running it as a JAR directly, and also when running it via the built EXE.
The problem is that when triggering the executable, it immediately returns execution to the command prompt, rather than waiting for the process to finish. I don't want to have to poll the output directory to check if the file exists and then give some arbitrary timeout on when to stop looking - I want the app to know that once the console command has completed, the processing is done. At that time I can do logic based on if I find the result file, and alert if it is not found or whatever other logic is right.
Is there a way to tell the javapackager command to set a wait until Java has died (good or bad) before returning control? Barring that, is there a code snippet/concept that would make the app hold off releasing control back to the terminal until the JVM has died?

I can confirm this behaviour for apps that I've packaged using javapackager included with Oracle JDK 8, 9 and 10 as well as with snapshots from OpenJDK 13. While the resulting binaries behave "as expected" under macOS and Linux, the Windows binary merely seems to spawn a new process and exits immediately.
Beginning with Java 9 jpackager invokes jlink internally, which has an option --strip-native-commands which basically removes binaries from the embedded JRE. With Java 8 you didn't have this option and executables such as java.exe are always removed. But my tests show that the JRE is otherwise complete and you should be able to simply include java.exe manually (better test this thoroughly!).
Therefore I propose the following workaround:
Create the application directory using javapackager -deploy -native image
Copy java.exe from your system-wide JRE installation to {OUTDIR}\runtime\bin (check if your license covers redistributing java.exe!)
Create a .bat file inside {OUTDIR} that calls runtime\bin\java.exe -jar ./app/yourapp.jar.
Now add {OUTDIR} to your .msi or innosetup installer or .zip file or whatever means of distribution you choose ;-)
You can then invoke the bat file instead of the exe. Since it is just a wrapper for java -jar it will wait until your program finished.

Related

Spawn another process on same JVM

From a Java application I want to run another Java application on the same Java installation but in a separate process.
AFAIK for a new process I would use ProcessBuilder to run a command like
java -jar my.jar
but what if java is in a different directory, or should be java.exe since we are on Windows, or java.exe has some other name since the first application was jlinked and jpackaged?
Edit: What I learned meanwhile is that a jpackaged application comes with a native executable that sits in front of the JVM but passes all arguments to the application. That means it is no longer possible to specify an alternative jar to be executed, and some other mechanism is necessary.
If jlink image used within jpackage based apps is built without using the --strip-native-commands flag then the runtime image will contain bin/java (or bin/java.exe and bin/javaw.exe on Windows).
This will mean that you should be able to determine a path to launch a new JVM which works inside or outside of jpackage apps just based on the current runtime's java.home and by appending extra VM arguments in normal way for the classpath and main / module of the other application.
On Windows the environment property echo %PATHEXT% usually contains .EXE so the following should specify the java executable for the current runtime without needing to add the correct file extension on Windows:
String java = Path.of(System.getProperty("java.home"),"bin", "java").toString();
You can test above inside your jpackage and non-jpackaged app with a simple one-liner (note that this is not proper way to use ProcessBuilder):
new ProcessBuilder(java, "-version").start().getErrorStream().transferTo(System.out);
Obviously, the above is no help if you wish to determine whether to use Windows console enabled java.exe versus non-console javaw.exe.

how to start a java application system-independent at Windows startup

I want to automatically run a Java application under Windows at startup time, but not depending on a specical Windows or a special JRE-version.
Generally, a good way to run programs at Windows login time would be to add a registry entry under
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
But it seems as if the system PATH is not evaluated when Windows tries to run the programs listed in the registry's RUN section.
So these both entries do work:
"C:\Program Files\Java\jdk1.8.0_111\bin\javaw" -jar c:\path\to\java.jar
"C:\ProgramData\Oracle\java\javapath\javaw" -jar c:\path\to\java.jar
But this one doesn't come up:
javaw -jar c:\path\to\java.jar
Now, the latter works when manually entered in a console window because there the required PATH exists and is evaluated:
PATH=....;C:\ProgramData\Oracle\Java\javapath;....
Now, I want to have the registry entry added from an automated installer programm and I would like to have it formed "windows-system-independent" (from Vista up to Win 10, and furthermore not depending from the version of the installed JRE). So I do not know a general path to the JRE and therefore I cannot add a specific RUN-command to the registry.
Does anyone know how to add JRE-calls system-independent correctly to the registry's RUN-section?
I've already tried with a command-file, e.g. "startup.cmd" with content java -jar file.jar there, have added a call of this file to the registry, and yes that worked, java was found, the application was started, but when using this method I have an annoying black command terminal window staying open all the time while the java app is running.
Thanx,
Tombo
Change your startup.cmd, from
java -jar file.jar
to
start java -jar file.jar
This will launch the java.exe in a new process an let your batch executor terminate.

Running a JAVA program as a scheduled task

I am trying to run a simple JAVA program once per day on a Windows 7 machine.
My code runs fine inside NetBeans. If I do a clean and build it suggests this:
C:\Program Files\Java\jdk1.7.0/bin/java -jar "C:\Users\User1\Documents\NetBeansProjects\Facebook\dist\Facebook.jar"
This does not work from the DOS prompt of course because of the space between program and files so I do this:
C:\Program Files\Java\jdk1.7.0/bin/java -jar "C:\Users\User1\Documents\NetBeansProjects\Facebook\dist\Facebook.jar" -jar "C:\Users\User1\Documents\NetBeansProjects\Facebook\dist\Facebook.jar"
This works from the DOS prompt.
I now create a task in Windows Scheduler to run:
C:\Program Files\Java\jdk1.7.0/bin/java
with arguments:
-jar "C:\Users\User1\Documents\NetBeansProjects\Facebook\dist\Facebook.jar"
When I then run it, all I see is a DOS box flashing up for a second. I expect the code to take about 30 secs to run. The code should persist data to a database and no updates happen.
The code also uses java.util.logging so I should see log entries and I don't.
I strongly suspect that I am not running the JAVA command properly or that there's a bad classpath issue that it present when running via Scheduler that isn't there when running from the DOS prompt.
Help would be appreciated. If you've seen this before and can sort it that would be great. If you can tell me how to get a meaningful error trace from Scheduler than that would also be really helpful.
Thanks!
I Think that you could create a simple batch script that will launch your program in this way :
#echo off
REM Eventually change directory to the program directory
cd C:\Users\User1\Documents\NetBeansProjects\Facebook\dist\
REM run the program
"C:\Program Files\Java\jdk1.7.0\bin\java.exe" -jar "C:\Users\User1\Documents\NetBeansProjects\Facebook\dist\Facebook.jar"
Copy it into the notepad and save as java_script.cmd and then schedule this script instead of the program directly.
I solved it after changing all fonts' references to "SansSerif"
I was using Jasper Reports inside Java to create a PDF file. It was working fine when I double click the batch file or Scheduler with Windows Server 2003 but not working with the Scheduler of 2008.
I tried many different things nothing worked so I though Could it be that Windows Server 2008 is blocking the access?.
Now is working perfect. So, if you are having problems check the references to anything you are using.
The scheduler will run under a different user unless you specify what user to run as. If it isn't running as your user then it won't be able to write to your directories.
The real problem to the original question is a java installation issue on Microsoft systems. Java jre installs into Program Files\java. The executable (java.exe) is only installed in that java\bin directory. Running from the command line, the os looks in the proper location for the java.exe. Running from other MS tools (such as VBA Excel or in this case TaskScheduler), it does not!
You can see that TaskScheduler is looking in the wrong place by viewing the tasks history in the TaskScheduler tool. Double click on some of the history events and one will list the action and return code. The action will show that the TaskScheduler is trying to run
"C:\Windows\system32\java.EXE"
So, copy java.exe from the java\bin directory into the place where the scheduler is looking, and now it will work.
Or update your task and provide the full path to java.exe.
You can also update the environment system path to look for java in the java\bin directory, but that has to apply to all users and sometimes this is faulty as well.

using javaw to run jars in batch files results in more than one java processes in process explorer - XYNTService

I have a somewhat strange issue. I have a java application that installs few services that run as Jars. Previously I used installed Java to run these Jars. There are four services and all will be instantiated from a single batch file with sequential call to each other. Something like this,
start %JAVA_HOME% commandtoruntjarfile
would work and all four services will run in the background and only one java.exe visible in process explorer. So I had another service installed as windows service which would start stop these services by calling the run bat or shutdown bat.
Now the customer requirement changed to using an internalized version of java. I extract java to a location, make our own environment variable name "ABC_HOME" and the required syntax in batch changes to
%ABC_HOME%\javaw commandtorunjarfile
When its run it works. but there is no stopping these. When I go to process explorer I see 4 java.exe running each for the four run commands in the batch file. If I stop the windows service all the four keep working. If I restart the windows service the number of java.exe in process explorer goes to eight and keeps going up until windows has had enough of it.
How do I get around it? I think the solution should be to have the one java process in process explorer but I cant seem to find any solution for that.
[EDIT]
The four sub services are actually XYNT processes. In the normal scenario it would be something like this
[Process1]
CommandLine = java -Xrs -DasService=yes -cp jarfiles
WorkingDir = c: bin scache
PauseStart = 1000
PauseEnd = 1000
UserInterface = No
Restart = Yes
For using java from a specific location the following change was needed
CommandLine = %JAVA_PATH%\bin\java.exe -Xrs -DasService=yes -cp jarfiles
but this wouldn't work as it would not accept the path variable in XYNT.ini file. so I called a batch file here and in that batch file I used the above code. So here is what the change looks like,
CommandLine = batchfile.bat
and in batchfile.bat
%JAVA_PATH%\bin\java.exe -Xrs -DasService=yes -cp jarfiles
Usually, every Java program run on your system has its own virtual machine running, which means: one java.exe/javaw.exe per instance of your program.
I can not tell why it "worked" from your point of view with java.exe like you described first, but the behaviour you described for javaw.exe (having 4 java processes in the process explorer) would be what I'd have expected.
For me the question is not why you're seeing 4 vs. 1 java processes, but how you can start/stop the "services". Killing the Java VM externally doesn't seem a very good solution. I'd consider building some IPC into the Java services that allow you to gracefully terminate the processes.

Runtime exec output path

I am trying to run a perl command with Java runtime exec in linux/ubuntu/gnome. The command generates an pdf file, but it saves it in my home folder. Is there any way that the exec method can set an output path for the commands executed? Thanks in advance.
The exec method just runs the command on the operating system, so you'll want to change the command you're running with exec more than anything in "Java" per se.
There are a few possibilities:
Change the working directory of your java program. The .pdf is being saved in your working directory because this is where the program is being run.
Unfortunately it's not simple to change this value after the program has been launched. It is, however, trivial to change before the program starts; just change the working directory before starting the program.
Move the file to it's desired location after it's been created in your home directory.
Change the command so that it includes the target location. Your perl script may have an option that will enable you to save it's output to a certain location (usually -o or --output). Using this your program would change from:
Runtime.exec("perl someprogram");
to something like:
Runtime.exec("perl someprogram -o /path/to/some.file")
You might be able to use "output redirection", if there is no option to do this.
Try something like what's below as your argument:
Runtime.exec("perl someprogram > /path/to/some.file")
Unfortunately, without knowing more details of your situation I can't provide more concrete advice.
While each approach has benefits and drawbacks, it's probably best to just implement the one that you understand best; if you can't get one to work, try another.
A good, free online resource for learning is Introduction to Linux: A Hands On Guide.
Section 2.2 has details on cd which you can use for 1..
Section 3.3, section 3 teaches about the mv command, which will be useful in 2..
Section 5.1 is about I/O redirection. Knowing about "output redirection" and the > operator, are important for 4..
For 3., you'll have to consult the documentation of the perl program you're using.
You could modify the Perl script to accept an absolute path for the output.
You can trying setting the working directory using exec(java.lang.String[], java.lang.String[], java.io.File) where File is the directory the command is executed from.
If all else fails, you'll can always copy the generated file from the Home directory to your final location.

Categories

Resources