001: /*--
002:
003: Copyright (C) 2002-2005 Adrian Price.
004: 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 disclaimer that follows
015: these conditions in the documentation and/or other materials
016: provided with the distribution.
017:
018: 3. The names "OBE" and "Open Business Engine" must not be used to
019: endorse or promote products derived from this software without prior
020: written permission. For written permission, please contact
021: adrianprice@sourceforge.net.
022:
023: 4. Products derived from this software may not be called "OBE" or
024: "Open Business Engine", nor may "OBE" or "Open Business Engine"
025: appear in their name, without prior written permission from
026: Adrian Price (adrianprice@users.sourceforge.net).
027:
028: THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
029: WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
030: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
031: DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
032: INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
033: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
034: SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
035: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
036: STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
037: IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
038: POSSIBILITY OF SUCH DAMAGE.
039:
040: For more information on OBE, please see
041: <http://obe.sourceforge.net/>.
042:
043: */
044:
045: package org.obe.spi.service;
046:
047: import org.apache.commons.logging.Log;
048: import org.apache.commons.logging.LogFactory;
049: import org.obe.OBERuntimeException;
050: import org.obe.client.api.repository.RepositoryException;
051: import org.obe.engine.WorkflowEngine;
052: import org.obe.spi.WorkflowService;
053: import org.obe.spi.runtime.BusinessCalendar;
054: import org.obe.util.CommonConfig;
055: import org.obe.util.SchemaUtils;
056:
057: import java.io.IOException;
058: import java.io.InputStream;
059: import java.lang.reflect.Constructor;
060: import java.lang.reflect.InvocationTargetException;
061: import java.util.Properties;
062:
063: /**
064: * Provides access to system-level services. The default implementation classes
065: * can be overridden either by providing a
066: * <code>ServiceManager.properties</code> configuration file, setting system
067: * properties, or by passing a <code>java.util.Properties</code> object to the
068: * constructor. The property names are defined as in this class as
069: * <code>public static final String</code> fields with <code>_TAG</code>
070: * suffixes.
071: *
072: * @author Adrian Price
073: */
074: public final class ServiceManager {
075: /**
076: * The property name that specifies the {@link ApplicationEventBroker} class
077: * to use.
078: */
079: public static final String APPLICATION_EVENT_BROKER_TAG = "obe.applicationEventBroker";
080: /**
081: * The property name that specifies the {@link AssignmentStrategyFactory}
082: * class to use.
083: */
084: public static final String ASSIGNMENT_STRATEGY_FACTORY_TAG = "obe.assignmentStrategyFactory";
085: /**
086: * The property name that specifies the {@link AsyncManager} class to use.
087: */
088: public static final String ASYNC_MANAGER_TAG = "obe.asyncManager";
089: /**
090: * The property name that specifies the {@link BusinessCalendar} class to
091: * use.
092: */
093: public static final String CALENDAR_FACTORY_TAG = "obe.calendarFactory";
094: /**
095: * The property name that specifies the {@link CompletionStrategyFactory} class to use.
096: */
097: public static final String COMPLETION_STRATEGY_FACTORY_TAG = "obe.completionStrategyFactory";
098: /**
099: * The property name that specifies the {@link DataConverter} class to use.
100: */
101: public static final String DATA_CONVERTER_TAG = "obe.dataConverter";
102: /**
103: * The property name that specifies the {@link EvaluatorFactory} class to
104: * use.
105: */
106: public static final String EVALUATOR_FACTORY_TAG = "obe.evaluatorFactory";
107: /**
108: * The property name that specifies the {@link FunctionFactory} class to
109: * use.
110: */
111: public static final String FUNCTION_FACTORY_TAG = "obe.functionFactory";
112: /**
113: * The property name that specifies the {@link InstanceRepository} class to
114: * use.
115: */
116: public static final String INSTANCE_REPOSITORY_TAG = "obe.instanceRepository";
117: /**
118: * The property name that specifies the {@link XPDLParserFactory} class
119: * to use.
120: */
121: public static final String PARSER_FACTORY_TAG = "obe.parserFactory";
122: /**
123: * The property name that specifies the {@link SecurityRealm} class to use.
124: */
125: public static final String SECURITY_REALM_TAG = "obe.securityRealm";
126: /**
127: * The property name that specifies the {@link ProcessRepository} class to
128: * use.
129: */
130: public static final String PROCESS_REPOSITORY_TAG = "obe.processRepository";
131: /**
132: * The property name that specifies the {@link ToolAgentFactory} class to
133: * use.
134: */
135: public static final String TOOL_AGENT_FACTORY_TAG = "obe.toolAgentFactory";
136: /**
137: * The property name that specifies the {@link WorkflowEventBroker} class
138: * to use.
139: */
140: public static final String WORKFLOW_EVENT_BROKER_TAG = "obe.workflowEventBroker";
141: /**
142: * The property name that specifies the {@link ResourceRepository} class to use.
143: */
144: public static final String RESOURCE_REPOSITORY_TAG = "obe.resourceRepository";
145: private static final String CONFIG_FILE = "ServiceManager.properties";
146: private static final Class[] SERVICE_CTOR_SIG = { ServiceManager.class };
147: // N.B. These service ordinals must match the _defaults array order.
148: private static final int WORKFLOW_EVENT_BROKER = 0;
149: private static final int APPLICATION_EVENT_BROKER = 1;
150: private static final int RESOURCE_REPOSITORY = 2;
151: private static final int ASSIGNMENT_STRATEGY_FACTORY = 3;
152: private static final int COMPLETION_STRATEGY_FACTORY = 4;
153: private static final int CALENDAR_FACTORY = 5;
154: private static final int DATA_CONVERTER = 6;
155: private static final int EVALUATOR_FACTORY = 7;
156: private static final int FUNCTION_FACTORY = 8;
157: private static final int SECURITY_REALM = 9;
158: private static final int PARSER_FACTORY = 10;
159: private static final int TOOL_AGENT_FACTORY = 11;
160: private static final int ASYNC_MANAGER = 12;
161: private static final int PROCESS_REPOSITORY = 13;
162: private static final int INSTANCE_REPOSITORY = 14;
163: private static final String[][] _defaults = {
164: { WORKFLOW_EVENT_BROKER_TAG,
165: "org.obe.event.BasicWorkflowEventBroker" },
166: { APPLICATION_EVENT_BROKER_TAG,
167: "org.obe.event.BasicApplicationEventBroker" },
168: { RESOURCE_REPOSITORY_TAG,
169: "org.obe.engine.repository.BasicResourceRepository" },
170: { ASSIGNMENT_STRATEGY_FACTORY_TAG,
171: "org.obe.runtime.strategy.BasicAssignmentStrategyFactory" },
172: { COMPLETION_STRATEGY_FACTORY_TAG,
173: "org.obe.runtime.strategy.BasicCompletionStrategyFactory" },
174: { CALENDAR_FACTORY_TAG,
175: "org.obe.engine.calendar.BasicCalendarFactory" },
176: { DATA_CONVERTER_TAG,
177: "org.obe.engine.util.BasicDataConverter" },
178: { EVALUATOR_FACTORY_TAG,
179: "org.obe.runtime.evaluator.BasicEvaluatorFactory" },
180: { FUNCTION_FACTORY_TAG,
181: "org.obe.runtime.evaluator.BasicFunctionFactory" },
182: { SECURITY_REALM_TAG,
183: "org.obe.runtime.participant.BasicSecurityRealm" },
184: { PARSER_FACTORY_TAG,
185: "org.obe.spi.service.XPDLParserFactory" },
186: { TOOL_AGENT_FACTORY_TAG,
187: "org.obe.runtime.tool.BasicToolAgentFactory" },
188: { ASYNC_MANAGER_TAG,
189: "org.obe.engine.async.BasicAsyncManager" },
190: { PROCESS_REPOSITORY_TAG,
191: "org.obe.engine.persistence.memory.BasicProcessRepository" },
192: { INSTANCE_REPOSITORY_TAG,
193: "org.obe.engine.persistence.memory.BasicInstanceRepository" }, };
194: private static final Properties _defaultProps = new Properties();
195: private static final Properties _configProps = new Properties(
196: _defaultProps);
197: private static final Log _logger = LogFactory
198: .getLog(ServiceManager.class);
199:
200: private final WorkflowEngine _engine;
201: private final WorkflowService[] _services;
202: private boolean _initialized;
203:
204: static {
205: // Defaults are hard coded.
206: for (int i = 0; i < _defaults.length; i++) {
207: _defaultProps.setProperty(_defaults[i][0], _defaults[i][1]);
208: }
209:
210: // Configuration file ServiceManager.properties overrides defaults.
211: InputStream in = CommonConfig.openInputStream(CONFIG_FILE);
212: if (in != null) {
213: try {
214: _configProps.load(in);
215: } catch (IOException e) {
216: _logger.error("Error loading configuration", e);
217: } finally {
218: try {
219: in.close();
220: } catch (IOException e) {
221: // Ignore stream close exceptions.
222: }
223: }
224: }
225: }
226:
227: {
228: // Initialized here to avoid field ordering dependencies.
229: _services = new WorkflowService[_defaults.length];
230: }
231:
232: /**
233: * Returns the default service manager configuration.
234: *
235: * @return Default settings.
236: */
237: public static Properties getDefaults() {
238: return (Properties) _defaultProps.clone();
239: }
240:
241: /**
242: * Constructs a service manager with service class name overrides specified
243: * by system properties. System properties override both defaults and
244: * settings from the <code>ServiceManager.properties</code> configuration
245: * file.
246: */
247: public ServiceManager() {
248: this (System.getProperties());
249: }
250:
251: /**
252: * Constructs a service manager with service class name overrides specified
253: * explicitly. These properties override both defaults and settings from
254: * the <code>ServiceManager.properties</code> configuration file.
255: *
256: * @param overrides Properties file containing overrides for some or all
257: * workflow service implementation classes.
258: */
259: public ServiceManager(Properties overrides) {
260: Properties props = new Properties(_configProps);
261: props.putAll(overrides);
262: try {
263: // Create all the services.
264: for (int i = 0; i < _services.length; i++)
265: _services[i] = createService(props, _defaults[i][0]);
266:
267: // Now it's safe to create the engine.
268: _engine = new WorkflowEngine(this );
269:
270: // If the system is not configured to be initialized by the OBE
271: // initialization servlet, init all the services now.
272: if (!ServerConfig.useInitServlet())
273: init();
274: } catch (Exception e) {
275: throw new OBERuntimeException(e);
276: }
277: }
278:
279: /**
280: * Initializes the various services and repositories. Should only be called
281: * once.
282: */
283: public synchronized void init() throws IOException,
284: RepositoryException {
285: if (_initialized) {
286: _logger.warn("Already initialized - ignoring init() call");
287: return;
288: }
289:
290: // Call init() for each service.
291: if (_logger.isDebugEnabled())
292: _logger.debug("Initializing services");
293:
294: for (int i = 0; i < _services.length; i++)
295: _services[i].init();
296: _engine.init();
297: _initialized = true;
298: }
299:
300: /**
301: * De-initializes the various services and repositories. Should only be
302: * called once.
303: */
304: public synchronized void exit() throws RepositoryException {
305: if (!_initialized) {
306: _logger.warn("Not initialized - ignoring exit() call");
307: return;
308: }
309:
310: // Call exit() for each service, in reverse of initialization order.
311: if (_logger.isDebugEnabled())
312: _logger.debug("De-initializing services");
313:
314: _engine.exit();
315: SchemaUtils.setEntityResolver(null);
316: SchemaUtils.setURIResolver(null);
317: for (int i = _services.length - 1; i >= 0; i--)
318: _services[i].exit();
319: _initialized = false;
320: }
321:
322: // Loads and instantiates the named WorkflowService implementation class.
323: private WorkflowService createService(Properties props, String key)
324: throws ClassNotFoundException, NoSuchMethodException,
325: InstantiationException, IllegalAccessException,
326: InvocationTargetException {
327:
328: String svcClassName = props.getProperty(key);
329: Class svcClass = Class.forName(svcClassName);
330: Constructor ctor = svcClass.getConstructor(SERVICE_CTOR_SIG);
331: WorkflowService service = (WorkflowService) ctor
332: .newInstance(new Object[] { this });
333:
334: _logger.info("Created service: " + service.getServiceName());
335:
336: return service;
337: }
338:
339: /**
340: * Returns the workflow service that manages inbound application events from
341: * external applications.
342: *
343: * @return The application event broker.
344: */
345: public ApplicationEventBroker getApplicationEventBroker() {
346: return (ApplicationEventBroker) _services[APPLICATION_EVENT_BROKER];
347: }
348:
349: /**
350: * Returns the workflow service that manages work item assignment
351: * strategies.
352: *
353: * @return The assignment strategy factory.
354: */
355: public AssignmentStrategyFactory getAssignmentStrategyFactory() {
356: return (AssignmentStrategyFactory) _services[ASSIGNMENT_STRATEGY_FACTORY];
357: }
358:
359: /**
360: * Returns the workflow service that manages asynchronous execution of
361: * subflows and process transitions.
362: *
363: * @return The async execution manager.
364: */
365: public AsyncManager getAsyncManager() {
366: return (AsyncManager) _services[ASYNC_MANAGER];
367: }
368:
369: /**
370: * Returns the workflow service that provides date arithmetic services.
371: *
372: * @return The business calendar.
373: */
374: public CalendarFactory getCalendarFactory() {
375: return (CalendarFactory) _services[CALENDAR_FACTORY];
376: }
377:
378: /**
379: * Returns the workflow service that manages activity completion strategies.
380: *
381: * @return The activity completion strategy factory.
382: */
383: public CompletionStrategyFactory getCompletionStrategyFactory() {
384: return (CompletionStrategyFactory) _services[COMPLETION_STRATEGY_FACTORY];
385: }
386:
387: /**
388: * Returns the workflow service that manages data conversions.
389: *
390: * @return The data converter service.
391: */
392: public DataConverter getDataConverter() {
393: return (DataConverter) _services[DATA_CONVERTER];
394: }
395:
396: /**
397: * Returns the workflow engine.
398: *
399: * @return The workflow engine.
400: */
401: public WorkflowEngine getEngine() {
402: return _engine;
403: }
404:
405: /**
406: * Returns the workflow service that evaluates scripted expressions.
407: *
408: * @return The script evaluator repository.
409: */
410: public EvaluatorFactory getEvaluatorFactory() {
411: return (EvaluatorFactory) _services[EVALUATOR_FACTORY];
412: }
413:
414: /**
415: * Returns the workflow service that provides extension functions to
416: * scripting languages.
417: *
418: * @return The function repository.
419: */
420: public FunctionFactory getFunctionFactory() {
421: return (FunctionFactory) _services[FUNCTION_FACTORY];
422: }
423:
424: /**
425: * Returns the workflow service that manages process instance persistence.
426: *
427: * @return The process instance repository.
428: */
429: public InstanceRepository getInstanceRepository() {
430: return (InstanceRepository) _services[INSTANCE_REPOSITORY];
431: }
432:
433: /**
434: * Returns the workflow service that provides XPDL parser implementations.
435: *
436: * @return The parser factory.
437: */
438: public XPDLParserFactory getParserFactory() {
439: return (XPDLParserFactory) _services[PARSER_FACTORY];
440: }
441:
442: /**
443: * Returns the workflow service that manages workflow participants.
444: *
445: * @return The participant repository.
446: */
447: public SecurityRealm getSecurityRealm() {
448: return (SecurityRealm) _services[SECURITY_REALM];
449: }
450:
451: /**
452: * Returns the workflow service that manages process definition persistence.
453: *
454: * @return The process repository.
455: */
456: public ProcessRepository getProcessRepository() {
457: return (ProcessRepository) _services[PROCESS_REPOSITORY];
458: }
459:
460: /**
461: * Returns the workflow service that manages tool definitions.
462: *
463: * @return The tool repository.
464: */
465: public ToolAgentFactory getToolAgentFactory() {
466: return (ToolAgentFactory) _services[TOOL_AGENT_FACTORY];
467: }
468:
469: /**
470: * Returns the workflow service that brokers workflow event notifications.
471: *
472: * @return The workflow event broker.
473: */
474: public WorkflowEventBroker getWorkflowEventBroker() {
475: return (WorkflowEventBroker) _services[WORKFLOW_EVENT_BROKER];
476: }
477:
478: /**
479: * Returns the workflow service that manages XML documents, templates,
480: * schemas etc.
481: *
482: * @return The XML document repository.
483: */
484: public ResourceRepository getResourceRepository() {
485: return (ResourceRepository) _services[RESOURCE_REPOSITORY];
486: }
487: }
|