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 2003-2005 (C) Exoffice Technologies Inc. All Rights Reserved. 42 * 43 * $Id: AbstractConnectionManager.java,v 1.6 2005/06/04 14:43:59 tanderson Exp $ 44 */ 45 package org.exolab.jms.net.connector; 46 47 import java.security.Principal; 48 import java.util.Collection; 49 import java.util.HashMap; 50 import java.util.Map; 51 import java.util.Iterator; 52 53 import org.exolab.jms.net.uri.URI; 54 55 56 /*** 57 * Abstract implementation of the {@link ConnectionManager} interface. 58 * 59 * @author <a href="mailto:tma@netspace.net.au">Tim Anderson</a> 60 * @version $Revision: 1.6 $ $Date: 2005/06/04 14:43:59 $ 61 * @todo - code smell - implements ConnectionFactory 62 */ 63 public abstract class AbstractConnectionManager 64 implements ConnectionManager, ConnectionFactory { 65 66 /*** 67 * The set of managed connection factories, and their corresponding 68 * ConnectionPools. 69 */ 70 private final Map _factories = new HashMap(); 71 72 /*** 73 * The invocation handler. 74 */ 75 private final InvocationHandler _handler; 76 77 /*** 78 * The connection authenticator. 79 */ 80 private final Authenticator _authenticator; 81 82 /*** 83 * The set of known connection factories, and their associated 84 * ManagedConnectionFactorys. 85 */ 86 private final Map _connectionFactories = new HashMap(); 87 88 /*** 89 * Configuration properties. May be <code>null</code>. 90 */ 91 private final Map _properties; 92 93 /*** 94 * The caller event listener. 95 */ 96 private CallerListener _listener; 97 98 99 /*** 100 * Construct a new <code>AbstractConnectionManager</code>. 101 * 102 * @param handler the invocation handler 103 * @param authenticator the connection authenticator 104 * @param properties configuration properties. May be <code>null</code> 105 */ 106 public AbstractConnectionManager(InvocationHandler handler, 107 Authenticator authenticator, 108 Map properties) { 109 if (handler == null) { 110 throw new IllegalArgumentException("Argument 'handler' is null"); 111 } 112 if (authenticator == null) { 113 throw new IllegalArgumentException( 114 "Argument 'authenticator' is null"); 115 } 116 _handler = handler; 117 _authenticator = authenticator; 118 _properties = properties; 119 } 120 121 /*** 122 * Allocate a new connection. 123 * 124 * @param factory used by application server to delegate connection 125 * matching/creation 126 * @param principal the security principal 127 * @param info the connection request info 128 * @return the new connection 129 * @throws ResourceException if the connection cannot be allocated 130 */ 131 public Connection allocateConnection(ManagedConnectionFactory factory, 132 Principal principal, 133 ConnectionRequestInfo info) 134 throws ResourceException { 135 136 ConnectionPool pool = getConnectionPool(factory); 137 ManagedConnection connection = pool.matchManagedConnections(principal, 138 info); 139 if (connection == null) { 140 connection = pool.createManagedConnection(principal, info); 141 } 142 return connection.getConnection(); 143 } 144 145 /*** 146 * Start accepting connections. 147 * 148 * @param factory used to delegate acceptor matching/creation 149 * @param info connection request info 150 * @throws ResourceException if the connections cannot be accepted 151 */ 152 public void accept(ManagedConnectionFactory factory, 153 ConnectionRequestInfo info) throws ResourceException { 154 ConnectionPool pool = getConnectionPool(factory); 155 ManagedConnectionAcceptor acceptor = 156 pool.matchManagedConnectionAcceptors(info); 157 if (acceptor == null) { 158 acceptor = pool.createManagedConnectionAcceptor(_authenticator, 159 info); 160 acceptor.accept(pool.getManagedConnectionAcceptorListener()); 161 } 162 } 163 164 /*** 165 * Determines if this factory supports connections to the specified URI. 166 * 167 * @param uri the connection address 168 * @return <code>true</code> if this factory supports the URI; 169 * <code>false</code> otherwise 170 */ 171 public boolean canConnect(URI uri) { 172 ConnectionFactory factory = getFactoryForConnect(uri); 173 return (factory != null); 174 } 175 176 /*** 177 * Returns a connection to the specified URI, using the default connection 178 * properties. 179 * 180 * @param principal the security principal. May be <code>null</code> 181 * @param uri the connection address 182 * @return a connection to <code>uri</code> 183 * @throws ResourceException if a connection cannot be established 184 */ 185 public Connection getConnection(Principal principal, URI uri) 186 throws ResourceException { 187 return getConnection(principal, uri, null); 188 } 189 190 /*** 191 * Returns a connection to the specified URI, using the specified connection 192 * properties. 193 * 194 * @param principal the security principal. May be <code>null</code> 195 * @param uri the connection address 196 * @param properties connection properties. If <code>null</code>, use the 197 * default connection properties 198 * @return a connection to <code>uri</code> 199 * @throws ResourceException if a connection cannot be established 200 */ 201 public Connection getConnection(Principal principal, URI uri, 202 Map properties) 203 throws ResourceException { 204 ConnectionFactory factory = getFactoryForConnect(uri); 205 if (factory == null) { 206 throw new ResourceException("No connector for URI=" + uri); 207 } 208 return factory.getConnection(principal, uri, properties); 209 } 210 211 /*** 212 * Determines if this factory supports listening for new connections on the 213 * specified URI. 214 * 215 * @param uri the connection address 216 * @return <code>true</code> if this factory supports the URI; 217 * <code>false</code> otherwise 218 */ 219 public boolean canAccept(URI uri) { 220 ConnectionFactory factory = getFactoryForAccept(uri); 221 return (factory != null); 222 } 223 224 /*** 225 * Listen for new connections on the specified URI, using the default 226 * connection acceptor properties. 227 * 228 * @param uri the connection address 229 * @throws ResourceException if connections can't be accepted on the 230 * specified URI 231 */ 232 public void accept(URI uri) throws ResourceException { 233 accept(uri, null); 234 } 235 236 /*** 237 * Listen for new connections on the specified URI, using the specified 238 * acceptor properties. 239 * 240 * @param uri the connection address 241 * @param properties acceptor properties. May be <code>null</code> 242 * @throws ResourceException if connections can't be accepted on the 243 * specified URI 244 */ 245 public void accept(URI uri, Map properties) 246 throws ResourceException { 247 ConnectionFactory factory = getFactoryForAccept(uri); 248 if (factory == null) { 249 throw new ResourceException("No connector for URI=" + uri); 250 } 251 factory.accept(uri, properties); 252 } 253 254 /*** 255 * Sets the caller event listener. 256 * 257 * @param listener the listener 258 */ 259 public synchronized void setCallerListener(CallerListener listener) { 260 _listener = listener; 261 Iterator iterator = _factories.values().iterator(); 262 while (iterator.hasNext()) { 263 ConnectionPool pool = (ConnectionPool) iterator.next(); 264 pool.setCallerListener(_listener); 265 } 266 } 267 268 /*** 269 * Close this connection manager. 270 * 271 * @throws ResourceException if a connection pool cannot be closed 272 */ 273 public synchronized void close() throws ResourceException { 274 Iterator iterator = _factories.values().iterator(); 275 while (iterator.hasNext()) { 276 ConnectionPool pool = (ConnectionPool) iterator.next(); 277 pool.close(); 278 } 279 _factories.clear(); 280 } 281 282 /*** 283 * Returns the first factory which can support connections to the specified 284 * URI. 285 * 286 * @param uri the URI 287 * @return the first factory which can support connections to 288 * <code>uri</code>, or <code>null</code> if none support it 289 */ 290 protected synchronized ConnectionFactory getFactoryForConnect(URI uri) { 291 ConnectionFactory result = null; 292 Iterator iterator = _connectionFactories.keySet().iterator(); 293 while (iterator.hasNext()) { 294 ConnectionFactory factory = (ConnectionFactory) iterator.next(); 295 if (factory.canConnect(uri)) { 296 result = factory; 297 break; 298 } 299 } 300 return result; 301 } 302 303 /*** 304 * Returns the first factory which can accept connections on the specified 305 * URI. 306 * 307 * @param uri the URI 308 * @return the first factory which can accept connections on 309 * <code>uri</code>, or <code>null</code> if none support it 310 */ 311 protected synchronized ConnectionFactory getFactoryForAccept(URI uri) { 312 ConnectionFactory result = null; 313 Iterator iterator = _connectionFactories.keySet().iterator(); 314 while (iterator.hasNext()) { 315 ConnectionFactory factory = (ConnectionFactory) iterator.next(); 316 if (factory.canAccept(uri)) { 317 result = factory; 318 break; 319 } 320 } 321 return result; 322 } 323 324 /*** 325 * Register a managed connection factory. 326 * 327 * @param factory the factory to register 328 * @throws ResourceException if the registration fails 329 */ 330 protected synchronized void addManagedConnectionFactory( 331 ManagedConnectionFactory factory) throws ResourceException { 332 ConnectionPool pool = createConnectionPool(factory, _handler, this); 333 pool.setCallerListener(_listener); 334 _factories.put(factory, pool); 335 _connectionFactories.put(factory.createConnectionFactory(this), 336 factory); 337 } 338 339 /*** 340 * Returns all registered managed connection factories. 341 * 342 * @return all registered managed connection factories 343 */ 344 protected synchronized Collection getManagedConnectionFactories() { 345 return _factories.keySet(); 346 } 347 348 /*** 349 * Creates a new connection pool. 350 * 351 * @param factory the managed connection factory 352 * @param handler the invocation handler, assigned to each new managed 353 * connection 354 * @param resolver the connection factory for resolving connections via 355 * their URI 356 * @throws ResourceException if the pool can't be created 357 */ 358 protected ConnectionPool createConnectionPool( 359 ManagedConnectionFactory factory, InvocationHandler handler, 360 ConnectionFactory resolver) throws ResourceException { 361 return new DefaultConnectionPool(factory, handler, resolver, 362 _properties); 363 } 364 365 /*** 366 * Returns the {@link ConnectionPool} which pools connections for the 367 * specified factory. 368 * 369 * @param factory the factory to locate the pool for 370 * @return the connection pool for <code>factory</code> 371 * @throws ResourceException if no connection pool exists 372 */ 373 protected synchronized ConnectionPool getConnectionPool( 374 ManagedConnectionFactory factory) throws ResourceException { 375 ConnectionPool pool = (ConnectionPool) _factories.get(factory); 376 if (pool == null) { 377 throw new ResourceException("Connection pool not found"); 378 } 379 return pool; 380 } 381 382 }