Calling a Java program from a CGI script fails - java

I have a Python CGI script from which I am trying to call a Java program to perform a task. The Java program uses JExcelAPI. When I run the Python script from the browser, it fails with error messages that it can't find the class definitions for the classes from JExcelAPI. I suppose this happens because the Python CGI script is run under the apache user, and the apache user does not have the appropriate environment variables set (namely the CLASSPATH variable). I have tried calling the program with the -classpath /path/to/JExcelAPI switch, but that does not work either. Can you help me find the way to make the apache user aware of the JExcelAPI? Is there a way to set the CLASSPATH environment variable for the apache user?
Thanks

Several solutions come to mind :
Create a bash script which calls the java program. You can set all the variables you like and debug on the commandline, e.g. sudo -u apache /usr/local/bin/java-task-wrapper. This simplifies calling it from a cgi considerably and the overhead of bash is negligeable compared to spinning up a JVM.
Create a standalone executable jar with tools like uberjar. No more classpah issues as everything is contained : java -jar java-task-standalone.jar
exec java -cp /path/to/JExcelAPI:/my/program/classes com.acme.MainClass
There is usually a variant of exec which takes an additional array or hashmap to add environment variables.
Some notes:
setting the CLASSPATH variable globally is not done anymore because it leads to many conflicts. In a wrapper script it is Ok as possibilities to clash is reduced.
JVM's take a long time to start and the execution will be slow since the JIT gets no chance to do its magic. Running your script in a lightweight webserver like jetty or winstone or listening on a socket will eliminate the startup cost and enabe the JIT to make things fast.

Related

Is JAVA_HOME fixed when executing a java command or can it be modified midcommand?

Just to be clear, I DON'T WANT to change the JAVA_HOME during a java command (and take this change into account for said command), but I'm facing a situation where several java commands can be run simultaneously from some ksh scripts, and in those scripts JAVA_HOME is set (and exported) to either a 32-bits or 64-bits version before executing the java command itself.
So I am concerned there could be some "clashes" of some sort... Any advice on how to avoid any "overlaps", if they are even possible?
Note: there can potentially be a lot of script executions at the same time, and >the commands run with 32-bits version of Java cannot be run with 64-bits >version of Java for compatibility issues with other-party processes
Thanks in advance
JAVA_HOME is just a convention and it has no effect on the running JVM.
You can set the JAVA_HOME safely for each script, however do not use export! or you might end up with unexpected results.
Also, usually, the java application is located at JAVA_HOME/bin so you need to make sure that your script is pointing to the correct JVM 32/64.
HTH,
Gal.
Like all environment variables, it's fixed at the start of the command. See, for example, this question (it's about a Python program, but the same concept applies).
However, as others have pointed out, it doesn't actually have any effect on Java commands.

Java - how to use forever tool for the jar file?

On CentOS 7 i have /home/www/html/java-server/Objects/server.jar file which time to time crash for good reason and need to re-start again automatic so that its always running.
How to use forever like tool or any other similar for Java on CentOS?
For example on my NodeJS server i use as below.
forever start --minUptime 1000 --spinSleepTime 1000 SERVER.js
or
forever -m5 server.js
EDIT:
Reference: https://stackoverflow.com/a/28704296/285594
Wrap your jar in a shell script (this is optional but often useful) and use Supervisor to monitor it. Supervisor is highly customizable so you can set how many times your process can be restarted in a period of time, etc.
Here is how I did it.
I was trying to get a spring boot executable jar to run.
I created a bash script like the following
#!/bin/bash
forever start -c bash ./my-app.jar
The key here is to use "-c bash" otherwise forever failed to run the jar. Forever kept trying to run with node
You can write a class in Java that loops. It would call your application and catch exceptions, restarting the application after each exception. Make sure the wrapper class releases references to the application so that it can be GC'ed.

Wrapping a jar file in a Windows service

Have you had experience with running a jar file using a command line, wrapped in a Windows service?
I'm trying to find a way to run a jar file without being logged into the machine, and since it allows command shell, I was wondering if it's a good idea.
Thanks!
Original Post:
I'm trying to run Associated Press's Web Feeds Manager, which is basically a jar file that can be run when logged in by double clicking it.
I'd like to run the same file but without being logged in to the machine. In their manual (http://wfm.ap.org/admin/content/help/Running_Agent_on_a_Remote_Server.htm) they write how to do that, using a commandline parameter.
Basically I'd like the jar to run as a Windows service, regardless of who's logged in, but Googling it showed it was problematic.
Have you had experience with remotely running jar files? What are the pitfalls?
Thanks!
On a google search, I came across this article -
Running Jar Applications as a Windows Service
It mentions about open source Java Service Wrapper project from Tanukisoftware.org for accomplishing this task.
Note: I've not used this personally.
If you are not interested in having the service started/stopped at boot/shutdown, but you just want the program to be started manually and keep running after logout, here is what you do:
$ nohup java -jar foobar.jar > foobar.log 2>&1 &
which means: start my foobar.jar (java -jar) and keep it running after I logout (nohup) redirect stdout to foobar.log (>) and also the stderr (2>&1), and make it running in background (& at the end).
Instead, if you are interested in installing a "service" in your linux box, there are many options, depending on what distribution you are using.
The most common are upstart (for ubuntu) and System V init scripts (Redhat or others). Also cron can be used to start/stop services at startup/shutdown.
You can find an example of installing a java app (hudson) on an init system here, or doing the same thing with upstart. Or, as I said, cron could be an option.
On Windows, there is Java Service Wrapper. And not much more.
For windows Java Service Wrapper is a better choice
My favourite is the upstart on linux, but it is Ubuntu only.
On Windows I see many alternatives according to this forum.

Running a Java program in a Perl/CGI script

I have a program that uses external libraries and code I've written in Java. However, I want to make it accessible via the web.
If I had full control over the webserver I was running it on, I would probably use Tomcat or JBoss, but I don't have such privileges at my school.
The servers I do have access to have Apache HTTP server with all the normal Linux goodies installed (think: Perl, PHP, etc.)
How would I write a Perl script that runs this Java program?
I've tried the basics such as "system java MyProgram" and "exec java MyProgram", but they don't seem to work.
I'd appreciate any help or insight on this. Thank you!
Process process;
try
{
process = Runtime.getRuntime().exec("cmd / c start c:\\Perl\\bin\\file.pl");
try to run like this as per your program.
When you run a CGI script, the environment is very limited, and this includes the PATH. Is it possible that your CGI script can't find the java command? Or maybe Perl simply is refusing to run the system command when in CGI mode (aka taint mode). See perldoc perlsec for more information.
Basically, you need to set PATH and then try running your system command with your java command.
Try this:
system('/full/path/to/java -cp full_class_path my.class.Name');

Running a java application through shell script in a JSP/Servlet

I am running a shell script through a web application. This shell script looks something like
`#! /bin/bash
user=""
pass=""
db_url=""
db_instance=""
sqlplus -s $user/$pass#$db_url/$db_instance # ./SqlScripts/foo.sql
sqlplus -s $user/$pass#$db_url/$db_instance # ./SqlScripts/bar.sql
CLASS_PATH="./lib/*"
java -classpath $CLASS_PATH package.Main ./Data/inputfile`
I am using ProcessBuilder to run the script and everything but the last line works fine. Am I creating a problem by calling shell through the jvm then calling the jvm again to run the application?
The problem was the environment that the script execution process was running in. I changed some of the environment variables of the process and everything is working fine now. The script was initially a standalone shell script, but I wrote one script for each of the databases used. In order to control the workflow I wrote a web application for this which calls seperate threads for each script and can manage the threads. Thanks for the responses!
Often, app servers run their servlets in a 'clean room' environment - e.g. they strip away all the variables that would normally be set from the outside for security reasons. Try using a fully qualified path to the java binary, and also try setting a full/absolute path for your CLASS_PATH variable.
The parent JVM and the child JVM should be separate processes, no particular reason why they should interfere.
What error do you get?
is java on your PATH?
OK, adding more questions in response to your comments ...
Which thread is waiting? Presumably the parent?
The child java process, do you have any evidence as to whether is succesfully initalises. My guess woukld be that the child is in some way blocked. If you kill the child does the parent then come back to life?
Suppose it was a simple "hello world" application, would that work?
Most likely the line:
CLASS_PATH="./lib/*"
And
$CLASS_PATH
It won't be expanded by the process builder because that's usually shells' job, which in this situation is not being invoked.
Try creating the complete list of ./lib/* and append it directly into the last line of your script.
java -classpath ./lib/a.jar:./lib/b.jar
Side note:
Invoking all this from java looks just bad to me. I would rather have it in a standalone script and invoke it by other means, but that's me.

Categories