001: /*
002: * Copyright (c) 2002-2003 by OpenSymphony
003: * All rights reserved.
004: */
005: package com.opensymphony.workflow.config;
006:
007: import com.opensymphony.workflow.FactoryException;
008: import com.opensymphony.workflow.StoreException;
009: import com.opensymphony.workflow.loader.*;
010: import com.opensymphony.workflow.loader.ClassLoaderUtil;
011: import com.opensymphony.workflow.spi.WorkflowStore;
012: import com.opensymphony.workflow.util.DefaultVariableResolver;
013: import com.opensymphony.workflow.util.VariableResolver;
014:
015: import org.w3c.dom.*;
016:
017: import java.io.InputStream;
018: import java.io.Serializable;
019:
020: import java.net.URL;
021:
022: import java.util.*;
023:
024: import javax.xml.parsers.*;
025:
026: /**
027: * Default implementation for a configuration object.
028: * This configuration object is passed to the {@link com.opensymphony.workflow.Workflow#setConfiguration(Configuration)}
029: * method. If the configuration is not initialized, the {@link #load(java.net.URL)} method will be called by
030: * the workflow. Alternatively, the caller can explicitly load the configuration by calling that method before
031: * calling {@link com.opensymphony.workflow.Workflow#setConfiguration(Configuration)}.
032: * <p>
033: * The loading behaviour comes into play when specifying a configuration remotely, for example in an EJB
034: * environment. It might be desirable to ensure that the configuration is loaded from within the EJB server,
035: * rather than in the calling client.
036: *
037: * @author Hani Suleiman
038: * @version $Revision: 1.14 $
039: */
040: public class DefaultConfiguration implements Configuration,
041: Serializable {
042: //~ Static fields/initializers /////////////////////////////////////////////
043:
044: private static final long serialVersionUID = 4120889092947132961L;
045: public static DefaultConfiguration INSTANCE = new DefaultConfiguration();
046:
047: //~ Instance fields ////////////////////////////////////////////////////////
048:
049: private Map persistenceArgs = new HashMap();
050: private String persistenceClass;
051: private WorkflowFactory factory = new URLWorkflowFactory();
052: private transient WorkflowStore store = null;
053: private VariableResolver variableResolver = new DefaultVariableResolver();
054: private boolean initialized;
055:
056: //~ Methods ////////////////////////////////////////////////////////////////
057:
058: public boolean isInitialized() {
059: return initialized;
060: }
061:
062: public boolean isModifiable(String name) {
063: return factory.isModifiable(name);
064: }
065:
066: public void setPersistence(String persistence) {
067: persistenceClass = persistence;
068: }
069:
070: public String getPersistence() {
071: return persistenceClass;
072: }
073:
074: public Map getPersistenceArgs() {
075: return persistenceArgs;
076: }
077:
078: public VariableResolver getVariableResolver() {
079: return variableResolver;
080: }
081:
082: public WorkflowDescriptor getWorkflow(String name)
083: throws FactoryException {
084: WorkflowDescriptor workflow = factory.getWorkflow(name);
085:
086: if (workflow == null) {
087: throw new FactoryException("Unknown workflow name");
088: }
089:
090: return workflow;
091: }
092:
093: public String[] getWorkflowNames() throws FactoryException {
094: return factory.getWorkflowNames();
095: }
096:
097: public WorkflowStore getWorkflowStore() throws StoreException {
098: if (store == null) {
099: String clazz = getPersistence();
100:
101: try {
102: store = (WorkflowStore) Class.forName(clazz)
103: .newInstance();
104: } catch (Exception ex) {
105: throw new StoreException("Error creating store", ex);
106: }
107:
108: store.init(getPersistenceArgs());
109: }
110:
111: return store;
112: }
113:
114: public void load(URL url) throws FactoryException {
115: InputStream is = getInputStream(url);
116:
117: if (is == null) {
118: throw new FactoryException(
119: "Cannot find osworkflow.xml configuration file in classpath or in META-INF");
120: }
121:
122: try {
123: DocumentBuilderFactory dbf = DocumentBuilderFactory
124: .newInstance();
125: dbf.setNamespaceAware(true);
126:
127: DocumentBuilder db;
128:
129: try {
130: db = dbf.newDocumentBuilder();
131: } catch (ParserConfigurationException e) {
132: throw new FactoryException(
133: "Error creating document builder", e);
134: }
135:
136: Document doc = db.parse(is);
137:
138: Element root = (Element) doc.getElementsByTagName(
139: "osworkflow").item(0);
140: Element p = XMLUtil.getChildElement(root, "persistence");
141: Element resolver = XMLUtil
142: .getChildElement(root, "resolver");
143: Element factoryElement = XMLUtil.getChildElement(root,
144: "factory");
145:
146: if (resolver != null) {
147: String resolverClass = resolver.getAttribute("class");
148:
149: if (resolverClass != null) {
150: variableResolver = (VariableResolver) ClassLoaderUtil
151: .loadClass(resolverClass, getClass())
152: .newInstance();
153: }
154: }
155:
156: persistenceClass = p.getAttribute("class");
157:
158: List args = XMLUtil.getChildElements(p, "property");
159:
160: //persistenceArgs = new HashMap();
161: for (int i = 0; i < args.size(); i++) {
162: Element e = (Element) args.get(i);
163: persistenceArgs.put(e.getAttribute("key"), e
164: .getAttribute("value"));
165: }
166:
167: if (factoryElement != null) {
168: String clazz = null;
169:
170: try {
171: clazz = factoryElement.getAttribute("class");
172:
173: if (clazz == null) {
174: throw new FactoryException(
175: "factory does not specify a class attribute");
176: }
177:
178: factory = (WorkflowFactory) ClassLoaderUtil
179: .loadClass(clazz, getClass()).newInstance();
180:
181: Properties properties = new Properties();
182: List props = XMLUtil.getChildElements(
183: factoryElement, "property");
184:
185: for (int i = 0; i < props.size(); i++) {
186: Element e = (Element) props.get(i);
187: properties.setProperty(e.getAttribute("key"), e
188: .getAttribute("value"));
189: }
190:
191: factory.init(properties);
192: factory.initDone();
193: } catch (FactoryException ex) {
194: throw ex;
195: } catch (Exception ex) {
196: throw new FactoryException(
197: "Error creating workflow factory " + clazz,
198: ex);
199: }
200: }
201:
202: initialized = true;
203: } catch (FactoryException e) {
204: throw e;
205: } catch (Exception e) {
206: throw new FactoryException("Error in workflow config", e);
207: }
208: }
209:
210: public boolean removeWorkflow(String workflow)
211: throws FactoryException {
212: return factory.removeWorkflow(workflow);
213: }
214:
215: public boolean saveWorkflow(String name,
216: WorkflowDescriptor descriptor, boolean replace)
217: throws FactoryException {
218: return factory.saveWorkflow(name, descriptor, replace);
219: }
220:
221: /**
222: * Load the default configuration from the current context classloader.
223: * The search order is:
224: * <li>Specified URL</li>
225: * <li>osworkflow.xml</li>
226: * <li>/osworkflow.xml</li>
227: * <li>META-INF/osworkflow.xml</li>
228: * <li>/META-INF/osworkflow.xml</li>
229: */
230: protected InputStream getInputStream(URL url) {
231: InputStream is = null;
232:
233: if (url != null) {
234: try {
235: is = url.openStream();
236: } catch (Exception ex) {
237: }
238: }
239:
240: ClassLoader classLoader = Thread.currentThread()
241: .getContextClassLoader();
242:
243: if (is == null) {
244: try {
245: is = classLoader.getResourceAsStream("osworkflow.xml");
246: } catch (Exception e) {
247: }
248: }
249:
250: if (is == null) {
251: try {
252: is = classLoader.getResourceAsStream("/osworkflow.xml");
253: } catch (Exception e) {
254: }
255: }
256:
257: if (is == null) {
258: try {
259: is = classLoader
260: .getResourceAsStream("META-INF/osworkflow.xml");
261: } catch (Exception e) {
262: }
263: }
264:
265: if (is == null) {
266: try {
267: is = classLoader
268: .getResourceAsStream("/META-INF/osworkflow.xml");
269: } catch (Exception e) {
270: }
271: }
272:
273: return is;
274: }
275:
276: /**
277: * Get the workflow factory for this configuration.
278: * This method should never ever be called from client code!
279: */
280: WorkflowFactory getFactory() {
281: return factory;
282: }
283: }
|