I programmed a Java app. For complex reasons I cannot export it as an executable (due to CVS and environment promoting practices) to Linux. I also cannot add the main class path to the MANIFEST.MF via 'jar -cvmf' command because it is not installed in the Linux environment the app is running in (I have no control over what gets installed). The only other option I found was to create the following shell script:
#!/bin/bash
#check that parameters were passed
if [ $# -lt 2 ]; then
echo ""
echo "Not enough arguments provided. You must have at least 2 arguments with ISO SQL time stamps."
echo " After that you can have unlimited number of parameters for tools."
echo ""
exit 1
fi
echo "Recovering events that occurred between $#"
ROOT_DIR=_spool_generator
JAR_DIR=jar
mkdir $ROOT_DIR
mkdir $ROOT_DIR/$JAR_DIR
FULL_DIR=$ROOT_DIR/$JAR_DIR
cp /home/wma/jar/SpoolGenerator.jar ./$FULL_DIR/
echo $#
START=$1
END=$2
java -cp "./$FULL_DIR/SpoolGenerator.jar" com.btv.main.Driver $# # --> does not work
#java -cp "./$FULL_DIR/SpoolGenerator.jar" com.btv.main.Driver "2001-02-12 18:15:00.0" "2001-02-12 19:15:00.0" --> works
#java -cp "./$FULL_DIR/SpoolGenerator.jar" com.btv.main.Driver "$START" "$END" --> works
echo "Execution is complete..."
exit
The key issue here is that I have an unlimited number of parameters the application uses. This works great when deploying the java app directly as an executable in Windows, works fine if I specify the positional arguments the Shell script takes, but how do I pass these same arguments to the java app from within the Linux script. I have to pass the parameters to the script surrounded in quotes due to the timstamp's special characters, this seems to cause some aberrant parsing when the parameters are passed to the jar. I appreciate any help.
Related
SO I am trying to change the JVM heap memory percentage
I have added these two lines in my Dockerfile
ENV JAVA_OPTS="--XX:MinRAMPercentage=50.0 --XX:MaxRAMPercentage=80.0"
CMD ["--spring.profiles.active=${profile}","${JAVA_OPTS}"]
But when I check this command:(java -XX:+PrintFlagsFinal -version | grep -E "UseContainerSupport | InitialRAMPercentage | MaxRAMPercentage | MinRAMPercentage") on my docker container, it shows default values of the above parameter:
No environment variable expansion or other processing is done on exec form CMD (or ENTRYPOINT or RUN). Your application is getting invoked with literally the strings --spring.profiles.active=${profile} and ${JAVA_OPTS}, and you will see these including the ${...} markers in your Java program's main() function.
Docker's normal assumption here is that any expansion like this will be done in a shell, and shell form CMD will wrap its string in /bin/sh -c '...' so this happens. However, this setup isn't compatible with splitting ENTRYPOINT and CMD: due to the mechanics of how the two parts are combined neither part can be wrapped in a shell if you're using the "container as command" pattern where the CMD is just an argument list.
The easiest way to handle this is to ignore ENTRYPOINT entirely; put all of the command and arguments into CMD; and use the shell form rather than the exec form.
ENV JAVA_OPTS="--XX:MinRAMPercentage=50.0 --XX:MaxRAMPercentage=80.0"
# no ENTRYPOINT; shell form of CMD
CMD java ${JAVA_OPTS} -jar /app/app.jar --spring.profiles.default=${profile}
If you docker run a temporary debugging container on this image, it will see the environment variable but the command you provide will replace the image's CMD.
docker run --rm your-image \
/bin/sh -c 'echo $JAVA_OPTS'
# prints the environment setting
Correspondingly if you run a separate java, it won't see the options that are only provided in the image's CMD. (Similarly try running java -XX:MaxRamPercentage=80.0 in one terminal window, and java -XX:+PrintFlagsFinal with no other options in another window, and the second invocation won't see the JVM options from the first JVM; the same mechanics apply to Docker containers.)
I have a script that ideally will be used in two different ways. One, run stand-alone from command line. Two invoke from a service script located in /etc/init.d.
I would like the script (call it run_app.sh) to work as follows:
#/bin/bash
# this is run_app.sh. It should be able to be run stand-alone or called from another script
if [ invoked by a calling script ] then
java -cp . -jar blah.jar
else
nohup java -cp . -jar blah.jar 2>&1 &
, so its the "invoked by a calling script" that I would need help with. Thank you.
If you plan to launch your script either by issuing ./run_app.sh or the service. You can just use $0:
#!/bin/bash
# this is run_app.sh. It should be able to be run stand-alone or called from another script
this_script_name="run_app.sh"
if [ "$0" == "./${this_script_name}" ] then
java -cp . -jar blah.jar
else
nohup java -cp . -jar blah.jar 2>&1 &
Instead of trying to find out how the script was called, I suggest to use a command line argument.
Script app.sh
#/bin/bash
# this is run_app.sh. It should be able to be run stand-alone or called from another script
if [ "$1" = "--service" ] then
java -cp . -jar blah.jar
else
nohup java -cp . -jar blah.jar 2>&1 &
fi
Manually run the script as app.sh, from the calling script run app.sh --service.
If you need to pass additional command line arguments to your script, you might have to implement some better option parsing.
Note: Checking $0 may work under certain conditions, but may not work in some other cases. Trying to find out details about the parent processes is even more difficult and fragile.
Another note: Your java command line arguments -cp . -jar blah.jar depend on the current directory. To make sure this works in all cases, the script should cd into the correct directory before calling java. e.g. cd $(dirname "$0") if the script is located in the same directory as blah.jar.
I have a .jar file I want to run whenever the system reboots/starts, so I put the line
nohup java -jar /mnt/fioa/fusion/nfs/labStats/LabInfoAutoLog.jar > /dev/null &
in my /etc/rc.local file. The program is validated as working, and if I run the above command at the command line the program works as expected.
Other versions I have tried without success:
nohup /usr/bin/java -jar /mnt/fioa/fusion/nfs/labStats/LabInfoAutoLog.jar > /dev/null &
and:
nohup java -jar /mnt/fioa/fusion/nfs/labStats/LabInfoAutoLog.jar 2> /dev/null \ .. &
I am running centos 6.4.
Check that your jar file is accesible roots, NFS mounted volumes may impose special restrictions for root.
Instead of discarding your error messages, you might want to route them to syslog, something like 2> /sbin/logger -t FOO 1> /sbin/logger -t BAR
Maybe the path isn't set yet at startup time and you need the full path to the java executable or, possibly, nohup.
I'm trying to run a java process via Powershell in Windows XP. Here's the command:
java.exe -cp .;./common.jar -Dcontext=atest1 -Dresourcepath=. DW_Install
So, the classpath is . and .\common.jar (I think java takes the wrong slashes, right?) There are two environment variables, one "atest1" the other "." and the class to execute main on is DW_Install (in the default package).
This command works in cmd.exe, but doesn't is PS. What's going on? What is PS doing while parsing this command that CMD doesn't do (or vice versa)?
Aaron
The problem is that PS for some reason parses -Dresourcepath=. differently than cmd. What works is
java -cp '.;.\common.jar' -Dcontext=atest1 "-Dresourcepath=." DW_Install
It doesn't matter which way the slash goes, and it doesn't matter which quotes one uses (' or "). The classpath must be escaped, however, with some kind of quotes. A good test to see what's getting by the PS interpreter is to echo it. The following:
echo java -cp '.;.\common.jar' -Dcontext=atest1 -Dresourcepath=. DW_Install
yields the following output:
java
-cp
.;.\common.jar
-Dcontext=atest1
-Dresourcepath=
.
DW_Install
(Notice the resourcepath and the value of resourcepath are not on the same line.) Whereas the output to
echo java -cp '.;.\common.jar' -Dcontext=atest1 '-Dresourcepath=.' DW_Install
yields the following output:
java
-cp
.;.\common.jar
-Dcontext=etaste1
-Dresourcepath=.
DW_Install
Which is much more to our liking.
Although I wish this upon none of you, I hope that this post helps those of you that must deploy java projects on Windows machines (even though they will not run on any other platform ever).
Running external command-line programs from PowerShell is sometimes a bit problematic because there PowerShell exposes two different parsing modes that get trumped by the different syntaxes of said external programs.
In any case, running a command in Powershell requires using either the . prefix (dot-"sourcing") or the & operator.
You can workaround this by passing each parameter to the external program as separate variables, like so:
PS> $classpath = ".;./common.jar"
PS> $env = "-Dcontext=atest1 -Dresourcepath=."
PS> $class = "DW_Install"
PS> . java.exe -cp $classpath $env $class
Another example based on https://gaming.stackexchange.com/questions/24543/how-do-i-change-player-name-in-minecraft-multiplayer-in-offline-mode-in-linux
function mineCraftAs {
Param (
[parameter(mandatory=$true, HelpMessage="Minecraft character name." ,ValueFromPipeline=$true)]
[string] $name
)
if(!(test-path $env:appdata)) { $(throw "Appdata not found at $env:appdata")}
$private:minecraftPath=Join-Path $env:appdata .minecraft
if(!(test-path $minecraftPath)) { $(throw "Minecraft not found at $minecraftpath")}
$private:minebinPath=join-path $minecraftPath "bin"
if(!(test-path $minebinPath)) { $(throw "Minecraft bin not found at $minebinPath")}
$minebinPath | write-debug
gci $minebinpath | write-debug
#java -Xms512m -Xmx1024m -cp "%APPDATA%/.minecraft\bin\*" -Djava.library.path="%APPDATA%\.minecraft\bin\natives" net.minecraft.client.Minecraft '"'%1'"'
echo java -Xms512m -Xmx1024m -cp ('"'+$minebinPath+'\*"') ('-Djava.library.path="'+$minebinPath+'\natives"') net.minecraft.client.Minecraft ($name)
$minecraftJob=& 'C:\Program Files (x86)\Java\jre6\bin\java.exe' -Xms512m -Xmx1024m -cp ('"'+$minebinPath+'\*"') ('-Djava.library.path="'+$minebinPath+'\natives"') net.minecraft.client.Minecraft ($name)
}
minecraftas newbie
The following should work:
java.exe -cp '.;./common.jar' -Dcontext=atest1 -Dresourcepath=. DW_Install
I guess that PowerShell interprets the ; in the classpath as command delimiter, thereby trying to run java -cp . and ./common.jar -D....
start-process -nnw java "-cp .;./common.jar -Dcontext=atest1 -Dresourcepath=. DW_Install"
I've been experiencing a strange issue the last couple of days while writing a shell script which executes Java (starting the JBoss AS). I have a variable JAVA_OPTS that I am creating, and finally passing to the 'java' command. When I hard code the values in JAVA_OPTS rather than using variable expansion, the java process executes normally. When I use variable expansion, I get errors from the java executable. Here is the relevant portions of the script:
SERVER="-server"
MEM_OPTS="-Xms512m -Xmx1024m"
case "$1" in
start)
java "$SERVER" "$MEM_OPTS" $JAVA_OPTS \
-classpath "${JBOSS_CLASSPATH}" \
-Dorg.jboss.resolver.warning=true \
-Dsun.rmi.dgc.client.gcInterval=3600000 \
-Dsun.rmi.dgc.server.gcInterval=3600000 \
-Djboss.server.name=${SERVICE_NAME} \
-Djboss.server.base.dir=`dirname ${EC_APP_HOME}` \
-Djboss.server.base.url=file://`dirname ${EC_APP_HOME}` \
-Djboss.server.home.dir=${EC_APP_HOME} \
-Djboss.server.home.url=file://${EC_APP_HOME} \
org.jboss.Main >> out.log 2>&1 &
Executing this gives the following:
Invalid initial heap size: -Xms512m -Xmx1024m
Could not create the Java virtual machine.
However when I remove the variable expansion like so:
java "$SERVER" -Xms512m -Xmx1024m $JAVA_OPTS \
java executes no problems. As an aside, when I include "-server" in the MEM_OPTS var, I get the error "unrecognized option".
So obviously, there is something up with the variable expansion. I've hexdump'd the script, and made sure there are no extra characters in the string, and verified that I'm using Unix line endings. I've also reproduced the problem on two different linux machines, albeit both running the same version of ubuntu (one 32bit, the other 64bit).
EDIT: I get the same result with all forms of variable substitution: $MEM_OPTS, ${MEM_OPTS}, "${MEM_OPTS}"
Any ideas?
When you use "$MEM_OPTS", you're passing -Xms512m -Xmx1024m as a single option.
Try this instead:
java "$SERVER" $MEM_OPTS $JAVA_OPTS \
A good guide to variable substitution and quoting with examples: http://tldp.org/LDP/abs/html/varsubn.html
I am not 100% sure about the semantics of the quotes, but "$MEM_OPTS" may create a single argument "-Xms512m -Xmx1024m", whereas the JVM needs to see two seperate arguments. Can you try without the quotes?
java $SERVER $MEM_OPTS $JAVA_OPTS
think it should work if the quotes around $MEM_OPTS are removed, as the quotes tell bash to pass the expanded contents as a single token argument to execv()
My mistake - I was setting IFS to "\n" only in a script I sourced in, functions.sh. I was never resetting the IFS to "\n\t ", so the variables were not split on spaces.
Thanks for the responses!
It should be a simple matter of changing:
java "$SERVER" "$MEM_OPTS" $JAVA_OPTS \
to:
java "$SERVER" $MEM_OPTS $JAVA_OPTS \
so that the memory options are passed as two arguments.
But, since you say that doesn't work (?), please try the following.
A) Create a shell script fakejava.sh containing:
#!/usr/bin/bash
echo $#
while [[ $# -ne 0 ]] ; do
echo " [$1]"
done
(you may need to alter that first line if your bash is somewhere else: use which bash to figure out where).
B) Set its permissions correctly:
chmod 700 fakejava.sh
C) Replace your entire java command with:
./fakejava.sh "$SERVER" $MEM_OPTS $JAVA_OPTS xx
and see how many arguments there actually are. I get:
5
[-server]
[-arg1]
[-arg2]
[none]
[xx]
from the controlling script:
#!/usr/bin/bash
JAVA_OPTS="none"
SERVER="-server"
MEM_OPTS="-arg1 -arg2"
./fakejava.sh "$SERVER" $MEM_OPTS $JAVA_OPTS xx