View Javadoc

1   /***
2    * Redistribution and use of this software and associated documentation
3    * ("Software"), with or without modification, are permitted provided
4    * that the following conditions are met:
5    *
6    * 1. Redistributions of source code must retain copyright
7    *    statements and notices.  Redistributions must also contain a
8    *    copy of this document.
9    *
10   * 2. Redistributions in binary form must reproduce the
11   *    above copyright notice, this list of conditions and the
12   *    following disclaimer in the documentation and/or other
13   *    materials provided with the distribution.
14   *
15   * 3. The name "Exolab" must not be used to endorse or promote
16   *    products derived from this Software without prior written
17   *    permission of Exoffice Technologies.  For written permission,
18   *    please contact info@exolab.org.
19   *
20   * 4. Products derived from this Software may not be called "Exolab"
21   *    nor may "Exolab" appear in their names without prior written
22   *    permission of Exoffice Technologies. Exolab is a registered
23   *    trademark of Exoffice Technologies.
24   *
25   * 5. Due credit should be given to the Exolab Project
26   *    (http://www.exolab.org/).
27   *
28   * THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS
29   * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
30   * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
31   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
32   * EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
33   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39   * OF THE POSSIBILITY OF SUCH DAMAGE.
40   *
41   * Copyright 2000-2005 (C) Exoffice Technologies Inc. All Rights Reserved.
42   *
43   * $Id: JmsServerStubImpl.java,v 1.5 2005/11/18 03:29:41 tanderson Exp $
44   */
45  package org.exolab.jms.client.net;
46  
47  import java.rmi.AccessException;
48  import java.rmi.NotBoundException;
49  import java.rmi.RemoteException;
50  import java.util.HashMap;
51  import java.util.Map;
52  import javax.jms.ExceptionListener;
53  import javax.jms.InvalidClientIDException;
54  import javax.jms.JMSException;
55  import javax.jms.JMSSecurityException;
56  
57  import org.exolab.jms.client.JmsServerStubIfc;
58  import org.exolab.jms.net.connector.Caller;
59  import org.exolab.jms.net.connector.CallerListener;
60  import org.exolab.jms.net.orb.ORB;
61  import org.exolab.jms.net.registry.Registry;
62  import org.exolab.jms.net.proxy.Proxy;
63  import org.exolab.jms.server.ServerConnection;
64  import org.exolab.jms.server.ServerConnectionFactory;
65  
66  
67  /***
68   * This class is responsible for returning a reference to the remote JMS
69   * server.
70   *
71   * @author <a href="mailto:jima@comware.com.au">Jim Alateras</a>
72   * @author <a href="mailto:tma@netspace.net.au">Tim Anderson</a>
73   * @version $Revision: 1.5 $ $Date: 2005/11/18 03:29:41 $
74   */
75  public class JmsServerStubImpl implements JmsServerStubIfc, CallerListener {
76  
77      /***
78       * The ORB.
79       */
80      private ORB _orb;
81  
82      /***
83       * Properties used to establish a connection to the remote server.
84       */
85      private final Map _properties;
86  
87      /***
88       * The server URI;
89       */
90      private final String _serverURI;
91  
92      /***
93       * Default user to connect to server. May be <code>null</code>.
94       */
95      private final String _defaultUser;
96  
97      /***
98       * Default user's password. May be <code>null</code>.
99       */
100     private final String _defaultPassword;
101 
102     /***
103      * The exception listener, which is shared by all the connections to the
104      * server.
105      */
106     private ExceptionListener _listener = null;
107 
108 
109     /***
110      * Construct a new <code>JmsServerStubImpl</code>.
111      *
112      * @param properties  properties to initialise this with
113      * @param environment the environment used. May be <code>null</code>
114      */
115     public JmsServerStubImpl(Map properties, Map environment) {
116         if (properties == null) {
117             throw new IllegalArgumentException("Argument 'properties' is null");
118         }
119         _properties = properties;
120 
121         _serverURI = (String) properties.get(ORB.PROVIDER_URI);
122         if (_serverURI == null) {
123             throw new IllegalArgumentException(
124                     "Argument 'properties' does not contain property "
125                     + ORB.PROVIDER_URI);
126         }
127         if (environment != null) {
128             _defaultUser = (String) environment.get(ORB.SECURITY_PRINCIPAL);
129             _defaultPassword = (String) environment.get(
130                     ORB.SECURITY_CREDENTIALS);
131         } else {
132             _defaultUser = null;
133             _defaultPassword = null;
134         }
135     }
136 
137     /***
138      * Creates a connection with the specified user identity.
139      * <p/>
140      * The connection is created in stopped mode. No messages will be delivered
141      * until the <code>Connection.start</code> method is explicitly called.
142      * <p/>
143      * If <code>clientID</code> is specified, it indicates the pre-configured
144      * client identifier associated with the client
145      * <code>ConnectionFactory</code> object.
146      *
147      * @param clientID the pre-configured client identifier. May be
148      *                 <code>null</code>.
149      * @param user     the caller's user name. May be <code>null</code>
150      * @param password the caller's password. May be <code>null</code>
151      * @return a newly created connection
152      * @throws InvalidClientIDException if the JMS client specifies an invalid
153      *                                  or duplicate client ID.
154      * @throws JMSException             if the JMS provider fails to create the
155      *                                  connection due to some internal error.
156      * @throws JMSSecurityException     if client authentication fails due to an
157      *                                  invalid user name or password.
158      */
159     public ServerConnection createConnection(String clientID, String user,
160                                              String password)
161             throws JMSException {
162         ServerConnection stub;
163 
164         if (user == null) {
165             user = _defaultUser;
166             password = _defaultPassword;
167         }
168 
169         ServerConnectionFactory factory
170                 = getServerConnectionFactory(user, password);
171         try {
172             ServerConnection connection
173                     = factory.createConnection(clientID, user, password);
174             stub = new JmsConnectionStubImpl(connection, _orb, _serverURI,
175                                              user, password);
176         } finally {
177             if (factory instanceof Proxy) {
178                 ((Proxy) factory).disposeProxy();
179             }
180         }
181         return stub;
182     }
183 
184     /***
185      * Set the exception listener so that the client can be notified of client
186      * disconnection events.
187      *
188      * @param listener the exception listener
189      */
190     public void setExceptionListener(ExceptionListener listener) {
191         _listener = listener;
192     }
193 
194     /***
195      * Notifies that a caller has been disconnected.
196      *
197      * @param caller the caller that was disconnected
198      */
199     public void disconnected(Caller caller) {
200         if (_listener != null) {
201             _listener.onException(new JMSException("Lost connection"));
202         }
203     }
204 
205     /***
206      * Looks up and returns the {@link ServerConnectionFactory} instance bound
207      * in the registry.
208      *
209      * @param user     the caller's user name. May be <code>null</code>
210      * @param password the caller's password. May be <code>null</code>
211      * @return the bound {@link ServerConnectionFactory}
212      * @throws JMSException if lookup fails
213      */
214     private synchronized ServerConnectionFactory getServerConnectionFactory(
215             String user, String password)
216             throws JMSException {
217         ServerConnectionFactory factory = null;
218         Map properties = _properties;
219 
220         if (user != null) {
221             properties = new HashMap(_properties);
222             properties.put(ORB.SECURITY_PRINCIPAL, user);
223             properties.put(ORB.SECURITY_CREDENTIALS, password);
224         }
225         Registry registry = null;
226         try {
227             if (_orb == null) {
228                 _orb = SharedORB.getInstance();
229             }
230             registry = _orb.getRegistry(properties);
231         } catch (AccessException exception) {
232             JMSSecurityException error = new JMSSecurityException(
233                     exception.getMessage());
234             error.setLinkedException(exception);
235             throw error;
236         } catch (RemoteException exception) {
237             JMSException error = new JMSException(
238                     "Failed to get registry service for URL: " + _serverURI);
239             error.setLinkedException(exception);
240             throw error;
241         }
242 
243         try {
244             factory = (ServerConnectionFactory) registry.lookup("server");
245         } catch (NotBoundException exception) {
246             throw new JMSException(
247                     "Server is not bound in the registry for URL: "
248                     + _serverURI);
249         } catch (RemoteException exception) {
250             JMSException error = new JMSException(
251                     "Failed to lookup OpenJMS server for URL: " + _serverURI);
252             error.setLinkedException(exception);
253             throw error;
254         }
255         try {
256             _orb.addCallerListener(_serverURI, this);
257         } catch (RemoteException exception) {
258             JMSException error = new JMSException(
259                     "Failed to register for disconnection notification for "
260                     + "URL: " + _serverURI);
261             error.setLinkedException(exception);
262             throw error;
263         }
264 
265         if (registry instanceof Proxy) {
266             ((Proxy) registry).disposeProxy();
267         }
268         return factory;
269     }
270 
271 }