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: ServerConnectionManagerImpl.java,v 1.3 2005/09/05 13:38:04 tanderson Exp $ 44 */ 45 package org.exolab.jms.server; 46 47 import java.security.Principal; 48 import java.util.HashMap; 49 import java.util.HashSet; 50 import javax.jms.InvalidClientIDException; 51 import javax.jms.JMSException; 52 import javax.jms.JMSSecurityException; 53 54 import org.apache.commons.logging.Log; 55 import org.apache.commons.logging.LogFactory; 56 57 import org.exolab.jms.common.security.BasicPrincipal; 58 import org.exolab.jms.messagemgr.ConsumerManager; 59 import org.exolab.jms.messagemgr.MessageManager; 60 import org.exolab.jms.messagemgr.ResourceManager; 61 import org.exolab.jms.net.connector.Authenticator; 62 import org.exolab.jms.net.connector.ResourceException; 63 import org.exolab.jms.persistence.DatabaseService; 64 import org.exolab.jms.scheduler.Scheduler; 65 66 67 /*** 68 * The <code>ServerConnectionManagerImpl</code> is responsible for managing all 69 * connections to the 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.3 $ $Date: 2005/09/05 13:38:04 $ 74 * @see ServerConnectionImpl 75 */ 76 public class ServerConnectionManagerImpl implements ServerConnectionManager { 77 78 /*** 79 * The authenticator. 80 */ 81 private final Authenticator _authenticator; 82 83 /*** 84 * The message manager. 85 */ 86 private final MessageManager _messages; 87 88 /*** 89 * The consumer manager. 90 */ 91 private ConsumerManager _consumers; 92 93 /*** 94 * The resource manager. 95 */ 96 private ResourceManager _resources; 97 98 /*** 99 * The database service. 100 */ 101 private final DatabaseService _database; 102 103 /*** 104 * The scheduler. 105 */ 106 private final Scheduler _scheduler; 107 108 /*** 109 * The set of active connections. 110 */ 111 private HashMap _connections = new HashMap(); 112 113 /*** 114 * The set of client identifiers. 115 */ 116 private HashSet _clientIDs = new HashSet(); 117 118 /*** 119 * Seed for connection identifiers. 120 */ 121 private long _seed = 0; 122 123 /*** 124 * The logger. 125 */ 126 private final Log _log 127 = LogFactory.getLog(ServerConnectionManagerImpl.class); 128 129 130 /*** 131 * Construct a new <code>ServerConnectionManagerImpl</code>. 132 * 133 * @param authenticator the authenticator to verify users with 134 */ 135 public ServerConnectionManagerImpl(Authenticator authenticator, 136 MessageManager messages, 137 DatabaseService database, 138 Scheduler scheduler) { 139 if (authenticator == null) { 140 throw new IllegalArgumentException( 141 "Argument 'authenticator' is null"); 142 } 143 if (messages == null) { 144 throw new IllegalArgumentException("Argument 'messages' is null"); 145 } 146 if (database == null) { 147 throw new IllegalArgumentException("Argument 'database' is null"); 148 } 149 if (scheduler == null) { 150 throw new IllegalArgumentException("Argument 'scheduler' is null"); 151 } 152 _authenticator = authenticator; 153 _messages = messages; 154 _database = database; 155 _scheduler = scheduler; 156 } 157 158 /*** 159 * Sets the consumer manager. 160 * 161 * @param consumers the consumer manager 162 */ 163 public void setConsumerManager(ConsumerManager consumers) { 164 _consumers = consumers; 165 } 166 167 /*** 168 * Sets the resource manager. 169 * 170 * @param resources the resource manager. 171 */ 172 public void setResourceManager(ResourceManager resources) { 173 _resources = resources; 174 } 175 176 /*** 177 * Creates a connection with the specified user identity. 178 * <p/> 179 * The connection is created in stopped mode. No messages will be delivered 180 * until the <code>Connection.start</code> method is explicitly called. 181 * <p/> 182 * If <code>clientID</code> is specified, it indicates the pre-configured 183 * client identifier associated with the client <code>ConnectionFactory</code> 184 * object. 185 * 186 * @param clientID the pre-configured client identifier. May be 187 * <code>null</code> <code>null</code>. 188 * @param userName the caller's user name 189 * @param password the caller's password 190 * @return a newly created connection 191 * @throws InvalidClientIDException if the JMS client specifies an invalid 192 * or duplicate client ID. 193 * @throws JMSException if the JMS provider fails to create the 194 * connection due to some internal error. 195 * @throws JMSSecurityException if client authentication fails due to an 196 * invalid user name or password. 197 */ 198 public ServerConnection createConnection(String clientID, String userName, 199 String password) 200 throws JMSException { 201 Principal principal = null; 202 if (userName != null) { 203 principal = new BasicPrincipal(userName, password); 204 } 205 try { 206 if (!_authenticator.authenticate(principal)) { 207 throw new JMSSecurityException("Failed to authenticate user: " + 208 userName); 209 } 210 } catch (ResourceException exception) { 211 _log.error(exception, exception); 212 throw new JMSSecurityException("Failed to authenticate user " 213 + userName); 214 } 215 216 ServerConnectionImpl result = null; 217 synchronized (_connections) { 218 addClientID(clientID); 219 long connectionId = ++_seed; 220 result = new ServerConnectionImpl( 221 this, connectionId, clientID, _messages, _consumers, 222 _resources, _database, _scheduler); 223 _connections.put(new Long(connectionId), result); 224 } 225 226 return result; 227 } 228 229 /*** 230 * Returns the connection associated with a particular connection 231 * identifier. 232 * 233 * @param connectionId the connection identifier 234 * @return the connection associated with <code>connectionId</code>, or 235 * <code>null</code> if none exists 236 */ 237 public ServerConnectionImpl getConnection(long connectionId) { 238 ServerConnectionImpl result = null; 239 synchronized (_connections) { 240 Long key = new Long(connectionId); 241 result = (ServerConnectionImpl) _connections.get(key); 242 } 243 return result; 244 } 245 246 /*** 247 * Notify closure of a connection. 248 * 249 * @param connection the connection that has been closed 250 */ 251 public void closed(ServerConnectionImpl connection) { 252 synchronized (_connections) { 253 Long key = new Long(connection.getConnectionId()); 254 _connections.remove(key); 255 _clientIDs.remove(connection.getClientID()); 256 } 257 } 258 259 /*** 260 * Register a client identifer. 261 * 262 * @param clientID the client identifier. If <code>null</code, it is 263 * ignored. 264 * @throws InvalidClientIDException if the identifier is a duplicate. 265 */ 266 public void addClientID(String clientID) throws InvalidClientIDException { 267 synchronized (_connections) { 268 if (clientID != null) { 269 if (!_clientIDs.add(clientID)) { 270 throw new InvalidClientIDException( 271 "Duplicate clientID: " + clientID); 272 } 273 } 274 } 275 } 276 277 }