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: JmsServer.java,v 1.48.2.1 2004/05/06 11:35:09 tanderson Exp $
44   */
45  package org.exolab.jms.server;
46  
47  import java.io.PrintStream;
48  import java.lang.reflect.Constructor;
49  import java.util.ArrayList;
50  
51  import javax.naming.Context;
52  import javax.naming.NamingException;
53  
54  import org.apache.commons.logging.Log;
55  import org.apache.commons.logging.LogFactory;
56  import org.apache.log4j.xml.DOMConfigurator;
57  
58  import org.exolab.core.service.ServiceException;
59  import org.exolab.core.service.ServiceManager;
60  import org.exolab.core.util.RmiRegistryService;
61  import org.exolab.jms.authentication.AuthenticationMgr;
62  import org.exolab.jms.config.Configuration;
63  import org.exolab.jms.config.ConfigurationManager;
64  import org.exolab.jms.config.Connector;
65  import org.exolab.jms.config.ConnectorHelper;
66  import org.exolab.jms.config.ConnectorResource;
67  import org.exolab.jms.config.LoggerConfiguration;
68  import org.exolab.jms.config.types.SchemeType;
69  import org.exolab.jms.events.BasicEventManager;
70  import org.exolab.jms.gc.GarbageCollectionService;
71  import org.exolab.jms.jndi.JndiServerIfc;
72  import org.exolab.jms.lease.LeaseManager;
73  import org.exolab.jms.messagemgr.DestinationManager;
74  import org.exolab.jms.messagemgr.MessageMgr;
75  import org.exolab.jms.persistence.DatabaseService;
76  import org.exolab.jms.scheduler.Scheduler;
77  import org.exolab.jms.threads.ThreadPoolManager;
78  import org.exolab.jms.util.CommandLine;
79  import org.exolab.jms.util.Version;
80  
81  
82  /***
83   * This class contains the main line for instantiating the JMS Server. It
84   * dynamically detemrines, from the configuration information which of the
85   * servers to implement and then calls the init method on them.
86   *
87   * @version     $Revision: 1.48.2.1 $ $Date: 2004/05/06 11:35:09 $
88   * @author      <a href="mailto:jima@exoffice.com">Jim Alateras</a>
89   * @author      <a href="mailto:tima@intalio.com">Tim Anderson</a>
90   * @see         ConfigurationManager
91   */
92  public class JmsServer {
93  
94      /***
95       * The service manager
96       */
97      protected ServiceManager _services = null;
98  
99      /***
100      * The interfaces to this server. One interface is constructed for
101      * each configured connector.
102      */
103     private JmsServerIfc[] _interfaces = null;
104 
105     /***
106      * The JNDI providers, when using embedded JNDI. One server is
107      * constructed for each configured connector.
108      */
109     private JndiServerIfc[] _jndiInterfaces = null;
110 
111     /***
112      * The configuration of this server
113      */
114     private Configuration _config;
115 
116     /***
117      * The logger
118      */
119     private static final Log _log = LogFactory.getLog(JmsServer.class);
120 
121     /***
122      * Construct a new <code>JmsServer</code>
123      *
124      * @param config the server configuration
125      * @throws ServerException if the server cannot be created
126      */
127     public JmsServer(Configuration config) throws ServerException {
128         version();
129         ConfigurationManager.setConfig(config);
130         _config = config;
131     }
132 
133 
134     /***
135      * Construct a new <code>JmsServer</code>, configured from the specified
136      * configuration file.
137      *
138      * @param file configuration file name
139      * @throws ServerException if the server cannot be created
140      */
141     public JmsServer(String file) throws ServerException {
142         version();
143 
144         try {
145             // initialise the configuration manager
146             ConfigurationManager.setConfig(file);
147             _config = ConfigurationManager.getConfig();
148         } catch (Exception exception) {
149             throw new FailedToCreateServerException(
150                 "Failed to read configuration: " + file, exception);
151         }
152     }
153 
154     /***
155      * Initialise the server
156      *
157      * @throws NamingException if administered objects cannot be bound in JNDI
158      * @throws ServerException if the server cannot be initialised
159      */
160     public void init() throws NamingException, ServerException {
161         // initialise the logger
162         LoggerConfiguration log = _config.getLoggerConfiguration();
163 
164         // @todo - need to do this in main(), to allow pluggable log factories
165         // when embedding OpenJMS
166         DOMConfigurator.configure(log.getFile());
167 
168         // initialise the service manager
169         _services = ServiceManager.instance();
170 
171         // initialise the embedded JNDI server if required
172         if (_config.getServerConfiguration().getEmbeddedJNDI()) {
173             EmbeddedNameService.getInstance();
174         }
175 
176         // create the embedded RMI registry, if it is configured
177         if (hasConnector(SchemeType.RMI) &&
178             _config.getRmiConfiguration().getEmbeddedRegistry()) {
179             createRegistry();
180         }
181 
182         // initialise the services, and start them
183 
184         try {
185             registerServices();
186             _services.startAll();
187         } catch (ServiceException exception) {
188             throw new ServerException("Failed to start services", exception);
189         }
190 
191         // create and bind administered destinations
192         DestinationManager.instance().registerConfiguredAdministeredDestinations();
193 
194         Context context = NamingHelper.getInitialContext(_config);
195 
196         // create the server interfaces
197         initConnectors(context);
198 
199         // create the JNDI provider interfaces if required
200         if (_config.getServerConfiguration().getEmbeddedJNDI()) {
201             initJNDIConnectors(context);
202         }
203     }
204 
205     /***
206      * This is the main line for the JMS Server. It processes the command line
207      * argument, instantiates an instance of the server class and calls the
208      * init routine on it.
209      */
210     public static void main(String[] args) {
211         try {
212             CommandLine cmdline = new CommandLine(args);
213 
214             boolean helpSet = cmdline.exists("help");
215             boolean versionSet = cmdline.exists("version");
216             boolean configSet = cmdline.exists("config");
217 
218             if (helpSet) {
219                 usage();
220             } else if (versionSet) {
221                 version();
222             } else if (!configSet && args.length != 0) {
223                 // invalid argument specified
224                 usage();
225             } else {
226                 String config = cmdline.value(
227                     "config", getOpenJMSHome() + "/config/openjms.xml");
228                 JmsServer server = new JmsServer(config);
229                 server.init();
230             }
231         } catch (Exception exception) {
232             exception.printStackTrace();
233             // force termination of any threads
234             System.exit(-1);
235         }
236     }
237 
238     public static void version() {
239         System.err.println(Version.TITLE + " " + Version.VERSION);
240         System.err.println(Version.COPYRIGHT);
241         System.err.println(Version.VENDOR_URL);
242     }
243 
244     /***
245      * Print out information on running this sevice
246      */
247     protected static void usage() {
248         PrintStream out = System.out;
249 
250         out.println("\n\n");
251         out.println("=====================================================");
252         out.println("Usage information for org.exolab.jms.server.JmsServer");
253         out.println("=====================================================");
254         out.println("\norg.exolab.jms.server.JmsServer");
255         out.println("    [-config <xml config file> | -version | -help]\n");
256         out.println("\t-config  file name of xml-based config file\n");
257         out.println("\t-version displays OpenJMS version information\n");
258         out.println("\t-help    displays this screen\n");
259     }
260 
261     /***
262      * Initialise the services
263      */
264     protected void registerServices() throws ServiceException {
265         // add the thread pool manager
266         _services.add(ThreadPoolManager.instance().getName(),
267             ThreadPoolManager.instance());
268 
269         // add the event manager
270         _services.add(BasicEventManager.instance().getName(),
271             BasicEventManager.instance());
272 
273         // add the database service
274         _services.add(DatabaseService.instance().getName(),
275             DatabaseService.instance());
276 
277         // add the scheduler
278         _services.add(Scheduler.createInstance().getName(),
279             Scheduler.instance());
280 
281         // add the lease manager
282         _services.add(LeaseManager.instance().getName(),
283             LeaseManager.instance());
284 
285         // add the transaction manager
286         //_services.add (TransactionService.instance().getName(),
287         //                 TransactionService.instance());
288 
289         // add the garbage collection service
290         _services.add(GarbageCollectionService.instance().getName(),
291             GarbageCollectionService.instance());
292 
293         // add the authentication manager
294         _services.add(AuthenticationMgr.createInstance().getName(),
295             AuthenticationMgr.instance());
296 
297         // add the resource manager service
298         //_services.add(ResourceManager.instance().getName(),
299         //                ResourceManager.instance());
300 
301         // add the message manager
302         _services.add(MessageMgr.createInstance().getName(),
303             MessageMgr.instance());
304     }
305 
306     /***
307      * Creates an interface to the server for each configured connector
308      *
309      * @param context the initial context
310      * @throws NamingException if administered objects cannot be bound in JNDI
311      * @throws ServerException if an interface can't be created
312      */
313     protected void initConnectors(Context context)
314         throws NamingException, ServerException {
315 
316         Connector[] connectors = _config.getConnectors().getConnector();
317         _interfaces = new JmsServerIfc[connectors.length];
318 
319         for (int i = 0; i < connectors.length; ++i) {
320             Connector connector = connectors[i];
321             _interfaces[i] = initConnector(connector, context);
322         }
323     }
324 
325     /***
326      * Create an interface to the server for the specified connector
327      *
328      * @param connector the connector
329      * @param context the initial context
330      * @return the interface corresponding to <code>connector</code>
331      * @throws NamingException if administered objects cannot be bound in JNDI
332      * @throws ServerException if the interface can't be created
333      */
334     protected JmsServerIfc initConnector(Connector connector, Context context)
335         throws NamingException, ServerException {
336 
337         _log.info("Creating server interface for the " + connector.getScheme()
338             + " connector");
339 
340         JmsServerIfc server;
341         ConnectorResource resource = ConnectorHelper.getConnectorResource(
342             connector.getScheme());
343 
344         String className = resource.getServer().getImplementationClass();
345         Class clazz;
346         try {
347             clazz = Class.forName(className);
348         } catch (ClassNotFoundException exception) {
349             throw new FailedToCreateServerException(
350                 "Failed to load class " + className);
351         }
352 
353         if (!JmsServerIfc.class.isAssignableFrom(clazz)) {
354             throw new FailedToCreateServerException(
355                 "Class " + className + " does not implement JmsServerIfc");
356         }
357         try {
358             server = (JmsServerIfc) clazz.newInstance();
359             _log.debug("Created an instance of " + className
360                 + " as a server interface");
361         } catch (Exception exception) {
362             throw new FailedToCreateServerException(
363                 exception.getMessage(), exception);
364         }
365 
366         // initialise the interface
367         server.init();
368 
369         // bind any configured connection factories
370         server.bindConnectionFactories(context);
371 
372         return server;
373     }
374 
375     protected void createRegistry() throws ServerException {
376 
377         int port = _config.getRmiConfiguration().getRegistryPort();
378         try {
379             RmiRegistryService service = new RmiRegistryService(port);
380             _services.add(service.getName(), service);
381         } catch (Exception exception) {
382             throw new FailedToCreateServerException(
383                 "Failed to start the RMI registry", exception);
384         }
385         _log.info("Embedded RMI registry running on port " + port);
386     }
387 
388     /***
389      * Creates a JNDI provider interface for each connector that supports it
390      *
391      * @param context the initial context
392      * @throws NamingException if a provider can't be initialised
393      * @throws ServerException if a provider can't be created
394      */
395     protected void initJNDIConnectors(Context context)
396         throws NamingException, ServerException {
397 
398         Connector[] connectors = _config.getConnectors().getConnector();
399         ArrayList interfaces = new ArrayList();
400 
401         for (int i = 0; i < connectors.length; ++i) {
402             Connector connector = connectors[i];
403             ConnectorResource resource = ConnectorHelper.getConnectorResource(
404                 connector.getScheme());
405             if (resource.getJndi().getImplementationClass() != null) {
406                 JndiServerIfc provider = initJNDIConnector(resource, context);
407                 interfaces.add(provider);
408             }
409         }
410         _jndiInterfaces = (JndiServerIfc[]) interfaces.toArray(
411             new JndiServerIfc[0]);
412     }
413 
414     /***
415      * Creates a JNDI provider interface for the specified connector
416      *
417      * @param connector the connector
418      * @param context the initial context
419      * @return the JNDI provider interface
420      * @throws NamingException if the provider can't be initialised
421      * @throws ServerException if the provider can't be created
422      */
423     protected JndiServerIfc initJNDIConnector(
424         ConnectorResource connector, Context context)
425         throws NamingException, ServerException {
426 
427         _log.info("Creating JNDI interface for the " + connector.getScheme()
428             + " connector");
429 
430         JndiServerIfc result;
431         String className = connector.getJndi().getImplementationClass();
432         Class clazz;
433         try {
434             clazz = Class.forName(className);
435         } catch (ClassNotFoundException exception) {
436             throw new FailedToCreateServerException(
437                 "Failed to load class " + className);
438         }
439         if (!JndiServerIfc.class.isAssignableFrom(clazz)) {
440             throw new FailedToCreateServerException(
441                 "Class " + className + " does not implement JndiServerIfc");
442         }
443         try {
444             Constructor constructor = clazz.getDeclaredConstructor(
445                 new Class[]{Context.class});
446             result = (JndiServerIfc) constructor.newInstance(
447                 new Object[]{context});
448             result.init();
449             _log.debug("Created an instance of " + className
450                 + " as a JNDI provider interface");
451         } catch (Exception exception) {
452             throw new FailedToCreateServerException(
453                 exception.getMessage(), exception);
454         }
455         return result;
456     }
457 
458     /***
459      * Determines if the configuration has the specified connector
460      *
461      * @param scheme the connector scheme
462      * @return <code>true<code> if the configuration has a connector
463      * corresponding to <code>scheme</code>
464      */
465     private boolean hasConnector(SchemeType scheme) {
466         boolean result = false;
467         Connector[] connectors = _config.getConnectors().getConnector();
468         for (int i = 0; i < connectors.length; ++i) {
469             if (connectors[i].getScheme().equals(scheme)) {
470                 result = true;
471                 break;
472             }
473         }
474         return result;
475     }
476 
477     /***
478      * Returns the value of the openjms.home environment variable
479      */
480     private static String getOpenJMSHome() {
481         return System.getProperty("openjms.home",
482             System.getProperty("user.dir"));
483     }
484 
485 } //-- JmsServer