KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mmbase > module > RemoteMMCI


1 /*
2
3 This software is OSI Certified Open Source Software.
4 OSI Certified is a certification mark of the Open Source Initiative.
5
6 The license (Mozilla version 1.0) can be read at the MMBase site.
7 See http://www.MMBase.org/license
8
9  */

10 package org.mmbase.module;
11
12 import java.lang.reflect.Constructor JavaDoc;
13 import java.net.MalformedURLException JavaDoc;
14 import java.rmi.*;
15 import java.rmi.registry.Registry JavaDoc;
16 import java.rmi.server.UnicastRemoteObject JavaDoc;
17
18 import org.mmbase.bridge.CloudContext;
19 import org.mmbase.bridge.LocalContext;
20 import org.mmbase.bridge.remote.RemoteCloudContext;
21 import org.mmbase.bridge.remote.rmi.RemoteCloudContext_Rmi;
22 import org.mmbase.module.core.MMBase;
23 import org.mmbase.util.logging.*;
24
25 /**
26  * RemoteMMCI is a MMBase module that starts a Remote Method Invocation
27  * registry and binds a remote MMCI context to the server. Look a rmmci.xml for configuration
28  * options. Note that in the configuration of mmbaseroot.xml the host should be a valid
29  * host address if the RMIRegistryServer in rmmci.xml is no set.
30  * @author Kees Jongenburger <keesj@dds.nl>
31  * @version $Id: RemoteMMCI.java,v 1.15.2.2 2006/10/20 07:53:12 nklasens Exp $
32  * @since MMBase-1.5
33  */

34 public class RemoteMMCI extends ProcessorModule {
35
36     private Registry JavaDoc registry;
37
38     //get an instance and initialize the logger
39
static final Logger log = Logging.getLoggerInstance(RemoteMMCI.class);
40
41     /**
42      * DEFAULT_RMIREGISTRY_PORT = 1111
43      */

44     public static final int DEFAULT_RMIREGISTRY_PORT = 1111;
45
46     /**
47      * DEFAULT_BIND_NAME = "remotecontext"
48      */

49     public static final String JavaDoc DEFAULT_BIND_NAME = "remotecontext";
50
51     /**
52      * Method called by MMBase at startup
53      * it calls the createRemoteMMCI based on the rmmci.xml configuration
54      */

55     public void init() {
56         super.init(); // is this required?
57
loadInitParameters("mmbase/rmmci");
58         log.debug("Module RemoteMMCI starting");
59
60         int registryPort = getPort();
61         int stubPort = getStubPort(registryPort);
62         String JavaDoc host = getHost();
63         String JavaDoc bindName = getBindName();
64         createRemoteMMCI(host, registryPort, bindName, stubPort);
65         log.info("RemoteMMCI registry listening on rmi://" + host + ":" + registryPort + "/" + bindName);
66         log.info("RemoteMMCI stubs listening on rmi://" + host + ":" + stubPort);
67         startChecker(this);
68     }
69
70     public String JavaDoc getBindName() {
71         String JavaDoc bindName = DEFAULT_BIND_NAME;
72         String JavaDoc bindNameParam = getInitParameter("bindname");
73         if (bindNameParam != null) {
74             if (bindNameParam.equals("$MACHINENAME")) {
75                 // use machine name
76
bindName = MMBase.getMMBase().getMachineName();
77             } else {
78                 bindName = bindNameParam;
79             }
80         } else {
81             log.warn("missing bindname init param, using default '" + bindName + "'");
82         }
83         return bindName;
84     }
85
86     public String JavaDoc getHost() {
87         //read the rmi server host from the configuration
88
String JavaDoc host = getInitParameter("RMIRegistryServer");
89         //if RMIRegistryServer is null or "" use the mmbaseroot.xml host
90
if (host == null || host.equals("")) {
91             try {
92                 // load MMBase and make sure it is started first
93
MMBase mmbase = MMBase.getMMBase();
94                 host = mmbase.getHost();
95                 log.debug("using host FROM MMBASEROOT " + host);
96                 java.net.InetAddress.getByName(host);
97                 System.setProperty("java.rmi.server.hostname", host);
98             } catch (java.net.UnknownHostException JavaDoc uhn) {
99                 log.warn("property host in mmbaseroot.xml is not set correctly.");
100                 log.warn("Chances are big the Remote MMCI will not work");
101             }
102         } else {
103             log.debug("RemoteMMCI is using the RMIRegistryServer{" + host + "} as hostname to create/connect to the RMI registry");
104         }
105         return host;
106     }
107
108     public int getPort() {
109         int registryPort = DEFAULT_RMIREGISTRY_PORT;
110
111         //read the server port from the configuration
112
String JavaDoc portString = getInitParameter("port");
113         if (portString != null) {
114             try {
115                 registryPort = Integer.parseInt(portString);
116             } catch (NumberFormatException JavaDoc nfe) {
117                 log.warn("port parameter '" + portString + "' of rmmci.xml is not of type int.");
118             };
119         } else {
120             log.service("Missing port init param, using default " + registryPort);
121         }
122         return registryPort;
123     }
124
125
126     public int getStubPort(int registryPort) {
127         int stubPort = -1;
128
129         //read the server port from the configuration
130
String JavaDoc portString = getInitParameter("stubport");
131         if (portString != null) {
132             try {
133                 stubPort = Integer.parseInt(portString);
134             } catch (NumberFormatException JavaDoc nfe) {
135                 log.warn("stubport parameter '" + portString + "' of rmmci.xml is not of type int.");
136             };
137         } else {
138             if (stubPort == -1) {
139                 stubPort = registryPort + 1;
140             }
141             log.service("Missing port init param, using default " + stubPort);
142         }
143         return stubPort;
144     }
145
146     
147     /**
148      * This method creates or locates the RMI registry at a specific port and host and binds a new RemoteContext
149      * @param registryPort the registry port to start the RMI registry
150      * @param bindName the name of the object (aka remotecontext)
151      */

152     private void createRemoteMMCI(String JavaDoc host, int registryPort, String JavaDoc bindName, int stubPort) {
153         //System.setSecurityManager (new RMISecurityManager ());
154
try {
155             Registry JavaDoc reg = getRegistry(host, registryPort);
156             if (reg != null) {
157                 register(reg, bindName, stubPort);
158                 log.debug("Module RemoteMMCI Running on (tcp port,name)=(" + registryPort + "," + bindName + ")");
159             }
160             else {
161                 log.warn("Module RemoteMMCI MOT running and failed to bind " + bindName + ")");
162             }
163         } catch (RemoteException rex) {
164             log.fatal("RMI Registry not started because of exception {" + rex.getMessage() + Logging.stackTrace(rex) + "}");
165         }
166     }
167
168     public Registry JavaDoc getRegistry(String JavaDoc host, int registryPort) throws RemoteException {
169         Registry JavaDoc reg = null;
170         try {
171             /* Note that a getRegistry call does not actually make a connection to the remote host.
172              * It simply creates a local reference to the remote registry and will succeed even if
173              * no registry is running on the remote host. Therefore, a subsequent method invocation
174              * to a remote registry returned as a result of this method may fail.
175              */

176              reg = java.rmi.registry.LocateRegistry.getRegistry(host, registryPort);
177             //try if the registry is running
178
reg.list();
179             //if no RemoteException is thrown we are probabely ok
180
log.debug("using an existing RMI registry");
181         } catch (RemoteException rex) {
182             /*
183              * Binding a stub to a local registry should be enough to keep it
184              * from being cleaned up by DGC (Distributed Garbage Collection)
185              * One case in which it currently isn't is when the registry
186              * invocation is made on a registry remote object directly
187              * instead of a stub for a registry (i.e. what's returned from
188              * LocateRegistry.createRegistry instead of LocateRegsitry.getRegistry)
189              * and the remote object's stub passed to the registry was returned from
190              * RemoteObject.toStub or UnicastRemoteObject.exportObject; in this
191              * situation, the following old bug thwarts reachability:
192              *
193              * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4114579
194              *
195              * But invoking a registry stub (like LocateRegistry.getRegistry returns)
196              * should avoid that problem, because the remote object's stub will get
197              * marshalled and unmarshalled and thus properly registered with DGC.
198              *
199              * Conclusion:
200              * - createRegistry = Real registry instance
201              * - getRegistry = Stub to registry instance
202              *
203              * Shutdown (unexportObject) requires the Real registry instance
204              */

205             registry = java.rmi.registry.LocateRegistry.createRegistry(registryPort);
206             log.debug("creating a new RMI registry");
207             if (registry != null) {
208                reg = java.rmi.registry.LocateRegistry.getRegistry(host, registryPort);
209             }
210             else {
211                log.fatal("RMI Registry not created.");
212             }
213         }
214         return reg;
215     }
216
217
218     public void register(Registry JavaDoc reg, String JavaDoc bindName, int stubPort) throws RemoteException, AccessException {
219         // Create the Database object
220
// interface RemoteCloudContext ... implemented by RemoteCloudContext_Rmi .. using LocalContext
221
RemoteCloudContext remoteCloudContext = new RemoteCloudContext_Rmi(LocalContext.getCloudContext(), stubPort);
222
223         log.debug("bind RemoteCloudContext in the registry using name=" + bindName);
224
225         //bind it to the registry.
226
reg.rebind(bindName, remoteCloudContext);
227     }
228
229     public String JavaDoc[] getListOfNames(String JavaDoc host, int registryPort) {
230         try {
231            Registry JavaDoc reg = getRegistry(host, registryPort);
232            if (reg != null) {
233               return reg.list();
234            }
235         } catch (java.rmi.RemoteException JavaDoc rex) {
236            log.fatal("RMI Registry not started because of exception {" + rex.getMessage() + "}");
237         }
238         return new String JavaDoc[0];
239      }
240
241
242     /**
243      * unbinds the object bound to the registry in order to try to stop the registry
244      * this usualy fails(the regsitry keeps running and prevents the webapp to shutdown)
245      */

246     protected void shutdown() {
247         if (registry != null) {
248             stopRegistry();
249         }
250         super.shutdown();
251     }
252
253     private void stopRegistry() {
254         log.info("Stopping the RMI registry");
255         try {
256             String JavaDoc[] names = registry.list();
257             for (int x = 0; x < names.length; x++) {
258                 try {
259                     log.service("Unbind " + names[x]);
260                     registry.unbind(names[x]);
261                 } catch (NotBoundException e1) {
262                     log.warn(Logging.stackTrace(e1));
263                 }
264             }
265             if (!UnicastRemoteObject.unexportObject(registry, true)) {
266                 log.warn("Could not unexport " + registry);
267             } else {
268                 log.service("Unexported " + registry);
269             }
270         } catch (AccessException e) {
271             log.warn(Logging.stackTrace(e));
272         } catch (RemoteException e) {
273             log.warn(Logging.stackTrace(e));
274         }
275         registry = null;
276         // Explicitely calling the garbage collector here helps tomcat to stop faster.
277
// It can take several minutes otherwise for the RMI Reaper thread to stop.
278
Runtime.getRuntime().gc();
279     }
280
281     public boolean test(String JavaDoc host, int registryPort, String JavaDoc bindName) {
282         try {
283            String JavaDoc uri = "rmi://" + host + ":" + registryPort + "/" + bindName;
284            Object JavaDoc remoteCloudContext = Naming.lookup(uri);
285            if (remoteCloudContext != null) {
286               log.debug("RMI lookup ok");
287               try {
288                     Class JavaDoc clazz = Class.forName("org.mmbase.bridge.remote.implementation.RemoteCloudContext_Impl");
289                     Constructor JavaDoc constr = clazz.getConstructor(new Class JavaDoc [] { Class.forName("org.mmbase.bridge.remote.RemoteCloudContext") });
290                     CloudContext cloudContext = (CloudContext) constr.newInstance(new Object JavaDoc[] { remoteCloudContext } );
291
292                     cloudContext.getCloud("mmbase");
293                     log.debug("RMI cloud object found");
294               } catch (Exception JavaDoc e){
295                  log.warn("RMI cloud object failure");
296                  log.warn(Logging.stackTrace(e));
297                  return false;
298               }
299            }
300            else {
301               log.warn("RMI lookup failed " + bindName);
302               return false;
303            }
304         } catch (AccessException e) {
305            log.warn(Logging.stackTrace(e));
306         } catch (RemoteException e) {
307            log.warn(Logging.stackTrace(e));
308            return false;
309         } catch (NotBoundException e) {
310            log.warn(Logging.stackTrace(e));
311            return false;
312         } catch (MalformedURLException JavaDoc e) {
313            log.warn(Logging.stackTrace(e));
314         }
315         return true;
316      }
317
318     public void resetBind(String JavaDoc host, int registryPort, String JavaDoc bindName, int stubPort) throws RemoteException, AccessException {
319         Registry JavaDoc reg = getRegistry(host, registryPort);
320         try {
321            reg.unbind(bindName);
322         } catch (AccessException e) {
323            log.warn(Logging.stackTrace(e));
324         } catch (RemoteException e) {
325            log.warn(Logging.stackTrace(e));
326         } catch (NotBoundException e) {
327            log.info("Unbind failed for " + bindName + " in RMIregistry " + host + ":" + registryPort);
328         }
329         register(reg, bindName, stubPort);
330      }
331
332      private void startChecker(RemoteMMCI remoteMMCI) {
333         String JavaDoc checkConnection = getInitParameter("checkconnection");
334         if (checkConnection != null && !checkConnection.equals("")){
335            log.info("RemoteMMCI will check connection every " + checkConnection + " ms");
336
337            RemoteChecker runnable = new RemoteChecker(remoteMMCI, Integer.parseInt(checkConnection));
338
339            Thread JavaDoc checker = new Thread JavaDoc(runnable, "RMICloudChecker");
340            checker.setDaemon(true);
341            checker.start();
342         }
343     }
344
345      static class RemoteChecker implements Runnable JavaDoc {
346
347         int interval = 60 * 1000;
348         RemoteMMCI remoteMMCI = null;
349
350         public RemoteChecker(RemoteMMCI remoteMMCI, int interval) {
351             this.remoteMMCI = remoteMMCI;
352             this.interval = interval;
353         }
354
355         public void run() {
356             while (true) {
357                 try {
358                     Thread.sleep(interval);
359                 }
360                 catch (InterruptedException JavaDoc e) {
361                     //ignore
362
}
363                 testRMI();
364             }
365         }
366
367         private void testRMI() {
368             try {
369                 String JavaDoc bindName = remoteMMCI.getBindName();
370                 int port = remoteMMCI.getPort();
371                 String JavaDoc host = remoteMMCI.getHost();
372                 int stubPort = remoteMMCI.getStubPort(port);
373                 if (!remoteMMCI.test(host, port, bindName)) {
374                     remoteMMCI.resetBind(host, port, bindName, stubPort);
375                 }
376             } catch (RemoteException e) {
377                 log.warn(e.getClass().getName() + ": " + e.getMessage(), e);
378             }
379         }
380     }
381
382 }
383
Popular Tags