Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/fetish/toolkit/FetishImpl.java


1   package com.fetish.toolkit;
2   
3   import java.util.Hashtable;
4   import java.net.*;
5   import java.rmi.Remote;
6   import java.rmi.RemoteException;
7   import com.fetish.directory.LUSManager;
8   import com.fetish.directory.Directory;
9   import com.fetish.directory.SearchCriteria;
10  import com.fetish.directory.SearchCriteriaInterface;
11  import com.fetish.directory.tool.InterfaceEntry;
12  import net.jini.core.discovery.LookupLocator;
13  import net.jini.core.lookup.ServiceID;
14  import net.jini.core.lookup.ServiceItem;
15  import net.jini.core.lookup.ServiceRegistrar;
16  import net.jini.core.lookup.ServiceRegistration;
17  import net.jini.core.lookup.ServiceTemplate;
18  import net.jini.core.lookup.ServiceMatches;
19  import net.jini.core.entry.Entry;
20  import net.jini.core.lease.Lease;
21  import net.jini.lease.LeaseRenewalManager;
22  
23  /**
24   * The Fetish Toolkit helper class.
25   * This class provides with methods that allow an easy use of the Fetish
26   * features, such as registering and deregistering a service and lookup
27   * of Fetish services by ServiceID, attributes and/or interface/s implemented.
28   */
29  public class FetishImpl /*extends Fetish*/ {
30  
31    private Hashtable registry = null;
32    private FetishLeaseRenewalManager lrm = null;
33  
34    /**
35     * Simple constructor.
36     * Sets up the internal registry and the lease renewal manager.
37     */
38    public FetishImpl() {
39      registry = new Hashtable();
40      lrm = new FetishLeaseRenewalManager( this );
41    }
42  
43    /**
44     * Obtains the FetishLeaseRenewalManager for the current toolkit class.
45     * The FetishLeaseRenewalManager is a class that allows renewing of
46     * Fetish leases, a feature that gives Fetish the power of being
47     * self-healing.<p>A class on the service side
48     * must renew the lease for the registered service.  If the lease expires
49     * the service will be removed from the Fetish registry.<p>
50     * If a service crashes it will eventually
51     * fail to renew the lease; when it expires the service will be removed,
52     * so nobody can retrieve a reference to it.  One or more listeners
53     * can be set to listen for lease expiration events, so when a service
54     * crashes and fails to renew its lease the listener can trigger the
55     * suitable mechanisms to solve the situation (for example, reload
56     * the service with the same ServiceID, notify the administrator, etc.)
57     */
58    private FetishLeaseRenewalManager getLrm() {
59      if( lrm == null ) {
60        lrm = new FetishLeaseRenewalManager( this );
61      }
62      return lrm;
63    }
64  
65    /**
66     * Gets the Fetish Toolkit registry of ServiceIDs and leases.
67     * The Fetish Toolkit registry holds the leases for all services
68     * registered using this instance of the toolkit.<br>
69     * Such leases <b>must</b> be in the same JVM the service executes
70     * in, so if the whole JVM crashes the leases will eventually expire.
71     */
72    private Hashtable getRegistry() {
73      if( registry == null ) {
74        registry = new Hashtable();
75      }
76      return registry;
77    }
78  
79    /**
80     * Obtains a reference to the Fada node given its url.
81     * This reference can the be used to cancel a lease, thus deleting
82     * the service it belongs to.
83     * @param url The url of the node to be contacted.  It must be in the
84     * form &lt;host&gt;[:&lt;port&gt;].  No protocol prefix must be used.
85     */
86    private static LUSManager getLUSManager( String url )
87    throws RemoteException {
88      try {
89        try {
90          // If exception occurs, it already has the protocol jini
91          URL myUrl = new URL( "http://" + url );
92          int port = myUrl.getPort();
93          if( port == -1 ) {
94            url = "jini://" + myUrl.getHost() + ":4160";
95          } else {
96            url = "jini://" + myUrl.getHost() + ":" + myUrl.getPort();
97          }
98        } catch( MalformedURLException mue ) {
99        }
100       LookupLocator locator = new LookupLocator( url );
101       ServiceRegistrar registrar = locator.getRegistrar();
102       Class[] classes = { LUSManager.class };
103       ServiceTemplate template =  new ServiceTemplate(
104                       null,
105                       classes,
106                       null
107                     );
108       Object lusm = registrar.lookup( template );
109       return ( LUSManager )lusm;
110     } catch( Exception e ) {
111       throw new RemoteException( "Unable to find LUSManager\n" +
112       "Reason: " + e.getMessage() );
113     }
114   }
115 
116   /**
117    * Obtains a reference to the Fada node given its url.
118    * This reference can the be used to cancel a lease, thus deleting
119    * the service it belongs to.
120    * @param url The url of the node to be contacted.  It must be in the
121    * form &lt;host&gt;[:&lt;port&gt;].  No protocol prefix must be used.
122    */
123   private static Directory getDirectory( String url )
124   throws RemoteException {
125     try {
126       try {
127         // If exception occurs, it already has the protocol jini
128         URL myUrl = new URL( "http://" + url );
129         int port = myUrl.getPort();
130         if( port == -1 ) {
131           url = "jini://" + myUrl.getHost() + ":4160";
132         } else {
133           url = "jini://" + myUrl.getHost() + ":" + myUrl.getPort();
134         }
135       } catch( MalformedURLException mue ) {
136       }
137       LookupLocator locator = new LookupLocator( url );
138       ServiceRegistrar registrar = locator.getRegistrar();
139       Class[] classes = { Directory.class };
140       ServiceTemplate template =  new ServiceTemplate(
141                       null,
142                       classes,
143                       null
144                     );
145       Object dir = registrar.lookup( template );
146       return ( Directory )dir;
147     } catch( Exception e ) {
148       throw new RemoteException( "Unable to find LUSManager\n" +
149       "Reason: " + e.getMessage() );
150     }
151   }
152 
153   /**
154    * Registers a service in the FADA architecture.
155    * This method registers the service as a Jini service in the LUS the
156    * FADA node is registered into, and keeps the Jini lease in the
157    * registry for renewal or user retrieval.
158    * @param url The url of the node to be contacted.  It must be in the
159    * form &lt;host&gt;[:&lt;port&gt;].  No protocol prefix must be used.
160    * @param sid The desired ServiceID of the service to be registered.
161    * @param service The proxy for the service to be stored at FADA.
162    * @param entries Array of Jini entries, defining more accurately the
163    * service.  It will be used at lookup time by third parties.
164    */
165   public ServiceID register( 
166     String url,
167     ServiceID sid,
168     Object service,
169     Entry[] entries
170     //long leaseDuration
171   ) throws RemoteException {
172 
173     ServiceRegistration result = null;
174     Hashtable registry = getRegistry();
175     ServiceID resultSid = null;
176     try {
177       Directory lusm = getDirectory( url );
178       ServiceItem serviceItem = new ServiceItem( sid, service, entries );
179       result = lusm.register( serviceItem , Lease.ANY );
180       //result = lusm.register( serviceItem , 30000 );
181       Lease lease = result.getLease();
182       resultSid = result.getServiceID();
183       lrm.renewFor( lease, resultSid, url );
184       RegistrationItem ri = new RegistrationItem( result, url, serviceItem );
185       registry.put( resultSid, ri );
186     } catch( Exception e ) {
187       throw new RemoteException( e.getMessage() );
188     }
189     return resultSid;
190   }
191 
192   /**
193    * Registers a service whose lease has expired.
194    * <br>
195    * This method is provided in case the lease object can't be renewed
196    * in time.  The main cause for this situation is that network delay
197    * has suddenly become very long, and the Kalman filter hasn't been
198    * able to estimate this very low probable situation.  The reregister
199    * method will register the service again, keeping all data as if
200    * has never been deregistered.
201    * @param sid The ServiceID of the service proxy whose lease has expired.
202    * @throws RemoteException if reregistration was not possible.
203    */
204   public void reregister( ServiceID sid ) throws RemoteException
205   {
206     RegistrationItem ri = ( RegistrationItem )registry.get( sid );
207     registry.remove( sid );
208     String url = ri.getUrl();
209     ServiceItem serviceItem = ri.getServiceItem();
210     serviceItem.serviceID = sid;
211     Directory lusm = getDirectory( url );
212     ServiceRegistration result = lusm.register( serviceItem , Lease.ANY );
213     Lease lease = result.getLease();
214     ServiceID resultSid = result.getServiceID();
215     ri = new RegistrationItem(
216                 result, url, serviceItem );
217     registry.put( resultSid, ri );
218     lrm.renewFor( lease, resultSid, url );
219   }
220 
221   /**
222    * Deletes the service identified by the ServiceID sid.
223    * This method cancels the Jini lease for the service identified by
224    * the ServiceID sid, thus deleting its entry in the Jini registry.
225    * It also deletes the entry in the Fetish registry.
226    * @param url The url of the node to be contacted.  It must be in the
227    * form &lt;host&gt;[:&lt;port&gt;].  No protocol prefix must be used.
228    * @param sid The ServiceID of the service to deregister.
229    * @return <code>false</code> if
230    * the deregistration was not possible (unexisting ServiceID,
231    * already deregistered service, communication error with any of the
232    * involved parties, etc); <code>true</code> otherwise.
233    */
234   public boolean unregister(
235     String url,
236     ServiceID sid
237   ) throws RemoteException {
238     boolean result = false;
239     try {
240       getDirectory( url ).unregister( sid );
241       Hashtable reg = getRegistry();
242       if( reg.containsKey( sid ) ) {
243         RegistrationItem ri = ( RegistrationItem )registry.get( sid );
244         Lease l = ri.getSr().getLease();
245         reg.remove( sid );
246         getLrm().cancel( l );
247       }
248       result = true;
249     } catch( Exception e ) {
250       throw new RemoteException(
251         "Unable to unregister: "
252         + e.getMessage()
253       );
254     }
255     return result;
256   }
257 
258   /**
259    * Returns an array with the service proxies that match the search criteria.
260    * The FADA node will return an array with all services that match the
261    * search criteria.  A service matches the criteria if:<br>
262    * <ul>
263    * <li>It implements the interface <code>service</code> <i>and</i></li>
264    * <li>It has at least one matching entry for all specified
265    * <code>entries</code> <i>and</i></li>
266    * <li>Its service id matches <code>sid</code></li>
267    * </ul>
268    * Any of the above search criteria may be null, meaning
269    * match all (serves as a wildcard).
270    * @param url The url of the node to be contacted.  It must be in the
271    * form &lt;host&gt;[:&lt;port&gt;].  No protocol prefix must be used.
272    * @param service The interface of the service we want to look for.
273    * May be null.
274    * @param entries The Jini Entry class array of attributes that may
275    * identify a service.  May be null.
276    * @param sid The Jini ServiceID of a previously registered service.
277    * May be null.
278    * @throws RemoteException If there was a communication error with any
279    * of the intervening parties (the FADA node, the Jini LUS, the
280    * physical connection itself, etc)
281    */
282   public static Object[] lookup( String url,
283                   Class service,
284                   Entry[] entries,
285                   ServiceID sid
286                   ) throws RemoteException {
287     Object[] result = new Object[0];
288     Directory dir = getDirectory( url );
289     Class[] classServ = new Class[1];
290     if( service != null ) {
291       InterfaceEntry intEnt = new InterfaceEntry( service.getName() );
292       Entry[] newEntries = null;
293       if( entries == null ) {
294         newEntries = new Entry[ 1 ];
295         newEntries[ 0 ] = intEnt;
296       } else {
297         newEntries = new Entry[ entries.length + 1 ];
298         for( int i = 0; i<entries.length; i++ ) {
299           newEntries[i] = entries[i];
300         }
301         newEntries[ entries.length ] = intEnt;
302       }
303       entries = newEntries;
304     } else {
305     }
306     SearchCriteriaInterface sc = new SearchCriteria(
307                 null,
308                 entries,
309                 sid
310               );    
311     ServiceMatches sm = null;
312     try {
313       sm = dir.lookup( sc, 65536, 3600000L, 65536 );
314       result = new Object[ sm.totalMatches ];
315       for( int i = 0; i < sm.totalMatches ; i++ )
316         result[i] = sm.items[i].service;
317     } catch( Exception e ) {
318     } 
319     return result;
320   }
321 
322   /**
323    * Makes a logical connection between any two FADA nodes.
324    * Lookup processes will span through all the graph of FADA nodes.
325    * This method provides with a mechanism to connect FADA nodes to 
326    * create a graph.<br>
327    * After execution of this method, all searches started from this node
328    * will also search the rest of the graph, and all services registered
329    * into this node will be accessible from any point in the graph.
330    * @param url1 The url of the node to be contacted.  It must be in the
331    * form &lt;host&gt;[:&lt;port&gt;].  No protocol prefix must be used.
332    * @param url2 The url of the node to be contacted.  It must be in the
333    * form &lt;host&gt;[:&lt;port&gt;].  No protocol prefix must be used.
334    * @throws RemoteException If there is any communication error with any
335    * of the nodes.
336    */
337   public static boolean connect( String url1, String url2 )
338   throws RemoteException {
339     LUSManager l1 = getLUSManager( url1 );
340     LUSManager l2 = getLUSManager( url2 );
341     return l1.connect( l2 );
342   }
343 
344   /**
345    * Obtains the Jini Lease of the service identified by sid.
346    * This Lease can then be administered by some other party, or be
347    * cancelled.
348    * <b>Warning</b>: cancelling a lease obtained by this method removes the
349    * service the lease belongs to from the Jini registry, but <b>NOT</b> from
350    * the Fetish registry.  This practice is dangerous and therefore
351    * discouraged.
352    * @param sid The Jini ServiceID of the service we want to obtain the lease
353    * for
354    * @ throws RemoteException If there is any communication error.
355    */
356   public Lease getFetishLease( ServiceID sid ) throws RemoteException {
357     Hashtable registry = getRegistry();
358     if( !registry.containsKey( sid ) )
359       return null;
360     RegistrationItem ri = ( RegistrationItem )registry.get( sid );
361     ServiceRegistration sr = ri.getSr();
362     Lease lease = sr.getLease();
363     try {
364       //getLrm().remove( lease );
365     } catch( Exception e ) {
366     }
367     return lease;
368   }
369 
370   /**
371    * Obtains the Jini ServiceID for a registered service.
372    * This ServiceID should be stored by the service for future registrations,
373    * in order to maintain a consistency.
374    * @param sr The Jini ServiceRegistration obtained in the register method.
375    * @return The ServiceID for the registered service.
376    */
377   public static ServiceID getSID( ServiceRegistration sr ) {
378     return sr.getServiceID();
379   }
380 
381   private static long parseChar( char c ) {
382     if( ( c >= '0' ) && ( c <= '9' ) ){
383       return (long)(c-'0');
384     } else {
385       return (long)( 10 + (long)( c - 'a' ) );
386     }
387   }
388 
389   /**
390    * Converts a string representing a ServiceID into an instance of ServiceID.
391    * <br>
392    * Takes a string representing a valid ServiceID and constructs a
393    * ServiceID instance with it.  It won't check the string is a real
394    * ServiceID, so errors may occur.
395    * @param sid The String that represents the ServiceID
396    * @return The ServiceID whose String representation matches the parameter
397    * sid
398    */
399   public static ServiceID parseSid( String sid ) {
400     long l1=0, l2=0;
401     String strippedSid = sid.substring( 0, 8 ) + sid.substring( 9, 13 ) +
402     sid.substring( 14, 18 ) + sid.substring( 19, 23 ) + sid.substring( 24, 36 );
403     int i = 0;
404     for( ; i<16; i++ ) {
405       l1 = ( l1 << 4 ) + parseChar( strippedSid.charAt( i ) );
406     }
407     for( ; i<32; i++ ) {
408       l2 = ( l2 << 4 ) + parseChar( strippedSid.charAt( i ) );
409     }
410     return new ServiceID( l1, l2 );
411   }
412 
413   private class RegistrationItem
414   {
415 
416     ServiceRegistration sr;
417     String url;
418     ServiceItem si;
419 
420     public RegistrationItem( ServiceRegistration sr, String url, ServiceItem si )
421     {
422       this.sr = sr;
423       this.url = url;
424       this.si = si;
425     }
426 
427     public ServiceRegistration getSr()
428     {
429       return this.sr;
430     }
431 
432     public void setSr( ServiceRegistration sr )
433     {
434       this.sr = sr;
435     }
436 
437     public String getUrl()
438     {
439       return this.url;
440     }
441 
442     public void setUrl( String url )
443     {
444       this.url = url;
445     }
446 
447     public void setServiceItem( ServiceItem si )
448     {
449       this.si = si;
450     }
451 
452     public ServiceItem getServiceItem()
453     {
454       return this.si;
455     }
456 
457   }
458   
459 }