package com.sap.furcas.runtime.tcs;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.core.runtime.Assert;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EEnum;
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.ETypedElement;
import org.eclipse.emf.ecore.resource.ResourceSet;
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.FromFixedSet;
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.SelectEntry;
import org.eclipse.emf.query2.TypeScopeProvider;
import org.eclipse.emf.query2.WhereEntry;
import org.eclipse.emf.query2.WhereRelationReference;
import org.eclipse.emf.query2.WhereString;
import com.sap.furcas.metamodel.FURCAS.TCS.Alternative;
import com.sap.furcas.metamodel.FURCAS.TCS.Block;
import com.sap.furcas.metamodel.FURCAS.TCS.ClassTemplate;
import com.sap.furcas.metamodel.FURCAS.TCS.ConcreteSyntax;
import com.sap.furcas.metamodel.FURCAS.TCS.ConditionalElement;
import com.sap.furcas.metamodel.FURCAS.TCS.ContextTemplate;
import com.sap.furcas.metamodel.FURCAS.TCS.EndOfLineRule;
import com.sap.furcas.metamodel.FURCAS.TCS.EnumLiteralMapping;
import com.sap.furcas.metamodel.FURCAS.TCS.EnumerationTemplate;
import com.sap.furcas.metamodel.FURCAS.TCS.FunctionCall;
import com.sap.furcas.metamodel.FURCAS.TCS.FunctionTemplate;
import com.sap.furcas.metamodel.FURCAS.TCS.InjectorAction;
import com.sap.furcas.metamodel.FURCAS.TCS.InjectorActionsBlock;
import com.sap.furcas.metamodel.FURCAS.TCS.ModePArg;
import com.sap.furcas.metamodel.FURCAS.TCS.OperatorTemplate;
import com.sap.furcas.metamodel.FURCAS.TCS.Property;
import com.sap.furcas.metamodel.FURCAS.TCS.PropertyReference;
import com.sap.furcas.metamodel.FURCAS.TCS.Rule;
import com.sap.furcas.metamodel.FURCAS.TCS.RulePattern;
import com.sap.furcas.metamodel.FURCAS.TCS.SeparatorPArg;
import com.sap.furcas.metamodel.FURCAS.TCS.Sequence;
import com.sap.furcas.metamodel.FURCAS.TCS.SequenceElement;
import com.sap.furcas.metamodel.FURCAS.TCS.SimplePattern;
import com.sap.furcas.metamodel.FURCAS.TCS.StringPattern;
import com.sap.furcas.metamodel.FURCAS.TCS.TCSPackage;
import com.sap.furcas.metamodel.FURCAS.TCS.Template;
import com.sap.furcas.metamodel.FURCAS.TCS.Token;
import com.sap.furcas.metamodel.FURCAS.textblocks.TextBlock;
import com.sap.furcas.modeladaptation.emf.adaptation.EMFModelAdapter;
import com.sap.furcas.runtime.common.exceptions.SyntaxElementException;
import com.sap.furcas.runtime.common.interfaces.ResolvedNameAndReferenceBean;
import com.sap.furcas.runtime.common.util.EcoreHelper;
public class TcsUtil {
/**
* TODO: Move to Syntax Lookup?
*/
@Deprecated
public static Collection<EClass> getAllSubtypes(EClass clazz) {
// TODO use query for this to have a greater scope
Collection<EClass> subTypes = new ArrayList<EClass>();
for (Iterator<EObject> it = clazz.eResource().getAllContents(); it.hasNext();) {
EObject e = it.next();
if (e instanceof EClass) {
if (clazz.isSuperTypeOf((EClass) e)) {
subTypes.add((EClass) e);
}
}
}
return subTypes;
}
/**
* Check multiplicity of referred StructuralFeature.
*
* @param p
* Property to check
* @return true, if Multiplicity is unlimited, or larger than 1.
*/
public static boolean isMultiValued(Property p) {
// TODO is there a constant instead of checking for below 0
ETypedElement feat = getStructuralFeature(p);
if (feat instanceof EReference || feat instanceof EParameter || feat instanceof EStructuralFeature) {
int upper = feat.getUpperBound();
return (upper < 0 || upper > 1);
}
return false;
}
public static EClassifier getType(Property p) {
ETypedElement e = getStructuralFeature(p);
if (e != null) {
return e.getEType();
}
return null;
}
public static String getMode(Property p) {
ModePArg modeArg = PropertyArgumentUtil.getModePArg(p);
if (modeArg != null) {
return modeArg.getMode();
}
return null;
}
/**
* Computes the fully qualified name of the given {@link EClassifier}.
*
* @param type
* the type to compute its qualified name from.
* @return the Qualified name of the given type as list of strings.
*/
public static List<String> getQualifiedName(EClassifier type) {
return EcoreHelper.getQualifiedName(type);
}
public static boolean isOperatored(Property p, Map<List<String>, Map<String, ClassTemplate>> classTemplateMap) {
ETypedElement s = getStructuralFeature(p);
if (s != null) {
if (classTemplateMap != null) {
List<String> typeName = getQualifiedName(getType(p));
if (classTemplateMap.containsKey(typeName)) {
ClassTemplate ct = classTemplateMap.get(typeName).get(getMode(p));
if (ct != null) {
return ct.isIsOperatored();
}
}
}
}
return false;
}
/**
* TODO: Move to Syntax Lookup?
*/
@Deprecated
public static Collection<ClassTemplate> getClassTemplates(EClass type, String mode,
Map<List<String>, Map<String, ClassTemplate>> classTemplateMap, ResourceSet connection) {
Assert.isLegal(classTemplateMap != null, "could not resolve class template for Reference, classTemplateMap is null");
List<ClassTemplate> results = new ArrayList<ClassTemplate>();
// get all matching class templates of this type and any of the
// (recursive) subtypes
Collection<EClass> subTypes = getAllSubtypes(type);
for (EClass subType : subTypes) {
if (classTemplateMap.containsKey(getQualifiedName(subType))) {
for (ClassTemplate ct : classTemplateMap.get(getQualifiedName(subType)).values()) {
if ((mode == null && ct.getMode() == null) || (mode != null && mode.equals(ct.getMode()))) {
results.add(ct);
}
}
}
}
return results;
}
public static ResourceSet getResourceSetFromEObject(EObject ref) {
return ref.eResource().getResourceSet();
}
/**
* Returns the first SequenceElement of a Sequence s, or null if s is null or it has no SequenceElements.
*
* @param s
* Sequence to return the first SequenceElement of
* @return the first SequenceElement of Sequence s
*/
public static SequenceElement getFirstSequenceElement(Sequence s) {
if (s != null) {
if (s.getElements() != null) {
if (s.getElements().size() > 0) {
return s.getElements().get(0);
}
}
}
return null;
}
public static boolean isFirstSequenceElement(SequenceElement se) {
EObject container = se.eContainer();
if (container instanceof Sequence) {
return se.equals(TcsUtil.getFirstSequenceElement((Sequence) container));
}
return false;
}
public static boolean isLastSequenceElement(SequenceElement e) {
if (e == null) {
return false;
}
return getNextSequenceElement(e) == null;
}
/**
* Returns the next SequenceElement in the parent Sequence, or null, if it is the last SequenceElement.
*
* @param e SequenceElement after which to look
* @return next SequenceElement in parent Sequence
*/
public static SequenceElement getNextSequenceElement(SequenceElement e) {
if (e == null) {
return null;
}
// use refImmediateComposite, as a SequenceElement can be part of
// different types of Sequences
EObject container = e.eContainer();
if (container instanceof Sequence) {
Sequence parentSequence = (Sequence) container;
List<SequenceElement> elements = parentSequence.getElements();
if (elements != null) {
int index = elements.indexOf(e);
if (index + 1 < elements.size()) {
return elements.get(index + 1);
}
}
}
return null;
}
/**
* Returns the next parent SequenceElement, if the SequenceElement has a parent Sequence, and that parent Sequence is either
* part of another SequenceElement, FunctionTemplate, or SeparatorPArg.
*
* The FunctionCall parameter is needed to disambiguate between the different FunctionCalls that reference the
* FunctionTemplate this SequenceElement is part of.
*
* @param e
* SequenceElement to find the parent SequenceElement of
* @param parentFunctionCallMap
* the closest FunctionCall this SequenceElement belongs to. can be null, if not belonging to a FunctionTemplate
* Sequence
* @param parentPropertyStack
* parent Properties. Important: Will be popped, when encountering a ClassTemplate. can be null.
* @return the next parent SequenceElement, or null
*/
public static SequenceElement getParentSequenceElement(SequenceElement e, Stack<FunctionCall> parentFunctionCallStack,
Stack<Property> parentPropertyStack, Map<List<String>, Map<String, ClassTemplate>> classTemplateMap) {
Sequence parentSequence = e.getElementSequence();
if (parentSequence != null) {
// check if parentSequence is part of a SequenceElement
EObject container = parentSequence.eContainer();
if (container instanceof SequenceElement) {
return (SequenceElement) container;
}
if (container instanceof FunctionTemplate) {
// reached a FunctionTemplate, continue at parent
// FunctionCall
Assert.isLegal(parentFunctionCallStack != null, "SequenceElement e belongs to a FunctionTemplate,"
+ " but no parentFunctionCallStack given to disambiguate");
Assert.isLegal(!parentFunctionCallStack.isEmpty(), "SequenceElement e belongs to a FunctionTemplate,"
+ " but no entry in parentFunctionCallStack to disambiguate");
FunctionCall parentFunctionCall = parentFunctionCallStack.pop();
Assert.isLegal(parentFunctionCall.getCalledFunction() == container,
"parentFunctionCall on stack is the wrong parent");
return parentFunctionCall;
}
if (container instanceof ClassTemplate) {
if (parentPropertyStack != null) {
if (parentPropertyStack.size() > 0) {
return parentPropertyStack.pop();
}
}
}
if (container instanceof SeparatorPArg) {
// reached a SeparatorPArg, continue at parent Property
SeparatorPArg parentSepArg = (SeparatorPArg) container;
EObject containerOfParent = parentSepArg.eContainer();
if (containerOfParent instanceof Property) {
return (Property) containerOfParent;
}
}
}
// check for non-sequence based special cases
// the sequence element is a dummy and has no parent sequence. instead,
// get the parent from the property stack
try {
if (parentPropertyStack != null) {
Property parent = parentPropertyStack.peek();
if (isEnumeration(parent) || isOperatored(parent, classTemplateMap)) {
return parentPropertyStack.pop();
}
}
} catch (Exception ex) {
// do nothing
}
return null;
}
public static ClassTemplate getMainClassTemplate(ConcreteSyntax syntax) {
if (syntax != null) {
for (Template t : syntax.getTemplates()) {
if (t instanceof ClassTemplate) {
ClassTemplate c = (ClassTemplate) t;
if (c.isIsMain()) {
return c;
}
}
}
}
return null;
}
/**
* Creates a map of qualifiedName + Mode to ClassTemplate of all ClassTemplates contained in the syntax
*
* @param syntax
* the ConcreteSyntax to build the map of
* @return map of qualifiedName + Mode to ClassTemplate
*/
public static Map<List<String>, Map<String, ClassTemplate>> createClassTemplateMap(ConcreteSyntax syntax) {
Assert.isLegal(syntax != null);
Map<List<String>, Map<String, ClassTemplate>> classTemplateMap = new HashMap<List<String>, Map<String, ClassTemplate>>();
List<Template> templates = syntax.getTemplates();
for (Template t : templates) {
if (t instanceof ClassTemplate) {
ClassTemplate ct = (ClassTemplate) t;
List<String> qualifiedName = getQualifiedName(ct);
putClassTemplate(classTemplateMap, qualifiedName, ct.getMode(), ct);
}
}
return classTemplateMap;
}
public static List<String> getQualifiedName(Template t) {
List<String> qualifiedName;
EClassifier ref = t.getMetaReference();
if (ref == null) { // syntaxes may merely define name of
// metamodel class rather than have a
// reference
qualifiedName = t.getNames();
} else {
qualifiedName = getQualifiedName(ref);
}
if (qualifiedName == null) {
System.err.println("class template could not be identified (qualifiedName and names both null");
}
return qualifiedName;
}
/**
* Creates a map of qualifiedName to OperatorTemplate of all OperatorTemplates contained in the syntax
*
* @param syntax
* the ConcreteSyntax to build the map of
* @return map of qualifiedName to OperatorTemplate
*/
public static Map<List<String>, OperatorTemplate> createOperatorTemplateMap(ConcreteSyntax syntax) {
Assert.isLegal(syntax != null);
Map<List<String>, OperatorTemplate> operatorTemplateMap = new HashMap<List<String>, OperatorTemplate>();
List<Template> templates = syntax.getTemplates();
for (Template t : templates) {
if (t instanceof OperatorTemplate) {
OperatorTemplate ot = (OperatorTemplate) t;
List<String> qualifiedName = getQualifiedName(ot);
operatorTemplateMap.put(qualifiedName, ot);
}
}
return operatorTemplateMap;
}
private static void putClassTemplate(Map<List<String>, Map<String, ClassTemplate>> classTemplateMap,
List<String> qualifiedName, String mode, ClassTemplate ct) {
if (classTemplateMap.containsKey(qualifiedName)) {
classTemplateMap.get(qualifiedName).put(mode, ct);
} else {
Map<String, ClassTemplate> modeMap = new HashMap<String, ClassTemplate>();
modeMap.put(mode, ct);
classTemplateMap.put(qualifiedName, modeMap);
}
}
/**
*
* @param propRef
* @return
*/
public static String getPropertyName(PropertyReference propRef) {
if (propRef != null) {
if (propRef.getName() != null) {
return propRef.getName();
} else {
ETypedElement strucFeat = propRef.getStrucfeature();
if (strucFeat != null) {
return strucFeat.getName();
}
}
}
return null;
}
// /**
// * Returns the value of the property identified by propName of the given target RefStruct.
// *
// *
// * @param target
// * RefStruct to get the property value of.
// * @param propName
// * Name of the property to get the value of.
// * @return The value of the given property for the target RefStruct. This can be a collection for multi-valued properties.
// */
// public static Object getPropertyValue(RefStruct target,
// PropertyReference propRef) {
// assert (target != null);
//
// if (propRef != null) {
//
// if (propRef.getName() != null) {
// // assume that name can only refer to an attribute or reference,
// // not an association link
// return target.refGetValue(propRef.getName());
// }
// ETypedElement elem = propRef.getStrucfeature();
// if (elem != null) {
// return target.refGetValue(elem.getName());
// }
// }
// return null;
// }
public static Object getPropertyValue(Object target, PropertyReference propRef) {
return getPropertyValue(((EObject) target), propRef);
}
/**
* Returns the value of the property identified by propName of the given target EObject.
*
* Unifies the access of Attributes, References and Association links.
*
* @param target
* EObject to get the property value of.
* @param propName
* Name of the property to get the value of.
* @return The value of the given property for the target EObject. This can be a collection for multi-valued properties.
*/
public static Object getPropertyValue(EObject target, PropertyReference propRef) {
assert (target != null);
if (propRef != null) {
if (propRef.getName() != null) {
// assume that name can only refer to an attribute or reference,
// not an association link
return target.eGet(target.eClass().getEStructuralFeature(propRef.getName()));
}
EStructuralFeature elem = propRef.getStrucfeature();
if (elem != null) {
// if (elem instanceof AssociationEnd) {
// AssociationEnd thisEnd = (AssociationEnd) elem;
// AssociationEnd otherEnd = thisEnd.otherEnd();
//
// RefAssociation ass = getResourceSetFromEObject(target)
// .getJmiHelper().getRefAssociationForAssociation(
// (Association) elem.refImmediateComposite());
//
// Collection<EObject> results = null;
//
// try {
// // Warning, the other end must be used for this to work
// results = ass.refQuery(otherEnd.getName(), target);
//
// } catch (TypeMismatchException e) {
// return null;
// }
// if (results.size() > 1) {
// return results;
// } else if (results.size() == 1) {
// return results.iterator().next();
// }
// } else {
return target.eGet(elem);
// }
}
}
return null;
}
/**
* @param p
* @return
*/
static public EStructuralFeature getStructuralFeature(Property p) {
PropertyReference propRef = p.getPropertyReference();
if (propRef != null) {
EStructuralFeature feat = propRef.getStrucfeature();
if (feat != null) {
return feat;
} else if (propRef.getName() != null) {
// TODO
// String proName = propRef.getName();
// // use name and enclosing template to find property in
// metamodel, lookup multiplicity there
throw new RuntimeException("Property References to Non-Moin Elements not implemented yet: " + propRef.getName());
} else {
throw new RuntimeException(
"BUG: Syntax cointains invalid property Reference missing name and StructureReference.");
}
} else {
throw new RuntimeException("BUG: Property without property Reference");
}
}
public static boolean isEnumeration(Property p) {
EStructuralFeature feat = getStructuralFeature(p);
return (feat.getEType() instanceof EEnum);
}
public static String joinNameList(List<String> names) {
String result = "";
if (names != null && names.size() != 0) {
result += names.get(0);
for (int i = 1; i < names.size(); i++) {
result += "::" + names.get(i);
}
}
return result;
}
/**
* TODO: Move to Syntax Lookup? Furhtermore, the pretty printer does seem to implement a very
* similar method.
*/
@Deprecated
public static List<EnumLiteralMapping> getEnumTemplateForType(ConcreteSyntax syntax, EClassifier type) {
// TODO if too slow, also build map like for class and operator
// templates
List<EnumLiteralMapping> results = new ArrayList<EnumLiteralMapping>();
for (Template t : syntax.getTemplates()) {
if (t instanceof EnumerationTemplate) {
if (getQualifiedName(t).equals(getQualifiedName(type))) {
// match
EnumerationTemplate enumTemplate = (EnumerationTemplate) t;
results.addAll(enumTemplate.getMappings());
break;
}
}
}
return results;
}
public static boolean isContext(Template template) {
if (template instanceof ClassTemplate) {
return ((ClassTemplate) template).isIsContext();
} else if (template instanceof OperatorTemplate) {
return ((OperatorTemplate) template).isIsContext();
} else {
return false;
}
}
/**
* Returns all directly contained {@link InjectorActionsBlock}s.
*
* @param elementSequence
*/
public static Collection<InjectorActionsBlock> getInjectorActions(Sequence elementSequence) {
List<InjectorActionsBlock> injectorActions = new ArrayList<InjectorActionsBlock>();
for (SequenceElement seqEl : elementSequence.getElements()) {
if (seqEl instanceof InjectorActionsBlock) {
injectorActions.add((InjectorActionsBlock) seqEl);
}
}
return injectorActions;
}
public static boolean isReferenceOnly(Template template) {
if (template instanceof ClassTemplate) {
return ((ClassTemplate) template).isIsReferenceOnly();
} else if (template instanceof OperatorTemplate) {
return ((OperatorTemplate) template).isIsReferenceOnly();
}
return false;
}
public static boolean isPropertyInit(SequenceElement se) {
return se instanceof InjectorActionsBlock;
}
/**
* Checks whether at least one of the given types has a template defined.
*
* @param subtypes
* @param mode
* @return
* @throws SyntaxElementException
*/
public static <Type> boolean areSubTypesWithTemplates(List<ResolvedNameAndReferenceBean<Type>> subtypes, String mode,
SyntaxLookup syntaxLookup) throws SyntaxElementException {
for (ResolvedNameAndReferenceBean<Type> subTypeName : subtypes) {
Collection<Template> subtemps = null;
subtemps = syntaxLookup.getTCSTemplate(subTypeName, mode);
if (subtemps.size() > 0) {
return true;
}
}
return false;
}
/**
* Gives the mode of the template if its a {@link ClassTemplate}.
*
* @param template
* @return
*/
public static String getTemplateMode(Template template) {
if (template instanceof ClassTemplate) {
return ((ClassTemplate) template).getMode();
}
return null;
}
public static boolean matchesContext(ContextTemplate ot, String tag) {
if (ot.isIsContext()) {
if (tag != null) {
if (ot.getContextTags() != null && ot.getContextTags().getTags() != null) {
for (String curTag : ot.getContextTags().getTags()) {
if (curTag.equals(tag)) {
return true;
}
}
}
} else {
// return EObject that matches this ClassTemplate
return true;
}
}
return false;
}
public static SequenceElement getContainerSequenceElement(SequenceElement e) {
Sequence parentSequence = e.getElementSequence();
if (parentSequence != null) {
EObject container = parentSequence.eContainer();
if (container instanceof SequenceElement) {
return (SequenceElement) container;
}
}
return null;
}
public static Token getCommentToken(ConcreteSyntax syntax) {
if (syntax != null) {
for (Token tok : syntax.getTokens()) {
// TODO update this, if COMMENT token stops being fixed
if (tok.getName().equals("COMMENT")) {
return tok;
}
}
}
return null;
}
/**
* succeeds only if the following form is present in the tcs file: token COMMENT : endOfLine(start = "--");
*
* @param tok
* @return
*/
public static String getEndOfLineCommentPrefix(Token tok) {
if (tok.getPattern() != null) {
for (SimplePattern pattern : tok.getPattern().getSimplePatterns()) {
if (pattern instanceof RulePattern) {
RulePattern rulePattern = (RulePattern) pattern;
Rule rule = rulePattern.getRule();
if (rule instanceof EndOfLineRule) {
EndOfLineRule eofRule = (EndOfLineRule) rule;
StringPattern eofRulePattern = eofRule.getStart();
if (eofRulePattern != null) {
return eofRulePattern.getName();
}
}
}
}
}
return null;
}
// FIXME: The collection comparision looks really strange.
public static boolean isPropValueAndOclResultEqual(Object propValue, Collection<?> oclResult) {
// oclHelper.findElementWithOCLQuery returns null for empty collections
if (propValue == null) {
return oclResult == null;
} else if (oclResult.size() == 1 && propValue.equals(oclResult.iterator().next())) {
return true;
} else if(propValue instanceof Collection) {
Collection<?> propValueColl = (Collection<?>) propValue;
Iterator<?> oclResultIterator = oclResult.iterator();
for (Iterator<?> iterator = propValueColl.iterator(); iterator
.hasNext() && oclResultIterator.hasNext();) {
Object object = iterator.next();
Object oclObject = oclResultIterator.next();
if(!object.equals(oclObject)) {
return false;
}
}
return true;
} else {
return false;
}
}
private final static Pattern contextPattern = Pattern.compile("#context(\\((\\w*)(\\)))?");
public static String getContextTag(String oclQuery) {
// strip OCL query prefix
if (oclQuery.startsWith(EMFModelAdapter.OCL_QUERY_PREFIX)) {
oclQuery = oclQuery.substring(EMFModelAdapter.OCL_QUERY_PREFIX.length());
}
// #context(blub) will make
// group 0: #context(blub)
// group 2: blub
// #context will make
// group 0: #context
// group 2: null
Matcher matcher = contextPattern.matcher(oclQuery);
if (matcher.find()) {
return matcher.group(2);
} else {
return null;
}
}
/**
* Retrieves the parent {@link Template} of the queryElement which may be either a {@link InjectorAction} or a
* {@link Property}.
*
* @param queryElement
* @return
*/
public static Template getParentTemplate(EObject queryElement) {
if (queryElement instanceof Property) {
return ((Property) queryElement).getParentTemplate();
} else if (queryElement instanceof InjectorAction) {
return ((InjectorAction) queryElement).getInjectorActionsBlock().getParentTemplate();
} else {
return null;
}
}
/**
* FIXME: What does this what a SyntaxLookup can't do? Why do we need it?
* If it does a little bit more, should't we enhance the syntax lookup? It will
* give us a central place where we can do caching and other optimizations.
*/
@Deprecated
public static Template findTemplate(EClass foreachElementType, String mode, Collection<URI> partitionScope) {
// TODO query fully qualified name!
ResultSet result;
EClassifier clazz = foreachElementType;
ResourceSet rs = foreachElementType.eResource().getResourceSet();
// TODO search only in the mapping partition!
Template template = null;
if (clazz != null) {
SelectEntry select = new SelectAlias("template");
FromType fromClassTemplate = new FromType("template", EcoreUtil.getURI(TCSPackage.eINSTANCE.getClassTemplate()), /* _withoutSubtypes */ false);
FromFixedSet fromClass = new FromFixedSet("class", EcoreUtil.getURI(clazz.eClass()), new URI[] { EcoreUtil.getURI(clazz) });
WhereEntry whereMetaReference = new WhereRelationReference(/* _leftAlias */ "template", /* _featureName */ "metaReference",
/* _rightAlias */ "class");
WhereEntry whereMode = new LocalWhereEntry("template", new WhereString("mode", Operation.EQUAL, mode));
Query queryForClassTemplate = new Query(new SelectEntry[] { select }, new FromEntry[] { fromClassTemplate, fromClass },
new WhereEntry[] { whereMetaReference, whereMode });
if (true /* template == null */) { // TODO
QueryProcessor queryProcessor = QueryProcessorFactory.getDefault().createQueryProcessor(IndexFactory.getInstance());
TypeScopeProvider mappingQueryScope = queryProcessor.getInclusiveQueryScopeProvider(partitionScope
.toArray(new URI[] {}));
QueryContext context = getQueryScope(rs, mappingQueryScope);
result = queryProcessor.execute(queryForClassTemplate, context);
URI[] eObjectsURIs = result.getUris("template");
if (eObjectsURIs.length > 1) {
template = (Template) rs.getEObject(eObjectsURIs[1], false);
} else if (eObjectsURIs.length == 1) {
template = (Template) rs.getEObject(eObjectsURIs[0], false);
}
if (template == null) {
// maybe operatorTemplate?
FromType fromOperatorTemplate = new FromType("template", EcoreUtil.getURI(TCSPackage.eINSTANCE.getOperatorTemplate()), /* _withoutSubtypes */ false);
Query queryForOperatorTemplate = new Query(new SelectEntry[] { select }, new FromEntry[] { fromOperatorTemplate, fromClass },
new WhereEntry[] { whereMetaReference, whereMode });
result = queryProcessor.execute(queryForOperatorTemplate, context);
template = getTemplate(result, rs, template);
}
}
}
return template;
}
private static Template getTemplate(ResultSet result, ResourceSet rs, Template template) {
URI[] eObjectsURIs;
eObjectsURIs = result.getUris("template");
if (eObjectsURIs.length > 1) {
template = (com.sap.furcas.metamodel.FURCAS.TCS.Template) rs.getEObject(eObjectsURIs[1], false);
} else if (eObjectsURIs.length == 1) {
template = (Template) rs.getEObject(eObjectsURIs[0], false);
}
return template;
}
private static QueryContext getQueryScope(ResourceSet rs, TypeScopeProvider mappingQueryScope) {
Set<URI> resourcesInScope = new HashSet<URI>();
for (URI uri : mappingQueryScope.getResourceScope()) {
resourcesInScope.add(uri);
}
return com.sap.furcas.runtime.common.util.EcoreHelper.getQueryContext(rs, resourcesInScope);
}
/**
* Given a record of which choices were made, in numerical form, as returned, e.g., by
* {@link TextBlock#getParentAltChoices()} including the leading -1, and given a base {@link ContextTemplate} from
* where to start, traverses through all {@link SequenceElement}s that were used according to
* <code>alternativeChoices</code> and looks for <code>searchFor</code>. Returns <code>true</code> if
* <code>searchFor</code> must have been executed based on what <code>alternativeChoices</code> tells;
* <code>false</code> otherwise.
* <p>
*
* In case an alternative is reached but <code>alternativeChoices</code> has no further elements, an
* {@link IllegalArgumentException} is thrown.
*
* @param base
* the template with whose sequence to start. The sequence's contained elements are traversed in
* depth-first order and at each choice, the first element of <code>alternativeChoices</code> is
* consumed, and the descent continues with the respective alternative.
*
* @param alternativeChoices
* a list such as the one returned by {@link TextBlock#getParentAltChoices()} including the leading -1.
* Must be non-<code>null</code> but may be empty. In case of an empty list, <code>base</code> is
* returned immediately.
*
* @param searchFor
* the sequence element to search for
*
* @throws IllegalArgumentException
* in case <code>alternativeChoices</code> doesn't contain enough elements for the choices to be made
* during the descent
*/
public static boolean wasExecuted(ContextTemplate base, List<Integer> alternativeChoices, SequenceElement searchFor) {
Sequence sequence = base.getTemplateSequence();
return sequence != null && wasExecuted(sequence, new LinkedList<Integer>(alternativeChoices), searchFor);
}
private static boolean wasExecuted(Sequence sequence, List<Integer> alternativeChoices, SequenceElement searchFor) {
boolean result = false;
for (SequenceElement element : sequence.getElements()) {
if (element == searchFor) {
result = true;
} else {
Sequence subSequence = getSubSequence(alternativeChoices, element);
if (subSequence != null) {
result = wasExecuted(subSequence, alternativeChoices, searchFor);
}
}
if (result) {
break;
}
}
return result;
}
private static Sequence getSubSequence(List<Integer> alternativeChoices, SequenceElement element) {
removeHeadUpToNextPositiveInteger(alternativeChoices);
Sequence subSequence;
if (element instanceof Alternative) {
subSequence = ((Alternative) element).getSequences().get(alternativeChoices.get(0));
alternativeChoices.remove(0);
} else if (element instanceof ConditionalElement) {
switch (alternativeChoices.get(0)) {
case 0:
subSequence = ((ConditionalElement) element).getThenSequence();
break;
case 1:
subSequence = ((ConditionalElement) element).getElseSequence();
break;
default:
throw new IllegalArgumentException("Choice "+alternativeChoices.get(0)+
" not compatible with ConditionalElement. Expected 0 or 1.");
}
alternativeChoices.remove(0);
} else if (element instanceof Block) {
subSequence = ((Block) element).getBlockSequence();
} else if (element instanceof FunctionCall) {
subSequence = ((FunctionCall) element).getCalledFunction().getFunctionSequence();
} else {
subSequence = null;
}
return subSequence;
}
private static void removeHeadUpToNextPositiveInteger(List<Integer> alternativeChoicesWithLeadingMinusOneRemoved) {
while (!alternativeChoicesWithLeadingMinusOneRemoved.isEmpty() && alternativeChoicesWithLeadingMinusOneRemoved.get(0) < 0) {
alternativeChoicesWithLeadingMinusOneRemoved.remove(0);
}
}
public static Template getParentTemplate(SequenceElement e, ConcreteSyntax syntax) {
EObject parent = e.eContainer();
while (parent != null && !(parent instanceof ConcreteSyntax)) {
if (parent instanceof ClassTemplate || parent instanceof OperatorTemplate || parent instanceof FunctionTemplate) {
return (Template) parent;
} else {
if (parent instanceof EObject) {
EObject r = parent;
parent = r.eContainer();
} else {
parent = null;
}
}
}
return TcsUtil.getMainClassTemplate(syntax);
}
public static Alternative getParentAlternative(SequenceElement e) {
EObject parent = e.eContainer();
while (parent != null && !(parent instanceof ConcreteSyntax)) {
if (parent instanceof Alternative) {
return (Alternative) parent;
} else {
if (parent instanceof EObject) {
EObject r = parent;
parent = r.eContainer();
} else {
parent = null;
}
}
}
return null;
}
public static Sequence getSequence(Template t) {
if (t instanceof ClassTemplate) {
ClassTemplate ct = (ClassTemplate) t;
return ct.getTemplateSequence();
}
if (t instanceof OperatorTemplate) {
OperatorTemplate ot = (OperatorTemplate) t;
return ot.getTemplateSequence();
}
if (t instanceof FunctionTemplate) {
FunctionTemplate ft = (FunctionTemplate) t;
return ft.getFunctionSequence();
}
return null;
}
public static <T extends EObject> Collection<T> getElementsOfType(EObject syntaxOrTemplate, Class<T> typeToFilterFor) {
Collection<T> result = new LinkedList<T>();
for (Iterator<EObject> i=syntaxOrTemplate.eAllContents(); i.hasNext(); ) {
EObject o = i.next();
if (typeToFilterFor.isInstance(o)) {
@SuppressWarnings("unchecked")
T t = (T) o;
result.add(t);
}
}
return result;
}
}