package org.ow2.mind.adl.generic; import static org.objectweb.fractal.adl.NodeUtil.cloneGraph; import static org.objectweb.fractal.adl.NodeUtil.cloneNode; import static org.ow2.mind.adl.ast.ASTHelper.isType; import static org.ow2.mind.adl.ast.ASTHelper.setResolvedComponentDefinition; import static org.ow2.mind.adl.ast.ASTHelper.unsetResolvedDefinition; import static org.ow2.mind.adl.generic.ast.GenericASTHelper.isPartiallyInstantiatedTemplate; import static org.ow2.mind.adl.generic.ast.GenericASTHelper.setAnyDefinition; import static org.ow2.mind.adl.generic.ast.GenericASTHelper.setPartiallyInstiantedTemplate; import java.util.Map; import org.objectweb.fractal.adl.ADLException; import org.objectweb.fractal.adl.Definition; import org.ow2.mind.adl.DefinitionReferenceResolver; import org.ow2.mind.adl.ast.Component; import org.ow2.mind.adl.ast.ComponentContainer; import org.ow2.mind.adl.ast.DefinitionReference; import org.ow2.mind.adl.generic.ast.FormalTypeParameter; import org.ow2.mind.adl.generic.ast.FormalTypeParameterReference; import org.ow2.mind.adl.generic.ast.TypeArgument; import org.ow2.mind.adl.generic.ast.TypeArgumentContainer; import com.google.inject.Inject; /** * Basic implementation of the {@link TemplateInstantiator} interface. The * instantiated definition is context-free. In particular, for the given * template: * * <pre> * composite Def1<U conformsto Type1, V conformsto Type2> { ... } * </pre> * * The following instantiations give the same result: * * <pre> * composite Def2<W conformsto Type1, Z conformsto Type1> { * contains Def1<W, Def3> as c1; * contains Def1<Z, Def3> as c2; * } * </pre> */ public class TemplateInstantiatorImpl implements TemplateInstantiator { @Inject protected DefinitionReferenceResolver definitionReferenceResolverItf; // --------------------------------------------------------------------------- // Implementation of the Loader interface // --------------------------------------------------------------------------- public Definition instantiateTemplate(final Definition genericDefinition, final Map<String, Object> typeArgumentValues, final Map<Object, Object> context) throws ADLException { // clone the genericDefinition to create the template instance final Definition templateInstance = cloneGraph(genericDefinition); // un-set 'PartiallyInstiantedTemplate' decoration. Will be re-set if needed setPartiallyInstiantedTemplate(templateInstance, false); // look for references to template variables into sub components if (templateInstance instanceof ComponentContainer) { for (final Component subComp : ((ComponentContainer) templateInstance) .getComponents()) { if (subComp.getDefinitionReference() != null) { final DefinitionReference defRef = subComp.getDefinitionReference(); final Definition d = instantiateDefinitionReference(defRef, templateInstance, typeArgumentValues, context); setResolvedComponentDefinition(subComp, d); if (isPartiallyInstantiatedTemplate(d)) setPartiallyInstiantedTemplate(templateInstance, true); } else if (subComp instanceof FormalTypeParameterReference && ((FormalTypeParameterReference) subComp) .getTypeParameterReference() != null) { // sub component is an instance of a formal type parameter. final FormalTypeParameterReference typeParamRef = (FormalTypeParameterReference) subComp; final String ref = typeParamRef.getTypeParameterReference(); // get the value of the formal type parameter. final Object value = typeArgumentValues.get(ref); assert value != null; if (value instanceof FormalTypeParameter) { // the value of the formal type parameter references another formal // type parameter final FormalTypeParameter typeParameter = (FormalTypeParameter) value; final Definition subCompDef = definitionReferenceResolverItf .resolve(typeParameter.getDefinitionReference(), null, context); setResolvedComponentDefinition(subComp, subCompDef); setPartiallyInstiantedTemplate(templateInstance, true); } else { assert value instanceof TypeArgument; final DefinitionReference defRef = ((TypeArgument) value) .getDefinitionReference(); if (defRef != null) { // the value of the formal type parameter is a definition // reference final Definition subCompDef = definitionReferenceResolverItf .resolve(defRef, null, context); if (!isPartiallyInstantiatedTemplate(subCompDef)) { typeParamRef.setTypeParameterReference(null); subComp.setDefinitionReference(cloneNode(defRef)); } setResolvedComponentDefinition(subComp, subCompDef); if (isPartiallyInstantiatedTemplate(subCompDef) || isType(subCompDef)) setPartiallyInstiantedTemplate(templateInstance, true); } else { // the value of the formal type parameter is "ANY" setAnyDefinition(subComp, (TypeArgument) value); } } } } } return templateInstance; } protected Definition instantiateDefinitionReference( final DefinitionReference defRef, final Definition templateInstance, final Map<String, Object> typeArgumentValues, final Map<Object, Object> context) throws ADLException { final boolean updated = updateDefinitionReference(defRef, typeArgumentValues, context); if (updated) { // unset resolved definition decoration to force re-evaluation of // definition reference. unsetResolvedDefinition(defRef); } final Definition d = definitionReferenceResolverItf.resolve(defRef, templateInstance, context); return d; } protected boolean updateDefinitionReference(final DefinitionReference defRef, final Map<String, Object> typeArgumentValues, final Map<Object, Object> context) throws ADLException { boolean updated = false; final TypeArgument[] typeArguments = (defRef instanceof TypeArgumentContainer) ? ((TypeArgumentContainer) defRef).getTypeArguments() : null; if (typeArguments != null) { // update definition reference to replace type parameter references by // there actual values and resolve the definition reference again. for (final TypeArgument typeArgument : typeArguments) { if (typeArgument.getTypeParameterReference() != null) { // the type argument is a reference to a formal type // parameter. final String ref = typeArgument.getTypeParameterReference(); final Object value = typeArgumentValues.get(ref); assert value != null; if (value instanceof TypeArgument) { final DefinitionReference definitionReference = ((TypeArgument) value) .getDefinitionReference(); typeArgument.setTypeParameterReference(null); typeArgument .setDefinitionReference(cloneGraph(definitionReference)); updated = true; // unset resolved definition decoration to force re-evaluation of // definition reference. unsetResolvedDefinition(defRef); } else { // do we need to do something ? } } else { final DefinitionReference typeArgumentDefRef = typeArgument .getDefinitionReference(); if (typeArgumentDefRef != null) { final boolean result = updateDefinitionReference( typeArgumentDefRef, typeArgumentValues, context); if (result) updated = true; } } } } return updated; } }