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-2003 (C) Exoffice Technologies Inc. All Rights Reserved.
42   *
43   * $Id: IpcJmsServer.java,v 1.18 2003/08/07 13:33:09 tanderson Exp $
44   *
45   * Date         Author  Changes
46   * $Date	    jimm    Created
47   */
48  
49  package org.exolab.jms.server.mipc;
50  
51  import java.io.IOException;
52  import java.net.InetAddress;
53  import java.util.HashMap;
54  import java.util.Hashtable;
55  
56  import javax.naming.Context;
57  import javax.naming.NamingException;
58  
59  import org.exolab.core.ipc.NotifierIfc;
60  import org.exolab.core.mipc.ConnectionNotifierIfc;
61  import org.exolab.core.mipc.MultiplexConnectionIfc;
62  import org.exolab.core.mipc.MultiplexConnectionServer;
63  import org.exolab.core.mipc.MultiplexConnectionServerIfc;
64  import org.exolab.jms.client.mipc.IpcJmsConstants;
65  import org.exolab.jms.config.Configuration;
66  import org.exolab.jms.config.ConfigurationManager;
67  import org.exolab.jms.config.Connector;
68  import org.exolab.jms.config.ConnectorHelper;
69  import org.exolab.jms.config.ConnectorResource;
70  import org.exolab.jms.config.ServerConfiguration;
71  import org.exolab.jms.config.TcpConfigurationType;
72  import org.exolab.jms.config.types.SchemeType;
73  import org.exolab.jms.server.ConnectionFactoryHelper;
74  import org.exolab.jms.server.JmsServerIfc;
75  import org.exolab.jms.server.JmsServerSession;
76  import org.exolab.jms.server.ServerException;
77  import org.exolab.jms.server.http.HttpJmsSessionConnection;
78  
79  
80  /***
81   * This class implements the JmsServerIfc and provides an IPC-based JMS Server.
82   *
83   * @version     $Revision: 1.18 $ $Date: 2003/08/07 13:33:09 $
84   * @author      <a href="mailto:mourikis@intalio.com">Jim Mourikis</a>
85   * @see         org.exolab.jms.server.JmsServer
86   * @see		org.exolab.jms.server.mipc.IpcJmsReceiver
87   */
88  public class IpcJmsServer implements JmsServerIfc, ConnectionNotifierIfc {
89  
90      /***
91       * The ipc connection server
92       */
93      private MultiplexConnectionServerIfc _server;
94  
95      /***
96       * The list of all client consumer connections, used to send JmsMessages
97       * on.
98       */
99      private HashMap _consumerList = new HashMap(10);
100 
101 
102     /***
103      * Construct a new <code>IpcJmsServer</code>
104      */
105     public IpcJmsServer() {
106     }
107 
108     /***
109      * ConnectionNotifierIfc method implementation.
110      * The MultipleConnectionServer calls this method whenever a new
111      * MultiplexConnection is established.
112      * It gives the user of MCS an opportunity to setup channel handlers.
113      */
114     public void connected(MultiplexConnectionIfc newConnection) {
115         IpcServerChannel cs;
116         cs = new IpcServerChannel(newConnection, getReceiver(), "server");
117         cs.start();
118     }
119 
120     /***
121      * Start the Ipc service in its own thread. This will then listen for
122      * new connections, establish connections as they arrive, and call the
123      * callback with new data when received.
124      */
125     public void init() throws ServerException {
126         TcpConfigurationType tcp = getTcpConfiguration();
127 
128         try {
129             _server = createServer(tcp.getPort());
130         } catch (IOException exception) {
131             throw new ServerException(
132                 "Failed to initialise server for the " + getScheme() +
133                 " connector", exception);
134         }
135 
136         ((Thread) _server).start();
137     }
138 
139     // implementation of JmsServerIfc.bindConnectionFactories
140     public void bindConnectionFactories(Context context)
141         throws NamingException, ServerException {
142 
143         Configuration config = ConfigurationManager.getConfig();
144 
145         // retrieve the configuration information from the configuration
146         // manager
147         ServerConfiguration server = config.getServerConfiguration();
148         TcpConfigurationType tcp = getTcpConfiguration();
149         String host = normalizeHost(server.getHost());
150         String internalHost = normalizeHost(tcp.getInternalHost());
151 
152         // we need to put together a list of parameters that the
153         // connection factories will need to use to connect
154         // to this server
155         Hashtable env = new Hashtable();
156         env.put(IpcJmsConstants.IPC_SERVER_HOST, host);
157         env.put(IpcJmsConstants.IPC_SERVER_PORT,
158             Integer.toString(tcp.getPort()));
159         if (internalHost != null) {
160             env.put(IpcJmsConstants.IPC_INTERNAL_SERVER_HOST, internalHost);
161         }
162         Connector connector = ConfigurationManager.getConnector(getScheme());
163         ConnectorResource resource =
164             ConnectorHelper.getConnectorResource(getScheme());
165 
166         Class proxy;
167         String className = resource.getServer().getProxyClass();
168         try {
169             proxy = Class.forName(className);
170         } catch (ClassNotFoundException exception) {
171             throw new ServerException(
172                 "Failed to locate the server proxy class: " + className);
173         }
174 
175         ConnectionFactoryHelper.bind(
176             context, connector.getConnectionFactories(), proxy, env);
177     }
178 
179     /***
180      * Add a new connection for this client.
181      *
182      * @param session the session
183      * @param connection the connection to the client
184      * @throws IOException if a connection error occurs
185      */
186     public synchronized void addConnection(JmsServerSession session,
187                                            MultiplexConnectionIfc connection)
188         throws IOException {
189         IpcJmsSessionList list =
190             (IpcJmsSessionList) _consumerList.get(connection);
191         if (list == null) {
192             list = new IpcJmsSessionList(connection);
193             _consumerList.put(connection, list);
194         }
195         list.add(session);
196     }
197 
198     /***
199      * Remove this sessions connection
200      *
201      * @param session the session
202      * @param connection the connection to the client
203      */
204     public synchronized void removeConnection(
205         JmsServerSession session, MultiplexConnectionIfc connection) {
206         IpcJmsSessionList list = (IpcJmsSessionList) _consumerList.get(
207             connection);
208         if (list != null) {
209             if (list.remove(session)) {
210                 _consumerList.remove(connection);
211             }
212         }
213     }
214 
215     /***
216      * Remove all managed client connections
217      */
218     public synchronized void removeAllConnections() {
219         Object[] e = _consumerList.values().toArray();
220 
221         for (int i = 0, j = _consumerList.size(); i < j; i++) {
222             ((IpcJmsSessionList) e[i]).removeAll();
223         }
224         _consumerList.clear();
225     }
226 
227     /***
228      * Create an normal connection.
229      *
230      * @param port The port number to use.
231      * @return the created connection
232      * @throws IOException if the server fails to initialise the ip service
233      */
234     protected MultiplexConnectionServerIfc createServer(int port)
235         throws IOException {
236         return new MultiplexConnectionServer(port, this);
237     }
238 
239     /***
240      * Returns the connector scheme for this server. Defaults to tcp
241      */
242     protected SchemeType getScheme() {
243         return SchemeType.TCP;
244     }
245 
246     /***
247      * Returns the TCP configuration
248      *
249      * @return the TCP configuration
250      */
251     protected TcpConfigurationType getTcpConfiguration() {
252         return ConfigurationManager.getConfig().getTcpConfiguration();
253     }
254 
255     /***
256      * Returns a new receiver for handling requests
257      */
258     protected IpcJmsReceiver getReceiver() {
259         IpcJmsReceiver receiver = new IpcJmsReceiver();
260 
261         NotifierIfc sessionHandler = new IpcJmsSessionConnection(this);
262         receiver.addDispatcher(sessionHandler.getClass().getName(),
263             sessionHandler);
264 
265         NotifierIfc serverHandler = new IpcJmsServerConnection();
266         receiver.addDispatcher(serverHandler.getClass().getName(),
267             serverHandler);
268 
269         NotifierIfc adminHandler = new IpcJmsAdminConnection();
270         receiver.addDispatcher(adminHandler.getClass().getName(),
271             adminHandler);
272 
273         // this is a hack... The http connector is inextricably tied to the
274         // tcp connector in the current architecture, so its unavoidable for
275         // the moment.
276         NotifierIfc httpHandler = new HttpJmsSessionConnection(this);
277         receiver.addDispatcher(httpHandler.getClass().getName(), httpHandler);
278 
279         return receiver;
280     }
281 
282     /***
283      * This method will normalize the host name. If the host is localhost then
284      * it will be converted to the corresponding IP address
285      *
286      * @param host - the raw host name
287      * @return String - the normalized IP address
288      */
289     private String normalizeHost(String host) {
290         String server = host;
291 
292         // ensure that the host is not null
293         if (host == null) {
294             return host;
295         }
296 
297         if (host.equals("localhost")) {
298             try {
299                 server = InetAddress.getLocalHost().getHostAddress();
300             } catch (java.net.UnknownHostException ignore) {
301                 // ignore
302             }
303         }
304 
305         return server;
306     }
307 
308 } //--IpcJmsServer