/*
* This file is part of the WfMOpen project.
* Copyright (C) 2001-2003 Danet GmbH (www.danet.de), GS-AN.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* $Id: ProcDefValidator.java 2904 2009-01-28 22:21:36Z mlipp $
*
* $Log$
* Revision 1.12 2007/02/27 14:34:16 drmlipp
* Some refactoring to reduce cyclic dependencies.
*
* Revision 1.11 2006/11/19 21:53:47 mlipp
* Finished support for native Java types.
*
* Revision 1.10 2006/11/19 11:16:35 mlipp
* Made ExternalReference an interface.
*
* Revision 1.9 2006/11/17 21:40:36 mlipp
* Added Java type tests.
*
* Revision 1.8 2006/11/17 16:16:12 drmlipp
* Started support for Java native types.
*
* Revision 1.7 2006/09/29 12:32:08 drmlipp
* Consistently using WfMOpen as projct name now.
*
* Revision 1.6 2006/03/08 14:46:43 drmlipp
* Synchronized with 1.3.3p5.
*
* Revision 1.5 2005/11/09 16:14:01 drmlipp
* Fixed jaxen problems.
*
* Revision 1.4 2005/08/23 14:11:56 drmlipp
* Synchronized with 1.3.1p5.
*
* Revision 1.1.1.5.6.3 2005/08/23 13:27:26 drmlipp
* Fixed problem with not dinstinguished process local application
* declarations.
*
* Revision 1.3 2005/04/22 15:11:02 drmlipp
* Merged changes from 1.3 branch up to 1.3p15.
*
* Revision 1.1.1.5.6.2 2005/04/19 09:32:17 drmlipp
* Moved warning about non-standard behaviour to proper place and made
* extended attribute specification more flexible.
*
* Revision 1.2 2005/02/04 14:25:26 drmlipp
* Synchronized with 1.3rc2.
*
* Revision 1.1.1.5.6.1 2005/02/03 13:02:46 drmlipp
* Moved warning about indexed formal parameters to process definition
* import.
*
* Revision 1.1.1.5 2004/08/18 15:17:38 drmlipp
* Update to 1.2
*
* Revision 1.52 2004/03/25 14:41:47 lipp
* Added possibility to specify actual parameters as XML.
*
* Revision 1.51 2004/03/18 12:53:00 lipp
* Support for XML as actual parameter.
*
* Revision 1.50 2004/01/19 12:30:58 lipp
* SchemaType now supported properly.
*
* Revision 1.49 2003/09/20 19:24:48 lipp
* Cannot really verify duration conditions.
*
* Revision 1.48 2003/09/19 15:19:10 lipp
* Using proper parser now.
*
* Revision 1.47 2003/09/17 10:39:52 lipp
* Reduced number of client side classes.
*
* Revision 1.46 2003/09/08 15:37:18 lipp
* Introduced deadline definition and suspend tracking.
*
* Revision 1.45 2003/07/11 10:49:02 huaiyang
* Fix the tip error with the error key.
*
* Revision 1.44 2003/07/11 10:30:07 huaiyang
* Error messages further improved.
*
* Revision 1.43 2003/07/10 12:43:30 huaiyang
* improve the error info.
*
* Revision 1.42 2003/07/04 10:56:14 huaiyang
* Performer can be expression in form of DataField in type PERFORMER.
*
* Revision 1.41 2003/06/27 08:51:45 lipp
* Fixed copyright/license information.
*
* Revision 1.40 2003/06/22 20:24:14 lipp
* Fixed argument type checking.
*
* Revision 1.39 2003/06/04 07:47:13 huaiyang
* refactor the method of valiadateSubFlow.
*
* Revision 1.38 2003/06/03 15:36:43 huaiyang
* Fix the error and add the validating of tool param type.
*
* Revision 1.37 2003/06/03 13:36:11 lipp
* Disabled faulty test.
*
* Revision 1.36 2003/06/03 11:27:56 huaiyang
* validate the type of formal- and actualParameters of subflow.
*
* Revision 1.35 2003/05/28 15:11:34 lipp
* Removed excessive warning on emtpy activity sets.
*
* Revision 1.34 2003/05/28 11:16:07 lipp
* Fixed message text.
*
* Revision 1.33 2003/05/28 07:51:26 huaiyang
* Modify the algorithm to check loop activities.
*
* Revision 1.32 2003/05/26 14:31:58 huaiyang
* add the check of loop activities.
*
* Revision 1.31 2003/05/26 12:42:03 huaiyang
* add the validation of script.
*
* Revision 1.30 2003/05/20 12:04:54 huaiyang
* new error message for not matched mode of formal- and actualParam.
*
* Revision 1.29 2003/05/15 13:50:19 huaiyang
* Check if actual parameters is defined as formal parameters.
*
* Revision 1.28 2003/05/15 13:14:45 huaiyang
* Check if the mode of formal and actual parameters matched.
*
* Revision 1.27 2003/05/13 08:37:15 huaiyang
* add the check of OUT- and INOUT- actual parameter in calling
* subflow.
*
* Revision 1.26 2003/05/12 10:39:02 lipp
* Fixed actual paramter check.
*
* Revision 1.25 2003/05/12 09:13:43 huaiyang
* add the validating of priority of process and activity.
*
* Revision 1.24 2003/05/08 14:54:23 huaiyang
* add the checking of empty activity set.
*
* Revision 1.23 2003/05/08 13:36:41 huaiyang
* function of validate subflow added.
*
* Revision 1.22 2003/05/06 13:21:30 lipp
* Resolved cyclic dependency.
*
* Revision 1.21 2003/04/24 19:47:50 lipp
* Removed dependency between general util and workflow api.
*
* Revision 1.20 2003/04/24 15:08:14 lipp
* Reading ApplicationDefinitiosn from SAX now.
*
* Revision 1.19 2003/03/31 16:50:28 huaiyang
* Logging using common-logging.
*
* Revision 1.18 2003/03/28 14:42:35 lipp
* Moved some code to XPDLUtil.
*
* Revision 1.17 2003/03/28 12:44:08 lipp
* Moved XPDL related constants to XPDLUtil.
*
* Revision 1.16 2003/03/27 10:45:37 lipp
* Renamed activity implementation classes for clarity.
*
* Revision 1.15 2003/03/25 17:16:08 lipp
* Fixed test.
*
* Revision 1.14 2003/03/07 14:11:10 huaiyang
* optimize the initialization of all the xpath.
*
* Revision 1.13 2003/03/07 08:01:02 huaiyang
* use workflow.util.CollectingErrorHandler to collect errors.
*
* Revision 1.12 2003/03/04 13:44:03 huaiyang
* add the method of validateBlockActivity.
*
* Revision 1.11 2002/12/19 21:37:43 lipp
* Reorganized interfaces.
*
* Revision 1.10 2002/12/03 13:49:16 huaiyang
* Add the check of otherwise condition.
*
* Revision 1.9 2002/11/25 09:28:29 huaiyang
* Bug with checking double application Id fixed.
*
* Revision 1.8 2002/11/13 09:14:56 huaiyang
* Remove obsolete debug message.
*
* Revision 1.7 2002/11/12 14:15:36 huaiyang
* Validate the transition restrictions of activity.
*
* Revision 1.6 2002/11/06 12:14:48 huaiyang
* Add the method of validateExtendedAttributes.
*
* Revision 1.5 2002/11/04 10:56:59 huaiyang
* Added the validating of transition for activitySet.
*
* Revision 1.4 2002/11/01 13:09:13 huaiyang
* Bug with validating activityset fixed.
*
* Revision 1.3 2002/11/01 12:21:30 huaiyang
* Validating of activity set added.
*
* Revision 1.2 2002/10/06 20:14:38 lipp
* Updated argument handling.
*
* Revision 1.1 2002/09/27 12:44:55 lipp
* Moved validation to a separate class.
*
*/
package de.danet.an.workflow.domain;
import java.io.IOException;
import java.io.Serializable;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.jaxen.JaxenException;
import org.jaxen.XPath;
import org.jaxen.jdom.JDOMXPath;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.Namespace;
import org.jdom.output.SAXOutputter;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import de.danet.an.util.sax.HandlerStack;
import de.danet.an.workflow.util.CollectingErrorHandler;
import de.danet.an.workflow.util.SAXEventBufferImpl;
import de.danet.an.workflow.util.XPDLUtil;
import de.danet.an.workflow.api.ExternalReference;
import de.danet.an.workflow.api.FormalParameter;
import de.danet.an.workflow.api.PrioritizedMessage;
import de.danet.an.workflow.internalapi.ExtExecutionObjectLocal;
/**
* This class performes validation methods for a process defintion
* package.
*
* @author <a href="mailto:lipp@danet.de"></a>
* @version $Revision: 2904 $
*/
public class ProcDefValidator {
/**
* logger of this class.
*/
static final org.apache.commons.logging.Log logger
= org.apache.commons.logging.LogFactory.getLog(ProcDefValidator.class);
// The defined data fields
private transient Map procdataMap = null;
private transient List dataFieldsList = null;
// The defined applications
private transient Map applicationDefs = null;
// the bundle base for all the error key.
private String bundleBase = "ImportMessages";
// all the xpath used in the validation
private XPath processPath = null;
private XPath actSetPath = null;
private XPath actPath = null;
private XPath alltranrefsPath = null;
private XPath splitXPath = null;
private XPath tranrefsPath = null;
private XPath transPath = null;
private XPath toolPath = null;
private XPath subFlowPath = null;
private XPath partPath = null;
private XPath scriptPath = null;
private XPath procpartPath = null;
private XPath procApplPath = null;
private XPath applPath = null;
private XPath toolAgentClassPath = null;
private XPath extAttrPath = null;
private XPath procExtAttrPath = null;
private XPath dataFieldPath = null;
private XPath procDataFieldPath = null;
private XPath dataTypePath = null;
private XPath procFormalParamsPath = null;
private XPath procPriorityPath = null;
private XPath actualParamsPath = null;
private XPath formalParamsPath = null;
private XPath indexedParamsPath = null;
/**
* This class is used to save the value and data type of the proc
* data.
*/
private class ProcData {
public Object value;
public Element dataType;
public ProcData (Object value, Element dataType) {
this.value = value;
this.dataType = dataType;
}
}
/**
* This class is used to save the ActualParameters and its responding
* data type of the tool.
*/
private class ToolInfo {
public String[] actualParams;
public ToolInfo (String[] actualParams) {
this.actualParams = actualParams;
}
}
/**
* Validate a process definition package.
* @param doc the JDOM <code>Document</code> to check.
* @param eh the <code>CollectingErrorHandler</code> to which
* error messages should be added.
* @exception JDOMException if an error occurs
* @exception JaxenException if an error occurs
*/
public void validate(Document doc, CollectingErrorHandler eh)
throws JDOMException, JaxenException {
// initialize all the xpath
init();
// validate it
validateHeaderDefinition(doc, eh);
validateProcessDefinition(doc, eh);
}
private void init() throws JDOMException, JaxenException {
processPath = buildJDOMXPath
("/xpdl:Package/xpdl:WorkflowProcesses/xpdl:WorkflowProcess");
actSetPath = buildJDOMXPath("xpdl:ActivitySets/xpdl:ActivitySet");
actPath = buildJDOMXPath("xpdl:Activities/xpdl:Activity");
tranrefsPath = buildJDOMXPath
("xpdl:TransitionRefs/xpdl:TransitionRef");
alltranrefsPath = buildJDOMXPath
("descendant::xpdl:TransitionRefs/xpdl:TransitionRef");
splitXPath = buildJDOMXPath
("xpdl:TransitionRestrictions/xpdl:TransitionRestriction"
+ "/xpdl:Split[@Type='XOR']");
transPath = buildJDOMXPath ("xpdl:Transitions/xpdl:Transition");
toolPath = buildJDOMXPath ("xpdl:Implementation/xpdl:Tool");
subFlowPath = buildJDOMXPath ("xpdl:Implementation/xpdl:SubFlow");
partPath = buildJDOMXPath
("/xpdl:Package/xpdl:Participants/xpdl:Participant");
scriptPath = buildJDOMXPath ("/xpdl:Package/xpdl:Script");
procpartPath = buildJDOMXPath
("xpdl:Participants/xpdl:Participant");
applPath = buildJDOMXPath
("/xpdl:Package/xpdl:Applications/xpdl:Application");
procApplPath = buildJDOMXPath("xpdl:Applications/xpdl:Application");
toolAgentClassPath = buildJDOMXPath
("xpdl:ExtendedAttributes"
+ "/xpdl:ExtendedAttribute[@Name=\"Implementation\"]"
+ "/*[self::vx:ToolAgent or self::vx1:ToolAgent]/@Class");
extAttrPath
= buildJDOMXPath ("/xpdl:Package/xpdl:ExtendedAttributes");
procExtAttrPath = buildJDOMXPath ("xpdl:ExtendedAttributes");
dataFieldPath = buildJDOMXPath
("/xpdl:Package/xpdl:DataFields/xpdl:DataField");
procDataFieldPath = buildJDOMXPath
("xpdl:DataFields/xpdl:DataField");
dataTypePath = buildJDOMXPath ("xpdl:DataType/xpdl:BasicType");
procFormalParamsPath = buildJDOMXPath
("/xpdl:Package/xpdl:WorkflowProcesses/xpdl:WorkflowProcess"
+ "/xpdl:FormalParameters/xpdl:FormalParameter");
procPriorityPath
= buildJDOMXPath ("xpdl:ProcessHeader/xpdl:Priority");
actualParamsPath
= buildJDOMXPath ("xpdl:ActualParameters/xpdl:ActualParameter");
formalParamsPath
= buildJDOMXPath ("xpdl:FormalParameters/xpdl:FormalParameter");
indexedParamsPath = buildJDOMXPath
("xpdl:FormalParameters/xpdl:FormalParameter/@Index");
}
private XPath buildJDOMXPath(String pathString) throws JDOMException,
JaxenException {
XPath path = new JDOMXPath (pathString);
path.addNamespace("xpdl", XPDLUtil.XPDL_NS);
path.addNamespace("vx", XPDLUtil.XPDL_EXTN_NS);
path.addNamespace("vx1", XPDLUtil.XPDL_EXTN_V1_1_NS);
return path;
}
private void validateHeaderDefinition
(Document doc, CollectingErrorHandler eh)
throws JDOMException, JaxenException {
validateScript(doc, eh);
validateApplDefs(doc, eh);
validateExtendedAttributes(doc,null, eh);
}
private void validateScript (Document doc, CollectingErrorHandler eh)
throws JDOMException, JaxenException {
// supported scripts and its version
String javascript = "text/javascript", jsversion = "1.5";
String ecmascript = "text/ecmascript", esversion = "3rd Edition";
// parse
Element script = (Element)scriptPath.selectSingleNode(doc);
if (script == null) {
return;
}
String type = script.getAttributeValue("Type");
String version = script.getAttributeValue("Version");
if (version == null) {
if (!type.equals(javascript) && !type.equals(ecmascript)) {
String[] errdatas = {type};
eh.add (new PrioritizedMessage
(PrioritizedMessage.Priority.ERROR, bundleBase
+ "#package.script.type.unsupported", errdatas));
}
return;
} else {
if ((type.equals(javascript) && (version.equals(jsversion)))
|| (type.equals(ecmascript) && (version.equals(esversion)))) {
return;
} else {
String[] errdts = {type, version};
eh.add (new PrioritizedMessage
(PrioritizedMessage.Priority.ERROR, bundleBase
+ "#package.script.version.unsupported", errdts));
}
}
}
private boolean validateProcessDefinition
(Document doc, CollectingErrorHandler eh)
throws JDOMException, JaxenException {
boolean faultless = true;
List processIds = new ArrayList();
Iterator processListIterator = processPath.selectNodes(doc).iterator();
while (processListIterator.hasNext()) {
Element process = (Element)processListIterator.next();
String id = process.getAttributeValue("Id");
//validatePriority
validatePriority
(id, (Element)procPriorityPath.selectSingleNode(process),
"procdef.header.priority.notallowed", id, eh);
//validateUniqueProcessId
processIds.add(id);
//validateUniqueActivityId
validateData (doc, process, eh);
validateActivities(doc, process, eh);
//validateUniqueTransitionId
validateTransition(process, eh);
//validateExtendedAttributes
validateExtendedAttributes(null, process, eh);
}
String duplicate = findDuplicate(processIds);
if (duplicate != null) {
faultless = false;
String[] errdatas = {duplicate};
eh.add (new PrioritizedMessage
(PrioritizedMessage.Priority.ERROR,
bundleBase + "#procdef.process.ununique", errdatas));
}
return faultless;
}
private void validateData (Document doc, Element process,
CollectingErrorHandler eh)
throws JaxenException {
Map pd = procdatas(doc, process, eh);
for (Iterator i = pd.entrySet().iterator(); i.hasNext();) {
Map.Entry e = (Map.Entry)i.next();
Object type = XPDLUtil.extractDataType
(((ProcData)e.getValue()).dataType);
if ((type instanceof ExternalReference)
&& XPDLUtil.isJavaType((ExternalReference)type)) {
String[] errdatas
= {((ExternalReference)type).location().getPath()};
try {
Class jType = XPDLUtil.getJavaType ((ExternalReference)type);
if (!(jType.isInterface()
|| Serializable.class.isAssignableFrom(jType))) {
eh.add (new PrioritizedMessage
(PrioritizedMessage.Priority.ERROR, bundleBase
+ "#procdef.data.notSerializable", errdatas));
}
} catch (ClassNotFoundException ee) {
eh.add (new PrioritizedMessage
(PrioritizedMessage.Priority.ERROR, bundleBase
+ "#procdef.data.invalidJavaType", errdatas));
}
}
}
}
private void validateActivities (Document doc, Element process,
CollectingErrorHandler eh)
throws JDOMException, JaxenException {
List activitySetList = actSetPath.selectNodes(process);
// validateUniqueActivityId
doValidateActivities
(doc, process, actPath.selectNodes(process), activitySetList, null,
false, eh);
// validateUniqueActivityId in ActivitySet
Iterator activitySetIterator = activitySetList.iterator();
while (activitySetIterator.hasNext()) {
Element actSetElem = (Element)activitySetIterator.next();
List acts = actPath.selectNodes(actSetElem);
if (acts.size() == 0) {
// empty activity set
String actSetId = actSetElem.getAttributeValue("Id");
String processId = process.getAttributeValue("Id");
String[] errDatas = {processId, actSetId};
eh.add (new PrioritizedMessage
(PrioritizedMessage.Priority.ERROR,
bundleBase + "#procdef.process.activityset.empty",
errDatas));
return;
} else {
doValidateActivities (doc, process, acts, activitySetList,
actSetElem, true, eh);
}
}
}
// Validate activity of a process or what included in activitySet. If
// isIncludedInActivitySet is set to true, then activitySet Element must be
// given.
private void doValidateActivities
(Document doc, Element process, Collection acts, List activitySetList,
Element actSetElem, boolean isIncludedInActivitySet,
CollectingErrorHandler eh)
throws JDOMException, JaxenException {
Namespace namespace
= Namespace.getNamespace ("xpdl", XPDLUtil.XPDL_NS);
List activityIds = new ArrayList();
List participantIdList = validateParticipants(doc, process, eh);
String processId = process.getAttributeValue("Id");
// Validate existence of the referenced transitionRef
List transitionIds = getTransitionIds
(process, actSetElem, isIncludedInActivitySet);
Iterator activitiesIterator = acts.iterator();
while (activitiesIterator.hasNext()) {
Element activity = (Element)activitiesIterator.next();
String id = activity.getAttributeValue("Id");
//validatePriority
validatePriority
(processId, (Element)activity.getChild("Priority", namespace),
"procdef.activity.priority.notallowed", id, eh);
validateDeadlines (processId, activity, eh);
//validateId
activityIds.add(id);
// validate the included BlockActivity.
validateBlockActivity
(processId, activitySetList, actSetElem, activity,eh);
// collects all transition ref id in activity.
Iterator transRefIterator
= alltranrefsPath.selectNodes(activity).iterator();
while(transRefIterator.hasNext()) {
Element transRefElem = (Element)transRefIterator.next();
String transRefId = transRefElem.getAttributeValue("Id");
if (!transitionIds.contains(transRefId)) {
eh.add (new PrioritizedMessage
(PrioritizedMessage.Priority.ERROR,
bundleBase + "#procdef.transitionid.notfound",
new Object[] {transRefId, processId}));
}
}
validateTranstionRestrictions(process, actSetElem, activity,
isIncludedInActivitySet, eh);
validateImplementation(doc, process, activity, eh);
//validate if the referenced participant defined and unique.
validatePerformer(processId, activity, participantIdList, eh);
}
String duplicate = findDuplicate(activityIds);
if (duplicate != null) {
String errorKey = null;
String activitySetId = null;
if (isIncludedInActivitySet) {
errorKey = "procdef.activityset.activity.ununique";
activitySetId = actSetElem.getAttributeValue("Id");
} else {
errorKey = "procdef.activity.ununique";
}
String[] errdatas = {duplicate, processId, activitySetId};
eh.add (new PrioritizedMessage
(PrioritizedMessage.Priority.ERROR,
bundleBase + "#" + errorKey, errdatas));
}
}
private void validateDeadlines
(String processId, Element actEl, CollectingErrorHandler eh)
throws JDOMException {
Namespace namespace
= Namespace.getNamespace ("xpdl", XPDLUtil.XPDL_NS);
List dls = actEl.getChildren ("Deadline", namespace);
for (Iterator i = dls.iterator(); i.hasNext();) {
Element dl = (Element)i.next();
String exep = dl.getChildText("ExceptionName", namespace);
if (exep == null || exep.length() == 0) {
eh.add
(new PrioritizedMessage
(PrioritizedMessage.Priority.ERROR,
bundleBase + "#procdef.activity.deadline.noException",
new Object[] { processId,
actEl.getAttributeValue("Id") }));
}
String cond = dl.getChildText("DeadlineCondition", namespace);
if (cond == null || cond.length() == 0) {
eh.add
(new PrioritizedMessage
(PrioritizedMessage.Priority.ERROR,
bundleBase + "#procdef.activity.deadline.noCondition",
new Object[] { processId,
actEl.getAttributeValue("Id") }));
continue;
}
}
}
private void validateBlockActivity
(String processId, List activitySetList, Element actSetElement,
Element activity, CollectingErrorHandler eh)
throws JDOMException, JaxenException {
Namespace namespace = Namespace.getNamespace ("xpdl", XPDLUtil.XPDL_NS);
Element blockActivity = activity.getChild("BlockActivity", namespace);
if (blockActivity == null) {
// no block activity defined in this activity
return;
}
String blockActivityId = blockActivity.getAttributeValue("BlockId");
String activityId = activity.getAttributeValue("Id");
String[] errdatas = {activityId, blockActivityId, processId};
if ((actSetElement != null)
&& blockActivityId.equals(actSetElement.getAttributeValue("Id"))) {
// the given activity included his super activity set as block
// activity.
eh.add
(new PrioritizedMessage
(PrioritizedMessage.Priority.ERROR,
bundleBase + "#procdef.activityset.activity.includeitself",
errdatas));
return;
}
if (activitySetList != null) {
boolean validActivitySet = false;
Iterator i = activitySetList.iterator();
while (i.hasNext()) {
Element actSet = (Element)i.next();
if (actSet.getAttributeValue("Id").equals(blockActivityId)) {
validActivitySet = true;
break;
}
}
if (!validActivitySet) {
// included BlockActivity not found in the defined
// activity set
eh.add
(new PrioritizedMessage
(PrioritizedMessage.Priority.ERROR,
bundleBase + "#procdef.activity.activityset.invalid",
errdatas));
return;
}
}
}
private void validateTranstionRestrictions
(Element process, Element actSet, Element activity,
boolean isIncludedInActivitySet, CollectingErrorHandler eh)
throws JDOMException, JaxenException {
List transRefIds = new ArrayList();
Element toBeSelectedNode = isIncludedInActivitySet?actSet:process;
String toBeSelectedNodeId = toBeSelectedNode.getAttributeValue("Id");
String actId = activity.getAttributeValue("Id");
Namespace namespace = Namespace.getNamespace ("xpdl", XPDLUtil.XPDL_NS);
Element splitElement = (Element)splitXPath.selectSingleNode(activity);
if (splitElement == null) {
return;
}
List transRefList = tranrefsPath.selectNodes(splitElement);
String[] errdatas = {actId, toBeSelectedNodeId};
if (transRefList.size() == 0) {
eh.add
(new PrioritizedMessage
(PrioritizedMessage.Priority.ERROR,
bundleBase + "#procdef.activity.split.transition.notdefined",
new Object[]{actId, toBeSelectedNodeId}));
return;
}
Iterator transRefIterator = transRefList.iterator();
while(transRefIterator.hasNext()) {
Element transRef = (Element)transRefIterator.next();
transRefIds.add(transRef.getAttributeValue("Id"));
}
// find out all transitions with the fromAct same as the actId.
String notCompleteErrKey = isIncludedInActivitySet
? "#procdef.activityset.split.transition.notcomplete"
: "#procdef.activity.split.transition.notcomplete";
List transList = transPath.selectNodes(toBeSelectedNode);
Iterator transIterator = transList.iterator();
while (transIterator.hasNext()) {
Element transElem = (Element)transIterator.next();
String fromId = transElem.getAttributeValue("From");
String transId = transElem.getAttributeValue("Id");
if (fromId.equals(actId) && !transRefIds.contains(transId)) {
eh.add
(new PrioritizedMessage
(PrioritizedMessage.Priority.ERROR,
bundleBase + notCompleteErrKey,
new Object[]{actId, transId, toBeSelectedNodeId}));
}
}
// Find out if any referenced transition with the condition of
// OTHERWISE is listed at the end of TransitionRestrictions of
// Activiity; if not, needs to be sorted and throws warning.
validateTransitionRestrictionsCondition(transRefList, transList, eh);
}
// Find out if any referenced transition with the condition of
// OTHERWISE is listed at the end of TransitionRestrictions of
// Activiity; if not, needs to be sorted and throws warning.
private void validateTransitionRestrictionsCondition
(List transRefList, List transList, CollectingErrorHandler eh) {
int index = 0;
boolean foundIt = false;
Element transRef = null;
for (Iterator i = transRefList.iterator(); i.hasNext(); index++) {
transRef = (Element)i.next();
Element condition
= condition(transList, transRef.getAttributeValue("Id"));
if (condition == null) {
continue;
}
if (condition.getAttributeValue("Type") != null
&& condition.getAttributeValue("Type").equals("OTHERWISE")){
foundIt = true;
break;
}
}
if (!foundIt || (index == transRefList.size() -1)) {
return;
}
eh.add
(new PrioritizedMessage
(PrioritizedMessage.Priority.WARN,
bundleBase + "#procdef.transition.otherwise.notatend"));
}
private Element condition (List transList, String transId) {
Namespace namespace = Namespace.getNamespace ("xpdl", XPDLUtil.XPDL_NS);
Element condition = null;
for (Iterator i = transList.iterator(); i.hasNext(); ) {
Element tran = (Element)i.next();
if (tran.getAttributeValue("Id").equals(transId)) {
condition = tran.getChild("Condition", namespace);
break;
}
}
return condition;
}
private boolean validateImplementation
(Document doc, Element process, Element activity,
CollectingErrorHandler eh)
throws JDOMException, JaxenException {
if (toolPath.selectNodes(activity).size() != 0) {
// Tool as Implementation
return validateTools(doc, process, activity, eh);
} else if (subFlowPath.selectNodes(activity).size() != 0) {
// SubFlow as Implementation
return validateSubFlow(doc, process, activity, eh);
} else {
return true;
}
}
private boolean validateTools
(Document doc, Element process, Element activity,
CollectingErrorHandler eh)
throws JDOMException, JaxenException {
// initialize the lists to be compared
List formalParamsDataTypeList = new ArrayList();
Set applicationIds = applicationDefs.keySet();
String processId = process.getAttributeValue("Id");
String activityId = activity.getAttributeValue("Id");
boolean faultless = true;
// Map of tool id and its actual parameters.
Map tools = new HashMap();
Iterator toolIterator = toolPath.selectNodes(activity).iterator();
while (toolIterator.hasNext()) {
Element toolElem = (Element)toolIterator.next();
String toolId = toolElem.getAttributeValue("Id");
if (toolId != null) {
List apList = new ArrayList();
Iterator apsIt
= actualParamsPath.selectNodes(toolElem).iterator();
while (apsIt.hasNext()) {
String ap = ((Element)apsIt.next()).getTextTrim();
apList.add(ap);
}
tools.put (toolId, new ToolInfo
((String[])apList.toArray
(new String[apList.size()])));
// Validate existence of the referenced ToolId
if (!applicationIds.contains(toolId)
&& !(applicationIds.contains
(new PSK(processId, toolId)))) {
faultless = false;
eh.add (new PrioritizedMessage
(PrioritizedMessage.Priority.ERROR,
bundleBase + "#procdef.tool.notfound",
new Object[]{toolId, activityId, processId}));
}
}
}
Iterator toolsIterator = tools.keySet().iterator();
while (toolsIterator.hasNext()) {
String tid = (String)toolsIterator.next();
String[] actualParams = ((ToolInfo)tools.get(tid)).actualParams;
// reference to process local tool?
ApplicationDefinition applDef
= (ApplicationDefinition)applicationDefs
.get (new PSK(processId, tid));
// reference to package level tool?
if (applDef == null) {
applDef = (ApplicationDefinition)applicationDefs.get(tid);
}
// the referenced tool is invalid.
if (applDef == null) {
return false;
}
FormalParameter[] formalParams = applDef.formalParameters();
// check the match of formal parameters and actual parameters
if (actualParams.length != formalParams.length) {
eh.add (new PrioritizedMessage
(PrioritizedMessage.Priority.ERROR,
bundleBase + "#procdef.toolimpl.params.notmatched",
new Object[]{tid, activityId, processId}));
return false;
}
// verify the actual parameters have been defined in data fields.
for (int i = 0; i < actualParams.length; i++) {
String actParam = actualParams[i];
if (procdataMap.containsKey(actParam)) {
boolean compat = true;
if (formalParams[i].mode().equals(FormalParameter.Mode.IN)
|| formalParams[i].mode()
.equals(FormalParameter.Mode.INOUT)) {
compat = typeCompatible
(formalParams[i].type(), XPDLUtil.extractDataType
(((ProcData)procdataMap.get(actParam)).dataType));
}
if (formalParams[i].mode().equals(FormalParameter.Mode.OUT)
|| formalParams[i].mode()
.equals(FormalParameter.Mode.INOUT)) {
compat = typeCompatible
(XPDLUtil.extractDataType
(((ProcData)procdataMap.get(actParam)).dataType),
formalParams[i].type());
}
if (!compat) {
eh.add
(new PrioritizedMessage
(PrioritizedMessage.Priority.ERROR, bundleBase
+ "#procdef.toolimpl.paramsdatatype.notmatched",
new Object[]{tid, activityId, processId,
actParam}));
return false;
}
} else {
if (formalParams[i].mode() != FormalParameter.Mode.IN) {
eh.add (new PrioritizedMessage
(PrioritizedMessage.Priority.ERROR, bundleBase
+ "#procdef.toolimpl.params.datanotfound",
new Object[]{actParam, tid, activityId,
processId}));
return false;
}
if (XPDLUtil.isXMLType (formalParams[i].type())) {
String res = notXMLOrValid (actParam);
if (res != null) {
eh.add
(new PrioritizedMessage
(PrioritizedMessage.Priority.ERROR, bundleBase
+ "#procdef.toolimpl.params.invalidXML",
new Object[]{actParam, tid, activityId,
processId, res}));
return false;
}
}
}
}
}
return faultless;
}
private boolean validateSubFlow
(Document doc, Element process, Element activity,
CollectingErrorHandler eh)
throws JDOMException, JaxenException {
Namespace xpdlns = Namespace.getNamespace (XPDLUtil.XPDL_NS);
Map processMap = processMap(doc);
String activityId = activity.getAttributeValue("Id");
String processId = process.getAttributeValue("Id");
Element subFlowElem = (Element)subFlowPath.selectSingleNode(activity);
if (subFlowElem == null) {
return true;
}
String subFlowId = subFlowElem.getAttributeValue("Id");
// check if this subflow is defined.
if (!processMap.keySet().contains(subFlowId)) {
eh.add (new PrioritizedMessage
(PrioritizedMessage.Priority.ERROR,
bundleBase + "#procdef.activity.subflow.notfound",
new Object[] {activityId, subFlowId, processId}));
return false;
}
// check if the formal params of the called process in the type of
// OUT and INOUT reference the datafields or formal params in the
// calling process.
// find out all the actual parameters of the calling process.
List actualParams = new ArrayList();
Iterator actualParamsIt
= actualParamsPath.selectNodes(subFlowElem).iterator();
while(actualParamsIt.hasNext()) {
String apm = ((Element)actualParamsIt.next()).getText();
actualParams.add(apm);
}
// Map of id and its mode
Map callerFpMap = new HashMap();
List formalParamsList = formalParamsPath.selectNodes(process);
Iterator formalParamsIt = formalParamsList.iterator();
while (formalParamsIt.hasNext()) {
Element fm = (Element)formalParamsIt.next();
String fmId = fm.getAttributeValue("Id");
callerFpMap.put(fmId, fm.getAttributeValue("Mode"));
}
// find out all the formal parameters of the called process.
Element subFlowProc = (Element)processMap.get(subFlowId);
List subFlowFormalParams = formalParamsPath.selectNodes(subFlowProc);
if (subFlowFormalParams.size() != actualParams.size()){
eh.add (new PrioritizedMessage
(PrioritizedMessage.Priority.ERROR, bundleBase
+ "#procdef.activity.subflow.params.notmatched",
new Object[] {activityId, subFlowId, processId}));
return false;
}
int index = 0;
for (Iterator formParamIter = subFlowFormalParams.iterator();
formParamIter.hasNext(); index ++) {
Element fpElem = (Element)formParamIter.next();
FormalParameter fp = new FormalParameter
(fpElem.getAttributeValue("Id"), Integer.toString(index),
FormalParameter.Mode.fromString
(fpElem.getAttributeValue("Mode")),
XPDLUtil.extractDataType
(fpElem.getChild("DataType", xpdlns)));
String actParam = ((String)actualParams.get(index)).trim();
if (callerFpMap.containsKey(actParam)) {
// check the mode of the formal parameter of the calling
// process
String callerParamMode = (String)callerFpMap.get(actParam);
if (callerParamMode.indexOf(fp.mode().toString()) == -1){
eh.add (new PrioritizedMessage
(PrioritizedMessage.Priority.ERROR, bundleBase
+ "#procdef.activity.subflow.parammode.notmatched",
new Object [] {
subFlowId, actParam, callerParamMode,
fp.mode().toString(), activityId,
processId}));
return false;
}
}
if (procdataMap.containsKey(actParam)) {
boolean compat = true;
if (fp.mode().equals(FormalParameter.Mode.IN)
|| fp.mode().equals(FormalParameter.Mode.INOUT)) {
compat = typeCompatible
(fp.type(), XPDLUtil.extractDataType
(((ProcData)procdataMap.get(actParam)).dataType));
}
if (fp.mode().equals(FormalParameter.Mode.OUT)
|| fp.mode().equals(FormalParameter.Mode.INOUT)) {
compat = compat && typeCompatible
(XPDLUtil.extractDataType
(((ProcData)procdataMap.get(actParam)).dataType),
fp.type());
}
if (!compat) {
String[] errDatas = {subFlowId, activityId, processId};
eh.add (new PrioritizedMessage
(PrioritizedMessage.Priority.ERROR, bundleBase
+ "#procdef.activity.subflow"
+ ".paramdatatype.notmatched", errDatas));
return false;
}
} else {
if (fp.mode() != FormalParameter.Mode.IN) {
eh.add
(new PrioritizedMessage
(PrioritizedMessage.Priority.ERROR, bundleBase
+ "#procdef.activity.subflow.datanotfound",
new Object[] {subFlowId, actParam, activityId,
processId}));
return false;
}
if (XPDLUtil.isXMLType (fp.type())) {
String res = notXMLOrValid (actParam);
if (res != null) {
eh.add
(new PrioritizedMessage
(PrioritizedMessage.Priority.ERROR, bundleBase
+ "#procdef.subflow.params.invalidXML",
new Object[]{subFlowId, actParam, activityId,
processId, res}));
return false;
}
}
}
}
return true;
}
private String notXMLOrValid (String text) {
String src = text.trim();
if (src.length() == 0 || src.charAt(0) != '<') {
return null;
}
if (src.startsWith("<>") && src.endsWith("</>")) {
src = src.substring(2, src.length() - 3);
}
try {
SAXParserFactory pf = SAXParserFactory.newInstance();
pf.setValidating (false);
SAXParser parser = pf.newSAXParser();
XMLReader reader = parser.getXMLReader();
// Parse the file
InputSource inSrc = new InputSource
(new StringReader("<temporary-root>"+src+"</temporary-root>"));
reader.parse (inSrc);
} catch (SAXException e) {
return e.getMessage ();
} catch (IOException e) {
return e.getMessage ();
} catch (ParserConfigurationException e) {
String s = "Cannot read XPDL: " + e.getMessage();
logger.fatal (s, e);
throw new IllegalStateException (s);
}
return null;
}
private boolean typeCompatible (Object aType, Object bType) {
if (XPDLUtil.isXMLType (aType) && XPDLUtil.isXMLType (bType)) {
return true;
} else if ((aType instanceof ExternalReference)
&& (bType instanceof ExternalReference)) {
if (XPDLUtil.isJavaType((ExternalReference)aType)
!= XPDLUtil.isJavaType((ExternalReference)bType)) {
return false;
}
if (XPDLUtil.isJavaType((ExternalReference)aType)) {
try {
Class aJType = XPDLUtil.getJavaType((ExternalReference)aType);
Class bJType = XPDLUtil.getJavaType((ExternalReference)bType);
return aJType.isAssignableFrom(bJType);
} catch (ClassNotFoundException e) {
logger.error("Class no longer loadable: " + e.getMessage());
}
return false;
}
// for the time being, assume all other external references
// to be compatible
return true;
} else if (aType.equals(bType)) {
// Basic type
return true;
} else {
logger.debug(aType + " is not compatible with " + bType);
return false;
}
}
private boolean validatePerformer
(String processId, Element activity, List participantIdList,
CollectingErrorHandler eh) throws JDOMException, JaxenException {
boolean faultless = true;
Namespace namespace
= Namespace.getNamespace ("xpdl", XPDLUtil.XPDL_NS);
String performer = activity.getChildText("Performer", namespace);
String id = activity.getAttributeValue("Id");
if ((performer != null) && !participantIdList.contains(performer)) {
// check if this performer is definiert in the data fields
faultless = false;
for (Iterator i = dataFieldsList.iterator(); i.hasNext();) {
Element elem = (Element)i.next();
String elemId = elem.getAttributeValue("Id");
Element dte = elem.getChild ("DataType", namespace);
if (elemId.equals(performer)) {
Element dtb = dte.getChild("BasicType", namespace);
if ((dtb != null) && ("PERFORMER".equals
(dtb.getAttributeValue("Type")))) {
return true;
}
}
}
eh.add (new PrioritizedMessage
(PrioritizedMessage.Priority.ERROR,
bundleBase + "#procdef.performer.notfound",
new Object[]{performer, id, processId}));
}
return faultless;
}
private List validateParticipants
(Document doc, Element process, CollectingErrorHandler eh)
throws JDOMException, JaxenException {
// some jaxen versions return an immutable list
List partiList = new ArrayList(partPath.selectNodes(doc));
partiList.addAll(procpartPath.selectNodes(process));
String processId = process.getAttributeValue("Id");
List partiIdList = new ArrayList();
Iterator partiInterator = partiList.iterator();
while (partiInterator.hasNext()) {
Element pd = (Element)partiInterator.next();
partiIdList.add (pd.getAttributeValue("Id"));
}
String duplicate = findDuplicate(partiIdList);
if (duplicate != null) {
String[] errdatas = {duplicate};
eh.add (new PrioritizedMessage
(PrioritizedMessage.Priority.ERROR,
bundleBase + "#procdef.participant.ununique", errdatas));
}
return partiIdList;
}
private void validateTransition (Element process,
CollectingErrorHandler eh)
throws JDOMException, JaxenException {
// Validate unique transition id and loop activies
doValidateTransition
(process, transPath.selectNodes(process), null, false, eh);
// validate unique transition id and loop activies in ActivitySet
Iterator activitySetIterator
= actSetPath.selectNodes(process).iterator();
while (activitySetIterator.hasNext()) {
Element actSetElem = (Element)activitySetIterator.next();
doValidateTransition (process, transPath.selectNodes(actSetElem),
actSetElem, true, eh);
}
}
// Validate transition of a process or what included in activitySet. If
// isIncludedInActivitySet is set to true, then activitySet Element must be
// given.
private boolean doValidateTransition
(Element process, Collection trans, Element actSetElem,
boolean isIncludedInActivitySet, CollectingErrorHandler eh)
throws JDOMException, JaxenException {
boolean faultless = true;
String actSetElemId = null;
if (isIncludedInActivitySet) {
actSetElemId = actSetElem.getAttributeValue("Id");
}
List activityIds
= getActivityIds (process, actSetElem, isIncludedInActivitySet);
List transitionIds = new ArrayList();
List transitionTos = new ArrayList();
String processId = process.getAttributeValue("Id");
Iterator activitiesIterator = trans.iterator();
while (activitiesIterator.hasNext()) {
Element transition = (Element)activitiesIterator.next();
String transitionId = transition.getAttributeValue("Id");
transitionIds.add(transitionId);
String transitionFrom = transition.getAttributeValue("From");
String transitionTo = transition.getAttributeValue("To");
transitionTos.add(transitionTo);
String errTransition = null;
// Validate existence of the referenced activityId
if (!activityIds.contains(transitionFrom)) {
errTransition = transitionFrom;
} else if (!activityIds.contains(transitionTo)) {
errTransition = transitionTo;
}
if (errTransition != null) {
faultless = false;
String errKey1 = "#procdef.transition.activityid.notfound";
if (isIncludedInActivitySet) {
errKey1
="#procdef.activityset.transition.activityid.notfound";
}
eh.add (new PrioritizedMessage
(PrioritizedMessage.Priority.ERROR,
bundleBase + errKey1,
new Object[]{errTransition, transitionId, processId,
actSetElemId}));
}
}
String duplicate = findDuplicate(transitionIds);
String[] errdatas = {duplicate, processId, actSetElemId};
if (duplicate != null) {
faultless = false;
String errKey = "#procdef.transition.ununique";
if (isIncludedInActivitySet) {
errKey = "#procdef.activityset.transition.ununique";
}
eh.add (new PrioritizedMessage
(PrioritizedMessage.Priority.ERROR,
bundleBase + errKey, errdatas));
}
int activityCount = activityIds.size();
// Validate loop activities
if (activityCount > 0) {
activityIds.removeAll(transitionTos);
if (activityIds.size() == 0) {
faultless = false;
eh.add (new PrioritizedMessage
(PrioritizedMessage.Priority.WARN,
bundleBase +"#procdef.transition.noentry", errdatas));
}
}
return faultless;
}
/**
* Extracts all the applications definition in the package and
* in this process and use it to generate a Map of ids and
* <code>ApplicationDefinition</code>.
* @return a Map of ids and <code>ApplicationDefinition</code>.
*/
private void validateApplDefs
(Document doc, CollectingErrorHandler eh) throws JaxenException {
applicationDefs = new HashMap ();
// package level definitions
List applList = applPath.selectNodes(doc);
List appIdList = new ArrayList();
for (Iterator itr = applList.iterator(); itr.hasNext();) {
Element appl = (Element)itr.next();
validateApplDef(eh, appIdList, appl, null);
}
String duplicate = findDuplicate(appIdList);
if (duplicate != null) {
String[] errdatas = {duplicate};
eh.add (new PrioritizedMessage
(PrioritizedMessage.Priority.ERROR,
bundleBase + "#procdef.application.ununique",
errdatas));
}
// process level definitons
List processes = processes(doc);
for (Iterator i = processes.iterator(); i.hasNext();) {
Element proc = (Element)i.next();
String procId = proc.getAttributeValue("Id");
// some versions of jaxen return an immutable list
List procApplList = new ArrayList(procApplPath.selectNodes(proc));
procApplList.addAll(applList);
appIdList = new ArrayList();
for (Iterator itr = procApplList.iterator(); itr.hasNext();) {
Element appl = (Element)itr.next();
validateApplDef(eh, appIdList, appl, procId);
}
duplicate = findDuplicate(appIdList);
if (duplicate != null) {
String[] errdatas = {duplicate};
eh.add (new PrioritizedMessage
(PrioritizedMessage.Priority.ERROR,
bundleBase + "#procdef.application.ununique",
errdatas));
}
}
}
/**
* @param eh
* @param appIdList
* @param appl
* @throws JaxenException
*/
private void validateApplDef (CollectingErrorHandler eh, List appIdList,
Element appl, String procId)
throws JaxenException {
String tac = toolAgentClassPath.stringValueOf(appl);
if (tac == null || tac.length() == 0) {
eh.add (new PrioritizedMessage
(PrioritizedMessage.Priority.ERROR, bundleBase
+ "#procdef.application.toolAgentClass",
new String[] { appl.getAttributeValue("Id") }));
}
try {
ApplicationDefinition ad = new ApplicationDefinition ();
subtreeToSAX (appl, ad.saxInitializer());
applicationDefs.put
(procId == null
? (Object)ad.id() : new PSK (procId, ad.id()), ad);
appIdList.add (ad.id());
List indexedParams = indexedParamsPath.selectNodes (appl);
if (indexedParams.size () > 0) {
String[] errdatas = {ad.id()};
eh.add (new PrioritizedMessage
(PrioritizedMessage.Priority.WARN, bundleBase
+ "#procdef.application.indexedParameter",
new String[] { ad.id() }));
}
} catch (IllegalArgumentException ex) {
eh.add (new PrioritizedMessage
(PrioritizedMessage.Priority.ERROR, ex.getMessage()));
}
}
/**
* Extracts all the applications definition in the package and
* in this process and use it to generate a Map of ids and
* <code>ApplicationDefinition</code>.
* @return a Map of ids and <code>ApplicationDefinition</code>.
*/
private void validateExtendedAttributes
(Document doc, Element process, CollectingErrorHandler eh)
throws JaxenException {
Element extendedAttrs = null;
if (doc != null) {
extendedAttrs = (Element)extAttrPath.selectSingleNode(doc);
} else if (process != null) {
extendedAttrs = (Element)procExtAttrPath.selectSingleNode(process);
}
if (extendedAttrs == null) {
return;
}
Namespace namespace = Namespace.getNamespace (XPDLUtil.XPDL_NS);
List extendedAttrList
= extendedAttrs.getChildren("ExtendedAttribute", namespace);
Iterator iterator = extendedAttrList.iterator();
while (iterator.hasNext()) {
Element extendedAttr = (Element)iterator.next();
String extendedAttrName = extendedAttr.getAttributeValue("Name");
// Check if the extendedAttribute is in MANUAL/AUTOMATIC/COMPLETED.
if (extendedAttrName.equals("RemoveClosedProcess")) {
String val = extendedAttr.getAttributeValue("Value");
if (val == null) {
val = extendedAttr.getTextTrim();
}
if (!val.equals("AUTOMATIC") && !val.equals("MANUAL")
&& !val.equals("COMPLETED")) {
eh.add (new PrioritizedMessage
(PrioritizedMessage.Priority.ERROR,
bundleBase
+ "#procdef.extendedattr.value.notallowed",
new String[] { extendedAttrName, val }));
}
} else if (extendedAttrName.equals("AuditEventSelection")) {
String val = extendedAttr.getAttributeValue("Value");
if (val == null) {
val = extendedAttr.getTextTrim();
}
if (!val.equals("AllEvents") && !val.equals("StateEventsOnly")
&& !val.equals("ProcessClosedEventsOnly")
&& !val.equals("NoEvents")) {
eh.add (new PrioritizedMessage
(PrioritizedMessage.Priority.ERROR, bundleBase
+ "#procdef.extendedattr.value.notallowed",
new String[] { extendedAttrName, val }));
}
if (process == null) {
eh.add (new PrioritizedMessage
(PrioritizedMessage.Priority.WARN,
bundleBase + "#package.nonstandard.auditing"));
} else {
eh.add (new PrioritizedMessage
(PrioritizedMessage.Priority.WARN,
bundleBase + "#process.nonstandard.auditing",
new String[] { process.getAttributeValue("Id") }));
}
} else if (extendedAttrName.equals("StoreAuditEvents")) {
String val = extendedAttr.getAttributeValue("Value");
if (val == null) {
val = extendedAttr.getTextTrim();
}
if (!val.equalsIgnoreCase("true")) {
if (process == null) {
eh.add (new PrioritizedMessage
(PrioritizedMessage.Priority.WARN,
bundleBase + "#package.nonstandard.logging"));
} else {
eh.add (new PrioritizedMessage
(PrioritizedMessage.Priority.WARN,
bundleBase + "#process.nonstandard.logging",
new String[]
{ process.getAttributeValue("Id") }));
}
}
}
}
}
private void validatePriority
(String processId, Element priority, String errorKey,
String errorText, CollectingErrorHandler eh) throws JDOMException {
if (priority == null) {
return;
}
String priorityStr = null;
try {
priorityStr = priority.getText();
if (priorityStr == null) {
return;
} else {
priorityStr = priorityStr.trim();
}
ExtExecutionObjectLocal.Priority.fromInt
(Integer.parseInt(priorityStr.trim()));
} catch (Exception e) {
String[] errdatas = {errorText, priorityStr, processId};
eh.add (new PrioritizedMessage
(PrioritizedMessage.Priority.ERROR,
bundleBase + "#" + errorKey, errdatas));
}
}
private List getActivityIds(Element process, Element actSet,
boolean isIncludedInActivitySet)
throws JDOMException, JaxenException {
List activityIds = new ArrayList();
Element toBeSelectedNode = isIncludedInActivitySet?actSet:process;
Iterator activitiesIterator
= actPath.selectNodes(toBeSelectedNode).iterator();
while (activitiesIterator.hasNext()) {
Element activity = (Element)activitiesIterator.next();
activityIds.add(activity.getAttributeValue("Id"));
}
return activityIds;
}
private List getTransitionIds
(Element process, Element actSet, boolean isIncludedInActivitySet)
throws JDOMException, JaxenException {
List transitionIds = new ArrayList();
Element toBeSelectedNode = isIncludedInActivitySet?actSet:process;
Iterator transIterator
= transPath.selectNodes(toBeSelectedNode).iterator();
while (transIterator.hasNext()) {
Element transElem = (Element)transIterator.next();
transitionIds.add(transElem.getAttributeValue("Id"));
}
return transitionIds;
}
// Get all the data fields defined in the package header and
// in the given process.
private Map procdatas
(Document doc, Element process, CollectingErrorHandler eh)
throws JaxenException {
procdataMap = new HashMap();
List docDataFields = dataFieldPath.selectNodes(doc);
List procDataFields = procDataFieldPath.selectNodes(process);
if (dataFieldsList == null) {
dataFieldsList = new ArrayList();
dataFieldsList.addAll(docDataFields);
dataFieldsList.addAll(procDataFields);
}
// determine all DataFields defined in the package header
extractDataFields(docDataFields, procdataMap, eh);
// determine all DataFields defined in the process
extractDataFields(procDataFields, procdataMap, eh);
// add formal parameters
Namespace xpdlns = Namespace.getNamespace (XPDLUtil.XPDL_NS);
Iterator iterator = procFormalParamsPath.selectNodes(doc).iterator();
while (iterator.hasNext()) {
Element elem = (Element)iterator.next();
String id = elem.getAttributeValue("Id");
procdataMap.put
(id, new ProcData(null, elem.getChild("DataType", xpdlns)));
}
return procdataMap;
}
/**
* Extract the defined data fields and put them in the procDataMap.
* @param dataFieldsList list of data field.
* @param procDataMap map with extracted data/value.
*/
private void extractDataFields(List dataFieldsList, Map procDataMap,
CollectingErrorHandler eh)
throws JaxenException {
Namespace xpdlns = Namespace.getNamespace (XPDLUtil.XPDL_NS);
Iterator iterator = dataFieldsList.iterator();
while (iterator.hasNext()) {
Element elem = (Element)iterator.next();
String id = elem.getAttributeValue("Id");
Element dte = elem.getChild ("DataType", xpdlns);
Element ve = elem.getChild("InitialValue", xpdlns);
try {
procdataMap.put
(id, new ProcData
(XPDLUtil.extractValue (dte, ve), dte));
} catch (IllegalArgumentException e) {
eh.add (new PrioritizedMessage
(PrioritizedMessage.Priority.ERROR,
bundleBase + "#procdef.data.cannotInit",
new Object[] { id, e.getMessage () }));
continue;
}
}
}
/**
* Returns the Map of the Ids and element of all the process of the whole
* xpdl doc.
*/
private Map processMap(Document doc) throws JaxenException {
Map processMap = new HashMap();
for (Iterator i = processes(doc).iterator(); i.hasNext();) {
Element proc = (Element)i.next();
processMap.put(proc.getAttributeValue("Id"), proc);
}
return processMap;
}
/**
* Returns the list of all process elements of the whole xpdl doc.
*/
private List processes(Document doc) throws JaxenException {
return processPath.selectNodes(doc);
}
/**
* Used to find the duplicate in the list. If found, returns the duplicate
* in String; if not, returns null;
*/
private String findDuplicate(List ids) {
if (ids.size() < 2 ) {
return null;
}
Collections.sort(ids);
for (int i=1; i<ids.size(); i++) {
if (((String)ids.get(i)).equals((String)ids.get(i-1))){
return (String)ids.get(i);
}
}
return null;
}
private void subtreeToSAX (Element e, ContentHandler h) {
try {
SAXEventBufferImpl buf = new SAXEventBufferImpl ();
SAXOutputter out = new SAXOutputter (buf);
out.output(new Document((Element)e.clone()));
HandlerStack hs = new HandlerStack (h);
buf.emit (hs.contentHandler());
} catch (JDOMException ex) {
throw new IllegalArgumentException (ex.getMessage ());
} catch (SAXException ex) {
throw new IllegalArgumentException (ex.getMessage ());
}
}
// Process Scoped Key
private class PSK {
private String processId;
private String key;
public PSK (String pId, String key) {
processId = pId;
this.key = key;
}
/**
* Describe <code>equals</code> method here.
*
* @param object an <code>Object</code> value
* @return a <code>boolean</code> value
*/
public boolean equals(Object object) {
if (!(object instanceof PSK)) {
return false;
}
PSK other = (PSK)object;
return processId.equals(other.processId)
&& key.equals(other.key);
}
/**
* Describe <code>hashCode</code> method here.
*
* @return an <code>int</code> value
*/
public int hashCode() {
return processId.hashCode() ^ key.hashCode();
}
}
}