001: /*
002: * This file is part of the WfMOpen project.
003: * Copyright (C) 2001-2003 Danet GmbH (www.danet.de), GS-AN.
004: * All rights reserved.
005: *
006: * This program is free software; you can redistribute it and/or modify
007: * it under the terms of the GNU General Public License as published by
008: * the Free Software Foundation; either version 2 of the License, or
009: * (at your option) any later version.
010: *
011: * This program 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
014: * GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: * $Id: AbstractProcessDefinitionDirectory.java,v 1.4.2.1 2007/11/02 16:00:33 drmlipp Exp $
021: *
022: * $Log: AbstractProcessDefinitionDirectory.java,v $
023: * Revision 1.4.2.1 2007/11/02 16:00:33 drmlipp
024: * Merged bug fixes from HEAD.
025: *
026: * Revision 1.6 2007/10/04 20:40:07 mlipp
027: * Avoid duplicate target namespaces in schema list.
028: *
029: * Revision 1.5 2007/10/04 14:39:38 mlipp
030: * Removed explicit dependency on Xerces. Note that we require a
031: * JAXP 1.2 compliant Parser (JDK 1.4 requires 1.1 only), but as we
032: * need updated endorsed XML libraries, this should not be a problem.
033: *
034: * Revision 1.4 2007/05/03 21:58:18 mlipp
035: * Internal refactoring for making better use of local EJBs.
036: *
037: * Revision 1.3 2006/09/29 12:32:08 drmlipp
038: * Consistently using WfMOpen as projct name now.
039: *
040: * Revision 1.2 2006/09/28 09:50:12 drmlipp
041: * Moved parsing methods to better place.
042: *
043: * Revision 1.1.1.1 2003/06/30 20:05:15 drmlipp
044: * Initial import
045: *
046: * Revision 1.24 2003/06/27 08:51:45 lipp
047: * Fixed copyright/license information.
048: *
049: * Revision 1.23 2002/09/19 15:19:45 huaiyang
050: * Moved unnecessary code.
051: *
052: * Revision 1.22 2002/09/19 08:44:15 huaiyang
053: * Moved validate staff from AbstractProcessDefinitionDirectory to
054: * DefaultProcessDefinition.
055: *
056: * Revision 1.21 2002/09/18 14:32:34 huaiyang
057: * Add validating of participant.
058: *
059: * Revision 1.20 2002/09/17 09:41:50 huaiyang
060: * validateApplicationDef method added.
061: *
062: * Revision 1.19 2002/09/16 15:29:17 huaiyang
063: * Add the validation of tool.
064: *
065: * Revision 1.18 2002/09/11 06:33:32 huaiyang
066: * Remove the variable of prefix.
067: *
068: * Revision 1.17 2002/09/09 13:11:46 huaiyang
069: * Cleanup the unnecessary code for old style process definition.
070: *
071: * Revision 1.16 2002/09/02 12:23:37 huaiyang
072: * Use namespace in validating methods.
073: *
074: * Revision 1.15 2002/08/28 10:34:51 huaiyang
075: * Use getDocType to check if this process definition spec is new.
076: *
077: * Revision 1.14 2002/08/28 09:22:09 huaiyang
078: * Compatible with new style of process definition spec.
079: *
080: * Revision 1.13 2002/08/26 14:17:07 lipp
081: * JavaDoc fixes.
082: *
083: * Revision 1.12 2002/08/20 21:17:21 lipp
084: * Replaced JAREntityResolver with resolver library.
085: *
086: * Revision 1.11 2002/08/15 15:02:50 huaiyang
087: * Use method of findDuplicate to find out duplicated Id.
088: *
089: * Revision 1.10 2002/08/15 12:46:43 huaiyang
090: * Validate the imported xpdl file.
091: *
092: * Revision 1.9 2002/08/14 07:53:52 lipp
093: * Added missing entity resolver helper.
094: *
095: * Revision 1.8 2002/08/01 14:19:50 huaiyang
096: * Use XPath to select elements of JDOM tree.
097: *
098: * Revision 1.7 2002/08/01 10:13:17 huaiyang
099: * Use JDOM instead of DOM now.
100: *
101: * Revision 1.6 2002/07/24 08:04:42 huaiyang
102: * doccheck.
103: *
104: * Revision 1.5 2002/07/08 19:37:59 lipp
105: * New import process definition method.
106: *
107: * Revision 1.4 2002/02/01 14:30:36 lipp
108: * Added error handling for process definition parsing.
109: *
110: * Revision 1.3 2002/01/15 16:10:51 robert
111: * replace ProcessDefinitionDirectory interface from workflow/domain
112: * to workflow/api
113: *
114: * Revision 1.2 2001/12/17 09:15:50 lipp
115: * Javadoc fixes.
116: *
117: * Revision 1.1 2001/12/14 13:28:25 lipp
118: * Cleaned up implementation structure of ProcessDefinitionDirectory,
119: * renamed Package to ProcessDirectoryPackage and restored initial load
120: * of process definitions.
121: *
122: */
123: package de.danet.an.workflow.domain;
124:
125: import java.io.IOException;
126: import java.net.URL;
127: import java.util.ArrayList;
128: import java.util.Enumeration;
129: import java.util.HashMap;
130: import java.util.Iterator;
131: import java.util.List;
132: import java.util.Map;
133: import java.util.Properties;
134: import java.util.Vector;
135:
136: import org.jaxen.JaxenException;
137: import org.jaxen.XPath;
138: import org.jaxen.jdom.JDOMXPath;
139: import org.jdom.Document;
140: import org.jdom.Element;
141: import org.jdom.JDOMException;
142: import org.jdom.Namespace;
143: import org.jdom.input.SAXBuilder;
144: import org.xml.sax.InputSource;
145:
146: import de.danet.an.util.sax.XmlnsUrisPatcher;
147: import de.danet.an.workflow.api.ImportException;
148: import de.danet.an.workflow.api.PrioritizedMessage;
149: import de.danet.an.workflow.api.ProcessDefinition;
150: import de.danet.an.workflow.localapi.ProcessDefinitionDirectoryLocal;
151: import de.danet.an.workflow.util.CollectingErrorHandler;
152: import de.danet.an.workflow.util.XPDLUtil;
153:
154: /**
155: * This class provides a basic implementation of
156: * {@link de.danet.an.workflow.localapi.ProcessDefinitionDirectoryLocal
157: * <code>ProcessDefinitionDirectory</code>}.
158: */
159: public abstract class AbstractProcessDefinitionDirectory implements
160: ProcessDefinitionDirectoryLocal {
161:
162: /**
163: * Parses the input that describe process definitions and converts it
164: * into a list of {@link ProcessDefinition <code>ProcessDefinition</code>}.
165: *
166: * @param toParse the input that describes the process definition as XPDL.
167: * @return a list; the first element of this list is a list of prioritized
168: * messages {@link de.danet.an.workflow.api.PrioritizedMessage
169: * <code>PrioritizedMessage</code>} and then follows all the parsed process
170: * definitions.
171: * @exception ImportException if the XPDL is not correct.
172: */
173: public static List parseProcessDefinitions(InputSource toParse)
174: throws ImportException {
175: List resultList = new ArrayList();
176: List processDefs = new ArrayList();
177: CollectingErrorHandler eh = new CollectingErrorHandler();
178: Document doc = null;
179: try {
180: // Create sax builder, set validating as true
181: SAXBuilder saxBuilder = new SAXBuilder(true);
182: saxBuilder.setFeature(
183: "http://xml.org/sax/features/namespace-prefixes",
184: true);
185: saxBuilder.setXMLFilter(new XmlnsUrisPatcher());
186: saxBuilder
187: .setProperty(
188: "http://java.sun.com/xml/jaxp/properties/schemaLanguage",
189: "http://www.w3.org/2001/XMLSchema");
190: saxBuilder
191: .setProperty(
192: "http://java.sun.com/xml/jaxp/properties/schemaSource",
193: schemaUris());
194: saxBuilder.setErrorHandler(eh);
195: // build Document
196: doc = saxBuilder.build(toParse);
197: Element root = doc.getRootElement();
198: if (root == null || !root.getName().equals("Package")
199: || !root.getNamespaceURI().equals(XPDLUtil.XPDL_NS)) {
200: eh.add(new PrioritizedMessage(
201: PrioritizedMessage.Priority.ERROR,
202: "ImportMessages#package.missing"));
203: } else if (eh.getErrors().size() == 0
204: && eh.getFatalErrors().size() == 0) {
205: ProcDefValidator procDefValidator = new ProcDefValidator();
206: procDefValidator.validate(doc, eh);
207: processDefs = AbstractProcessDefinitionDirectory
208: .getProcessDefinitionsFromXPDL(doc);
209: }
210: } catch (JDOMException jex) {
211: eh
212: .add(new PrioritizedMessage(
213: PrioritizedMessage.Priority.ERROR, jex
214: .getMessage()));
215: } catch (IOException e) {
216: eh.add(new PrioritizedMessage(
217: PrioritizedMessage.Priority.ERROR, e.getMessage()));
218: } catch (IllegalArgumentException iaex) {
219: eh.add(new PrioritizedMessage(
220: PrioritizedMessage.Priority.ERROR, iaex
221: .getMessage()));
222: } catch (JaxenException jaxe) {
223: DefaultProcessDefinition.logger.error(jaxe.getMessage(),
224: jaxe);
225: throw new IllegalArgumentException(
226: "Cannot traverse XPDL-JDOM: " + jaxe.getMessage());
227: }
228: List pms = eh.getMessages();
229:
230: if (eh.getErrors().size() > 0 || eh.getFatalErrors().size() > 0) {
231: throw new ImportException(
232: "There have been problems while parsing XPDL", pms);
233: }
234: // the first element of the result list is list of prioritized messages
235: resultList.add(pms);
236: // follows the list of process definitions
237: resultList.addAll(processDefs);
238: return resultList;
239: }
240:
241: private static Object[] schemaUris() throws IllegalStateException {
242: try {
243: Map schemas = new HashMap();
244: ClassLoader cl = Thread.currentThread()
245: .getContextClassLoader();
246: Enumeration rese = cl
247: .getResources("de/danet/an/workflow/resources/schemas.properties");
248: // there are buggy classloaders that do not implement
249: // getResources properly. As a workaround, we make an
250: // additional call to getResource if getResources returns
251: // an empty result.
252: if (!rese.hasMoreElements()) {
253: Object r = cl
254: .getResource("de/danet/an/workflow/resources/schemas.properties");
255: if (r != null) {
256: Vector v = new Vector(1);
257: v.add(r);
258: rese = v.elements();
259: }
260: }
261: while (rese.hasMoreElements()) {
262: URL res = (URL) rese.nextElement();
263: Properties sprops = new Properties();
264: sprops.load(res.openStream());
265: Enumeration sids = sprops.keys();
266: while (sids.hasMoreElements()) {
267: String sid = (String) sids.nextElement();
268: String sloc = (String) sprops.get(sid);
269: schemas.put(sid, (new URL(res, sloc)).toString());
270: }
271: }
272: return schemas.values().toArray();
273: } catch (IOException ioe) {
274: throw new IllegalStateException();
275: }
276: }
277:
278: private static List getProcessDefinitionsFromXPDL(Document doc)
279: throws JDOMException, JaxenException, ImportException {
280: List resultList = new ArrayList();
281: List processes = new ArrayList();
282: Element root = doc.getRootElement();
283: // Namespace
284: Namespace namespace = Namespace.getNamespace(XPDLUtil.XPDL_NS);
285: // cut out the WorkflowProcess nodes
286: XPath path = new JDOMXPath(
287: "/xpdl:Package/xpdl:WorkflowProcesses/xpdl:WorkflowProcess");
288: path.addNamespace("xpdl", XPDLUtil.XPDL_NS);
289: Iterator processListIterator = path.selectNodes(doc).iterator();
290: while (processListIterator.hasNext()) {
291: Element child = (Element) processListIterator.next();
292: processes.add(child);
293: }
294: if (processes.size() == 0) {
295: return resultList;
296: }
297: Element parent = root.getChild("WorkflowProcesses", namespace);
298: parent.removeContent();
299: Iterator it2 = processes.iterator();
300: while (it2.hasNext()) {
301: Element rootClone = (Element) root.clone();
302: Element newProcess = (Element) it2.next();
303: // new Document
304: // import the package description and add to new document
305: Document newDoc = new Document(rootClone);
306: // import process definition and add under processes
307: Element newProcesses = rootClone.getChild(
308: "WorkflowProcesses", namespace);
309: newProcesses.addContent(newProcess);
310: ProcessDefinition pd = new DefaultProcessDefinition(newDoc);
311: // add to resultlist
312: resultList.add(pd);
313: }
314: return resultList;
315: }
316: }
|