Recently, I wanted to take a Java command line program and turn it into a Windows Service. There are a number of ways to do this, but I decided to try out the Apache Commons Daemon project (http://commons.apache.org/daemon/).
It is actually very simple to turn your Java Program into a service with Commons Daemon but, if you’re like me, you will very quickly become confused by browsing the project page, so here are some tips.
Procrun
On the Commons Daemon homepage, under the "Platforms" section you’ll see that it says "For win32 platforms use procrun". Procrun is actually an umbrella term for a set of libraries and applications. The applications we are concerned with are called "prunsrv" and "prunmgr".
The "prunsrv" application is the Windows Service binary. It is native windows binary that runs as a windows service and starts up an embedded JVM to run your Java code in (it can run in other modes, but "embedded JVM" was all I cared about). The "prunmgr" is a GUI application to start/stop and configure the service. It can also be run in the system tray where its icon will show the current state of the service (running or stopped). The Commons Daemon homepage has a link in its left navigation called "Procrun" which has documentation for these two applications.
So where do you download the "prunsrv" and "prunmgr" binaries? That is the confusing part! Your first instinct will be to click the "Download" link on the Commons Daemon home page, but that only has a download for UNIX. Next, you’ll click the "Procrun" link, but that only has documentation. Last, you’ll click on the "Native binaries" link, but that page has nothing but a link back to the documentation.
After a bit of googling, and sifting through a lot of "where do I download procrun?" postings, I found that the Commons Daemon project does not provide binaries for these applications. The only binaries available are from the Tomcat project. Tomcat comes with 2 windows binaries: tomcat6.exe and tomcat6w.exe. It turns out that these are "prunsrv" and "prunmgr" respectively!
You can download the binaries without downloading Tomcat (or to get 64 bit versions) here:
http://svn.apache.org/repos/asf/tomcat/tc6.0.x/trunk/res/procrun/
The Daemon Java Interface is not used!
The next thing that confused me was that the Commons Daemon project has a Java API, that revolves around an interface called "Daemon". This interface has methods one would expect in a service such as start/stop and initialize/destroy methods.
My assumption was that you needed to implement the Daemon interface to have Procrun interact with your java application. I spent a lot of time trying to figure out how this worked (the Procrun documentation makes no mention of this interface). Well, it turns out that this interface is not used at all by the Procrun application. (It might be used by the UNIX daemon binary, I’m not sure.) If your only goal is to create a Windows Service, don’t bother with the Daemon Java interface.
Writing a Service
Procrun will call a static method that takes a String array as its only argument to start your service. By default, Procrun will look for and call static void main(String[] args) as the startup method, but you can configure any method name. Procrun will also call a static method that takes a String array as its only argument to stop your service. Again, it will default to static void main(String[] args), but this is also configurable.
The idea is that your "main" method will determine whether the service is starting or stopping based on the arguments. You can specify different static methods for start and stop, but they still must have a single String array for its argument.
(Note: Another thing that had confused me was that you will get the message "Static method 'void main(String[])' not found" if Procrun can’t find your start/stop method, even if you specify a method name other than “main”)
The service will be considered in "running" state for as long as your "start" method blocks. Procrun will run your start method in a worker thread, and monitor that thread for your method to return.
Sample Java Service: "MyService"
I created a sample Java service called "MyService", which is a simple class that just logs a message to standard out ever minute.
Below is a simplified sequence diagram of how Procrun starts and stops the MyService class.

Below is the code for the MyService class:
package com.platinumsolutions;
/**
* Simple service class that writes a
* message to standard out every minute.
*/
public class MyService {
/**
* Single static instance of the service class
*/
private static MyService
serviceInstance = new MyService();
/**
* Static method called by prunsrv to start/stop
* the service. Pass the argument "start"
* to start the service, and pass "stop" to
* stop the service.
*/
public static void windowsService(String args[]) {
String cmd = "start";
if(args.length > 0) {
cmd = args[0];
}
if("start".equals(cmd)) {
serviceInstance.start();
}
else {
serviceInstance.stop();
}
}
/**
* Flag to know if this service
* instance has been stopped.
*/
private boolean stopped = false;
/**
* Start this service instance
*/
public void start() {
stopped = false;
System.out.println("My Service Started "
+ new java.util.Date());
while(!stopped) {
System.out.println("My Service Executing "
+ new java.util.Date());
synchronized(this) {
try {
this.wait(60000); // wait 1 minute
}
catch(InterruptedException ie){}
}
}
System.out.println("My Service Finished "
+ new java.util.Date());
}
/**
* Stop this service instance
*/
public void stop() {
stopped = true;
synchronized(this) {
this.notify();
}
}
}
Deploying the Sample Java Service
I will be using the following folder hierarchy for my sample service:
C:\MyService
\bin
\myService.exe
\myServicew.exe
\classes
\com\platinumsolutions\MyService.class
\logs
You’ll notice that I renamed the prunsrv and prunmgr executables (originally called tomcat6.exe and tomcat6w.exe) to "myService.exe" and "myServicew.exe" respectively. This is simply so that when I look in the running process list for my service, it will be listed as "myService.exe".
To deploy my service, I open a Command Prompt to the "C:\MyService\bin" folder and run the following command:
C:\MyService\bin> myService.exe //IS//MyService --Install=C:\MyService\bin\myService.exe --Description="My Java Service" --Jvm=auto --Classpath=C:\MyService\classes --StartMode=jvm --StartClass=com.platinumsolutions.MyService --StartMethod=windowsService --StartParams=start --StopMode=jvm --StopClass=com.platinumsolutions.MyService --StopMethod=windowsService --StopParams=stop --LogPath=C:\MyService\logs --StdOutput=auto --StdError=auto
There is an exhaustive list of command line parameters documented at http://commons.apache.org/daemon/procrun.html
Here is a description of command line arguments I am using for the sample service
| Parameter | Value | Description |
|---|---|---|
| //IS// | MyService | "IS" is "Install Service", and MyService is the service name. (The name that will be listed in the Window Control Panel Service Administration) |
| --Install | C:\MyService\bin\myService.exe | The full path to the prunsrv executable to install as the service binary |
| --Description | "My Java Service" | Descriptive name displayed in the Window Control Panel Service Administration. |
| --Jvm | auto | This specifies the jvm.dll to use for the embedded JVM. By specifying "auto", it will automatically locate the Java instance installed on the machine. |
| --Classpath | C:\MyService\classes | The classpath for the JVM environment. Include any Jar files here that your service depends on. |
| --StartMode | jvm | This specifies that we want to use an embedded JVM to run our service. |
| --StartClass | com.platinumsolutions.MyService | The sample Java service class. |
| --StartMethod | windowsService | The static method used to start the service (this static method must take a String array as an argument) |
| --StartParams | start | String values to pass to the StartMethod. The sample Java service expects a single parameter of "start" to start the service. |
| --StopMode | jvm | This specifies that we want to use an embedded JVM to run our service. |
| --StopClass | com.platinumsolutions.MyService | The sample Java service class. |
| --StopMethod | windowsService | The static method used to stop the service (this static method must take a String array as an argument) |
| --StopParams | stop | String values to pass to the StopMethod. The sample Java service expects a single parameter of "stop" to stop the service. |
| --LogPath | C:\MyService\logs | Specify the folder where prunsvr will write *it’s* log files to, including the StdOutput and StdError redirect logs. |
| --StdOutput | auto | The name of the log file to create where the Standard Out will be redirected to. By specifying "auto", the file will be called "stdout" with a date/time stamp appended to it. |
| --StdError | auto | The name of the log file to create where the Standard Error will be redirected to. By specifying "auto", the file will be called "stderr" with a date/time stamp appended to it. |
Monitor the sample service with prunmgr
By default the service will be installed with a startup mode of "Manual", so it is not running after it is deployed. It can be started via the Window's Control Panel's Administer Services screen, or we can use Procrun's prunmgr.
As previously mentioned, I renamed prunmgr (which was originally named tomcat6w.exe) to "myServicew.exe". Running myServicew.exe will bring up a GUI screen with a start/stop button as well as a number of tabs to modify the configuration. Just about every value that you can specify on the command line when deploying can be changed after deployment via this GUI.
One nice feature of prunmgr is the ability to have it run in the system tray. To run prunmgr in the system tray, use the command line parameter "//MS//" like so:
C:\MyService\bin> myServicew.exe //MS//
The system tray icon will have a red box on it if the service is stopped, and a green arrow if it is running. You can start/stop the service by right clicking the system tray icon and picking start/stop from the context menu.
In Conclusion
It's actually very simple to turn a Java application into a windows service with Apache Commons Daemon. In fact you can do it with no change at all to your command line program since, by default, all Procrun does is call your programs "main" method, and waits for it to return. Hopefully this write up will help you get your service up and running in no time at all.
Comments
Hi Christopher,
Is it possible to run the Quartz Java Schedulers by using the Windows Service...?
Would really appreciate if you can focus some light on how to do that....
Cheers...!!!
Hello Christopher..!
I tried following the steps given I am able to install the service but when I tried to start the service I am not able to. My Requirement is to run a Quartz Java Scheduler as a windows service.In my start method I am tryiong to start the scheduler. And then it is giving exceptipns. This might be a path issue. Since when I the same as a java console program It working fine.
ScheduleManagerService.exe //IS//MyScheduler1 --Install=d:\Scheduler\binaries\ScheduleManagerService.exe --Description=My Java Service --Jvm=auto --Classpath=d:\Scheduler\classes\;D:\Scheduler\lib\mysql-connector-java-5.0.8-bin.jar;D:\Scheduler\lib\quartz-1.5.1.1.jar; --StartMode=jvm --StartClass=com.muln.scheduler.SchedulerManager --StartMethod=windowsService --StartParams=start --StopMode=jvm --StopClass=com.muln.scheduler.SchedulerManager --StopMethod=windowsService --StopParams=stop --LogPath=D:\logs --StdOutput=auto --StdError=autotdOutput=auto --StdError=auto
Christopher, thanks for useful example.
Also I found another daemon launcher approach in ASF SVN - it might be useful fof someone:
http://svn.apache.org/viewvc/mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/main/Daemon.java?view=markup
Wow thanks for the really great tips here. I was searching how to turn my Java Program to a Windows service for quite a long time. I had never thought about such an opportunity as Apache Commons Daemon project. Now when I have opened it, it is a little bit confusing for me, but I will follow your instructions and I think that everything will be all right. Thanks one more time for this post. I will be looking forward to another great ones from you.
Sincerely,
Paul Karson
i tried to run your code under windows vista business edition and got the following error in the log file:
[2009-10-09 18:10:39] [info] Procrun (2.0.5.0) started
[2009-10-09 18:10:39] [80 service.c] [error] Access is denied.
[2009-10-09 18:10:39] [543 prunsrv.c] [error] Unable to open the Service Manager
[2009-10-09 18:10:39] [info] Procrun finished.
anyone can advice this error please? thanks !
Christopher, you have done a great job with this article. I couldn't find any proper explanation in the apache site but your article cleared up all the doubts.
Thanks!!!!
When I try to deploy with x32 5.5.x binaries, I get the below error:
[2009-09-29 16:03:14] [427 prunsrv.c] [error]
The system cannot find the file specified.
[2009-09-29 16:03:14] [1348 prunsrv.c] [error]
Load configuration failed
any thoughts?
Thanks in advance
Very useful - thanks very much for the article. One point worth noting though - as you say, the download page (still) doesn't make the Windows binaries available, but the link you suggest is also now out of date. Some hunting now required.....
Thanks, I updated the article to reference the latest Tomcat 6 procrun executables, and updated the links.
I've got stupid (maybe) question:
is apache daemon even used in this example? Is there any possible usage of it?
This example does not use the Jsvc application (which is for UNIX), but the Procrun application (which is for Windows).
The Apache Daemon "project" actually maintains both the Jsvc and Procrun source code bases.
UNIX Jsvc
http://svn.apache.org/viewvc/commons/proper/daemon/trunk/src/native/unix/
Windows Procrun
http://svn.apache.org/viewvc/commons/proper/daemon/trunk/src/native/nt/
Hi,
I would like to run a wondows service with the approach you porposed on a server where I have also Tomcat installed as service.
Do I need to have separate "prunsrv" and "prunmgr" or can I use "tomcat5.exe" and "tomcat5w.exe" already used by Tomcat ???
Thank you!
BYE
You can use the same prunsrv and prunmgr executables for multiple services, so yes you can use the ones already used by tomcat.
Note though that, by default, the prunmgr uses it's executable name to find the service.
For example, If I register a service with the name "MyService" then, when I run tomcat5w.exe, it will fail with a message of "Unable to open service 'tomcat5'.
To use prunmgr in this case, you have to specify the service name on the command line via:
tomcat5w.exe //ES//MyService
Hi Chris,
I am trying to stop the service on some condition by calling serviceInstance.stop(); in MyService.java. The client JVM gets terminated, but the service (icon on desktop) is still green. I want the icon to turn red, which indicates the user that the client is not running. Unfortunately, it still shows green, but when I right click on the service icon, it shows 'Start Service'. This is misleading as the user needs to check if the service is running, though the service shows green icon. It would be a good feature to kill the service (turn it to red) when the java client (which is started by srvice) is stopped.
Any help in this regard is appreciated..
Thank you,
Kumar.
I just noticed that myself. The prunmgr system tray icon only seems to change when the service is stopped via the system tray.
The weird thing is that if you right click on the icon, the only choice you'll see is "start service", so it knows the service has stopped, but it won't turn the icon red.
I tried a newer version of Procrun, but it has the same problem.
Tomcat 6 Procrun
Guess it's a bug (or a technical limitation)
Great article. In addition, your application must run
as account "nt authority\networkservice" if it references mapped drives.
Hi,
First of alll, I would like to thank you for all your efforts and explination.
This article made my job very easy and also it also saved little amount of money as we thought of purchaging Java Service Wrapper.
Thanks a lot once again.
Vinod Prathipati
Thanks for the guidance!
I managed to build a bit more complex sample based on the one in the article with tomcat6 binaries. Works great.
Thanks a lot.
Hi,
I found this article to be very useful to get started on using the Apache daemon component. However, I am facing some issue. When I follow the same steps as mentioned in this article along with the same sample, the service is getting installed. But, when I try starting the service from service manager or the myservicew.exe, it fails with an error saying Failed to load the class MainService. I am mentioning the directory in classpath correctly only. Am I missing anything here? Any help is highly appreciated.
Regards,
Hari
Did you change the package name? My sample service class is in a package of "com.platinumsolutions", which is why in my folder hierarchy, I have the class located in the folder "com/platinumsoulutions" under the "classes" folder. (and since I'm not using any jar files, my classpath consists only of the "classes" folder). If you changed the package name in the MyService class, make sure you adjust your folder hierarchy and classpath value accordingly.
Other than that, I don't know what the problem could be.
Hi Chris,
Thanks for putting up such a nice article, I have stuck with some technical issue. I need your please to solve the issue.
I followed and customized few code to meet my requirements:
.....
while(!stopped) {
System.out.println("My Service Executing "
try {
ListAllProcessAndMail(); ---Method called
}
catch (Exception e)
}
- "ListAllProcessAndMail" - This method is called after every one min. This method is supposed to send a mail listing all the processes running on my machine.
However the issue is, When Session object(JavaMail) is created, the service get terminated and doesn't start.
Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
Properties props = new Properties(); props.setProperty("mail.transport.protocol", "smtp");
props.setProperty("mail.host", mailhost); props.put("mail.smtp.auth", "true"); props.put("mail.smtp.port", "465"); props.put("mail.smtp.socketFactory.port", "465"); props.put("mail.smtp.socketFactory.class","javax.net.ssl.SSLSocketFactory"); props.put("mail.smtp.socketFactory.fallback", "false"); props.setProperty("mail.smtp.quitwait", "false");
Session session = Session.getDefaultInstance(props,null);
- SERVICE terminates here
FYI: When I try my code(sending a mail) outside this service. It works fine.
I was unable to reproduce your problem. I don't have access to an SMTP server with SSL enabled, so I couldn't duplicate your code exactly. I did take the MyService class and added some simple code to send an email as the service action:
I also had to add "mail.jar" to the classpath when registering the service.
When I did this, registered, and started the service, it worked fine (sent out a mail every minute like I expected). Maybe your issue is with the SSL and registering a security provider?
Sorry I can't help more.
Thanks for the work. Really nice article. Saved me a lot of time
Hi, i make all like in this article,
service was successfully registered, but when i start it in
service control manager occured an exception, jvm can instatiate class that excatly presents in classpath
I too got stuck trying to decipher the Apache Commons Daemon home page, but your tutorial cleared things up nicely. I was previously using Tanuki's Java Service Wrapper, but this is a far more elegant solution for us.
Cheers!
Adam White
JMR SoftwareSystems
best article i found about procrun. the threading analysis clarified a few questions in my mind
Excelent article, im going to try it out today... Save me a lot of time.
Thanks !
Post new comment