[
Date Prev][
Date Next][
Thread Prev][
Thread Next][
Date Index][
Thread Index]
[
List Home]
[henshin-dev] Patch "UserConstraint" for henshin.matching and .interpreter
|
Dear Gregor and all,
as discussed last Tuesday, we need a patch for henshin.matching and
henshin.interpreter that allows us in our new triple graph grammar
editor to apply rules according to certain source consistency conditions.
Using the patch, these conditions can be incorporated in a special
UserConstraint class where we implement the additional checks that have
to be performed for matching.
In our particular case, we check a boolean attribute "isTranslated" of a
rule node that, if true, must be mapped to a graph node only if this
graph node has been translated before; (and the other way round: a
"false"-tagged rule node must be matched only to a graph node that has
NOT YET been translated -- we check this by looking up certain tables
where we store ids of translated elements).
We cannot model this by an equally-bound "isTranslated" attributes in
the instance model because the instance model (and its EMF model) must
not be extended by new attribute (types); the "isTranslated" attribute
serves only for rule application purposes, but does not belong to the model.
Moreover, it does NOT help us to check only if the objects are in the
"used objects" list of the matchfinder, because there may be objects
that have been used by the rule before ("used_object=true") but should
be used again by the next rule since the matches of both rules may well
overlap in these objects.
The "used_object" value alone does not tell us whether the
"isTranslated"-values of rule and graph object do coincide or not.
Hence, we need the patch and would be very happy if you could integrate it.
The patch is very general and allows Henshin users to add user-specific
constraints to the matching process.
(If no user constraints are needed, nothing has to be done and
everything works as before.)
Here is a short description of the changes in this patch (based on
revision 1243):
1) in org.eclipse.emf.henshin.matching
- new class in Package constraints: public abstract class
UserConstraint implements Constraint
2) in org.eclipse.emf.henshin.interpreter
- new class: public abstract class HenshinUserConstraint extends
UserConstraint
- in class EmfEngine:
+ a new variable
private HashMap<Class<? extends UserConstraint>, Object[]>
userConstraints = new HashMap<Class<? extends UserConstraint>,Object[]>();
+ a new method
public void registerUserConstraint(Class<? extends UserConstraint>
con,Object... params)
Using the patch in our particular case:
Method registerUserConstraint is called in execute() by us in
tggeditor.commands.ExecuteRulesCommand:
HashMap<Node, Boolean> isTranslatedNodeMap = new HashMap<Node,
Boolean>();
emfEngine.registerUserConstraint(RuleConstraint.class,
isTranslatedNodeMap);
The RuleConstraint class is our TGGEditor class
tggeditor.commands.RuleConstraint and extends HenshinUserConstraint and
implements the source consistency check we need.
I attach the patches for matching and interpreter. Please have a look
and tell us what you think.
Best,
Claudia
Index: src/org/eclipse/emf/henshin/internal/interpreter/RuleInfo.java
===================================================================
--- src/org/eclipse/emf/henshin/internal/interpreter/RuleInfo.java (revision 1243)
+++ src/org/eclipse/emf/henshin/internal/interpreter/RuleInfo.java (working copy)
@@ -11,8 +11,13 @@
*******************************************************************************/
package org.eclipse.emf.henshin.internal.interpreter;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+
import javax.script.ScriptEngine;
+import org.eclipse.emf.henshin.matching.constraints.UserConstraint;
import org.eclipse.emf.henshin.model.Rule;
public class RuleInfo {
@@ -22,11 +27,11 @@
private ChangeInfo changeInfo;
private ConditionInfo conditionInfo;
- public RuleInfo(Rule rule, ScriptEngine scriptEngine) {
+ public RuleInfo(Rule rule, ScriptEngine scriptEngine,HashMap<Class<? extends UserConstraint>, Object[]> userConstraints) {
this.rule = rule;
this.conditionInfo = new ConditionInfo(rule, scriptEngine);
- this.variableInfo = new VariableInfo(this, scriptEngine);
+ this.variableInfo = new VariableInfo(this, scriptEngine,userConstraints);
this.changeInfo = new ChangeInfo(rule);
}
Index: src/org/eclipse/emf/henshin/internal/interpreter/VariableInfo.java
===================================================================
--- src/org/eclipse/emf/henshin/internal/interpreter/VariableInfo.java (revision 1243)
+++ src/org/eclipse/emf/henshin/internal/interpreter/VariableInfo.java (working copy)
@@ -1,11 +1,14 @@
package org.eclipse.emf.henshin.internal.interpreter;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
@@ -17,8 +20,10 @@
import org.eclipse.emf.henshin.interpreter.util.ModelHelper;
import org.eclipse.emf.henshin.matching.constraints.AttributeConstraint;
import org.eclipse.emf.henshin.matching.constraints.DanglingConstraint;
+import org.eclipse.emf.henshin.matching.constraints.DomainSlot;
import org.eclipse.emf.henshin.matching.constraints.ParameterConstraint;
import org.eclipse.emf.henshin.matching.constraints.ReferenceConstraint;
+import org.eclipse.emf.henshin.matching.constraints.UserConstraint;
import org.eclipse.emf.henshin.matching.constraints.Variable;
import org.eclipse.emf.henshin.model.Attribute;
import org.eclipse.emf.henshin.model.BinaryFormula;
@@ -55,7 +60,7 @@
private Rule rule;
private ScriptEngine scriptEngine;
- public VariableInfo(RuleInfo ruleInfo, ScriptEngine scriptEngine) {
+ public VariableInfo(RuleInfo ruleInfo, ScriptEngine scriptEngine, HashMap<Class<? extends UserConstraint>, Object[]> userConstraints) {
this.rule = ruleInfo.getRule();
this.scriptEngine = scriptEngine;
@@ -67,11 +72,13 @@
createVariables(rule.getLhs(), null);
+ if (userConstraints != null) {
for (Node node : rule.getLhs().getNodes()) {
+ createUserConstraints(node,userConstraints);
if (!ModelHelper.isNodeMapped(rule.getMappings(), node))
createDanglingConstraints(node);
}
-
+ }
mainVariables = variable2mainVariable.values();
}
@@ -172,6 +179,62 @@
var.addConstraint(constraint);
}
+
+ private void createUserConstraints(Node node, HashMap<Class<? extends UserConstraint>, Object[]> userConstraints) {
+
+ Variable var = node2variable.get(node);
+ for (Entry<Class<? extends UserConstraint>, Object[]> entry : userConstraints.entrySet()) {
+ Constructor<?>[] constructors = entry.getKey().getConstructors();
+ constructorLoop: for (Constructor<?> constructor : constructors) {
+ Object[] params = null;
+ Class<?>[] constructorTypes = constructor.getParameterTypes();
+ boolean matchingTypes = true;
+ if (constructorTypes.length != entry.getValue().length+1){
+ continue;
+ }
+
+ for (int i = 1;i < constructorTypes.length;i++) {
+ if (matchingTypes)
+ matchingTypes &= constructorTypes[i].isAssignableFrom(entry.getValue()[i-1].getClass());
+ else
+ continue constructorLoop;
+ }
+
+ if (constructorTypes[0].equals(Node.class)){
+ params = new Object[1 + entry.getValue().length];
+ params[0] = node;
+ System.arraycopy(entry.getValue(), 0, params, 1, entry.getValue().length);
+
+ } else {
+ continue;
+ }
+
+ UserConstraint instance;
+ try {
+ instance = (UserConstraint) constructor.newInstance(params);
+ var.addConstraint(instance);
+
+ } catch (IllegalArgumentException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (InstantiationException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (InvocationTargetException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ break;
+ }
+
+ }
+
+
+ }
+
private Map<EReference, Integer> getEdgeCounts(Node node, boolean incoming) {
Collection<Edge> edges = incoming ? node.getIncoming() : node.getOutgoing();
Collection<Edge> oppositeEdges = incoming ? node.getOutgoing() : node.getIncoming();
Index: src/org/eclipse/emf/henshin/interpreter/EmfEngine.java
===================================================================
--- src/org/eclipse/emf/henshin/interpreter/EmfEngine.java (revision 1243)
+++ src/org/eclipse/emf/henshin/interpreter/EmfEngine.java (working copy)
@@ -13,6 +13,7 @@
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -52,6 +53,7 @@
import org.eclipse.emf.henshin.matching.constraints.DomainSlot;
import org.eclipse.emf.henshin.matching.constraints.Matchfinder;
import org.eclipse.emf.henshin.matching.constraints.Solution;
+import org.eclipse.emf.henshin.matching.constraints.UserConstraint;
import org.eclipse.emf.henshin.matching.constraints.Variable;
import org.eclipse.emf.henshin.matching.util.TransformationOptions;
import org.eclipse.emf.henshin.model.AmalgamationUnit;
@@ -84,6 +86,8 @@
// options that alter the matching strategy of the engine
TransformationOptions options;
+ private HashMap<Class<? extends UserConstraint>, Object[]> userConstraints = new HashMap<Class<? extends UserConstraint>,Object[]>();
+
/**
* Creates a new EmfEngine instance.
*/
@@ -240,7 +244,7 @@
private RuleInfo getRuleInformation(final Rule rule) {
RuleInfo ruleInfo = ruleInformation.get(rule);
if (ruleInfo == null) {
- ruleInfo = new RuleInfo(rule, scriptEngine);
+ ruleInfo = new RuleInfo(rule, scriptEngine,userConstraints);
ruleInformation.put(rule, ruleInfo);
}
@@ -535,4 +539,11 @@
public void setOptions(final TransformationOptions options) {
this.options = options;
}
+
+ public void registerUserConstraint(Class<? extends UserConstraint> con,Object... params){
+ if (this.userConstraints == null){
+ this.userConstraints = new HashMap<Class<? extends UserConstraint>,Object[]>();
+ }
+ this.userConstraints.put(con,params);
+ }
}
\ No newline at end of file
Index: src/org/eclipse/emf/henshin/interpreter/HenshinUserConstraint.java
===================================================================
--- src/org/eclipse/emf/henshin/interpreter/HenshinUserConstraint.java (revision 0)
+++ src/org/eclipse/emf/henshin/interpreter/HenshinUserConstraint.java (working copy)
@@ -0,0 +1,41 @@
+package org.eclipse.emf.henshin.interpreter;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.henshin.matching.EmfGraph;
+import org.eclipse.emf.henshin.matching.constraints.DomainSlot;
+import org.eclipse.emf.henshin.matching.constraints.UserConstraint;
+import org.eclipse.emf.henshin.model.Graph;
+import org.eclipse.emf.henshin.model.Node;
+
+public abstract class HenshinUserConstraint extends UserConstraint {
+
+
+ /**
+ *
+ * @param node the node in the LHS of the rule which this constraint belongs to
+ */
+ public HenshinUserConstraint(Node node) {
+ super(node);
+ }
+
+ /**
+ *
+ * @param graphNode the mapped node in the hostgraph
+ * @return Returns whether this constraint is satisfied or not i.e. there exists a morphism between the graph containing this constraints node and the host graph.
+ */
+ public abstract boolean check(Node graphNode);
+
+ @Override
+ public boolean check(DomainSlot slot,EmfGraph graph){
+ return check(getGraphNode(slot,graph));
+ }
+
+ protected Node getGraphNode(DomainSlot slot,EmfGraph graph){
+ return getGraphNode(getValue(slot), graph);
+ }
+
+ protected Node getGraphNode(EObject eObject,EmfGraph graph){
+ return ((HenshinGraph)graph).geteObject2nodeMap().get(eObject);
+ }
+
+}
Index: META-INF/MANIFEST.MF
===================================================================
--- META-INF/MANIFEST.MF (revision 1243)
+++ META-INF/MANIFEST.MF (working copy)
@@ -8,7 +8,8 @@
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Bundle-ActivationPolicy: lazy
Require-Bundle: org.eclipse.emf.ecore.xmi;bundle-version="2.5.0",
- org.eclipse.emf.ecore.change;bundle-version="2.5.0"
+ org.eclipse.emf.ecore.change;bundle-version="2.5.0",
+ org.eclipse.emf.henshin.model;bundle-version="0.8.1"
Export-Package: org.eclipse.emf.henshin.matching,
org.eclipse.emf.henshin.matching.conditions.attribute,
org.eclipse.emf.henshin.matching.conditions.nested,
Index: src/org/eclipse/emf/henshin/matching/constraints/DomainSlot.java
===================================================================
--- src/org/eclipse/emf/henshin/matching/constraints/DomainSlot.java (revision 1243)
+++ src/org/eclipse/emf/henshin/matching/constraints/DomainSlot.java (working copy)
@@ -178,6 +178,10 @@
}
}
+ for (UserConstraint constraint : variable.getUserConstraints()){
+ if (!constraint.check(this,graph))
+ return false;
+ }
checkedVariables.add(variable);
}
@@ -207,7 +211,9 @@
remoteChangeMap.remove(constraint);
}
}
-
+ for (UserConstraint userConstraint : sender.getUserConstraints()) {
+ userConstraint.unlock(sender,this);
+ }
if (locked && sender == owner) {
locked = false;
usedObjects.remove(value);
Index: src/org/eclipse/emf/henshin/matching/constraints/UserConstraint.java
===================================================================
--- src/org/eclipse/emf/henshin/matching/constraints/UserConstraint.java (revision 0)
+++ src/org/eclipse/emf/henshin/matching/constraints/UserConstraint.java (working copy)
@@ -0,0 +1,24 @@
+package org.eclipse.emf.henshin.matching.constraints;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.henshin.matching.EmfGraph;
+import org.eclipse.emf.henshin.model.Node;
+
+public abstract class UserConstraint implements Constraint {
+
+
+ public UserConstraint(Node node) {
+ }
+
+
+ public abstract boolean check(DomainSlot slot,EmfGraph graph);
+
+ public boolean unlock(Variable sender,DomainSlot slot){
+ return true;
+ }
+
+ protected EObject getValue(DomainSlot slot){
+ return slot.value;
+ }
+
+}
Index: src/org/eclipse/emf/henshin/matching/constraints/Variable.java
===================================================================
--- src/org/eclipse/emf/henshin/matching/constraints/Variable.java (revision 1243)
+++ src/org/eclipse/emf/henshin/matching/constraints/Variable.java (working copy)
@@ -22,6 +22,7 @@
private Collection<DanglingConstraint> danglingConstraints;
private Collection<ReferenceConstraint> referenceConstraints;
private Collection<ParameterConstraint> parameterConstraints;
+ private Collection<UserConstraint> userConstraints;
/**
* Constructor<br>
@@ -36,6 +37,7 @@
danglingConstraints = new HashSet<DanglingConstraint>();
referenceConstraints = new HashSet<ReferenceConstraint>();
parameterConstraints = new HashSet<ParameterConstraint>();
+ userConstraints = new HashSet<UserConstraint>();
}
/**
@@ -100,4 +102,14 @@
public Collection<ParameterConstraint> getParameterConstraints() {
return parameterConstraints;
}
+
+ public Collection<UserConstraint> getUserConstraints() {
+ return userConstraints;
}
+
+ public void addConstraint(UserConstraint userConstraints) {
+ this.userConstraints.add(userConstraints);
+ }
+
+
+}
begin:vcard
fn:Dr. Claudia Ermel
n:Ermel;Claudia
org;quoted-printable;quoted-printable:Technische Universit=C3=A4t Berlin;Institut f=C3=BCr Softwaretechnik und Theoretische Informatik
adr:;;Franklinstr. 28-29;Berlin;;10587;Germany
email;internet:claudia.ermel@xxxxxxxxxxxx
tel;work:+49 30 314 27787
tel;fax:+49 30 314 23516
url:http://www.tfs.tu-berlin.de/menue/home/team/ermel_claudia/
version:2.1
end:vcard