View Javadoc

1   /*
2    * Copyright (c) 1998-2002 The Jgroup Team.
3    *
4    * This program is free software; you can redistribute it and/or modify
5    * it under the terms of the GNU Lesser General Public License version 2 as
6    * published by the Free Software Foundation.
7    *
8    * This program is distributed in the hope that it will be useful,
9    * but WITHOUT ANY WARRANTY; without even the implied warranty of
10   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11   * GNU Lesser General Public License for more details.
12   *
13   * You should have received a copy of the GNU Lesser General Public License
14   * along with this program; if not, write to the Free Software
15   * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16   *
17   */
18  
19  package jgroup.relacs.registry;
20  
21  import java.lang.reflect.InvocationHandler;
22  import java.rmi.AccessException;
23  import java.rmi.NotBoundException;
24  import java.rmi.Remote;
25  import java.rmi.RemoteException;
26  import java.rmi.registry.Registry;
27  import java.rmi.server.RMIClientSocketFactory;
28  import java.rmi.server.RMIServerSocketFactory;
29  
30  import jgroup.core.ConfigManager;
31  import jgroup.core.ConfigurationException;
32  import jgroup.core.ExternalGMIService;
33  import jgroup.core.GroupManager;
34  import jgroup.core.IID;
35  import jgroup.core.JgroupException;
36  import jgroup.core.Layer;
37  import jgroup.core.MemberId;
38  import jgroup.core.MembershipListener;
39  import jgroup.core.MembershipService;
40  import jgroup.core.MergingListener;
41  import jgroup.core.View;
42  import jgroup.core.protocols.Anycast;
43  import jgroup.core.protocols.Multicast;
44  import jgroup.core.registry.BootstrapRegistry;
45  import jgroup.core.registry.DependableRegistry;
46  import jgroup.relacs.config.AppConfig;
47  import jgroup.relacs.gm.LeaseInfo;
48  import jgroup.relacs.rmi.Exporter;
49  import jgroup.util.Abort;
50  
51  import org.apache.log4j.Logger;
52  
53  /**
54   *  This class implements the <code>DependableRegistry</code> interface.
55   *
56   *  @author Alberto Montresor
57   *  @author Hein Meling
58   *  @since Jgroup 0.4
59   */
60  public final class RegistryImpl
61    implements DependableRegistry, MergingListener, MembershipListener
62  {
63  
64    ////////////////////////////////////////////////////////////////////////////////////////////
65    // Logger
66    ////////////////////////////////////////////////////////////////////////////////////////////
67  
68    /** Obtain logger for this class */
69    private static final Logger log = Logger.getLogger(RegistryImpl.class);
70  
71  
72    ////////////////////////////////////////////////////////////////////////////////////////////
73    // Fields
74    ////////////////////////////////////////////////////////////////////////////////////////////
75  
76    private ExternalGMIService  egmis;
77    private MembershipService   pgms;
78    private RegistryTable       registrytable;
79    private MemberId            me;
80  
81  
82    ////////////////////////////////////////////////////////////////////////////////////////////
83    // Constructors
84    ////////////////////////////////////////////////////////////////////////////////////////////
85  
86    /**
87     * Creates and exports a dependable registry replica on the local host that
88     * listen to incoming requests on an anonymous communication port.
89     * Objects contained in the <tt>conf</tt> map are used by Jgroup to
90     * configure the group communication system; the distributed system
91     * description must be included in this map object.
92     *
93     * @exception RemoteException
94     *   If the registry could not be exported
95     * @exception JgroupException
96     *   Generic exception raised by Jgroup
97     * @exception ConfigurationException
98     *   Raised when the distributed system configuration object contains an error
99     */
100   public RegistryImpl()
101     throws RemoteException, JgroupException, ConfigurationException
102   {
103     this(null, null, null);
104   }
105 
106   /**
107    * Special constructor for creating the dependable registry as part of
108    * another group (e.g., the replication manager group).
109    * 
110    * Creates and exports a dependable registry replica on the local host that
111    * listen to incoming requests on an anonymous communication port.
112    * Objects contained in the <tt>conf</tt> map are used by Jgroup to
113    * configure the group communication system; the distributed system
114    * description must be included in this map object.
115    *
116    * @exception RemoteException
117    *   If the registry could not be exported
118    * @exception JgroupException
119    *   Generic exception raised by Jgroup
120    * @exception ConfigurationException
121    *   Raised when the distributed system configuration object contains an error
122    */
123   public RegistryImpl(GroupManager gm)
124     throws RemoteException, JgroupException, ConfigurationException
125   {
126     this(gm, null, null);
127     /*
128      * Obtain the various layers required by the dependable registry
129      * from the group manager stack of the hosting application, and
130      * add the dependable registry object as a listener to these layers.
131      */
132     Layer layer = (Layer) gm.getService("EGMI");
133     layer.addListener(this);
134     layer = (Layer) gm.getService("SMS");
135     layer.addListener(this);
136     layer = (Layer) gm.getService("PGMS");
137     layer.addListener(this);
138   }
139 
140   /**
141    * Creates and exports a dependable registry replica on the local host that
142    * listen to incoming requests on the port specified within the configuration
143    * object.  Objects contained in the <tt>conf</tt> map are used by Jgroup to
144    * configure the group communication system; the distributed system
145    * description must be included in this map object.
146    *
147    * The new instance listens to incoming requests using a
148    * <code>ServerSocket</code> created from the supplied
149    * <code>RMIServerSocketFactory</code>.  A client
150    * that receives a reference to this registry will use a
151    * <code>Socket</code> created from the supplied
152    * <code>RMIClientSocketFactory</code>.
153    *
154    * @param csf
155    *   Client-side <code>Socket</code> factory used to make
156    *   connections to the registry
157    * @param ssf
158    *   Server-side <code>ServerSocket</code> factory used to
159    *   accept connections to the registry
160    * @exception RemoteException
161    *   If the registry could not be exported
162    * @exception JgroupException
163    *   Generic exception raised by Jgroup
164    * @exception ConfigurationException
165    *   Raised when the distributed system configuration object contains an error
166    */
167   public RegistryImpl(RMIClientSocketFactory csf, RMIServerSocketFactory ssf)
168     throws RemoteException, JgroupException, ConfigurationException
169   {
170     this(null, csf, ssf);
171   }
172 
173   /**
174    * Creates and exports a dependable registry replica on the local host that
175    * listen to incoming requests on the port specified within the configuration
176    * object.  Objects contained in the <tt>conf</tt> map are used by Jgroup to
177    * configure the group communication system; the distributed system
178    * description must be included in this map object.
179    *
180    * The new instance listens to incoming requests using a
181    * <code>ServerSocket</code> created from the supplied
182    * <code>RMIServerSocketFactory</code>.  A client
183    * that receives a reference to this registry will use a
184    * <code>Socket</code> created from the supplied
185    * <code>RMIClientSocketFactory</code>.
186    *
187    * @param csf
188    *   Client-side <code>Socket</code> factory used to make
189    *   connections to the registry
190    * @param ssf
191    *   Server-side <code>ServerSocket</code> factory used to
192    *   accept connections to the registry
193    * @exception RemoteException
194    *   If the registry could not be exported
195    * @exception JgroupException
196    *   Generic exception raised by Jgroup
197    * @exception ConfigurationException
198    *   Raised when the distributed system configuration object contains an error
199    */
200   public RegistryImpl(GroupManager gm, RMIClientSocketFactory csf, RMIServerSocketFactory ssf)
201     throws RemoteException, JgroupException, ConfigurationException
202   {
203     registrytable = new RegistryTable();
204     if (gm == null) {
205       gm = GroupManager.getGroupManager(this);
206     }
207     egmis = (ExternalGMIService) gm.getService(ExternalGMIService.class);
208     pgms = (MembershipService) gm.getService(MembershipService.class);
209     me = pgms.getMyIdentifier();
210     if (log.isDebugEnabled())
211       log.debug("Obtained identifier: " + me);
212     AppConfig app = AppConfig.getApplication(this);
213     int gid = app.getGroupId();
214     if (GroupManager.contains(gid)) {
215       /* The group manager is for the dependable registry only. */
216       pgms.join(gid);
217     }
218     Registry reg = BootstrapRegistry.getLocalRegistry(csf, ssf);
219     Remote handler = egmis.getBootstrapHandler();
220     reg.rebind(DEPENDABLE_REGISTRY_NAME, handler);
221   }
222 
223 
224   ////////////////////////////////////////////////////////////////////////////////////////////
225   // Main
226   ////////////////////////////////////////////////////////////////////////////////////////////
227 
228   /**
229    * Main method of the class
230    */
231   public static void main(String argv[])
232   {
233     // Start registry
234     try {
235       ConfigManager.init();
236       DependableRegistry registry = new RegistryImpl();
237       log.info("Dependable registry ready...");
238       while (true) {
239         try { Thread.sleep(0x7fffffffffffffffL);
240         } catch(InterruptedException ex) {}
241       }
242     } catch(Exception exception) {
243       Abort.exit("Failed to start the dependable registry", exception, 1);
244     }
245   }
246 
247 
248   ////////////////////////////////////////////////////////////////////////////////////////////
249   // Methods from DependableRegistry
250   ////////////////////////////////////////////////////////////////////////////////////////////
251 
252   @Multicast public IID bind(String service, RegistryEntry entry, Class serverClass)
253     throws RemoteException, AccessException
254   {
255     return bind(service, entry, serverClass, -1);
256   }
257 
258   @Multicast public IID bind(String service, RegistryEntry entry, Class serverClass, long leaseTime)
259     throws RemoteException, AccessException
260   {
261     IID iid = egmis.getIdentifier();
262     if (log.isDebugEnabled())
263       log.debug("bind(): " + service + " " + iid.getVmid());
264     checkAccess("Registry.bind");
265     BindingList bl = new BindingList(service, entry, serverClass, iid, leaseTime);
266     registrytable.add(iid.getVmid(), bl);
267     return iid;
268   }
269 
270   @Multicast public void unbind(IID iid)
271     throws RemoteException, NotBoundException, AccessException
272   {
273     if (log.isDebugEnabled())
274       log.debug("Registry.unbind() " + iid);
275     checkAccess("Registry.unbind");
276     registrytable.remove(iid.getVmid(), iid.getCounter());
277   }
278 
279   @Anycast public String[] list()
280     throws RemoteException
281   {
282     if (log.isDebugEnabled())
283       log.debug("Registry.list()");
284     String[] services = registrytable.list();
285     for (int i = 0; i < services.length; i++) {
286       try {
287         clearExpiredLeases(services[i]);
288       } catch (NotBoundException nbe) {
289         log.error("Internal error: " + nbe.getMessage());
290       }
291     }
292     return registrytable.list();
293   }
294 
295   @Anycast public Remote lookup(String serviceName)
296     throws RemoteException, NotBoundException
297   {
298     clearExpiredLeases(serviceName);
299     if (log.isDebugEnabled())
300       log.debug("Registry.lookup(): " + serviceName);
301     ServiceData service  = registrytable.getService(serviceName);
302     RegistryEntry entry = service.getRegistryEntry();
303     InvocationHandler handler = entry.createInvocationHandler(serviceName, service.getEntries());
304     return Exporter.getProxy(service.getServerClass(), handler);
305   }
306 
307   @Multicast public void refresh(IID iid)
308     throws RemoteException, AccessException, NotBoundException
309   {
310     /* Updates the timestamp in the BindingList node for the given IID. */
311     BindingList bl = registrytable.lookup(iid.getVmid(), iid.getCounter());
312     bl.timestamp = System.currentTimeMillis();
313   }
314 
315 
316   ////////////////////////////////////////////////////////////////////////////////////////////
317   // Methods from MembershipListener
318   ////////////////////////////////////////////////////////////////////////////////////////////
319 
320   public void viewChange(View view)
321   {
322     if (log.isDebugEnabled())
323       log.debug("--- RegistryImpl.viewChange: ---" + view);
324     registrytable.viewChange(view);
325   }
326 
327   public void hasLeft() { }
328 
329   public void prepareChange() { }
330 
331 
332   ////////////////////////////////////////////////////////////////////////////////////////////
333   // Methods from ShutdownListener
334   ////////////////////////////////////////////////////////////////////////////////////////////
335 
336   public void shutdown()
337   {
338     try {
339       if (log.isDebugEnabled())
340         log.info("RegistryImpl.shutdown: commenced...");
341       BootstrapRegistry.unbind(DEPENDABLE_REGISTRY_NAME);
342       pgms.leave();
343       if (log.isDebugEnabled())
344         log.info("RegistryImpl.shutdown: completed: " + DEPENDABLE_REGISTRY_NAME);
345     } catch (Exception e) {
346       log.warn("Unable to shutdown RegistryImpl", e);
347     }
348   }
349 
350 
351   ////////////////////////////////////////////////////////////////////////////////////////////
352   // Methods from MergingListener
353   ////////////////////////////////////////////////////////////////////////////////////////////
354 
355   public Object getState(MemberId[] dests)
356   {
357     if (log.isDebugEnabled()) {
358       for (int i=0; i < dests.length; i++)
359         log.debug("getState dests["+i+"]: "+dests[i]);
360     }
361     return registrytable.getState(dests, me);
362   }
363 
364   public void putState(Object obj, MemberId[] sources)
365   {
366     if (log.isDebugEnabled()) {
367       for (int i=0; i < sources.length; i++)
368         log.debug("putState sources["+i+"]: "+sources[i]);
369     }
370     try {
371       registrytable.putState((MergingData) obj, sources);
372     } catch (Exception e) {
373       log.error("Error when receiving a putState invocation", e);
374     }
375   }
376 
377 
378   ////////////////////////////////////////////////////////////////////////////////////////////
379   // Private methods
380   ////////////////////////////////////////////////////////////////////////////////////////////
381 
382   /**
383    *  Remove all expired leases for the given service.
384    *
385    *  @param service
386    *    The service for which to remove expired leases.
387    *  @throws RemoteException
388    *  @throws NotBoundException
389    */
390   private void clearExpiredLeases(String service)
391     throws RemoteException, NotBoundException
392   {
393     /* Gets IID and timestamp for the provided service name */
394     LeaseInfo leaseInfo = registrytable.getLookupInf(service);
395     /*
396      * Check if server has refreshed the lease according to given leastime.
397      * If leastime is set to -1, LeaseLayer is not used.
398      */
399     if (leaseInfo.getLeasetime() != -1) {
400       for (int j = 0; j < leaseInfo.size(); j++) {
401         if (leaseInfo.leaseExpired(j)) {
402           unbind(leaseInfo.getIID(j));
403         }
404       }
405     }
406   }
407 
408   private static void checkAccess(String s)
409     throws AccessException
410   {
411     // TODO: Currently, bind is always permitted; we need to think if it is necessary to
412     // restrict the access to the hosts in the configuration file.
413     return;
414   }
415 
416 } // END RegistryImpl