1 /*------------------------------------------------------------------------------
2 Name: RmiConnection.java
3 Project: xmlBlaster.org
4 Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file
5 Comment: Helper to connect to xmlBlaster using RMI
6 ------------------------------------------------------------------------------*/
7 package org.xmlBlaster.client.protocol.rmi;
8
9
10 import org.xmlBlaster.protocol.rmi.I_AuthServer;
11 import org.xmlBlaster.protocol.rmi.I_XmlBlaster;
12 import org.xmlBlaster.protocol.rmi.RmiUrl;
13
14 import org.xmlBlaster.client.protocol.I_XmlBlasterConnection;
15
16 import java.util.logging.Logger;
17 import java.util.logging.Level;
18 import org.xmlBlaster.util.Global;
19 import org.xmlBlaster.util.XmlBlasterException;
20 import org.xmlBlaster.util.def.ErrorCode;
21 import org.xmlBlaster.util.XmlBlasterSecurityManager;
22 import org.xmlBlaster.util.MsgUnitRaw;
23 import org.xmlBlaster.client.qos.ConnectReturnQos;
24 import org.xmlBlaster.util.qos.address.Address;
25 import org.xmlBlaster.util.xbformat.I_ProgressListener;
26
27 import java.rmi.RemoteException;
28 import java.rmi.Naming;
29 import java.rmi.NotBoundException;
30 import java.rmi.Remote;
31 import java.net.MalformedURLException;
32
33 import java.applet.Applet;
34
35
36 /**
37 * This is a helper class, helping a Java client to connect to xmlBlaster
38 * using RMI.
39 * <p>
40 * Please note that you don't need to use this wrapper, you can use the raw RMI
41 * interface as well. You can also hack your own little wrapper, which does exactly
42 * what you want.
43 * <p>
44 * There is a constructor for applets, and standalone Java clients.
45 * <p />
46 * If you need a failsafe client, you can invoke the xmlBlaster RMI methods
47 * through this class as well (for example use rmiConnection.publish() instead of the direct
48 * RMI server.publish()).
49 * <p />
50 * If you want to connect from a servlet, please use the framework in xmlBlaster/src/java/org/xmlBlaster/protocol/http
51 * <pre>
52 * # Configure RMI plugin to load:
53 * ClientProtocolPlugin[RMI][1.0]=org.xmlBlaster.client.protocol.rmi.RmiConnection
54 * </pre>
55 *
56 * @see <a href="http://www.xmlBlaster.org/xmlBlaster/doc/requirements/protocol.rmi.html">The RMI requirement</a>
57 * @author <a href="mailto:xmlBlaster@marcelruff.info">Marcel Ruff</a>.
58 */
59 public class RmiConnection implements I_XmlBlasterConnection
60 {
61 private String ME = "RmiConnection";
62 private Global glob;
63 private static Logger log = Logger.getLogger(RmiConnection.class.getName());
64
65 private I_AuthServer authServer = null;
66 private I_XmlBlaster blasterServer = null;
67 private String sessionId = null;
68 protected Address clientAddress;
69 private RmiUrl rmiUrl;
70
71 /** XmlBlaster RMI registry listen port is 1099, to access for bootstrapping */
72 public static final int DEFAULT_REGISTRY_PORT = 1099; // org.xmlBlaster.protocol.rmi.RmiDriver.DEFAULT_REGISTRY_PORT;
73 private boolean verbose = true;
74
75 /**
76 * Called by plugin loader which calls init(Global, PluginInfo) thereafter.
77 */
78 public RmiConnection() {
79 }
80
81 /**
82 * RMI client access to xmlBlaster for <strong>normal client applications</strong>.
83 * <p />
84 * @param arg parameters given on command line
85 */
86 public RmiConnection(Global glob) throws XmlBlasterException {
87 init(glob, null);
88 }
89
90 /**
91 * RMI client access to xmlBlaster for <strong>applets</strong>.
92 * <p />
93 * @param ap Applet handle
94 */
95 public RmiConnection(Global glob, Applet ap) throws XmlBlasterException {
96 init(glob, null);
97 }
98
99 /** Enforced by I_Plugin */
100 public String getType() {
101 return getProtocol();
102 }
103
104 /** Enforced by I_Plugin */
105 public String getVersion() {
106 return "1.0";
107 }
108
109 /**
110 * This method is called by the PluginManager (enforced by I_Plugin).
111 * @see org.xmlBlaster.util.plugin.I_Plugin#init(org.xmlBlaster.util.Global,org.xmlBlaster.util.plugin.PluginInfo)
112 */
113 public void init(org.xmlBlaster.util.Global glob, org.xmlBlaster.util.plugin.PluginInfo pluginInfo) throws XmlBlasterException {
114 this.glob = (glob == null) ? Global.instance() : glob;
115
116 XmlBlasterSecurityManager.createSecurityManager(this.glob);
117 log.info("Created '" + getProtocol() + "' protocol plugin to connect to xmlBlaster server");
118 }
119
120 /**
121 * Connect to RMI server.
122 */
123 public void connectLowlevel(Address address) throws XmlBlasterException {
124 if (log.isLoggable(Level.FINER)) log.finer("connectLowlevel() ...");
125
126 if (this.authServer != null) {
127 return;
128 }
129
130 this.clientAddress = address;
131
132 // default xmlBlaster RMI publishing registryPort is 1099
133 this.rmiUrl = new RmiUrl(glob, this.clientAddress);
134
135 String authServerUrl = this.rmiUrl.getUrl() + "I_AuthServer";
136 String addr = this.clientAddress.getEnv("AuthServerUrl", authServerUrl).getValue();
137 Remote rem = lookup(addr);
138 if (rem instanceof org.xmlBlaster.protocol.rmi.I_AuthServer) {
139 this.authServer = (I_AuthServer)rem;
140 this.clientAddress.setRawAddress(addr);
141 log.info("Accessed xmlBlaster authentication reference with '" + addr + "'");
142 }
143 else {
144 throw new XmlBlasterException(glob, ErrorCode.RESOURCE_CONFIGURATION_ADDRESS, ME, "No connect to '" + addr + "' possible, class needs to implement interface I_AuthServer.");
145 }
146
147 String xmlBlasterUrl = this.rmiUrl.getUrl() + "I_XmlBlaster";
148 addr = this.clientAddress.getEnv("XmlBlasterUrl", xmlBlasterUrl).getValue();
149 rem = lookup(addr);
150 if (rem instanceof org.xmlBlaster.protocol.rmi.I_XmlBlaster) {
151 this.blasterServer = (I_XmlBlaster)rem;
152 log.info("Accessed xmlBlaster server reference with '" + addr + "'");
153 }
154 else {
155 throw new XmlBlasterException(glob, ErrorCode.RESOURCE_CONFIGURATION_ADDRESS, ME, "No connect to '" + addr + "' possible, class needs to implement interface I_XmlBlaster.");
156 }
157 }
158
159
160 /**
161 * Connect to RMI server.
162 * @see I_XmlBlasterConnection#connectLowlevel(Address)
163 */
164 private Remote lookup(String addr) throws XmlBlasterException {
165 try {
166 return Naming.lookup(addr);
167 }
168 catch (RemoteException e) {
169 if (this.verbose) log.warning("Can't access address ='" + addr + "', no rmi registry running");
170 throw new XmlBlasterException(glob, ErrorCode.COMMUNICATION_NOCONNECTION, ME, "Can't access address ='" + addr + "', no rmi registry running");
171 }
172 catch (NotBoundException e) {
173 if (this.verbose) log.warning("The given address ='" + addr + "' is not bound to rmi registry: " + e.toString());
174 throw new XmlBlasterException(glob, ErrorCode.COMMUNICATION_NOCONNECTION, ME, "The given address '" + addr + "' is not bound to rmi registry: " + e.toString());
175 }
176 catch (MalformedURLException e) {
177 log.severe("The given address ='" + addr + "' is invalid: " + e.toString());
178 throw new XmlBlasterException(glob, ErrorCode.RESOURCE_CONFIGURATION_ADDRESS, ME, "The given address '" + addr + "' is invalid: " + e.toString());
179 }
180 catch (Throwable e) {
181 log.severe("The given address ='" + addr + "' is invalid : " + e.toString());
182 throw new XmlBlasterException(glob, ErrorCode.RESOURCE_CONFIGURATION_ADDRESS, ME, "The given address '" + addr + "' is invalid : " + e.toString());
183 }
184 finally {
185 this.verbose = false;
186 }
187 }
188
189 /**
190 * Reset
191 */
192 public void resetConnection(){
193 this.authServer = null;
194 this.blasterServer = null;
195 this.sessionId = null;
196 }
197
198 /**
199 * Accessing the xmlBlaster handle.
200 * For internal use, throws an ordinary Exception if xmlBlaster==null
201 * We use this for similar handling as org.omg exceptions.
202 * @return Server
203 */
204 private I_XmlBlaster getXmlBlaster() throws XmlBlasterException {
205 if (this.blasterServer == null) {
206 if (log.isLoggable(Level.FINE)) log.fine("No RMI connection available.");
207 throw new XmlBlasterException(glob, ErrorCode.COMMUNICATION_NOCONNECTION, ME,
208 "The RMI xmlBlaster handle is null, no connection available");
209 }
210 return this.blasterServer;
211 }
212
213 /**
214 * @return The connection protocol name "RMI"
215 */
216 public final String getProtocol() {
217 return "RMI";
218 }
219
220 /**
221 * Login to the server.
222 * <p />
223 * @param connectQos The encrypted connect QoS
224 * @exception XmlBlasterException if login fails
225 */
226 public String connect(String connectQos) throws XmlBlasterException {
227 if (connectQos == null)
228 throw new XmlBlasterException(ME+".connect()", "Please specify a valid QoS");
229 if (log.isLoggable(Level.FINER)) log.finer("connect() ...");
230
231 if (this.sessionId != null) {
232 log.warning("You are already logged in.");
233 return "";
234 }
235
236 connectLowlevel(this.clientAddress);
237
238 try {
239 return authServer.connect(connectQos);
240 } catch(RemoteException e) {
241 if (log.isLoggable(Level.FINE)) log.fine("Login failed");
242 throw new XmlBlasterException(glob, ErrorCode.COMMUNICATION_NOCONNECTION, ME, "Login failed");
243 }
244 }
245
246 /**
247 * @see I_XmlBlasterConnection#setConnectReturnQos(ConnectReturnQos)
248 */
249 public void setConnectReturnQos(ConnectReturnQos connectReturnQos) {
250 this.sessionId = connectReturnQos.getSecretSessionId();
251 this.ME = "RmiConnection-"+connectReturnQos.getSessionName().toString();
252 }
253
254 /**
255 * Logout from the server.
256 * <p />
257 * The callback server is removed as well, releasing all RMI threads.
258 * Note that this kills the server ping thread as well (if in failsafe mode)
259 * @return true successfully logged out
260 * false failure on gout
261 */
262 public boolean disconnect(String disconnectQos) {
263 if (log.isLoggable(Level.FINER)) log.finer("logout() ...");
264
265 try {
266 if (authServer != null) {
267 authServer.disconnect(this.sessionId, (disconnectQos==null)?"":disconnectQos);
268 }
269 shutdown();
270 resetConnection();
271 return true;
272 } catch(XmlBlasterException e) {
273 log.warning("XmlBlasterException: " + e.getMessage());
274 } catch(RemoteException e) {
275 log.warning(e.toString());
276 e.printStackTrace();
277 }
278
279 try {
280 shutdown();
281 }
282 catch (XmlBlasterException ex) {
283 log.severe("disconnect: could not shutdown properly. " + ex.getMessage());
284 }
285 resetConnection();
286 return false;
287 }
288
289
290 /**
291 * Shut down.
292 * Is called by logout()
293 */
294 public void shutdown() throws XmlBlasterException {
295 }
296
297 /**
298 * @return true if you are logged in
299 */
300 public boolean isLoggedIn() {
301 return this.blasterServer != null;
302 }
303
304 /**
305 * Enforced by I_XmlBlasterConnection interface (failsafe mode).
306 * see explanations of publish() method.
307 * @see <a href="http://www.xmlBlaster.org/xmlBlaster/src/java/org/xmlBlaster/protocol/corba/xmlBlaster.idl" target="others">CORBA xmlBlaster.idl</a>
308 */
309 public final String subscribe(String xmlKey, String qos) throws XmlBlasterException {
310 if (log.isLoggable(Level.FINER)) log.finer("subscribe() ...");
311 try {
312 return getXmlBlaster().subscribe(this.sessionId, xmlKey, qos);
313 } catch(XmlBlasterException e) {
314 throw e;
315 } catch(Exception e) {
316 throw new XmlBlasterException(glob, ErrorCode.COMMUNICATION_NOCONNECTION, ME, "subscribe", e);
317 }
318 }
319
320 /**
321 * Enforced by I_XmlBlasterConnection interface (failsafe mode)
322 * @see <a href="http://www.xmlBlaster.org/xmlBlaster/src/java/org/xmlBlaster/protocol/corba/xmlBlaster.idl" target="others">CORBA xmlBlaster.idl</a>
323 */
324 public final String[] unSubscribe(String xmlKey, String qos) throws XmlBlasterException {
325 if (log.isLoggable(Level.FINER)) log.finer("unSubscribe() ...");
326 try {
327 return getXmlBlaster().unSubscribe(this.sessionId, xmlKey, qos);
328 } catch(XmlBlasterException e) {
329 throw e;
330 } catch(Exception e) {
331 throw new XmlBlasterException(glob, ErrorCode.COMMUNICATION_NOCONNECTION, ME, "unSubscribe", e);
332 }
333 }
334
335 /**
336 * Publish fault-tolerant the given message.
337 * <p />
338 * This is a wrapper around the raw RMI publish() method
339 * If the server disappears you get an exception.
340 * This call will not block.
341 * <p />
342 * Enforced by I_XmlBlasterConnection interface (failsafe mode)
343 * @see <a href="http://www.xmlBlaster.org/xmlBlaster/src/java/org/xmlBlaster/protocol/corba/xmlBlaster.idl" target="others">CORBA xmlBlaster.idl</a>
344 */
345 public final String publish(MsgUnitRaw msgUnit) throws XmlBlasterException {
346 if (log.isLoggable(Level.FINE)) log.fine("Publishing ...");
347 try {
348 return getXmlBlaster().publish(this.sessionId, msgUnit);
349 } catch(XmlBlasterException e) {
350 if (log.isLoggable(Level.FINE)) log.fine("XmlBlasterException: " + e.getMessage());
351 throw e;
352 } catch(Exception e) {
353 throw new XmlBlasterException(glob, ErrorCode.COMMUNICATION_NOCONNECTION, ME, "publish", e);
354 }
355 }
356
357
358 /**
359 * @see <a href="http://www.xmlBlaster.org/xmlBlaster/src/java/org/xmlBlaster/protocol/corba/xmlBlaster.idl" target="others">CORBA xmlBlaster.idl</a>
360 */
361 public String[] publishArr(MsgUnitRaw [] msgUnitArr) throws XmlBlasterException
362 {
363 if (log.isLoggable(Level.FINER)) log.finer("publishArr() ...");
364 try {
365 return getXmlBlaster().publishArr(this.sessionId, msgUnitArr);
366 } catch(XmlBlasterException e) {
367 if (log.isLoggable(Level.FINE)) log.fine("XmlBlasterException: " + e.getMessage());
368 throw e;
369 } catch(Exception e) {
370 throw new XmlBlasterException(glob, ErrorCode.COMMUNICATION_NOCONNECTION, ME, "publishArr", e);
371 }
372 }
373
374 /**
375 * RMI does not support oneway messages.
376 * @see <a href="http://www.xmlBlaster.org/xmlBlaster/src/java/org/xmlBlaster/protocol/corba/xmlBlaster.idl" target="others">CORBA xmlBlaster.idl</a>
377 */
378 public void publishOneway(MsgUnitRaw [] msgUnitArr) throws XmlBlasterException
379 {
380 if (log.isLoggable(Level.FINER)) log.finer("publishOneway(), RMI does not support oneway, we switch to publishArr() ...");
381 publishArr(msgUnitArr);
382 }
383
384 /**
385 * @see <a href="http://www.xmlBlaster.org/xmlBlaster/src/java/org/xmlBlaster/protocol/corba/xmlBlaster.idl" target="others">CORBA xmlBlaster.idl</a>
386 */
387 public final String[] erase(String xmlKey, String qos) throws XmlBlasterException
388 {
389 if (log.isLoggable(Level.FINER)) log.finer("erase() ...");
390 try {
391 return getXmlBlaster().erase(this.sessionId, xmlKey, qos);
392 } catch(XmlBlasterException e) {
393 throw e;
394 } catch(Exception e) {
395 throw new XmlBlasterException(glob, ErrorCode.COMMUNICATION_NOCONNECTION, ME, "erase", e);
396 }
397 }
398
399
400 /**
401 * @see <a href="http://www.xmlBlaster.org/xmlBlaster/src/java/org/xmlBlaster/protocol/corba/xmlBlaster.idl" target="others">CORBA xmlBlaster.idl</a>
402 */
403 public final MsgUnitRaw[] get(String xmlKey, String qos) throws XmlBlasterException
404 {
405 if (log.isLoggable(Level.FINER)) log.finer("get() ...");
406 try {
407 return getXmlBlaster().get(this.sessionId, xmlKey, qos);
408 } catch(XmlBlasterException e) {
409 throw e;
410 } catch(Exception e) {
411 e.printStackTrace();
412 throw new XmlBlasterException(glob, ErrorCode.COMMUNICATION_NOCONNECTION, ME, "get", e);
413 }
414 }
415
416 /**
417 * Register a listener for to receive information about the progress of incoming data.
418 * Only one listener is supported, the last call overwrites older calls. This implementation
419 * does nothing here, it just returns null.
420 *
421 * @param listener Your listener, pass 0 to unregister.
422 * @return The previously registered listener or 0
423 */
424 public I_ProgressListener registerProgressListener(I_ProgressListener listener) {
425 log.fine("This method is currently not implemeented.");
426 return null;
427 }
428
429 /**
430 * Check server.
431 * @see <a href="http://www.xmlBlaster.org/xmlBlaster/src/java/org/xmlBlaster/protocol/corba/xmlBlaster.idl" target="others">CORBA xmlBlaster.idl</a>
432 */
433 public String ping(String str) throws XmlBlasterException {
434 try {
435 return getXmlBlaster().ping(str);
436 } catch(Exception e) {
437 throw new XmlBlasterException(glob, ErrorCode.COMMUNICATION_NOCONNECTION, ME, "ping", e);
438 }
439 }
440
441
442 /**
443 * Command line usage.
444 * <p />
445 * These variables may be set in xmlBlaster.properties as well.
446 * Don't use the "-" prefix there.
447 */
448 public static String usage()
449 {
450 String text = "\n";
451 text += "RmiConnection 'RMI' options:\n";
452 text += " -dispatch/connection/plugin/rmi/registryPort\n";
453 text += " Specify a port number where rmiregistry of the xmlBlaster server listens.\n";
454 text += " Default is port "+DEFAULT_REGISTRY_PORT+", the port 0 switches this feature off.\n";
455 text += " -dispatch/connection/plugin/rmi/hostname\n";
456 text += " Specify a hostname where rmiregistry of the xmlBlaster server runs.\n";
457 text += " Default is the localhost.\n";
458 text += " -dispatch/callback/plugin/rmi/registryPort\n";
459 text += " Specify a port number where rmiregistry for the callback server listens.\n";
460 text += " Default is port "+DEFAULT_REGISTRY_PORT+", the port 0 switches this feature off.\n";
461 text += " -dispatch/callback/plugin/rmi/hostname\n";
462 text += " Specify a hostname where rmiregistry for the callback server runs.\n";
463 text += " Default is the localhost (useful for multi homed hosts).\n";
464 text += "\n";
465 return text;
466 }
467 } // class RmiConnection
syntax highlighted by Code2HTML, v. 0.9.1