/*
* (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.awt.geom.Point2D;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.openflexo.foundation.FlexoXMLSerializableObject;
import org.openflexo.foundation.wkf.FlexoLevel;
import org.openflexo.foundation.wkf.FlexoPetriGraph;
import org.openflexo.foundation.wkf.FlexoProcess;
import org.openflexo.foundation.wkf.LevelledObject;
import org.openflexo.foundation.wkf.WKFArtefact;
import org.openflexo.foundation.wkf.WKFObject;
import org.openflexo.foundation.wkf.edge.WKFEdge;
import org.openflexo.foundation.xml.FlexoProcessBuilder;
import org.openflexo.foundation.xml.FlexoXMLMappings;
import org.openflexo.toolbox.EmptyVector;
import org.openflexo.xmlcode.XMLMapping;
/**
* Represents a connex sub-graph composed of AbstractNode elements linked with FlexoPreCondition and FlexoPostCondition Note that a
* NodeCompound is created by cloning and thus, contains clones of initial nodes !
*
* @author sguerin
*
*/
public final class NodeCompound extends WKFObject implements LevelledObject {
private static final Logger logger = Logger.getLogger(NodeCompound.class.getPackage().getName());
private Vector<PetriGraphNode> _nodes;
private Vector<WKFArtefact> artefacts;
private FlexoLevel _level = null;
/**
* Constructor used during deserialization
*/
public NodeCompound(FlexoProcessBuilder builder) {
this(builder.process);
initializeDeserialization(builder);
}
/**
* Default constructor
*/
public NodeCompound(FlexoProcess process) {
super(process);
_nodes = new Vector<PetriGraphNode>();
artefacts = new Vector<WKFArtefact>();
}
/**
* Default constructor
*/
public NodeCompound(FlexoProcess process, Vector<PetriGraphNode> nodes, Vector<WKFArtefact> artefacts) {
this(process);
// 1. First we select only the elements that are that have a common petri-graph
FlexoPetriGraph parent = null;
Iterator<PetriGraphNode> i = nodes.iterator();
while (i.hasNext()) {
PetriGraphNode node = i.next();
if (parent == null) {
parent = node.getParentPetriGraph();
} else if (parent != node.getParentPetriGraph()) {
i.remove();
}
}
Iterator<WKFArtefact> i2 = artefacts.iterator();
while (i2.hasNext()) {
WKFArtefact artefact = i2.next();
if (parent == null) {
parent = artefact.getParentPetriGraph();
} else if (parent != artefact.getParentPetriGraph()) {
i2.remove();
}
}
// 2. We set a copy of the vector as our current data
this.artefacts = new Vector<WKFArtefact>(artefacts);
_nodes = new Vector<PetriGraphNode>(nodes);
// 3. We create a clone
NodeCompound clone = (NodeCompound) cloneUsingXMLMapping();
if (clone != null) {
// 4. We set the objects as our objects
_nodes = clone.getNodes();
this.artefacts = clone.getArtefacts();
_level = clone.getLevel(); // Level is automatically set during deserialization
makeConnex(clone, nodes, artefacts);
if (logger.isLoggable(Level.FINE)) {
logger.fine("Serialized selection is: ");
logger.fine(getXMLRepresentation());
}
} else {
_nodes = new Vector<PetriGraphNode>();
this.artefacts = new Vector<WKFArtefact>();
if (logger.isLoggable(Level.SEVERE)) {
logger.severe("Could not clone this NodeCompound");
}
}
}
private void makeConnex(NodeCompound clone, Vector<PetriGraphNode> originalSelectedNodes, Vector<WKFArtefact> originalSelectedArtefacts) {
XMLMapping mapping = new FlexoXMLMappings().getWKFMapping();
HashSet<WKFEdge> embedded = new HashSet<WKFEdge>();
mapping.getEmbeddedObjectsForObject(clone, embedded, WKFEdge.class, true);
HashSet<WKFObject> originalSet = new HashSet<WKFObject>();
Iterator<PetriGraphNode> originalIterator = clone.getNodes().iterator();
while (originalIterator.hasNext()) {
PetriGraphNode node = originalIterator.next();
mapping.getRestrictedEmbeddedObjectsForObject(node, originalSet, WKFObject.class, true);
}
Iterator<WKFArtefact> originalAnnotationIterator = clone.getArtefacts().iterator();
while (originalAnnotationIterator.hasNext()) {
WKFArtefact a = originalAnnotationIterator.next();
mapping.getRestrictedEmbeddedObjectsForObject(a, originalSet, WKFObject.class, true);
}
Iterator<WKFEdge> i = embedded.iterator();
while (i.hasNext()) {
WKFEdge post = i.next();
if (post.getStartNode() == null || post.getEndNode() == null || !originalSet.contains(post.getStartNode())
|| !originalSet.contains(post.getEndNode())) {
post.delete();
}
}
}
@Override
public FlexoXMLSerializableObject cloneUsingXMLMapping() {
// logger.info("getNodes()="+getNodes());
NodeCompound returned = (NodeCompound) super.cloneUsingXMLMapping();
if (returned != null) {
// logger.info("returned.getNodes()="+returned.getNodes());
for (Enumeration<PetriGraphNode> e = returned.getNodes().elements(); e.hasMoreElements();) {
PetriGraphNode temp = e.nextElement();
if (temp instanceof SubProcessNode) {
if (((SubProcessNode) temp).getPortMapRegistery() != null) {
((SubProcessNode) temp).getPortMapRegistery().lookupServiceInterface();
}
}
}
}
return returned;
}
@Override
public void initializeDeserialization(Object builder) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("initializeDeserialization() for " + this.getClass().getName());
}
super.initializeDeserialization(builder);
if (getProcess() != null) {
getProcess().initializeDeserialization(builder);
}
}
@Override
public void finalizeDeserialization(Object builder) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("finalizeDeserialization() for " + this.getClass().getName());
}
super.finalizeDeserialization(builder);
if (getProcess() != null) {
getProcess().finalizeDeserialization(builder);
}
}
@Override
public String getFullyQualifiedName() {
return "NODE_COMPOUND";
}
public void setLocation(Point2D location, String context) {
Point2D offset = null;
Point2D upperLeftCorner = null;
for (Enumeration<WKFObject> e = getAllEmbeddedWKFObjects().elements(); e.hasMoreElements();) {
WKFObject node = e.nextElement();
if (node == this) {
continue;
}
if (upperLeftCorner == null) {
upperLeftCorner = new Point2D.Double();
upperLeftCorner.setLocation(node.getLocation(context));
} else {
upperLeftCorner.setLocation(Math.min(upperLeftCorner.getX(), node.getX(context)),
Math.min(upperLeftCorner.getY(), node.getY(context)));
}
}
if (upperLeftCorner == null) {
upperLeftCorner = new Point2D.Double();
}
offset = new Point2D.Double();
offset.setLocation(location.getX() - upperLeftCorner.getX(), location.getY() - upperLeftCorner.getY());
for (Enumeration<WKFObject> e = getAllEmbeddedWKFObjects().elements(); e.hasMoreElements();) {
WKFObject node = e.nextElement();
setLocation(node, offset, context);
if (node instanceof SelfExecutableNode) {
SelfExecutableNode self = (SelfExecutableNode) node;
if (self.hasExecutionPetriGraph()) {
setLocation(self.getExecutionPetriGraph(), offset, context);
}
} else {
if (node instanceof AbstractActivityNode) {
AbstractActivityNode activity = (AbstractActivityNode) node;
if (activity.hasContainedPetriGraph()) {
setLocation(activity.getOperationPetriGraph(), offset, context);
Vector allOperations = activity.getAllOperationNodes();
for (Enumeration e2 = allOperations.elements(); e2.hasMoreElements();) {
OperationNode operation = (OperationNode) e2.nextElement();
if (operation.hasContainedPetriGraph()) {
setLocation(operation.getActionPetriGraph(), offset, context);
}
}
}
} else if (node instanceof OperationNode) {
OperationNode operation = (OperationNode) node;
if (operation.hasContainedPetriGraph()) {
setLocation(operation.getActionPetriGraph(), offset, context);
}
} else if (node instanceof LOOPOperator) {
LOOPOperator operator = (LOOPOperator) node;
if (operator.hasExecutionPetriGraph()) {
setLocation(operator.getExecutionPetriGraph(), offset, context);
}
}
}
}
}
private void setLocation(WKFObject object, Point2D offset, String context) {
if (object != null) {
object.setX(Math.max(object.getX(context) + offset.getX(), 0), context);
object.setY(Math.max(object.getY(context) + offset.getY(), 0), context);
}
}
public Vector<PetriGraphNode> getNodes() {
return _nodes;
}
public void setNodes(Vector<PetriGraphNode> nodes) {
_nodes = nodes;
}
public void addToNodes(PetriGraphNode aNode) {
if (aNode.getLevel() != null) {
if (_level != null) {
if (_level != aNode.getLevel()) {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Inconsistent data in NodeCompound");
}
return;
}
} else {
_level = aNode.getLevel();
}
}
_nodes.add(aNode);
}
public void removeFromNodes(PetriGraphNode aNode) {
_nodes.remove(aNode);
}
public Vector<WKFArtefact> getArtefacts() {
return artefacts;
}
public void setArtefacts(Vector<WKFArtefact> artefacts) {
this.artefacts = artefacts;
}
public void addToArtefacts(WKFArtefact artefact) {
if (artefact.getLevel() != null) {
if (_level != null) {
if (_level != artefact.getLevel()) {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Inconsistent data in NodeCompound");
}
return;
}
} else {
_level = artefact.getLevel();
}
}
artefacts.add(artefact);
}
public void removeFromArtefacts(WKFArtefact artefact) {
artefacts.remove(artefact);
}
@Override
public FlexoLevel getLevel() {
return _level;
}
@Override
public final void delete() {
super.delete();
deleteObservers();
}
@Override
public Vector<WKFObject> getAllEmbeddedDeleted() {
return EmptyVector.EMPTY_VECTOR(WKFObject.class);
}
public boolean isSingleNode() {
return _nodes.size() == 1;
}
public PetriGraphNode getFirstNode() {
if (isSingleNode()) {
return _nodes.firstElement();
}
return null;
}
/**
* 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);
returned.addAll(_nodes);
returned.addAll(artefacts);
return returned;
}
/**
* Return all operation components contained in this compound
*
* @return a Vector of OperationNode
*/
public Vector<OperationNode> getAllOperationNodes() {
Vector<OperationNode> returned = new Vector<OperationNode>();
if (getLevel() == FlexoLevel.ACTIVITY) {
for (Enumeration e = getNodes().elements(); e.hasMoreElements();) {
AbstractNode node = (AbstractNode) e.nextElement();
if (node instanceof AbstractActivityNode) {
returned.addAll(((AbstractActivityNode) node).getAllOperationNodes());
}
}
} else if (getLevel() == FlexoLevel.OPERATION) {
for (Enumeration e = getNodes().elements(); e.hasMoreElements();) {
AbstractNode node = (AbstractNode) e.nextElement();
if (node instanceof OperationNode) {
returned.add((OperationNode) node);
}
}
}
return returned;
}
/**
* Return all operation components contained in this compound containing a WOComponent
*
* @return a Vector of OperationNode containing a WOComponent
*/
public Vector getAllOperationNodesContainingAWO() {
Vector<OperationNode> returned = new Vector<OperationNode>();
Vector<OperationNode> allOperationNodes = getAllOperationNodes();
OperationNode cur = null;
for (Enumeration<OperationNode> e = allOperationNodes.elements(); e.hasMoreElements();) {
cur = e.nextElement();
if (cur.getComponentInstance() != null && cur.getComponentInstance().getComponentDefinition() != null) {
returned.add(cur);
}
}
return returned;
}
/**
* Overrides getClassNameKey
*
* @see org.openflexo.foundation.FlexoModelObject#getClassNameKey()
*/
@Override
public String getClassNameKey() {
return "node_compound";
}
}