/**
* Copyright (C) 2009 STMicroelectronics
*
* This file is part of "Mind Compiler" is free software: you can redistribute
* it and/or modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact: mind@ow2.org
*
* Authors: Matthieu Leclercq
* Contributors:
*/
package org.ow2.mind.adl.ast;
import static java.lang.Integer.parseInt;
import static org.ow2.mind.CommonASTHelper.newNode;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import org.objectweb.fractal.adl.ADLException;
import org.objectweb.fractal.adl.Definition;
import org.objectweb.fractal.adl.Loader;
import org.objectweb.fractal.adl.Node;
import org.objectweb.fractal.adl.NodeFactory;
import org.objectweb.fractal.adl.interfaces.Interface;
import org.objectweb.fractal.adl.interfaces.InterfaceContainer;
import org.objectweb.fractal.adl.types.TypeInterface;
import org.objectweb.fractal.api.control.BindingController;
import org.ow2.mind.NodeContainerDecoration;
import org.ow2.mind.PathHelper;
import org.ow2.mind.adl.annotation.predefined.Singleton;
import org.ow2.mind.adl.generic.ast.FormalTypeParameterContainer;
import org.ow2.mind.adl.generic.ast.TypeArgumentContainer;
import org.ow2.mind.adl.parameter.ast.ArgumentContainer;
import org.ow2.mind.adl.parameter.ast.FormalParameterContainer;
import org.ow2.mind.annotation.AnnotationHelper;
/**
* Helper methods for ADL AST nodes.
*/
public class ASTHelper {
protected ASTHelper() {
}
// ---------------------------------------------------------------------------
// Definition helper methods
// ---------------------------------------------------------------------------
/**
* Returns <code>true</code> if the given definition is a type definition.
*
* @param def a definition.
* @return <code>true</code> if the given definition is a type definition.
*/
public static boolean isType(final Definition def) {
return !isPrimitive(def) && !isComposite(def);
}
/**
* Returns <code>true</code> if the given definition is a primitive
* definition.
*
* @param def a definition.
* @return <code>true</code> if the given definition is a primitive
* definition.
*/
public static boolean isPrimitive(final Definition def) {
return def instanceof ImplementationContainer;
}
/**
* Returns <code>true</code> if the given definition is a composite
* definition.
*
* @param def a definition.
* @return <code>true</code> if the given definition is a composite
* definition.
*/
public static boolean isComposite(final Definition def) {
return def instanceof ComponentContainer;
}
/**
* The name of the decoration used to indicate if a definition is singleton.
* This decoration should only be used by StringTemplate.
*/
public static final String SINGLETON_DECORATION_NAME = "is-singleton";
/**
* Returns <code>true</code> if the given definition has the {@link Singleton}
* decoration.
*
* @param def a definition.
* @return <code>true</code> if the given definition has the {@link Singleton}
* decoration.
*/
public static boolean isSingleton(final Definition def) {
return AnnotationHelper.getAnnotation(def, Singleton.class) != null;
}
/**
* Sets the {@value #SINGLETON_DECORATION_NAME} decoration to
* <code>true</code> on the given definition.
*
* @param def a definition.
*/
public static void setSingletonDecoration(final Definition def) {
def.astSetDecoration(SINGLETON_DECORATION_NAME, Boolean.TRUE);
}
/**
* Returns a new {@link Definition} that correspond to a definition of
* primitive component.
*
* @param nodeFactory the {@link NodeFactory} to use to create the node.
* @param name the {@link Definition#getName() name} of the definition.
* @param extended references to the extended definitions (may be
* <code>null</code>).
* @return a new {@link Definition} that correspond to a definition of
* primitive component.
*/
public static Definition newPrimitiveDefinitionNode(
final NodeFactory nodeFactory, final String name,
final DefinitionReference... extended) {
final MindDefinition d = newNode(nodeFactory, "primitive",
MindDefinition.class, AbstractDefinition.class,
InterfaceContainer.class, AttributeContainer.class,
ImplementationContainer.class, FormalParameterContainer.class);
d.setName(name);
if (extended != null && extended.length > 0) {
final DefinitionReferenceContainer extendz = newNode(nodeFactory,
"extends", DefinitionReferenceContainer.class);
for (final DefinitionReference ext : extended) {
extendz.addDefinitionReference(ext);
}
d.setExtends(extendz);
}
return d;
}
/**
* Returns a new {@link Definition} that correspond to a definition of
* composite component.
*
* @param nodeFactory the {@link NodeFactory} to use to create the node.
* @param name the {@link Definition#getName() name} of the definition.
* @param extended references to the extended definitions (may be
* <code>null</code>).
* @return a new {@link Definition} that correspond to a definition of
* primitive component.
*/
public static Definition newCompositeDefinitionNode(
final NodeFactory nodeFactory, final String name,
final DefinitionReference... extended) {
final MindDefinition d = newNode(nodeFactory, "primitive",
MindDefinition.class, InterfaceContainer.class,
ComponentContainer.class, BindingController.class,
FormalParameterContainer.class, FormalTypeParameterContainer.class);
d.setName(name);
if (extended != null && extended.length > 0) {
final DefinitionReferenceContainer extendz = newNode(nodeFactory,
"extends", DefinitionReferenceContainer.class);
for (final DefinitionReference ext : extended) {
extendz.addDefinitionReference(ext);
}
d.setExtends(extendz);
}
return d;
}
/**
* Returns a new {@link Definition} that correspond to an unresolved
* definition. This kind of definition node can be used as a return value of
* front-end components that must return a definition but was unable to load
* it.
*
* @param nodeFactory the {@link NodeFactory} to use to create the node.
* @param name the {@link Definition#getName() name} of the definition.
* @return a new {@link Definition} that correspond to an unresolved
* definition.
* @see #isUnresolvedDefinitionNode(Definition)
*/
public static Definition newUnresolvedDefinitionNode(
final NodeFactory nodeFactory, final String name) {
final MindDefinition d = newNode(nodeFactory, "unresolved",
MindDefinition.class);
d.setName(name);
return d;
}
/**
* Returns <code>true</code> if the given {@link Definition} does not
* correspond to a correct definition, but has been created by
* {@link #newUnresolvedDefinitionNode(NodeFactory, String)}.
*
* @param d a definition node.
* @return <code>true</code> if the given {@link Definition} correspond to an
* unresolved definition.
* @see #newUnresolvedDefinitionNode(NodeFactory, String)
*/
public static boolean isUnresolvedDefinitionNode(final Definition d) {
return d.astGetType().equals("unresolved");
}
// ---------------------------------------------------------------------------
// Interface helper methods
// ---------------------------------------------------------------------------
/**
* Returns the integer value of the {@link MindInterface#getNumberOfElement()
* numberOfElement} field of the given interface node.
*
* @param itf an {@link Interface} node.
* @return the integer value of the {@link MindInterface#getNumberOfElement()
* numberOfElement} field of the given interface node, or
* <code>-1</code> if the given interface does not have a
* numberOfElement field.
*/
public static int getNumberOfElement(final Interface itf) {
if (!(itf instanceof MindInterface)) return -1;
final String noe = ((MindInterface) itf).getNumberOfElement();
if (noe == null)
return -1;
else
return parseInt(noe);
}
/**
* Returns the interface node contained by the given container and having the
* given name.
*
* @param itfContainer a container.
* @param name the name of the interface to return.
* @return the interface node contained by the given container and having the
* given name, or <code>null</code> if the given container is not an
* {@link InterfaceContainer} or does not contain an interface with
* the given name.
*/
public static Interface getInterface(final Node itfContainer,
final String name) {
if (!(itfContainer instanceof InterfaceContainer)) return null;
for (final Interface itf : ((InterfaceContainer) itfContainer)
.getInterfaces()) {
if (name.equals(itf.getName())) return itf;
}
return null;
}
/**
* Create a new {@link MindInterface} node using the given {@link NodeFactory}
*
* @param nodeFactory the {@link NodeFactory} to use to create the node.
* @return a new {@link MindInterface} node.
*/
public static MindInterface newInterfaceNode(final NodeFactory nodeFactory) {
return newNode(nodeFactory, "interface", MindInterface.class);
}
/**
* Create a new client {@link MindInterface} node using the given
* {@link NodeFactory}
*
* @param nodeFactory the {@link NodeFactory} to use to create the node.
* @param name the name of the created interface.
* @param signature the signature of the created interface.
* @return a new {@link MindInterface} node.
*/
public static MindInterface newClientInterfaceNode(
final NodeFactory nodeFactory, final String name, final String signature) {
final MindInterface itf = newInterfaceNode(nodeFactory);
itf.setRole(TypeInterface.CLIENT_ROLE);
itf.setName(name);
itf.setSignature(signature);
return itf;
}
/**
* Create a new server {@link MindInterface} node using the given
* {@link NodeFactory}
*
* @param nodeFactory the {@link NodeFactory} to use to create the node.
* @param name the name of the created interface.
* @param signature the signature of the created interface.
* @return a new {@link MindInterface} node.
*/
public static MindInterface newServerInterfaceNode(
final NodeFactory nodeFactory, final String name, final String signature) {
final MindInterface itf = newInterfaceNode(nodeFactory);
itf.setRole(TypeInterface.SERVER_ROLE);
itf.setName(name);
itf.setSignature(signature);
return itf;
}
// ---------------------------------------------------------------------------
// Flow Interface helper methods
// ---------------------------------------------------------------------------
/**
* The {@link TypeInterface#getRole() role} of 'input' data-flow interface.
*/
public static final String INPUT_ROLE = "input";
/**
* The {@link TypeInterface#getRole() role} of 'output' data-flow interface.
*/
public static final String OUTPUT_ROLE = "output";
/**
* Returns <code>true</code> if the given interface is a flow interface (i.e.
* if its {@link TypeInterface#getRole() role} is either {@link #INPUT_ROLE}
* or {@link #OUTPUT_ROLE}).
*
* @param itf an interface.
* @return <code>true</code> if the given interface is a flow interface.
*/
public static boolean isFlowInterface(final Interface itf) {
if (!(itf instanceof TypeInterface)) return false;
final String role = ((TypeInterface) itf).getRole();
return (INPUT_ROLE.equals(role) || OUTPUT_ROLE.equals(role));
}
/**
* Returns <code>true</code> if the given interface is an output flow
* interface (i.e. if its {@link TypeInterface#getRole() role} is
* {@link #OUTPUT_ROLE}).
*
* @param itf an interface.
* @return <code>true</code> if the given interface is an output flow
* interface.
*/
public static boolean isOutput(final Interface itf) {
if (!(itf instanceof TypeInterface)) return false;
final String role = ((TypeInterface) itf).getRole();
return OUTPUT_ROLE.equals(role);
}
/**
* Returns <code>true</code> if the given interface is an input flow interface
* (i.e. if its {@link TypeInterface#getRole() role} is {@link #INPUT_ROLE}).
*
* @param itf an interface.
* @return <code>true</code> if the given interface is an input flow
* interface.
*/
public static boolean isInput(final Interface itf) {
if (!(itf instanceof TypeInterface)) return false;
final String role = ((TypeInterface) itf).getRole();
return INPUT_ROLE.equals(role);
}
// ---------------------------------------------------------------------------
// DefinitionReference helper methods
// ---------------------------------------------------------------------------
/**
* The name of the {@link Node#astSetDecoration(String, Object) decoration}
* used to attach the resolved {@link Definition} to a
* {@link DefinitionReference}.
*
* @see #setResolvedDefinition(DefinitionReference, Definition)
* @see #getResolvedDefinition(DefinitionReference, Loader, Map)
*/
public static final String RESOLVED_DEFINITION_DECORATION_NAME = "resolved-definition";
/**
* Sets the resolved {@link Definition} corresponding to the given
* {@link DefinitionReference}. The decoration that is actually attached to
* the given <code>defRef</code> node is an instance of
* {@link DefinitionDecoration}. This imply that, if the <code>defRef</code>
* is serialized, only the {@link Definition#getName() name} of the definition
* is serialized (and not the definition AST).
*
* @param defRef a definition reference.
* @param resolvedDef the corresponding definition.
* @see #getResolvedDefinition(DefinitionReference, Loader, Map)
*/
public static void setResolvedDefinition(final DefinitionReference defRef,
final Definition resolvedDef) {
defRef.astSetDecoration(RESOLVED_DEFINITION_DECORATION_NAME,
new DefinitionDecoration(resolvedDef));
}
/**
* Removes the resolved {@link Definition} on the given
* {@link DefinitionReference}.
*
* @param defRef a definition reference.
*/
public static void unsetResolvedDefinition(final DefinitionReference defRef) {
defRef.astSetDecoration(RESOLVED_DEFINITION_DECORATION_NAME, null);
}
/**
* Retrieve the {@link Definition} corresponding to the given
* {@link DefinitionReference}. Returns <code>null</code>, if the given
* <code>defRef</code> node has no
* {@link #RESOLVED_DEFINITION_DECORATION_NAME} decoration. If the decoration
* attached to the given <code>defRef</code> node contains only the definition
* name and not the definition AST (i.e. the <code>defRef</code> node has been
* de-serialized), the given <code>loaderItf</code> is used to load the
* corresponding definition.
*
* @param defRef a definition reference.
* @param loaderItf a {@link Loader} interface that is used if only the name
* of the definition is attached (and not the definition AST). May be
* <code>null</code>.
* @param context additional parameters. Used only if only the name of the
* definition is attached (and not the definition AST). May be
* <code>null</code>.
* @return the {@link Definition} corresponding to the given
* {@link DefinitionReference} or <code>null</code>, if the given
* <code>defRef</code> node has no
* {@link #RESOLVED_DEFINITION_DECORATION_NAME} decoration or if only
* the name of the definition is attached and <code>loaderItf</code>
* is <code>null</code>.
* @throws ADLException if an error occurs while
* {@link Loader#load(String, Map) loading} the definition using the
* given <code>loaderItf</code>.
*/
public static Definition getResolvedDefinition(
final DefinitionReference defRef, final Loader loaderItf,
final Map<Object, Object> context) throws ADLException {
final DefinitionDecoration definitionDecoration = (DefinitionDecoration) defRef
.astGetDecoration(RESOLVED_DEFINITION_DECORATION_NAME);
return getDefinition(definitionDecoration, loaderItf, context);
}
/**
* Create a new {@link DefinitionReference} node using the given
* {@link NodeFactory}
*
* @param nodeFactory the {@link NodeFactory} to use to create the node.
* @param name the {@link DefinitionReference#getName() name} attribute of the
* created node.
* @return a new {@link DefinitionReference} node.
*/
public static DefinitionReference newDefinitionReference(
final NodeFactory nodeFactory, final String name) {
final DefinitionReference defRef = newNode(nodeFactory,
"definitionReference", DefinitionReference.class,
ArgumentContainer.class, TypeArgumentContainer.class);
defRef.setName(name);
return defRef;
}
// ---------------------------------------------------------------------------
// Component helper methods
// ---------------------------------------------------------------------------
/**
* The name of the {@link Node#astSetDecoration(String, Object) decoration}
* used to attach the resolved {@link Definition} to a {@link Component}.
*
* @see #setResolvedComponentDefinition(Component, Definition)
* @see #getResolvedComponentDefinition(Component, Loader, Map)
*/
public static final String RESOLVED_COMPONENT_DEFINITION_DECORATION_NAME = "resolved-component-definition";
/**
* Sets the resolved {@link Definition} corresponding to the given
* {@link Component}. The decoration that is actually attached to the given
* <code>comp</code> node is an instance of {@link DefinitionDecoration}. This
* imply that, if the <code>comp</code> is serialized, only the
* {@link Definition#getName() name} of the definition is serialized (and not
* the definition AST).
*
* @param comp a component node.
* @param resolvedDef the corresponding definition.
* @see #getResolvedComponentDefinition(Component, Loader, Map)
*/
public static void setResolvedComponentDefinition(final Component comp,
final Definition resolvedDef) {
comp.astSetDecoration(RESOLVED_COMPONENT_DEFINITION_DECORATION_NAME,
new DefinitionDecoration(resolvedDef));
}
/**
* Retrieve the {@link Definition} corresponding to the given
* {@link Component}. Returns <code>null</code>, if the given
* <code>comp</code> node has no {@link #RESOLVED_DEFINITION_DECORATION_NAME}
* decoration. If the decoration attached to the given <code>comp</code> node
* contains only the definition name and not the definition AST (i.e. the
* <code>comp</code> node has been de-serialized), the given
* <code>loaderItf</code> is used to load the corresponding definition.
*
* @param comp a component node.
* @param loaderItf a {@link Loader} interface that is used if only the name
* of the definition is attached (and not the definition AST). May be
* <code>null</code>.
* @param context additional parameters. Used only if only the name of the
* definition is attached (and not the definition AST). May be
* <code>null</code>.
* @return the {@link Definition} corresponding to the given
* {@link DefinitionReference} or <code>null</code>, if the given
* <code>defRef</code> node has no
* {@link #RESOLVED_DEFINITION_DECORATION_NAME} decoration or if only
* the name of the definition is attached and <code>loaderItf</code>
* is <code>null</code>.
* @throws ADLException if an error occurs while
* {@link Loader#load(String, Map) loading} the definition using the
* given <code>loaderItf</code>.
*/
public static Definition getResolvedComponentDefinition(final Component comp,
final Loader loaderItf, final Map<Object, Object> context)
throws ADLException {
final DefinitionDecoration definitionDecoration = (DefinitionDecoration) comp
.astGetDecoration(RESOLVED_COMPONENT_DEFINITION_DECORATION_NAME);
return getDefinition(definitionDecoration, loaderItf, context);
}
/**
* Returns the component node contained by the given container and having the
* given name.
*
* @param componentContainer a container.
* @param name the name of the component to return.
* @return the component node contained by the given container and having the
* given name, or <code>null</code> if the given container is not a
* {@link ComponentContainer} or does not contain a component with the
* given name.
*/
public static Component getComponent(final Node componentContainer,
final String name) {
if (!(componentContainer instanceof ComponentContainer)) return null;
for (final Component subComp : ((ComponentContainer) componentContainer)
.getComponents()) {
if (name.equals(subComp.getName())) {
return subComp;
}
}
return null;
}
/**
* Create a new {@link Component} node using the given {@link NodeFactory}
*
* @param nodeFactory the {@link NodeFactory} to use to create the node.
* @param name the {@link Component#getName() name} attribute of the created
* node.
* @param defRef the reference to the definition that the created component
* node is an instance.
* @return a new {@link Component} node.
*/
public static Component newComponent(final NodeFactory nodeFactory,
final String name, final DefinitionReference defRef) {
final Component comp = newNode(nodeFactory, "component", Component.class);
comp.setName(name);
comp.setDefinitionReference(defRef);
return comp;
}
/**
* Create a new {@link Component} node using the given {@link NodeFactory}
*
* @param nodeFactory the {@link NodeFactory} to use to create the node.
* @param name the {@link Component#getName() name} attribute of the created
* node.
* @param definitionName the name of the definition that the created component
* node is an instance.
* @return a new {@link Component} node.
*/
public static Component newComponent(final NodeFactory nodeFactory,
final String name, final String definitionName) {
return newComponent(nodeFactory, name,
newDefinitionReference(nodeFactory, definitionName));
}
// ---------------------------------------------------------------------------
// Binding helper methods
// ---------------------------------------------------------------------------
/**
* Returns the integer value of the {@link Binding#getFromInterfaceNumber()
* fromInterfaceNumber} field of the given binding node.
*
* @param binding an {@link Binding} node.
* @return the integer value of the {@link Binding#getFromInterfaceNumber()
* fromInterfaceNumber} field of the given binding node, or
* <code>-1</code> if the given binding does not have a
* fromInterfaceNumber field.
*/
public static int getFromInterfaceNumber(final Binding binding) {
final String s = binding.getFromInterfaceNumber();
if (s == null)
return -1;
else
return parseInt(s);
}
/**
* Returns the integer value of the {@link Binding#getToInterfaceNumber()
* toInterfaceNumber} field of the given binding node.
*
* @param binding an {@link Binding} node.
* @return the integer value of the {@link Binding#getToInterfaceNumber()
* toInterfaceNumber} field of the given binding node, or
* <code>-1</code> if the given binding does not have a
* toInterfaceNumber field.
*/
public static int getToInterfaceNumber(final Binding binding) {
final String s = binding.getToInterfaceNumber();
if (s == null)
return -1;
else
return parseInt(s);
}
/**
* Create a new {@link Binding} node using the given {@link NodeFactory}
*
* @param nodeFactory the {@link NodeFactory} to use to create the node.
* @return a new {@link Binding} node.
*/
public static Binding newBinding(final NodeFactory nodeFactory) {
return newNode(nodeFactory, "binding", Binding.class);
}
public static final String FROM_COMPOSITE_CONTROLLER_DECORATION = "from-composite-controller";
public static void setFromCompositeControllerDecoration(
final Binding binding, final boolean b) {
binding.astSetDecoration(FROM_COMPOSITE_CONTROLLER_DECORATION, b);
}
public static boolean isFromCompositeControllerDecoration(
final Binding binding) {
final Boolean b = (Boolean) binding
.astGetDecoration(FROM_COMPOSITE_CONTROLLER_DECORATION);
return b != null && b;
}
public static final String TO_COMPOSITE_CONTROLLER_DECORATION = "to-composite-controller";
public static void setToCompositeControllerDecoration(final Binding binding,
final boolean b) {
binding.astSetDecoration(TO_COMPOSITE_CONTROLLER_DECORATION, b);
}
public static boolean isToCompositeControllerDecoration(final Binding binding) {
final Boolean b = (Boolean) binding
.astGetDecoration(TO_COMPOSITE_CONTROLLER_DECORATION);
return b != null && b;
}
// ---------------------------------------------------------------------------
// Implementation helper methods
// ---------------------------------------------------------------------------
/**
* Returns <code>true</code> if the given source node refers to a pre-compiled
* file (i.e. it refers to a file that ends with <code>.o</code>,
* <code>.a</code>, <code>.so</code> or <code>.dll</code>.
*
* @param src a source node.
* @return <code>true</code> if the given source node refers to a pre-compiled
* file.
*/
public static boolean isPreCompiled(final Source src) {
final String srcPath = src.getPath();
if (srcPath == null) return false;
final String srcExt = PathHelper.getExtension(srcPath);
return srcExt != null
&& (srcExt.equals("o") || srcExt.equals("a") || srcExt.equals("so") || srcExt
.equals("dll"));
}
/**
* Returns <code>true</code> if the given source node refers to an assembly
* source file (i.e. it refers to a file that ends with <code>.s</code>, or
* <code>.S</code>).
*
* @param src a source node.
* @return <code>true</code> if the given source node refers to an assembly
* source file.
*/
public static boolean isAssembly(final Source src) {
final String srcPath = src.getPath();
if (srcPath == null) return false;
final String srcExt = PathHelper.getExtension(srcPath);
return srcExt != null
&& (srcExt.equals("s") || srcExt.equals("S") || srcExt.equals("asm"));
}
/**
* Create a new {@link Source} node using the given {@link NodeFactory}
*
* @param nodeFactory the {@link NodeFactory} to use to create the node.
* @return a new {@link Source} node.
*/
public static Source newSource(final NodeFactory nodeFactory) {
return newNode(nodeFactory, "source", Source.class);
}
/**
* Create a new {@link Data} node using the given {@link NodeFactory}
*
* @param nodeFactory the {@link NodeFactory} to use to create the node.
* @return a new {@link Data} node.
*/
public static Data newData(final NodeFactory nodeFactory) {
return newNode(nodeFactory, "data", Data.class);
}
// ---------------------------------------------------------------------------
// Attribute helper methods
// ---------------------------------------------------------------------------
/**
* Returns the attribute node contained by the given container and having the
* given name.
*
* @param attributeContainer a container.
* @param name the name of the attribute to return.
* @return the attribute node contained by the given container and having the
* given name, or <code>null</code> if the given container is not an
* {@link AttributeContainer} or does not contain an attribute with
* the given name.
*/
public static Attribute getAttribute(final Node attributeContainer,
final String name) {
if (!(attributeContainer instanceof AttributeContainer)) return null;
for (final Attribute attr : ((AttributeContainer) attributeContainer)
.getAttributes()) {
if (name.equals(attr.getName())) {
return attr;
}
}
return null;
}
/**
* Create a new {@link Attribute} node using the given {@link NodeFactory}
*
* @param nodeFactory the {@link NodeFactory} to use to create the node.
* @return a new {@link Attribute} node.
*/
public static Attribute newAttribute(final NodeFactory nodeFactory) {
return newNode(nodeFactory, "attribute", Attribute.class);
}
// ---------------------------------------------------------------------------
// Factory helper methods
// ---------------------------------------------------------------------------
public static final String FACTORY_INSTANTIATED_DEFINITION_DECORATION_NAME = "factory-definition";
public static void setFactoryInstantiatedDefinition(
final Definition factoryDefinition,
final Definition instantiatedDefinition) {
factoryDefinition.astSetDecoration(
FACTORY_INSTANTIATED_DEFINITION_DECORATION_NAME,
new DefinitionDecoration(instantiatedDefinition));
}
public static Definition getFactoryInstantiatedDefinition(
final Definition factoryDefinition, final Loader loaderItf,
final Map<Object, Object> context) throws ADLException {
final DefinitionDecoration definitionDecoration = (DefinitionDecoration) factoryDefinition
.astGetDecoration(FACTORY_INSTANTIATED_DEFINITION_DECORATION_NAME);
return getDefinition(definitionDecoration, loaderItf, context);
}
// ---------------------------------------------------------------------------
// DefinitionQualifiers helper methods
// ---------------------------------------------------------------------------
/**
* Returns <code>true</code> if the given definition has the
* {@link AbstractDefinition#getIsAbstract() abstract} qualifier.
*
* @param definition a definition.
* @return <code>true</code> if the given definition implements the
* {@link AbstractDefinition} interface and has the
* {@link AbstractDefinition#getIsAbstract() abstract} qualifier.
*/
public static boolean isAbstract(final Definition definition) {
return (definition instanceof AbstractDefinition)
&& AbstractDefinition.TRUE
.equalsIgnoreCase(((AbstractDefinition) definition).getIsAbstract());
}
// ---------------------------------------------------------------------------
// Utility methods
// ---------------------------------------------------------------------------
public static Definition getDefinition(
final DefinitionDecoration definitionDecoration, final Loader loaderItf,
final Map<Object, Object> context) throws ADLException {
if (definitionDecoration == null) {
return null;
} else {
Definition definition = definitionDecoration.getDefinition();
if (definition == null && loaderItf != null) {
definition = loaderItf.load(definitionDecoration.getDefinitionName(),
context);
definitionDecoration.setDefinition(definition);
}
return definition;
}
}
/**
* Instances of this class are used as decoration by
* {@link ASTHelper#setResolvedDefinition(DefinitionReference, Definition)}
* and {@link ASTHelper#setResolvedComponentDefinition(Component, Definition)}
* . This class contains the attached {@link Definition} AST and its name.
* When instances of this class are serialized, only the name of the
* definition is actually serialized (i.e. the definition AST is transient).
* This implies that de-serialized instance of this class will only contains
* the name of the definition. This is why
* {@link ASTHelper#getResolvedDefinition} and
* {@link ASTHelper#getResolvedComponentDefinition} methods have a
* <code>loaderItf</code> parameter that is used in that case to re-load the
* corresponding definition AST.
*/
public static final class DefinitionDecoration
implements
NodeContainerDecoration,
Serializable {
private transient Definition definition;
private final String definitionName;
/**
* Default constructor.
*
* @param definition the attached definition.
*/
public DefinitionDecoration(final Definition definition) {
if (definition == null)
throw new IllegalArgumentException("definition can't be null");
if (definition.getName() == null)
throw new IllegalArgumentException("definition's name can't be null");
this.definition = definition;
definitionName = definition.getName();
}
/**
* @return the attached definition or <code>null</code> if this object do
* not contains a definition.
*/
public Definition getDefinition() {
return definition;
}
/**
* Sets the definition AST corresponding to this decoration.
*
* @param definition the definition AST corresponding to this decoration.
* @throws IllegalArgumentException if the name of the given definition do
* not match the name contained by this decoration.
*/
public void setDefinition(final Definition definition) {
if (definition == null)
throw new IllegalArgumentException("definition can't be null");
if (definition.getName() == null)
throw new IllegalArgumentException("definition's name can't be null");
if (!definition.getName().equals(definitionName))
throw new IllegalArgumentException("Wrong definition name \""
+ definitionName + "\" expected instead of \""
+ definition.getName() + "\".");
this.definition = definition;
}
/**
* @return the name of the definition attached with this decoration.
*/
public String getDefinitionName() {
return definitionName;
}
// -------------------------------------------------------------------------
// Implementation of the NodeContainerDecoration interface
// -------------------------------------------------------------------------
public Collection<Node> getNodes() {
if (definition == null) {
return Collections.emptyList();
} else {
final List<Node> l = new ArrayList<Node>();
l.add(definition);
return l;
}
}
public void replaceNodes(final IdentityHashMap<Node, Node> replacements) {
if (replacements.containsKey(definition)) {
definition = (Definition) replacements.get(definition);
}
}
}
}