/* * (c) Copyright 2010-2011 AgileBirds * * This file is part of OpenFlexo. * * OpenFlexo 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 3 of the License, or * (at your option) any later version. * * OpenFlexo 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 OpenFlexo. If not, see <http://www.gnu.org/licenses/>. * */ package org.openflexo.foundation.wkf.node; import java.util.Enumeration; import java.util.TreeMap; import java.util.Vector; import org.openflexo.foundation.validation.DeletionFixProposal; import org.openflexo.foundation.validation.ValidationError; import org.openflexo.foundation.validation.ValidationIssue; import org.openflexo.foundation.validation.ValidationRule; import org.openflexo.foundation.validation.ValidationWarning; import org.openflexo.foundation.wkf.ExecutableWorkflowElement; import org.openflexo.foundation.wkf.FlexoProcess; import org.openflexo.foundation.wkf.Role; import org.openflexo.foundation.wkf.WKFObject; import org.openflexo.foundation.wkf.dm.PreInserted; import org.openflexo.foundation.wkf.dm.PreRemoved; import org.openflexo.localization.FlexoLocalization; import org.openflexo.toolbox.ProgrammingLanguage; public abstract class FlexoNode extends PetriGraphNode implements ExecutableWorkflowElement { // ========================================================================== // ============================= Variables ================================== // ========================================================================== private NodeType _nodeType; private Vector<FlexoPreCondition> _preConditions; private boolean isWaiting; private boolean isSelfActivated; /** * Attached pre-condition: relevant only for begin nodes of Operation and Action level */ private FlexoPreCondition _attachedPreCondition; public FlexoNode(FlexoProcess process) { super(process); _nodeType = NodeType.NORMAL; _preConditions = new Vector<FlexoPreCondition>(); } @Override public void delete() { if (getAttachedPreCondition() != null) { FlexoPreCondition pre = getAttachedPreCondition(); pre.setAttachedBeginNode(null); pre.delete(); } deletePreConditions(); super.delete(); } /** * Build and return a vector of all the objects that will be deleted during this deletion * * @param aVector * of DeletableObject */ @Override public Vector<WKFObject> getAllEmbeddedDeleted() { Vector<WKFObject> returned = getAllEmbeddedWKFObjects(); returned.addAll(getPreConditions()); if (_attachedPreCondition != null) { returned.addAll(_attachedPreCondition.getAllEmbeddedDeleted()); } return returned; } private void deletePreConditions() { Enumeration<FlexoPreCondition> en = new Vector<FlexoPreCondition>(_preConditions).elements(); while (en.hasMoreElements()) { en.nextElement().delete(); } } public boolean isSelfActivated() { return isSelfActivated; } public void setIsSelfActivated(boolean is_SelfActivated) { this.isSelfActivated = is_SelfActivated; } public boolean isSelfExecutableNode() { return this instanceof SelfExecutableNode; } public boolean isWaiting() { return isWaiting; } public void setIsWaiting(boolean is_Waiting) { this.isWaiting = is_Waiting; } /** * Sets attached pre-condition: relevant only for begin nodes of Operation and Action level * * @param condition */ public void setAttachedPreCondition(FlexoPreCondition preCondition) { _attachedPreCondition = preCondition; } /** * Returns attached pre-condition: relevant only for begin nodes of Operation and Action level */ public FlexoPreCondition getAttachedPreCondition() { return _attachedPreCondition; } // ========================================================================== // ============================= Pre-conditions ============================= // ========================================================================== /** * The insertion or removal of preConditions has to be done with addToPreConditions or removeFromPreConditions methods. * * @return Vector of FlexoPreCondition */ public Vector<FlexoPreCondition> getPreConditions() { return _preConditions; } public void setPreConditions(Vector<FlexoPreCondition> aVector) { _preConditions = aVector; } public void addToPreConditions(FlexoPreCondition pre) { if (!_preConditions.contains(pre)) { _preConditions.add(pre); pre.setAttachedNode(this); setChanged(); notifyObservers(new PreInserted(pre)); } } public void removeFromPreCondition(FlexoPreCondition pre) { if (_preConditions.contains(pre)) { _preConditions.remove(pre); pre.setAttachedNode(null); setChanged(); notifyObservers(new PreRemoved(pre)); } } /** * This attribute isn't supposed to be changed after node creation. * * @return the NodeType */ public NodeType getNodeType() { return _nodeType; } /** * This attribute isn't supposed to be changed after node creation. * * @return the NodeType */ public void setNodeType(NodeType aType) { _nodeType = aType; } public boolean isBeginOrEndNode() { return isBeginNode() || isEndNode(); } public boolean isBeginNode() { return getNodeType() == NodeType.BEGIN; } public boolean isEndNode() { return getNodeType() == NodeType.END; } public boolean isNormalNode() { return getNodeType() == NodeType.NORMAL; } @Override public void getBestRole(Vector<Node> visited, TreeMap<Integer, Vector<Role>> roles, int depth) { if (visited.contains(this)) { return; } visited.add(this); for (FlexoPreCondition pre : getPreConditions()) { getBestRole(pre, visited, roles, depth); } super.getBestRole(visited, roles, depth); } @Override public boolean isAccessible() { if (isBeginNode()) { return true; } int accessNumber = getIncomingPostConditions().size(); for (FlexoPreCondition pre : getPreConditions()) { accessNumber += pre.getIncomingPostConditions().size(); } return accessNumber > 0 || super.isAccessible(); } public abstract boolean isInteractive(); public static String DEFAULT_NORMAL_FLEXO_NODE_NAME() { return FlexoLocalization.localizedForKey("noname"); } public static String DEFAULT_BEGIN_FLEXO_NODE_NAME() { return FlexoLocalization.localizedForKey("begin_node"); } public static String DEFAULT_END_FLEXO_NODE_NAME() { return FlexoLocalization.localizedForKey("end_node"); } @Override public String getDefaultName() { if (isBeginNode()) { return DEFAULT_BEGIN_FLEXO_NODE_NAME(); } else if (isEndNode()) { return DEFAULT_END_FLEXO_NODE_NAME(); } else { return DEFAULT_NORMAL_FLEXO_NODE_NAME(); } } // ========================================================= // ============= Control graph management ================== // ========================================================= private static ControlGraphFactory<FlexoNode> _activationComputingFactory; private static ControlGraphFactory<FlexoNode> _desactivationComputingFactory; public static void setActivationComputingFactory(ControlGraphFactory<FlexoNode> factory) { _activationComputingFactory = factory; } public static void setDesactivationComputingFactory(ControlGraphFactory<FlexoNode> factory) { _desactivationComputingFactory = factory; } public WorkflowControlGraph<FlexoNode> getActivation() { if (_activationComputingFactory != null) { return _activationComputingFactory.getControlGraph(this); } return null; } public WorkflowControlGraph<FlexoNode> getDesactivation() { if (_desactivationComputingFactory != null) { return _desactivationComputingFactory.getControlGraph(this); } return null; } @Override public void setProgrammingLanguageForControlGraphComputation(ProgrammingLanguage language) { if (getActivation() != null) { getActivation().setProgrammingLanguage(language); } if (getDesactivation() != null) { getDesactivation().setProgrammingLanguage(language); } } @Override public void setInterproceduralForControlGraphComputation(boolean interprocedural) { if (getActivation() != null) { getActivation().setInterprocedural(interprocedural); } if (getDesactivation() != null) { getDesactivation().setInterprocedural(interprocedural); } } @Override public String getExecutableElementName() { return FlexoLocalization.localizedForKeyWithParams("node_($0)", getName()); } public static class InteractiveNodeCannotBePutInsideExecutionPetriGraph extends ValidationRule<InteractiveNodeCannotBePutInsideExecutionPetriGraph, FlexoNode> { public InteractiveNodeCannotBePutInsideExecutionPetriGraph() { super(FlexoNode.class, "interactive_nodes_cannot_be_found_inside_an_execution_petri_graph"); } @Override public ValidationIssue<InteractiveNodeCannotBePutInsideExecutionPetriGraph, FlexoNode> applyValidation(FlexoNode node) { if (node.isInteractive() && node.isEmbeddedInSelfExecutableNode()) { return new ValidationError<InteractiveNodeCannotBePutInsideExecutionPetriGraph, FlexoNode>(this, node, "interactive_nodes_cannot_be_found_inside_an_execution_petri_graph", new DeletionFixProposal<InteractiveNodeCannotBePutInsideExecutionPetriGraph, FlexoNode>("delete_this_node")); } return null; } } public static class EndNodeCannotHaveMultipleEdges extends ValidationRule<EndNodeCannotHaveMultipleEdges, FlexoNode> { public EndNodeCannotHaveMultipleEdges() { super(FlexoNode.class, "end_node_at_this_level_cannot_have_multiple_outgoing_edges"); } @Override public ValidationIssue<EndNodeCannotHaveMultipleEdges, FlexoNode> applyValidation(FlexoNode node) { if (node instanceof ActionNode && node.isEndNode() && node.getOutgoingPostConditions().size() > 1) { return new ValidationWarning<EndNodeCannotHaveMultipleEdges, FlexoNode>(this, node, "end_node_at_this_level_cannot_have_multiple_outgoing_edges"); } return null; } } }