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