001: /* ====================================================================
002: * The Jcorporate Apache Style Software License, Version 1.2 05-07-2002
003: *
004: * Copyright (c) 1995-2003 Jcorporate Ltd. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * 3. The end-user documentation included with the redistribution,
019: * if any, must include the following acknowledgment:
020: * "This product includes software developed by Jcorporate Ltd.
021: * (http://www.jcorporate.com/)."
022: * Alternately, this acknowledgment may appear in the software itself,
023: * if and wherever such third-party acknowledgments normally appear.
024: *
025: * 4. "Jcorporate" and product names such as "Expresso" must
026: * not be used to endorse or promote products derived from this
027: * software without prior written permission. For written permission,
028: * please contact info@jcorporate.com.
029: *
030: * 5. Products derived from this software may not be called "Expresso",
031: * or other Jcorporate product names; nor may "Expresso" or other
032: * Jcorporate product names appear in their name, without prior
033: * written permission of Jcorporate Ltd.
034: *
035: * 6. No product derived from this software may compete in the same
036: * market space, i.e. framework, without prior written permission
037: * of Jcorporate Ltd. For written permission, please contact
038: * partners@jcorporate.com.
039: *
040: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
041: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
042: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
043: * DISCLAIMED. IN NO EVENT SHALL JCORPORATE LTD OR ITS CONTRIBUTORS
044: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
045: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
046: * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
047: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
048: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
049: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
050: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
051: * SUCH DAMAGE.
052: * ====================================================================
053: *
054: * This software consists of voluntary contributions made by many
055: * individuals on behalf of the Jcorporate Ltd. Contributions back
056: * to the project(s) are encouraged when you make modifications.
057: * Please send them to support@jcorporate.com. For more information
058: * on Jcorporate Ltd. and its products, please see
059: * <http://www.jcorporate.com/>.
060: *
061: * Portions of this software are based upon other open source
062: * products and are subject to their respective licenses.
063: */
064: package com.jcorporate.expresso.kernel;
065:
066: import com.jcorporate.expresso.kernel.digester.ComponentConfig;
067: import com.jcorporate.expresso.kernel.digester.ExpressoServicesConfig;
068: import com.jcorporate.expresso.kernel.exception.ConfigurationException;
069: import com.jcorporate.expresso.kernel.management.ComponentFactory;
070: import com.jcorporate.expresso.kernel.management.ExpressoRuntimeMap;
071: import org.apache.log4j.Logger;
072:
073: import java.net.MalformedURLException;
074: import java.net.URL;
075: import java.util.ArrayList;
076: import java.util.Iterator;
077: import java.util.List;
078:
079: /**
080: * <p/>
081: * This class is the focalpoint class that constructs the Expresso Runtime
082: * system. It loads the Expresso Services files, Metadata files and
083: * constructs everything as needed.
084: * </p>
085: * <p>Typical Usage for loading the expresso services configuration from
086: * the classpath: <br/>
087: * <code><pre>
088: * globalContainer = SystemFactory.buildExpressoComponentSystem(
089: * this.getClass().getResource("Test1ExpressoServices.xml"),
090: * this.getClass().getResource("TestLog4jConfig.xml"),
091: * "/My/Log/Location");
092: * </pre></code>
093: * </P
094: *
095: * @author Michael Rimov
096: */
097: public class SystemFactory {
098: /**
099: * Default filename to look for in classloader if all else fails.
100: */
101: public static final String DEFAULT_EXPRESSO_SERVICES = "expresso-services.xml";
102:
103: /**
104: * The order that components were initialized
105: */
106: private List componentOrder = new ArrayList(10);
107:
108: /**
109: * The order that components were configured. configOrder(x) ==
110: * configuration for componentOrder(x)
111: */
112: private List configOrder = new ArrayList(10);
113:
114: /**
115: * Default constructor.... should not be accessed directly.
116: */
117: protected SystemFactory() {
118: }
119:
120: /**
121: * Factory Method.
122: *
123: * @return an instantiated SystemFactory object
124: */
125: public static SystemFactory getInstance() {
126: return new SystemFactory();
127: }
128:
129: /**
130: * Basic initialization system.
131: *
132: * @param servicesFile The path location of the services file. If null,
133: * the system will attempt to use the ClassLoader to locate an
134: * expresso-services file.
135: * @param loggingConfiguration The location of the logging configuration
136: * file. If null, the system will be initialized via a log4j.xml
137: * file in the classpath.
138: * @param logDir the location where Expresso wants to use as a logging
139: * directory.
140: * @return an instantiated Root container.
141: */
142: public static RootContainerInterface buildExpressoComponentSystem(
143: String servicesFile, String loggingConfiguration,
144: String logDir) throws ConfigurationException {
145: return SystemFactory.getInstance().initialize(servicesFile,
146: loggingConfiguration, logDir);
147: }
148:
149: /**
150: * Classloader compatable version of the factory system.
151: *
152: * @param servicesFile A URL to the services file. (Might be from a
153: * Class.loadResource() call.
154: * @param loggingConfiguration A URL to the logging configuration file
155: * (Might also be from a Class.loadResource() file
156: * @param logDir the path location of the log files (optional)
157: * @return A built RootContainer implementation.
158: */
159: public static RootContainerInterface buildExpressoComponentSystem(
160: URL servicesFile, URL loggingConfiguration, String logDir)
161: throws ConfigurationException {
162: if (servicesFile == null) {
163: throw new IllegalArgumentException(
164: "Must have a non-null servicesFile parameter");
165: }
166:
167: if (loggingConfiguration == null) {
168: throw new IllegalArgumentException(
169: "Must have a non-null loggingConfiguration parameter");
170: }
171:
172: return SystemFactory.getInstance().initialize(servicesFile,
173: loggingConfiguration, logDir);
174: }
175:
176: /**
177: * Goes through and initializes the individual Expresso Components
178: *
179: * @param root the Root container to populate
180: * @param esc the services config file that contains what components should
181: * be initialized into the
182: */
183: public void buildAndInitializeComponents(
184: RootContainerInterface root, ExpressoServicesConfig esc)
185: throws ConfigurationException {
186: long startTime = System.currentTimeMillis();
187:
188: Logger initLog = Logger.getLogger(RootContainer.class);
189:
190: if (initLog.isInfoEnabled()) {
191: initLog
192: .info("Logging Initialized. Loading Expresso Services Config");
193: }
194:
195: esc.loadExpressoServices();
196:
197: //
198: //Register the runtime map so management tools can cross runtime
199: //boundaries.
200: //
201: ExpressoRuntimeMap.registerRuntime(esc.getName(), root);
202:
203: try {
204: ComponentConfig configuration = esc.getRootConfig();
205:
206: if (initLog.isDebugEnabled()) {
207: initLog
208: .debug("Successfully parsed expresso-services.xml");
209: }
210:
211: componentOrder.add(root);
212: configOrder.add(esc.getRootConfig());
213: initializeOneContainer(root.getContainerImplementation(),
214: configuration, initLog);
215:
216: if (initLog.isInfoEnabled()) {
217: initLog
218: .info("Successfully loaded all component classes");
219: }
220:
221: configureComponents(initLog);
222: startComponents(initLog);
223: root.setExpressoServicesConfig(esc);
224:
225: long stopTime = System.currentTimeMillis();
226:
227: if (initLog.isInfoEnabled()) {
228: initLog
229: .info("Total time for this runtime initialization: "
230: + (stopTime - startTime) + " ms");
231: }
232: } catch (ConfigurationException ex) {
233: initLog
234: .error("Error initializing Configuration System",
235: ex);
236: ExpressoRuntimeMap.unregisterRuntime(esc.getName());
237: throw new ConfigurationException(ex);
238: }
239: }
240:
241: /**
242: * Single location that constructs all the Container Implementation
243: * classes. This can be extended here to allow for loading of other
244: * 'pluggable' implementations at a later time
245: *
246: * @return a ComponentContainer implementation.
247: */
248: public ComponentContainer constructComponentContainer() {
249: return new DefaultContainerImpl();
250: }
251:
252: /**
253: * Internal usage of the initialization system. It is synchronized so
254: * there is only one runtime parsed and added to a particular Virtual
255: * Machine at a time [should help solve any weird initialization race
256: * conditions and we aren't quite so worried about startup time]
257: *
258: * @param servicesFile A URL to the services file. (Might be from a
259: * Class.loadResource() call.
260: * @param loggingConfiguration A URL to the logging configuration file
261: * (Might also be from a Class.loadResource() file
262: * @param logDir the path location of the log files (optional)
263: * @return A built RootContainer implementation.
264: */
265: protected synchronized RootContainerInterface initialize(
266: URL servicesFile, URL loggingConfiguration, String logDir)
267: throws ConfigurationException {
268: LogManager lm = new LogManager(loggingConfiguration, logDir);
269: Logger initLog = Logger.getLogger(SystemFactory.class);
270:
271: if (initLog.isInfoEnabled()) {
272: initLog
273: .info("Logging Initialized. Loading Expresso Services Config");
274: }
275:
276: ComponentFactory cf = ComponentFactory.getInstance();
277:
278: RootContainerInterface gc = cf.constructRootContainer();
279: gc.setLogManager(lm);
280:
281: ExpressoServicesConfig esc = new ExpressoServicesConfig();
282: esc.setExpressoServicesFile(servicesFile);
283: gc.setServicesFileLocation(servicesFile);
284:
285: buildAndInitializeComponents(gc, esc);
286:
287: return gc;
288: }
289:
290: /**
291: * Protected initialization.
292: *
293: * @param servicesFile The path location of the services file. If null,
294: * the system will attempt to use the ClassLoader to locate an
295: * expresso-services file.
296: * @param loggingConfiguration The location of the logging configuration
297: * file. If null, the system will be initialized via a log4j.xml
298: * file in the classpath.
299: * @param logDir the location where Expresso wants to use as a logging
300: * directory.
301: * @return an instantiated RootContainerInterface instance
302: * @throws ConfigurationException upon configuration startup error
303: */
304: protected synchronized RootContainerInterface initialize(
305: String servicesFile, String loggingConfiguration,
306: String logDir) throws ConfigurationException {
307: //
308: //Only allow one System to be built at a time.
309: //
310: synchronized (SystemFactory.class) {
311: //
312: //Initialize Logging
313: //
314: LogManager lm = new LogManager(loggingConfiguration, logDir);
315:
316: Logger initLog = Logger.getLogger(SystemFactory.class);
317:
318: if (initLog.isInfoEnabled()) {
319: initLog
320: .info("Logging Initialized. Loading Expresso Services Config");
321: }
322:
323: ComponentFactory cf = ComponentFactory.getInstance();
324:
325: RootContainerInterface rootContainer = cf
326: .constructRootContainer();
327: rootContainer.setLogManager(lm);
328:
329: ExpressoServicesConfig esc = new ExpressoServicesConfig();
330:
331: if (servicesFile == null) {
332: if (initLog.isDebugEnabled()) {
333: initLog
334: .debug("Attempting to load expresso services from class loader");
335: }
336:
337: URL url = Thread.currentThread()
338: .getContextClassLoader().getResource(
339: DEFAULT_EXPRESSO_SERVICES);
340: esc.setExpressoServicesFile(url);
341: rootContainer.setServicesFileLocation(url);
342: } else {
343: if (initLog.isDebugEnabled()) {
344: initLog
345: .debug("Attempting to load expresso services from file name: "
346: + servicesFile);
347: }
348:
349: esc.setExpressoServicesFile(servicesFile);
350:
351: java.io.File f = new java.io.File(servicesFile);
352:
353: if (f == null) {
354: throw new ConfigurationException(
355: "Unable to get services file location as a URL.");
356: }
357:
358: try {
359: rootContainer.setServicesFileLocation(f.toURL());
360: } catch (MalformedURLException ex) {
361: throw new ConfigurationException(
362: "Error getting services file location as a URL.",
363: ex);
364: }
365: }
366:
367: buildAndInitializeComponents(rootContainer, esc);
368:
369: return rootContainer;
370: }
371: }
372:
373: /**
374: * Configures all the initialized components that implement Configuration
375: * lifecycle events.
376: *
377: * @param log the logging system to use for informational use.
378: */
379: private void configureComponents(Logger log) {
380: ComponentFactory cf = ComponentFactory.getInstance();
381:
382: for (Iterator i = componentOrder.iterator(), eachConfig = configOrder
383: .iterator(); i.hasNext();) {
384: Object o = i.next();
385: ComponentConfig oneConfig = (ComponentConfig) eachConfig
386: .next();
387:
388: try {
389: if (o instanceof ComponentLifecycle) {
390: if (log.isDebugEnabled()) {
391: log.debug("Configuring component: "
392: + o.getClass().getName());
393: }
394:
395: ExpressoComponent ec = (ExpressoComponent) o;
396: cf.configureComponent(oneConfig, ec);
397: } else {
398: if (log.isDebugEnabled()) {
399: log
400: .debug("Object "
401: + o.getClass().getName()
402: + " does not implement ComponentLifecycle. Skipping 'configure' method");
403: }
404: }
405: } catch (ConfigurationException ex) {
406: log.error("Error configuring component: "
407: + o.getClass().getName(), ex);
408: }
409: }
410: }
411:
412: /**
413: * Recursive function... initializes one container.
414: *
415: * @param currentContainer the container to initialize
416: * @param containerComponentConfig the current component configuration bean
417: * in the heirarchy.
418: * @param log the logger to log progress
419: * @throws ConfigurationException upon initialization error.
420: */
421: private void initializeOneContainer(
422: ComponentContainer currentContainer,
423: ComponentConfig containerComponentConfig, Logger log)
424: throws ConfigurationException {
425: List children = containerComponentConfig.getChildComponents();
426:
427: try {
428: ComponentFactory cf = ComponentFactory.getInstance();
429:
430: for (Iterator i = children.iterator(); i.hasNext();) {
431: ComponentConfig childComponentConfig = (ComponentConfig) i
432: .next();
433: ExpressoComponent oneObj = cf.constructComponent(
434: currentContainer, childComponentConfig);
435:
436: this .componentOrder.add(oneObj);
437: this .configOrder.add(childComponentConfig);
438:
439: if (log.isInfoEnabled()) {
440: log.info("Loading component: "
441: + childComponentConfig.getClassName()
442: + " as " + childComponentConfig.getName());
443: }
444:
445: ExpressoComponent ec = (ExpressoComponent) oneObj;
446:
447: if (oneObj instanceof Containable) {
448: ComponentContainer newContainer = ((Containable) ec)
449: .getContainerImplementation();
450:
451: if (childComponentConfig.getChildComponents()
452: .size() > 0) {
453: initializeOneContainer(newContainer,
454: childComponentConfig, log);
455: }
456: }
457: }
458: } catch (Exception e) {
459: log.error("Error configuring component.", e);
460: }
461: }
462:
463: /**
464: * Start any components that are loaded and configured and implement the
465: * Startable interface
466: *
467: * @param log The logger to log any information that might be of note.
468: */
469: private void startComponents(Logger log) {
470: ComponentFactory cf = ComponentFactory.getInstance();
471:
472: for (Iterator i = componentOrder.iterator(); i.hasNext();) {
473: Object o = i.next();
474: cf.startComponent((ExpressoComponent) o);
475: }
476: }
477: }
|