Java tutorial
/* * Copyright (c) 2004-2012 The YAWL Foundation. All rights reserved. * The YAWL Foundation is a collaboration of individuals and * organisations who are committed to improving workflow technology. * * This file is part of YAWL. YAWL is free software: you can * redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation. * * YAWL 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 Lesser General * Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with YAWL. If not, see <http://www.gnu.org/licenses/>. */ package org.yawlfoundation.yawl.unmarshal; import org.apache.logging.log4j.LogManager; import org.jdom2.Attribute; import org.jdom2.Element; import org.jdom2.Namespace; import org.yawlfoundation.yawl.elements.*; import org.yawlfoundation.yawl.elements.data.YParameter; import org.yawlfoundation.yawl.elements.data.YVariable; import org.yawlfoundation.yawl.engine.time.YTimer; import org.yawlfoundation.yawl.engine.time.YWorkItemTimer; import org.yawlfoundation.yawl.logging.YLogPredicate; import org.yawlfoundation.yawl.schema.YSchemaVersion; import org.yawlfoundation.yawl.util.DynamicValue; import org.yawlfoundation.yawl.util.JDOMUtil; import org.yawlfoundation.yawl.util.StringUtil; import javax.xml.datatype.Duration; import java.net.MalformedURLException; import java.net.URL; import java.util.*; /** * Builds decomposition objects from XML doclets. * * @author Lachlan Aldred * @author Michael Adams refactored for version 2 */ public class YDecompositionParser { private Element _decompElem; private Postset _postsetIDs; private Map<YTask, List<String>> _removeSetIDs; private Namespace _yawlNS; private YDecomposition _decomposition; private Map<YTask, String> _decomposesToIDs; private YSpecificationParser _specificationParser; Map<YTask, List<Element>> _removeSetForFlows = new HashMap<YTask, List<Element>>(); private YSchemaVersion _version; /** * gets the built decomposition. * @return the decomposition */ YDecomposition getDecomposition() { return _decomposition; } /** * Parses the decomposition from the appropriate XML doclet. * @param decompElem the XML doclet containing the decomp configuration. * @param specificationParser a reference to parent spec parser. * @param version the version of XML structure */ YDecompositionParser(Element decompElem, YSpecificationParser specificationParser, YSchemaVersion version) { _decompElem = decompElem; _yawlNS = decompElem.getNamespace(); _specificationParser = specificationParser; _version = version; _postsetIDs = new Postset(); _removeSetIDs = new HashMap<YTask, List<String>>(); _decomposesToIDs = new HashMap<YTask, String>(); _decomposition = createDecomposition(decompElem); _postsetIDs.addImplicitConditions(); linkElements(); } private YDecomposition createDecomposition(Element decompElem) { Namespace schemaInstanceNS = decompElem.getNamespace("xsi"); String xsiType = _decompElem.getAttributeValue("type", schemaInstanceNS); String id = _decompElem.getAttributeValue("id"); String elementName = _decompElem.getName(); if ("NetFactsType".equals(xsiType) || "rootNet".equals(elementName)) { _decomposition = new YNet(id, _specificationParser.getSpecification()); parseNet((YNet) _decomposition, decompElem); } else if ("WebServiceGatewayFactsType".equals(xsiType)) { _decomposition = new YAWLServiceGateway(id, _specificationParser.getSpecification()); parseWebServiceGateway((YAWLServiceGateway) _decomposition, decompElem); } /** * AJH: Added to support XML attribute pass-thru from specification into task output data doclet. * Load element attributes */ for (Attribute attr : decompElem.getAttributes()) { String attname = attr.getName(); boolean isXsiNS = attr.getNamespace() == schemaInstanceNS; //don't add the standard YAWL schema attributes to the pass through list. if (!("id".equals(attname) || ("type".equals(attname) && isXsiNS))) { String value = attr.getValue(); if (value.startsWith("dynamic{")) { _decomposition.setAttribute(attr.getName(), new DynamicValue(value, _decomposition)); } else _decomposition.setAttribute(attr.getName(), value); } } parseDecompositionRoles(_decomposition, decompElem); _decomposition.setLogPredicate(parseLogPredicate(decompElem, _yawlNS)); // added for resourcing parseExternalInteraction(_decomposition, decompElem); parseCodelet(_decomposition, decompElem); return _decomposition; } private void parseDecompositionRoles(YDecomposition decomposition, Element decompElem) { String name = decompElem.getChildText("name", _yawlNS); if (name != null) { decomposition.setName(name); } String documentation = decompElem.getChildText("documentation", _yawlNS); if (documentation != null) { decomposition.setDocumentation(documentation); } List<Element> inputParamElems = decompElem.getChildren("inputParam", _yawlNS); for (int i = 0; i < inputParamElems.size(); i++) { YParameter yparameter = new YParameter(_decomposition, YParameter._INPUT_PARAM_TYPE); yparameter.setOrdering(i); parseParameter(inputParamElems.get(i), yparameter, _yawlNS, isBeta2Version()); decomposition.addInputParameter(yparameter); } List<Element> outputParamElems = decompElem.getChildren("outputParam", _yawlNS); for (int i = 0; i < outputParamElems.size(); i++) { YParameter yparameter = new YParameter(_decomposition, YParameter._OUTPUT_PARAM_TYPE); yparameter.setOrdering(i); parseParameter(outputParamElems.get(i), yparameter, _yawlNS, isBeta2Version()); decomposition.addOutputParameter(yparameter); } for (Element outputExpressionElem : decompElem.getChildren("outputExpression", _yawlNS)) { String outputExpressionText = outputExpressionElem.getAttributeValue("query"); decomposition.setOutputExpression(outputExpressionText); } markEmptyComplexTypeVariables(decomposition); } private void parseWebServiceGateway(YAWLServiceGateway webServiceGateway, Element decompositionElem) { for (Element yawlServiceElem : decompositionElem.getChildren("yawlService", _yawlNS)) { String yawlServiceID = yawlServiceElem.getAttributeValue("id"); YAWLServiceReference yawlService = new YAWLServiceReference(yawlServiceID, webServiceGateway); webServiceGateway.setYawlService(yawlService); } List<Element> enablementParamElems = decompositionElem.getChildren("enablementParam", _yawlNS); for (int i = 0; i < enablementParamElems.size(); i++) { Element enablementParamElem = enablementParamElems.get(i); YParameter parameter = new YParameter(_decomposition, YParameter._ENABLEMENT_PARAM_TYPE); parameter.setOrdering(i); parseParameter(enablementParamElem, parameter, _yawlNS, isBeta2Version()); webServiceGateway.setEnablementParameter(parameter); } } private void parseProcessControlElements(YNet aNet, Element processControlElementsElem) { Element inputConditionElem = processControlElementsElem.getChild("inputCondition", _yawlNS); aNet.setInputCondition((YInputCondition) parseCondition(aNet, inputConditionElem)); Element outputConditionElem = processControlElementsElem.getChild("outputCondition", _yawlNS); aNet.setOutputCondition((YOutputCondition) parseCondition(aNet, outputConditionElem)); for (Element taskElem : processControlElementsElem.getChildren("task", _yawlNS)) { aNet.addNetElement(parseTask(taskElem)); } for (Element condElem : processControlElementsElem.getChildren("condition", _yawlNS)) { aNet.addNetElement(parseCondition(aNet, condElem)); } } private YTask parseTask(Element taskElem) { short[] splitJoinTypes = parseSplitJoinTypes(taskElem); Element decomposesToRefElem = taskElem.getChild("decomposesTo", _yawlNS); String decomposesToID = null; if (decomposesToRefElem != null) { decomposesToID = decomposesToRefElem.getAttributeValue("id"); } String taskID = taskElem.getAttributeValue("id"); String decompositionType = _specificationParser.getDecompositionType(decomposesToID); YTask task = null; if ("NetFactsType".equals(decompositionType)) { task = new YCompositeTask(taskID, splitJoinTypes[1], splitJoinTypes[0], (YNet) _decomposition); } else if ("WebServiceGatewayFactsType".equals(decompositionType) || decomposesToID == null || // empty task or no decomp ref decompositionType == null) { // ref to missing decomp task = new YAtomicTask(taskID, splitJoinTypes[1], splitJoinTypes[0], (YNet) _decomposition); } if (decomposesToID != null) { _decomposesToIDs.put(task, decomposesToID); } parseExternalTaskRoles(taskElem, task); parseNameAndDocumentation(task, taskElem); if ((task != null) && (!_version.isBetaVersion())) { task.setResourcingSpecs(taskElem.getChild("resourcing", _yawlNS)); parseTimerParameters(task, taskElem); parseCustomFormURL(task, taskElem); parseConfiguration(task, taskElem); } return task; } private short[] parseSplitJoinTypes(Element externalTaskElem) { String[] xmlSplitJoinCodes = new String[2]; xmlSplitJoinCodes[0] = externalTaskElem.getChild("split", _yawlNS).getAttributeValue("code"); xmlSplitJoinCodes[1] = externalTaskElem.getChild("join", _yawlNS).getAttributeValue("code"); short[] splitJoinTypes = new short[2]; for (int i = 0; i < splitJoinTypes.length; i++) { if (xmlSplitJoinCodes[i].equalsIgnoreCase("and")) { splitJoinTypes[i] = YTask._AND; } else if (xmlSplitJoinCodes[i].equalsIgnoreCase("or")) { splitJoinTypes[i] = YTask._OR; } else if (xmlSplitJoinCodes[i].equalsIgnoreCase("xor")) { splitJoinTypes[i] = YTask._XOR; } } return splitJoinTypes; } private void parseExternalTaskRoles(Element externalTaskElem, YTask externalTask) { _removeSetIDs.put(externalTask, parseRemoveSet(externalTaskElem)); _removeSetForFlows.put(externalTask, parseRemoveSetFromFlow(externalTaskElem)); _postsetIDs.add(externalTask.getID(), parsePostset(externalTaskElem)); Element startingMappings = externalTaskElem.getChild("startingMappings", _yawlNS); if (startingMappings != null) { externalTask.setDataMappingsForTaskStarting(parseMappings(startingMappings, true)); } Element completedMappings = externalTaskElem.getChild("completedMappings", _yawlNS); if (completedMappings != null) { externalTask.setDataMappingsForTaskCompletion(parseMappings(completedMappings, false)); } Element enablementMappings = externalTaskElem.getChild("enablementMappings", _yawlNS); if (enablementMappings != null && externalTask instanceof YAtomicTask) { ((YAtomicTask) externalTask).setDataMappingsForEnablement(parseMappings(enablementMappings, true)); } String taskType = externalTaskElem.getAttributeValue("type", externalTaskElem.getNamespace("xsi")); if ("MultipleInstanceExternalTaskFactsType".equals(taskType)) { externalTask.setUpMultipleInstanceAttributes(externalTaskElem.getChildText("minimum", _yawlNS), externalTaskElem.getChildText("maximum", _yawlNS), externalTaskElem.getChildText("threshold", _yawlNS), externalTaskElem.getChild("creationMode", _yawlNS).getAttributeValue("code")); String expression = externalTaskElem.getChild("miDataInput", _yawlNS).getChild("expression", _yawlNS) .getAttributeValue("query"); String processingExpressionForInput = externalTaskElem.getChild("miDataInput", _yawlNS) .getChild("splittingExpression", _yawlNS).getAttributeValue("query"); String remoteVarName = externalTaskElem.getChild("miDataInput", _yawlNS) .getChildText("formalInputParam", _yawlNS); externalTask.setDataBindingForInputParam(expression, remoteVarName); externalTask.setMultiInstanceInputDataMappings(remoteVarName, processingExpressionForInput); Element miDataOutputElem = externalTaskElem.getChild("miDataOutput", _yawlNS); if (miDataOutputElem != null) { String remoteExpressionName = miDataOutputElem.getChild("formalOutputExpression", _yawlNS) .getAttributeValue("query"); String aggregationQuery = miDataOutputElem.getChild("outputJoiningExpression", _yawlNS) .getAttributeValue("query"); String localVarName = miDataOutputElem.getChildText("resultAppliedToLocalVariable", _yawlNS); externalTask.setDataBindingForOutputExpression(remoteExpressionName, localVarName); externalTask.setMultiInstanceOutputDataMappings(remoteExpressionName, aggregationQuery); } } } private List<Element> parseRemoveSetFromFlow(Element externalTaskElem) { List<Element> removeSetForFlows = externalTaskElem.getChildren("removesTokensFromFlow", _yawlNS); if (removeSetForFlows != null) { List<Element> removeIDs = new ArrayList<Element>(); for (Element id : removeSetForFlows) { removeIDs.add(id); } return removeIDs; } return Collections.emptyList(); } private Map<String, String> parseMappings(Element mappingsElem, boolean isStartMappings) { Map<String, String> map = new TreeMap<String, String>(); for (Element mapping : mappingsElem.getChildren()) { String expression = mapping.getChild("expression", _yawlNS).getAttributeValue("query"); String varOrParam = mapping.getChildText("mapsTo", _yawlNS); if (isStartMappings) { map.put(varOrParam, expression); } else { map.put(expression, varOrParam); } } return map; } private List<String> parseRemoveSet(Element externalTaskElem) { List<String> removeIDs = new ArrayList<String>(); for (Element removesElem : externalTaskElem.getChildren("removesTokens", _yawlNS)) { removeIDs.add(removesElem.getAttributeValue("id")); } return removeIDs; } private YCondition parseCondition(YNet aNet, Element conditionElem) { String conditionType = conditionElem.getName(); String id = conditionElem.getAttributeValue("id"); YCondition condition = null; if ("condition".equals(conditionType)) { String label = conditionElem.getChildText("label"); if (label != null) { condition = new YCondition(id, label, aNet); } else { condition = new YCondition(id, aNet); } } else if ("inputCondition".equals(conditionType)) { String name = conditionElem.getChildText("name"); if (name != null) { condition = new YInputCondition(id, name, aNet); } else { condition = new YInputCondition(id, aNet); } } else if ("outputCondition".equals(conditionType)) { String name = conditionElem.getChildText("name"); if (name != null) { condition = new YOutputCondition(id, name, aNet); } else { condition = new YOutputCondition(id, aNet); } } else condition = new YCondition(id, aNet); // should never hit this parseNameAndDocumentation(condition, conditionElem); _postsetIDs.add(condition.getID(), parsePostset(conditionElem)); return condition; } private void parseNameAndDocumentation(YExternalNetElement element, Element netElementElem) { String name = netElementElem.getChildText("name", _yawlNS); if (name == null && (element instanceof YTask)) { String id = netElementElem.getAttributeValue("id"); name = stripEngineID(id); } element.setName(name); String documentation = netElementElem.getChildText("documentation", _yawlNS); element.setDocumentation(documentation); } private void parseCustomFormURL(YTask task, Element taskElem) { String formStr = taskElem.getChildText("customForm", _yawlNS); if (formStr != null) { try { URL formURI = new URL(formStr); task.setCustomFormURI(formURI); } catch (MalformedURLException use) { LogManager.getLogger(this.getClass()) .error("Invalid custom form URL in specification for task {}: {}" + ". Custom form URL will be ignored.", task.getID(), formStr); } } } private void parseConfiguration(YTask task, Element taskElem) { Element configure = taskElem.getChild("configuration", _yawlNS); if (configure != null) { task.setConfigurationElement(taskElem); } } private void parseTimerParameters(YTask task, Element taskElem) { Element timerElem = taskElem.getChild("timer", _yawlNS); if (timerElem != null) { YTimerParameters timerParameters = new YTimerParameters(); String netParam = timerElem.getChildText("netparam", _yawlNS); // net-level param holds values at runtime if (netParam != null) { timerParameters.set(netParam); } else { // get the triggering event String triggerStr = timerElem.getChildText("trigger", _yawlNS); YWorkItemTimer.Trigger trigger = YWorkItemTimer.Trigger.valueOf(triggerStr); // expiry is a stringified long value representing a specific datetime String expiry = timerElem.getChildText("expiry", _yawlNS); if (expiry != null) timerParameters.set(trigger, new Date(new Long(expiry))); else { // duration type - specified as a Duration? String durationStr = timerElem.getChildText("duration", _yawlNS); if (durationStr != null) { Duration duration = StringUtil.strToDuration(durationStr); if (duration != null) { timerParameters.set(trigger, duration); } } else { // ticks / interval durationparams type Element durationElem = timerElem.getChild("durationparams", _yawlNS); String tickStr = durationElem.getChildText("ticks", _yawlNS); String intervalStr = durationElem.getChildText("interval", _yawlNS); YTimer.TimeUnit interval = YTimer.TimeUnit.valueOf(intervalStr); timerParameters.set(trigger, new Long(tickStr), interval); } } } task.setTimerParameters(timerParameters); } } private List<FlowStruct> parsePostset(Element netElementElem) { List<FlowStruct> postsetFlowStructs = new ArrayList<FlowStruct>(); for (Element flowsIntoElem : netElementElem.getChildren("flowsInto", _yawlNS)) { String nextElementRef = flowsIntoElem.getChild("nextElementRef", _yawlNS).getAttributeValue("id"); FlowStruct flowStruct = new FlowStruct(nextElementRef, flowsIntoElem.getChildText("predicate", _yawlNS), flowsIntoElem.getChildText("documentation", _yawlNS)); String predicateString = flowsIntoElem.getChildText("predicate", _yawlNS); if (predicateString != null) { flowStruct._flowPredicate = predicateString; String predicateOrderingStr = flowsIntoElem.getChild("predicate", _yawlNS) .getAttributeValue("ordering"); if (predicateOrderingStr != null) { flowStruct._predicateOrdering = new Integer(predicateOrderingStr); } } Element isDefaultFlow = flowsIntoElem.getChild("isDefaultFlow", _yawlNS); if (isDefaultFlow != null) { flowStruct._isDefaultFlow = true; } postsetFlowStructs.add(flowStruct); } return postsetFlowStructs; } private YNet parseNet(YNet net, Element netElem) { if (!isBeta2Version()) { String isRootNet = netElem.getAttributeValue("isRootNet"); if ("true".equals(isRootNet)) { _specificationParser.getSpecification().setRootNet(net); // set external data gateway (since 2.1) String gateway = netElem.getChildText("externalDataGateway", _yawlNS); if (gateway != null) net.setExternalDataGateway(gateway); } } for (Element localVariableElem : netElem.getChildren("localVariable", _yawlNS)) { YVariable localVar = new YVariable(_decomposition); parseLocalVariable(localVariableElem, localVar, _yawlNS, isBeta2Version()); net.setLocalVariable(localVar); } parseProcessControlElements(net, netElem.getChild("processControlElements", _yawlNS)); return net; } private void markEmptyComplexTypeVariables(YDecomposition decomposition) { List<YVariable> varList = new ArrayList<YVariable>(decomposition.getInputParameters().values()); varList.addAll(decomposition.getOutputParameters().values()); if (decomposition instanceof YNet) { varList.addAll(((YNet) decomposition).getLocalVariables().values()); } List<String> emptyTypeNames = _specificationParser.getEmptyComplexTypeFlagTypeNames(); for (YVariable var : varList) { if (var.getDataTypeName() != null) { String dataTypeName = var.getDataTypeNameUnprefixed(); if (emptyTypeNames.contains(dataTypeName)) { var.setEmptyTyped(true); } } } } /** * Adds variable specific information to the YParameter argument (in & out var). * @param localVariableElem * @param variable */ public static void parseLocalVariable(Element localVariableElem, YVariable variable, Namespace ns, boolean version2) { //parse & set the initial value variable.setInitialValue(JDOMUtil.decodeEscapes(localVariableElem.getChildText("initialValue", ns))); String name; String dataType; String namespace = null; //if version is beta 2 vars are stored in different format if (version2) { name = localVariableElem.getAttributeValue("name"); dataType = localVariableElem.getChildText("type", ns); if (null != dataType) { namespace = dataType.startsWith("xs") ? "http://www.w3.org/2001/XMLSchema" : null; //if data type is of QName form eliminate the first bit as it is useless for //version 2 anyway if (dataType.indexOf(':') != -1) { dataType = dataType.substring(dataType.indexOf(':') + 1); } } if (null == namespace) variable.setUntyped(true); } else { //must be version 3 or greater name = localVariableElem.getChildText("name", ns); dataType = localVariableElem.getChildText("type", ns); namespace = localVariableElem.getChildText("namespace", ns); //check to see if the variable is untyped variable.setUntyped(localVariableElem.getChild("isUntyped", ns) != null); // set mandatory (default is false) variable.setMandatory(localVariableElem.getChild("mandatory", ns) != null); //set the element name if it uses one String elementName; elementName = localVariableElem.getChildText("element", ns); variable.setElementName(elementName); // set ordering (if schema 2.1 or later) String orderingStr = localVariableElem.getChildText("index", ns); if (StringUtil.isIntegerString(orderingStr)) { variable.setOrdering(new Integer(orderingStr)); } variable.getAttributes().fromJDOM(localVariableElem.getAttributes()); variable.getAttributes().transformDynamicValues(variable); } //the variable either is data typed xor linked to an element declaration variable.setDataTypeAndName(dataType, name, namespace); } /** * @return whether this is a a beta 2 specification version or not. */ private boolean isBeta2Version() { return _version.isBeta2(); } /** * Adds parameter specific information to the YParameter argument (in & out var). * @param paramElem the XML data * @param parameter the in & out var. */ public static void parseParameter(Element paramElem, YParameter parameter, Namespace ns, boolean version2) { parseLocalVariable(paramElem, parameter, ns, version2); String orderStr = paramElem.getChildText("ordering"); if ((orderStr != null) && (StringUtil.isIntegerString(orderStr))) parameter.setOrdering(Integer.parseInt(orderStr)); boolean isCutThroughParam = paramElem.getChild("isCutThroughParam", ns) != null; if (isCutThroughParam) { parameter.setIsCutThroughParam(isCutThroughParam); } String defaultValue = JDOMUtil.decodeEscapes(paramElem.getChildText("defaultValue", ns)); if (defaultValue != null) parameter.setDefaultValue(defaultValue); parameter.setLogPredicate(parseLogPredicate(paramElem, ns)); } private void parseExternalInteraction(YDecomposition decomposition, Element decompElem) { String interactionStr = decompElem.getChildText("externalInteraction", _yawlNS); if (interactionStr != null) decomposition.setExternalInteraction(interactionStr.equalsIgnoreCase("manual")); } private void parseCodelet(YDecomposition decomposition, Element decompElem) { String codelet = decompElem.getChildText("codelet", _yawlNS); if (codelet != null) decomposition.setCodelet(codelet); } private static YLogPredicate parseLogPredicate(Element decompElem, Namespace ns) { Element elemLogPredicate = decompElem.getChild("logPredicate", ns); return elemLogPredicate != null ? new YLogPredicate(elemLogPredicate, ns) : null; } protected Map<YTask, String> getDecomposesToIDs() { return _decomposesToIDs; } private String stripEngineID(String id) { if (id != null) { int pos = id.indexOf('_'); if (pos > -1) { String lhs = id.substring(0, pos); id = StringUtil.isIntegerString(lhs) ? id.substring(pos + 1) : lhs; } } return id; } private void linkElements() { if (_decomposition instanceof YNet) { YNet decomposition = (YNet) _decomposition; for (YExternalNetElement currentNetElement : decomposition.getNetElements().values()) { List<FlowStruct> postsetIDs = _postsetIDs.getQPostset(currentNetElement.getID()); if (postsetIDs != null) { for (FlowStruct flowStruct : postsetIDs) { YExternalNetElement nextElement = decomposition.getNetElement(flowStruct._flowInto); YFlow flow = new YFlow(currentNetElement, nextElement); flow.setEvalOrdering(flowStruct._predicateOrdering); flow.setIsDefaultFlow(flowStruct._isDefaultFlow); flow.setXpathPredicate(flowStruct._flowPredicate); flow.setDocumentation(flowStruct._label); currentNetElement.addPostset(flow); } } } for (YTask externalTask : _removeSetIDs.keySet()) { List<YExternalNetElement> removeSetObjects = new Vector<YExternalNetElement>(); for (String id : _removeSetIDs.get(externalTask)) { removeSetObjects.add(decomposition.getNetElement(id)); } if (removeSetObjects.size() > 0) { externalTask.addRemovesTokensFrom(removeSetObjects); } } for (YTask taskWithRemoveSet : _removeSetForFlows.keySet()) { for (Element removesTokensFromFlowElem : _removeSetForFlows.get(taskWithRemoveSet)) { Element flowSourceElem = removesTokensFromFlowElem.getChild("flowSource", _yawlNS); Element flowDestElem = removesTokensFromFlowElem.getChild("flowDestination", _yawlNS); String flowSourceID = flowSourceElem.getAttributeValue("id"); String flowDestID = flowDestElem.getAttributeValue("id"); YExternalNetElement flowSource = decomposition.getNetElement(flowSourceID); YExternalNetElement flowDest = decomposition.getNetElement(flowDestID); for (YExternalNetElement maybeImplicit : flowSource.getPostsetElements()) { if (((YCondition) maybeImplicit).isImplicit()) { Set<YExternalNetElement> oneTaskInThisList = maybeImplicit.getPostsetElements(); YTask taskAfterImplicit = (YTask) oneTaskInThisList.iterator().next(); if (taskAfterImplicit.equals(flowDest)) { List<YExternalNetElement> additionalRemoves = new ArrayList<YExternalNetElement>(); additionalRemoves.add(maybeImplicit); taskWithRemoveSet.addRemovesTokensFrom(additionalRemoves); } } } } } } } /*****************************************************************************/ private class Postset { // maps a String ID to a List of FlowStruct objects Map<String, List<FlowStruct>> _postsetMap = new HashMap<String, List<FlowStruct>>(); public void add(String id, List<FlowStruct> postsetStruct) { List<FlowStruct> oldRefIDs = _postsetMap.get(id); if (oldRefIDs == null) { oldRefIDs = new Vector<FlowStruct>(); } oldRefIDs.addAll(postsetStruct); _postsetMap.put(id, oldRefIDs); } public List<FlowStruct> getQPostset(String id) { return _postsetMap.get(id); } public List getPostset(List<String> ids) { List<FlowStruct> postset = new Vector<FlowStruct>(); for (String id : ids) { postset.addAll(_postsetMap.get(id)); } return postset; } public void addImplicitConditions() { List<String> elementIDs = new Vector<String>(_postsetMap.keySet()); for (String currentElementID : elementIDs) { YExternalNetElement currentNetElement = getNetElement(currentElementID); if (currentNetElement instanceof YTask) { for (FlowStruct flowStruct : _postsetMap.get(currentElementID)) { YExternalNetElement netElement = getNetElement(flowStruct._flowInto); // if one task flows directly to another task then we create an // anonymous condition and insert it between the two tasks. if (netElement instanceof YTask) { String anonID = makeAnonID(currentNetElement.getID(), netElement.getID()); YCondition condition = new YCondition(anonID, (YNet) _decomposition); condition.setImplicit(true); ((YNet) _decomposition).addNetElement(condition); String tempElemID = flowStruct._flowInto; flowStruct._flowInto = condition.getID(); List<FlowStruct> dom = new Vector<FlowStruct>(); dom.add(new FlowStruct(tempElemID, null, null)); _postsetMap.put(condition.getID(), dom); } } } } } private YExternalNetElement getNetElement(String id) { return ((YNet) _decomposition).getNetElement(id); } private String makeAnonID(String current, String next) { StringBuilder anonID = new StringBuilder(30); anonID.append("c{").append(current).append("_").append(next).append("}"); return anonID.toString(); } } /****************************************************************************/ private static class FlowStruct { String _flowInto; String _flowPredicate; Integer _predicateOrdering; boolean _isDefaultFlow; String _label; public FlowStruct(String flowInto, String flowPredicate, String label) { _flowInto = flowInto; _flowPredicate = flowPredicate; _label = label; } } }