diff options
author | Christian W. Damus | 2013-09-04 07:27:01 +0000 |
---|---|---|
committer | Eike Stepper | 2013-09-04 07:27:01 +0000 |
commit | 63f73fefd48ad3c408924221931d98df132d44ba (patch) | |
tree | db0ef3745b3fb81f4d533ae514f4c6d6865f6ac4 | |
parent | 971b3c85d0e1d6ad07f6113f7e71cc7ea83f4c44 (diff) | |
download | cdo-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
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; + } +} |