Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian W. Damus2013-09-02 14:26:03 +0000
committerEike Stepper2013-09-02 18:04:49 +0000
commit84e430d5c931b8fcee93821c78a4d138a6f51e3f (patch)
treed89dc1f649e464074f81542a5dfecc7027c6b8ab
parentf2b28a2742a13e0a12090d03d2c422cd3da8be59 (diff)
downloadcdo-84e430d5c931b8fcee93821c78a4d138a6f51e3f.tar.gz
cdo-84e430d5c931b8fcee93821c78a4d138a6f51e3f.tar.xz
cdo-84e430d5c931b8fcee93821c78a4d138a6f51e3f.zip
416366: [CDO] Support implicit root class in server-side CDO queries
https://bugs.eclipse.org/bugs/show_bug.cgi?id= 416366 Add a 'cdoImplicitRootClass' query option to the OCLQueryHandler, similar to the existing 'cdoLazyExtents'. The value is an EClass, default is null. Because the value is an EClass, it is not supported as a variable that is passed through to the OCL expression parsing and evaluation environments, so it is filtered out of the OCL environment. The lazy-extent parameter also doesn't make sense in the OCL expression. Change-Id: Ic4c40965fcce2dad092943a526b75a816421ea31
-rw-r--r--plugins/org.eclipse.emf.cdo.server.ocl/src/org/eclipse/emf/cdo/server/ocl/OCLQueryHandler.java350
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_416366_Test.java79
2 files changed, 321 insertions, 108 deletions
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 8b13b075f2..cb666d1609 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
@@ -22,7 +22,6 @@ import org.eclipse.emf.cdo.common.util.CDOQueryInfo;
import org.eclipse.emf.cdo.server.CDOServerUtil;
import org.eclipse.emf.cdo.server.IQueryContext;
import org.eclipse.emf.cdo.server.IQueryHandler;
-import org.eclipse.emf.cdo.server.ISession;
import org.eclipse.emf.cdo.spi.common.commit.CDOChangeSetDataRevisionProvider;
import org.eclipse.emf.cdo.spi.server.QueryHandlerFactory;
import org.eclipse.emf.cdo.view.CDOView;
@@ -44,6 +43,7 @@ import org.eclipse.emf.spi.cdo.InternalCDOObject;
import org.eclipse.ocl.Environment;
import org.eclipse.ocl.EvaluationEnvironment;
import org.eclipse.ocl.OCL;
+import org.eclipse.ocl.ParserException;
import org.eclipse.ocl.Query;
import org.eclipse.ocl.ecore.BooleanLiteralExp;
import org.eclipse.ocl.ecore.Constraint;
@@ -56,10 +56,13 @@ import org.eclipse.ocl.ecore.StringLiteralExp;
import org.eclipse.ocl.expressions.OCLExpression;
import org.eclipse.ocl.expressions.Variable;
import org.eclipse.ocl.helper.OCLHelper;
+import org.eclipse.ocl.options.ParsingOptions;
import org.eclipse.ocl.types.OCLStandardLibrary;
import org.eclipse.ocl.util.ProblemAware;
+import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
@@ -79,35 +82,34 @@ public class OCLQueryHandler implements IQueryHandler
*/
public static final String LAZY_EXTENTS_PARAMETER = "cdoLazyExtents";
+ /**
+ * Query parameter indicating the {@link EClass} to set as the implicit root class of the type
+ * hierarchy. The default is {@code null}.
+ *
+ * @since 4.2
+ */
+ public static final String IMPLICIT_ROOT_CLASS_PARAMETER = "cdoImplicitRootClass";
+
+ private static final Set<String> SERVER_QUERY_PARAMETERS = Collections.unmodifiableSet(new java.util.HashSet<String>(
+ Arrays.asList(LAZY_EXTENTS_PARAMETER, IMPLICIT_ROOT_CLASS_PARAMETER)));
+
private static final EcoreFactory FACTORY = EcoreFactory.eINSTANCE;
private boolean lazyExtents = true;
+ private EClass implicitRootClass;
+
public OCLQueryHandler()
{
}
public void executeQuery(CDOQueryInfo info, IQueryContext context)
{
- String queryString = info.getQueryString();
CDOExtentMap extentMap = null;
try
{
- Map<String, Object> queryParameters = info.getParameters();
- Object o = queryParameters.get(LAZY_EXTENTS_PARAMETER);
- if (o != null)
- {
- try
- {
- lazyExtents = (Boolean)o;
- }
- catch (ClassCastException ex)
- {
- throw new IllegalArgumentException("Parameter " + LAZY_EXTENTS_PARAMETER + " must be a boolean but it is a "
- + o + " class " + o.getClass().getName(), ex);
- }
- }
+ readParameters(info.getParameters());
CDORevisionProvider revisionProvider = context.getView();
CDOChangeSetData changeSetData = info.getChangeSetData();
@@ -116,74 +118,15 @@ public class OCLQueryHandler implements IQueryHandler
revisionProvider = new CDOChangeSetDataRevisionProvider(revisionProvider, changeSetData);
}
- ISession session = context.getView().getSession();
- CDOView view = CDOServerUtil.openView(session, context, revisionProvider);
- CDOPackageRegistry packageRegistry = view.getSession().getPackageRegistry();
-
- EcoreEnvironmentFactory envFactory = new EcoreEnvironmentFactory(packageRegistry);
- OCL<?, EClassifier, ?, ?, ?, ?, ?, ?, ?, Constraint, EClass, EObject> ocl = OCL.newInstance(envFactory);
-
+ CDOView view = CDOServerUtil.openView(context.getView().getSession(), context, revisionProvider);
extentMap = createExtentMap(view, changeSetData, context);
- ocl.setExtentMap(extentMap);
-
- OCLHelper<EClassifier, ?, ?, Constraint> helper = ocl.createOCLHelper();
-
- EClassifier classifier;
- EObject object = null;
+ OCL<?, EClassifier, ?, ?, ?, ?, ?, ?, ?, Constraint, EClass, EObject> ocl = createOCL(view, extentMap);
- Object contextParameter = info.getContext();
- if (contextParameter instanceof CDOID)
- {
- CDOID id = (CDOID)contextParameter;
- if (id.isNull())
- {
- classifier = getArbitraryContextClassifier(packageRegistry);
- }
- else
- {
- InternalCDOObject cdoObject = (InternalCDOObject)view.getObject(id);
- object = cdoObject.cdoInternalInstance();
- classifier = object.eClass();
- }
- }
- else if (contextParameter instanceof EClassifier)
- {
- classifier = (EClassifier)contextParameter;
- }
- else
- {
- classifier = getArbitraryContextClassifier(packageRegistry);
- }
-
- helper.setContext(classifier);
-
- Environment<?, EClassifier, ?, ?, ?, ?, ?, ?, ?, Constraint, EClass, EObject> environment = ocl.getEnvironment();
- Map<String, Object> parameters = new HashMap<String, Object>(queryParameters);
- initEnvironment(environment, packageRegistry, parameters);
-
- OCLExpression<EClassifier> expr = helper.createQuery(queryString);
- Query<EClassifier, EClass, EObject> query = ocl.createQuery(expr);
- if (query instanceof ProblemAware)
- {
- ProblemAware problemAware = (ProblemAware)query;
- Diagnostic problems = problemAware.getProblems();
- if (problems != null)
- {
- throw new DiagnosticException(problems);
- }
- }
-
- EvaluationEnvironment<EClassifier, ?, ?, EClass, EObject> evalEnv = query.getEvaluationEnvironment();
- Set<Entry<String, Object>> entrySet = parameters.entrySet();
- for (Entry<String, Object> parameter : entrySet)
- {
- String key = parameter.getKey();
- Object value = parameter.getValue();
- evalEnv.add(key, value);
- }
+ ContextParameter contextParameter = new ContextParameter(view, info);
+ Query<EClassifier, EClass, EObject> query = createQuery(view, info, contextParameter, ocl);
- Object result = evaluate(query, object);
- if (result == environment.getOCLStandardLibrary().getInvalid())
+ Object result = evaluate(query, contextParameter.getObject());
+ if (result == ocl.getEnvironment().getOCLStandardLibrary().getInvalid())
{
throw new Exception(
"OCL query evaluated to 'invalid'. Run with '-Dorg.eclipse.ocl.debug=true' and visit the log for failure details.");
@@ -206,7 +149,7 @@ public class OCLQueryHandler implements IQueryHandler
}
catch (Exception ex)
{
- throw WrappedException.wrap(ex, "Problem executing OCL query: " + queryString);
+ throw WrappedException.wrap(ex, "Problem executing OCL query: " + info.getQueryString());
}
finally
{
@@ -256,46 +199,98 @@ public class OCLQueryHandler implements IQueryHandler
return lazyExtents;
}
- protected EClassifier getArbitraryContextClassifier(CDOPackageRegistry packageRegistry)
+ /**
+ * @since 4.2
+ */
+ protected OCL<?, EClassifier, ?, ?, ?, ?, ?, ?, ?, Constraint, EClass, EObject> createOCL(CDOView view,
+ CDOExtentMap extentMap)
+ {
+ EcoreEnvironmentFactory envFactory = new EcoreEnvironmentFactory(view.getSession().getPackageRegistry());
+
+ OCL<?, EClassifier, ?, ?, ?, ?, ?, ?, ?, Constraint, EClass, EObject> ocl = OCL.newInstance(envFactory);
+ ocl.setExtentMap(extentMap);
+ return ocl;
+ }
+
+ /**
+ * @since 4.2
+ */
+ protected Query<EClassifier, EClass, EObject> createQuery(CDOView view, CDOQueryInfo info,
+ ContextParameter contextParameter, OCL<?, EClassifier, ?, ?, ?, ?, ?, ?, ?, Constraint, EClass, EObject> ocl)
+ throws ParserException, DiagnosticException
{
- for (CDOPackageUnit packageUnit : packageRegistry.getPackageUnits())
+ Map<String, Object> parameters = new HashMap<String, Object>(info.getParameters());
+ initEnvironment(ocl.getEnvironment(), view.getSession().getPackageRegistry(), parameters);
+
+ OCLHelper<EClassifier, ?, ?, Constraint> helper = ocl.createOCLHelper();
+ helper.setContext(contextParameter.getClassifier());
+
+ OCLExpression<EClassifier> expr = helper.createQuery(info.getQueryString());
+ Query<EClassifier, EClass, EObject> query = ocl.createQuery(expr);
+ if (query instanceof ProblemAware)
{
- for (CDOPackageInfo packageInfo : packageUnit.getPackageInfos())
+ ProblemAware problemAware = (ProblemAware)query;
+ Diagnostic problems = problemAware.getProblems();
+ if (problems != null)
{
- if (!packageUnit.isSystem())
- {
- for (EClassifier classifier : packageInfo.getEPackage().getEClassifiers())
- {
- return classifier;
- }
- }
+ throw new DiagnosticException(problems);
}
}
- throw new IllegalStateException("Context missing");
+ setOCLQueryParameters(parameters, query);
+ return query;
+ }
+
+ /**
+ * @deprecated As of 4.2 no longer supported.
+ */
+ @Deprecated
+ protected EClassifier getArbitraryContextClassifier(CDOPackageRegistry packageRegistry)
+ {
+ return ContextParameter.getArbitraryContextClassifier(packageRegistry);
}
protected void initEnvironment(
Environment<?, EClassifier, ?, ?, ?, ?, ?, ?, ?, Constraint, EClass, EObject> environment,
CDOPackageRegistry packageRegistry, Map<String, Object> parameters)
{
+
+ // initialize parsing options
+ EClass implicitRootClass = getImplicitRootClass();
+ if (implicitRootClass != null)
+ {
+ ParsingOptions.setOption(environment, ParsingOptions.implicitRootClass(environment), implicitRootClass);
+ }
+
+ // create variables for query parameters that should be passed through to the OCL query expression
OCLStandardLibrary<EClassifier> stdLib = environment.getOCLStandardLibrary();
for (Entry<String, Object> parameter : parameters.entrySet())
{
String name = parameter.getKey();
- Object value = parameter.getValue();
+ if (isOCLQueryParameter(name))
+ {
+ Object value = parameter.getValue();
- OCLExpression<EClassifier> initExpression = createInitExpression(stdLib, packageRegistry, value);
+ OCLExpression<EClassifier> initExpression = createInitExpression(stdLib, packageRegistry, value);
- Variable<EClassifier, ?> variable = FACTORY.createVariable();
- variable.setName(name);
- variable.setType(initExpression.getType());
- variable.setInitExpression(initExpression);
+ Variable<EClassifier, ?> variable = FACTORY.createVariable();
+ variable.setName(name);
+ variable.setType(initExpression.getType());
+ variable.setInitExpression(initExpression);
- addEnvironmentVariable(environment, variable);
+ addEnvironmentVariable(environment, variable);
+ }
}
}
+ /**
+ * @since 4.2
+ */
+ protected EClass getImplicitRootClass()
+ {
+ return implicitRootClass;
+ }
+
protected OCLExpression<EClassifier> createInitExpression(OCLStandardLibrary<EClassifier> stdLib,
CDOPackageRegistry packageRegistry, Object value)
{
@@ -355,6 +350,81 @@ public class OCLQueryHandler implements IQueryHandler
throw new IllegalArgumentException("Unrecognized parameter type: " + value.getClass().getName());
}
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ protected void addEnvironmentVariable(
+ Environment<?, EClassifier, ?, ?, ?, ?, ?, ?, ?, Constraint, EClass, EObject> environment,
+ Variable<EClassifier, ?> variable)
+ {
+ environment.addElement(variable.getName(), (Variable)variable, true);
+ }
+
+ /**
+ * @since 4.2
+ */
+ protected void readParameters(Map<String, ?> queryParameters)
+ {
+ lazyExtents = readParameter(queryParameters, LAZY_EXTENTS_PARAMETER, lazyExtents);
+ implicitRootClass = readParameter(queryParameters, IMPLICIT_ROOT_CLASS_PARAMETER, EClass.class, implicitRootClass);
+ }
+
+ /**
+ * @since 4.2
+ */
+ protected boolean readParameter(Map<String, ?> queryParameters, String name, boolean defaultValue)
+ {
+ return readParameter(queryParameters, name, Boolean.class, defaultValue);
+ }
+
+ /**
+ * @since 4.2
+ */
+ protected <T> T readParameter(Map<String, ?> queryParameters, String name, Class<T> type, T defaultValue)
+ {
+ T result = defaultValue;
+
+ Object o = queryParameters.get(name);
+ if (o != null)
+ {
+ try
+ {
+ result = type.cast(o);
+ }
+ catch (ClassCastException ex)
+ {
+ throw new IllegalArgumentException("Parameter " + name + " must be a " + type.getSimpleName() + " but it is a "
+ + o + " class " + o.getClass().getName(), ex);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * @since 4.2
+ */
+ protected void setOCLQueryParameters(Map<String, Object> parameters, Query<EClassifier, EClass, EObject> query)
+ {
+ EvaluationEnvironment<EClassifier, ?, ?, EClass, EObject> evalEnv = query.getEvaluationEnvironment();
+ for (Entry<String, Object> parameter : parameters.entrySet())
+ {
+ String key = parameter.getKey();
+
+ if (isOCLQueryParameter(key))
+ {
+ Object value = parameter.getValue();
+ evalEnv.add(key, value);
+ }
+ }
+ }
+
+ /**
+ * @since 4.2
+ */
+ protected boolean isOCLQueryParameter(String name)
+ {
+ return !SERVER_QUERY_PARAMETERS.contains(name);
+ }
+
private Integer getInteger(Object value)
{
if (value instanceof Integer)
@@ -390,14 +460,6 @@ public class OCLQueryHandler implements IQueryHandler
return null;
}
- @SuppressWarnings({ "unchecked", "rawtypes" })
- protected void addEnvironmentVariable(
- Environment<?, EClassifier, ?, ?, ?, ?, ?, ?, ?, Constraint, EClass, EObject> environment,
- Variable<EClassifier, ?> variable)
- {
- environment.addElement(variable.getName(), (Variable)variable, true);
- }
-
public static void prepareContainer(IManagedContainer container)
{
container.registerFactory(new Factory());
@@ -421,4 +483,76 @@ public class OCLQueryHandler implements IQueryHandler
return new OCLQueryHandler();
}
}
+
+ /**
+ * @author Eike Stepper
+ * @since 4.2
+ */
+ private static final class ContextParameter
+ {
+ private final EClassifier classifier;
+
+ private final EObject object;
+
+ public ContextParameter(CDOView view, CDOQueryInfo info)
+ {
+ Object contextParameter = info.getContext();
+ if (contextParameter instanceof CDOID)
+ {
+ CDOID id = (CDOID)contextParameter;
+ if (id.isNull())
+ {
+ CDOPackageRegistry packageRegistry = view.getSession().getPackageRegistry();
+ classifier = getArbitraryContextClassifier(packageRegistry);
+ object = null;
+ }
+ else
+ {
+ InternalCDOObject cdoObject = (InternalCDOObject)view.getObject(id);
+ classifier = cdoObject.eClass();
+ object = cdoObject.cdoInternalInstance();
+ }
+ }
+ else if (contextParameter instanceof EClassifier)
+ {
+ classifier = (EClassifier)contextParameter;
+ object = null;
+ }
+ else
+ {
+ CDOPackageRegistry packageRegistry = view.getSession().getPackageRegistry();
+ classifier = getArbitraryContextClassifier(packageRegistry);
+ object = null;
+ }
+ }
+
+ public EClassifier getClassifier()
+ {
+ return classifier;
+ }
+
+ public EObject getObject()
+ {
+ return object;
+ }
+
+ private static EClassifier getArbitraryContextClassifier(CDOPackageRegistry packageRegistry)
+ {
+ for (CDOPackageUnit packageUnit : packageRegistry.getPackageUnits())
+ {
+ for (CDOPackageInfo packageInfo : packageUnit.getPackageInfos())
+ {
+ if (!packageUnit.isSystem())
+ {
+ for (EClassifier classifier : packageInfo.getEPackage().getEClassifiers())
+ {
+ return classifier;
+ }
+ }
+ }
+ }
+
+ throw new IllegalStateException("Context missing");
+ }
+ }
}
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_416366_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_416366_Test.java
new file mode 100644
index 0000000000..4433a4c5b6
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_416366_Test.java
@@ -0,0 +1,79 @@
+/*
+ * 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.tests.model5.Child;
+import org.eclipse.emf.cdo.tests.model5.Parent;
+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.EcorePackage;
+
+import java.util.List;
+
+/**
+ * Bug 416366: Support implicit root class in OCL queries
+ *
+ * @author Christian W. Damus (CEA LIST)
+ */
+public class Bugzilla_416366_Test extends AbstractCDOTest
+{
+ public void testImplicitEObjectFeatures() throws Exception
+ {
+ Parent parentA = createParent("A");
+ parentA.getChildren().add(createChild("A1"));
+ parentA.getChildren().add(createChild("A2"));
+
+ Parent parentB = createParent("B");
+ parentB.getChildren().add(createChild("B1"));
+ parentB.getChildren().add(createChild("B2"));
+
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.createResource(getResourcePath("test-resource"));
+ resource.getContents().add(parentA);
+ resource.getContents().add(parentB);
+
+ transaction.commit();
+
+ CDOView newView = session.openView();
+ CDOQuery ocl = newView.createQuery("ocl",
+ "Child.allInstances()->select(c|c.eContainer().oclAsType(Parent).name = 'B')", getModel5Package().getChild());
+
+ // eContainer() is inherited implicitly from EObject
+ ocl.setParameter("cdoImplicitRootClass", EcorePackage.Literals.EOBJECT);
+
+ List<Child> results = ocl.getResult(Child.class);
+ assertEquals(2, results.size());
+
+ // They are children of B
+ assertEquals(true, parentB.getChildren().contains(transaction.getObject(results.get(0))));
+ assertEquals(true, parentB.getChildren().contains(transaction.getObject(results.get(1))));
+ }
+
+ private Parent createParent(String name)
+ {
+ Parent result = getModel5Factory().createParent();
+ result.setName(name);
+ return result;
+ }
+
+ private Child createChild(String name)
+ {
+ Child result = getModel5Factory().createChild();
+ result.setName(name);
+ return result;
+ }
+}

Back to the top