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 }