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.net.UnknownHostException;
22 import java.rmi.NotBoundException;
23 import java.rmi.RemoteException;
24 import java.rmi.registry.Registry;
25 import java.rmi.server.RMIClientSocketFactory;
26 import java.rmi.server.RMIServerSocketFactory;
27 import java.util.ArrayList;
28 import java.util.Collections;
29 import java.util.Iterator;
30 import java.util.List;
31
32 import jgroup.core.ConfigManager;
33 import jgroup.core.ConfigurationException;
34 import jgroup.core.JgroupException;
35 import jgroup.core.ExternalGMIService.BootstrapInvocationHandler;
36 import jgroup.core.registry.BootstrapRegistry;
37 import jgroup.core.registry.DependableRegistry;
38 import jgroup.core.registry.LookupRegistry;
39 import jgroup.core.registry.RegistryLocator;
40 import jgroup.relacs.config.AppConfig;
41 import jgroup.relacs.config.Host;
42 import jgroup.relacs.config.HostSet;
43 import jgroup.relacs.rmi.Exporter;
44 import jgroup.util.Util;
45
46 import org.apache.log4j.Logger;
47
48 /**
49 * <code>RelacsRegistryLocator</code> is used to obtain a bootstrap
50 * reference to the Jgroup dependable registry, or to create a Jgroup
51 * dependable registry instance on the local machine. Every instance
52 * of the Jgroup registry service is based on two remote registries:
53 * the standard local registry and the replicated one. The standard
54 * local registry is used to retrieve a reference for the replicated
55 * remote registry. The access port for these registries are
56 * configured in the XML configuration file.
57 *
58 * @see <a href="http://java.sun.com/j2se/1.4.1/docs/api/java/rmi/registry/LocateRegistry.html">java.rmi.LocateRegistry</a>
59 * @author Alberto Montresor
60 * @author Hein Meling
61 * @since Jgroup 0.3
62 */
63 public final class RelacsRegistryLocator
64 implements RegistryLocator
65 {
66
67 ////////////////////////////////////////////////////////////////////////////////////////////
68 // Logger
69 ////////////////////////////////////////////////////////////////////////////////////////////
70
71 /** Obtain logger for this class */
72 private static final Logger log = Logger.getLogger(RelacsRegistryLocator.class);
73
74
75 ////////////////////////////////////////////////////////////////////////////////////////////
76 // Fields
77 ////////////////////////////////////////////////////////////////////////////////////////////
78
79 /**
80 * Variable for keeping the current group proxy for the dependable
81 * registry instances. It is returned when multiple instances query
82 * for a dependable registry within the same JVM.
83 */
84 private DependableRegistry drProxy = null;
85
86 /**
87 * A list of threads used for polling (checking) for dependable
88 * registry instances within the current distributed system.
89 */
90 private List<RegistryPollingThread> pollingThreads =
91 Collections.synchronizedList(new ArrayList<RegistryPollingThread>(16));
92
93 /**
94 * The set of group proxy handlers for the dependable registry.
95 */
96 private List<BootstrapInvocationHandler> handlers =
97 new ArrayList<BootstrapInvocationHandler>(5);
98
99
100 ////////////////////////////////////////////////////////////////////////////////////////////
101 // Constructors
102 ////////////////////////////////////////////////////////////////////////////////////////////
103
104 /**
105 * Will be used to obtain an instance of RegistryLocator.
106 */
107 public RelacsRegistryLocator() { }
108
109
110 ////////////////////////////////////////////////////////////////////////////////////////////
111 // Public methods
112 ////////////////////////////////////////////////////////////////////////////////////////////
113
114 /**
115 * Returns a proxy for the dependable registry service.
116 *
117 * @return
118 * A proxy for the dependable registry service.
119 *
120 * @exception RemoteException
121 * Raised if the proxy could not be obtained.
122 * @exception ConfigurationException
123 * Raised if there is a problem with the distributed system
124 * configuration data.
125 */
126 public DependableRegistry getRegistry()
127 throws JgroupException, RemoteException
128 {
129 return getRegistry(null);
130 }
131
132
133 /**
134 * Returns a proxy for the dependable registry service formed by all
135 * registry replica instances found within the distributed system
136 * configuration. <p>
137 *
138 * Communication with this remote registry will use the supplied
139 * <t>RMIClientSocketFactory csf</t> to create socket connections to
140 * the dependable registry on the distributed system and port. <p>
141 *
142 * Note that the method returns the same group reference (variable
143 * <code>drProxy</code>) for the dependable registry upon multiple
144 * invocations of this method. However, the threads continue to run
145 * also after the first invocation, and thus the group proxy may be
146 * augmented with further dependable registry replicas. This means
147 * that, although the first (few) use(s) of the returned group proxy
148 * may have accessed only a subset of the available DR replicas,
149 * future invocations on the group proxy will include all available
150 * DR replicas.
151 *
152 * @param csf
153 * Client-side socket factory used to make connections to the
154 * dependable registry. If <code>csf</code> is null, then the
155 * default client-side socket factory will be used.
156 *
157 * @return
158 * A proxy for the dependable registry service
159 *
160 * @exception RemoteException
161 * If a proxy could not be obtained; probably due to unavailability
162 * of any registry replica instances.
163 * @exception ConfigurationException
164 * Raised if there is a problem with the distributed system
165 * configuration data.
166 */
167 public DependableRegistry getRegistry(RMIClientSocketFactory csf)
168 throws JgroupException, RemoteException
169 {
170 if (drProxy != null)
171 return drProxy;
172
173 /*
174 * Obtains remote references for the dependable registry and inserts
175 * them in the handler. This is achieved by probing each host in
176 * the distributed system, using a separate thread for each host.
177 * This is to avoid blocking when a host is not responsive.
178 */
179 HostSet allHosts = ConfigManager.getDistributedSystem().getAllHosts();
180 for (Iterator hostIter = allHosts.iterator(); hostIter.hasNext(); ) {
181 Host host = (Host) hostIter.next();
182 String fqdn = host.getCanonicalHostName();
183 /* Create a polling thread for each host in the distributed system. */
184 RegistryPollingThread regPoller = new RegistryPollingThread(fqdn, csf);
185 Thread t = new Thread(regPoller);
186 t.setDaemon(true);
187 t.start();
188 pollingThreads.add(regPoller);
189 }
190
191 /*
192 * Here we sleep a bit, to allow (all) registry instances to return
193 * their <code>Remote</code> reference.
194 */
195 AppConfig app = AppConfig.getApplication(RegistryImpl.class);
196 int locatorProbeTimeout = app.getIntParam("LocatorProbeTimeout", 1000);
197 Util.sleep(locatorProbeTimeout);
198 if (handlers.size() < 1) {
199 Util.sleep(2*locatorProbeTimeout);
200 if (handlers.size() < 1)
201 throw new RemoteException("Giving up: No registry instances found.");
202 }
203 if (log.isDebugEnabled()) {
204 log.debug("Number of hosts not responded yet: " + pollingThreads.size()
205 + ", registries found thus far: " + handlers.size());
206 }
207
208 BootstrapInvocationHandler handler = handlers.get(0);
209 for (int i = 1; i < handlers.size(); ++i) {
210 handler.merge(handlers.get(i));
211 }
212 /* Returns the proxy for the registry, using the handler */
213 drProxy = (DependableRegistry) Exporter.getProxy(RegistryImpl.class, handler);
214 return drProxy;
215 }
216
217
218 /**
219 * Creates and exports a dependable registry replica on the local
220 * host listening for incoming requests on an the port specified in
221 * the system configuration file. <p>
222 *
223 * @return
224 * The newly created dependable registry replica.
225 *
226 * @exception RemoteException
227 * Raised if the registry could not be exported.
228 * @exception JgroupException
229 * Raised if a registry instance could not be created.
230 * @exception ConfigurationException
231 * Raised if there was a problem parsing the distributed system
232 * configuration file.
233 */
234 public DependableRegistry createRegistry()
235 throws JgroupException, RemoteException
236 {
237 return new RegistryImpl();
238 }
239
240
241 /**
242 * Creates and exports a dependable registry replica on the local
243 * host listening for incoming requests on an the port specified in
244 * the system configuration file. <p>
245 *
246 * The new instance of the dependable registry listens to incoming
247 * requests using a <code>ServerSocket</code> created from the
248 * supplied <code>RMIServerSocketFactory</code>. A client that
249 * receives a reference to this registry will then use a
250 * <code>Socket</code> created from the supplied
251 * <code>RMIClientSocketFactory</code>.
252 *
253 * @param csf
254 * Client-side <code>Socket</code> factory used to make connections
255 * to the registry.
256 * @param ssf
257 * Server-side <code>ServerSocket</code> factory used to accept
258 * connections to the registry.
259 *
260 * @return
261 * The newly created dependable registry replica.
262 *
263 * @exception RemoteException
264 * Raised if the registry could not be exported.
265 * @exception JgroupException
266 * Raised if a registry instance could not be created.
267 * @exception ConfigurationException
268 * Raised if there was a problem parsing the distributed system
269 * configuration file.
270 */
271 public DependableRegistry createRegistry(RMIClientSocketFactory csf, RMIServerSocketFactory ssf)
272 throws RemoteException, JgroupException
273 {
274 return new RegistryImpl(csf, ssf);
275 }
276
277
278 /* (non-Javadoc)
279 * @see jgroup.core.registry.RegistryLocator#getLookupRegistry()
280 */
281 public LookupRegistry getLookupRegistry()
282 throws JgroupException, RemoteException
283 {
284 return (LookupRegistry) getRegistry();
285 }
286
287
288 ////////////////////////////////////////////////////////////////////////////////////////////
289 // Private methods
290 ////////////////////////////////////////////////////////////////////////////////////////////
291
292 /**
293 * Probe the specified host for a dependable registry replica, and
294 * returns a remote reference to the dependable registry replica if
295 * such replica exists on the given host; otherwise an exception is
296 * thrown. <p>
297 *
298 * Note that the <code>lookup</code> method used within this method
299 * may block if there is a communication problem.
300 *
301 * @param hostname
302 * The host to probe for a dependable registry replica.
303 * @param csf
304 * The <code>RMIClientSocketFactory</code> to use.
305 *
306 * @return
307 * The <code>Remote</code> object reference to the registry replica.
308 *
309 * @exception RemoteException
310 * Is raised if there was communication problems, such as the host
311 * is not running any bootstrap registry, or other communication
312 * problems.
313 * @exception NotBoundException
314 * Is raised if the bootstrap registry did not contain a reference
315 * to a dependable registry replica.
316 */
317 private static BootstrapInvocationHandler getSingleRegistry(String hostname, RMIClientSocketFactory csf)
318 throws UnknownHostException, RemoteException, NotBoundException
319 {
320 Registry registry = BootstrapRegistry.getRemoteRegistry(hostname, csf, false);
321 return (BootstrapInvocationHandler) registry.lookup(DependableRegistry.DEPENDABLE_REGISTRY_NAME);
322 }
323
324
325 ////////////////////////////////////////////////////////////////////////////////////////////
326 // Private internal class
327 ////////////////////////////////////////////////////////////////////////////////////////////
328
329 /**
330 * A <code>RegistryPollingThread</code> class is created for each
331 * host on which there may be running a dependable registry instance.
332 * It will query the specified host for its local registry instance
333 * and if there is a communication problem (long delay), the thread
334 * will simply block. Since each host is being queried by a separate
335 * thread, those threads without communication problems will return
336 * quickly, allowing the system to avoid problems with blocking in
337 * the event of communication problems (due to the lookup problem
338 * with standard Java RMI.) <p>
339 *
340 * @author Hein Meling
341 * @since Jgroup 1.2
342 */
343 private class RegistryPollingThread
344 implements Runnable
345 {
346 private String fqdn;
347 private RMIClientSocketFactory csf;
348
349 RegistryPollingThread(String fqdn, RMIClientSocketFactory csf)
350 {
351 this.fqdn = fqdn;
352 this.csf = csf;
353 }
354
355 /**
356 * Get the <code>Remote</code> reference for a registry running on
357 * the host associated with this thread instance, and if there was
358 * a registry, insert that <code>Remote</code> reference into the
359 * <code>handler</code> object. Given that the method
360 * getSingleRegistry does not block, the run method will simply
361 * finish by removing this thread from the polling list and exit.
362 */
363 public void run()
364 {
365 try {
366 handlers.add(getSingleRegistry(fqdn, csf));
367 if (log.isDebugEnabled())
368 log.debug(fqdn + ": dependable registry found.");
369 } catch (Exception e) {
370 if (log.isDebugEnabled())
371 log.debug(fqdn + ": dependable registry not found.");
372 } finally {
373 pollingThreads.remove(this);
374 }
375 }
376 }
377
378 } // END RelacsRegistryLocator