/*******************************************************************************
* Copyright (c) 2009, 2010 SAP AG 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:
* SAP AG - initial API and implementation
******************************************************************************/
package de.hpi.sam.bp2009.solution.oclToMqlMapping.impl;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EParameter;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.query.index.IndexFactory;
import org.eclipse.emf.query2.FromEntry;
import org.eclipse.emf.query2.FromType;
import org.eclipse.emf.query2.LocalWhereEntry;
import org.eclipse.emf.query2.Operation;
import org.eclipse.emf.query2.Query;
import org.eclipse.emf.query2.QueryContext;
import org.eclipse.emf.query2.QueryProcessor;
import org.eclipse.emf.query2.QueryProcessorFactory;
import org.eclipse.emf.query2.ResultSet;
import org.eclipse.emf.query2.SelectAlias;
import org.eclipse.emf.query2.SelectAttrs;
import org.eclipse.emf.query2.SelectEntry;
import org.eclipse.emf.query2.WhereComparisonAliases;
import org.eclipse.emf.query2.WhereComparisonAttrs;
import org.eclipse.emf.query2.WhereEntry;
import org.eclipse.emf.query2.WhereInt;
import org.eclipse.emf.query2.WhereNestedReference;
import org.eclipse.emf.query2.WhereRelationReference;
import org.eclipse.ocl.ecore.OperationCallExp;
import org.eclipse.ocl.ecore.PropertyCallExp;
import org.eclipse.ocl.expressions.IteratorExp;
import org.eclipse.ocl.expressions.OCLExpression;
import org.eclipse.ocl.util.OCLStandardLibraryUtil;
import org.eclipse.ocl.utilities.PredefinedType;
import de.hpi.sam.bp2009.solution.queryContextScopeProvider.impl.ProjectBasedQueryContextScopeProviderImpl;
public class Query2 {
/**
* buildMqlQuery prepares for each Predefined type of the Iterator Expression a matching Query 2 after mapping all parts of
* the Expression, the query 2 will be executed
*
* @param contextObjects
* a Set<EObject> for setting the Query Context
* @param ocType
* an Object for building the scope for Query 2
* @param body
* is the OCLExpression, this must be the body of the IteratorExp for mapping all parts of the Expression to Query
* 2
* @param itExp
* is the IteratorExp, needed to defined the different mapping for each Predefined Type
* @param mapEvalVisitor
* is the Mapping Evaluation Visitor, needed to instantiate a second Visitor to map the expression
* @return result
*/
public Object buildMqlQuery(Set<EObject> contextObjects, EClassifier ocType, OCLExpression<EClassifier> body,
IteratorExp<EClassifier, EParameter> itExp, MappingEvaluationVisitor mapEvalVisitor) {
switch (OCLStandardLibraryUtil.getOperationCode(itExp.getName())) {
case PredefinedType.SELECT:
return mappingForSelect(contextObjects, body, ocType);
case PredefinedType.COLLECT:
return mappingForCollect(contextObjects, body, ocType);
case PredefinedType.EXISTS:
case PredefinedType.FOR_ALL:
case PredefinedType.ANY:
case PredefinedType.REJECT:
case PredefinedType.COLLECT_NESTED:
case PredefinedType.ONE:
case PredefinedType.SORTED_BY:
case PredefinedType.IS_UNIQUE:
case PredefinedType.CLOSURE:
default:
return null;
}
}
private Collection<EObject> mappingForSelect(Set<EObject> contextObjects, OCLExpression<EClassifier> body, EClassifier ocType) {
if(body instanceof OperationCallExp){
OCLExpression<EClassifier> bodySource = ((OperationCallExp)body).getSource();
if(bodySource instanceof PropertyCallExp){
OCLExpression<EClassifier> bodySourceSource = ((PropertyCallExp)bodySource).getSource();
if (bodySourceSource instanceof PropertyCallExp){
EStructuralFeature prop = ((PropertyCallExp) bodySourceSource).getReferredProperty();
if (prop instanceof EReference) {
return selectOverBodyWithNavigation(contextObjects, body, ocType);
}
}else{
OCLExpression<EClassifier> arg = ((OperationCallExp) body).getArgument().get(0);
if (arg instanceof PropertyCallExp){
OCLExpression<EClassifier> argSource = ((PropertyCallExp)arg).getSource();
if(argSource instanceof PropertyCallExp){
PropertyCallExp src = (PropertyCallExp) argSource;
EStructuralFeature prop = src.getReferredProperty();
if (prop instanceof EReference) {
return selectOverBodyWithComparisonAndNavigation(body, ocType, null);
}
}else{
return selectOverBodyWithComparisonWithoutNavigation(null, body, ocType);
}
}else{
return selectOverBodyWithCondition(null, body, ocType);
}
}
}
}
return null;
}
private Map<?, Integer> mappingForCollect(Set<EObject> contextObjects, OCLExpression<EClassifier> body, EClassifier ocType) {
if (body instanceof PropertyCallExp) {
EStructuralFeature prop = ((PropertyCallExp) body).getReferredProperty();
if (prop instanceof EReference) {
return collectOverReference(contextObjects, body, ocType);
}
if (prop instanceof EAttribute) {
return collectOverAttribute(contextObjects, body, ocType);
}
}
// body is of type OperationCallExpression -> the expression can not be mapped
return null;
}
private Collection<EObject> selectOverBodyWithNavigation(Set<EObject> contextObjects, OCLExpression<EClassifier> body, EClassifier ocType) {
Collection<EObject> result = null;
ResultSet resultSet = null;
QueryContext queryContext = new ProjectBasedQueryContextScopeProviderImpl(contextObjects.toArray(new EObject[contextObjects.size()])).getForwardScopeAsQueryContext();
QueryProcessor queryProcessor = QueryProcessorFactory.getDefault().createQueryProcessor(IndexFactory.getInstance());
URI uri = EcoreUtil.getURI(ocType);
OCLExpression<EClassifier> bodySource = ((OperationCallExp) body).getSource();
OCLExpression<EClassifier> bodySourceSource = ((PropertyCallExp)bodySource).getSource();
EStructuralFeature prop = ((PropertyCallExp) bodySourceSource).getReferredProperty();
String ali = ((PropertyCallExp) bodySourceSource).getSource().getName();
try {
// select over body with navigation
// "select "+ali+" from [" + uri1 + "] as "+ali+" where "+nav+" in ( select p2 from [" +
// uri2+"] as p2 where p2." + cond+")"
URI uri2 = EcoreUtil.getURI(((EReference) prop).getEType());
String ali2 = ali.concat("_");
Operation operation = mapStringToOperation(((OperationCallExp) body).getReferredOperation().getName());
Integer value = new Integer(((OperationCallExp) body).getArgument().get(0).toString());
SelectEntry nestedSelect = new SelectAlias(ali2);
FromEntry nestedFrom = new FromType(ali2, uri2, /* withoutSubtypes */true);
WhereInt whereLong = new WhereInt(((PropertyCallExp)bodySource).getReferredProperty().getName(), operation, value);
LocalWhereEntry nestedWhere = new LocalWhereEntry(ali2, whereLong);
Query nestedQuery = new Query(new SelectEntry[] { nestedSelect }, new FromEntry[] { nestedFrom },
new WhereEntry[] { nestedWhere });
SelectEntry select = new SelectAlias(ali);
FromEntry from = new FromType(ali, uri, /* withoutSubtypes */true);
WhereNestedReference where = new WhereNestedReference(ali, prop.getName(), nestedQuery);
Query query = new Query(new SelectEntry[] { select }, new FromEntry[] { from }, new WhereEntry[] { where });
resultSet = queryProcessor.execute(query, queryContext);
} catch (RuntimeException e) {
} finally {
result = buildResult(resultSet, queryContext, ali);
}
return result;
}
private Collection<EObject> selectOverBodyWithCondition(Set<EObject> contextObjects, OCLExpression<EClassifier> body, EClassifier ocType) {
Collection<EObject> result = null;
ResultSet resultSet = null;
QueryContext queryContext = new ProjectBasedQueryContextScopeProviderImpl(contextObjects.toArray(new EObject[contextObjects.size()])).getForwardScopeAsQueryContext();
QueryProcessor queryProcessor = QueryProcessorFactory.getDefault().createQueryProcessor(IndexFactory.getInstance());
URI uri = EcoreUtil.getURI(ocType);
OCLExpression<EClassifier> bodySource = ((OperationCallExp) body).getSource();
String ali = ((PropertyCallExp) bodySource).getSource().getName();
try {
// select over body with condition
// "select "+ ali+" from [" + uri1 + "] as "+ali+" where " + stringBody
String attrName = ((PropertyCallExp) bodySource).getReferredProperty().getName();
Operation operation = mapStringToOperation(((OperationCallExp) body).getReferredOperation().getName());
Integer value = new Integer(((OperationCallExp) body).getArgument().get(0).toString());
SelectEntry select = new SelectAlias(ali);
FromEntry from = new FromType(ali, uri, true);
WhereInt whereLong = new WhereInt(attrName, operation, value);
LocalWhereEntry where = new LocalWhereEntry(ali, whereLong);
Query query = new Query(new SelectEntry[] { select }, new FromEntry[] { from }, new WhereEntry[] { where });
resultSet = queryProcessor.execute(query, queryContext);
} catch (RuntimeException e) {
} finally {
result = buildResult(resultSet, queryContext, ali);
}
return result;
}
private Collection<EObject> selectOverBodyWithComparisonAndNavigation(OCLExpression<EClassifier> body, EClassifier ocType, Set<EObject> contextObjects) {
Collection<EObject> result = null;
ResultSet resultSet = null;
QueryContext queryContext = new ProjectBasedQueryContextScopeProviderImpl(contextObjects.toArray(new EObject[contextObjects.size()])).getForwardScopeAsQueryContext();
QueryProcessor queryProcessor = QueryProcessorFactory.getDefault().createQueryProcessor(IndexFactory.getInstance());
URI uri = EcoreUtil.getURI(ocType);
OCLExpression<EClassifier> arg = ((OperationCallExp) body).getArgument().get(0);
OCLExpression<EClassifier> argSource = ((PropertyCallExp)arg).getSource();
PropertyCallExp src = (PropertyCallExp) argSource;
EStructuralFeature prop = src.getReferredProperty();
String ali = src.getSource().toString();
try {
// select over body with a comparison with navigation
// "select "+ ali+" from [" + uri1 + "] as "+ali+" ,["+uri2+"] as p3 where " +nav+"=p3 where "+ali+ cond+ "p3."+ cond2
EClassifier propType = ((EReference) prop).getEType();
URI uri2 = EcoreUtil.getURI(propType);
PropertyCallExp bodySource = ((PropertyCallExp) ((OperationCallExp) body).getSource());
String ali2 = bodySource.getSource().toString();
if (ali.equals(ali2)) {
ali2 = ali2.concat("_");
}
String navName = prop.getName();
Operation operation = mapStringToOperation(((OperationCallExp) body).getReferredOperation().getName());
SelectEntry select = new SelectAlias(ali);
FromEntry from1 = new FromType(ali, uri, /* withoutSubtypes */true);
FromEntry from2 = new FromType(ali2, uri2, /* withoutSubtypes */true);
WhereRelationReference where1 = new WhereRelationReference(ali, navName, ali2);
WhereComparisonAttrs where2 = new WhereComparisonAttrs(ali, bodySource.getReferredProperty().getName(),
operation, ali2, ((PropertyCallExp) arg).getReferredProperty().getName());
Query query = new Query(new SelectEntry[] { select }, new FromEntry[] { from1, from2 }, new WhereEntry[] {
where1, where2 });
resultSet = queryProcessor.execute(query, queryContext);
} catch (RuntimeException e) { }
finally {
result = buildResult(resultSet, queryContext, ali);
}
return result;
}
private Collection<EObject> selectOverBodyWithComparisonWithoutNavigation(Set<EObject> contextObjects, OCLExpression<EClassifier> body, EClassifier ocType) {
Collection<EObject> result = null;
ResultSet resultSet = null;
QueryContext queryContext = new ProjectBasedQueryContextScopeProviderImpl(contextObjects.toArray(new EObject[contextObjects.size()])).getForwardScopeAsQueryContext();
QueryProcessor queryProcessor = QueryProcessorFactory.getDefault().createQueryProcessor(IndexFactory.getInstance());
URI uri = EcoreUtil.getURI(ocType);
OCLExpression<EClassifier> bodySource = ((OperationCallExp) body).getSource();
String ali = ((PropertyCallExp) bodySource).getSource().getName();
try {
// select over body with a comparison without navigation
// "select "+ ali+" from [" + uri1 + "] as p , ["+uri1+"] as "+ali+" where "+ali+"=p where "+cond
String ali2 = ali.concat("_");
String leftAttrName = ((PropertyCallExp) bodySource).getReferredProperty().getName();
String eOp = ((OperationCallExp) body).getReferredOperation().getName();
Operation operation = mapStringToOperation(eOp);
OCLExpression<EClassifier> rightProperty = ((OperationCallExp) body).getArgument().get(0);
if (!(rightProperty instanceof PropertyCallExp)) {
throw new RuntimeException();
}
String rightAlias = ((PropertyCallExp) rightProperty).getSource().getName();
String rightAttrName = ((PropertyCallExp) rightProperty).getReferredProperty().getName();
SelectEntry select = new SelectAlias(ali);
FromEntry from1 = new FromType(ali2, uri, /* withoutSubtypes */true);
FromEntry from2 = new FromType(ali, uri, /* withoutSubtypes */true);
WhereComparisonAliases where1 = new WhereComparisonAliases(ali, ali2);
WhereComparisonAttrs where2 = new WhereComparisonAttrs(ali2, leftAttrName, operation, rightAlias,
rightAttrName);
Query query = new Query(new SelectEntry[] { select }, new FromEntry[] { from1, from2 }, new WhereEntry[] {
where1, where2 });
resultSet = queryProcessor.execute(query, queryContext);
} catch (RuntimeException e) {
} finally {
result = buildResult(resultSet, queryContext, ali);
}
return result;
}
private Map<EObject, Integer> collectOverReference(Set<EObject> contextObjects, OCLExpression<EClassifier> body, EClassifier ocType) {
Map<EObject, Integer> result = null;
ResultSet resultSet = null;
QueryContext queryContext = new ProjectBasedQueryContextScopeProviderImpl(contextObjects.toArray(new EObject[contextObjects.size()])).getForwardScopeAsQueryContext();
QueryProcessor queryProcessor = QueryProcessorFactory.getDefault().createQueryProcessor(IndexFactory.getInstance());
URI uri = EcoreUtil.getURI(ocType);
// collect over an association
// "select "+ali2+" from [" + uri1 + "] as "+ali+" , [" +uri2+ "] as " + ali2 + " where "+ stringBody
// +" in (select p2 from ["+uri2+"] as p2
URI uri2 = EcoreUtil.getURI(((EReference) ((PropertyCallExp) body).getReferredProperty()).getEType());
String ali = ((PropertyCallExp) body).getSource().getName();
String ali2 = ali.concat("_");
try {
String ali3 = ali2.concat("_");
SelectEntry nestedSelect = new SelectAlias(ali3);
FromEntry nestedFrom = new FromType(ali3, uri2, /* withoutSubtypes */true);
Query nestedQuery = new Query(new SelectEntry[] { nestedSelect }, new FromEntry[] { nestedFrom });
SelectEntry select = new SelectAlias(ali2);
FromEntry from1 = new FromType(ali, uri, /* withoutSubtypes */true);
FromEntry from2 = new FromType(ali2, uri2, /* withoutSubtypes */true);
WhereNestedReference where = new WhereNestedReference(ali, ((PropertyCallExp) body).getReferredProperty().getName(),
nestedQuery);
Query query = new Query(new SelectEntry[] { select }, new FromEntry[] { from1, from2 }, new WhereEntry[] { where });
resultSet = queryProcessor.execute(query, queryContext);
} catch (RuntimeException e) { }
finally {
result = new HashMap<EObject, Integer>();
if (!resultSet.isEmpty()) {
int count = 1;
for (int i = 0; i < resultSet.getSize(); i++) {
EObject value = queryContext.getResourceSet().getEObject(resultSet.getUri(i, ali2), /* loadOnDemand */true); //$NON-NLS-1$
if (result.containsValue(value)) {
count++;
result.put(value, count);
} else {
count = 1;
result.put(value, count);
}
}
}
}
return result;
}
private Map<Object, Integer> collectOverAttribute(Set<EObject> contextObjects, OCLExpression<EClassifier> body, EClassifier ocType) {
Map<Object, Integer> result = null;
ResultSet resultSet = null;
QueryContext queryContext = new ProjectBasedQueryContextScopeProviderImpl(contextObjects.toArray(new EObject[contextObjects.size()])).getForwardScopeAsQueryContext();
QueryProcessor queryProcessor = QueryProcessorFactory.getDefault().createQueryProcessor(IndexFactory.getInstance());
URI uri = EcoreUtil.getURI(ocType);
String ali = ((PropertyCallExp) body).getSource().getName();
try {
// collect over an attribute
// "select "+ stringBody+" from [" + uri1 + "] as "+ali
SelectEntry select = new SelectAttrs(ali, new String[] { ((PropertyCallExp) body).getReferredProperty().getName() });
FromEntry from = new FromType(ali, uri, /* withoutSubtypes */true);
Query query = new Query(new SelectEntry[] { select }, new FromEntry[] { from });
resultSet = queryProcessor.execute(query, queryContext);
} catch (RuntimeException e) { }
finally {
Map<Object, Integer> col = new HashMap<Object, Integer>();
if (!resultSet.isEmpty()) {
int count = 1;
for (int i = 0; i < resultSet.getSize(); i++) {
Object value = null;
Object[] attribute = resultSet.getAttributes(i, ali);
for (int j = 0; j < attribute.length; j++) {
value = attribute[j];
}
if (col.containsKey(value)) {
count++;
col.put(value, count);
} else {
count = 1;
col.put(value, count);
}
}
}
result = col;
}
return result;
}
private Operation mapStringToOperation(String eOp) {
Operation operation;
if ("=".equals(eOp))
operation = Operation.EQUAL;
else if ("!=".equals(eOp) || "=!".equals(eOp) || "<>".equals(eOp))
operation = Operation.NOTEQUAL;
else if (">=".equals(eOp) || "=>".equals(eOp))
operation = Operation.GREATEREQUAL;
else if (">".equals(eOp))
operation = Operation.GREATER;
else if ("<=".equals(eOp) || "=<".equals(eOp))
operation = Operation.SMALLEREQUAL;
else if ("<".equals(eOp))
operation = Operation.SMALLER;
else if ("like".equalsIgnoreCase(eOp))
operation = Operation.GREATEREQUAL;
else
throw new RuntimeException();
return operation;
}
private Collection<EObject> buildResult(ResultSet resultSet, QueryContext queryContext, String ali) {
Collection<EObject> result = new HashSet<EObject>();
if (!resultSet.isEmpty()) {
for (int i = 0; i < resultSet.getSize(); i++) {
result.add(queryContext.getResourceSet().getEObject(resultSet.getUri(i, ali), /* loadOnDemand */true)); //$NON-NLS-1$
}
}
return result;
}
}