package org.js.model.workflow.graphtransformation;
import java.util.ArrayList;
import java.util.HashMap;
import org.eclipse.jwt.meta.model.core.Model;
import org.eclipse.jwt.meta.model.events.impl.EventImpl;
import org.eclipse.jwt.meta.model.organisations.Role;
import org.eclipse.jwt.meta.model.processes.Action;
import org.eclipse.jwt.meta.model.processes.Activity;
import org.eclipse.jwt.meta.model.processes.ActivityEdge;
import org.eclipse.jwt.meta.model.processes.ActivityNode;
import org.eclipse.jwt.meta.model.processes.impl.ActionImpl;
import org.eclipse.jwt.meta.model.processes.impl.ActivityEdgeImpl;
import org.eclipse.jwt.meta.model.processes.impl.FinalNodeImpl;
import org.eclipse.jwt.meta.model.processes.impl.ForkNodeImpl;
import org.eclipse.jwt.meta.model.processes.impl.InitialNodeImpl;
import org.eclipse.jwt.we.model.view.Diagram;
import org.js.graph.transformation.ActivityFinal;
import org.js.graph.transformation.ArrivingRole;
import org.js.graph.transformation.BelongsTo;
import org.js.graph.transformation.Condition;
import org.js.graph.transformation.Edge;
import org.js.graph.transformation.ExistingRole;
import org.js.graph.transformation.FlowFinal;
import org.js.graph.transformation.Fork;
import org.js.graph.transformation.GraphTransformation;
import org.js.graph.transformation.IdleAction;
import org.js.graph.transformation.InheritsFrom;
import org.js.graph.transformation.Initial;
import org.js.graph.transformation.LeftSide;
import org.js.graph.transformation.Node;
import org.js.graph.transformation.Rule;
import org.js.graph.transformation.SpecializationAction;
import org.js.graph.transformation.VariableRole;
import org.js.model.rbac.RBACService;
import org.js.model.workflow.RoleConnector;
import org.js.model.workflow.util.ChangePrimitive;
import org.js.model.workflow.util.StakeholderInput;
import org.js.model.workflow.util.WorkflowConfUtil;
import org.js.model.workflow.util.WorkflowModelUtil;
/**
* This class is used as help methods for graph transformation.
*
* @author Xi
*
*
*/
public class GraphTransformationUtil {
public static RBACService rbacService = new RBACService();
/**
* apply the graph transformation.
*
* @param shInput
* @param gt
* @param workflowModel
* @param activity
* @param diagram
*/
public static void graphTransformation(StakeholderInput shInput,
GraphTransformation gt, Model workflowModel, Activity activity,
Diagram diagram) {
ArrayList<LeftSideRef> leftSides = null;
for (Rule rule : gt.getRules()) {
leftSides = searchLeftSide(rule, activity);
for (LeftSideRef leftSideRef : leftSides) {
if (isApplicable(rule, leftSideRef, shInput)) {
applyChangePrimitives(workflowModel, activity, diagram,
rule, leftSideRef, shInput);
}
}
}
}
/**
* search the left side of a given rule in the given workflow.
*
* @param rule
* @param activity
* @return
*/
public static ArrayList<LeftSideRef> searchLeftSide(Rule rule,
Activity activity) {
ArrayList<LeftSideRef> leftSides = new ArrayList<LeftSideRef>();
for (ActivityNode node : activity.getNodes()) {
leftSides.addAll(getLeftSideRef(node, rule.getLeftside()));
}
return leftSides;
}
/**
* according to the given activity node we search the left side of the rule.
*
* @param actNode
* @param leftSide
* @return
*/
public static ArrayList<LeftSideRef> getLeftSideRef(ActivityNode actNode,
LeftSide leftSide) {
ArrayList<LeftSideRef> leftSideRefs = new ArrayList<LeftSideRef>();
LeftSideRef leftSideRef = new LeftSideRef();
Node root = getLeftSideRoot(leftSide);
checkStructure(actNode, root, leftSideRefs, leftSideRef, leftSide);
return leftSideRefs;
}
/**
* check whether the given two elements have the type.
*
* @param actNode
* activity node from workflow
* @param node
* node from rule
* @param leftSideRefs
* @param leftSideRef
* @param leftSide
* @return
*/
public static boolean checkStructure(ActivityNode actNode, Node node,
ArrayList<LeftSideRef> leftSideRefs, LeftSideRef leftSideRef,
LeftSide leftSide) {
if (parseRuleElement(node).equals(actNode.getClass())) {
// if ((node instanceof SpecializationAction && !WorkflowModelUtil.getActionName((Action) actNode).equals(WorkflowModelUtil.SPECIALIZATION_ACTION))
// || (node instanceof IdleAction && !WorkflowModelUtil.getActionName((Action) actNode).equals(WorkflowModelUtil.IDLE_ACTION))) {
// return false;
// }
leftSideRef.getNodes().add(actNode);
leftSideRef.getActivityNodesMap().put(node, actNode);
// beware if fork is included in left side without outgoing edges, but where an outgoing edge will be added in the transformation operation,
// the outgoing edge is already assigned due to the bidirectional references!!
if (node.getOut().size() != 0) {
for (Edge edge : node.getOut()) {
if (leftSide.getEdges().contains(edge)) {
for (ActivityEdge actEdge : actNode.getOut()) {
if (parseRuleElement(edge.getTarget()).equals(
actEdge.getTarget().getClass())) {
LeftSideRef newLeftSideRef = LeftSideRef
.createLeftSideRef(leftSideRef);
checkStructure(actEdge, edge, leftSideRefs,
newLeftSideRef, leftSide);
}
}
} else {
leftSideRefs.add(leftSideRef);
}
}
} else {
leftSideRefs.add(leftSideRef);
}
}
return false;
}
/**
* check whether the given two elements have the type.
*
* @param actedge
* edge from workflow
* @param edge
* edge from rule
* @param leftSideRefs
* @param leftSideRef
* @param leftSide
* @return
*/
public static boolean checkStructure(ActivityEdge actedge, Edge edge,
ArrayList<LeftSideRef> leftSideRefs, LeftSideRef leftSideRef,
LeftSide leftSide) {
if (parseRuleElement(edge).equals(actedge.getClass())) {
leftSideRef.getEdges().add(actedge);
leftSideRef.getActivityEdgesMap().put(edge, actedge);
if (edge.getTarget() != null
&& leftSide.getNodes().contains(edge.getTarget())) {
checkStructure(actedge.getTarget(), edge.getTarget(),
leftSideRefs, leftSideRef, leftSide);
} else {
leftSideRefs.add(leftSideRef);
}
}
return false;
}
/**
* get the root nodes of the given left side.
*
* @param leftSide
* @return
*/
public static Node getLeftSideRoot(LeftSide leftSide) {
for (Node node : leftSide.getNodes()) {
if (node.getIn().size() == 0) {
return node;
}
}
return null;
}
/**
* get the tail node of the given left side.
*
* @param leftSide
* @return
*/
public static Node getLeftSideTail(LeftSide leftSide) {
for (Node node : leftSide.getNodes()) {
if (node.getOut().size() == 0) {
return node;
}
}
return null;
}
public static void applyChangePrimitives(Model workflowModel,
Activity activity, Diagram diagram, Rule rule,
LeftSideRef leftSideRef, StakeholderInput shInput) {
// handle the role and the group
// TODO: set layout
Role role = ChangePrimitive.addRole(workflowModel, activity, diagram,
shInput.getStakeholderType(), shInput.getStakeholderName(),
100, 100);
org.js.model.rbac.Role rbacRole = ((RoleConnector) WorkflowConfUtil
.getAspectInstance(role, WorkflowConfUtil.ROLE_ASPECT))
.getRoleref();
if (shInput.getStakeholderGroup() != null) {
ChangePrimitive.addGroup(workflowModel,
shInput.getStakeholderGroup(), rbacRole);
}
HashMap<Node, ActivityNode> addedNodes = new HashMap<Node, ActivityNode>();
HashMap<Edge, ActivityEdge> addedEdges = new HashMap<Edge, ActivityEdge>();
// handle the change primitives
if (rule.getOperations().getRemoveEdges() != null) {
for (Edge edge : rule.getOperations().getRemoveEdges().getEdge()) {
ActivityEdge actEdge = leftSideRef.getActivityEdgesMap().get(
edge);
ChangePrimitive.removeEdge(activity, actEdge.getSource(),
actEdge.getTarget());
}
}
if (rule.getOperations().getRemoveNodes() != null) {
for (Node node : rule.getOperations().getRemoveNodes().getNode()) {
ActivityNode actNode = leftSideRef.getActivityNodesMap().get(
node);
ChangePrimitive.removeActivityNode(workflowModel, activity,
diagram, actNode.getName());
}
}
if (rule.getOperations().getAddNodes() != null) {
for (Node node : rule.getOperations().getAddNodes().getNode()) {
ActivityNode addedNode = null;
if (node instanceof Initial) {
addedNode = ChangePrimitive.addInitialNode(activity,
diagram, WorkflowModelUtil.INITIAL_NODE, 100, 100);
} else if (node instanceof ActivityFinal) {
addedNode = ChangePrimitive.addActivityFinalNode(activity,
diagram, WorkflowModelUtil.ACTIVITY_FINAL_NODE,
100, 100);
} else if (node instanceof FlowFinal) {
addedNode = ChangePrimitive.addFlowFinalNode(activity,
diagram, "", 100, 100);
} else if (node instanceof Fork) {
addedNode = ChangePrimitive.addForkNode(activity, diagram,
100, 100);
} else if (node instanceof SpecializationAction) {
addedNode = ChangePrimitive.addAction(workflowModel,
activity, diagram,
WorkflowModelUtil.SPECIALIZATION_ACTION, 100, 100);
} else if (node instanceof IdleAction) {
addedNode = ChangePrimitive.addAction(workflowModel,
activity, diagram, WorkflowModelUtil.IDLE_ACTION,
100, 100);
}
addedNodes.put(node, addedNode);
}
}
if (rule.getOperations().getAddEdges() != null) {
for (Edge edge : rule.getOperations().getAddEdges().getEdge()) {
ActivityNode source = addedNodes.get(edge.getSource());
ActivityNode target = addedNodes.get(edge.getTarget());
if (source == null) {
source = leftSideRef.getActivityNodesMap().get(
edge.getSource());
}
if (target == null) {
target = leftSideRef.getActivityNodesMap().get(
edge.getTarget());
}
ActivityEdge addedEdge = ChangePrimitive.addEdge(activity,
source, target);
addedEdges.put(edge, addedEdge);
}
}
// add role reference between action and role
Action newAction = (Action) addedNodes.get(rule.getRoles()
.getArrivingRole().getAction());
ChangePrimitive.addRoleActionRef(workflowModel, activity, diagram,
role, newAction);
ChangePrimitive.updateActionState(newAction);
}
/**
* check whether the give rule is applicable.
*
* @param rule
* @param leftSideRef
* @param shInput
* @return
*/
public static boolean isApplicable(Rule rule, LeftSideRef leftSideRef,
StakeholderInput shInput) {
for (Condition condition : rule.getApplicationConditions()
.getConditions()) {
// check inherits condition
if (condition instanceof InheritsFrom) {
org.js.model.rbac.Role parent = ((InheritsFrom) condition)
.getParent();
VariableRole child = ((InheritsFrom) condition).getChild();
if (child instanceof ExistingRole) {
Action action = (Action) leftSideRef.getNodeRef(child
.getAction());
org.js.model.rbac.Role childRef = ((RoleConnector) WorkflowConfUtil
.getAspectInstance(action.getPerformedBy(),
WorkflowConfUtil.ROLE_ASPECT)).getRoleref();
boolean containsParent = false;
for (org.js.model.rbac.Role tempParent : rbacService
.getParentRoles(childRef)) {
if (tempParent.getId().equals(parent.getId())) {
containsParent = true;
}
}
if (!containsParent) {
return false;
}
} else {
if (!shInput.getStakeholderType().getId()
.equals(parent.getId())) {
return false;
}
}
}
// check belongs to condition
else {
VariableRole leader = ((BelongsTo) condition).getLeader();
VariableRole member = ((BelongsTo) condition).getMember();
if (member instanceof ArrivingRole
&& leader instanceof ExistingRole) {
Action action = (Action) leftSideRef.getNodeRef(leader
.getAction());
org.js.model.rbac.Role leaderRef = ((RoleConnector) WorkflowConfUtil
.getAspectInstance(action.getPerformedBy(),
WorkflowConfUtil.ROLE_ASPECT)).getRoleref();
if (shInput.getStakeholderGroup() == null
|| !shInput.getStakeholderGroup().getId()
.equals(leaderRef.getId())) {
return false;
}
} else {
// we do not need this case
}
}
}
return true;
}
/**
* get the jwt meta model element from the given rule element.
*
* @param element
* @return
*/
public static Class parseRuleElement(Object element) {
if (element instanceof Initial) {
return InitialNodeImpl.class;
} else if (element instanceof ActivityFinal) {
return FinalNodeImpl.class;
} else if (element instanceof FlowFinal) {
return EventImpl.class;
} else if (element instanceof Fork) {
return ForkNodeImpl.class;
} else if (element instanceof SpecializationAction
|| element instanceof IdleAction) {
return ActionImpl.class;
} else if (element instanceof Edge) {
return ActivityEdgeImpl.class;
}
return null;
}
}