/*******************************************************************************
* Copyright (c) 2010-2015 Henshin developers. All rights reserved.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* TU Berlin, University of Luxembourg, SES S.A.
*******************************************************************************/
/**
*
*/
package de.tub.tfs.henshin.editor.actions.rule;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.henshin.model.Edge;
import org.eclipse.emf.henshin.model.HenshinPackage;
import org.eclipse.emf.henshin.model.Mapping;
import org.eclipse.emf.henshin.model.Node;
import org.eclipse.emf.henshin.model.Rule;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.ui.actions.SelectionAction;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.SWT;
import org.eclipse.ui.IWorkbenchPart;
import de.tub.tfs.henshin.editor.ui.dialog.ValidTestDialog;
import de.tub.tfs.henshin.editor.util.ModelUtil;
import de.tub.tfs.henshin.editor.util.ResourceUtil;
/**
* The Class RuleValidAction.
*/
public class ValidateRuleAction extends SelectionAction {
/** The Constant ID. */
public static final String ID = "henshineditor.actions.RuleValidAction"; //$NON-NLS-N$
/** The Constant DESC. */
static private final String DESC = "Validate";
/** The Constant TOOLTIP. */
static private final String TOOLTIP = "Validate Rule";
static private final ImageDescriptor ICON = ResourceUtil.ICONS.CHECK
.descr(18);
/** The rule. */
protected Rule rule;
/** The rhs node2lhs node. */
private Map<Node, Node> rhsNode2lhsNode;
/** The rhs edge2lhs edge. */
private Map<Edge, Edge> rhsEdge2lhsEdge;
/**
* Instantiates a new rule valid action.
*
* @param part
* the part
*/
public ValidateRuleAction(IWorkbenchPart part) {
super(part);
setId(ID);
setText(DESC);
setDescription(DESC);
setToolTipText(TOOLTIP);
setImageDescriptor(ICON);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.gef.ui.actions.WorkbenchPartAction#calculateEnabled()
*/
@Override
protected boolean calculateEnabled() {
List<?> selectedObjects = getSelectedObjects();
rule = null;
if (selectedObjects.size() == 1) {
Object selectedObject = selectedObjects.get(0);
if ((selectedObject instanceof EditPart)) {
Object model = ((EditPart) selectedObject).getModel();
if (model instanceof Rule) {
rule = (Rule) model;
}
}
}
return rule != null;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.action.Action#run()
*/
@Override
public void run() {
rhsNode2lhsNode = new HashMap<Node, Node>();
rhsEdge2lhsEdge = new HashMap<Edge, Edge>();
List<String> meldungen = new ArrayList<String>();
List<Node> createdNodes = new ArrayList<Node>();
List<Node> deletedNodes = new ArrayList<Node>();
List<Edge> createdEdges = new ArrayList<Edge>();
List<Edge> deletedEdges = new ArrayList<Edge>();
Map<Edge, Edge> changeEdgesOld2New = new HashMap<Edge, Edge>();
createdNodes.addAll(rule.getRhs().getNodes());
deletedNodes.addAll(rule.getLhs().getNodes());
for (Mapping m : rule.getMappings()) {
createdNodes.remove(m.getImage());
deletedNodes.remove(m.getOrigin());
rhsNode2lhsNode.put(m.getImage(), m.getOrigin());
}
for (Edge edge : rule.getRhs().getEdges()) {
if (rhsNode2lhsNode.containsKey(edge.getSource())
&& rhsNode2lhsNode.containsKey(edge.getTarget())) {
Node sourceLhs = rhsNode2lhsNode.get(edge.getSource());
Node targetLhs = rhsNode2lhsNode.get(edge.getTarget());
for (Edge edgeLhs : sourceLhs.getOutgoing()) {
if (edgeLhs.getTarget() == targetLhs
&& edgeLhs.getType() == edge.getType()
&& !rhsEdge2lhsEdge.containsValue(edgeLhs)) {
rhsEdge2lhsEdge.put(edge, edgeLhs);
break;
}
}
}
}
createdEdges.addAll(rule.getRhs().getEdges());
createdEdges.removeAll(rhsEdge2lhsEdge.keySet());
deletedEdges.addAll(rule.getLhs().getEdges());
deletedEdges.removeAll(rhsEdge2lhsEdge.values());
// Create a new object node together with its containment edge.
for (Node node : createdNodes) {
int count = 0;
for (Edge edge : node.getIncoming()) {
if (edge.getType().isContainment()) {
count++;
}
}
if (count == 0) {
meldungen.add("The node " + node.getName() + ": "
+ node.getType().getName()
+ " does not have any containment edges.");
}
if (count > 1) {
meldungen.add("The node " + node.getName() + ": "
+ node.getType().getName()
+ " has too many containment edges.");
}
}
// Delete an object node together with its containment edge only.
for (Node node : deletedNodes) {
boolean contaimentLoeschen = false;
for (Edge edge : node.getIncoming()) {
if (edge.getType().isContainment()
&& deletedEdges.contains(edge)) {
contaimentLoeschen = true;
break;
}
}
if (!contaimentLoeschen) {
meldungen.add("Der Knoten " + node.getName() + ": "
+ node.getType().getName()
+ " soll ohne containment Kante gel�scht werden. ");
}
}
// Create a containment edge together with its contained object node or
// change the container.
Iterator<Edge> iter = createdEdges.iterator();
while (iter.hasNext()) {
Edge edge = iter.next();
if (edge.getType().isContainment()) {
if (!createdNodes.contains(edge.getTarget())) {
Node nodeLhs = rhsNode2lhsNode.get(edge.getTarget());
boolean chenged = false;
for (Edge edgeLhs : nodeLhs.getIncoming()) {
if (deletedEdges.contains(edgeLhs)
&& edgeLhs.getType().isContainment()) {
changeEdgesOld2New.put(edgeLhs, edge);
deletedEdges.remove(edgeLhs);
iter.remove();
chenged = true;
break;
}
}
if (!chenged) {
meldungen.add("Die Containment Kante "
+ edge.getType().getName()
+ " wird ohne zugeh�rigen Knoten erstellt. ");
}
}
}
}
// Delete a containment edge together with its contained object node (or
// change the container).
for (Edge edge : deletedEdges) {
if (edge.getType().isContainment()
&& !deletedNodes.contains(edge.getTarget())) {
meldungen.add("Containment Kante " + edge.getType().getName()
+ " wird ohne zugeh�rigen Knoten gel�scht. ");
}
}
// Create cycle-capable containment edges only, if the old and the new
// container are both transitively contained in the same container.
for (Edge edge : changeEdgesOld2New.keySet()) {
Node o = edge.getSource();
Node m = edge.getTarget();
Node n = rhsNode2lhsNode.get(changeEdgesOld2New.get(edge)
.getSource());
if (n == null) {
meldungen.add("Neue Container ist in LHS nicht definiert.");
} else {
if (!((contains(o, n) && !contains(m, n)) || contains(n, o))) {
meldungen
.add("Der Graph kann nach dem Ausf�hren Zyklen enthalten.");
}
}
}
for (Node rhsNode : rule.getRhs().getNodes()) {
if (rhsNode.getType().isAbstract()) {
List<Mapping> mappings = ModelUtil.getReferences(rhsNode,
Mapping.class, rule,
HenshinPackage.Literals.MAPPING__IMAGE);
if (mappings.isEmpty()) {
meldungen.add("RHS Node " + rhsNode.getName()
+ " of abstract type :"
+ rhsNode.getType().getName()
+ " does not have any mapping.");
}
}
}
if (meldungen.size() == 0) {
meldungen.add("Validation completed successfully.");
}
ValidTestDialog vD = new ValidTestDialog(getWorkbenchPart().getSite()
.getShell(), SWT.NULL, meldungen);
vD.open();
}
/**
* Contains.
*
* @param node1
* the node1
* @param node2
* the node2
* @return true, if successful
*/
private boolean contains(Node node1, Node node2) {
for (Edge edge : node2.getIncoming()) {
if (edge.getType().isContainment()) {
if (edge.getSource() == node1) {
return true;
}
return contains(node1, edge.getSource());
}
}
return false;
}
}