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.rmi.NotBoundException;
22  import java.rmi.RemoteException;
23  
24  import jgroup.core.ExternalGMIListener;
25  import jgroup.core.ExternalGMIService;
26  import jgroup.core.IID;
27  import jgroup.core.JgroupException;
28  import jgroup.core.MembershipListener;
29  import jgroup.core.MembershipService;
30  import jgroup.core.View;
31  import jgroup.core.registry.DependableRegistry;
32  import jgroup.core.registry.RegistryFactory;
33  import jgroup.core.registry.RegistryService;
34  import jgroup.relacs.config.AppConfig;
35  
36  import org.apache.log4j.Logger;
37  
38  /**
39   *  This layer implements the registry service interface, allowing
40   *  the server associated with the local group manager, or layers within
41   *  the group manager to gain access to the content of the dependable
42   *  registry.
43   *
44   *  @author Alberto Montresor
45   *  @author Hein Meling
46   *  @since Jgroup 2.1
47   */
48  public class RegistryLayer
49    implements RegistryService, MembershipListener
50  {
51  	
52    ////////////////////////////////////////////////////////////////////////////////////////////
53    // Logger
54    ////////////////////////////////////////////////////////////////////////////////////////////
55  
56    /** Obtain logger for this class */
57    private static final Logger log = Logger.getLogger(RegistryLayer.class);
58  
59  
60    ////////////////////////////////////////////////////////////////////////////////////////////
61    // Fields
62    ////////////////////////////////////////////////////////////////////////////////////////////
63  
64    /** The external GMI service reference */
65    private ExternalGMIService egmis;
66  
67    /** IID representing this replica's binding in the dependable registry. */
68    private IID iid = null;
69  
70    /** The server object using this layer. */
71    private Object server = null;
72  
73    /** The application configuration information for the server. */
74    private AppConfig thisApp;
75  
76    /** The lease time to be used by the dependable registry (initially disabled = -1) */
77    private long leaseTime = -1;
78  
79    /** The shutdown hook thread used to unbind from the dependable registry */
80    private Thread shutdownHook = null;
81  
82  
83    ////////////////////////////////////////////////////////////////////////////////////////////
84    // Constructor / Static factory
85    ////////////////////////////////////////////////////////////////////////////////////////////
86  
87    private RegistryLayer(ExternalGMIService egmis)
88    {
89      this.egmis = egmis;
90    }
91  
92    public static RegistryLayer getLayer(ExternalGMIService egmis, MembershipService pgms)
93    {
94      return new RegistryLayer(egmis);
95    }
96  
97  
98    ////////////////////////////////////////////////////////////////////////////////////////////
99    // Layer interface methods
100   ////////////////////////////////////////////////////////////////////////////////////////////
101 
102   /**
103    *  This method does not need to do any processing since the
104    *  RegistryListener interface is an empty marker.
105    */
106   public void addListener(Object listener)
107   {
108     if (listener == null)
109       throw new NullPointerException("No replica specified for the registry layer.");
110     this.server = listener;
111     /* Get the application object for this replica */
112     thisApp = AppConfig.getApplication(server);
113     if (thisApp.hasService("LeaseRefresh")) {
114       leaseTime = thisApp.getIntParam("LeaseRefresh.leaseTime", DEFAULT_LEASE_TIME);
115     }
116 
117     /*
118      * If we are not using the lease layer or the notify layer, we install
119      * the shutdown hook so as to perform a clean release of the replica,
120      * once a CTRL-C is pressed.  We don't want to use this shutdown hook
121      * when testing the lease and notify layers.
122      */
123     if (!thisApp.hasService("LeaseRefresh") && !thisApp.hasService("NotifyRefresh")) {
124       /*
125        * Create a shutdown hook thread that will be executed when the server
126        * exits relatively cleanly (e.g., through CTRL-C), it will unbind the
127        * replica from the dependable registry before exiting.
128        */
129       shutdownHook = new Thread("RegistryLayer-ShutdownHook") {
130         public void run() {
131           doUnbind();
132         }};
133     }
134   }
135 
136 
137   ////////////////////////////////////////////////////////////////////////////////////////////
138   // RegistryService interface methods
139   ////////////////////////////////////////////////////////////////////////////////////////////
140 
141   public IID bind()
142     throws RemoteException, JgroupException
143   {
144     return bind(server);
145   }
146 
147   public IID bind(Object server)
148     throws RemoteException, JgroupException
149   {
150     String name = AppConfig.getApplication(server).getRegistryName();
151     return bind(name, server);
152   }
153 
154   public IID bind(String name, Object server)
155     throws RemoteException, JgroupException
156   {
157     DependableRegistry registry = RegistryFactory.getRegistry();
158     return bind(name, server, registry);
159   }
160 
161   public IID bind(String name, Object server, DependableRegistry registry)
162     throws RemoteException, JgroupException
163   {
164     if (server == null) 
165       throw new NullPointerException("Server is null; cannot bind");
166     Class serverClass = server.getClass();
167     if (!ExternalGMIListener.class.isAssignableFrom(serverClass))
168       throw new JgroupException("Cannot bind server since it does not implement an external GMI interface");
169     return registry.bind(name, egmis.getRegistryEntry(name), serverClass, leaseTime);
170   }
171 
172   public void unbind()
173     throws RemoteException, NotBoundException, JgroupException
174   {
175     if (iid == null)
176       throw new NullPointerException("Cannot unbind(null)");
177     unbind(iid);
178   }
179 
180   public void unbind(IID bid)
181     throws RemoteException, NotBoundException, JgroupException
182   {
183     DependableRegistry registry = RegistryFactory.getRegistry();
184     unbind(bid, registry);
185   }
186 
187   public void unbind(IID bid, DependableRegistry registry)
188     throws RemoteException, NotBoundException
189   {
190     if (shutdownHook != null) {
191       /* If unbind was successful, remove the shutdown hook to avoid extra unbinds */
192       Runtime.getRuntime().removeShutdownHook(shutdownHook);
193     }
194     registry.unbind(bid);
195   }
196 
197   public void refreshLease()
198     throws RemoteException, JgroupException
199   {
200     DependableRegistry registry = RegistryFactory.getRegistry();
201     try {
202       registry.refresh(iid);
203     } catch (NotBoundException nbe) {
204       log.warn(nbe.getMessage());
205     }
206   }
207 
208   public IID getIID()
209     throws NullPointerException
210   {
211     if (iid == null)
212       throw new NullPointerException("iid is null; Replica not yet bound to the dependable registry.");
213     return iid;
214   }
215 
216 
217   ////////////////////////////////////////////////////////////////////////////////////////////
218   // MembershipListener interface methods
219   ////////////////////////////////////////////////////////////////////////////////////////////
220 
221   /**
222    * Bind the local server with the dependable registry if:
223    * 
224    * <ol>
225    * <li> it has not already been bound,
226    * <li> it is configured to auto bind and
227    * <li> if the this view represents a fully replicated service view.
228    * </ol>
229    * 
230    * @see jgroup.core.MembershipListener#viewChange(jgroup.core.View)
231    */
232   public void viewChange(View view)
233   {
234     if (iid == null &&
235         thisApp.getBooleanParam("Registry.auto") &&
236         view.size() == thisApp.getInitialRedundancy()) {
237       /*
238        * Perform the bind method in a separate thread to avoid delays in
239        * the view install phase.
240        */
241       new Thread("BindThread-" + thisApp.getGroupId()) {
242         public void run() {
243           try {
244             if (log.isDebugEnabled())
245               log.debug("Group is fully replicated; auto binding with registry");
246             iid = bind();
247             if (log.isDebugEnabled())
248               log.debug("Successfully bound: " + thisApp.getRegistryName());
249             if (shutdownHook != null) {
250               /*
251                * Note that we don't start the shutdown hook thread here; instead
252                * when the JVM exit, it will start all registered shutdown hooks.
253                */
254               Runtime.getRuntime().addShutdownHook(shutdownHook);
255             }
256           } catch (Exception e) {
257             log.error("Unable to bind " + thisApp.getRegistryName() + " to the dependable registry", e);
258           }
259         }
260       }.start();
261     }
262   }
263 
264   /* (non-Javadoc)
265    * @see jgroup.core.MembershipListener#prepareChange()
266    */
267   public void prepareChange() {}
268 
269   /* (non-Javadoc)
270    * @see jgroup.core.MembershipListener#hasLeft()
271    */
272   public void hasLeft()
273   {
274     doUnbind();
275   }
276 
277   /**
278    * Do unbind from the dependable registry, but only if it was previously bound.
279    */
280   private void doUnbind()
281   {
282     // It may happen that we never bind with the registry; no need to unbind then.
283     if (iid == null)
284       return;
285     try {
286       /* Unbind the replica from the dependable registry proxy. */
287       unbind(iid);
288       if (log.isDebugEnabled())
289         log.debug("Replica was unbound from registry: " + iid);
290     } catch (Exception e) {
291       log.warn("Failed to unbind replica from registry", e);
292     }
293   }
294 
295 } // END RegistryLayer