/******************************************************************************* * Copyright (c) 2008 SAP * see https://research.qkal.sap.corp/mediawiki/index.php/CoMONET * * Date: $Date: 2008-09-19 13:53:53 +0200 (Fr, 19 Sep 2008) $ * @version $Revision: 1832 $ * @author: $Author: c5107456 $ *******************************************************************************/ package com.sap.furcas.parsergenerator.tcs.t2m.grammar; import java.util.Collection; import java.util.Iterator; import java.util.List; import org.eclipse.emf.common.util.Diagnostic; import org.eclipse.emf.ecore.EStructuralFeature; import com.sap.furcas.metamodel.FURCAS.TCS.ClassTemplate; import com.sap.furcas.metamodel.FURCAS.TCS.ForeachPredicatePropertyInit; import com.sap.furcas.metamodel.FURCAS.TCS.InjectorAction; import com.sap.furcas.metamodel.FURCAS.TCS.InjectorActionsBlock; import com.sap.furcas.metamodel.FURCAS.TCS.LookupPropertyInit; import com.sap.furcas.metamodel.FURCAS.TCS.PredicateSemantic; import com.sap.furcas.metamodel.FURCAS.TCS.PrimitivePropertyInit; import com.sap.furcas.metamodel.FURCAS.TCS.PropertyInit; import com.sap.furcas.metamodel.FURCAS.TCS.PropertyReference; import com.sap.furcas.metamodel.FURCAS.TCS.QualifiedNamedElement; import com.sap.furcas.metamodel.FURCAS.TCS.Template; import com.sap.furcas.parsergenerator.tcs.t2m.grammar.constraints.PropertyInstanceOfConstraint; import com.sap.furcas.parsergenerator.tcs.t2m.grammar.constraints.RuleBodyPropertyConstraint; import com.sap.furcas.parsergenerator.util.TcsUtil; 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.MessageHelper; import com.sap.furcas.runtime.tcs.MetaModelElementResolutionHelper; import com.sap.furcas.runtime.tcs.RuleNameFinder; import com.sap.furcas.runtime.tcs.SyntaxLookup; import com.sap.furcas.runtime.tcs.TemplateNamingHelper; /** * handles separate Injector Actions which have no syntactic representation */ public class InjectorActionsHandler<Type> { private static final String OCL_QUERY_PREFIX = "OCL:"; private final SemanticErrorBucket errorBucket; private final SyntaxLookup syntaxLookup; private final MetaModelElementResolutionHelper<Type> resolutionHelper; private final IMetaModelLookup<Type> metaLookup; private final TemplateNamingHelper<Type> namingHelper; /** * @param handlerConfig */ public InjectorActionsHandler(SyntaxElementHandlerConfigurationBean<Type> handlerConfig) { errorBucket = handlerConfig.getErrorBucket(); syntaxLookup = handlerConfig.getSyntaxLookup(); metaLookup = handlerConfig.getMetaLookup(); resolutionHelper = handlerConfig.getResolutionHelper(); namingHelper = handlerConfig.getNamingHelper(); } public void addElement(InjectorActionsBlock block, RuleBodyStringBuffer buffer) throws MetaModelLookupException, SyntaxElementException { Collection<InjectorAction> actions = block.getInjectorActions(); if (actions == null || actions.size() == 0) { return; } Template propertyOwnerTypeTemplate = syntaxLookup.getEnclosingQualifiedElement(block); buffer.append('{'); for (Iterator<InjectorAction> iterator = actions.iterator(); iterator.hasNext();) { InjectorAction injectorAction = iterator.next(); if (injectorAction instanceof PropertyInit) { PropertyInit propInit = (PropertyInit) injectorAction; addPropertyInitAction(block, buffer, propertyOwnerTypeTemplate, propInit); } else { throw new RuntimeException("Unknown subclass of InjectorAction " + injectorAction.getClass()); } } buffer.append('}'); } /** * adds "{setProperty(propName, value);}" for a primitive template and * "{setRef(ret, propName, TypeOfProperty, null, null, value, null, null, false, null);}" if lookup init */ private void addPropertyInitAction(InjectorActionsBlock block, RuleBodyStringBuffer buffer, QualifiedNamedElement propertyOwnerTypeTemplate, PropertyInit propInit) throws MetaModelLookupException, SyntaxElementException { String propName = getPropertyName(propInit); if (propName == null || propName.trim().equals("")) { errorBucket.addError("Empty property name.", propInit); return; } buffer.append(ObservationDirectivesHelper.getEnterInjectorActionNotification()); String value = propInit.getValue(); String propInitURI = ObservationDirectivesHelper.getId(propInit); if (propInit instanceof PrimitivePropertyInit) { // TODO refer to and use Primitive template transformer to create // required // datatype buffer.append("setProperty(ret, \"" + propName + "\", " + value + ");"); } else if (propInit instanceof LookupPropertyInit) { // //All property inits are now considered optional as their // violation will be error handled through constraint checking. boolean isOptional = true; ResolvedNameAndReferenceBean<Type> metaModelTypeOfPropertyReference = TcsUtil.getReferencedType(block, buffer, propName, propertyOwnerTypeTemplate, resolutionHelper, metaLookup); String resolvedTypeOfPropertyName = namingHelper.getMetaTypeListParameter(metaModelTypeOfPropertyReference); if (value.startsWith(OCL_QUERY_PREFIX)) { validateOclQuery(block.getParentTemplate(), value, propInit); String oclQuery = TcsUtil.escapeMultiLineOclQuery(value); buffer.append("setOclRef(ret, \"" + propName + "\", null, null, \"" + oclQuery + "\", " + isOptional + ", \""+propInitURI+"\", SyntaxRegistryFacade.getModelUpdaterRegistry());"); } else { buffer.append("setRef(ret, \"" + propName + "\", " + resolvedTypeOfPropertyName + ", null, null, \"" + value + "\", null, null, false, null, " + isOptional + ");"); } } else if (propInit instanceof ForeachPredicatePropertyInit) { String mode = ((ForeachPredicatePropertyInit) propInit).getMode(); buffer.append("\n{\n"); buffer.append("List<PredicateSemantic> list = new ArrayList<PredicateSemantic>();\n"); buffer.append("RuleNameFinder finder = new RuleNameFinder();\n"); Iterator<PredicateSemantic> semIt = ((ForeachPredicatePropertyInit) propInit).getPredicateSemantic().iterator(); RuleNameFinder finder = new RuleNameFinder(); while (semIt.hasNext()) { PredicateSemantic next = semIt.next(); String localMode = mode; if (next.getMode() != null) { localMode = next.getMode(); } if (next.getWhen() != null) { validateOclQuery(block.getParentTemplate(), next.getWhen(), propInit); String oclQueryWhen = TcsUtil.escapeMultiLineOclQuery(next.getWhen()); buffer.append("list.add(new PredicateSemantic(\"" + oclQueryWhen + "\", \"" + finder.getRuleName(next.getAs(), localMode) + "\"));\n"); } else { buffer.append("list.add(new PredicateSemantic(null, \"" + finder.getRuleName(next.getAs(), localMode) + "\"));\n"); } } boolean hasContext = false; if (block.getParentTemplate() instanceof ClassTemplate) { hasContext = ((ClassTemplate) block.getParentTemplate()).isIsContext(); } validateOclQuery(block.getParentTemplate(), value, propInit); String oclQuery = TcsUtil.escapeMultiLineOclQuery(value); if (mode == null) { buffer.append("setPredicateRef(ret,\"" + propName + "\",null,\"" + oclQuery + "\",list,finder," + hasContext + ", \""+propInitURI+"\", SyntaxRegistryFacade.getModelUpdaterRegistry());"); } else { buffer.append("setPredicateRef(ret,\"" + propName + "\",\"" + mode + "\",\"" + oclQuery + "\",list,finder," + hasContext + ", \""+propInitURI+"\", SyntaxRegistryFacade.getModelUpdaterRegistry());"); } buffer.append("\n}\n"); } buffer.append(ObservationDirectivesHelper.getExitInjectorActionNotification()); } private void validateOclQuery(Template template, String query, PropertyInit propInit) { List<Diagnostic> oclErrors = metaLookup.validateOclQuery(template, query); for (Diagnostic error : oclErrors) { if(error.getSeverity() == Diagnostic.ERROR) { errorBucket.addError(error.getMessage() + " in OCL query: \"" + query + "\"", propInit); } else if(error.getSeverity() == Diagnostic.WARNING) { errorBucket.addWarning(error.getMessage() + " in OCL query " + query, propInit); } } } /** * @param propInit * @return */ private static String getPropertyName(PropertyInit propInit) { PropertyReference propRef = propInit.getPropertyReference(); if (propRef != null) { if (propRef.getName() != null) { return propRef.getName(); } else { EStructuralFeature strucFeat = propRef.getStrucfeature(); if (strucFeat != null) { return strucFeat.getName(); } } } return null; } /** * util method that looks up the type of a referenced object, and also * considers the context of the current template sequence. * * @param block * @param buffer * @param name * @param propertyOwnerTypeTemplate * @return * @throws MetaModelLookupException * @throws SyntaxElementException */ protected ResolvedNameAndReferenceBean<Type> getReferencedType(InjectorActionsBlock block, RuleBodyStringBuffer buffer, String name, QualifiedNamedElement propertyOwnerTypeTemplate) throws MetaModelLookupException, SyntaxElementException { // check for instanceof constraint context in current buffer List<RuleBodyPropertyConstraint> constraints = buffer.getCurrentConstraints(); ResolvedNameAndReferenceBean<Type> substitutePropertyType = null; for (Iterator<RuleBodyPropertyConstraint> iterator = constraints.iterator(); iterator.hasNext();) { RuleBodyPropertyConstraint ruleBodyPropertyConstraint = iterator.next(); if (ruleBodyPropertyConstraint instanceof PropertyInstanceOfConstraint) { PropertyInstanceOfConstraint instOfConst = (PropertyInstanceOfConstraint) ruleBodyPropertyConstraint; if (instOfConst.getPropertyName().equals(name)) { List<String> substitutePropertyTypeName = instOfConst.getTypename(); substitutePropertyType = resolutionHelper.resolve(substitutePropertyTypeName); // the last in the list wins, that's fine, since they can // overrule each other. } } } ResolvedNameAndReferenceBean<Type> metaElementRef; try { metaElementRef = resolutionHelper.resolve(propertyOwnerTypeTemplate); } catch (NameResolutionFailedException e) { throw new SyntaxElementException(e.getMessage(), block, e); } ResolvedNameAndReferenceBean<Type> realMetaModelTypeOfPropertyTemplate = metaLookup.getFeatureClassReference( metaElementRef, name); // realMetaModelTypeOfPropertyTemplate = // syntaxLookup.getTCSTemplate(propertyTypeName); if (realMetaModelTypeOfPropertyTemplate == null) { throw new SyntaxElementException("Type " + MessageHelper.getTemplateName(propertyOwnerTypeTemplate) + " has no feature " + name, block); } ResolvedNameAndReferenceBean<Type> metaModelTypeOfProperty; if (substitutePropertyType != null) { // check in Metamodel that new ownername is subclass of previous // one, else // error if (metaLookup.isSubTypeOf(substitutePropertyType, realMetaModelTypeOfPropertyTemplate)) { metaModelTypeOfProperty = substitutePropertyType; } else { throw new SyntaxElementException("Conditional subtype " + substitutePropertyType + " of feature " + name + " is not a subtype of expected type " + realMetaModelTypeOfPropertyTemplate, block); } } else { metaModelTypeOfProperty = realMetaModelTypeOfPropertyTemplate; } return metaModelTypeOfProperty; } }