The Artima Developer Community
Sponsored Link

Browse User Interfaces for Jini Services
Build a JFC-Based Application for Browsing and Launching Jini Services
by Jeffrey Peden
First Published in JavaWorld, March 2001

<<  Page 4 of 7  >>

Advertisement

Service Registration

Finally, we are ready to examine the code that will perform the registration of our service with the Jini lookup service. Some static methods will help perform that for us.

The first method to be called is initialize_Security_Manager(). That method sets the system security manager and makes sure that the security policy file has been set. We'll examine the policy in more detail when we run the service.

The next method called is initialize_Codebase_Server(). One of the most common mistakes developers make when working with Jini is forgetting to provide a Web server for dynamic class downloading. That procedure utilizes an embedded HTTP server, which can load and serve class files from the JVM's classpath. In exchange for the minimal overhead of a few extra threads, we gain tremendous flexibility in deployment. The utility class used here, dreamBean Software's DynaServer, can load any class or resource that is available to the local ClassLoader implementations offered to the server. DynaServer has been contributed by its author, Rickard Öberg, under an open source license to the Jini-Tools project lead by Iain Shigeoka.

That procedure is especially useful when developing ServiceUI-based services, which may use images, sounds, or other resources that need to be loaded on the client side. Instead of specifying a static location from which classes and resources should be loaded, we let the server decide how to set the java.rmi.server.codebase property and, on the client side, we can use the RMIClassLoader to get resources for us. While we're not loading any resources in our UI, here is an example on how you can load an image:


java.net.URL resourceURL = getClass().getResource("/images/logo.gif");
JButton logoButton = new JButton(new ImageIcon(resourceURL));

As long as the service has the images directory located within its classpath (or in a jar included in the classpath), the client-side code will be able to dynamically locate the resource and load it from the CodebaseServer.

Finally, we're ready to instantiate the service and register it with the lookup service. The registration step is what differentiates a Jini service from a simple RMI remote object, and since that is where we link the service with the ServiceUI, it is that much more of a crucial step. We'll walk through the initialize_Service() method a step at a time:


   protected static void initialize_Service(TimeServiceImpl proxy){
      try {
         UIDescriptor jini_Service_UI_Descriptor = getUIDescriptor();
         Entry[] jini_Service_Attributes = { new Name("Time Service Example"),
                                             jini_Service_UI_Descriptor };
         ...  

First, that static method takes an instance of our proxy. You'll notice that the method's entire body is enclosed within a try-catch block. Next, we initialize the attributes, which will be attached to the service when we register it with the lookup service. There we are attaching a net.jini.lookup.entry.Name, which contains a String-based human-readable name of the service. We are also attaching a net.jini.lookup.entry.UIDescriptor, which is the primary means for attaching a UI to a service.

The UIDescriptor object we create is part of the ServiceUI framework. That object is a subclass of the net.jini.entry.AbstractEntry class, and it contains a description of our UI, as well as all the code necessary to instantiate the UI. The getUIDescriptor() method takes care of creating the object for us:


   public static UIDescriptor getUIDescriptor() throws IOException{
      UIDescriptor desc = new UIDescriptor();
      desc.role = MainUI.ROLE;
      desc.toolkit = JFrameFactory.TOOLKIT;
      desc.attributes = new HashSet();
      desc.attributes.add(
         new UIFactoryTypes(  
            Collections.singleton(JFrameFactory.TYPE_NAME)));
      desc.factory = new MarshalledObject(new Factory());
      return desc;
   }

The role and toolkit fields contain strings describing the UI. Because they are public fields, the client may request services from the lookup service by specifying template entries to be matched. The ServiceUI 1.0 specification defines three core roles: MainUI, AdminUI, and AboutUI. The role system is extensible, so that as service designers, we may choose to add a new role if we have a UI type that does not match one of the predefined types.

The toolkit field describes the resources needed by the UI. For this example, you need the javax.swing toolkit available, but you might imagine a service intended for a J2ME MIDP device, which does not have AWT or Swing toolkits available. A resource-constrained device might search only for services with UIs that use the available toolkit, and not use precious memory examining services that it cannot use.

Finally, the attributes field is a java.util.Set that contains a UIFactoryTypes object. UIFactoryTypes is intended to describe the type of factory object contained within the UIDescriptor. The set can also contain other descriptive information about the UI, including the preferred size or location of the JFrame.

The last field in the UIDescriptor is the Factory object. That field does not actually describe the UI, but it contains an object that is capable of instantiating the UI. That Factory object is wrapped in a MarshalledObject, so that the client can examine the UIDescriptor without requiring it to download all the classes associated with the UI.

The Factory design pattern is used here because with many UI toolkits, component instantiation is closely tied to the local JVM. For instance, when creating an AWT frame, a native peer is created that builds the actual window on the hosting OS. For that reason, you cannot simply create the window within the service JVM and serialize it across the network to the client. Instead, you create an object on the service side that knows how to instantiate the UI. You then serialize that Factory object and attach it to the service. The client can then download that Factory, and instantiate the UI within the local JVM's context. That is a fundamental feature of the ServiceUI framework.

Our Factory is a JFrameFactory type, meaning that the object we return implements the JFrameFactory interface and by contract implements the getJFrame() method. When getJFrame() is called, the Factory object calls the constructor of the TimeJFrame class and returns it to the client. The code for our Factory is listed below:


   private static class Factory implements JFrameFactory{
      public JFrame getJFrame(Object roleObject){
         try {
            return new TimeJFrame((ServiceItem)roleObject);
         }catch (ClassCastException e) {
            throw new IllegalArgumentException("ServiceItem for TimeService required");
         }  
      }
   }

Returning to our initialize_Service(...) method, all the core components of our ServiceUI example are now built. The next few steps are common to the registration of all Jini services. We'll be using some utility classes provided by Sun in the Jini 1.1 release:


         ...
         LookupDiscoveryManager jini_Lookup_Discovery =
            new LookupDiscoveryManager( null,
               new LookupLocator[0],
               null);
         LeaseRenewalManager jini_Lease_Manager = new LeaseRenewalManager();
         JoinManager jini_Join_Manager = new JoinManager(proxy,
                jini_Service_Attributes,
                new ServiceIDListener(){
                    public void serviceIDNotify(ServiceID id) {
                        System.out.println("Got ServiceID: "+id);
                    }
                },
                jini_Lookup_Discovery,jini_Lease_Manager);
         System.out.println("Registered service");
      }catch (Exception e){
            e.printStackTrace();
            System.out.println("Problem registering service");
      }
   }

The LookupDiscoveryManager class locates Jini lookup services for us. We have configured it to find lookup services on the local area network, in any group. The next class needed in service registration is the LeaseRenewalManager, which will maintain the service's lease with the lookup service. Finally, the JoinManager works in conjunction with those two classes to register and maintain the registration with all lookup services.

<<  Page 4 of 7  >>


Sponsored Links



Google
  Web Artima.com   
Copyright © 1996-2017 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use - Advertise with Us