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
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
162 LoggerConfiguration log = _config.getLoggerConfiguration();
163
164
165
166 DOMConfigurator.configure(log.getFile());
167
168
169 _services = ServiceManager.instance();
170
171
172 if (_config.getServerConfiguration().getEmbeddedJNDI()) {
173 EmbeddedNameService.getInstance();
174 }
175
176
177 if (hasConnector(SchemeType.RMI) &&
178 _config.getRmiConfiguration().getEmbeddedRegistry()) {
179 createRegistry();
180 }
181
182
183
184 try {
185 registerServices();
186 _services.startAll();
187 } catch (ServiceException exception) {
188 throw new ServerException("Failed to start services", exception);
189 }
190
191
192 DestinationManager.instance().registerConfiguredAdministeredDestinations();
193
194 Context context = NamingHelper.getInitialContext(_config);
195
196
197 initConnectors(context);
198
199
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
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
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
266 _services.add(ThreadPoolManager.instance().getName(),
267 ThreadPoolManager.instance());
268
269
270 _services.add(BasicEventManager.instance().getName(),
271 BasicEventManager.instance());
272
273
274 _services.add(DatabaseService.instance().getName(),
275 DatabaseService.instance());
276
277
278 _services.add(Scheduler.createInstance().getName(),
279 Scheduler.instance());
280
281
282 _services.add(LeaseManager.instance().getName(),
283 LeaseManager.instance());
284
285
286
287
288
289
290 _services.add(GarbageCollectionService.instance().getName(),
291 GarbageCollectionService.instance());
292
293
294 _services.add(AuthenticationMgr.createInstance().getName(),
295 AuthenticationMgr.instance());
296
297
298
299
300
301
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
367 server.init();
368
369
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 }