/******************************************************************************* * Copyright (c) 2011 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 com.sap.furcas.prettyprinter; import java.util.ArrayList; import java.util.Collection; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import com.sap.furcas.metamodel.FURCAS.TCS.AsPArg; import com.sap.furcas.metamodel.FURCAS.TCS.ClassTemplate; import com.sap.furcas.metamodel.FURCAS.TCS.ConcreteSyntax; import com.sap.furcas.metamodel.FURCAS.TCS.ContextTemplate; import com.sap.furcas.metamodel.FURCAS.TCS.EnumerationTemplate; import com.sap.furcas.metamodel.FURCAS.TCS.OperatorTemplate; import com.sap.furcas.metamodel.FURCAS.TCS.PrimitiveTemplate; import com.sap.furcas.metamodel.FURCAS.TCS.Property; import com.sap.furcas.metamodel.FURCAS.TCS.ReferenceByPArg; import com.sap.furcas.metamodel.FURCAS.TCS.RefersToPArg; import com.sap.furcas.metamodel.FURCAS.TCS.Template; import com.sap.furcas.prettyprinter.exceptions.AmbigousTemplateException; import com.sap.furcas.prettyprinter.exceptions.NoMatchingTemplateException; import com.sap.furcas.runtime.common.exceptions.MetaModelLookupException; import com.sap.furcas.runtime.common.exceptions.NameResolutionFailedException; import com.sap.furcas.runtime.common.exceptions.SyntaxElementException; import com.sap.furcas.runtime.common.interfaces.IMetaModelLookup; import com.sap.furcas.runtime.common.interfaces.ResolvedNameAndReferenceBean; import com.sap.furcas.runtime.tcs.MetaModelElementResolutionHelper; import com.sap.furcas.runtime.tcs.PropertyArgumentUtil; import com.sap.furcas.runtime.tcs.SyntaxLookup; import com.sap.furcas.runtime.tcs.TcsUtil; /** * A {@link TemplateFinder} is used to search through the templates of a {@link ConcreteSyntax}. * * @author Stephan Erb * */ public class TemplateFinder { private final SyntaxLookup syntaxLookup; private final IMetaModelLookup<EObject> metamodelLookup; private final MetaModelElementResolutionHelper<EObject> resolutionHelper; public TemplateFinder(SyntaxLookup syntaxLookup, IMetaModelLookup<EObject> metamodelLookup) { this.syntaxLookup = syntaxLookup; this.metamodelLookup = metamodelLookup; this.resolutionHelper = new MetaModelElementResolutionHelper<EObject>(metamodelLookup); } public PrimitiveTemplate findPrimitiveTemplate(Property seqElem) { AsPArg asParg = PropertyArgumentUtil.getAsPArg(seqElem); if (asParg == null) { try { ResolvedNameAndReferenceBean<EObject> metaElementRef = resolutionHelper.resolve( syntaxLookup.getEnclosingQualifiedElement(seqElem)); ResolvedNameAndReferenceBean<EObject> metamodelType = metamodelLookup.getFeatureClassReference( metaElementRef, TcsUtil.getPropertyName(seqElem.getPropertyReference())); ReferenceByPArg refByParg = PropertyArgumentUtil.getReferenceByPArg(seqElem); RefersToPArg refersToParg = PropertyArgumentUtil.getRefersToPArg(seqElem); if (refByParg != null) { String referenceByQuery = PropertyArgumentUtil.getReferenceByAsOCL(refByParg); EObject type = metamodelLookup.getOclReturnType(metamodelType.getReference(), referenceByQuery); ResolvedNameAndReferenceBean<EObject> metaModelTypeOfQueryResult = metamodelLookup.resolveReferenceName(type); return syntaxLookup.getDefaultPrimitiveTemplateRule(metaModelTypeOfQueryResult); } else if (refersToParg != null) { ResolvedNameAndReferenceBean<EObject> referredFeatureType = metamodelLookup.getFeatureClassReference( metamodelType, refersToParg.getPropertyName()); return syntaxLookup.getDefaultPrimitiveTemplateRule(referredFeatureType); } else { return syntaxLookup.getDefaultPrimitiveTemplateRule(metamodelType); } } catch (NameResolutionFailedException e) { throw new RuntimeException(e); } catch (MetaModelLookupException e) { throw new RuntimeException(e); } catch (SyntaxElementException e) { throw new RuntimeException(e); } } else { return (PrimitiveTemplate) asParg.getTemplate(); } } public Collection<ContextTemplate> findMatchingContextTemplates(EClass eClass, String mode) { Collection<ContextTemplate> templates = new ArrayList<ContextTemplate>(1); try { ResolvedNameAndReferenceBean<EObject> resolvedName = metamodelLookup.resolveReferenceName(eClass); Collection<Template> candidates = syntaxLookup.getTCSTemplate(resolvedName, mode); for (Template candidate : candidates) { if (candidate instanceof OperatorTemplate) { templates.add((OperatorTemplate) candidate); } if (candidate instanceof ClassTemplate && !((ClassTemplate) candidate).isIsAbstract()) { templates.add((ClassTemplate) candidate); } } if (templates.isEmpty() ) { for (EClass supertype : eClass.getESuperTypes()) { templates.addAll(findMatchingContextTemplates(supertype, mode)); } } return templates; } catch (MetaModelLookupException e) { throw new RuntimeException(e); } catch (SyntaxElementException e) { throw new RuntimeException(e); } } public EnumerationTemplate findEnumerationTemplate(Property seqElem) throws NoMatchingTemplateException, AmbigousTemplateException { try { ResolvedNameAndReferenceBean<EObject> resolvedName = metamodelLookup.resolveReferenceName(TcsUtil.getType(seqElem)); Collection<EnumerationTemplate> templates = filterFor(syntaxLookup.getTCSTemplate(resolvedName, /*mode*/null), EnumerationTemplate.class); if (templates.size() < 1) { throw new NoMatchingTemplateException(TcsUtil.getType(seqElem)); } else if (templates.size() > 1) { throw new AmbigousTemplateException(TcsUtil.getType(seqElem), templates.size()); } else { return templates.iterator().next(); } } catch (MetaModelLookupException e) { throw new RuntimeException(e); } catch (SyntaxElementException e) { throw new RuntimeException(e); } } private <E> Collection<E> filterFor(Collection<?> elements, Class<E> clazz) { ArrayList<E> result = new ArrayList<E>(); for (Object e : elements) { if (clazz.isInstance(e)) { result.add(clazz.cast(e)); } } return result; } }