Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian W. Damus2013-09-04 07:27:01 +0000
committerEike Stepper2013-09-04 07:27:01 +0000
commit63f73fefd48ad3c408924221931d98df132d44ba (patch)
treedb0ef3745b3fb81f4d533ae514f4c6d6865f6ac4
parent971b3c85d0e1d6ad07f6113f7e71cc7ea83f4c44 (diff)
downloadcdo-63f73fefd48ad3c408924221931d98df132d44ba.tar.gz
cdo-63f73fefd48ad3c408924221931d98df132d44ba.tar.xz
cdo-63f73fefd48ad3c408924221931d98df132d44ba.zip
[416474] [OCL] Add some non-standard operations to support efficient OCL
queries https://bugs.eclipse.org/bugs/show_bug.cgi?id=416474 Change-Id: I8ae59bda5cb20a1cbfee1fae81713032b6627e79
-rw-r--r--plugins/org.eclipse.emf.cdo.server.ocl/src/org/eclipse/emf/cdo/server/ocl/CDOAdditionalOperation.java368
-rw-r--r--plugins/org.eclipse.emf.cdo.server.ocl/src/org/eclipse/emf/cdo/server/ocl/CDOEnvironment.java196
-rw-r--r--plugins/org.eclipse.emf.cdo.server.ocl/src/org/eclipse/emf/cdo/server/ocl/CDOEnvironmentFactory.java71
-rw-r--r--plugins/org.eclipse.emf.cdo.server.ocl/src/org/eclipse/emf/cdo/server/ocl/CDOEvaluationEnvironment.java54
-rw-r--r--plugins/org.eclipse.emf.cdo.server.ocl/src/org/eclipse/emf/cdo/server/ocl/OCLQueryHandler.java4
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_416474_Test.java160
6 files changed, 852 insertions, 1 deletions
diff --git a/plugins/org.eclipse.emf.cdo.server.ocl/src/org/eclipse/emf/cdo/server/ocl/CDOAdditionalOperation.java b/plugins/org.eclipse.emf.cdo.server.ocl/src/org/eclipse/emf/cdo/server/ocl/CDOAdditionalOperation.java
new file mode 100644
index 0000000000..b1c3335d74
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.ocl/src/org/eclipse/emf/cdo/server/ocl/CDOAdditionalOperation.java
@@ -0,0 +1,368 @@
+/*
+ * Copyright (c) 2013 Eike Stepper (Berlin, Germany) and others.
+ * 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:
+ * Christian W. Damus (CEA LIST) - initial API and implementation
+ */
+package org.eclipse.emf.cdo.server.ocl;
+
+import org.eclipse.emf.cdo.eresource.CDOResource;
+
+import org.eclipse.emf.common.notify.impl.AdapterImpl;
+import org.eclipse.emf.ecore.EAttribute;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.emf.ecore.EDataType;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EOperation;
+import org.eclipse.emf.ecore.EParameter;
+import org.eclipse.emf.ecore.EcoreFactory;
+import org.eclipse.emf.ecore.EcorePackage;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+
+import org.eclipse.ocl.ecore.TypeType;
+import org.eclipse.ocl.expressions.CollectionKind;
+import org.eclipse.ocl.utilities.TypedElement;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Additional operations for use in OCL queries in the CDO context.
+ *
+ * @author Christian W. Damus
+ * @since 4.2
+ */
+abstract class CDOAdditionalOperation extends AdapterImpl
+{
+ private final CDOEnvironment env;
+
+ private final String name;
+
+ private CDOAdditionalOperation(CDOEnvironment env, String name)
+ {
+ this.env = env;
+ this.name = name;
+ }
+
+ public final CDOEnvironment getEnv()
+ {
+ return env;
+ }
+
+ public final String getName()
+ {
+ return name;
+ }
+
+ /**
+ * Creates the ECore operation(s) that I implement and registers them in my environment on the appropriate owner type.
+ */
+ protected abstract void register();
+
+ /**
+ * Evaluates me on the specified {@code source} object with the given (possibly empty) {@code arguments}.
+ */
+ protected abstract Object evaluate(CDOEvaluationEnvironment evalEnv, Object source, Object[] arguments);
+
+ /**
+ * Resolves the possibly generic return type of an operation according to its relation to the source ({@code owner}) type and argument types.
+ */
+ protected EClassifier getResultType(EClassifier owner, EOperation operation,
+ List<? extends TypedElement<EClassifier>> args)
+ {
+ EClassifier result = operation.getEType();
+ return result != null ? result : env.getOCLStandardLibrary().getOclVoid();
+ }
+
+ protected final EOperation createEOperation(EClassifier resultType)
+ {
+ EOperation result = EcoreFactory.eINSTANCE.createEOperation();
+
+ result.setName(getName());
+ result.setEType(resultType);
+ result.eAdapters().add(this);
+
+ return result;
+ }
+
+ protected final EOperation createEOperation(EClassifier resultType, String paramName, EClassifier paramType)
+ {
+ EOperation result = createEOperation(resultType);
+
+ EParameter param = EcoreFactory.eINSTANCE.createEParameter();
+ param.setName(paramName);
+ param.setEType(paramType);
+ result.getEParameters().add(param);
+
+ return result;
+ }
+
+ protected final EClassifier collectionType(CollectionKind kind, EClassifier elementType)
+ {
+ return (EClassifier)env.getTypeResolver().resolveCollectionType(kind, elementType);
+ }
+
+ static CDOAdditionalOperation getInstance(EOperation operation)
+ {
+ CDOAdditionalOperation result = null;
+
+ // As a hacky filter to avoid the cost of iterating adapters for the vast majority of operations that
+ // are not one of ours, check for our common prefix
+ if (operation.getName().startsWith("cdo")) //$NON-NLS-1$
+ {
+ for (Object next : operation.eAdapters())
+ {
+ if (next instanceof CDOAdditionalOperation)
+ {
+ result = (CDOAdditionalOperation)next;
+ break;
+ }
+ }
+ }
+
+ return result;
+ }
+
+ static void registerOperations(CDOEnvironment env)
+ {
+ new AllProperContents(env).register();
+ new MatchesAnyStringAttribute(env).register();
+ }
+
+ /**
+ * The <tt>cdoAllContents</tt> operation that collects all of the proper (non-cross-resource-contained)
+ * elements within a {@link CDOResource} or an {@link EObject}. An optional argument filters the result
+ * to instances of a particular model class.
+ *
+ * @author Christian W. Damus
+ */
+ private static class AllProperContents extends CDOAdditionalOperation
+ {
+ private static final String NAME = "cdoAllProperContents"; //$NON-NLS-1$
+
+ private AllProperContents(CDOEnvironment env)
+ {
+ super(env, NAME);
+ }
+
+ @Override
+ protected void register()
+ {
+ CDOEnvironment env = getEnv();
+ EClassifier oclAny = env.getOCLStandardLibrary().getOclAny();
+ EClassifier oclT = env.getOCLStandardLibrary().getT();
+ EClassifier resultType = collectionType(CollectionKind.COLLECTION_LITERAL, oclT);
+
+ // One variant without a filter type argument
+ env.addHelperOperation(oclAny, createEOperation(resultType));
+
+ // And one with
+ env.addHelperOperation(oclAny, createEOperation(resultType, "type", env.getOCLStandardLibrary().getOclType())); //$NON-NLS-1$
+ }
+
+ @Override
+ protected Object evaluate(CDOEvaluationEnvironment evalEnv, Object source, Object[] arguments)
+ {
+ Collection<EObject> result = new java.util.ArrayList<EObject>();
+
+ // Only resources and EObjects have contents
+ Iterator<EObject> iter;
+ if (source instanceof Resource)
+ {
+ iter = EcoreUtil.getAllProperContents((Resource)source, false);
+ }
+ else if (source instanceof EObject)
+ {
+ iter = EcoreUtil.getAllProperContents((EObject)source, false);
+ }
+ else
+ {
+ iter = Collections.<EObject> emptyList().iterator();
+ }
+
+ if (arguments.length == 1)
+ {
+ // Get the type-filter argument
+ EClassifier typeFilter = (EClassifier)arguments[0];
+ if (typeFilter == null)
+ {
+ typeFilter = EcorePackage.Literals.EOBJECT;
+ }
+
+ while (iter.hasNext())
+ {
+ EObject next = iter.next();
+ if (!next.eIsProxy() && typeFilter.isInstance(next)) // Because it could be a containment proxy
+ {
+ result.add(next);
+ }
+ }
+
+ }
+ else
+ {
+ while (iter.hasNext())
+ {
+ EObject next = iter.next();
+ if (!next.eIsProxy()) // Because it could be a containment proxy
+ {
+ result.add(next);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ protected EClassifier getResultType(EClassifier owner, EOperation operation,
+ List<? extends TypedElement<EClassifier>> args)
+ {
+ // The result type of the type-filtered variant is a collection of the filter type
+ EClassifier elementType = args.isEmpty() ? getEnv().getOCLStandardLibrary().getOclAny() : ((TypeType)args.get(0)
+ .getType()).getReferredType();
+ return collectionType(CollectionKind.COLLECTION_LITERAL, elementType);
+ }
+ }
+
+ /**
+ * @author Christian W. Damus
+ */
+ private static class MatchesAnyStringAttribute extends CDOAdditionalOperation
+ {
+ private static final String NAME = "cdoMatches"; //$NON-NLS-1$
+
+ private static final int CACHE_SIZE = 16;
+
+ private Map<String, Matcher> matcherCache;
+
+ private Map<EClass, List<EAttribute>> stringAttributes;
+
+ private MatchesAnyStringAttribute(CDOEnvironment env)
+ {
+ super(env, NAME);
+ }
+
+ @Override
+ protected void register()
+ {
+ CDOEnvironment env = getEnv();
+ EClassifier oclAny = env.getOCLStandardLibrary().getOclAny();
+ env.addHelperOperation(oclAny,
+ createEOperation(env.getOCLStandardLibrary().getBoolean(), "regex", env.getOCLStandardLibrary().getString())); //$NON-NLS-1$
+ }
+
+ @Override
+ protected Object evaluate(CDOEvaluationEnvironment evalEnv, Object source, Object[] arguments)
+ {
+ boolean result = false;
+
+ // Only EObjects have String-valued attributes (or attributes at all!)
+ if (source instanceof EObject)
+ {
+ EObject object = (EObject)source;
+ Matcher m = getMatcher((String)arguments[0]);
+
+ // Check all string-valued attributes of this EClass
+ for (EAttribute next : getStringAttributes(object.eClass()))
+ {
+ if (!next.isMany())
+ {
+ String value = (String)object.eGet(next);
+ result = value != null && m.reset(value).matches();
+ }
+ else
+ {
+ @SuppressWarnings("unchecked")
+ List<String> valueList = (List<String>)object.eGet(next);
+ for (int i = 0; !result && i < valueList.size(); i++)
+ {
+ String value = valueList.get(i);
+ result = value != null && m.reset(value).matches();
+ }
+ }
+
+ if (result)
+ {
+ break;
+ }
+ }
+ }
+
+ return result;
+ }
+
+ private Matcher getMatcher(String regex)
+ {
+ if (matcherCache == null)
+ {
+ matcherCache = new java.util.LinkedHashMap<String, Matcher>(CACHE_SIZE, 0.75f, true)
+ {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected boolean removeEldestEntry(Map.Entry<String, Matcher> eldest)
+ {
+ return size() > CACHE_SIZE;
+ }
+ };
+ }
+
+ Matcher result = matcherCache.get(regex);
+
+ if (result == null)
+ {
+ result = Pattern.compile(regex).matcher(""); //$NON-NLS-1$
+ matcherCache.put(regex, result);
+ }
+
+ return result;
+ }
+
+ private List<EAttribute> getStringAttributes(EClass eClass)
+ {
+ if (stringAttributes == null)
+ {
+ stringAttributes = new java.util.HashMap<EClass, List<EAttribute>>();
+ }
+
+ List<EAttribute> result = stringAttributes.get(eClass);
+
+ if (result == null)
+ {
+ for (EAttribute next : eClass.getEAllAttributes())
+ {
+ EDataType type = next.getEAttributeType();
+ if (type != null && type.getInstanceClass() == String.class)
+ {
+ if (result == null)
+ {
+ result = new java.util.ArrayList<EAttribute>();
+ }
+ result.add(next);
+ }
+ }
+
+ if (result == null)
+ {
+ result = Collections.emptyList();
+ }
+
+ stringAttributes.put(eClass, result);
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.ocl/src/org/eclipse/emf/cdo/server/ocl/CDOEnvironment.java b/plugins/org.eclipse.emf.cdo.server.ocl/src/org/eclipse/emf/cdo/server/ocl/CDOEnvironment.java
new file mode 100644
index 0000000000..2ddc758396
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.ocl/src/org/eclipse/emf/cdo/server/ocl/CDOEnvironment.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2004-2013 Eike Stepper (Berlin, Germany) and others.
+ * 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:
+ * Christian W. Damus (CEA LIST) - initial API and implementation
+ */
+package org.eclipse.emf.cdo.server.ocl;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.emf.ecore.EEnumLiteral;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EOperation;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EParameter;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.resource.Resource;
+
+import org.eclipse.ocl.Environment;
+import org.eclipse.ocl.TypeChecker;
+import org.eclipse.ocl.ecore.CallOperationAction;
+import org.eclipse.ocl.ecore.Constraint;
+import org.eclipse.ocl.ecore.EcoreEnvironment;
+import org.eclipse.ocl.ecore.EcoreEnvironmentFactory;
+import org.eclipse.ocl.ecore.SendSignalAction;
+import org.eclipse.ocl.utilities.TypedElement;
+
+import java.util.List;
+
+/**
+ * CDO-specific Ecore environment implementation. It adds operations that assist in building efficient OCL queries.
+ *
+ * @author Christian W. Damus
+ * @since 4.2
+ */
+class CDOEnvironment extends EcoreEnvironment
+{
+ public CDOEnvironment(EcoreEnvironmentFactory fac, Resource resource)
+ {
+ super(fac, resource);
+ }
+
+ public CDOEnvironment(
+ Environment<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject> parent)
+ {
+ super(parent);
+ }
+
+ @Override
+ protected TypeChecker<EClassifier, EOperation, EStructuralFeature> createTypeChecker()
+ {
+ TypeChecker<EClassifier, EOperation, EStructuralFeature> result = super.createTypeChecker();
+ if (result instanceof TypeChecker.Cached<?, ?, ?>)
+ {
+ return new DelegatingCachedTypeChecker((TypeChecker.Cached<EClassifier, EOperation, EStructuralFeature>)result);
+ }
+
+ return new DelegatingTypeChecker(result);
+ }
+
+ /**
+ * @author Christian W. Damus
+ */
+ private static class DelegatingTypeChecker implements TypeChecker<EClassifier, EOperation, EStructuralFeature>
+ {
+ private final TypeChecker<EClassifier, EOperation, EStructuralFeature> delegate;
+
+ public DelegatingTypeChecker(TypeChecker<EClassifier, EOperation, EStructuralFeature> delegate)
+ {
+ this.delegate = delegate;
+ }
+
+ public EClassifier getResultType(Object problemObject, EClassifier owner, EOperation operation,
+ List<? extends TypedElement<EClassifier>> args)
+ {
+ CDOAdditionalOperation cdoOperation = CDOAdditionalOperation.getInstance(operation);
+ if (cdoOperation != null)
+ {
+ return cdoOperation.getResultType(owner, operation, args);
+ }
+
+ return delegate.getResultType(problemObject, owner, operation, args);
+ }
+
+ //
+ // Strict delegation of API
+ //
+
+ public int getRelationship(EClassifier type1, EClassifier type2)
+ {
+ return delegate.getRelationship(type1, type2);
+ }
+
+ public EClassifier getPropertyType(EClassifier owner, EStructuralFeature property)
+ {
+ return delegate.getPropertyType(owner, property);
+ }
+
+ public EClassifier commonSuperType(Object problemObject, EClassifier type1, EClassifier type2)
+ {
+ return delegate.commonSuperType(problemObject, type1, type2);
+ }
+
+ public boolean checkMutuallyComparable(Object problemObject, EClassifier type1, EClassifier type2, int opcode)
+ {
+ return delegate.checkMutuallyComparable(problemObject, type1, type2, opcode);
+ }
+
+ public boolean exactTypeMatch(EClassifier type1, EClassifier type2)
+ {
+ return delegate.exactTypeMatch(type1, type2);
+ }
+
+ public boolean compatibleTypeMatch(EClassifier type1, EClassifier type2)
+ {
+ return delegate.compatibleTypeMatch(type1, type2);
+ }
+
+ public List<EOperation> getOperations(EClassifier owner)
+ {
+ return delegate.getOperations(owner);
+ }
+
+ public List<EStructuralFeature> getAttributes(EClassifier owner)
+ {
+ return delegate.getAttributes(owner);
+ }
+
+ public EOperation resolveGenericSignature(EClassifier owner, EOperation oper)
+ {
+ return delegate.resolveGenericSignature(owner, oper);
+ }
+
+ public EClassifier findSignalMatching(EClassifier receiver, List<EClassifier> signals, String name,
+ List<? extends TypedElement<EClassifier>> args)
+ {
+ return delegate.findSignalMatching(receiver, signals, name, args);
+ }
+
+ public EOperation findOperationMatching(EClassifier owner, String name,
+ List<? extends TypedElement<EClassifier>> args)
+ {
+ return delegate.findOperationMatching(owner, name, args);
+ }
+
+ public boolean matchArgs(EClassifier owner, List<?> paramsOrProperties,
+ List<? extends TypedElement<EClassifier>> args)
+ {
+ return delegate.matchArgs(owner, paramsOrProperties, args);
+ }
+
+ public EStructuralFeature findAttribute(EClassifier owner, String name)
+ {
+ return delegate.findAttribute(owner, name);
+ }
+
+ public boolean isStandardLibraryFeature(EClassifier owner, Object feature)
+ {
+ return delegate.isStandardLibraryFeature(owner, feature);
+ }
+ }
+
+ /**
+ * @author Christian W. Damus
+ */
+ private static class DelegatingCachedTypeChecker extends DelegatingTypeChecker implements
+ TypeChecker.Cached<EClassifier, EOperation, EStructuralFeature>
+ {
+ private final TypeChecker.Cached<EClassifier, EOperation, EStructuralFeature> delegate;
+
+ public DelegatingCachedTypeChecker(TypeChecker.Cached<EClassifier, EOperation, EStructuralFeature> delegate)
+ {
+ super(delegate);
+ this.delegate = delegate;
+ }
+
+ public EOperation getDynamicOperation(EClassifier dynamicType, EOperation staticOperation)
+ {
+ return delegate.getDynamicOperation(dynamicType, staticOperation);
+ }
+
+ public void reset()
+ {
+ delegate.reset();
+ }
+
+ public void setBypass(boolean bypass)
+ {
+ delegate.setBypass(bypass);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.ocl/src/org/eclipse/emf/cdo/server/ocl/CDOEnvironmentFactory.java b/plugins/org.eclipse.emf.cdo.server.ocl/src/org/eclipse/emf/cdo/server/ocl/CDOEnvironmentFactory.java
new file mode 100644
index 0000000000..301f485677
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.ocl/src/org/eclipse/emf/cdo/server/ocl/CDOEnvironmentFactory.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2004-2013 Eike Stepper (Berlin, Germany) and others.
+ * 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:
+ * Christian W. Damus (CEA LIST) - initial API and implementation
+ */
+package org.eclipse.emf.cdo.server.ocl;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.emf.ecore.EEnumLiteral;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EOperation;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EParameter;
+import org.eclipse.emf.ecore.EStructuralFeature;
+
+import org.eclipse.ocl.Environment;
+import org.eclipse.ocl.EvaluationEnvironment;
+import org.eclipse.ocl.ecore.CallOperationAction;
+import org.eclipse.ocl.ecore.Constraint;
+import org.eclipse.ocl.ecore.EcoreEnvironmentFactory;
+import org.eclipse.ocl.ecore.SendSignalAction;
+
+/**
+ * The factory of CDO-specific Ecore environments.
+ *
+ * @author Christian W. Damus
+ * @since 4.2
+ */
+class CDOEnvironmentFactory extends EcoreEnvironmentFactory
+{
+ public CDOEnvironmentFactory(EPackage.Registry packageRegistry)
+ {
+ super(packageRegistry);
+ }
+
+ public CDOEnvironmentFactory()
+ {
+ }
+
+ @Override
+ public Environment<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject> createEnvironment()
+ {
+ return new CDOEnvironment(this, null);
+ }
+
+ @Override
+ public Environment<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject> createEnvironment(
+ Environment<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject> parent)
+ {
+ return new CDOEnvironment(parent);
+ }
+
+ @Override
+ public EvaluationEnvironment<EClassifier, EOperation, EStructuralFeature, EClass, EObject> createEvaluationEnvironment()
+ {
+ return new CDOEvaluationEnvironment(this);
+ }
+
+ @Override
+ public EvaluationEnvironment<EClassifier, EOperation, EStructuralFeature, EClass, EObject> createEvaluationEnvironment(
+ EvaluationEnvironment<EClassifier, EOperation, EStructuralFeature, EClass, EObject> parent)
+ {
+ return new CDOEvaluationEnvironment(parent);
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.ocl/src/org/eclipse/emf/cdo/server/ocl/CDOEvaluationEnvironment.java b/plugins/org.eclipse.emf.cdo.server.ocl/src/org/eclipse/emf/cdo/server/ocl/CDOEvaluationEnvironment.java
new file mode 100644
index 0000000000..7b9a2fd01a
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.ocl/src/org/eclipse/emf/cdo/server/ocl/CDOEvaluationEnvironment.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2004-2013 Eike Stepper (Berlin, Germany) and others.
+ * 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:
+ * Christian W. Damus (CEA LIST) - initial API and implementation
+ */
+package org.eclipse.emf.cdo.server.ocl;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EOperation;
+import org.eclipse.emf.ecore.EStructuralFeature;
+
+import org.eclipse.ocl.EvaluationEnvironment;
+import org.eclipse.ocl.ecore.EcoreEnvironmentFactory;
+import org.eclipse.ocl.ecore.EcoreEvaluationEnvironment;
+
+/**
+ * A CDO-specific specialization of the OCL evaluation environment.
+ *
+ * @author Christian W. Damus
+ * @since 4.2
+ */
+class CDOEvaluationEnvironment extends EcoreEvaluationEnvironment
+{
+ public CDOEvaluationEnvironment(EcoreEnvironmentFactory factory)
+ {
+ super(factory);
+ }
+
+ public CDOEvaluationEnvironment(
+ EvaluationEnvironment<EClassifier, EOperation, EStructuralFeature, EClass, EObject> parent)
+ {
+ super(parent);
+ }
+
+ @Override
+ public Object callOperation(EOperation operation, int opcode, Object source, Object[] args)
+ throws IllegalArgumentException
+ {
+ CDOAdditionalOperation cdoOperation = CDOAdditionalOperation.getInstance(operation);
+ if (cdoOperation != null)
+ {
+ return cdoOperation.evaluate(this, source, args);
+ }
+
+ return super.callOperation(operation, opcode, source, args);
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.ocl/src/org/eclipse/emf/cdo/server/ocl/OCLQueryHandler.java b/plugins/org.eclipse.emf.cdo.server.ocl/src/org/eclipse/emf/cdo/server/ocl/OCLQueryHandler.java
index 3ea4971212..bce7cfe33a 100644
--- a/plugins/org.eclipse.emf.cdo.server.ocl/src/org/eclipse/emf/cdo/server/ocl/OCLQueryHandler.java
+++ b/plugins/org.eclipse.emf.cdo.server.ocl/src/org/eclipse/emf/cdo/server/ocl/OCLQueryHandler.java
@@ -7,6 +7,7 @@
*
* Contributors:
* Eike Stepper - initial API and implementation
+ * Christian W. Damus (CEA LIST) - Additional OCL operations for efficient queries
*/
package org.eclipse.emf.cdo.server.ocl;
@@ -205,9 +206,10 @@ public class OCLQueryHandler implements IQueryHandler
protected OCL<?, EClassifier, ?, ?, ?, ?, ?, ?, ?, Constraint, EClass, EObject> createOCL(CDOView view,
CDOExtentMap extentMap)
{
- EcoreEnvironmentFactory envFactory = new EcoreEnvironmentFactory(view.getSession().getPackageRegistry());
+ EcoreEnvironmentFactory envFactory = new CDOEnvironmentFactory(view.getSession().getPackageRegistry());
OCL<?, EClassifier, ?, ?, ?, ?, ?, ?, ?, Constraint, EClass, EObject> ocl = OCL.newInstance(envFactory);
+ CDOAdditionalOperation.registerOperations((CDOEnvironment)ocl.getEnvironment());
ocl.setExtentMap(extentMap);
return ocl;
}
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_416474_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_416474_Test.java
new file mode 100644
index 0000000000..00515ddc58
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_416474_Test.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2013 Eike Stepper (Berlin, Germany) and others.
+ * 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:
+ * Christian W. Damus (CEA LIST) - initial API and implementation
+ */
+package org.eclipse.emf.cdo.tests.bugzilla;
+
+import org.eclipse.emf.cdo.eresource.CDOResource;
+import org.eclipse.emf.cdo.session.CDOSession;
+import org.eclipse.emf.cdo.tests.AbstractCDOTest;
+import org.eclipse.emf.cdo.transaction.CDOTransaction;
+import org.eclipse.emf.cdo.view.CDOQuery;
+import org.eclipse.emf.cdo.view.CDOView;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EcoreFactory;
+import org.eclipse.emf.ecore.EcorePackage;
+
+import java.util.List;
+
+/**
+ * Bug 416474: [OCL] Add some non-standard operations to support efficient OCL queries
+ *
+ * @author Christian W. Damus (CEA LIST)
+ */
+public class Bugzilla_416474_Test extends AbstractCDOTest
+{
+ public void testAllProperContentsNoTypeFilter() throws Exception
+ {
+ EPackage root = createPackage("root_416474_1", "root_416474_1",
+ "http://www.eclipse.org/CDO/test/bug416474/Root_416474_1");
+ EClass a = createClass(root, "RootA_416474_1");
+ EClass b = createClass(root, "RootB_416474_1");
+
+ EPackage nested = createPackage("nested_416474_1", "nested_416474_1",
+ "http://www.eclipse.org/CDO/test/bug416474/Nested_416474_1");
+ createClass(nested, "NestedA_416474_1");
+ createClass(nested, "NestedB_416474_1");
+ root.getESubpackages().add(nested);
+
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource1 = transaction.createResource(getResourcePath("root_416474_1.ecore"));
+ resource1.getContents().add(root);
+ CDOResource resource2 = transaction.createResource(getResourcePath("nested_416474_1.ecore"));
+ resource2.getContents().add(nested);
+
+ transaction.commit();
+
+ CDOView newView = session.openView();
+ CDOQuery ocl = newView.createQuery("ocl",
+ "eresource::CDOResource.allInstances()->any(name='root_416474_1.ecore').cdoAllProperContents()",
+ EcorePackage.Literals.EPACKAGE);
+
+ List<?> results = ocl.getResult();
+ assertEquals(true, results.contains(newView.getObject(root)));
+ assertEquals(true, results.contains(newView.getObject(a)));
+ assertEquals(true, results.contains(newView.getObject(b)));
+ assertEquals(3, results.size());
+ }
+
+ public void testAllProperContentsTypeFilter() throws Exception
+ {
+ EPackage root = createPackage("root_416474_2", "root_416474_2",
+ "http://www.eclipse.org/CDO/test/bug416474/Root_416474_2");
+ createClass(root, "RootA_416474_2");
+ createClass(root, "RootB_416474_2");
+
+ EPackage nested = createPackage("nested_416474_2", "nested_416474_2",
+ "http://www.eclipse.org/CDO/test/bug416474/Nested_416474_2");
+ createClass(nested, "NestedA_416474_2");
+ createClass(nested, "NestedB_416474_2");
+ root.getESubpackages().add(nested);
+
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource1 = transaction.createResource(getResourcePath("root_416474_2.ecore"));
+ resource1.getContents().add(root);
+ CDOResource resource2 = transaction.createResource(getResourcePath("nested_416474_2.ecore"));
+ resource2.getContents().add(nested);
+
+ transaction.commit();
+
+ CDOView newView = session.openView();
+ CDOQuery ocl = newView
+ .createQuery(
+ "ocl",
+ "eresource::CDOResource.allInstances()->any(name='root_416474_2.ecore').cdoAllProperContents(EClass).name->asSet()",
+ EcorePackage.Literals.EPACKAGE);
+
+ List<?> results = ocl.getResult();
+ assertEquals(true, results.contains("RootA_416474_2"));
+ assertEquals(true, results.contains("RootB_416474_2"));
+ assertEquals(2, results.size());
+ }
+
+ public void testMatchesAnyStringAttribute() throws Exception
+ {
+ EPackage root = createPackage("root_416474_3", "root_416474_3",
+ "http://www.eclipse.org/CDO/test/bug416474/Root_416474_3");
+ createClass(root, "RootA_416474_3");
+ createClass(root, "RootB_416474_3");
+
+ EPackage nested = createPackage("nested_416474_3", "nested_416474_3",
+ "http://www.eclipse.org/CDO/test/bug416474/Nested_416474_3");
+ EClass a1 = createClass(nested, "NestedA_416474_3");
+ EClass b1 = createClass(nested, "NestedB_416474_3");
+ root.getESubpackages().add(nested);
+
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource1 = transaction.createResource(getResourcePath("root_416474_3.ecore"));
+ resource1.getContents().add(root);
+ CDOResource resource2 = transaction.createResource(getResourcePath("nested_416474_3.ecore"));
+ resource2.getContents().add(nested);
+
+ transaction.commit();
+
+ CDOView newView = session.openView();
+ CDOQuery ocl = newView.createQuery("ocl",
+ "EModelElement.allInstances()->select(e | e.cdoMatches('.*bug416474.*'))", EcorePackage.Literals.EPACKAGE);
+
+ List<?> results = ocl.getResult();
+ assertEquals(true, results.contains(newView.getObject(root)));
+ assertEquals(true, results.contains(newView.getObject(nested)));
+ assertEquals(2, results.size());
+
+ ocl = newView.createQuery("ocl", "EModelElement.allInstances()->select(e | e.cdoMatches('.*Nested.?_416474_3'))",
+ EcorePackage.Literals.EPACKAGE);
+
+ results = ocl.getResult();
+ assertEquals(true, results.contains(newView.getObject(nested)));
+ assertEquals(true, results.contains(newView.getObject(a1)));
+ assertEquals(true, results.contains(newView.getObject(b1)));
+ assertEquals(3, results.size());
+ }
+
+ private EPackage createPackage(String name, String nsPrefix, String nsURI)
+ {
+ EPackage result = EcoreFactory.eINSTANCE.createEPackage();
+ result.setName(name);
+ result.setNsPrefix(nsPrefix);
+ result.setNsURI(nsURI);
+ return result;
+ }
+
+ private EClass createClass(EPackage owner, String name)
+ {
+ EClass result = EcoreFactory.eINSTANCE.createEClass();
+ result.setName(name);
+ owner.getEClassifiers().add(result);
+ return result;
+ }
+}

Back to the top