Apache Commons Daemon will run your Java program as Linux daemon or WinNT Service.
Answer from Bahaa Zaid on Stack OverflowApache Commons Daemon will run your Java program as Linux daemon or WinNT Service.
If you can't rely on Java Service Wrapper cited elsewhere (for instance, if you are running on Ubuntu, which has no packaged version of SW) you probably want to do it the old fashioned way: have your program write its PID in /var/run/$progname.pid, and write a standard SysV init script (use for instance the one for ntpd as an example, it's simple) around it. Preferably, make it LSB-compliant, too.
Essentially, the start function tests if the program is already running (by testing if /var/run/$progname.pid exists, and the contents of that file is the PID of a running process), and if not run
logfile=/var/log/$progname.log
pidfile=/var/run/$progname.pid
nohup java -Dpidfile=$pidfile $jopts $mainClass </dev/null > $logfile 2>&1
The stop function checks on /var/run/$progname.pid, tests if that file is the PID of a running process, verifies that it is a Java VM (so as not to kill a process that simply reused the PID from a dead instance of my Java daemon) and then kills that process.
When called, my main() method will start by writing its PID in the file defined in System.getProperty("pidfile").
One major hurdle, though: in Java, there is no simple and standard way to get the PID of the process the JVM runs in.
Here is what I have come up with:
private static String getPid() {
File proc_self = new File("/proc/self");
if(proc_self.exists()) try {
return proc_self.getCanonicalFile().getName();
}
catch(Exception e) {
/// Continue on fall-back
}
File bash = new File("/bin/bash");
if(bash.exists()) {
ProcessBuilder pb = new ProcessBuilder("/bin/bash","-c","echo $PPID");
try {
Process p = pb.start();
BufferedReader rd = new BufferedReader(new InputStreamReader(p.getInputStream()));
return rd.readLine();
}
catch(IOException e) {
return String.valueOf(Thread.currentThread().getId());
}
}
// This is a cop-out to return something when we don't have BASH
return String.valueOf(Thread.currentThread().getId());
}
Videos
You can run a Java application as a service (Windows) or daemon (Linux) using the Apache Commons daemon code.
Structure
Daemon is made of 2 parts. One written in C that makes the interface to the operating system and the other in Java that provides the Daemon API.
Platforms
Both Win32 and UNIX like platforms are supported. For Win32 platforms use procrun. For UNIX like platforms use jsvc.
Java code
You have to write a Class (MyClass) that implements the following methods:
* void load(String[] arguments): Here open the configuration files, create the trace file, create the ServerSockets, the Threads
* void start(): Start the Thread, accept incoming connections
* void stop(): Inform the Thread to live the run(), close the ServerSockets
* void destroy(): Destroy any object created in init()
You can turn any Java program into a service/daemon using the Java Service Wrapper. It is used by multiple OSS projects, and ships as part of the Nexus Maven Repository Manager so that it can be installed as a service out of the box. To use it, you, the author, just need to create a configuration file and then run a simple batch file to create the service on Windows or copy an init script to the correct runlevel on Linux.
A daemon thread is a thread that does not prevent the JVM from exiting when the program finishes but the thread is still running. An example for a daemon thread is the garbage collection.
You can use the setDaemon(boolean) method to change the Thread daemon properties before the thread starts.
A few more points (Reference: Java Concurrency in Practice)
- When a new thread is created it inherits the daemon status of its parent.
When all non-daemon threads finish, the JVM halts, and any remaining daemon threads are abandoned:
- finally blocks are not executed,
- stacks are not unwound - the JVM just exits.
Due to this reason daemon threads should be used sparingly, and it is dangerous to use them for tasks that might perform any sort of I/O.
Services on Linux are just shell scripts which start background processes. Have a look in /etc/init.d - you can open the files in a text editor. All you need is a bash script which responds to the parameters start and stop in an appropriate way (eg. start will start your service and record the process ID in a known location, stop will kill the process with the PID from the file you created), and then place it in /etc/init.d.
Have a look at Init Scripts and An introduction to services, runlevels, and rc.d scripts
As far as I know there isn't a Maven plugin for either Apache Daemon or Akuma. Though you could attempt to invoke them from within a Maven build by using the maven-exec-plugin.
As far as your companies reservations about using GPL-licensed products, it's worth reading up on the implications of use. It is not as virulent as corporations fear. Here's an interpretation of the GPL. It of course doesn't carry any weight in law (and may not be correct or supported by precedent, I am not a lawyer), but might be sufficient to allow you to start a conversation with your legal people.
From the referenced page:
Simply combining a copyrighted work with another work does not create a derivative work. The original copyrighted work must be modified in some way. The resulting derivative work must itself "represent an original work of authorship." So if the licensee does not modify the original GPL-licensed program, but merely runs it, he is not creating a derivative work.
There is the Appassembler Maven plugin that I think does what you need (though it does create JSW wrappers). It creates a shell script (and a bat file), and collects all the application jars into a directory. It can optionally be configured to create JSW-based Daemon configurations.
Here is an example configuration that will generate the standalone application in the target/appassembler folder, and generate the JSW wrapper files in the target/appassembler/jsw/myApp directory. Note the assemble goal is bound to the integration-test phase to ensure the project's jar is created. To generate the output run mvn verify or to just generate the service wrappers run mvn package:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>appassembler-maven-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<id>assemble-standalone</id>
<phase>integration-test</phase>
<goals>
<goal>assemble</goal>
</goals>
<configuration>
<programs>
<program>
<mainClass>name.seller.rich.MyMainClass</mainClass>
<name>myShellScript</name>
</program>
</programs>
<platforms>
<platform>windows</platform>
<platform>unix</platform>
</platforms>
<!--collect all jars into the lib directory-->
<repositoryLayout>flat</repositoryLayout>
<repositoryName>lib</repositoryName>
</configuration>
</execution>
<execution>
<id>generate-jsw-scripts</id>
<phase>package</phase>
<goals>
<goal>generate-daemons</goal>
</goals>
<configuration>
<!--declare the JSW config -->
<daemons>
<daemon>
<id>myApp</id>
<mainClass>name.seller.rich.MyMainClass</mainClass>
<commandLineArguments>
<commandLineArgument>start</commandLineArgument>
</commandLineArguments>
<platforms>
<platform>jsw</platform>
</platforms>
</daemon>
</daemons>
<target>${project.build.directory}/appassembler</target>
</configuration>
</execution>
</executions>
</plugin>
For reference the generated files are as follows:
myApp\bin\myApp
myApp\bin\myApp.bat
myApp\bin\wrapper-linux-x86-32
myApp\bin\wrapper-macosx-universal-32
myApp\bin\wrapper-solaris-x86-32
myApp\bin\wrapper-windows-x86-32.exe
myApp\conf\wrapper.conf
myApp\lib\libwrapper-linux-x86-32.so
myApp\lib\libwrapper-macosx-universal-32.jnilib
myApp\lib\libwrapper-solaris-x86-32.so
myApp\lib\wrapper-windows-x86-32.dll
myApp\lib\wrapper.jar
The same way you make any program run as a daemon regardless of the language it has been written in!
Read the documentation for systemd. At a minimum, you will have to create something like /etc/systemd/system/yourprogram.service. There are way too many options that you need to set depending on exactly what your program does. In all likelihood, all the defaults will be fine.
Services are managed by systemd. Just start with a simple Unit file:
rpi ~$ sudo systemctl --full --force edit myjar.service
In the empty editor insert these statements, save them and quit the editor:
[Unit]
Descrition=My jar service
After=multi-user.target
[Service]
Environment="ENV_VAR_FOR_JAR=something"
ExecStart=/absolute/path/to/myprogram.jar
[Install]
WantedBy=multi-user.target
To manage the service just use:
rpi ~$ sudo systemctl start|stop|restart myjar.service
rpi ~$ sudo systemctl --full edit myjar.service # edit the Unit again
rpi ~$ systemctl status myjar.service
If you want to start the service at boot up, then do
rpi ~$ sudo systemctl enable myjar.service
If this doesn't run on the first attempt (very likely) then ask again so we can look what other special settings your program needs. Have a look at man systemd.exec for some options.