001: /**
002: * JOnAS: Java(TM) Open Application Server
003: * Copyright (C) 1999-2004 Bull S.A.
004: * Contact: jonas-team@objectweb.org
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
019: * USA
020: *
021: * --------------------------------------------------------------------------
022: * $Id: ServiceManager.java 9618 2006-09-21 11:27:49Z benoitf $
023: * --------------------------------------------------------------------------
024: */package org.objectweb.jonas.service;
025:
026: import java.util.ArrayList;
027: import java.util.Enumeration;
028: import java.util.Hashtable;
029: import java.util.List;
030: import java.util.Map;
031:
032: import javax.naming.Context;
033: import javax.naming.NamingException;
034:
035: import org.objectweb.jonas.common.JProp;
036: import org.objectweb.jonas.common.Log;
037: import org.objectweb.jonas.naming.CompNamingContext;
038:
039: import org.objectweb.util.monolog.api.BasicLevel;
040: import org.objectweb.util.monolog.api.Logger;
041:
042: /**
043: * This class implements a manager of org.objectweb.jonas.service.Service for JOnAS.
044: *
045: * The services are defined in the jonas.properties files
046: * - 'jonas.services' property defines the list of the services,
047: * - for each service
048: * - 'jonas.service.<service-name>.class' property defines the class of the
049: * implementation of the service,
050: * - 'jonas.service.<service-name>.XXXX' properties define the configuration
051: * of the service
052: *
053: * @author Helene Joanin
054: * Contributor(s):
055: * 01/06/15: Regis Le Brettevillois - Libelis
056: * 02/06 : Florent Benoit & Ludovic Bert : Ear service/Web Container service
057: * Philippe Durieux
058: * 03/01/14 Adriana Danes : pass the entire property name (jonas.service.<service-name>.XXXX)
059: * in the configuration context at service creation time
060: */
061:
062: public class ServiceManager {
063:
064: /**
065: * Services of JOnAS
066: */
067: static final String SERVICES_PROP_NAME = JProp.JONASPREFIX
068: + ".services";
069:
070: /**
071: * A JOnAS service
072: */
073: static final String PREFIX_SERVICE_PROP_NAME = JProp.JONASPREFIX
074: + ".service";
075:
076: /**
077: * The logger used.
078: */
079: private static Logger logger = null;
080:
081: /**
082: * The ServerManager singleton value
083: */
084: private static ServiceManager unique = null;
085:
086: /**
087: * JOnAS properties
088: */
089: private JProp props = null;
090:
091: /**
092: * The list of the managed services
093: */
094: private static List services = null;
095:
096: /**
097: * The managed services and their names
098: */
099: private Map servicesByName = null;
100:
101: /**
102: * The Configuration context for each managed service
103: */
104: private Map contextsByService = null;
105:
106: /**
107: * Private constructor to force only 1 instance.
108: * @throws Exception if the ServiceManager can't be built.
109: */
110: private ServiceManager() {
111: logger = Log.getLogger(Log.JONAS_SERVER_PREFIX);
112: // read properties from the different jonas.properties files
113: props = JProp.getInstance();
114: // read all services from properties
115: readServices();
116: }
117:
118: /**
119: * Get the unique instance.
120: * Create it at first call.
121: * @return ServiceManager the unique instance
122: * @throws Exception if the ServiceManager can't be built.
123: */
124: public static ServiceManager getInstance() {
125: if (unique == null) {
126: unique = new ServiceManager();
127: }
128: return unique;
129: }
130:
131: /**
132: * Get the service which have the given name
133: * @param name the given name
134: * @return the service which have the given name
135: * @throws ServiceException if the service can't be retrieved.
136: */
137: public Service getService(String name) throws ServiceException {
138: if (servicesByName == null) {
139: throw new ServiceException(
140: "No service has been initialized yet");
141: }
142: Service s = (Service) servicesByName.get(name);
143: if (s == null) {
144: throw new ServiceException("Unknown service '" + name + "'");
145: }
146: return s;
147: }
148:
149: /**
150: * Return the EJB service (service's name: 'ejb')
151: * @return the EJB service.
152: * @throws ServiceException if can not get the ejb service.
153: */
154: public Service getEjbService() throws ServiceException {
155: return getService("ejb");
156: }
157:
158: /**
159: * Return the Ear service (service's name: 'ear')
160: * @return the EAR service.
161: * @throws ServiceException if can not get the ear service.
162: */
163: public Service getEarService() throws ServiceException {
164: return getService("ear");
165: }
166:
167: /**
168: * Return the Rar service (service's name: 'resource')
169: * @return the RAR service.
170: * @throws ServiceException if can not get the rar service.
171: */
172: public Service getRarService() throws ServiceException {
173: return getService("resource");
174: }
175:
176: /**
177: * Return the web service (service's name: 'web').
178: * @return the web service.
179: * @throws ServiceException if can not get the web service.
180: */
181: public Service getWebContainerService() throws ServiceException {
182: return getService("web");
183: }
184:
185: /**
186: * Return the WebServices service (service's name: 'ws').
187: * @return the WebServices service.
188: * @throws ServiceException if can not get the WebServices service.
189: */
190: public Service getWebServicesService() throws ServiceException {
191: return getService("ws");
192: }
193:
194: /**
195: * Return the mail service (service's name: 'mail').
196: * @return the mail service.
197: * @throws ServiceException if can not get the mail service.
198: */
199: public Service getMailService() throws ServiceException {
200: return getService("mail");
201: }
202:
203: /**
204: * Return the DataBase service (service's name: 'dbm')
205: * @return the DBM service.
206: * @throws ServiceException if can not get the dbm service.
207: */
208: public Service getDataBaseService() throws ServiceException {
209: return getService("dbm");
210: }
211:
212: /**
213: * Return the Transaction service (service's name: 'jtm')
214: * @return the JTM service.
215: * @throws ServiceException if can not get the jtm service.
216: */
217: public Service getTransactionService() throws ServiceException {
218: return getService("jtm");
219: }
220:
221: /**
222: * Return the JMS service (service's name: 'jms')
223: * @return the JMS service.
224: * @throws ServiceException if can not get the jms service.
225: */
226: public Service getJmsService() throws ServiceException {
227: return getService("jms");
228: }
229:
230: /**
231: * Return the Security service (service's name: 'security')
232: * @return the Security service.
233: * @throws ServiceException if can not get the security service.
234: */
235: public Service getSecurityService() throws ServiceException {
236: return getService("security");
237: }
238:
239: /**
240: * Return the JMX service (service's name: 'jmx')
241: * @return the JMX service.
242: * @throws ServiceException if can not get the jmx service.
243: */
244: public Service getJmxService() throws ServiceException {
245: return getService("jmx");
246: }
247:
248: /**
249: * Return the discovery service (service's name: 'discovery')
250: * @return the discovery service.
251: * @throws ServiceException if can not get the discovery service.
252: */
253: public Service getDiscoveryService() throws ServiceException {
254: return getService("discovery");
255: }
256:
257: /**
258: * Return the Registry service (service's name: 'registry')
259: * @return the Registry service.
260: * @throws ServiceException if can not get the registry service.
261: */
262: public Service getRegistryService() throws ServiceException {
263: return getService("registry");
264: }
265:
266: /**
267: * Return the Resource service (service's name: 'resource')
268: * @return the Resource service.
269: * @throws ServiceException if can not get the resource service.
270: */
271: public Service getResourceService() throws ServiceException {
272: return getService("resource");
273: }
274:
275: /**
276: * Start the mandatory "registry" service
277: * @throws ServiceException if the "registry" service can't be started.
278: */
279: public void startRegistry() throws ServiceException {
280: if (logger.isLoggable(BasicLevel.DEBUG)) {
281: logger.log(BasicLevel.DEBUG, "");
282: }
283: Service reg = getRegistryService();
284: try {
285: reg.init((Context) contextsByService.get(reg));
286: reg.start();
287: logger.log(BasicLevel.INFO, "registry service started");
288: } catch (ServiceException e) {
289: throw new ServiceException("Cannot init/start registry" + e);
290: }
291: }
292:
293: /**
294: * Start the jmx service
295: * @throws ServiceException if the jmx service can't be started.
296: */
297: public void startJmx(String idMBeanServer) throws ServiceException {
298: if (logger.isLoggable(BasicLevel.DEBUG)) {
299: logger.log(BasicLevel.DEBUG, "");
300: }
301: Service jmxService = getJmxService();
302: try {
303: Context paramCtx = (Context) contextsByService
304: .get(jmxService);
305: if (idMBeanServer != null) {
306: try {
307: paramCtx.bind("idMBeanServer", idMBeanServer);
308: } catch (NamingException ne) {
309: throw new ServiceException(
310: "Cannot bind idMBeanServer = '"
311: + idMBeanServer
312: + "' for JMX service.", ne);
313: }
314: }
315: jmxService.init(paramCtx);
316: jmxService.start();
317: logger.log(BasicLevel.INFO, "jmx service started");
318: } catch (ServiceException e) {
319: throw e;
320: }
321: }
322:
323: /**
324: * Starts the managed services.
325: * @throws ServiceException if the services can't be started.
326: */
327: public void startServices() throws ServiceException {
328: if (logger.isLoggable(BasicLevel.DEBUG)) {
329: logger.log(BasicLevel.DEBUG, "");
330: }
331: Service[] services = getServices();
332: Context serviceContext = null;
333: // registry = service 0, already started.
334: // jmx = service 1, already started
335: for (int i = 2; i < services.length; i++) {
336: Service service = services[i];
337: try {
338: serviceContext = (Context) contextsByService
339: .get(service);
340: service.init(serviceContext);
341: service.start();
342: logger.log(BasicLevel.INFO, service.getName()
343: + " service started");
344: } catch (ServiceException e) {
345: throw new ServiceException(
346: "Cannot init/start service '"
347: + service.getName() + "': "
348: + e.getMessage(), e);
349: }
350: }
351: }
352:
353: /**
354: * Returns the list of the managed services
355: * @return String[] the name of the managed services.
356: * @throws ServiceException if the list can't be retrieved.
357: */
358: public Service[] getServices() throws ServiceException {
359: Service[] ss = new Service[services.size()];
360: for (int i = 0; i < services.size(); i++) {
361: ss[i] = (Service) services.get(i);
362: }
363: return ss;
364: }
365:
366: /**
367: * return the list of services + registry if needed.
368: * @return String[] the name of the services.
369: */
370: public String[] getServiceNames() {
371: if (logger.isLoggable(BasicLevel.DEBUG)) {
372: logger.log(BasicLevel.DEBUG, "");
373: }
374: String[] serviceNames;
375: serviceNames = props.getValueAsArray(SERVICES_PROP_NAME);
376: if (serviceNames == null) {
377: return null;
378: }
379: if (serviceNames[0].equals("registry")
380: && serviceNames[1].equals("jmx")) {
381: return serviceNames;
382: }
383: ArrayList services = new ArrayList();
384: services.add(0, "registry");
385: services.add(1, "jmx");
386: int nbServices = 2;
387: for (int i = 0; i < serviceNames.length; i++) {
388: if (!serviceNames[i].equals("registry")
389: && !serviceNames[i].equals("jmx")) {
390: services.add(serviceNames[i]);
391: nbServices++;
392: }
393: }
394: serviceNames = new String[nbServices];
395: if (logger.isLoggable(BasicLevel.DEBUG)) {
396: logger.log(BasicLevel.DEBUG,
397: "Created new array of String of size "
398: + services.size());
399: }
400: for (int i = 0; i < nbServices; i++) {
401: serviceNames[i] = (String) services.get(i);
402: }
403: return serviceNames;
404: }
405:
406: /**
407: * For each service, create it and its associated configuration context.
408: * (creates services, contextsByService and servicesByName)
409: * @throws ServiceException if the services can't be read.
410: */
411: protected void readServices() throws ServiceException {
412: if (logger.isLoggable(BasicLevel.DEBUG)) {
413: logger.log(BasicLevel.DEBUG, "");
414: }
415: services = new ArrayList();
416: contextsByService = new Hashtable();
417: servicesByName = new Hashtable();
418: String[] serviceNames;
419: serviceNames = getServiceNames();
420: if (serviceNames == null) {
421: throw new ServiceException("Property '"
422: + SERVICES_PROP_NAME + "' is missing in '"
423: + JProp.JONASPREFIX + "' properties file");
424: }
425: for (int i = 0; i < serviceNames.length; i++) {
426: String serviceName = serviceNames[i];
427: Service serviceObj = createServiceFrom(serviceName);
428: if (serviceObj != null) {
429: try {
430: Context ctx = createServiceContextFor(serviceName);
431: services.add(serviceObj);
432: contextsByService.put(serviceObj, ctx);
433: servicesByName.put(serviceName, serviceObj);
434: } catch (NamingException e) {
435: throw new ServiceException(
436: "cannot create the context name of the service '"
437: + serviceName + "'", e);
438: }
439: }
440: }
441: }
442:
443: /**
444: * Creates and returns the service which have the given name.
445: * (Uses the 'jonas.service.<serviceName>.class' property for that)
446: * @param serviceName the name of the service to instanciate.
447: * @return Service the instance of the service.
448: * @throws ServiceException if the service can't be created.
449: */
450: protected Service createServiceFrom(String serviceName)
451: throws ServiceException {
452: if (logger.isLoggable(BasicLevel.DEBUG)) {
453: logger.log(BasicLevel.DEBUG, serviceName);
454: }
455: String prefixPropName = PREFIX_SERVICE_PROP_NAME + "."
456: + serviceName;
457: String serviceClassName = props.getValue(prefixPropName
458: + ".class");
459: if (serviceClassName == null) {
460: throw new ServiceException("Property '" + prefixPropName
461: + ".class' missing in '" + JProp.JONASPREFIX
462: + "' properties file");
463: }
464: try {
465: ClassLoader classLoader = this .getClass().getClassLoader();
466: if (classLoader == null) {
467: classLoader = Thread.currentThread()
468: .getContextClassLoader();
469: }
470: Class serviceClass = classLoader
471: .loadClass(serviceClassName);
472: Service service = (Service) serviceClass.newInstance();
473: service.setName(serviceName);
474: if (logger.isLoggable(BasicLevel.DEBUG)) {
475: logger.log(BasicLevel.DEBUG, "class used: "
476: + serviceClassName);
477: }
478: return (service);
479: } catch (NoClassDefFoundError ncdfe) {
480: logger
481: .log(
482: BasicLevel.WARN,
483: "WARNING : The service '"
484: + serviceName
485: + "' is disabled because a class for this service is missing."
486: + " Check your services in jonas.properties file and your environment variables. Missing class : '"
487: + ncdfe.getMessage() + "'", ncdfe);
488: // Return null so the service won't be added.
489: return null;
490: } catch (ClassNotFoundException cnfe) {
491: logger
492: .log(
493: BasicLevel.WARN,
494: "WARNING : The service '"
495: + serviceName
496: + "' is disabled because a class for this service is missing."
497: + " Check your services in jonas.properties file and your environment variables. Missing class : '"
498: + cnfe.getMessage() + "'", cnfe);
499: // Return null so the service won't be added.
500: return null;
501: } catch (Exception e) {
502: throw new ServiceException(
503: "Error when creating the service '" + serviceName
504: + "'", e);
505: }
506: }
507:
508: /**
509: * Creates and returns the context for the configuration of the service
510: * which have the given name.
511: * (Uses the 'jonas.service.<serviceName>.XXXX' properties for that)
512: * @param serviceName the name of the service to obtain the configuration.
513: * @return Context the context for the service.
514: * @throws NamingException if the context can't be built.
515: */
516: protected Context createServiceContextFor(String serviceName)
517: throws NamingException {
518: if (logger.isLoggable(BasicLevel.DEBUG)) {
519: logger.log(BasicLevel.DEBUG, serviceName);
520: }
521: String prefixPropName = PREFIX_SERVICE_PROP_NAME + "."
522: + serviceName;
523: CompNamingContext ctx = new CompNamingContext(serviceName);
524: for (Enumeration e = props.getEnv().propertyNames(); e
525: .hasMoreElements();) {
526: String propName = (String) e.nextElement();
527: if (propName.startsWith(prefixPropName + ".")) {
528: ctx.rebind(propName, props.getValue(propName));
529: // Also, bind the short property value (without the Prefix)
530: ctx.rebind(propName.substring((prefixPropName + ".")
531: .length()), props.getValue(propName));
532: }
533: }
534: // set Jonas name properties to all ctx
535: ctx.rebind(JProp.JONAS_NAME, props.getValue(JProp.JONAS_NAME));
536: ctx
537: .rebind(JProp.DOMAIN_NAME, props
538: .getValue(JProp.DOMAIN_NAME));
539: // Test JMX Remote
540: // Get specific JMX props
541: if (serviceName.equals("jmx")) {
542: String prop = props.getValue("host.name");
543: if (prop != null) {
544: ctx.rebind("host.name", prop);
545: }
546: prop = props.getValue("jmxconnector.port");
547: if (prop != null) {
548: ctx.rebind("jmxconnector.port", prop);
549: }
550: }
551: return ctx;
552: }
553:
554: /**
555: * Management Method: Stop all services.
556: * The services are stopped in the reverse order of their starting.
557: * (Continue the processing of stopping for the others services, even if there is a problem
558: * for one service.)
559: * @throws ServiceException if the service can't be stopped.
560: */
561: public void stopServices() throws ServiceException {
562: String msgError = new String();
563: String sepError = "";
564: Service[] services = getServices();
565: for (int i = services.length - 1; i >= 0; i--) {
566: Service service = services[i];
567: if (service.isStarted()) {
568: try {
569: service.stop();
570: if (logger.isLoggable(BasicLevel.DEBUG)) {
571: logger.log(BasicLevel.DEBUG, service.getName()
572: + " service stopped");
573: }
574: } catch (ServiceException e) {
575: msgError = msgError.concat(sepError
576: + "Cannot stop the service '"
577: + service.getName() + "': " + e);
578: sepError = "\n";
579: }
580: }
581: }
582: if (msgError.length() != 0) {
583: throw new ServiceException(msgError);
584: }
585: }
586: }
|