Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpkonemann2010-11-15 20:53:02 +0000
committerpkonemann2010-11-15 20:53:02 +0000
commit38fcc998ad6a10047cc1bb991a4d09d092bab802 (patch)
tree1c142d53dfb56d3ca792b57c22997f159fc9044e
parentc0ba078e27e21cba7caded105b65d1b95c1b34a1 (diff)
downloadorg.eclipse.emf.compare-38fcc998ad6a10047cc1bb991a4d09d092bab802.tar.gz
org.eclipse.emf.compare-38fcc998ad6a10047cc1bb991a4d09d092bab802.tar.xz
org.eclipse.emf.compare-38fcc998ad6a10047cc1bb991a4d09d092bab802.zip
Enums added to default attributes of symbolic references; npe fixed; test case specification fixed. One more failing test case remaining..
-rw-r--r--plugins/org.eclipse.emf.compare.mpatch.emfdiff2mpatch.generic/src/org/eclipse/emf/compare/mpatch/emfdiff2mpatch/generic/impl/ElementSetReferenceCreator.java440
-rw-r--r--plugins/org.eclipse.emf.compare.mpatch.emfdiff2mpatch.generic/symrefsrc/org/eclipse/emf/compare/mpatch/symrefs/util/OCLConditionHelper.java272
2 files changed, 365 insertions, 347 deletions
diff --git a/plugins/org.eclipse.emf.compare.mpatch.emfdiff2mpatch.generic/src/org/eclipse/emf/compare/mpatch/emfdiff2mpatch/generic/impl/ElementSetReferenceCreator.java b/plugins/org.eclipse.emf.compare.mpatch.emfdiff2mpatch.generic/src/org/eclipse/emf/compare/mpatch/emfdiff2mpatch/generic/impl/ElementSetReferenceCreator.java
index 86d119946..3278802a4 100644
--- a/plugins/org.eclipse.emf.compare.mpatch.emfdiff2mpatch.generic/src/org/eclipse/emf/compare/mpatch/emfdiff2mpatch/generic/impl/ElementSetReferenceCreator.java
+++ b/plugins/org.eclipse.emf.compare.mpatch.emfdiff2mpatch.generic/src/org/eclipse/emf/compare/mpatch/emfdiff2mpatch/generic/impl/ElementSetReferenceCreator.java
@@ -1,212 +1,228 @@
-/*******************************************************************************
- * Copyright (c) 2010 Technical University of Denmark.
- * 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:
- * Patrick Koenemann, DTU Informatics - initial API and implementation
- *******************************************************************************/
-package org.eclipse.emf.compare.mpatch.emfdiff2mpatch.generic.impl;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-
-import org.eclipse.emf.compare.mpatch.IElementReference;
-import org.eclipse.emf.compare.mpatch.emfdiff2mpatch.generic.util.QvtlibHelper;
-import org.eclipse.emf.compare.mpatch.symrefs.ElementSetReference;
-import org.eclipse.emf.compare.mpatch.symrefs.OclCondition;
-import org.eclipse.emf.compare.mpatch.symrefs.SymrefsFactory;
-import org.eclipse.emf.ecore.EAttribute;
-import org.eclipse.emf.ecore.EClass;
-import org.eclipse.emf.ecore.EObject;
-
-/**
- * This implementation creates {@link ElementSetReference}s as symbolic references. That is, an {@link OclCondition} is
- * created that contains an expression over all attributes of that element.
- *
- * Example: An instance of an abstract {@link EClass} called <i>Person</i> results in the following condition:<br>
- * <code>self.abstract = true and self.interface = false and self.name = 'Person' and instanceTypeName = ''</code>
- *
- * @author Patrick Koenemann (pk@imm.dtu.dk)
- *
- */
-public class ElementSetReferenceCreator extends AbstractReferenceCreator {
-
- /**
- * All these types are treated as primitive types during symbolic reference creation.
- */
- static final Collection<String> PRIMITIVE_TYPES = Arrays.asList(new String[] { "java.lang.String", "int",
- "java.lang.Integer", "boolean", "java.lang.Boolean", "long", "java.lang.Long", "byte", "java.lang.Byte",
- "char", "java.lang.Character", "short", "java.lang.Short", });
-
- /**
- * Create a symbolic reference for the context.<br>
- * For all elements, this default implementation creates an {@link ElementSetReference} with a default OCL
- * expression which is used to identify the element.
- *
- * @param self
- * The context, an arbitrary {@link EObject}.
- * @return A symbolic reference to the context as an {@link IElementReference}.
- */
- @Override
- public IElementReference createSymbolicReference(EObject self) {
-
- // create symbolic reference object for any given object
- return create(self, 1);
- }
-
- public String getLabel() {
- return "Condition-based";
- }
-
- // //////////////////////////// HERE STARTS THE SYMREF CREATION //////////////////////////////
-
- /**
- * Create a symbolic reference which contains an ocl condition which holds the criteria for the referenced model
- * element given in the parameter.
- *
- * @param self
- * The element which should be referenced.
- * @param contextDepth
- * The depth for which context references should be created. If <code>0</code>, then no context reference
- * is created.
- * @return A symbolic reference to the model element.
- */
- public ElementSetReference create(EObject self, int contextDepth) {
- final ElementSetReference ref = SymrefsFactory.eINSTANCE.createElementSetReference();
- ref.setType(self.eClass());
- ref.setUriReference(QvtlibHelper.getUriString(self));
- ref.setLabel(QvtlibHelper.getLabel(self));
- ref.getConditions().add(createOclCondition(self));
-
- // the context can of course only be set if the parent exists
- if (contextDepth > 0 && self.eContainer() != null) {
- ref.setContext(create(self.eContainer(), contextDepth - 1));
- }
-
- return ref;
- }
-
- /**
- * This creates an {@link OclCondition} which describes the given object.<br>
- * Subclasses may override or extend the condition.
- *
- * @param self
- * the context
- * @return an {@link OclCondition} which sufficiently describes the context
- */
- protected OclCondition createOclCondition(EObject self) {
- final EClass eclass = self.eClass();
-
- // build ocl condition for all attributes as a string
- String expr = ""; // "self.oclIsTypeOf(" + eclass.getName() + ")";
- for (final EAttribute attribute : eclass.getEAllAttributes()) {
- if (isRelevantAttribute(attribute)) {
- expr += (expr.length() > 0 ? " and " : "") + eAttributeToCondition(attribute, self.eGet(attribute));
- }
- }
-
- // create ocl condition object
- final OclCondition condition = SymrefsFactory.eINSTANCE.createOclCondition();
- condition.setExpression(expr);
-
- return condition;
- }
-
- /**
- * This defines which attributes are used for building the OCL condition. The default implementation uses only the
- * primitive types contained in {@link ElementSetReferenceCreator#PRIMITIVE_TYPES}.
- *
- * Furthermore, all derived attributes are ignored. This is due to an issue with UML models.
- *
- * Subclasses may override this to refine the set of types.
- *
- * @param eAttribute
- * An {@link EAttribute} in the transformation.
- * @return <code>true</code>, if the attribute should be part of the condition; <code>false</code> otherwise.
- */
- protected boolean isRelevantAttribute(EAttribute eAttribute) {
- return PRIMITIVE_TYPES.contains(eAttribute.getEType().getInstanceClassName()) && !eAttribute.isDerived();
- }
-
- /**
- * Create an OCL condition from the given {@link Object} of type {@link EAttribute}.<br>
- * Subclasses may use information from the <code>eAttribute</code> to refine the condition.
- *
- * Example:<br>
- * A String attribute called <code>foo</code> containing the value <code>"bar"</code> results in the condition <code>self.foo = 'bar'</code>
- * .
- *
- * @param eAttribute
- * The type of the object.
- * @param obj
- * The object for which the condition should be created.
- * @return An ocl condition which describes this object.
- */
- protected String eAttributeToCondition(EAttribute eAttribute, Object obj) {
- final String prefix = ""; // "self.";
- if (obj instanceof List<?>) {
- // recursive call for lists :-)
- return prefix + eAttribute.getName() + "->asSequence() = " + listAttributeToString((List<?>) obj);
-
- } else if (obj == null) {
- // FIXME: unfortunately, the OCL implementation does not work with
- // OclVoid as null! workaround: create set and check if it is empty :o)
- return prefix + eAttribute.getName() + "->asSet()->isEmpty()";
-
- } else {
- // handle primitive types
- return prefix + eAttribute.getName() + " = " + primitiveAttributeToString(obj);
- }
- }
-
- /**
- * If attributes have a cardinality &gt;1, it needs to be compared using a collection type.
- *
- * Example:<br>
- * A list containing <code>"foo"</code> and <code>"bar"</code> is returned as <code>Sequence{'foo','bar'}</code>.
- *
- * @param list
- * A list of objects.
- * @return An ocl sequence containing the given objects.
- */
- protected String listAttributeToString(List<?> list) {
- String result = "";
- for (final Object o : (List<?>) list) {
- if (o instanceof List<?>) {
- result += (result.length() == 0 ? "" : ",") + listAttributeToString((List<?>) o);
- } else {
- result += (result.length() == 0 ? "" : ",") + primitiveAttributeToString(o);
- }
- }
- return "Sequence{" + result + "}";
- }
-
- /**
- * Return a String representation of the given object <code>obj</code>.<br>
- * Subclasses may refine this conversion.
- *
- * @param obj
- * The object to convert.
- * @return A valid ocl string representation of the value.
- */
- protected String primitiveAttributeToString(Object obj) {
- if (obj == null) {
- return "OclVoid"; // this does not work yet, unfortunately!
- } else if (obj instanceof String) {
- return "'" + (String) obj + "'";
- } else if (obj instanceof Integer) {
- return obj.toString();
- } else if (obj instanceof Boolean) {
- return (Boolean) obj ? "true" : "false";
- } else if (obj instanceof EObject) {
- return "<EObject is not yet supported as attribute type!>";
- } else {
- return "<Type not supported: " + obj.getClass().getName() + ">";
- }
- }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2010 Technical University of Denmark.
+ * 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:
+ * Patrick Koenemann, DTU Informatics - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.mpatch.emfdiff2mpatch.generic.impl;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.emf.compare.mpatch.IElementReference;
+import org.eclipse.emf.compare.mpatch.emfdiff2mpatch.generic.util.QvtlibHelper;
+import org.eclipse.emf.compare.mpatch.symrefs.ElementSetReference;
+import org.eclipse.emf.compare.mpatch.symrefs.OclCondition;
+import org.eclipse.emf.compare.mpatch.symrefs.SymrefsFactory;
+import org.eclipse.emf.ecore.EAttribute;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EEnum;
+import org.eclipse.emf.ecore.EObject;
+
+/**
+ * This implementation creates {@link ElementSetReference}s as symbolic references. That is, an {@link OclCondition} is
+ * created that contains an expression over all attributes of that element.
+ *
+ * Example: An instance of an abstract {@link EClass} called <i>Person</i> results in the following condition:<br>
+ * <code>self.abstract = true and self.interface = false and self.name = 'Person' and instanceTypeName = ''</code>
+ *
+ * @author Patrick Koenemann (pk@imm.dtu.dk)
+ *
+ */
+public class ElementSetReferenceCreator extends AbstractReferenceCreator {
+
+ /**
+ * All these types are treated as primitive types during symbolic reference creation.
+ */
+ static final Collection<String> PRIMITIVE_TYPES = Arrays.asList(new String[] { "java.lang.String", "int",
+ "java.lang.Integer", "boolean", "java.lang.Boolean", "long", "java.lang.Long", "byte", "java.lang.Byte",
+ "char", "java.lang.Character", "short", "java.lang.Short", });
+
+ /**
+ * Create a symbolic reference for the context.<br>
+ * For all elements, this default implementation creates an {@link ElementSetReference} with a default OCL
+ * expression which is used to identify the element.
+ *
+ * @param self
+ * The context, an arbitrary {@link EObject}.
+ * @return A symbolic reference to the context as an {@link IElementReference}.
+ */
+ @Override
+ public IElementReference createSymbolicReference(EObject self) {
+
+ // create symbolic reference object for any given object
+ return create(self, 1);
+ }
+
+ public String getLabel() {
+ return "Condition-based";
+ }
+
+ // //////////////////////////// HERE STARTS THE SYMREF CREATION //////////////////////////////
+
+ /**
+ * Create a symbolic reference which contains an ocl condition which holds the criteria for the referenced model
+ * element given in the parameter.
+ *
+ * @param self
+ * The element which should be referenced.
+ * @param contextDepth
+ * The depth for which context references should be created. If <code>0</code>, then no context reference
+ * is created.
+ * @return A symbolic reference to the model element.
+ */
+ public ElementSetReference create(EObject self, int contextDepth) {
+ final ElementSetReference ref = SymrefsFactory.eINSTANCE.createElementSetReference();
+ ref.setType(self.eClass());
+ ref.setUriReference(QvtlibHelper.getUriString(self));
+ ref.setLabel(QvtlibHelper.getLabel(self));
+ ref.getConditions().add(createOclCondition(self));
+
+ // the context can of course only be set if the parent exists
+ if (contextDepth > 0 && self.eContainer() != null) {
+ ref.setContext(create(self.eContainer(), contextDepth - 1));
+ }
+
+ return ref;
+ }
+
+ /**
+ * This creates an {@link OclCondition} which describes the given object.<br>
+ * Subclasses may override or extend the condition.
+ *
+ * @param self
+ * the context
+ * @return an {@link OclCondition} which sufficiently describes the context
+ */
+ protected OclCondition createOclCondition(EObject self) {
+ final EClass eclass = self.eClass();
+
+ // build ocl condition for all attributes as a string
+ String expr = ""; // "self.oclIsTypeOf(" + eclass.getName() + ")";
+ for (final EAttribute attribute : eclass.getEAllAttributes()) {
+ if (isRelevantAttribute(attribute)) {
+ expr += (expr.length() > 0 ? " and " : "") + eAttributeToCondition(attribute, self.eGet(attribute));
+ }
+ }
+
+ // create ocl condition object
+ final OclCondition condition = SymrefsFactory.eINSTANCE.createOclCondition();
+ condition.setExpression(expr);
+
+ return condition;
+ }
+
+ /**
+ * This defines which attributes are used for building the OCL condition. The default implementation uses only the
+ * primitive types contained in {@link ElementSetReferenceCreator#PRIMITIVE_TYPES} and enumeration types.
+ *
+ * Furthermore, all derived attributes are ignored. This is due to an issue with UML models.
+ *
+ * Subclasses may override this to refine the set of types.
+ *
+ * @param eAttribute
+ * An {@link EAttribute} in the transformation.
+ * @return <code>true</code>, if the attribute should be part of the condition; <code>false</code> otherwise.
+ */
+ protected boolean isRelevantAttribute(EAttribute eAttribute) {
+
+ // is it an enumeration?
+ if (eAttribute.getEType() instanceof EEnum) {
+ return true;
+ }
+
+ // is it one of the supported primitive types?
+ return PRIMITIVE_TYPES.contains(eAttribute.getEType().getInstanceClassName()) && !eAttribute.isDerived();
+ }
+
+ /**
+ * Create an OCL condition from the given {@link Object} of type {@link EAttribute}.<br>
+ * Subclasses may use information from the <code>eAttribute</code> to refine the condition.
+ *
+ * Example:<br>
+ * A String attribute called <code>foo</code> containing the value <code>"bar"</code> results in the condition <code>self.foo = 'bar'</code>
+ * .
+ *
+ * @param eAttribute
+ * The type of the object.
+ * @param obj
+ * The object for which the condition should be created.
+ * @return An ocl condition which describes this object.
+ */
+ protected String eAttributeToCondition(EAttribute eAttribute, Object obj) {
+ final String prefix = ""; // "self.";
+ if (obj instanceof List<?>) {
+ // recursive call for lists :-)
+ return prefix + eAttribute.getName() + "->asSequence() = " + listAttributeToString((List<?>) obj);
+
+ } else if (obj instanceof Enum){
+ final Class<?> declaringClass = ((Enum<?>) obj).getDeclaringClass();
+ /*
+ * the quotes " are required to escape keywords, e.g. VisibilityKind::"package".
+ * if the quotes are missing, then the visibility 'package' collides with the ocl keyword 'package'.
+ */
+ return prefix + eAttribute.getName() + " = " + declaringClass.getSimpleName() + "::\"" + ((Enum<?>)obj).toString() + "\"";
+
+ } else if (obj == null) {
+ // FIXME: unfortunately, the OCL implementation does not work with
+ // OclVoid as null! workaround: create set and check if it is empty :o)
+ return prefix + eAttribute.getName() + "->asSet()->isEmpty()";
+
+ } else {
+ // handle primitive types
+ return prefix + eAttribute.getName() + " = " + primitiveAttributeToString(obj);
+ }
+ }
+
+ /**
+ * If attributes have a cardinality &gt;1, it needs to be compared using a collection type.
+ *
+ * Example:<br>
+ * A list containing <code>"foo"</code> and <code>"bar"</code> is returned as <code>Sequence{'foo','bar'}</code>.
+ *
+ * @param list
+ * A list of objects.
+ * @return An ocl sequence containing the given objects.
+ */
+ protected String listAttributeToString(List<?> list) {
+ String result = "";
+ for (final Object o : (List<?>) list) {
+ if (o instanceof List<?>) {
+ result += (result.length() == 0 ? "" : ",") + listAttributeToString((List<?>) o);
+ } else {
+ result += (result.length() == 0 ? "" : ",") + primitiveAttributeToString(o);
+ }
+ }
+ return "Sequence{" + result + "}";
+ }
+
+ /**
+ * Return a String representation of the given object <code>obj</code>.<br>
+ * Subclasses may refine this conversion.
+ *
+ * @param obj
+ * The object to convert.
+ * @return A valid ocl string representation of the value.
+ */
+ protected String primitiveAttributeToString(Object obj) {
+ if (obj == null) {
+ return "OclVoid"; // this does not work yet, unfortunately!
+ } else if (obj instanceof String) {
+ return "'" + (String) obj + "'";
+ } else if (obj instanceof Integer) {
+ return obj.toString();
+ } else if (obj instanceof Boolean) {
+ return (Boolean) obj ? "true" : "false";
+ } else if (obj instanceof EObject) {
+ return "<EObject is not yet supported as attribute type!>";
+ } else {
+ return "<Type not supported: " + obj.getClass().getName() + ">";
+ }
+ }
+
+}
diff --git a/plugins/org.eclipse.emf.compare.mpatch.emfdiff2mpatch.generic/symrefsrc/org/eclipse/emf/compare/mpatch/symrefs/util/OCLConditionHelper.java b/plugins/org.eclipse.emf.compare.mpatch.emfdiff2mpatch.generic/symrefsrc/org/eclipse/emf/compare/mpatch/symrefs/util/OCLConditionHelper.java
index 5360ec1a6..d87a61e76 100644
--- a/plugins/org.eclipse.emf.compare.mpatch.emfdiff2mpatch.generic/symrefsrc/org/eclipse/emf/compare/mpatch/symrefs/util/OCLConditionHelper.java
+++ b/plugins/org.eclipse.emf.compare.mpatch.emfdiff2mpatch.generic/symrefsrc/org/eclipse/emf/compare/mpatch/symrefs/util/OCLConditionHelper.java
@@ -1,135 +1,137 @@
-/*******************************************************************************
- * Copyright (c) 2010 Technical University of Denmark.
- * 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:
- * Patrick Koenemann, DTU Informatics - initial API and implementation
- *******************************************************************************/
-package org.eclipse.emf.compare.mpatch.symrefs.util;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.eclipse.emf.compare.mpatch.emfdiff2mpatch.generic.Activator;
-import org.eclipse.emf.compare.mpatch.symrefs.OclCondition;
-import org.eclipse.emf.ecore.EClass;
-import org.eclipse.emf.ecore.EClassifier;
-import org.eclipse.emf.ecore.EObject;
-import org.eclipse.emf.query.conditions.eobjects.EObjectCondition;
-import org.eclipse.emf.query.handlers.PruneHandler;
-import org.eclipse.emf.query.ocl.conditions.BooleanOCLCondition;
-import org.eclipse.emf.query.statements.FROM;
-import org.eclipse.emf.query.statements.IQueryResult;
-import org.eclipse.emf.query.statements.SELECT;
-import org.eclipse.emf.query.statements.WHERE;
-import org.eclipse.ocl.ParserException;
-import org.eclipse.ocl.Query;
-import org.eclipse.ocl.ecore.OCL;
-import org.eclipse.ocl.helper.OCLHelper;
-
-public class OCLConditionHelper {
-
- /** OCL instance with regex support for string primitives. */
- protected final static OCL ocl = org.eclipse.ocl.ecore.OCL.newInstance(new RegexEnvironmentFactory());
-
- /**
- * A cache for OCL String conditions converted to EMF Query conditions. This increases the performance when the map
- * is filled.
- *
- * TODO: Maybe we could think of an alternative improvement, e.g. building the query / condition object ourselves.
- */
- private static final Map<String, EObjectCondition> cachedConditions = new HashMap<String, EObjectCondition>();
-
- /**
- * Use EMF Query and OCL to find all emf model elements in the given resource which match the given ocl condition.
- *
- * @param condition
- * @param resource
- * @return
- */
- public static Collection<EObject> collectValidElements(OclCondition condition, EObject model) {
-
- // convert the condition and quit if that was not successful
- EObjectCondition whereCondition = getWhereCondition(condition);
- if (whereCondition == null)
- return Collections.emptyList();
-
- // perform the query
- final IQueryResult result;
- try {
- result = new SELECT(new FROM(model), new WHERE(whereCondition)).execute();
- } catch (Exception e) {
- Activator.getDefault().logError("Error while executing OCL statement with condition: " + whereCondition, e);
- return Collections.emptyList();
- }
-
- /*
- * some debugging output
- */
- // msg("=========> " + condition.getExpression());
- // msg("applied to: " + model);
- // for (final Object next : result) {
- // msg("-> " + next);
- // }
-
- return result;
- }
-
- // /**
- // * For debugging.
- // */
- // private static void msg(String s) {
- // // Activator.getDefault().logInfo(s);
- // System.out.println("OCLConditionHelper: " + s);
- // }
-
- /**
- * Create a condition for emf query out of an ocl condition having an expression and optionally checking also the
- * type.
- *
- * @param condition
- * An OCL condition containing an expression and information whether to also check the type.
- * @return A condition for EMF query or <code>null</code>, if the condition could not be created e.g. because the
- * expression was not parseable.
- */
- public static EObjectCondition getWhereCondition(OclCondition condition) {
-
- // build the key for this condition, depending on the expression and the type
- String key = condition.getElementReference().getType().getInstanceClassName()
- + (condition.isCheckType() ? "?" : "!") + condition.getExpression();
-
- // try to get an already cached ocl condition
- EObjectCondition whereCondition = cachedConditions.get(key);
-
- // if condition is not yet cached, lets parse it from the string expression and create a query
- if (whereCondition == null) {
-
- // ocl's little helper
- OCLHelper<EClassifier, ?, ?, ?> helper = ocl.createOCLHelper();
- helper.setContext(condition.getElementReference().getType());
- Query<EClassifier, EClass, EObject> query;
- try {
-
- // create the query (costly operation)
- query = ocl.createQuery(helper.createQuery(condition.getExpression()));
- } catch (final ParserException e) {
- Activator.getDefault().logError("Error while parsing ocl condition: " + condition.getExpression(), e);
- return null;
- }
-
- // build a condition from the query (somehow costly operation)
- whereCondition = new BooleanOCLCondition<EClassifier, EClass, EObject>(ocl.getEnvironment(), query,
- condition.isCheckType() ? condition.getElementReference().getType() : null, PruneHandler.NEVER);
-
- // cache that condition!
- cachedConditions.put(key, whereCondition);
- }
- return whereCondition;
- }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2010 Technical University of Denmark.
+ * 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:
+ * Patrick Koenemann, DTU Informatics - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.mpatch.symrefs.util;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.emf.compare.mpatch.emfdiff2mpatch.generic.Activator;
+import org.eclipse.emf.compare.mpatch.symrefs.OclCondition;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.query.conditions.eobjects.EObjectCondition;
+import org.eclipse.emf.query.handlers.PruneHandler;
+import org.eclipse.emf.query.ocl.conditions.BooleanOCLCondition;
+import org.eclipse.emf.query.statements.FROM;
+import org.eclipse.emf.query.statements.IQueryResult;
+import org.eclipse.emf.query.statements.SELECT;
+import org.eclipse.emf.query.statements.WHERE;
+import org.eclipse.ocl.ParserException;
+import org.eclipse.ocl.Query;
+import org.eclipse.ocl.ecore.OCL;
+import org.eclipse.ocl.expressions.OCLExpression;
+import org.eclipse.ocl.helper.OCLHelper;
+
+public class OCLConditionHelper {
+
+ /** OCL instance with regex support for string primitives. */
+ protected final static OCL ocl = org.eclipse.ocl.ecore.OCL.newInstance(new RegexEnvironmentFactory());
+
+ /**
+ * A cache for OCL String conditions converted to EMF Query conditions. This increases the performance when the map
+ * is filled.
+ *
+ * TODO: Maybe we could think of an alternative improvement, e.g. building the query / condition object ourselves.
+ */
+ private static final Map<String, EObjectCondition> cachedConditions = new HashMap<String, EObjectCondition>();
+
+ /**
+ * Use EMF Query and OCL to find all emf model elements in the given resource which match the given ocl condition.
+ *
+ * @param condition
+ * @param resource
+ * @return
+ */
+ public static Collection<EObject> collectValidElements(OclCondition condition, EObject model) {
+
+ // convert the condition and quit if that was not successful
+ EObjectCondition whereCondition = getWhereCondition(condition);
+ if (whereCondition == null)
+ return Collections.emptyList();
+
+ // perform the query
+ final IQueryResult result;
+ try {
+ result = new SELECT(new FROM(model), new WHERE(whereCondition)).execute();
+ } catch (Exception e) {
+ Activator.getDefault().logError("Error while executing OCL statement with condition: " + whereCondition, e);
+ return Collections.emptyList();
+ }
+
+ /*
+ * some debugging output
+ */
+ // msg("=========> " + condition.getExpression());
+ // msg("applied to: " + model);
+ // for (final Object next : result) {
+ // msg("-> " + next);
+ // }
+
+ return result;
+ }
+
+ // /**
+ // * For debugging.
+ // */
+ // private static void msg(String s) {
+ // // Activator.getDefault().logInfo(s);
+ // System.out.println("OCLConditionHelper: " + s);
+ // }
+
+ /**
+ * Create a condition for emf query out of an ocl condition having an expression and optionally checking also the
+ * type.
+ *
+ * @param condition
+ * An OCL condition containing an expression and information whether to also check the type.
+ * @return A condition for EMF query or <code>null</code>, if the condition could not be created e.g. because the
+ * expression was not parseable.
+ */
+ public static EObjectCondition getWhereCondition(OclCondition condition) {
+
+ // build the key for this condition, depending on the expression and the type
+ String key = condition.getElementReference().getType().getInstanceClassName()
+ + (condition.isCheckType() ? "?" : "!") + condition.getExpression();
+
+ // try to get an already cached ocl condition
+ EObjectCondition whereCondition = cachedConditions.get(key);
+
+ // if condition is not yet cached, lets parse it from the string expression and create a query
+ if (whereCondition == null) {
+
+ // ocl's little helper
+ OCLHelper<EClassifier, ?, ?, ?> helper = ocl.createOCLHelper();
+ helper.setContext(condition.getElementReference().getType());
+ Query<EClassifier, EClass, EObject> query;
+ try {
+
+ // create the query (costly operation)
+ final OCLExpression<EClassifier> oclExpression = helper.createQuery(condition.getExpression());
+ query = ocl.createQuery(oclExpression);
+ } catch (final ParserException e) {
+ Activator.getDefault().logError("Error while parsing ocl condition: " + condition.getExpression(), e);
+ return null;
+ }
+
+ // build a condition from the query (somehow costly operation)
+ whereCondition = new BooleanOCLCondition<EClassifier, EClass, EObject>(ocl.getEnvironment(), query,
+ condition.isCheckType() ? condition.getElementReference().getType() : null, PruneHandler.NEVER);
+
+ // cache that condition!
+ cachedConditions.put(key, whereCondition);
+ }
+ return whereCondition;
+ }
+
+}

Back to the top