SDSU CS 696 Emerging Technologies: Java Distributed Computing
Spring Semester, 1999
An Activatable Jini Service
Previous    Lecture Notes Index    Next    
© 1999, All Rights Reserved, SDSU & Roger Whitney
San Diego State University -- This page last updated 25-Apr-99

Contents of Doc 30, An Activatable Jini Service


References
Sdsu.logging classes
Documentation at: http://www.eli.sdsu.edu/java-SDSU/Package-sdsu.logging.html

Jini API, Local on-line version at: http://www-rohan.sdsu.edu/doc/jini/doc/api/index.html


Doc 30, An Activatable Jini Service Slide # 2

An Activatable Jini Service


This example will demonstrate a simple activatable Jini service. In other examples done in these notes, the goal has been to illustrate a Jini feature, not to implement a realistic server. In this example the goal was to illustrate a reasonable Jini server. The client code and the registration code still needs work. The HelloServer does not do much, so some issues are not demonstrated.


Activation

Making the server activatable helps insure that the server will be available for clients. The rmid daemon will keep the server active. Since rmid will restart the server process, this means that the server will have to register itself with Jini lookup service (reggie). There are two complicating issues that must be addressed.

First, If the server registers itself with the lookup service, the server must be activated to make this happen. The server is not activated until a client references the server. Clients use the lookup service to access the server! When you register the server with the activation system, you receive a stub object for the server. Use this stub to access the server, which will activate the server and cause it to be registered with the Jini lookup service. See the RegisterHelloServer class below for details.

Second, since the server is registered with the lookup service there is a lease to maintain. If the server is maintaining the lease, then the server must always be running. This can be done by setting the restart parameter in the java.rmi.activation.ActivationDesc class. See the RegisterHelloServer class below for details. (The Jini transaction manager appears to have a way around this issue.) If the server does not maintain its lease with the lookup service, then some other process must maintain the lease. The server must register with that process. If one has a number of lightly used Jini servers (services) you could let the servers be activated on demand. Use a persistent lease service to maintain the leases for these lightly-used servers.

Doc 30, An Activatable Jini Service Slide # 3
Saving ServiceID

Each Jini service (or server) is assigned a unique service id the first time it registers with a Jini lookup service. This service id is to be used in all subsequent registrations with any Jini lookup service. The example shows one way of saving this service id and using it in later registrations. See the HelloServer class for details.

Delayed Registration

Bringing up a Jini aware machine/network after begin down could cause a packet storm when all the Jini services/servers join with the lookup services, which are also just coming up and joining other lookup services. This example has a random length delay between 0 and 15 seconds to mitigate this problem. See the HelloServer class for details.

Logging

If your server/client code is bug free, you never have network problems, no one ever tries to break your server/client system, your machines never crash or go down, or there is no need to know how often the system is used, then you do not need to using logging. The HelloServer uses the logging system available in the SDSU Java Library. Log results can be sent to a file or to the screen. There are different types of log messages. Debug statements can be turned off so they can be left in the code. The debug statements in HelloServer can be turned on/off by changing a value in a configuration file. The change only takes place after the server is restarted. The configuration file is in java.util.Propterties format. All key-value pairs are optional. Default values are type=file, debug=on, file= ServerLog {set in HelloServer.initializeLogging()}.The configuration file format is:

type=file | screen
debug=on | off
file=fileName

So a sample file is:
type=file
debug=off

The example assumes that the file is named "log.properties” located in path in the variable serverDataDir of the RegisterHelloServer program. See the RegisterHelloServer class for more details.
Admin Interface

I did not provide an administration interface for the service. It would be useful to turn debugging on and off dynamically via an administration interface. The current Jini Admin interfaces have no security.

Doc 30, An Activatable Jini Service Slide # 4

The Example

HelloInterface


The standard HelloInterface.

import java.rmi.Remote;
import java.rmi.RemoteException;
public interface HelloInterface extends Remote 
   {
   public String sayHello() throws RemoteException;
   }


Doc 30, An Activatable Jini Service Slide # 5

HelloClient


Should use discovery here, but did not have time. This is the standard hello client.

import net.jini.core.entry.Entry;
import net.jini.core.lookup.ServiceTemplate; 
import net.jini.core.lookup.ServiceRegistrar; 
import net.jini.core.discovery.LookupLocator;
import net.jini.lookup.entry.Name; 
import java.rmi.RMISecurityManager;
public class HelloClient
   {
   private static final REGGIE_URL = "jini://eli.sdsu.edu";
   private static final SERVER_LABEL = "HelloServer";
   public static void main (String[] args) throws Exception
      {
      System.setSecurityManager (new RMISecurityManager ());
      LookupLocator lookup = new LookupLocator(REGGIE_URL); 
      ServiceRegistrar registrar = lookup.getRegistrar ();
      
      Entry[] serverAttributes = new Entry[1];
      serverAttributes[0] = new Name( SERVER_LABEL );
      ServiceTemplate template = 
         new ServiceTemplate (null, null, serverAttributes);
      HelloInterface myServerInterface = 
         (HelloInterface) registrar.lookup (template);
      System.out.println ( myServerInterface.sayHello () );
      }
   }


Doc 30, An Activatable Jini Service Slide # 6

HelloServer


Click here for the source code.

public class HelloServer extends Activatable  
   implements HelloInterface, ServiceIDListener
   {
   //MarshalledObject hash keys
   // In passing data to the HelloServer in the constructor
   public static final String    GROUP_KEY = "reggieGroups";
   public static final String    DATA_DIR_KEY = "dataStore";
   public static final String SERVICE_LABEL_KEY = "name";
   // File used to store the service id.
   private static final String SERVICE_ID_FILE = "serviceID";
   
   // Logging keys and default values
   private static final String LOG_SETTING_FILE = "log.properties";
   private static final String LOG_FILE = "ServerLog";
   private static final String LOG_FILE_KEY = "file";
   private static final String LOG_TYPE_KEY = "type";
   private static final String LOG_TYPE_FILE = "file";
   private static final String LOG_TYPE_SCREEN = "screen";
   private static final String DEBUG_KEY = "debug";
   private static final String DEBUG_ON = "on";
   // Directory containing log file, log configuration file and 
   //  service ID file, value comes from marshalledObject
   private File storageLocation;
   // the server is registered under this name with lookup service
   // value is obtained from marshalledObject passed to server
   private String serviceName;

Doc 30, An Activatable Jini Service Slide # 7

Constructor

   public HelloServer( ActivationID id, MarshalledObject data) 
      throws RemoteException 
      {
      super(id, 0);
      try
         {
         // Get the data from the MarshalledObject
         HashMap initialData = (HashMap) data.get();
            
         String[] groups = (String[]) initialData.get( GROUP_KEY );
         String dataLocation = 
            (String )initialData.get( DATA_DIR_KEY );
         serviceName = 
            (String )initialData.get( SERVICE_LABEL_KEY );
         storageLocation = new File( dataLocation );
         initializeLogging();
         Logger.log( "HelloServer Started" );
         
         joinReggie( groups);
         }
      catch (Exception startupError)
         {
         Logger.error( "Start up error" );
         Logger.error( startupError );
         }
      }

Doc 30, An Activatable Jini Service Slide # 8

HelloServer Public Methods


   public void serviceIDNotify (ServiceID uniqueID)
      {
      Logger.log( "Obtained serviceID " + uniqueID );
      saveServiceID( uniqueID );
      }
   public String sayHello () throws RemoteException
      {
      try
         {
         Logger.log( "Connection from " + getClientHost() );
         }
      catch (java.rmi.server.ServerNotActiveException error)
         {
         Logger.log( "Connection, client data not available" );
         }
      return ("Hello World from Jini Hello server!");
      }

Doc 30, An Activatable Jini Service Slide # 9

HelloServer Joining a Lookup Service


   private void joinReggie( String[] groups ) throws IOException
      {
      Logger.debug( "Join" );
      ServiceID helloID = getServiceID();
      Entry[] labels = getServiceLabels();
   
      // Avoid all Jini services registering at same time when 
      // machine is brought up - use random delay
      randomPause( 1000 * 15 );
      
      if (helloID == null )
         {
         Logger.debug( "Join, no ID" );
         new JoinManager(this, labels, groups, null, this, 
            new LeaseRenewalManager () );
         }
      else
         {
         Logger.debug( "Join with ID" );
         new JoinManager( helloID, this,labels, groups, null, 
            new LeaseRenewalManager () );
         }
      }
   private Entry[] getServiceLabels()
      {
      Entry[] labels = new Entry[1];
      labels[0] = new Name(serviceName);
      return labels;
      }

Doc 30, An Activatable Jini Service Slide # 10

RandomPause

   /**
    * Delay execution for random time between 0 and maxDelay
    * milliseconds
    */
   private void randomPause(int maxDelay)
      {
      try
         {
         Random delayGenerator = new Random();
         long delay = delayGenerator.nextInt( maxDelay );
         Logger.debug( "Pause for " + delay + " milliseconds" );
         Thread.sleep( delay );
         }
      catch (InterruptedException interuptedError )
         {//just proceed, as this is just a pause method
         }
      }

Doc 30, An Activatable Jini Service Slide # 11

Saving/Reading ServiceID

saveServiceID

   /**
    * Save the service id in a file. If save does not succeed, no file 
    * will be created.
    */
   private void saveServiceID( ServiceID uniqueID )
      {
      File serviceIDFile = 
         new File( storageLocation, SERVICE_ID_FILE );
      try
         {
         FileOutputStream out = new FileOutputStream( serviceIDFile );
         BufferedOutputStream buffered = 
            new BufferedOutputStream( out);
         DataOutputStream cout = new DataOutputStream( buffered);
         uniqueID.writeBytes( cout );
         cout.close();
         }
      catch (IOException writeProblem)
         {
         Logger.error( "Error in writing service id file" );
         Logger.error( writeProblem );
         serviceIDFile.delete();
         }
      }

Doc 30, An Activatable Jini Service Slide # 12

getServiceID


   /**
    * Recover ServiceID from file. Return null if ServiceID 
    * does not exist or can not be recovered
    */
   private ServiceID getServiceID()
      {
      File serviceIDFile = 
         new File( storageLocation, SERVICE_ID_FILE );
      if ( !serviceIDFile.exists() )
         return null;
         
      try
         {
         FileInputStream in = new FileInputStream( serviceIDFile );
         BufferedInputStream buffered = new BufferedInputStream( in);
         DataInputStream cin = new DataInputStream( buffered);
         ServiceID id = new ServiceID( cin );
         cin.close();
         return id;
         }
      catch (IOException readProblem)
         {
         Logger.error( "Error in reading service id file" );
         Logger.error( readProblem );
         return null;
         }
      }

Doc 30, An Activatable Jini Service Slide # 13

The logging System


   private void initializeLogging( )
      {
      Properties logSettings = getLogProperties( );
      String logType = 
         logSettings.getProperty(LOG_TYPE_KEY,LOG_TYPE_FILE );
      String debug = 
         logSettings.getProperty( DEBUG_KEY, DEBUG_ON );
      String logFileName = 
         logSettings.getProperty( LOG_FILE_KEY, LOG_FILE );
      
      SelectiveLogger serverLogger;
      try
         {
         if ( logType.equals( LOG_TYPE_SCREEN ) )
            serverLogger = (SelectiveLogger) ScreenLogger.register(  );
         else
            {
            File logFile = new File( storageLocation, logFileName );
            serverLogger =  (SelectiveLogger) FileLogger.register( logFile.getPath()  );
            }
         
         if (debug.equals(DEBUG_ON) )
            serverLogger.debugOn();
         else
            serverLogger.debugOff();
         }
      catch (LoggerCreationException logFileProblem )
         {
         // Can't create Filelogger so use screenlogger.
         ScreenLogger.register(  );
         }
      }

Doc 30, An Activatable Jini Service Slide # 14

getLogProperties


   private Properties getLogProperties()
      {
      Properties logSettings = new Properties();
      File logSettingFile = 
         new File( storageLocation, LOG_SETTING_FILE);
      try
         {
         if ( logSettingFile.exists() )
            {
            FileInputStream in = new FileInputStream( logSettingFile );
            BufferedInputStream buffered = new BufferedInputStream( in);
            logSettings.load( buffered );
            }
         return logSettings;
         }
      catch (Exception readLoadError)
         {
         return new Properties();
         }
      }

Doc 30, An Activatable Jini Service Slide # 15

RegisterHelloServer

Click here for the source code

You must change the values of serverClassLocation, serverDataDir, policyFileLocation, and reggieGroups if you wish to run this example. ServerClassLocation is the path to your copy of the HelloServer class. ServerDataDir is directory you wish the the HelloServer to place its log files, store the service id , and where the log.properties file is placed.

public class RegisterHelloServer
   {
   // Place important constants in one place
   static String serviceLabel = "HelloServer";
   static String serverClass = "HelloServer";
   static String serverClassLocation = 
      "file:/export/home/whitney/java/whitney/jini/examples/activatable/";
   
   static String serverDataDir = 
   "/export/home/whitney/java/whitney/jini/examples/activatable/ServerData";
   
   static String policyFileLocation = "/export/home/whitney/jini_data";
   static String[] reggieGroups = { "whitney" };
   public static void  main( String[] args ) throws Exception
      {
      System.setSecurityManager(new RMISecurityManager());
      System.out.println("Start main");
      Properties policyFileLocation = new Properties(); 
      policyFileLocation.put("policy", policyFileLocation);
      ActivationGroupDesc.CommandEnvironment ace = null; 
      ActivationGroupDesc exampleGroup = 
         new ActivationGroupDesc(policyFileLocation, ace);
 
      ActivationGroupID agi = 
         ActivationGroup.getSystem().registerGroup(exampleGroup);
      ActivationGroup.createGroup(agi, exampleGroup, 0);

Doc 30, An Activatable Jini Service Slide # 16
RegisterHelloServer Continued

      HashMap initializationData = new HashMap();
      initializationData.put( HelloServer.GROUP_KEY, reggieGroups );
      initializationData.put( HelloServer.DATA_DIR_KEY, serverDataDir );
      initializationData.put( HelloServer.SERVICE_LABEL_KEY, serviceLabel );
      
      MarshalledObject data = new MarshalledObject( initializationData );
      ActivationDesc desc = 
         new ActivationDesc(serverClass, serverClassLocation, data, true);
      System.out.println("Register with rmid");
      
      HelloInterface server = (HelloInterface) Activatable.register(desc);
      System.out.println("Class registered with rmid");
      
      //Force object to be activated by accessing it.
      System.out.println( server.sayHello() );
      System.out.println("Class activated");
      }
   }

Copyright ©, All rights reserved.
1999 SDSU & Roger Whitney, 5500 Campanile Drive, San Diego, CA 92182-7700 USA.
OpenContent license defines the copyright on this document.

Previous    visitors since 25-Apr-99    Next