Generally it's desirable to deploy the Java server in such a manner that it automatically starts when the computer does, and stops when the computer shuts down. This could be quickly and easily implemented by writing an NT service that communicates with the Java server.
NT services can start before any user logs on the NT machine. After the user logs on, he or she may pause, stop, or restart the service using the Service Control Panel applet. When the user logs off though, the desktop and all processes assigned to the desktop are closed; however, the existing services will keep running.
NT services run under a system account so it's not easy to debug them, therefore it's not advisable to deploy the Java server directly as an NT service. A thin layer of the NT service that acts as proxy for the Java server by starting, interrogating, and shutting it down can do this. Moreover, interrogating the Java server to determine its current status and shutting it down involves interprocess communication (IPC).
Creating an NT service in Java that communicates with the Java server through remote method invocation (RMI) enables the service to easily communicate with the Java server. When the service is started it launches the Java server before any user logs on to the system. The service polls the Java server at regular intervals for its status and updates the Service Control Manager (SCM). Then it shuts down the server when the computer system shuts down, or the user can stop the server from the Service Control Panel applet. During this process, the service logs both informational and warning messages to the NT event log. The architectural framework is shown in Figure 1.
Within the framework I'll briefly enumerate the steps required to implement an NT service. This makes the architecture more comprehensible. The steps required to create an NT service, irrespective of the programming language, are:
Register the service with the SCM
Initialize the service
< Overload the service callback methods
Step 1: Registering with the SCM.
The services are started and stopped through the SCM; however, for this to happen they must be registered with the SCM.
Step 2: Initializing the service.
During the initialization process, the service tells the SCM its current state - stopped or running. It also indicates to the SCM what kind of service callback methods it will accept.
Step 3: Handling the service
When the NT service is properly registered and initialized with the SCM, the SCM begins to send messages to the service and call its callback methods. These methods handle shut down, stop, and more.
Communicating the Service
with Java Server
Now I want to deploy a server called myServer. Let's expose an interface, iService, that myServer exposes to the NT service. iService has methods that the NT service calls to stop or poll myServer. Any Java server that's required to be deployed as an NT service implements the iService. The class diagram is shown in Figure 2.
The iService is a remote interface that has two methods: isRunning and shutdownServer. isRunning determines the current state of the Java server, whether it's running correctly or has crashed. shutdownServer prepares the Java server to shut down. It sets a boolean flag that tells the Java server to release all resources and finally shut down. The interface declaration is given below:
Sample Java Server
Acting as an RMI server for the NT service, myServer implements iService and UnicastRemoteObject. In its constructor, the server binds itself as "myServer", which the NT service could look up to get its reference. The related code is given below:
Any Java server deployed as an NT service implements the iService interface described above and handles service polling, start, and stop.
myServer implements the isRunning and shutdown methods. isRunning simply returns true. If the server isn't running well, it throws a RemoteException that the service catches. Based on the return value or the RemoteException, the service updates the status of the Java server in the SCM.
public boolean isRunning()
To handle the Stop event, the Java server maintains a private boolean variable bShouldShutdown_. In the shutdown method the Java server updates its value to true. The code snippet is provided below:
public void shutdownServer()
bShouldShutdown_ = true;
Within the main function of the Java server a loop regularly checks for the bShouldShutdown_ flag. When the bShouldShutdown_ flags become true, the server releases any resources being used and shuts down the server by calling the following code snippet:
while(bShouldShutdown_ == false)
/* release server resources if any */
A quick and easy way to create an NT service in Java is to implement the com.ms.service interface that comes with the service.zip package included in the Microsoft SDK for Java. Let's call the service class myService. This service internally maintains the remote reference to the Java server it obtained by looking up the RMI server. After creating the service in Java, it can be converted to an executable by using the jntsvc.exe utility that comes with the MS SDK for Java. The executable can be deployed as the service using the myService.exe /install option. Since this service is written in Java, all possible Java features are available to it.
The service can be implemented by following these steps:
Specify the callback methods
Start the rmiregistry and Java server
Poll the Java server
Java Service Constructor
The constructor tells the SCM what callback functions the service is ready to accept. In our case we can intercept the shutdown and stop callback methods. These methods can be specified to the SCM by using the following code snippet:
setRunning(ACCEPT_SHUTDOWN | ACCEPT_STOP);
The next step is to launch the Java server. Since it implements a remote interface and is an RMI server, the rmiregistry also needs to be spawned as a separate process. Spawning the rmiregistry and the Java server as separate processes within the service is done by calling a private method, launchJavaServer. Both these processes can be started using a runtime class. The relevant sequence diagram is shown in Figure 3.
Polling the Java Server
Polling is required to update the current status of the Java server - whether it's running or has stopped - in the Service Control Panel applet. This is accomplished by polling the Java server at regular intervals and retrieving its status over RMI. The polling loop determines the status by calling the isRunning method of the iService interface that the Java server implements. isRunning is called at regular intervals over RMI. This is accomplished by calling pollJavaServer, a private method, within the constructor of the service.
The polling mechanism, in the pollJavaServer method, retrieves the Java server reference by calling the lookup method.
The polling loop polls the Java server at regular intervals to determine its status:
boolean bIsRunning =
if (bIsRunning == false)
throw new Exception("Error occurred while polling Java
Shutting Down the Java Server
The Java service gets invoked with handleShutdown or handleStop callback functions when the user goes to the Service Control applet and clicks the "Shutdown" or "Stop" button, respectively, for the service. The handleStop method sets the bContinuePolling to false so that the Java service stops polling the Java server, then shuts it down by calling the remote method shutdownServer. This is followed by closing the rmiregistry and Java processes that were invoked in the constructor of the service. The code snippet of handleStop method is given below:
Writing to the Event Log
Informational or error messages from the service can be written to the event log. To write informational messages use System.out.println; to log error messages use System.err.println. An example of an error message in the code is:
bind to the Java Server:");
An example of outputting an informational message is:
System.out.println("Started RMI registry.");
Compilation and Deployment
You can use the source code provided with this article on the JDJ Web site to deploy the sample Java server as an NT service. I'll briefly touch upon how to compile and register the service with the SCM. In the following example, the source code is present in
Java and Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON Publications, Inc. is independent of Sun Microsystems, Inc.