HomeDigital EditionSys-Con RadioSearch Java Cd
Advanced Java AWT Book Reviews/Excerpts Client Server Corba Editorials Embedded Java Enterprise Java IDE's Industry Watch Integration Interviews Java Applet Java & Databases Java & Web Services Java Fundamentals Java Native Interface Java Servlets Java Beans J2ME Libraries .NET Object Orientation Observations/IMHO Product Reviews Scalability & Performance Security Server Side Source Code Straight Talking Swing Threads Using Java with others Wireless XML
 

Deploying a JavaServer as an NT Service, by Nitin Nanda

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.

Framework
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).

Figure 1
Figure  1:

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 callback methods.
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.

Figure 2
Figure  2:

iService Interface
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:

public interface iService
extends java.rmi.Remote
{
boolean isRunning() throws java.rmi.RemoteException;
void shutdownServer()
throws java.rmi.RemoteException;
}

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:

Naming.rebind("myServer", theServer);
Any Java server deployed as an NT service implements the iService interface described above and handles service polling, start, and stop.

Handling Polling
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()
throws java.rmi.RemoteException
{
return true;
}

Handling Stop
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()
throws java.rmi.RemoteException
{
bShouldShutdown_ = true;
}

Handling Shutdown
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)
{
Thread.sleep (2000);
}
/* release server resources if any */
Runtime.getRuntime().exit(0);

Java Service
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
  • Handle stop

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.

Figure 3
Figure  3:

prRMIRegistry = Runtime.getRuntime().
exec("rmiregistry");

prJavaServer = Runtime.getRuntime().
exec("java com.jdj.server.myServer");

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.

String sURL = "rmi://" + "127.0.0.1"
+ ":1099/" + "myServer";
theJavaServer = (myServer)Naming.lookup(sURL);
The polling loop polls the Java server at regular intervals to determine its status:
while(bContinuePolling)
{
try
{
boolean bIsRunning =
theJavaServer.isRunning();
if (bIsRunning == false)
{
throw new Exception("Error occurred while polling Java Server.");
}
Thread.sleep(45000);
}
}

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:

protected boolean handleStop ()
{
bContinuePolling = false;
try
{
if (theJavaServer != null)
theJavaServer.shutdownServer();
}
prJavaServer.destroy();
prRMIRegistry.destroy();
setStopped();
}

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:

System.err.println("Unable to 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 directory.

Compiling the Server
To compile the server, issue the command:

\javac com\jdj\server\*.java
To generate the stub and skeleton files, issue the command:
\rmic com.jdj.server.myServer

The command jntsvc generates myService.exe file, which would be deployed in the SCM in the next step.

Deployment
Since the NT service runs under the system account, you need to set up the system classpath and system path. The system classpath must have rmi.zip and myServer_stub.class (for remote invocation of Java server) in the classpath. Also it must contain the directory in which the Java server is installed.

The system path should contain the bin directory of the JDK because the NT service spawns rmiregistry.exe and Java.exe programs that are present in the JDK's bin directory. Note: Remember to reboot your computer after setting the system classpath and path.

Conclusion
Deploying a Java server as an NT service enables you to start the server without requiring a user to be logged in. The service runs under a system account. A thin layer of the service communicates with the Java server to start it, interrogate its status, and stop it.

This article uses Microsoft SDK for Java to implement the service and rmi.zip to enable RMI communication between the NT service and the Java server. This approach might be compatible only with Java servers that run on JDK 1.1.x. You can directly use the NT service that's provided. With a small modification in the server code (by implementing iService interface) your server can be deployed as an NT service.

If you want to use a non-Microsoft approach to create an NT service it's a somewhat lengthier approach. This would be created in C/C++ and talk to the Java server through JNI. The basic architectural framework described here would be applicable in the latter approach too.

Resources

Author Bio
Nitin Nanda is an associate project manager in an R & D center of Quark, Inc., based in Chandigarh, India. He's responsible for managing the development of a three-tiered product engineered in RMI. [email protected]

Download Assoicated Source Files (Zip format - 2.82 KB)

 

All Rights Reserved
Copyright ©  2004 SYS-CON Media, Inc.
  E-mail: [email protected]

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.