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-2004 (C) Exoffice Technologies Inc. All Rights Reserved. 42 * 43 * $Id: JmsConnection.java,v 1.26 2004/01/11 02:33:44 tanderson Exp $ 44 * 45 * Date Author Changes 46 * 3/21/2000 jima Created 47 */ 48 package org.exolab.jms.client; 49 50 51 import java.util.Enumeration; 52 import java.util.Vector; 53 54 import javax.jms.Connection; 55 import javax.jms.ConnectionMetaData; 56 import javax.jms.ExceptionListener; 57 import javax.jms.IllegalStateException; 58 import javax.jms.JMSException; 59 60 import org.apache.commons.logging.Log; 61 import org.apache.commons.logging.LogFactory; 62 63 import org.exolab.core.service.ServiceException; 64 import org.exolab.jms.events.BasicEventManager; 65 66 67 /*** 68 * Client side implementation of the <code>javax.jms.Connection</code> 69 * interface. 70 * 71 * @version $Revision: 1.26 $ $Date: 2004/01/11 02:33:44 $ 72 * @author <a href="mailto:jima@exoffice.com">Jim Alateras</a> 73 * @author <a href="mailto:tma@netspace.net.au">Tim Anderson</a> 74 */ 75 abstract class JmsConnection implements Connection { 76 77 /*** 78 * This flag indicates whether or not the connection is closed. It 79 * is set to false on creation 80 */ 81 private boolean _closed = false; 82 83 /*** 84 * This flag indicates whether the connection is in the start or 85 * stopped state 86 */ 87 private boolean _stopped = true; 88 89 /*** 90 * This flag indicates whether the connection has been modified. 91 * If so, subsequent attempts to invoke {@link #setClientID} will 92 * cause an <code>IllegalStateException</code> being thrown 93 */ 94 private boolean _modified = false; 95 96 /*** 97 * This is the identity associated with the client. The identity is 98 * generated and assigned by the connection factory 99 */ 100 private String _clientId = null; 101 102 /*** 103 * Gates the setting of the clientId more than once 104 */ 105 private boolean _clientIdSet = false; 106 107 /*** 108 * A connection can maintain one and only one exception listener, The 109 * listener will be informed of unusual and exception events 110 */ 111 private ExceptionListener _exceptionListener = null; 112 113 /*** 114 * Manage the list of activated and registered sessions. Everytime a 115 * session is created through this connection it is registered. 116 */ 117 private Vector _sessions = new Vector(); 118 119 /*** 120 * This is a back pointer to the connection factory which created this 121 * connection. It is assigned during object construction 122 */ 123 private JmsConnectionFactory _factory = null; 124 125 /*** 126 * This is a stub to a remote object on the JMSSever. This abstraction 127 * allows us to use different underlying ORBS. 128 */ 129 private JmsConnectionStubIfc _stub = null; 130 131 /*** 132 * The id is generated by the server and is unique for each connection 133 * created. This id is then used to generate other ids 134 */ 135 private String _connectionId = null; 136 137 /*** 138 * The number of connections created 139 */ 140 private static volatile int _activeConnections = 0; 141 142 /*** 143 * The connection data is immutable at this stage. This enables us to cache 144 * a single copy in memory 145 */ 146 private static final JmsConnectionMetaData _metaData = 147 new JmsConnectionMetaData(); 148 149 /*** 150 * The logger 151 */ 152 private static final Log _log = LogFactory.getLog(JmsConnection.class); 153 154 155 /*** 156 * Construct a new <code>JmsConnection</code> 157 * <p> 158 * This attempts to establish a connection to the JMS server 159 * 160 * @param factory the connection factory responsible for creating this 161 * @param id the client identity 162 * @param username the client username 163 * @param password the client password 164 * @throws JMSException if a connection cannot be established 165 */ 166 protected JmsConnection(JmsConnectionFactory factory, String id, 167 String username, String password) 168 throws JMSException { 169 170 if (factory == null) { 171 throw new IllegalArgumentException("Argument 'factory' is null"); 172 } 173 if (id == null) { 174 throw new IllegalArgumentException("Argument 'id' is null"); 175 } 176 if (id.trim().length() == 0) { 177 throw new IllegalArgumentException("Argument 'id' is invalid: '" 178 + id + "'"); 179 } 180 181 _factory = factory; 182 _clientId = id; 183 184 _stopped = true; 185 186 // use the factory object to retrieve the proxy that 187 // will be used to get a JmsConnectionStubIfc instance 188 // and cache its identity locally 189 _stub = factory.getProxy().createConnection(_clientId, username, 190 password); 191 _connectionId = _stub.getConnectionId(); 192 193 // start the event manager 194 startEventManager(); 195 } 196 197 // implementation of Connection.getClientID 198 public String getClientID() throws JMSException { 199 ensureOpen(); 200 setModified(); 201 202 return _clientId; 203 } 204 205 206 // implementation of Connection.setClientID 207 public void setClientID(String id) throws JMSException { 208 ensureOpen(); 209 210 // check if the client id has already been set 211 if (_clientIdSet) { 212 throw new IllegalStateException( 213 "The client id has already been set"); 214 } 215 216 if (_modified) { 217 throw new IllegalStateException( 218 "The client identifier must be set before any other operation " 219 + "is performed"); 220 } 221 222 // gate the client id from being set more than once. 223 _clientId = id; 224 _clientIdSet = true; 225 } 226 227 228 // implementation of Connection.getMetaData 229 public ConnectionMetaData getMetaData() throws JMSException { 230 ensureOpen(); 231 setModified(); 232 return _metaData; 233 } 234 235 // implementation of Connection.getExceptionListener 236 public ExceptionListener getExceptionListener() throws JMSException { 237 ensureOpen(); 238 setModified(); 239 return _exceptionListener; 240 } 241 242 243 // implementation of Connection.setExceptionListener 244 public void setExceptionListener(ExceptionListener listener) 245 throws JMSException { 246 ensureOpen(); 247 setModified(); 248 _exceptionListener = listener; 249 } 250 251 /*** 252 * Notify the exception listener of a JMSException. If the exception 253 * listener is not set then ignore it 254 * 255 * @param message message to deliver 256 */ 257 public void notifyExceptionListener(JMSException message) { 258 // check the error code 259 if (message.getErrorCode() != null && 260 message.getErrorCode().equals( 261 JmsErrorCodes.CONNECTION_TO_SERVER_DROPPED)) { 262 // the connection to the server has been dropped so we need to 263 // release all local resources. 264 try { 265 destroy(); 266 } catch (JMSException exception) { 267 _log.error(exception.getMessage(), exception); 268 } 269 } 270 271 // finally notify registered exception listener 272 if (_exceptionListener != null) { 273 _exceptionListener.onException(message); 274 } 275 } 276 277 // implementation of Connection.start 278 public synchronized void start() throws JMSException { 279 ensureOpen(); 280 setModified(); 281 282 try { 283 if (_stopped) { 284 // propagate the start to all the associated sessions. When 285 // that is complete transition the state of the connection to 286 // RUNNING 287 Enumeration sessions = _sessions.elements(); 288 while (sessions.hasMoreElements()) { 289 JmsSession session = (JmsSession) sessions.nextElement(); 290 session.start(); 291 } 292 // set the state of the connection to start 293 _stopped = false; 294 } 295 } catch (JMSException exception) { 296 // do we need to change _stopped to true if the any of the 297 // sessions fail to start 298 throw exception; 299 } 300 } 301 302 // implementation of Connection.stop 303 public synchronized void stop() throws JMSException { 304 ensureOpen(); 305 setModified(); 306 307 if (!_stopped) { 308 // propagate the stop to all the encapsulated sessions before 309 // changing the state of the connection. Only when all the 310 // sessions have successfully transitioned, without exception, 311 // do we change the state of the connection 312 Enumeration sessions = _sessions.elements(); 313 while (sessions.hasMoreElements()) { 314 JmsSession session = (JmsSession) sessions.nextElement(); 315 session.stop(); 316 } 317 318 // set the state of the connection to stopped before stopping 319 // all the enclosed sessions 320 _stopped = true; 321 } 322 } 323 324 // implementation of Connection.close 325 public synchronized void close() throws JMSException { 326 if (!_closed) { 327 try { 328 // before we close we should stop the connection and any 329 // associated sessions 330 stop(); 331 332 // propagate the close to all the encapsulated sessions before 333 // changing the state of the connection. Only when all the 334 // sessions have successfully transitioned, without exception, 335 // do we change the state of the connection. All the sessions 336 // are removed from the connection. 337 Object sessions[] = _sessions.toArray(); 338 for (int i = 0; i < sessions.length; ++i) { 339 JmsSession session = (JmsSession) sessions[i]; 340 session.close(); 341 // the session deregisters itself with the connection via 342 // removeSession() 343 } 344 345 // send a close to the stub and then null the stub 346 getJmsConnectionStub().close(); 347 _stub = null; 348 349 // remove yourself from the list of connections managed by the 350 // connection factory and then null the factory. 351 _factory.removeConnection(this); 352 _factory = null; 353 354 // set the closed flag so calling it multiple times is 355 // cool 356 _closed = true; 357 } finally { 358 stopEventManager(); 359 } 360 } 361 } 362 363 /*** 364 * Release all resources used by this connection, including supporting 365 * sessions 366 * 367 * @throws JMSException - error completing this request 368 */ 369 public synchronized void destroy() throws JMSException { 370 if (!_closed) { 371 try { 372 // propagate the close to all the encapsulated sessions before 373 // changing the state of the connection. Only when all the 374 // sessions have successfully transitioned, without exception, 375 // do we change the state of the connection. All the sessions 376 // are removed from the connection. 377 Object sessions[] = _sessions.toArray(); 378 for (int i = 0; i < sessions.length; ++i) { 379 JmsSession session = (JmsSession) sessions[i]; 380 session.destroy(); 381 } 382 383 // send a close to the stub and then null the stub 384 getJmsConnectionStub().destroy(); 385 _stub = null; 386 387 // remove yourself from the list of connections managed by the 388 // connection factory and then null the factory. 389 _factory.removeConnection(this); 390 _factory = null; 391 392 // set the closed flag so calling it multiple times is 393 // cool 394 _closed = true; 395 } finally { 396 stopEventManager(); 397 } 398 } 399 } 400 401 /*** 402 * Return the identity of this connection. An identity is created by the 403 * server and is unique within that servers environment 404 * 405 * @return String 406 */ 407 public String getConnectionId() { 408 return _connectionId; 409 } 410 411 /*** 412 * Return an instance of the remote server connection. If one has not 413 * been assigned then throw the JMSException exception 414 * 415 * @return JmsConnectionStub connection to the server 416 * @throws JMSException 417 */ 418 JmsConnectionStubIfc getJmsConnectionStub() throws JMSException { 419 if (_stub == null) { 420 throw new JMSException("The connectionstub is set to null"); 421 } 422 423 return _stub; 424 } 425 426 /*** 427 * Add the specified session to the list of managed sessions 428 * 429 * @param session session to register 430 */ 431 protected void addSession(JmsSession session) { 432 _sessions.addElement(session); 433 } 434 435 /*** 436 * Remove the specified session from the list of managed sessions. 437 * If it doesn't exist then fail silently 438 * 439 * @param session session to remove 440 */ 441 protected void removeSession(JmsSession session) { 442 _sessions.removeElement(session); 443 } 444 445 /*** 446 * Test whether the specified session is managed by this connection 447 * 448 * @param session session to test against 449 * @return boolean true if managed 450 */ 451 protected boolean isManaged(JmsSession session) { 452 return _sessions.contains(session); 453 } 454 455 /*** 456 * Returns an enumeration of all sessions managed by this connection 457 * 458 * @return an enumeration of all sessions managed by this connection 459 */ 460 protected Enumeration getSessions() { 461 return _sessions.elements(); 462 } 463 464 /*** 465 * Return the running state of the connection 466 * 467 * @return <code>true</code> if stopped 468 */ 469 protected boolean isStopped() { 470 return _stopped; 471 } 472 473 /*** 474 * Flags this connection as being modified. Subsequent attempts 475 * to invoke {@link #setClientID} will result in an 476 * <code>IllegalStateException</code> being thrown 477 */ 478 protected void setModified() { 479 _modified = true; 480 } 481 482 /*** 483 * Delete the temporary destination and all the registered sessions 484 * consumers waiting to receive messages from this destination will 485 * be stopped. 486 * <p> 487 * It will throw a JMSException if the specified destination is not 488 * temporary or if the destination is null or if the destination is 489 * not owned by this connection 490 * 491 * @param destination temporary destination to delete 492 * @throws JMSException 493 */ 494 synchronized void deleteTemporaryDestination(JmsDestination destination) 495 throws JMSException { 496 if ((destination != null) && 497 (destination instanceof JmsTemporaryDestination)) { 498 JmsTemporaryDestination temp_dest = 499 (JmsTemporaryDestination) destination; 500 501 // check to see that this destination was actually created by 502 // this connection 503 if (temp_dest.getOwningConnection() == this) { 504 // this is currently a no-op but we probably need a way to 505 // clean up on the server side 506 } else { 507 throw new JMSException("The temp destination cannot be " + 508 "used outside the scope of the connection creating it"); 509 } 510 } else { 511 throw new JMSException("The destination is not temporary"); 512 } 513 } 514 515 /*** 516 * Verifies that the connection is open 517 * 518 * @throws IllegalStateException if the connection is closed 519 */ 520 protected void ensureOpen() throws IllegalStateException { 521 if (_closed) { 522 throw new IllegalStateException( 523 "Cannot perform operation - session has been closed"); 524 } 525 } 526 527 /*** 528 * This method will start the event manager service on the first connection 529 * that is created 530 */ 531 private static void startEventManager() { 532 try { 533 if (_activeConnections++ == 0) { 534 try { 535 BasicEventManager.instance().start(); 536 } catch (ServiceException exception) { 537 // ignore 538 } 539 } 540 } catch (Exception exception) { 541 _log.error(exception.getMessage(), exception); 542 } 543 } 544 545 /*** 546 * This method will terminate the event manager service when the last 547 * connection has been closed 548 */ 549 private static void stopEventManager() { 550 try { 551 if (--_activeConnections == 0) { 552 BasicEventManager.instance().stop(); 553 } 554 } catch (Exception exception) { 555 exception.printStackTrace(); 556 } 557 } 558 559 } //-- JmsConnection 560

This page was automatically generated by Maven