Package de.danet.an.workflow.domain

Source Code of de.danet.an.workflow.domain.ProcDefValidator$ProcData

/*
* 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();
  }
    }
}
TOP

Related Classes of de.danet.an.workflow.domain.ProcDefValidator$ProcData

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.