I'm writing an application that leverages jsvc to start up a Java service as a daemon. I need to use something like jsvc because my application utilizes ports under 1024 and yet I'd really like to not run it as root so that created files are owned by another user. I'd also like to keep dependencies and configuration to a minimum so that all the client needs is a JVM and the jsvc binary installed.
However, it seems that jsvc has one major catch; it can't detect the home folder of Java on a given Unix operating system, which is quite frustrating:
$ ./startup.sh
Cannot locate Java home
I have been able to work around the issue on Ubuntu at least by manually setting the JVM home directory:
jsvc ... -home /usr/lib/jvm/default-java/ ...
Is there any way to determine the Java home directory dynamically from a Bash script so I can make this work across most Unixes/Linuxes? I'd be able to sleep much better at night doing something like:
JAVA_HOME="$( ... )"
jsvc ... -home "$JAVA_HOME" ...
...rather than hard-coding for each individual operating system. Is there a way that, given a java binary, I can find the home directory of its JVM/JRE?
Not sure if this works across *nixes, but found this solution:
JAVA_HOME="$( readlink -f "$( which java )" | sed "s:bin/.*$::" )"
I've tested it on Ubuntu and it works, however it does not work for OSX.
My solution was compiling the native linux source as the main jsvc page says in
http://commons.apache.org/proper/commons-daemon//jsvc.html
Here is my step by step procedure
Download www.fightrice.com/mirrors/apache/commons/daemon/source/commons-daemon-1.0.13-src.tar.gz
Once you extract the file then go to ...../commons-daemon-1.0.13-src/src/native/unix
in terminal as a root do the following:
$ support/buildconf.sh
$ ./configure --with-java=/usr/lib/jvm/default-java
$ make
test generated jsvc binary app
$ ./jsvc -help
It works! cleanly.
Use dirname and which commands to find Java's bin directory:
echo `dirname \`which java\``
JAVA_HOME=`dirname \`which java\``
... Only works if Java is already on the $PATH.
One other way is :
type -p java
Expect this to return the correct JAVA installation folder.
Related
After a research in google i found good answers like:
1)using jps or jps -l to get the jars running under JVM
OK with this answer but if the user has not java installed at all and i run my jar using for example a .bat file and a folder with java JRE.
Also gps function is experimental and only JDK contais it and not JRE.
2)Check if jar running from shell
I need a solution for this on windows platform.Although a platform indepedent solution is always prefferable.
Something more about jps(cause it is Platform Independent) I will appreciate an answer where you provide me a good solution with jps function.
use this command to check the jar is running or not.
ps aux | grep java
eg:
sys_name 7526 60.1 2.6 4474364 104092 pts/4 Sl+ 23:57 0:09 java -jar start.jar
You can us ps and grep on a *nix system as described above. For windows you can do:
tasklist /v /FI "IMAGENAME eq java.exe"
This will get you a list of all the Java programs running. I don't think you can get much closer on Windows.
To test this, pick a .exe file you see running in Task Manager and test out the cmd line.
If you see the following output :
No tasks are running which match the specified criteria
That means there is no task running equal to java.exe.
Use the following command:
ps aux | grep java
I just want to be able to do ./whatever.jar instead of java -jar whatever.jar.
I've found a way:
#!/bin/bash
java -jar $0 $*
exit
# jar goes here...
but it doesn't work. Java just complains that it's an invalid/corrupt jarfile.
I also tried piping:
#!/bin/bash
tail -n +4 $0 | java -jar
exit
# jar goes here...
but this doesn't work.
One way to do it is to somehow split the file into two separate parts (the script part and the jar part), and then execute the jar, but that'd be redundant. You'd might as well make a script that executes the jar and execute that script.
So I need to figure out how to somehow tail it and fake the file.
I thought I could do it using /dev/stdout:
#!/bin/bash
java -jar /dev/stdout
tail -n +5 $0
exit
# jar goes here...
That doesn't work either. It just prints the contents of the jar and java complains that it's invalid. (I figured out later that there's nothing to read in /dev/stdout)
So I need to read from stdout some other way. I really wish I could pipe it though. It would make things SO much easier :)
You need a service called jexec some linux distros come with this installed check for /etc/init.d/jexec. My CentOS 5.5 definitely does.
What it does is register the jexec interpreter with the binfmt system.
For more information you might what to have a quick read of binfmt_misc.
Assuming you have the kernel source code installed, check out /usr/src/linux/Documentation/java.txt for a way to run Java code directly using the kernel's BINFMT_MISC support (assuming it's compiled into the version of the kernel you're running, but I think it is on most major distros). If you don't have the source installed, you should be able to find it online easy enough (here's one example).
FYI, if you wanted to do it your original way it would go like this:
$ cat jar.sh
#!/usr/bin/env bash
java -jar <(tail -n +4 "$0")
exit
$ cat jar.sh runme.jar > works.jar
$ chmod a+x works.jar
$ ./works.jar
Presuming a recent bash with support for <()
java -jar does not work with stdin, apparently it does some seeks rather than straight reads.
On a system you can't mod, you have to use a tmp. for example.
#!/bin/bash
JF=/tmp/junk$$.jar
(uudecode -o /dev/stdout >$JF;java -jar $JF;unlink $JF) <<JAR
begin-base64 644 junk.jar
UEsDBBQACAAIAEaBz0AAAAAAAAAAAAAAAAAJAAQATUVUQS1JTkYv/soAAAMA
UEsHCAAAAAACAAAAAAAAAFBLAwQUAAgACABGgc9AAAAAAAAAAAAAAAAAFAAA
AE1FVEEtSU5GL01BTklGRVNULk1G803My0xLLS7RDUstKs7Mz7NSMNQz4OVy
LkpNLElN0XWqBAmY6RnEG5koaASX5in4ZiYX5RdXFpek5hYreOYl62nycvkm
ZubpOuckFhdbKWSV5mXzcvFyAQBQSwcIBHn3CVkAAABZAAAAUEsDBBQACAAI
AEd+z0AAAAAAAAAAAAAAAAAKAAAAanVuay5jbGFzc21QTUvDQBB926RJE6Ot
ramfhXoQogcDXiteBPFQVIjowdOmXcrGZCMxEfxZelDw4A/wR4mzUShCF3Zn
9s2bt2/26/vjE8ARBi4stB10sNpC10UPazZ8G30G61gqWZ4wGMH+DYN5mk8F
Q3sslbioslgU1zxOCTEzLhVDP7gbJ/yJhylXszAqC6lmI93oRnlVTMSZ1GQn
qdT9oeZ5sNGyse5hA5sM3rlI03x4mxfpdNfGlodt7JC45jN05sqXcSIm5T8o
en4sRUZG84oK/q8NmYdX5KEkJ4JnI4beApjBftC3lAbwg0X+MUSTvkivBm3y
DJqCsgFFRrF58A72QglNSqdVg5qyBO+PuketGnVe0egabzDndLdWNUjVJGS5
fmXlB1BLBwjDUWL/IAEAAJ4BAABQSwECFAAUAAgACABGgc9AAAAAAAIAAAAA
AAAACQAEAAAAAAAAAAAAAAAAAAAATUVUQS1JTkYv/soAAFBLAQIUABQACAAI
AEaBz0AEefcJWQAAAFkAAAAUAAAAAAAAAAAAAAAAAD0AAABNRVRBLUlORi9N
QU5JRkVTVC5NRlBLAQIUABQACAAIAEd+z0DDUWL/IAEAAJ4BAAAKAAAAAAAA
AAAAAAAAANgAAABqdW5rLmNsYXNzUEsFBgAAAAADAAMAtQAAADACAAAAAA==
====
JAR
Or I could just install the jarwrapper (Ubuntu) package.
Write a separate shell script:
whatever.sh
#!/bin/bash
java -jar whatever.jar $*
You can't make the JAR file directly executable because it's not an executable file. It's Java bytecode which can't be read directly by the machine nor any standard shell interpreter that I know of.
My java program was written on a windows machine and I am trying to get it installed and running on a Ubuntu 10.04 machine. I have created a .tar.gz file with myProgram.jar in it as well as 5 supporting library .jar files in a lib folder. Where do I put these files? Do I need to extract it on the Linux machine to a usr/bin folder? Does the shell script go inside the tar.gz? I have read that if you write the shell script on a windows machine you can have issues once you move it to the Linux machine, so I am writing the shell script on the Linux machine using gedit. I am just not sure what to do next.
So far in my script I have,
#!/bin/bash
java -jar myProgram.jar
I am going to try and extract the tar.gz file to the usr/bin directory and see if it runs.
Any suggestions or help would be greatly appreciated.
Thanks in advance,
Ray
Your question is quite "broad" :). I hope you find the following useful.
Do not extract the files to /usr/bin. See e.g. http://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard on where and where not to put files on a *nix system.
Extract the jar's to e.g. /opt/yourProgram/*.
The shell script should be inside there too. Make sure its executable (i.e chmod 755 script.sh)
In your shell script add cd /opt/yourProgram to have the proper working directory for your program before you invoke java.
If you want this program to be started easily by everyone create a symbolic link in /usr/bin or better in /usr/local/bin pointing to your script. Do this as last step after everything else is working.
In your shell script you'll have to add the other jars to the classpath e.g.
java -cp lib/some.jar:lib/other.jar -jar myProgram.jar
or
java -cp lib/some.jar:lib/other.jar:myProgram.jar com.acme.ClassContainingMain
Recommended practice: Add set -e at the very beginning of your script
As you already mentioned it's considered harmful to edit a shell script using a windows editor. The reason is that the windows editor will encode line-breaks (i.e. you hit the Return key) differently. This will make bash puke :)
Im not too clear of what you are looking for.
The script that you have written should work absolutely fine if you have placed your script and myprogram.jar at the same level.
And also im not sure how your myprogram.jar is referring the dependent libraries. So can't comment on them. Best bet will be to place your script and all jars together and try running the script.
I'm using gvim as my main 'IDE' on windows 7 and I would like to use ctags to navigate through the code. I've downloaded it and ran based on this tutorial: http://www.techrepublic.com/article/configure-vi-for-java-application-development/5054618
ctags -f ~/.tags -R ~/myprojects/src $JAVA_HOME/src
I've then setup my vimrc with...
set tags=~/.tags
However when I do Ctrl+] on a keyword, it says it can not find the file which the tag is defined in. Shows the correct path except it misses out c:\ from the start so vim can't load it.
How can get it to give me the correct path?
I'm using the latest version of gvim and ctags.
Thanks
FWITW, I'm not entirely sold on the concept of keeping my tags in one location.
This part of the command call:
-f ~/.tags
Nor would I hard path to my current project. This part:
-R ~/myprojects/src
BTW, Windows doesn't have ~ so I don't think either of those would work (not sure if Vim will find ~, i.e. "home").
If I were you, I would cut my teeth on the simplest method until you get more comfortable with the Vim methods and ideals.
Easiest method:
Always let Vim know the "Current Directory" (making the assumption that you are not launching Vim via the command prompt). When you open a file always set the current directory by issuing the following command from normal mode:
:cd %:p:h
Generate a tag file in the current directory with the following command (from normal mode).
:!ctags -R .
Happy jumping.
I need to get a stack trace for a JVM process running on a client machine that uses windows.
The client has the JRE installed but not the JDK.
I want to use JStack but it is not installed and we can't install a JDK on the client's machine. I also tried using AdaptJ stack trace product from a Java Webstart Session but that didn't work because we remote in and get an error about not being the session that started the application at a specified PID.
Essentially I want a way to install JStack without installing the JDK.
You probably want to use SendSignal, which was designed for exactly this purpose.
The JDK and associated tools work fine whether "installed" or not, if you just zip up and extract it to a temporary directory, you should be able to run jstack. (No PATH or JAVA_HOME modifications necessary). Just make sure you use the same version that corresponds to the JRE your client has the application running with. At least in the case of JConsole, it seems to fuss if the versions are different. I'm not sure if jstack behaves the same way.
I'm not saying this is the ideal solution, just that it would work. I think jdigital and Eddie's suggestions are better first bets, and even though this shouldn't interfere with an existing java installation the same way running the installer would, the customer may disagree regardless.
jstack and jps are part of tools.jar of the JDK.
Also attach.dll is required to attach jstack to a process.
Ofcourse the tools.jar and attach.dll are not part of JRE.
To make jstack work on a systems which has no JDK (mostly Windows), I usually do the following.
Copy tools.jar and attach.dll from JDK and put in to some location
on the target system. Example: to c:\temp\jstack
Write a bat script to manually invoke it using JRE.
For example, create a bat file jstack.bat:
set JRE=c:\jrefolder
"%JRE%\bin\java" -classpath "c:\temp\jstack\tools.jar" -Djava.library.path="c:\temp\jstack" sun.tools.jstack.JStack %*
Similarly for jps, create a jps.bat with following content.
set JRE=c:\jrefolder
"%JRE%\bin\java" -classpath "c:\temp\jstack\tools.jar" -Djava.library.path="c:\temp\jstack" sun.tools.jps.Jps %*
Usage:
jstack.bat -l <pid>
Hope this helps.
Would you be able to use JConsole via remote access?
To get a thread dump with only a JRE you need tools.jar and attach.dll from the JDK of the same Java version. Install this somewhere and copy these into the jre. Must be identical version!
If you need a dump of a process running under the system account you can use the Windows sysinternals psexec.exe to gain access to the process. Copy this into the JRE bin or somewhere in the path.
This batch file writes the stack dump to a file with a datetime filename so multiple traces can be taken and compared easily.
Threads.bat
:: Creates a thread dump for the tomcat6.exe process
:: saved in a timestamped filename and views it!
:: Jim Birch 20111128 rev 2015-10-12
::Required the following files to be placed in the jre/bin folder:
:: attach.dll - From the Java JDK (must be the same version)
:: tools.jar - ditto
:: psexec.exe - from Windows sysinternals
::cd to jre/bin
d:
cd \application\jre\bin
::build datetime filename
rem datetime from wmi.exe
for /f "tokens=2 delims==" %%I in ('wmic os get localdatetime /format:list') do set dt0=%%I
rem datetime string as YYYY-MM-DD-hhmmss
set dt=%dt0:~0,4%-%dt0:~4,2%-%dt0:~6,2%-%dt0:~8,6%
set ff=td-%dt%.txt
echo filename: %ff%
::PID of the process by named exe, eg, tomcat6
for /F "tokens=2" %%I in ('TASKLIST /NH /FI "IMAGENAME eq tomcat6.exe"' ) DO SET PID=%%I
echo pid: %PID%
::combine above with jstack command
psexec -s jstack.exe -l %PID% >> %ff%
:: view result
start %ff%
::insert pause to debug or timer to review script operation
::ping localhost -n 20 >nul
::pause
If you want to use the on-board tools of the JDK and also want to both have a minimal (i.e., not including copying the whole JDK) and convenient (i.e. not invoking with a custom .bat) solution, this works for me (tried on Java 1.8):
Create an empty folder ($DEST below) and copy the following files (from the JDK $JDK_HOME) into bin and lib folders as follows:
Source -> Destination
$JDK_HOME/bin/jps.exe -> $DEST/bin/jps.exe
$JDK_HOME/bin/jstack.exe -> $DEST/bin/jstack.exe
$JDK_HOME/bin/jli.dll -> $DEST/bin/jli.dll
$JDK_HOME/jre/bin/attach.dll -> $DEST/bin/attach.dll
$JDK_HOME/lib/tools.jar -> $DEST/lib/tools.jar
Then ZIP and copy this over to the destination machine running a compatible JRE.
You should be able to run jps and jstack from the bin folder now as you would run them from the original JDK.