1 /*------------------------------------------------------------------------------
2 Name: RmiDriver.java
3 Project: xmlBlaster.org
4 Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file
5 Comment: RmiDriver class to invoke the xmlBlaster server using RMI.
6 Version: $Id: RmiDriver.java 15205 2006-06-29 17:25:12Z ruff $
7 ------------------------------------------------------------------------------*/
8 package org.xmlBlaster.protocol.rmi;
9
10 import java.util.logging.Logger;
11 import java.util.logging.Level;
12 import org.xmlBlaster.util.Global;
13 import org.xmlBlaster.util.XmlBlasterException;
14 import org.xmlBlaster.util.def.Constants;
15 import org.xmlBlaster.util.def.ErrorCode;
16 import org.xmlBlaster.util.XmlBlasterSecurityManager;
17 import org.xmlBlaster.engine.qos.AddressServer;
18 import org.xmlBlaster.protocol.I_Authenticate;
19 import org.xmlBlaster.protocol.I_XmlBlaster;
20 import org.xmlBlaster.protocol.I_Driver;
21
22 import java.rmi.RemoteException;
23 import java.rmi.Naming;
24 import java.rmi.AlreadyBoundException;
25
26 /**
27 * RmiDriver class to invoke the xmlBlaster server using RMI.
28 * <p />
29 * Design issues:
30 * <p />
31 * How to identify the calling client.
32 * <p />
33 * How does RMI handle incoming requests?<br />
34 * Is it a worker thread model, or a 1 client/one thread
35 * model, or 1 worker thread per RMI call?
36 * When a call comes in a random thread is taken from a pool.<br />
37 * According to the rmi specs "A method dispatched by the RMI runtime to a
38 * remote object implementation (a server) may or may not execute in a
39 * separate thread. Some calls originating from the same client virtual
40 * machine will execute in the same thread; some will execute in different
41 * threads. Calls originating from different client virtual machines will
42 * execute in different threads. Other than this last case of different
43 * client virtual machines, the RMI runtime makes no guarantees with
44 * respect to mapping remote object invocations to threads. "<br />
45 * <p />
46 * Possible soultions:
47 * <ul>
48 * <li>Give each client its own remote object to call<br />
49 * We can implicitly identiofy the client, but we
50 * will have problems with many connecting clients
51 * because of the 1-1 mapping between threads and sockets.
52 * </li>
53 * <li>Pass the sessionId with each method call<br />
54 * Implicitly this will be one server object serving all clients
55 * It is not very smart
56 * </li>
57 * <li>Hack rmic to automatically pass a client id</li>
58 * </ul>
59 * We will choose the second solution (pass the sessionId).
60 * <p />
61 * RMI has not fine controlled policy like the CORBA POA!
62 * <p />
63 * A rmi-registry server is created automatically, if there is running already one, that is used.<br />
64 * You can specify another port or host to create/use a rmi-registry server:
65 * <pre>
66 * -plugin/rmi/registryPort Specify a port number where rmiregistry listens.
67 * Default is port 1099, the port 0 switches this feature off.
68 * -plugin/rmi/hostname Specify a hostname where rmiregistry runs.
69 * Default is the localhost.
70 * </pre>
71 * <p />
72 * Invoke options: <br />
73 * <pre>
74 * java -Djava.rmi.server.codebase=file:///${XMLBLASTER_HOME}/classes/ \
75 * -Djava.security.policy=${XMLBLASTER_HOME}/config/xmlBlaster.policy \
76 * -Djava.rmi.server.hostname=hostname.domainname
77 * MyApp -plugin/rmi/registryPort 2078
78 * </pre>
79 * Another option is to include the directory of xmlBlaster.policy into
80 * your CLASSPATH.
81 *
82 * @see <a href="http://www.xmlBlaster.org/xmlBlaster/doc/requirements/protocol.rmi.html">The RMI requirement</a>
83 * @see <a href="http://java.sun.com/products/jdk/1.2/docs/guide/rmi/faq.html" target="others">RMI FAQ</a>
84 * @see <a href="http://archives.java.sun.com/archives/rmi-users.html" target="others">RMI USERS</a>
85 */
86 public class RmiDriver implements I_Driver
87 {
88 private String ME = "RmiDriver";
89 private Global glob = null;
90 private static Logger log = Logger.getLogger(RmiDriver.class.getName());
91 /** XmlBlaster RMI registry listen port is 1099, to access for bootstrapping */
92 public static final int DEFAULT_REGISTRY_PORT = 1099;
93 /** The singleton handle for this xmlBlaster server */
94 private I_Authenticate authenticate = null;
95 /** The singleton handle for this xmlBlaster server */
96 private I_XmlBlaster xmlBlasterImpl = null;
97 /** The RMI implementation, which delegates to authenticate */
98 private AuthServerImpl authRmiServer = null;
99 /** The name for the RMI registry */
100 private String authBindName = null;
101 /** The RMI implementation, which delegates to xmlBlaster server */
102 private XmlBlasterImpl xmlBlasterRmiServer = null;
103 /** The name for the RMI registry */
104 private String xmlBlasterBindName = null;
105 private boolean isActive = false;
106 /** The protocol plugin configuration */
107 private AddressServer addressServer;
108
109
110 /** Get a human readable name of this driver */
111 public String getName() {
112 return ME;
113 }
114
115 /**
116 * Access the xmlBlaster internal name of the protocol driver.
117 * @return "RMI"
118 */
119 public String getProtocolId() {
120 return "RMI";
121 }
122
123 /** Enforced by I_Plugin */
124 public String getType() {
125 return getProtocolId();
126 }
127
128 /** Enforced by I_Plugin */
129 public String getVersion() {
130 return "1.0";
131 }
132
133 /**
134 * This method is called by the PluginManager (enforced by I_Plugin).
135 * @see org.xmlBlaster.util.plugin.I_Plugin#init(org.xmlBlaster.util.Global,org.xmlBlaster.util.plugin.PluginInfo)
136 */
137 public void init(org.xmlBlaster.util.Global glob, org.xmlBlaster.util.plugin.PluginInfo pluginInfo)
138 throws XmlBlasterException {
139
140 this.glob = glob;
141 this.ME = "RmiDriver" + this.glob.getLogPrefixDashed();
142
143
144 org.xmlBlaster.engine.ServerScope engineGlob = (org.xmlBlaster.engine.ServerScope)glob.getObjectEntry(Constants.OBJECT_ENTRY_ServerScope);
145 if (engineGlob == null)
146 throw new XmlBlasterException(this.glob, ErrorCode.INTERNAL_UNKNOWN, ME + ".init", "could not retreive the ServerNodeScope. Am I really on the server side ?");
147 try {
148 this.authenticate = engineGlob.getAuthenticate();
149 if (this.authenticate == null) {
150 throw new XmlBlasterException(this.glob, ErrorCode.INTERNAL_UNKNOWN, ME + ".init", "authenticate object is null");
151 }
152 I_XmlBlaster xmlBlasterImpl = this.authenticate.getXmlBlaster();
153 if (xmlBlasterImpl == null) {
154 throw new XmlBlasterException(this.glob, ErrorCode.INTERNAL_UNKNOWN, ME + ".init", "xmlBlasterImpl object is null");
155 }
156
157 init(glob, new AddressServer(glob, getType(), glob.getId(), pluginInfo.getParameters()), this.authenticate, xmlBlasterImpl);
158
159 activate();
160 }
161 catch (XmlBlasterException ex) {
162 throw ex;
163 }
164 catch (Throwable ex) {
165 throw new XmlBlasterException(this.glob, ErrorCode.INTERNAL_UNKNOWN, ME + ".init", "init. Could'nt initialize the driver.", ex);
166 }
167 }
168
169 /**
170 * Get the address how to access this driver.
171 * @return "rmi://www.mars.universe:1099/I_AuthServer"
172 */
173 public String getRawAddress() {
174 return authBindName;
175 }
176
177 /**
178 * Start xmlBlaster RMI access.
179 * @param glob Global handle to access logging, property and commandline args
180 */
181 private synchronized void init(Global glob, AddressServer addressServer, I_Authenticate authenticate, I_XmlBlaster xmlBlasterImpl) throws XmlBlasterException
182 {
183 this.authenticate = authenticate;
184 this.xmlBlasterImpl = xmlBlasterImpl;
185 this.addressServer = addressServer;
186
187 XmlBlasterSecurityManager.createSecurityManager(glob);
188
189 // plugin/rmi/registryPort
190 int registryPort = addressServer.getEnv("registryPort", DEFAULT_REGISTRY_PORT).getValue(); // default xmlBlaster RMI publishing port is 1099
191 String hostname = addressServer.getEnv("hostname", glob.getLocalIP()).getValue();
192
193 try {
194 if (registryPort > 0) {
195 // Start a 'rmiregistry' if desired
196 try {
197 java.rmi.registry.LocateRegistry.createRegistry(registryPort);
198 log.info("Started RMI registry on port " + registryPort);
199 } catch (java.rmi.server.ExportException e) {
200 // Try to bind to an already running registry:
201 try {
202 java.rmi.registry.LocateRegistry.getRegistry(hostname, registryPort);
203 log.info("Another rmiregistry is running on port " + DEFAULT_REGISTRY_PORT +
204 " we will use this one. You could change the port with e.g. '-plugin/rmi/registryPort 1122' to run your own rmiregistry.");
205 }
206 catch (RemoteException e2) {
207 String text = "Port " + DEFAULT_REGISTRY_PORT + " is already in use, but does not seem to be a rmiregistry. Please can change the port with e.g. -plugin/rmi/registryPortCB=1122 : " + e.toString();
208 log.severe(text);
209 throw new XmlBlasterException(ME, text);
210 }
211 }
212 }
213
214 String prefix = "rmi://";
215 authBindName = prefix + hostname + ":" + registryPort + "/I_AuthServer";
216 authBindName = addressServer.getEnv("AuthServerUrl", authBindName).getValue();
217
218 xmlBlasterBindName = prefix + hostname + ":" + registryPort + "/I_XmlBlaster";
219 xmlBlasterBindName = addressServer.getEnv("XmlBlasterUrl", xmlBlasterBindName).getValue();
220 } catch (Exception e) {
221 e.printStackTrace();
222 throw new XmlBlasterException("InitRmiFailed", "Could not initialize RMI registry: " + e.toString());
223 }
224
225 if (log.isLoggable(Level.FINE)) log.fine("Initialized RMI server");
226 }
227
228 /**
229 * Activate xmlBlaster access through this protocol.
230 */
231 public synchronized void activate() throws XmlBlasterException {
232 if (log.isLoggable(Level.FINER)) log.finer("Entering activate");
233 try {
234 authRmiServer = new AuthServerImpl(glob, this.addressServer, this.authenticate, xmlBlasterImpl);
235 xmlBlasterRmiServer = new XmlBlasterImpl(glob, this.addressServer, xmlBlasterImpl);
236 }
237 catch (RemoteException e) {
238 log.severe(e.toString());
239 throw new XmlBlasterException("RmiDriverFailed", e.toString());
240 }
241
242 bindToRegistry();
243
244 isActive = true;
245
246 log.info("Started successfully RMI driver.");
247 }
248
249 /**
250 * Deactivate xmlBlaster access (standby), no clients can connect.
251 */
252 public synchronized void deActivate() throws XmlBlasterException {
253 if (log.isLoggable(Level.FINER)) log.finer("Entering deActivate");
254 try {
255 if (authBindName != null) {
256 Naming.unbind(authBindName);
257 }
258 // force shutdown, even if we still have calls in progress:
259 java.rmi.server.UnicastRemoteObject.unexportObject(authRmiServer, true);
260 } catch (Exception e) {
261 log.warning("Can't shutdown authentication server: " + e.toString());
262 }
263
264 try {
265 if (xmlBlasterBindName != null) Naming.unbind(xmlBlasterBindName);
266 // force shutdown, even if we still have calls in progress:
267 java.rmi.server.UnicastRemoteObject.unexportObject(xmlBlasterRmiServer, true);
268 } catch (Exception e) {
269 log.warning("Can't shutdown xmlBlaster server: " + e.toString());
270 }
271
272 isActive = false;
273
274 log.info("RMI deactivated, no client access possible.");
275 }
276
277 /**
278 * Instructs RMI to shut down.
279 */
280 public void shutdown() throws XmlBlasterException {
281 if (log.isLoggable(Level.FINE)) log.fine("Shutting down RMI driver ...");
282
283 if (isActive) {
284 try {
285 deActivate();
286 } catch (XmlBlasterException e) {
287 log.severe(e.toString());
288 }
289 }
290
291 authBindName = null;
292 log.info("RMI driver stopped, naming entries released.");
293 }
294
295
296 /**
297 * Publish the RMI xmlBlaster server to rmi registry.
298 * <p />
299 * The bind name is typically "rmi://localhost:1099/xmlBlaster"
300 * @exception XmlBlasterException
301 * RMI registry error handling
302 */
303 private void bindToRegistry() throws XmlBlasterException
304 {
305 if (log.isLoggable(Level.FINER)) log.finer("bindToRegistry() ...");
306
307 // Publish RMI based xmlBlaster server ...
308 try {
309 Naming.bind(authBindName, authRmiServer);
310 log.info("Bound authentication RMI server to registry with name '" + authBindName + "'");
311 } catch (AlreadyBoundException e) {
312 try {
313 Naming.rebind(authBindName, authRmiServer);
314 log.warning("Removed another entry while binding authentication RMI server to registry with name '" + authBindName + "'");
315 }
316 catch(Exception e2) {
317 if (log.isLoggable(Level.FINE)) log.fine("RMI registry of '" + authBindName + "' failed: " + e2.toString());
318 throw new XmlBlasterException(ME+".RmiRegistryFailed", "RMI registry of '" + authBindName + "' failed: " + e2.toString());
319 }
320 } catch (java.rmi.NoSuchObjectException e) { // 'rmi://noty:7904/I_AuthServer': authRmiServer -> no such object in table
321 if (log.isLoggable(Level.FINE)) log.fine("RMI registry of '" + authBindName + "' authRmiServer=" + authRmiServer + " failed: " + e.getMessage());
322 throw new XmlBlasterException(glob, ErrorCode.RESOURCE_CONFIGURATION, ME+".RmiRegistryFailed",
323 "RMI registry of '" + authBindName + "' failed, probably another server instance is running already (implementation to handle this is missing): " + e.toString());
324 } catch (Throwable e) {
325 if (log.isLoggable(Level.FINE)) log.fine("RMI registry of '" + authBindName + "' failed: " + e.getMessage());
326 throw new XmlBlasterException(glob, ErrorCode.RESOURCE_CONFIGURATION, ME+".RmiRegistryFailed",
327 "RMI registry of '" + authBindName + "' failed: ", e);
328 }
329
330 try {
331 Naming.bind(xmlBlasterBindName, xmlBlasterRmiServer);
332 log.info("Bound xmlBlaster RMI server to registry with name '" + xmlBlasterBindName + "'");
333 } catch (AlreadyBoundException e) {
334 try {
335 Naming.rebind(xmlBlasterBindName, xmlBlasterRmiServer);
336 log.warning("Removed another entry while binding xmlBlaster RMI server to registry with name '" + xmlBlasterBindName + "'");
337 } catch (Exception e2) {
338 log.severe("RMI registry of '" + xmlBlasterBindName + "' failed: " + e.toString());
339 throw new XmlBlasterException(glob, ErrorCode.RESOURCE_CONFIGURATION, ME+".RmiRegistryFailed", "RMI registry of '" + xmlBlasterBindName + "' failed: " + e.toString());
340 }
341 } catch (Throwable e) {
342 log.severe("RMI registry of '" + xmlBlasterBindName + "' failed: " + e.toString());
343 throw new XmlBlasterException(glob, ErrorCode.RESOURCE_CONFIGURATION, ME+".RmiRegistryFailed", "RMI registry of '" + xmlBlasterBindName + "' failed", e);
344 }
345 }
346
347
348 /**
349 * Command line usage.
350 */
351 public String usage()
352 {
353 String text = "\n";
354 text += "RmiDriver options:\n";
355 text += " -plugin/rmi/registryPort\n";
356 text += " Specify a port number where rmiregistry listens.\n";
357 text += " Default is port "+DEFAULT_REGISTRY_PORT+", the port 0 switches this feature off.\n";
358 text += " -plugin/rmi/hostname\n";
359 text += " Specify a hostname where rmiregistry runs.\n";
360 text += " Default is the localhost.\n";
361 text += "\n";
362 return text;
363 }
364 }
syntax highlighted by Code2HTML, v. 0.9.1