/**
* <copyright>
* Copyright (c) 2010-2014 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
* </copyright>
*/
package org.eclipse.emf.henshin.interpreter.impl;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.henshin.interpreter.Assignment;
import org.eclipse.emf.henshin.interpreter.Match;
import org.eclipse.emf.henshin.interpreter.util.InterpreterUtil;
import org.eclipse.emf.henshin.model.Edge;
import org.eclipse.emf.henshin.model.Node;
import org.eclipse.emf.henshin.model.Parameter;
import org.eclipse.emf.henshin.model.Rule;
import org.eclipse.emf.henshin.model.Unit;
/**
* Default {@link Match} implementation.
*/
public class MatchImpl extends AssignmentImpl implements Match {
// Nodes to be matched:
protected List<Node> nodes;
/**
* Default constructor.
* @param rule Rule to be matched.
*/
public MatchImpl(Rule rule) {
this (rule, false);
}
/**
* Constructor.
* @param rule The rule that this match is used for.
* @param isResultMatch Determines whether this is a result match.
*/
public MatchImpl(Rule rule, boolean isResultMatch) {
super(rule, isResultMatch);
}
/**
* Constructor.
* @param assignment The assignment or match to be copied.
* @param isResultMatch Determines whether this is a result match.
*/
public MatchImpl(Assignment assignment, boolean isResultMatch) {
super(assignment.getUnit(), isResultMatch);
copyParameterValues(assignment);
if (assignment instanceof Match) {
Match match = (Match) assignment;
for (Node node : nodes) {
setNodeTarget(node, match.getNodeTarget(node));
}
}
}
/*
* (non-Javadoc)
* @see org.eclipse.emf.henshin.interpreter.impl.AssignmentImpl#setUnit(org.eclipse.emf.henshin.model.Unit)
*/
@Override
protected void setUnit(Unit unit) {
if (!(unit instanceof Rule)) {
throw new IllegalArgumentException("Unit must be a rule");
}
this.unit = unit;
// LHS or RHS nodes?
this.nodes = isResult ? ((Rule) unit).getRhs().getNodes() : ((Rule) unit).getLhs().getNodes();
}
/*
* (non-Javadoc)
* @see org.eclipse.emf.henshin.interpreter.Match#getRule()
*/
@Override
public Rule getRule() {
return (Rule) unit;
}
/*
* (non-Javadoc)
* @see org.eclipse.emf.henshin.interpreter.Match#getNodeTarget(org.eclipse.emf.henshin.model.Node)
*/
@Override
public EObject getNodeTarget(Node node) {
return (EObject) values.get(node);
}
/*
* (non-Javadoc)
* @see org.eclipse.emf.henshin.interpreter.Match#setNodeTarget(org.eclipse.emf.henshin.model.Node, org.eclipse.emf.ecore.EObject)
*/
@Override
public void setNodeTarget(Node node, EObject target) {
setValue(node, target);
// Check whether there is a parameter with the same name:
if (unit!=null && node.getName()!=null) {
Parameter param = unit.getParameter(node.getName());
if (param!=null) {
setValue(param, target);
}
}
}
/*
* (non-Javadoc)
* @see org.eclipse.emf.henshin.interpreter.impl.AssignmentImpl#setParameterValue(org.eclipse.emf.henshin.model.Parameter, java.lang.Object)
*/
@Override
public void setParameterValue(Parameter param, Object value) {
setValue(param, value);
// Check whether there are nodes with the same name as the parameter:
String name = param.getName();
if (name!=null && nodes!=null && (value==null || value instanceof EObject)) {
for (Node node : nodes) {
if (name.equals(node.getName())) {
setValue(node, value);
}
}
}
}
/*
* (non-Javadoc)
* @see org.eclipse.emf.henshin.interpreter.Match#getAllNodeTargets()
*/
@Override
public List<EObject> getNodeTargets() {
List<EObject> targets = new ArrayList<EObject>();
if (nodes!=null) {
for (Node node : nodes) {
EObject tar = (EObject) values.get(node);
if (tar!=null) {
targets.add(tar);
}
}
}
return targets;
}
/*
* (non-Javadoc)
* @see org.eclipse.emf.henshin.interpreter.Match#getMultiMatches(org.eclipse.emf.henshin.model.Rule)
*/
@Override
public List<Match> getMultiMatches(Rule multiRule) {
@SuppressWarnings("unchecked")
List<Match> nested = (List<Match>) values.get(multiRule);
if (nested==null) {
nested = new ArrayList<Match>();
values.put(multiRule, nested);
}
return nested;
}
/*
* (non-Javadoc)
* @see org.eclipse.emf.henshin.interpreter.Match#overlapsWith(org.eclipse.emf.henshin.interpreter.Match)
*/
@Override
public boolean overlapsWith(Match match) {
List<EObject> common = getNodeTargets();
common.retainAll(match.getNodeTargets());
return !common.isEmpty();
}
/*
* (non-Javadoc)
* @see org.eclipse.emf.henshin.interpreter.Match#isComplete()
*/
@Override
public boolean isComplete() {
if (nodes==null || getRule()==null) {
return false;
}
if (!values.keySet().containsAll(nodes)) {
return false;
}
for (Rule multiRule : getRule().getMultiRules()) {
for (Match nestedMatch : getMultiMatches(multiRule)) {
if (!nestedMatch.isComplete()) {
return false;
}
}
}
return true;
}
/*
* (non-Javadoc)
* @see org.eclipse.emf.henshin.interpreter.Match#isValid()
*/
@Override
public boolean isValid() {
// Check completeness:
if (!isComplete()) {
return false;
}
// Check object types:
for (Node node : nodes) {
if (node.getType().isSuperTypeOf(((EObject) values.get(node)).eClass())) {
return false;
}
}
// Check if all edges are present:
for (Node node : nodes) {
EObject source = (EObject) values.get(node);
for (Edge edge : node.getOutgoing()) {
EReference edgeType = edge.getType();
EObject target = (EObject) values.get(edge.getTarget());
if (edgeType.isMany()) {
@SuppressWarnings("unchecked")
List<EObject> targetObjects = (List<EObject>) source.eGet(edgeType);
if (!targetObjects.contains(target)) {
return false;
}
} else {
if (source.eGet(edgeType)!=target) {
return false;
}
}
}
}
return true;
}
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (!super.equals(obj) || !(obj instanceof Match)) {
return false;
}
Match match = (Match) obj;
if (nodes!=null) {
for (Node node : nodes) {
if (values.get(node)!=match.getNodeTarget(node)) {
return false;
}
}
}
return true;
}
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
if (isResult) {
return "Result match for rule '" + unit.getName() + "':\n" + toStringWithIndent("");
} else {
return "Match for rule '" + unit.getName() + "':\n" + toStringWithIndent("");
}
}
/*
* toString helper.
*/
@Override
protected String toStringWithIndent(String indent) {
String result = super.toStringWithIndent(indent);
String matchType = isResult ? "Result match" : "Match";
int index = 1;
if (nodes.isEmpty()) {
result = result + indent + "- no nodes\n";
} else {
for (Node node : nodes) {
String name = node.getName()!=null ? "'" + node.getName() + "'" : "#" + index;
EObject target = getNodeTarget(node);
if (target!=null) {
result = result + indent + "- node " + name + " => " +
InterpreterUtil.objectToString(target) + "\n";
}
index++;
}
}
index = 1;
for (Rule multiRule : ((Rule) unit).getMultiRules()) {
String name = multiRule.getName()!=null ? "'" + multiRule.getName() + "'" : "#" + index;
result = result + "\n" + indent + " Multi-rule " + name + ":\n";
List<Match> matches = getMultiMatches(multiRule);
for (int i=0; i<matches.size(); i++) {
result = result + "\n" + indent + " " + matchType + " #" + i + ":\n";
Match match = matches.get(i);
if (match instanceof MatchImpl) {
result = result + ((MatchImpl) match).toStringWithIndent(indent + " ");
} else {
result = result + indent + " " + match.toString();
}
}
index++;
}
return result;
}
}