/*
* (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;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.openflexo.foundation.utils.FlexoIndexManager;
import org.openflexo.foundation.validation.FixProposal;
import org.openflexo.foundation.validation.ParameteredFixProposal;
import org.openflexo.foundation.validation.ValidationError;
import org.openflexo.foundation.validation.ValidationIssue;
import org.openflexo.foundation.validation.ValidationRule;
import org.openflexo.foundation.wkf.dm.ArtefactInserted;
import org.openflexo.foundation.wkf.dm.ArtefactRemoved;
import org.openflexo.foundation.wkf.dm.GroupInserted;
import org.openflexo.foundation.wkf.dm.GroupRemoved;
import org.openflexo.foundation.wkf.dm.NodeInserted;
import org.openflexo.foundation.wkf.dm.NodeRemoved;
import org.openflexo.foundation.wkf.dm.PetriGraphHasBeenOpened;
import org.openflexo.foundation.wkf.edge.InvalidEdgeException;
import org.openflexo.foundation.wkf.edge.TokenEdge;
import org.openflexo.foundation.wkf.node.AbstractActivityNode;
import org.openflexo.foundation.wkf.node.AbstractNode;
import org.openflexo.foundation.wkf.node.EventNode;
import org.openflexo.foundation.wkf.node.FatherNode;
import org.openflexo.foundation.wkf.node.FlexoNode;
import org.openflexo.foundation.wkf.node.FlexoPreCondition;
import org.openflexo.foundation.wkf.node.LOOPOperator;
import org.openflexo.foundation.wkf.node.Node;
import org.openflexo.foundation.wkf.node.OperationNode;
import org.openflexo.foundation.wkf.node.OperatorNode;
import org.openflexo.foundation.wkf.node.PetriGraphNode;
import org.openflexo.foundation.wkf.node.SelfExecutableNode;
import org.openflexo.localization.FlexoLocalization;
import org.openflexo.toolbox.ToolBox;
/**
* Please comment this class
*
* @author sguerin
*
*/
public abstract class FlexoPetriGraph extends WKFObject implements LevelledObject {
private static final Logger logger = Logger.getLogger(FlexoPetriGraph.class.getPackage().getName());
/**
* Stores all the node of this Petri Graph
*/
protected Vector<PetriGraphNode> _nodes;
protected WKFObject _container;
protected String containerContext;
private Vector<WKFArtefact> artefacts;
private Vector<WKFGroup> groups;
// ==========================================================================
// ============================= Constructor
// ================================
// ==========================================================================
/**
* Default constructor
*/
public FlexoPetriGraph(FlexoProcess process) {
super(process);
_nodes = new Vector<PetriGraphNode>();
artefacts = new Vector<WKFArtefact>();
groups = new Vector<WKFGroup>();
}
public static FlexoPetriGraph createPetriGraph(FlexoLevel level) {
FlexoPetriGraph returned = null;
if (level == FlexoLevel.ACTIVITY) {
returned = new ActivityPetriGraph((FlexoProcess) null);
} else if (level == FlexoLevel.OPERATION) {
returned = new OperationPetriGraph((FlexoProcess) null);
} else if (level == FlexoLevel.ACTION) {
returned = new ActionPetriGraph((FlexoProcess) null);
}
return returned;
}
public void setContainer(WKFObject container, String context) {
if (logger.isLoggable(Level.FINE)) {
logger.fine(" setContainer() for " + this.getClass().getName() + " with " + container.getClass().getName() + " with "
+ getNodes().size() + " nodes");
}
_container = container;
for (Enumeration<PetriGraphNode> e = getNodes().elements(); e.hasMoreElements();) {
PetriGraphNode node = e.nextElement();
node.setParentPetriGraph(this);
}
}
public TokenEdge createTokenEdge(PetriGraphNode begin, PetriGraphNode end) {
try {
Node pc = null;
if (end instanceof FlexoNode) {
FlexoNode endNode = (FlexoNode) end;
if (endNode.getPreConditions().size() == 0) {
if (endNode instanceof FatherNode) {
if (!((FatherNode) endNode).hasContainedPetriGraph()) {
if (endNode instanceof AbstractActivityNode) {
new OperationPetriGraph((AbstractActivityNode) endNode);
} else if (endNode instanceof OperationNode) {
new ActionPetriGraph((OperationNode) endNode);
} else if (logger.isLoggable(Level.WARNING)) {
logger.warning("Unknown type of FatherNode " + end.getClass().getName());
}
}
if (((FatherNode) end).hasContainedPetriGraph()) {
Vector<FlexoNode> v = ((FatherNode) end).getContainedPetriGraph().getAllBeginNodes();
FlexoNode attachedBeginNode;
if (v.size() == 0) {
attachedBeginNode = ((FatherNode) end).getContainedPetriGraph().createBeginNode(null);
} else {
attachedBeginNode = v.firstElement();
}
pc = new FlexoPreCondition(endNode, attachedBeginNode);
} else {
pc = new FlexoPreCondition(endNode);
}
} else {
pc = new FlexoPreCondition(endNode);
}
} else {
pc = endNode.getPreConditions().firstElement();
}
} else {
pc = end;
}
return new TokenEdge(begin, pc);
} catch (InvalidEdgeException e) {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Could not create edge between begin and end node");
}
return null;
}
}
public abstract FlexoNode createBeginNode(String context);
public abstract FlexoNode createEndNode(String context);
public WKFObject getContainer() {
return _container;
}
@Override
public String getFullyQualifiedName() {
if (getContainer() != null) {
return getContainer().getFullyQualifiedName() + ".PETRI_GRAPH";
}
return "???";
}
// ==========================================================================
// ========================== Embedding implementation =====================
// ==========================================================================
public boolean isRootPetriGraph() {
return getProcess() != null && getProcess().getActivityPetriGraph() == this;
}
@Override
public boolean isContainedIn(WKFObject obj) {
return getContainer().isContainedIn(obj);
}
@Override
public boolean contains(WKFObject obj) {
if (obj instanceof PetriGraphNode) {
for (Enumeration<PetriGraphNode> en = _nodes.elements(); en.hasMoreElements();) {
PetriGraphNode item = en.nextElement();
if (item == obj) {
return true;
}
}
return false;
}
return super.contains(obj);
}
public Vector<PetriGraphNode> getNodes() {
return _nodes;
}
public Enumeration<PetriGraphNode> getSortedNodes() {
disableObserving();
PetriGraphNode[] o = FlexoIndexManager.sortArray(getNodes().toArray(new PetriGraphNode[0]));
enableObserving();
return ToolBox.getEnumeration(o);
}
/**
* Returns a sorted vector of all nodes of class <code>klass</code>, including the ones embedded by SelfExecutableNode and LOOPOperator,
* sorted according to the order defined in the petrigraphs. Whenever a node (a SelfExecutableNode or a LOOPOperator) embeds nodes, if
* the node matches the <code>klass</code> parameter, it is first inserted and then it adds all the matching embedded nodes, if
* relevant).
*
* @param <T>
* the type of the typed vector you want
* @param klass
* a class that extends PetriGraphNode
* @return a sorted vector of all nodes of class <code>klass</code>, including the ones embedded by SelfExecutableNode and LOOPOperator.
*/
@SuppressWarnings("unchecked")
public <T extends PetriGraphNode> Vector<T> getAllEmbeddedSortedNodesOfClass(Class<T> klass) {
disableObserving();
Vector<T> vector = new Vector<T>();
Enumeration<PetriGraphNode> en = getSortedNodes();
while (en.hasMoreElements()) {
PetriGraphNode node = en.nextElement();
if (klass.isAssignableFrom(node.getClass())) {
vector.add((T) node);
}
if (node instanceof SelfExecutableNode && ((SelfExecutableNode) node).getExecutionPetriGraph() != null) {
vector.addAll(((SelfExecutableNode) node).getExecutionPetriGraph().getAllEmbeddedSortedNodesOfClass(klass));
} else if (node instanceof LOOPOperator && ((LOOPOperator) node).getExecutionPetriGraph() != null) {
vector.addAll(((LOOPOperator) node).getExecutionPetriGraph().getAllEmbeddedSortedNodesOfClass(klass));
}
}
return vector;
}
public void setNodes(Vector<PetriGraphNode> someNodes) {
_nodes.removeAllElements();
for (Enumeration<PetriGraphNode> en = someNodes.elements(); en.hasMoreElements();) {
PetriGraphNode item = en.nextElement();
addToNodes(item);
}
}
public void addToNodes(PetriGraphNode aNode) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("insertNode() with " + aNode + " of " + aNode.getClass().getName());
}
if (getLevel() != aNode.getLevel() && !(aNode instanceof OperatorNode) && !(aNode instanceof EventNode)) {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Invalid level: cannot insert node");
}
} else {
if (!_nodes.contains(aNode)) {
_nodes.add(aNode);
aNode.setParentPetriGraph(this);
if (!isDeserializing() && !isCreatedByCloning()) {
aNode.setIndexValue(aNode.getCollection().length);
FlexoIndexManager.reIndexObjectOfArray(aNode.getCollection());
}
setChanged();
notifyObservers(new NodeInserted(aNode, this, getContainer()));
if (getProcess() != null) {
getProcess().clearCachedObjects();
// return true;
}
}
}
// return false;
}
public boolean removeFromNodes(PetriGraphNode node) {
if (_nodes.contains(node)) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Remove node as observer of PG");
}
for (WKFGroup group : getGroups()) {
if (group.contains(node)) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Remove node " + node + " from group " + group);
}
group.removeFromNodes(node);
group.notifyGroupUpdated();
}
}
_nodes.remove(node);
node.setParentPetriGraph(null);
setChanged();
notifyObservers(new NodeRemoved(node));
FlexoIndexManager.reIndexObjectOfArray(getNodes().toArray(new PetriGraphNode[0]));
if (getProcess() != null) {
getProcess().clearCachedObjects();
}
return true;
}
return false;
}
/**
* Return a vector of all BEGIN_NODE of this Petri Graph
*
* @return Vector of FlexoNode
*/
public Vector<FlexoNode> getAllBeginNodes() {
// TODO: optimize me later !!!
Vector<FlexoNode> returned = new Vector<FlexoNode>();
Enumeration<PetriGraphNode> en = _nodes.elements();
while (en.hasMoreElements()) {
PetriGraphNode current = en.nextElement();
if (current instanceof FlexoNode) {
if (((FlexoNode) current).isBeginNode()) {
returned.add((FlexoNode) current);
}
}
}
return returned;
}
/**
* Returns all nodes of this petri graph that are instances or sub-class instances of the class <code>klass</code>
*
* @param <T>
* a typed parameter that extends PetriGraphNode so that the returned vector you received is properly typed
* @param klass
* @return
*/
@SuppressWarnings("unchecked")
public final <T extends PetriGraphNode> Vector<T> getAllNodesOfClass(Class<T> klass) {
Vector<T> returned = new Vector<T>();
Enumeration<PetriGraphNode> en = _nodes.elements();
while (en.hasMoreElements()) {
PetriGraphNode current = en.nextElement();
if (klass.isAssignableFrom(current.getClass())) {
returned.add((T) current);
}
}
return returned;
}
/**
* Returns all nodes of this petri graph that are instances or sub-class instances of the class <code>klass</code>
*
* @param <T>
* a typed parameter that extends PetriGraphNode so that the returned vector you received is properly typed
* @param klass
* @return
*/
@SuppressWarnings("unchecked")
public final <T> Vector<T> getAllNodesOfInterface(Class<T> klass) {
Vector<T> returned = new Vector<T>();
Enumeration<PetriGraphNode> en = _nodes.elements();
while (en.hasMoreElements()) {
PetriGraphNode current = en.nextElement();
if (klass.isAssignableFrom(current.getClass())) {
returned.add((T) current);
}
}
return returned;
}
/**
* Returns all embedded nodes of the same level of this petri graph that are instances or sub-class instances of the class
* <code>klass</code>
*
* @param <T>
* a typed parameter that extends PetriGraphNode so that the returned vector you received is properly typed
* @param klass
* @return
*/
@SuppressWarnings("unchecked")
public final <T extends AbstractNode> Vector<T> getAllEmbeddedNodesOfClassOfSameLevel(Class<T> klass) {
Vector<T> v = new Vector<T>();
Enumeration<PetriGraphNode> en = _nodes.elements();
while (en.hasMoreElements()) {
PetriGraphNode node = en.nextElement();
if (klass.isAssignableFrom(node.getClass())) {
v.add((T) node);
}
if (node instanceof FatherNode && ((FatherNode) node).getContainedPetriGraph() != null
&& ((FatherNode) node).getContainedPetriGraph().getLevel() == getLevel()) {
v.addAll(((FatherNode) node).getContainedPetriGraph().getAllEmbeddedNodesOfClassOfSameLevel(klass));
} else if (node instanceof SelfExecutableNode && ((SelfExecutableNode) node).getExecutionPetriGraph() != null) {// These are
// always of
// this level
v.addAll(((SelfExecutableNode) node).getExecutionPetriGraph().getAllEmbeddedNodesOfClassOfSameLevel(klass));
} else if (node instanceof LOOPOperator && ((LOOPOperator) node).getExecutionPetriGraph() != null) {// These are always of this
// level
v.addAll(((LOOPOperator) node).getExecutionPetriGraph().getAllEmbeddedNodesOfClassOfSameLevel(klass));
}
}
return v;
}
/**
* Returns a vector of all operator nodes that are embedded by this petri graph. This will drill down into all nodes embedded by this
* petri graph
*
* @return all operator nodes embedded in this petri graph
*/
public final Vector<OperatorNode> getAllEmbeddedOperators() {
Vector<OperatorNode> v = new Vector<OperatorNode>();
Enumeration<PetriGraphNode> en = _nodes.elements();
while (en.hasMoreElements()) {
AbstractNode node = en.nextElement();
if (node instanceof OperatorNode) {
v.add((OperatorNode) node);
}
if (node instanceof FatherNode && ((FatherNode) node).getContainedPetriGraph() != null) {
v.addAll(((FatherNode) node).getContainedPetriGraph().getAllEmbeddedOperators());
} else if (node instanceof SelfExecutableNode && ((SelfExecutableNode) node).getExecutionPetriGraph() != null) {
v.addAll(((SelfExecutableNode) node).getExecutionPetriGraph().getAllEmbeddedOperators());
} else if (node instanceof LOOPOperator && ((LOOPOperator) node).getExecutionPetriGraph() != null) {
v.addAll(((LOOPOperator) node).getExecutionPetriGraph().getAllEmbeddedOperators());
}
}
return v;
}
public final Vector<OperatorNode> getAllEmbeddedOperatorsOfSameLevel() {
Vector<OperatorNode> v = new Vector<OperatorNode>();
Enumeration<PetriGraphNode> en = _nodes.elements();
while (en.hasMoreElements()) {
PetriGraphNode node = en.nextElement();
if (node instanceof OperatorNode) {
v.add((OperatorNode) node);
}
if (node instanceof FatherNode && ((FatherNode) node).getContainedPetriGraph() != null
&& ((FatherNode) node).getContainedPetriGraph().getLevel() == getLevel()) {
v.addAll(((FatherNode) node).getContainedPetriGraph().getAllEmbeddedOperatorsOfSameLevel());
} else if (node instanceof SelfExecutableNode && ((SelfExecutableNode) node).getExecutionPetriGraph() != null) {// These are
// always of
// this level
v.addAll(((SelfExecutableNode) node).getExecutionPetriGraph().getAllEmbeddedOperatorsOfSameLevel());
} else if (node instanceof LOOPOperator && ((LOOPOperator) node).getExecutionPetriGraph() != null) {// These are always of this
// level
v.addAll(((LOOPOperator) node).getExecutionPetriGraph().getAllEmbeddedOperatorsOfSameLevel());
}
}
return v;
}
/**
* Returns all nodes embedded by this petri graph that are of the class <code>klass</code>.
*
* @param <T>
* @param klass
* @return all nodes embedded by this petri graph that are of the class <code>klass</code>.
*/
@SuppressWarnings("unchecked")
public final <T extends AbstractNode> Vector<T> getAllEmbeddedNodesOfClass(Class<T> klass) {
Vector<T> v = new Vector<T>();
Enumeration<PetriGraphNode> en = _nodes.elements();
while (en.hasMoreElements()) {
PetriGraphNode node = en.nextElement();
if (klass.isAssignableFrom(node.getClass())) {
v.add((T) node);
}
if (node instanceof FatherNode && ((FatherNode) node).getContainedPetriGraph() != null) {
v.addAll(((FatherNode) node).getContainedPetriGraph().getAllEmbeddedNodesOfClass(klass));
}
if (node instanceof SelfExecutableNode && ((SelfExecutableNode) node).getExecutionPetriGraph() != null) {
v.addAll(((SelfExecutableNode) node).getExecutionPetriGraph().getAllEmbeddedNodesOfClass(klass));
} else if (node instanceof LOOPOperator && ((LOOPOperator) node).getExecutionPetriGraph() != null) {
v.addAll(((LOOPOperator) node).getExecutionPetriGraph().getAllEmbeddedNodesOfClass(klass));
}
}
return v;
}
/**
* Return a vector of all END_NODE of this Petri Graph
*
* @return Vector of FlexoNode
*/
public Vector<FlexoNode> getAllEndNodes() {
// TODO: optimize me later !!!
Vector<FlexoNode> returned = new Vector<FlexoNode>();
Enumeration<PetriGraphNode> en = _nodes.elements();
while (en.hasMoreElements()) {
PetriGraphNode current = en.nextElement();
if (current instanceof FlexoNode) {
if (((FlexoNode) current).isEndNode()) {
returned.add((FlexoNode) current);
}
}
}
return returned;
}
public boolean hasOtherNodesThanBeginEndNodes() {
for (PetriGraphNode node : getNodes()) {
if (!(node instanceof FlexoNode)) {
return true;
}
if (!((FlexoNode) node).isBeginOrEndNode()) {
return true;
}
}
return artefacts.size() > 0;
}
public Vector<AbstractNode> getAllEmbeddedAbstractNodes() {
return getAllEmbeddedNodesOfClass(AbstractNode.class);
}
/**
* Return a vector of all Operator nodes of this Petri Graph
*
* @return Vector of OperatorNode
*/
public final Vector<OperatorNode> getAllOperatorNodes() {
return getAllNodesOfClass(OperatorNode.class);
}
/**
* Return a vector of all Operator nodes of this Petri Graph
*
* @return Vector of OperatorNode
*/
public Vector<SelfExecutableNode> getAllSelfExecutableNodes() {
return getAllNodesOfInterface(SelfExecutableNode.class);
}
/**
* Return a vector of all LOOPOperator nodes of this Petri Graph
*
* @return Vector of LOOPOperator
*/
public Vector<LOOPOperator> getAllLoopOperators() {
return getAllNodesOfClass(LOOPOperator.class);
}
/**
* Return a vector of all Event nodes of this Petri Graph
*
* @return Vector of EventNode
*/
public Vector<EventNode> getAllEventNodes() {
return getAllNodesOfClass(EventNode.class);
}
/**
* Return a vector of all BEGIN_NODE of this Petri Graph
*
* @return Vector of FlexoNode
*/
public Vector<EventNode> getAllStartNodes() {
Vector<EventNode> returned = getAllNodesOfClass(EventNode.class);
Iterator<EventNode> i = returned.iterator();
while (i.hasNext()) {
EventNode current = i.next();
if (!current.isStart()) {
i.remove();
}
}
return returned;
}
/**
* Returns all artefacts embedded by this petri graph
*
* @return all artefacts embedded by this petri graph.
*/
public final Vector<WKFArtefact> getAllEmbeddedArtefacts() {
Vector<WKFArtefact> v = new Vector<WKFArtefact>();
v.addAll(artefacts);
Enumeration<PetriGraphNode> en = _nodes.elements();
while (en.hasMoreElements()) {
PetriGraphNode node = en.nextElement();
if (node instanceof FatherNode && ((FatherNode) node).getContainedPetriGraph() != null) {
v.addAll(((FatherNode) node).getContainedPetriGraph().getAllEmbeddedArtefacts());
}
if (node instanceof SelfExecutableNode && ((SelfExecutableNode) node).getExecutionPetriGraph() != null) {
v.addAll(((SelfExecutableNode) node).getExecutionPetriGraph().getAllEmbeddedArtefacts());
} else if (node instanceof LOOPOperator && ((LOOPOperator) node).getExecutionPetriGraph() != null) {
v.addAll(((LOOPOperator) node).getExecutionPetriGraph().getAllEmbeddedArtefacts());
}
}
return v;
}
public OperatorNode getOperatorNodeNamed(String name) {
if (name == null) {
return null;
}
for (OperatorNode node : getAllOperatorNodes()) {
if (name.equals(node.getName())) {
return node;
}
}
return null;
}
public abstract FlexoNode createNewBeginNode();
public abstract FlexoNode createNewBeginNode(String nodeName);
public abstract FlexoNode createNewEndNode();
public abstract FlexoNode createNewEndNode(String nodeName);
// ==========================================================================
// ============================= Accessors
// ==================================
// ==========================================================================
@Override
public void setIsVisible(boolean b) {
if (b != getIsVisible()) {
if (!b) {
Enumeration<PetriGraphNode> en = getNodes().elements();
PetriGraphNode item = null;
while (en.hasMoreElements()) {
item = en.nextElement();
if (item instanceof FatherNode) {
if (((FatherNode) item).getContainedPetriGraph() != null) {
((FatherNode) item).getContainedPetriGraph().setIsVisible(b);
}
}
}
}
super.setIsVisible(b);
if (b) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Make PG visible");
}
setChanged();
notifyObservers(new PetriGraphHasBeenOpened(this));
}
}
}
/**
* Returns the level of this FlexoPetriGraph
*
* @see org.openflexo.foundation.wkf.LevelledObject#getLevel()
*/
@Override
public abstract FlexoLevel getLevel();
// ==========================================================================
// ================================= Delete ===============================
// ==========================================================================
@Override
public final void delete() {
Enumeration<AbstractNode> en = new Vector<AbstractNode>(_nodes).elements();
while (en.hasMoreElements()) {
en.nextElement().delete();
}
Enumeration<WKFArtefact> en1 = new Vector<WKFArtefact>(artefacts).elements();
while (en1.hasMoreElements()) {
en1.nextElement().delete();
}
super.delete();
deleteObservers();
_container = null;
}
/**
* Build and return a vector of all the objects that will be deleted during process deletion
*
* @param aVector
* of DeletableObject
*/
@Override
public Vector<WKFObject> getAllEmbeddedDeleted() {
return getAllEmbeddedWKFObjects();
}
/**
* Return a Vector of all embedded WKFObjects
*
* @return a Vector of WKFObject instances
*/
@Override
public Vector<WKFObject> getAllEmbeddedWKFObjects() {
Vector<WKFObject> returned = new Vector<WKFObject>();
returned.add(this);
Enumeration<AbstractNode> en = new Vector<AbstractNode>(_nodes).elements();
while (en.hasMoreElements()) {
returned.addAll(en.nextElement().getAllEmbeddedDeleted());
}
for (WKFGroup group : getGroups()) {
returned.addAll(group.getAllEmbeddedWKFObjects());
}
for (WKFArtefact artefact : getArtefacts()) {
returned.addAll(artefact.getAllEmbeddedWKFObjects());
}
return returned;
}
public Vector<FlexoNode> getUnboundBeginNodes() {
Vector<FlexoNode> allBeginNodes = getAllBeginNodes();
Vector<FlexoNode> returned = new Vector<FlexoNode>();
for (FlexoNode n : allBeginNodes) {
if (n.getAttachedPreCondition() == null) {
returned.add(n);
}
}
return returned;
}
public Vector<FlexoNode> getBoundBeginNodes() {
Vector<FlexoNode> allBeginNodes = getAllBeginNodes();
Vector<FlexoNode> returned = new Vector<FlexoNode>();
for (FlexoNode n : allBeginNodes) {
if (n.getAttachedPreCondition() != null) {
returned.add(n);
}
}
return returned;
}
public Vector<WKFArtefact> getArtefacts() {
return artefacts;
}
public void setArtefacts(Vector<WKFArtefact> artefacts) {
this.artefacts = artefacts;
}
public void addToArtefacts(WKFArtefact annotation) {
annotation.setParentPetriGraph(this);
artefacts.add(annotation);
setChanged();
notifyObservers(new ArtefactInserted(annotation));
if (getProcess() != null) {
getProcess().clearCachedObjects();
}
}
public void removeFromArtefacts(WKFArtefact annotation) {
annotation.setParentPetriGraph(null);
artefacts.remove(annotation);
setChanged();
notifyObservers(new ArtefactRemoved(annotation));
if (getProcess() != null) {
getProcess().clearCachedObjects();
}
}
public Vector<WKFGroup> getGroups() {
return groups;
}
public void setGroups(Vector<WKFGroup> groups) {
this.groups = groups;
}
public void addToGroups(WKFGroup group) {
group.setParentPetriGraph(this);
groups.add(group);
setChanged();
notifyObservers(new GroupInserted(group));
}
public void removeFromGroups(WKFGroup group) {
group.setParentPetriGraph(null);
groups.remove(group);
setChanged();
notifyObservers(new GroupRemoved(group));
}
public void notifyNodeUngroup(WKFGroup group, Vector<PetriGraphNode> nodesThatWereInGroup) {
setChanged();
notifyObservers(new GroupRemoved(group, nodesThatWereInGroup));
}
public boolean acceptsObject(WKFObject object) {
if (object instanceof LevelledObject) {
return getLevel() == ((LevelledObject) object).getLevel() || ((LevelledObject) object).getLevel() == null;
}
return false;
}
// ==========================================================================
// ============================= Validation
// =================================
// ==========================================================================
public static class PetriGraphMustHaveAtLeastOneBeginNode extends
ValidationRule<PetriGraphMustHaveAtLeastOneBeginNode, FlexoPetriGraph> {
public PetriGraphMustHaveAtLeastOneBeginNode() {
super(FlexoPetriGraph.class, "petri_graph_must_have_at_least_one_begin_node");
}
@Override
public ValidationIssue<PetriGraphMustHaveAtLeastOneBeginNode, FlexoPetriGraph> applyValidation(FlexoPetriGraph pg) {
if (pg.getAllBeginNodes().size() == 0) {
ValidationError<PetriGraphMustHaveAtLeastOneBeginNode, FlexoPetriGraph> error = new ValidationError<PetriGraphMustHaveAtLeastOneBeginNode, FlexoPetriGraph>(
this, pg, "petri_graph_must_have_at_least_one_begin_node");
String newBeginNodeName = "";
if (pg instanceof ActivityPetriGraph) {
newBeginNodeName = pg.getProcess().findNextInitialName(FlexoLocalization.localizedForKey("begin_node"));
} else if (pg instanceof OperationPetriGraph) {
newBeginNodeName = pg.getProcess().findNextInitialName(FlexoLocalization.localizedForKey("begin_node"),
((OperationPetriGraph) pg).getContainer());
} else if (pg instanceof ActionPetriGraph) {
newBeginNodeName = pg.getProcess().findNextInitialName(FlexoLocalization.localizedForKey("begin_node"),
((ActionPetriGraph) pg).getContainer());
}
error.addToFixProposals(new CreateNewBeginNode(newBeginNodeName));
return error;
}
return null;
}
public class CreateNewBeginNode extends ParameteredFixProposal<PetriGraphMustHaveAtLeastOneBeginNode, FlexoPetriGraph> {
public CreateNewBeginNode(String newBeginNodeName) {
super("create_new_begin_node", "newBeginNodeName", "enter_a_name_for_the_new_begin_node", newBeginNodeName);
}
@Override
protected void fixAction() {
String newBeginNodeName = (String) getValueForParameter("newBeginNodeName");
FlexoPetriGraph pg = getObject();
if (pg instanceof ActivityPetriGraph) {
((ActivityPetriGraph) pg).createNewBeginNode(newBeginNodeName);
} else if (pg instanceof OperationPetriGraph) {
((OperationPetriGraph) pg).createNewBeginNode(newBeginNodeName);
} else if (pg instanceof ActionPetriGraph) {
((ActionPetriGraph) pg).createNewBeginNode(newBeginNodeName);
}
}
}
}
public static class ExecutionPetriGraphMustHaveExactelyOneBeginNode extends
ValidationRule<ExecutionPetriGraphMustHaveExactelyOneBeginNode, FlexoPetriGraph> {
public ExecutionPetriGraphMustHaveExactelyOneBeginNode() {
super(FlexoPetriGraph.class, "execution_petri_graph_must_have_exactely_one_begin_node");
}
@Override
public ValidationIssue<ExecutionPetriGraphMustHaveExactelyOneBeginNode, FlexoPetriGraph> applyValidation(FlexoPetriGraph pg) {
if (pg.getContainer() instanceof SelfExecutableNode || pg.getContainer() instanceof LOOPOperator) {
if (pg.getAllBeginNodes().size() == 0) {
ValidationError<ExecutionPetriGraphMustHaveExactelyOneBeginNode, FlexoPetriGraph> error = new ValidationError<ExecutionPetriGraphMustHaveExactelyOneBeginNode, FlexoPetriGraph>(
this, pg, "execution_petri_graph_must_have_exactely_one_begin_node");
error.addToFixProposals(new CreateBeginNode(pg));
return error;
} else if (pg.getAllBeginNodes().size() > 1) {
ValidationError<ExecutionPetriGraphMustHaveExactelyOneBeginNode, FlexoPetriGraph> error = new ValidationError<ExecutionPetriGraphMustHaveExactelyOneBeginNode, FlexoPetriGraph>(
this, pg, "execution_petri_graph_must_have_exactely_one_begin_node");
for (PetriGraphNode node : pg.getAllBeginNodes()) {
error.addToFixProposals(new ChooseBeginNode(pg, node));
}
return error;
}
}
return null;
}
public static class ChooseBeginNode extends FixProposal<ExecutionPetriGraphMustHaveExactelyOneBeginNode, FlexoPetriGraph> {
private PetriGraphNode node;
public ChooseBeginNode(FlexoPetriGraph pg, PetriGraphNode nodeThatWillBeKept) {
super("choose_node_($node.name)_and_remove_others");
node = nodeThatWillBeKept;
}
public PetriGraphNode getNode() {
return node;
}
@Override
protected void fixAction() {
Vector<PetriGraphNode> allNodes = new Vector<PetriGraphNode>(getObject().getAllBeginNodes());
for (PetriGraphNode n : allNodes) {
if (n != node) {
n.delete();
}
}
}
}
public static class CreateBeginNode extends FixProposal<ExecutionPetriGraphMustHaveExactelyOneBeginNode, FlexoPetriGraph> {
public CreateBeginNode(FlexoPetriGraph pg) {
super("create_new_begin_node");
}
@Override
protected void fixAction() {
// TODO: use FlexoAction
getObject().createNewBeginNode();
}
}
}
public static class ExecutionPetriGraphMustHaveExactelyOneEndNode extends
ValidationRule<ExecutionPetriGraphMustHaveExactelyOneEndNode, FlexoPetriGraph> {
public ExecutionPetriGraphMustHaveExactelyOneEndNode() {
super(FlexoPetriGraph.class, "execution_petri_graph_must_have_exactely_one_end_node");
}
@Override
public ValidationIssue<ExecutionPetriGraphMustHaveExactelyOneEndNode, FlexoPetriGraph> applyValidation(FlexoPetriGraph pg) {
if (pg.getContainer() instanceof SelfExecutableNode || pg.getContainer() instanceof LOOPOperator) {
if (pg.getAllEndNodes().size() == 0) {
ValidationError<ExecutionPetriGraphMustHaveExactelyOneEndNode, FlexoPetriGraph> error = new ValidationError<ExecutionPetriGraphMustHaveExactelyOneEndNode, FlexoPetriGraph>(
this, pg, "execution_petri_graph_must_have_exactely_one_end_node");
error.addToFixProposals(new CreateEndNode(pg));
return error;
} else if (pg.getAllEndNodes().size() > 1) {
ValidationError<ExecutionPetriGraphMustHaveExactelyOneEndNode, FlexoPetriGraph> error = new ValidationError<ExecutionPetriGraphMustHaveExactelyOneEndNode, FlexoPetriGraph>(
this, pg, "execution_petri_graph_must_have_exactely_one_end_node");
for (PetriGraphNode node : pg.getAllEndNodes()) {
error.addToFixProposals(new ChooseEndNode(pg, node));
}
return error;
}
}
return null;
}
public static class ChooseEndNode extends FixProposal<ExecutionPetriGraphMustHaveExactelyOneEndNode, FlexoPetriGraph> {
private PetriGraphNode node;
public ChooseEndNode(FlexoPetriGraph pg, PetriGraphNode nodeThatWillBeKept) {
super("choose_node_($node.name)_and_remove_others");
node = nodeThatWillBeKept;
}
public PetriGraphNode getNode() {
return node;
}
@Override
protected void fixAction() {
Vector<PetriGraphNode> allNodes = new Vector<PetriGraphNode>(getObject().getAllEndNodes());
for (PetriGraphNode n : allNodes) {
if (n != node) {
n.delete();
}
}
}
}
public static class CreateEndNode extends FixProposal<ExecutionPetriGraphMustHaveExactelyOneEndNode, FlexoPetriGraph> {
public CreateEndNode(FlexoPetriGraph pg) {
super("create_new_end_node");
}
@Override
protected void fixAction() {
// TODO: use FlexoAction
getObject().createNewEndNode();
}
}
}
public int getIndexForBeginNode(PetriGraphNode beginNode) {
int idx = 0;
for (FlexoNode n : getAllBeginNodes()) {
if (n == beginNode) {
return idx;
}
idx++;
}
return -1;
}
public int getIndexForEndNode(FlexoNode endNode) {
int idx = 0;
for (FlexoNode n : getAllEndNodes()) {
if (n == endNode) {
return idx;
}
idx++;
}
return -1;
}
public int getIndexForNormalNode(PetriGraphNode node) {
int idx = 0;
for (FlexoNode n : getAllNodesOfClass(FlexoNode.class)) {
if (n == node) {
return idx;
}
if (n.isNormalNode()) {
idx++;
}
}
return -1;
}
}