Code Details


The MetaDataEntry class (Listing 18.2) is the equivalent to an XML-defined Dublin Core Metadata element set. JavaSpaces requires classes to extend the Entry interface or the AbstractEntry class to be capable of storage in a tuple space.

Listing 18.2 The MetaDataEntry Class
 package org.jworkplace.content; import net.jini.entry.AbstractEntry; public class MetaDataEntry extends Index {     public String description;     public String subject;     public String creator;     public String publisher;     public String date;     public String type;     public String language;     public String format;     public String location;     public MetaDataEntry() {        this(null,null,null,null,null,null,null,null,null);     }     public MetaDataEntry(String subject,                          String creator,                          String publisher,                          String date,                          String type,                          String language,                          String format,                          String location,                          String description)     {        super();        this.name = "MyCatalog";        this.subject = subject;        this.creator = creator;        this.publisher = publisher;        this.date = date;        this.type = type;        this.language = language;        this.format = format;        this.location = location;        this.description = description;     }    public void setName(String name) {       this.name = name;    } } 

Take special note of the no-argument constructor, which is required of JavaSpaces entries, and that the fields in the class must be serializable. Also, we have added the location element that will be used to capture a URL representing the location of the content being described.

The MetaDataEntry class also extends the Index class (Listing 18.3), which is used to create indexing capabilities for JavaSpaces entries. There are many approaches to accomplishing this same task in a space. This technique uses a unique collection name and position element. For instance, in this example we use MyCatalog to define a collection name. Every time an entry is written to a space, you increment the position element. So in effect, specifying the name of the set and position of the element can retrieve a specific element. This is useful when you need to loop through all entries within a specific entry set.

You could have created a separate index that was synchronized with the entries being written to or taken from JavaSpaces. You then could loop through the index to retrieve the associated entries. Alternatively, you could create an entry that contains a collection container; perhaps a Map set, which maintains a collection of metadata elements that do not extend AbstractEntry. However, once you begin to "hide" entries in collections, you lose some of the inherent capabilities of a space. A space has the capability to notify you when an entry that matches a template is written, which you provide. In this way, you can request notification when specific content is defined in your portal. Better yet, you can associate software agent activation with matching specific entries. The notification platform becomes more powerful when content begins to trigger automated activities.

Listing 18.3 The Index Class
 package org.jworkplace.content; import net.jini.entry.AbstractEntry; abstract public class Index extends AbstractEntry {     public String name;     public Integer position;     public int increment() {         position = new Integer(position.intValue() + 1);         return position.intValue();     }     public int decrement() {         position = new Integer(position.intValue() - 1);         return position.intValue();     } } 

To use the Index class, simply increment the counter each time you write an entry to the named collection.

Resource Leasing

One of the concepts introduced in Jini is the concept of resource leasing, or time-based resource allocation. Leasing resources has direct implications on the programming model used, and the services that must be implemented to support a Jini network. Leasing implies that nothing is permanent in the Jini system. You must renew leases and renew interest in resources for them to remain active and available. Otherwise, they will be purged from the network by their removal from the lookup service.

There is a lease renewal service defined as a helper service in the Jini framework that renews interest in resources for you. This service enables disconnected clients, and minimizes the amount of development work required by developers that use the Jini model.

The MetaBean class (Listing 18.4) is used to process catalog requests. It first processes the Request object and creates a MetaDataEntry and an associated MetaDataEntryBean (Listing 18.5). It supports the catalog method, which writes a MetaDataEntry to JavaSpaces. In addition, it supports the proper handling of the collection capabilities of an index and retrieval of MetaDataEntry information by presentation pages.

Listing 18.4 The MetaBean Class
 package org.jworkplace.content; import java.beans.*; import java.util.ArrayList; import javax.servlet.http.*; import javax.servlet.*; import net.jini.core.entry.Entry; import net.jini.core.lease.Lease; import net.jini.space.JavaSpace; public class MetaBean {    private JavaSpace space;    private LeaseManager leaseMgr;    private int nextPosition = 0;    private boolean processError = false;   // use a lease manager to renew leases.   // Note the lease manager is only active as long as   // this process is active. A better alternative might be   // to use a separate process for lease renewal, such as   // the LeaseRenewal Service   //   public MetaBean() {    leaseMgr = new LeaseManager(); }   / set by HomePlace once JavaSpaces has been discovered   public void setSpace (JavaSpace space) {     this.space = space;   }   public JavaSpace getSpace() {     return this.space;   }    // called to process a request public synchronized MetaDataEntryBean processRequest (HttpServletRequest request) {     this.processError = false;     MetaDataEntry entry = new MetaDataEntry(request.getParameter ("subject"),                                             request.getParameter ("creator"),                                             request.getParameter ("publisher"),                                             request.getParameter ("date"),                                             request.getParameter ("type"),                                             request.getParameter ("language"),                                             request.getParameter ("format"),                                             request.getParameter ("location"),                                             request.getParameter ("description"));     MetaDataEntryBean bean = new MetaDataEntryBean();     bean.makeLink(entry);     return bean;   }    // returns an array of MetaDataEntry elements    public MetaDataEntry[] getEntries() {       Entry entry = null;       ArrayList list = new ArrayList();       int position = 0;       for(;;){         entry = read(position++);         if(entry == null) break;         list.add(entry);       }       nextPosition = list.size();       return (MetaDataEntry[])list.toArray(new MetaDataEntry[0]);    }    // called to catalog content    public void catalog(MetaDataEntryBean bean) {       write((MetaDataEntry)bean.followLink());    }    //    // Find a matching catalog entry given a request object    //   public MetaDataEntry find(HttpServletRequest request) {       MetaDataEntry template = new MetaDataEntry();       String element = request.getParameter("subject");       template.subject = ( (element.equals("") || element == null) ? null : element);       element = request.getParameter("creator");       template.creator = ( (element.equals("") || element == null) ? null : lement);       element = request.getParameter("publisher");       template.publisher = ( (element.equals("") || element == null) ? null : element);       element = request.getParameter("date");       template.date = ( (element.equals("") || element == null) ? null : element);       element = request.getParameter("type");       template.type = ( (element.equals("") || element == null) ? null : element);       element = request.getParameter("language");       template.language = ( (element.equals("") || element == null) ? null : element);       element = request.getParameter("format");       template.format = ( (element.equals("") || element == null) ? null : element);       element = request.getParameter("location");       template.location = ( (element.equals("") || element == null) ? null : element);       element = request.getParameter("description");       template.description = ( (element.equals("") || element == null) ? null : element);\       return (MetaDataEntry)read(template);   }    // Write a MetaDataEntry to JavaSpaces    // Uses the correct idiom to support an indexed collection    // Changing the lease time would require changes to keep the index    // in sync with entries as they expire or are removed from the space.    private synchronized void write(MetaDataEntry entry)    {       entry.position = new Integer(nextPosition);       try {         Lease lease = space.write(entry, null, Lease.FOREVER);         nextPosition++;         leaseMgr.renewFor(lease, leaseTime, this);       } catch (Exception e) { e.printStackTrace();                               this.processError = true;                               nextPosition ; }    }    // Given a position will attempt to retrieve matching entry    // Non-Blocking read uses readIfExists    private Entry read(int position)    {       Entry entry = null;       MetaDataEntry template = new MetaDataEntry();       template.position = new Integer(position);       try {           // Will return immediately if no matching entry is found           entry = space.readIfExists(template, null, 10*1000);       } catch (Exception e) { e.printStackTrace();                               this.processError = true; }       return entry;    }    // Given a MetaDataEntry template attempts to read    // a matching space entry    // Blocking Read   increase wait time e.g. 10*1000 to    // wait longer for matching entry    private Entry read(MetaDataEntry template)    {       Entry entry = null;       try {           // Set to wait for 10 seconds           entry = space.read(template, null, 10*1000);       } catch (Exception e) { e.printStackTrace();                               this.processError = true; }       return entry;    }    // used to determine if an error occurred    // during space access    public boolean getProcessError () {       return this.processError;    } } 
Listing 18.5 The MetaDataEntryBean Class
 package org.jworkplace.content; import java.io.Serializable; import net.jini.core.entry.Entry; import net.jini.lookup.entry.EntryBean; public class MetaDataEntryBean implements EntryBean, Serializable {     protected MetaDataEntry assoc;     public MetaDataEntryBean() {        assoc = new MetaDataEntry();     }     public void makeLink(Entry e) {        assoc = (MetaDataEntry) e;     }     public Entry followLink() {        return assoc;     }   public void setDescription (String description) {     assoc.description  = description;   }   public String getDescription () {     return assoc.description;   }   public void setSubject (String subject) {     assoc.subject = subject;   }   public String getSubject() {     return assoc.subject;   }   public void setCreator(String creator) {     assoc.creator = creator;   }   public String getCreator() {     return assoc.creator;   }   public void setPublisher (String publisher) {     assoc.publisher = publisher;   }   public String getPublisher() {     return assoc.publisher;   }   public void setDate (String date) {     assoc.date = date;   }   public String getDate() {     return assoc.date;   }   public void setType (String type) {     assoc.type = type;   }   public String getType() {     return assoc.type;   }   public void setLanguage (String language) {     assoc.language = language;   }   public String getLanguage() {     return assoc.language;   }   public void setFormat(String format) {     assoc.format = format;   }   public String getFormat() {     return assoc.format;   }   public void setLocation(String location) {     assoc.location = location;   }   public String getLocation() {     return assoc.location;   } } 

The HomePlace class (Listing 18.6) extends the HttpServlet class. It is used to route user requests and resolves a reference to the JavaSpaces services. The init method sets the security manager required by RMI and Jini. In addition, it performs the lookup of the service registrar (reggie) and the JavaSpaces service. This is done once when the servlet is initialized. The first call to the process will be slow, but subsequent calls are substantially faster. It is in this method that the MetaBean used by the application is created and initialized.

As an alternative to using a static reference to the MetaBean, you could place the reference to the bean in a named attribute. Other pages could reference the bean by using a getAttribute("metabean").

Listing 18.6 The HomePlace Class
 package org.jworkplace.homeplace; import java.io.*; import java.rmi.*; import java.text.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; import net.jini.space.JavaSpace; import org.jworkplace.util.*; import org.jworkplace.content.*; public class HomePlace extends HttpServlet {    private SpaceBean spaceBean;    private static MetaBean metaBean;    private JavaSpace space;    private String updatePage = "/document.jsp";    private String searchPage = "/find.jsp";    private String listPage = "/view.jsp";    private String errorPage = "/error.jsp";    public void init() {       System.setSecurityManager(new RMISecurityManager());       try {          spaceBean = new SpaceBean();       } catch(Exception e) { e.printStackTrace();                              System.exit(1); }       try {          space = getHomeSpace();          metaBean = new MetaBean();          metaBean.setSpace(space);       } catch (InterruptedException e) {}    }    public void doPost(HttpServletRequest request,                       HttpServletResponse response)                       throws IOException, ServletException    {        response.setContentType("text/html");    // default page    String nextPage = listPage;    String action = request.getParameter("action");    if(action != null) {        if(action.equals("Update"))        {           MetaDataEntryBean entryBean = metaBean.processRequest(request);           metaBean.catalog(entryBean);           nextPage = updatePage;        } else if( action.equals("Search")) {           nextPage = searchPage;        }    }        ServletContext ctx = getServletContext();        RequestDispatcher dispatcher = ctx.getRequestDispatcher(nextPage);        dispatcher.forward(request, response); }    public void doGet(HttpServletRequest request,                       HttpServletResponse response)                       throws IOException, ServletException    {         doPost(request,response);    }    public void destroy() {}    public JavaSpace getHomeSpace() throws InterruptedException    {         return spaceBean.getSpace();    }    public static MetaBean getMetaBean() {         return metaBean;    } } 

Service Discovery

The SpaceBean (Listing 18.7) implements the DiscoveryListener interface. When the SpaceBean is instantiated, it creates a LookupDiscovery manager. The LookupDiscovery manager is used to discover lookup services such as reggie.

When a lookup service is found, it invokes the discovered method of the DiscoveryListener interface. The DiscoveredEvent returns a list of lookup services discovered. Using these lookups, you can build service-specific templates to query the lookup service for matching services. In our example, we simply want to find an instance of JavaSpaces.

The lookup service enables service-using entities to register and find services that meet specific criteria. In this respect, the lookup service provides functions similar to a yellow page service. The lookup service is what in effect bootstraps the Jini network. Services register with the lookup service, and applications find services of interest using the lookup service. After a service is found, an application can invoke the methods that the service exposes through its public interface.

Listing 18.7 The SpaceBean Class
 package org.jworkplace.util; import java.rmi.*; import java.io.IOException; import net.jini.core.entry.*; import net.jini.core.lookup.ServiceRegistrar; import net.jini.discovery.DiscoveryListener; import net.jini.discovery.DiscoveryEvent; import net.jini.discovery.LookupDiscovery; import net.jini.space.JavaSpace; public class SpaceBean implements DiscoveryListener {    private JavaSpace space;    private ServiceRegistrar[] registrars;    public SpaceBean() throws IOException  {         // start finding registrars (lookup services)         LookupDiscovery mgt = new LookupDiscovery(LookupDiscovery.NO_GROUPS);         mgt.addDiscoveryListener(this);         ((LookupDiscovery)mgt).setGroups(LookupDiscovery.ALL_GROUPS);    }    // one or more lookup services have been found    public synchronized void discovered(DiscoveryEvent de) {        // get the array of lookup services discovered       registrars = de.getRegistrars();       // try to find JavaSpaces       findSpace(registrars);    }    // this method will be called if a lookup service has been    // removed from the set lookups available    // You would need to implement the appropriate process    // to remove the lookup service from your list of available services    // We simply ignore this event    public void discarded(DiscoveryEvent de) {}    // Loop through the lookup services discovered until you find JavaSpaces    private void findSpace(ServiceRegistrar[] registrars) {       if(space == null) {         for(int i=0; i < registrars.length; i++) {            try {               space = ServiceFinder.findSpace(registrars[i]);               if(space != null) {                  System.out.println("SpaceBean:findSpace - JavaSpaces resolved to: " +  graphics/ccc.gifspace);                  // notify any caller waiting                  notifyAll();                  break;               }            } catch (Exception e) { e.printStackTrace(); }         }       }    }    // get a reference to JavaSpaces, wait until it is found    public synchronized JavaSpace getSpace() throws InterruptedException {       while(space == null) {         wait();       }       return space;    }    // additional get and set methods here such as setGroups, setLocators,    // setSpaceName etc } 

The ServiceFinder class (Listing 18.8) is a utility class used by the SpaceBean to build the necessary template to find an instance of JavaSpaces. It builds a generic template and invokes the lookup method on the lookup service. It can also be used to find the registrar by using a supplied template.

Listing 18.8 The ServiceFinder Class
 package org.jworkplace.util; import java.rmi.*; import net.jini.core.lookup.ServiceTemplate; import net.jini.core.lookup.ServiceRegistrar; import net.jini.core.transaction.server.TransactionManager; import net.jini.space.JavaSpace; import net.jini.discovery.LookupDiscoveryService; public class ServiceFinder    {     public static JavaSpace findSpace(ServiceRegistrar registrar) {         JavaSpace space = null;         ServiceTemplate template;         Class[] spaceInterface = { JavaSpace.class };         template = new ServiceTemplate(null, spaceInterface, null);         return findSpace(registrar, template); }    public static JavaSpace findSpace(ServiceRegistrar registrar,                                        ServiceTemplate template) {      JavaSpace space = null;      try {           space = (JavaSpace)registrar.lookup(template);      } catch (Exception e) {            e.printStackTrace();            System.out.println("ServiceFinder:findSpace exiting");      }      return space;    } } 


JavaT P2P Unleashed
JavaT P2P Unleashed
ISBN: N/A
EAN: N/A
Year: 2002
Pages: 209

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net