/******************************************************************************* * Copyright (c) 2008 SAP * see https://research.qkal.sap.corp/mediawiki/index.php/CoMONET * * Date: $Date: 2010-04-14 09:00:22 +0200 (Mi, 14 Apr 2010) $ * Revision: $Revision: 9646 $ * Author: $Author: c5106462 $ *******************************************************************************/ package com.sap.furcas.runtime.parser.impl; import java.util.List; import com.sap.furcas.runtime.common.exceptions.ModelAdapterException; import com.sap.furcas.runtime.common.interfaces.IModelElementProxy; import com.sap.furcas.runtime.common.interfaces.IRuleName; import com.sap.furcas.runtime.common.util.ContextAndForeachHelper; import com.sap.furcas.runtime.parser.ANTLR3LocationToken; import com.sap.furcas.runtime.parser.IModelAdapter; import com.sap.furcas.runtime.parser.ModelElementCreationException; import com.sap.furcas.runtime.parser.impl.context.ContextManager; /** * a delayed reference is a temporary object created during parsing. It * represents a reference, that cannot instantly be resolved because the object * referenced may not exist before the end of parsing. The DelayedReference * stores all information necessary to resolve an object and set the reference * on a source object. */ public abstract class DelayedReference implements Cloneable { /** The Constant AUTOCREATE_ALWAYS. */ public static final String AUTOCREATE_ALWAYS = "always"; /** The Constant AUTOCREATE_NEVER. */ public static final String AUTOCREATE_NEVER = "never"; /** The Constant AUTOCREATE_MISSING. */ public static final String AUTOCREATE_MISSING = "ifmissing"; public enum ReferenceType { /** * Constant for reference type OCL */ TYPE_OCL, /** Constant for reference type default */ TYPE_DEFAULT, /** Constant for reference type semantic predicate */ TYPE_FOREACH_PREDICATE, CONTEXT_LOOKUP, SEMANTIC_DISAMBIGUATE } /** The current context. */ private Object referenceContextObject; /** * If the reference occurs in a template that is invoked by a "foreach" predicate in * another template, this attribute is set to the value of the foreach's OCL expression * that was current when this reference was created. */ private Object currentForeachElement; /** The object. */ private Object modelElement; /** The property name. */ private final String propertyName; /** The value type name. */ private List<String> valueTypeName; /** The key name. */ private String keyName; /** The key value. */ private Object keyValue; /** The look in. */ private String lookIn; /** The auto create. */ private String autoCreate; /** The create as. */ private List<String> createAs; /** The import context. */ private boolean importContext; /** The create in. */ private String createIn; /** The token. */ private final ANTLR3LocationToken token; /** The real value. */ private Object realValue = null; /** The InjectorAction. */ private Object queryElement; private String oclQuery; private final boolean isOptional; private String mode; private IRuleName ruleNameFinder; private ANTLR3LocationToken firstToken; /** * indicates the type of this reference expected to be one of the type * constants defined in this class */ private final ReferenceType type; private List<PredicateSemantic> predicateActionList; private boolean hasContext; private Object textBlock; private List<SemanticDisambRuleData> semRulData; private Object semanticObject; protected Object opTemplateLefthand; /** * Used by * {@link ObservableInjectingParser#setRef(Object, String, List, String, Object, String, String, List, boolean, String)} * * @param currentContextElement * Node in the context tree created during parsing (elements are * added to such nodes) * @param currentForeachElement TODO * @param object * Object for which to set a reference * @param propertyName * Property referring to something * @param valueTypeName * Type of referenced object * @param keyName * id property of referenced object * @param keyValue * id of referenced object * @param lookIn * ("#all" for everywhere, null for context, some context path * else.) TODO: Investigate path notation * @param autoCreate * ("always" | "never" | "ifmissing" ) * @param createAs * Override for valueTypeName (to use SubType?) * @param importContext * declares context of referred object to become part of * referring object context (see java imports) * @param createIn * Where to create the reference if it could not be resolved * @param isOptional * If isOptional the non-resolved reference won't result in an * error. * @param type TODO * @param token * used to determine location, which is used for error messages */ protected DelayedReference(IModelElementProxy currentContextElement, Object currentForeachElement, Object object, String propertyName, List<String> valueTypeName, String keyName, Object keyValue, String lookIn, String autoCreate, List<String> createAs, boolean importContext, String createIn, boolean isOptional, ReferenceType type, ANTLR3LocationToken token) { this.referenceContextObject = currentContextElement; this.currentForeachElement = currentForeachElement; this.modelElement = object; this.propertyName = propertyName; this.valueTypeName = valueTypeName; this.keyName = keyName; this.keyValue = keyValue; this.lookIn = lookIn; this.autoCreate = autoCreate; this.createAs = createAs; this.importContext = importContext; this.createIn = createIn; this.isOptional = isOptional; this.token = token; this.type = type; } /** * Used by * {@link ObservableInjectingParser#setOclRef(Object, String, String, Object, String)} * * @param currentContext * the model element (proxy) that is the innermost context to be * used for default lookups, such as <tt>refersTo = name</tt> * without any further specifications or queries. * @param currentForeachElement TODO * @param object * the element on which the property identified by * <tt>propertyName</tt> is to be set * @param propertyName * identifies the property to be set on <tt>object</tt> * @param keyName * feature name given with <tt>refersTo</tt>, e.g., "name" in * case <tt>refersTo=name</tt> was used. * @param keyValue * the parameter to be used for the lookup; typically the text * parsed as the referencing identifier; for the OCL query, this * will be substituted for a <tt>?</tt> occurring in the OCL * expression; for a simple <tt>refersTo=someFeature</tt> this * value will be compared to the value of <tt>someFeature</tt>. * @param oclQuery * If provided, a string currently prefixed with "OCL:" whose * suffix is parsed using the OCL parser of MOIN. It can use "?" * anywhere, also multiple times, in the query which will then be * substituted by <tt>keyValue</tt>; if <tt>#context</tt> or * <tt>#context(name)</tt> is used in the query, it will be * substituted by the respective context element. * @param type TODO * @param isOptional * If a reference is defined as being optional, if it is optional * a not resolving of the reference won't result in an error. * @param token * partly redundant to <tt>keyValue</tt>, kept because in some * specific cases an unescaping from the token is necessary to * obtain the <tt>keyValue</tt>. */ protected DelayedReference(IModelElementProxy currentContext, Object currentForeachElement, Object object, String propertyName, String keyName, Object keyValue, String oclQuery, ReferenceType type, boolean isOptional, ANTLR3LocationToken token) { this.referenceContextObject = currentContext; this.currentForeachElement = currentForeachElement; this.modelElement = object; this.propertyName = propertyName; this.keyName = keyName; this.keyValue = keyValue; this.oclQuery = oclQuery; this.token = token; this.isOptional = isOptional; this.type = type; } /** * Used by * {@link ObservableInjectingParser#setPredicateRef(Object, String, String, String, List, IRuleName, boolean, String, ModelUpdaterRegistry)} */ protected DelayedReference(Object referenceContextObject, ReferenceType type, Object modelElement, String propertyName, String oclQuery, String mode, List<PredicateSemantic> list, IRuleName ruleNameFinder, ANTLR3LocationToken token, boolean hasContext, boolean isOptional) { super(); this.referenceContextObject = referenceContextObject; this.modelElement = modelElement; this.propertyName = propertyName; this.oclQuery = oclQuery; this.mode = mode; this.token = token; this.type = type; this.predicateActionList = list; this.ruleNameFinder = ruleNameFinder; this.hasContext = hasContext; this.isOptional = isOptional; } protected DelayedReference(Object currentContextElement, ReferenceType type, Object modelElement, Object semanticObject, Object opTemplateLefthand, String opName, List<SemanticDisambRuleData> ruleData, ANTLR3LocationToken lastToken, ANTLR3LocationToken firstToken, boolean hasContext2, boolean isOptional) { super(); this.referenceContextObject = currentContextElement; this.modelElement = modelElement; this.type = type; this.firstToken = firstToken; this.token = lastToken; this.isOptional = isOptional; this.hasContext = hasContext2; this.semRulData = ruleData; this.semanticObject = semanticObject; this.propertyName =opName; this.opTemplateLefthand = opTemplateLefthand; } public abstract boolean setDelayedReference(DelayedReference reference, IModelAdapter modelAdapter, ContextManager contextManager, ObservableInjectingParser parser) throws ModelAdapterException, ModelElementCreationException; /** * Gets the current context. * * @return the current context */ public Object getContextElement() { return referenceContextObject; } public Object getCurrentForeachElement() { return currentForeachElement; } public ANTLR3LocationToken getFirstToken() { return firstToken; } /** * Gets the model element of from which to set a reference to another * element. * * @return the element */ public Object getModelElement() { return modelElement; } /** * Determines which object will be used as <tt>self</tt> in evaluating the * OCL expression. Can either be a {@link ModelElementProxy proxy} or a * {@link RefObject}. If the OCL expression uses <tt>#context</tt>, the * {@link #getContextElement() context element} is used; otherwise the * {@link #getModelElement()} call is used. */ public Object getElementForSelf() { if (ContextAndForeachHelper.usesContext(getOclQuery())) { return getContextElement(); } else if (ContextAndForeachHelper.usesForeach(getOclQuery())) { return getCurrentForeachElement(); } else { return getModelElement(); } } /** * Gets the property name. * * @return the property name */ public String getPropertyName() { return propertyName; } /** * Gets the value type name. * * @return the value type name */ public List<String> getValueTypeName() { return valueTypeName; } /** * Gets the key name. * * @return the key name */ public String getKeyName() { return keyName; } /** * Gets the key value. * * @return the key value */ public Object getKeyValue() { return keyValue; } /** * Gets the look in. * * @return the look in */ public String getLookIn() { return lookIn; } /** * Gets the auto create. * * @return the auto create */ public String getAutoCreate() { return autoCreate; } /** * Gets the creates the as. * * @return the creates the as */ public List<String> getCreateAs() { return createAs; } /** * Checks if is import context. * * @return true, if is import context */ public boolean isImportContext() { return importContext; } /** * Gets the creates the in. * * @return the creates the in */ public String getCreateIn() { return createIn; } /** * Gets the token. * * @return the token */ public ANTLR3LocationToken getToken() { return token; } /** * Gets the InjectorAction or SequenceElement from where the query * originates. * * @return Either a InjectorAction or SequenceElement. */ public Object getQueryElement() { return queryElement; } /** * Gets the real value. * * @return the real value */ public Object getRealValue() { return realValue; } /** * Sets the real value. * * @param realValue * the new real value */ public void setRealValue(Object realValue) { this.realValue = realValue; } /** * @return the oclQuery */ public String getOclQuery() { return oclQuery; } /* * (non-Javadoc) * * @see java.lang.Object#toString() */ @Override public String toString() { String result = modelElement != null && modelElement.getClass() != null ? modelElement.getClass().getName() : "<generic>"; if(getType() == DelayedReference.ReferenceType.TYPE_FOREACH_PREDICATE) { result += " [FOR_EACH_PROPERTY_INIT] "; } result += '.' + getPropertyName() + "=>" + getValueTypeName(); if (getCreateAs() != null) { result += " as " + getCreateAs(); } result += " with " + getKeyName() + "=" + getKeyValue(); if (getCreateIn() != null) { result += " to create in " + getCreateIn(); } if(getOclQuery() != null) { result += " using query: " + getOclQuery(); } return result; } /** * @param result */ public void setModelElement(Object newObject) { this.modelElement = newObject; } /** * @param result */ public void setContextElement(Object newContext) { this.referenceContextObject = newContext; } /** * Returns whether the reference is optional which means that if it is not * resolved it won't result in an error. * * @return true if the referencer is optional. */ public boolean isOptional() { return isOptional; } /** * * @return mode */ public String getMode() { return mode; } public ReferenceType getType() { return type; } public List<PredicateSemantic> getPredicateActionList() { return predicateActionList; } public void setQueryElement(Object sequenceElementOrInjectorAction) { this.queryElement = sequenceElementOrInjectorAction; } public IRuleName getRuleNameFinder() { return ruleNameFinder; } public boolean hasContext() { return hasContext; } @Override public DelayedReference clone() { try { return (DelayedReference) super.clone(); } catch (CloneNotSupportedException e) { // this should never happen. return null; } } public void setTextBlock(Object textBlock) { this.textBlock = textBlock; } public Object getTextBlock() { return textBlock; } public List<SemanticDisambRuleData> getSemRulData() { return semRulData; } public Object getSemanticObject() { return semanticObject; } public Object getOpTemplateLefthand() { return opTemplateLefthand; } public boolean isSemanticDisambiguatedOperatorRule() { return false; } }