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-2004 (C) Exoffice Technologies Inc. All Rights Reserved.
42 *
43 * $Id: IpcJmsServerStub.java,v 1.19 2004/01/20 14:11:36 tanderson Exp $
44 */
45
46 package org.exolab.jms.client.mipc;
47
48 import java.io.IOException;
49 import java.util.HashSet;
50 import java.util.Hashtable;
51 import java.util.Vector;
52
53 import javax.jms.ExceptionListener;
54 import javax.jms.JMSException;
55 import javax.jms.JMSSecurityException;
56
57 import org.apache.commons.logging.Log;
58 import org.apache.commons.logging.LogFactory;
59
60 import org.exolab.core.ipc.IpcIfc;
61 import org.exolab.core.mipc.DisconnectionEventListener;
62 import org.exolab.core.mipc.MultiplexConnection;
63 import org.exolab.core.mipc.MultiplexConnectionIfc;
64 import org.exolab.core.mipc.ObjectChannel;
65 import org.exolab.core.mipc.TcpConstants;
66 import org.exolab.jms.client.JmsConnectionStubIfc;
67 import org.exolab.jms.client.JmsErrorCodes;
68 import org.exolab.jms.client.JmsServerStubIfc;
69
70
71 /***
72 * This class is repsonsible for opening an ipc connection to the server
73 * and creating IpcJmsConnections.
74 *
75 * @version $Revision: 1.19 $ $Date: 2004/01/20 14:11:36 $
76 * @author <a href="mailto:mourikis@exolab.org">Jim Mourikis</a>
77 * @see org.exolab.jms.client.mipc.IpcJmsConnectionStub
78 * @see org.exolab.core.mipc.DisconnectionEventListener
79 **/
80 public class IpcJmsServerStub
81 implements JmsServerStubIfc, DisconnectionEventListener {
82
83 /***
84 * The multiplex connection to the server
85 */
86 private MultiplexConnectionIfc _mc = null;
87
88 /***
89 * The server channel
90 */
91 private IpcIfc _connection = null;
92
93 /***
94 * The server host address
95 */
96 private String _serverAddress = TcpConstants.LOCAL_HOST;
97
98 /***
99 * The internal server host address if OpenJMS server is serving both
100 * internet connections behind a NAT router and internal connections.
101 */
102 private String _internalServerAddress = null;
103
104 /***
105 * The port number the server is listening to
106 */
107 private int _port = TcpConstants.DEFAULT_PORT;
108
109 /***
110 * The set of open IpcJmsConnectionStub instances
111 */
112 private HashSet _connections = new HashSet();
113
114 /***
115 * The message dispatcher
116 */
117 private IpcJmsMessageListener _listener;
118
119 /***
120 * The exception listener is used to communicate server connection
121 * problems
122 */
123 private ExceptionListener _exceptionListener = null;
124
125 /***
126 * The logger
127 */
128 private static final Log _log = LogFactory.getLog(IpcJmsServerStub.class);
129
130
131 /***
132 * Default constructor for serialization
133 */
134 public IpcJmsServerStub() {
135 }
136
137 /***
138 * The constructor has a collection of environment variables
139 * which it uses to construct a connection to the remote
140 * server
141 *
142 * @param env
143 */
144 public IpcJmsServerStub(Hashtable env) {
145 if (env.containsKey(IpcJmsConstants.IPC_SERVER_HOST)) {
146 _serverAddress = (String) env.get(IpcJmsConstants.IPC_SERVER_HOST);
147 }
148 if (env.containsKey(IpcJmsConstants.IPC_INTERNAL_SERVER_HOST)) {
149 _internalServerAddress = (String) env.get
150 (IpcJmsConstants.IPC_INTERNAL_SERVER_HOST);
151 }
152
153 if (env.containsKey(IpcJmsConstants.IPC_SERVER_PORT)) {
154 try {
155 _port = Integer.parseInt((String) env.get(
156 IpcJmsConstants.IPC_SERVER_PORT));
157 } catch (NumberFormatException exception) {
158 // failure to convert exception use the
159 // default port
160 _log.warn("Server port is not a valid format."
161 + " Defaulting to " + _port);
162 }
163 }
164 }
165
166 /***
167 * Instantiate an instance of this stub with the specified host and
168 * port numbers
169 *
170 * @param host server host address
171 * @param port server port number
172 */
173 public IpcJmsServerStub(String host, int port) {
174 if ((host != null) &&
175 (host.length() > 0)) {
176 _serverAddress = host;
177 }
178
179 _port = port;
180 }
181
182 /***
183 * Create a connection to the JMS Server. A new connectionId will be
184 * returned if the connection is successful. Create a new IpcJmsConnection
185 * object with the given id's.
186 *
187 * @param clientId the identity of client
188 * @param username the client username
189 * @param password the client password
190 * @throws JMSException
191 */
192 public synchronized JmsConnectionStubIfc createConnection(
193 String clientId, String username, String password)
194 throws JMSException {
195 JmsConnectionStubIfc stub = null;
196
197 openConnection();
198 try {
199 String connectionId;
200 Vector v = pack("createConnection", clientId, username, password);
201 synchronized (_connection) {
202 _connection.send(v);
203 connectionId = (String) checkReply("createConnection");
204 }
205
206 stub = new IpcJmsConnectionStub(
207 this, _connection, clientId, connectionId, _listener);
208 _connections.add(stub);
209 } catch (JMSException exception) {
210 throw exception;
211 } catch (Exception exception) {
212 JMSException error = new JMSException(
213 "Failed to create connection");
214 error.setLinkedException(exception);
215 throw error;
216 }
217 return stub;
218 }
219
220 /***
221 * Set the server host. This is the host that the server runs on
222 *
223 * @param host the name of the host
224 */
225 public void setServerAddress(String host) {
226 _serverAddress = host;
227 }
228
229 /***
230 * Returns the server host
231 *
232 * @return the server host
233 */
234 public String getServerAddress() {
235 return _serverAddress;
236 }
237
238 /***
239 * Set the server port. This is the port that the server runs on
240 *
241 * @param port the server port number
242 */
243 public void setServerPort(int port) {
244 _port = port;
245 }
246
247 /***
248 * Returns the server port
249 *
250 * @return the server port
251 */
252 public int getServerPort() {
253 return _port;
254 }
255
256 // implementation of DisconnectionEventListener.disconnected
257 public void disconnected(MultiplexConnectionIfc connection) {
258 close();
259
260 // notify the exception listener if one is registered
261 if (_exceptionListener != null) {
262 JMSException exception = new JMSException(
263 "Connection to server terminated",
264 JmsErrorCodes.CONNECTION_TO_SERVER_DROPPED);
265 _exceptionListener.onException(exception);
266 }
267 }
268
269 // implementation of JmsServerStubIfc.setExceptionListener
270 public void setExceptionListener(ExceptionListener listener) {
271 _exceptionListener = listener;
272 }
273
274 public synchronized void close() {
275 // local clean up
276 try {
277 if (_connection != null) {
278 _connection.close();
279 _listener.stop();
280 _mc.finish();
281 }
282 } catch (Exception exception) {
283 // just swallow :-)
284 } finally {
285 _mc = null;
286 _connection = null;
287 _listener = null;
288 }
289 }
290
291 public synchronized void closed(IpcJmsConnectionStub connection) {
292 _connections.remove(connection);
293 if (_connections.isEmpty()) {
294 close();
295 }
296 }
297
298 /***
299 * Create a multiplexed connection to the server
300 *
301 * @param serverAddress the address of the server
302 * @param internalServerAddress internal server address. May be null.
303 * @param port the port number to use
304 * @return the connection to the server
305 * @throws IOException if the connection cannot be established
306 */
307 protected MultiplexConnectionIfc createClientConnection(
308 String serverAddress, String internalServerAddress, int port)
309 throws Exception {
310
311 MultiplexConnectionIfc result = null;
312
313 try {
314 result = new MultiplexConnection(serverAddress, port);
315 } catch (IOException exception) {
316 if (internalServerAddress != null) {
317 result = new MultiplexConnection(internalServerAddress, port);
318 } else {
319 // just rethrow it.
320 throw exception;
321 }
322 }
323 return result;
324 }
325
326 /***
327 * Check to see if an ipc connection has been created. If not, connect with
328 * the given hostname and port number.
329 *
330 * @throws JMSException if a connection cannot be established
331 */
332 private synchronized void openConnection() throws JMSException {
333 if (_mc == null) {
334 try {
335 _mc = createClientConnection(
336 _serverAddress, _internalServerAddress, _port);
337 } catch (Exception exception) {
338 throw new JMSException(
339 "Failed to create connection: " + exception);
340 }
341
342 _mc.setDisconnectionEventListener(this);
343 ((Thread) _mc).start();
344
345 _connection = new ObjectChannel("server", _mc);
346 _listener = new IpcJmsMessageListener(_mc);
347 }
348 }
349
350 /***
351 * A convenience method to check the success of operations which return
352 * a true on sucess.
353 *
354 * @param method The requested server function.
355 * @return the result of the call, or <code>null</code> if the call
356 * didn't return a result
357 * @throws JMSException for any failure.
358 */
359 private Object checkReply(String method) throws JMSException {
360 Object result = null;
361 Vector v = null;
362 try {
363 v = (Vector) _connection.receive();
364 } catch (Exception err) {
365 // rethrow as a JMSException
366 throw new JMSException("Operation " + method + " failed: " + err);
367 }
368
369 if (v != null) {
370 Boolean b = (Boolean) v.get(0);
371 if (!b.booleanValue()) {
372 if (v.get(1) instanceof JMSException) {
373 throw (JMSException) v.get(1);
374 } else {
375 throw new JMSException("Operation " + method +
376 " failed:\n" + v.get(1));
377 }
378 }
379 result = v.get(1);
380 } else {
381 throw new JMSException("Unknown connection error for " + method);
382 }
383
384 return result;
385 }
386
387 /***
388 * Pack all the data that is required by the server in a vector.
389 * Set the size of the vector to be exactly the right size for efficiency.
390 *
391 * @param method the function to invoke on the server.
392 * @param id the unique client id.
393 * @param username the client username
394 * @param password the client password
395 * @return Vector The vector containing all the data.
396 */
397 private Vector pack(String method, String id, String username,
398 String password) {
399 Vector v = new Vector(5);
400 v.add("org.exolab.jms.server.mipc.IpcJmsServerConnection");
401 v.add(method);
402 v.add(id);
403 v.add(username);
404 v.add(password);
405 return v;
406 }
407
408 }
This page was automatically generated by Maven