Mail Archive Home | fractal-commits List | June 2008 Index
| <-- Date Index --> | <-- Thread Index --> |
Minor improvement in AbstractNode class The NodeClassLoader generates a class with two constructors: The default one (without parameter) creates a node whose astType is the default one (i.e. the one given to the NodeClassLoader.generateClass) The second one take as parameter the astType of the node to create Add a new NodeFactory interface and implementation. This node factory allows to generate node classes without writing a DTD file. Add a 'cloneGraph' method in NodeUtil. This method handles shared nodes correctly. Fix in Node[Input/Output]Stream: Handles Node in decorations Refactor the NodeMerger implementation to simply its extension by subclasses. This allows in particular to write sub-class of NodeMergerImpl that introduces semantic in AST merging.
--- trunk/fractaladl/toolchain/ast-core/src/main/java/org/objectweb/fractal/adl/AbstractNode.java 2008-06-29 14:16:17 UTC (rev 7983)
+++ trunk/fractaladl/toolchain/ast-core/src/main/java/org/objectweb/fractal/adl/AbstractNode.java 2008-06-30 08:59:50 UTC (rev 7984)
@@ -33,9 +33,10 @@
public abstract class AbstractNode implements Node {
- private String type;
+ private final String type;
private String source;
+
// On-demand allocation of the decoration map to minimize the memory
// footprint.
private Map<String, Object> decorations;
@@ -50,14 +51,13 @@
* @return allocated decoration map.
*/
private Map<String, Object> decorations() {
- if (this.decorations == null)
- this.decorations = new HashMap<String, Object>();
- return this.decorations;
+ if (decorations == null) decorations = new HashMap<String, Object>();
+ return decorations;
}
- // --------------------------------------------------------------------------
+ // ---------------------------------------------------------------------------
// Implementation of the Node interface
- // --------------------------------------------------------------------------
+ // ---------------------------------------------------------------------------
public String astGetType() {
return type;
@@ -71,36 +71,43 @@
this.source = source;
}
- public Object astGetDecoration(String name) {
- return this.decorations().get(name);
+ public Object astGetDecoration(final String name) {
+ if (decorations == null)
+ return null;
+ else
+ return this.decorations().get(name);
}
public Map<String, Object> astGetDecorations() {
- return new HashMap<String, Object>(this.decorations());
+ if (decorations == null)
+ return new HashMap<String, Object>();
+ else
+ return new HashMap<String, Object>(this.decorations());
}
- public void astSetDecoration(String name, Object decoration) {
+ public void astSetDecoration(final String name, final Object decoration) {
this.decorations().put(name, decoration);
}
- public void astSetDecorations(Map<String, Object> decorations) {
- this.decorations().putAll(decorations);
+ public void astSetDecorations(final Map<String, Object> decorations) {
+ if (decorations.size() > 0) this.decorations().putAll(decorations);
}
- // --------------------------------------------------------------------------
+ // ---------------------------------------------------------------------------
// Overridden methods
- // --------------------------------------------------------------------------
+ // ---------------------------------------------------------------------------
@Override
public String toString() {
// look for a "name" attribute
- Map<String, String> attributes = astGetAttributes();
- String name = attributes.get("name");
+ final Map<String, String> attributes = astGetAttributes();
+ final String name = attributes.get("name");
if (name != null) {
return type + '<' + name + '>';
} else if (attributes.size() == 1) {
// node contains only one attribute
- Map.Entry<String, String> attr = attributes.entrySet().iterator().next();
+ final Map.Entry<String, String> attr = attributes.entrySet().iterator()
+ .next();
return type + '<' + attr.getKey() + '=' + attr.getValue() + '>';
} else {
return type + '@' + System.identityHashCode(this);
--- trunk/fractaladl/toolchain/ast-core/src/main/java/org/objectweb/fractal/adl/Node.java 2008-06-29 14:16:17 UTC (rev 7983)
+++ trunk/fractaladl/toolchain/ast-core/src/main/java/org/objectweb/fractal/adl/Node.java 2008-06-30 08:59:50 UTC (rev 7984)
@@ -44,7 +44,6 @@
*
* @return the type of this node.
*/
-
String astGetType();
/**
@@ -52,7 +51,6 @@
*
* @return the source of this node (such as a file name).
*/
-
String astGetSource();
/**
@@ -60,7 +58,6 @@
*
* @param source the source of this node (such as a file name).
*/
-
void astSetSource(String source);
/**
@@ -68,7 +65,6 @@
*
* @return the attributes of this node.
*/
-
Map<String, String> astGetAttributes();
/**
@@ -78,7 +74,6 @@
* (attributes that are not defined in this argument are left
* unchanged).
*/
-
void astSetAttributes(Map<String, String> attributes);
/**
@@ -88,7 +83,6 @@
* @return a decoration of this node. May be <code>null</code> if this node
* does not have a decoration with the specified name.
*/
-
Object astGetDecoration(String name);
/**
@@ -97,7 +91,6 @@
* @param name the decoration's name.
* @param decoration a decoration.
*/
-
void astSetDecoration(String name, Object decoration);
/**
@@ -105,7 +98,6 @@
*
* @return the decorations of this node.
*/
-
Map<String, Object> astGetDecorations();
/**
@@ -115,7 +107,6 @@
* (decorations that are not defined in this argument are left
* unchanged).
*/
-
void astSetDecorations(Map<String, Object> decorations);
/**
@@ -123,7 +114,6 @@
*
* @return the types of the sub nodes that this node can have.
*/
-
String[] astGetNodeTypes();
/**
@@ -132,7 +122,6 @@
* @param type a node type.
* @return the sub nodes of this node that are of the given type.
*/
-
Node[] astGetNodes(String type);
/**
@@ -140,7 +129,6 @@
*
* @param node the sub node to be added to this node.
*/
-
void astAddNode(Node node);
/**
@@ -148,7 +136,6 @@
*
* @param node the sub node to be removed from this node.
*/
-
void astRemoveNode(Node node);
/**
@@ -156,6 +143,5 @@
*
* @return a new, empty AST node of the same type as this node.
*/
-
Node astNewInstance();
}
--- trunk/fractaladl/toolchain/ast-core/src/main/java/org/objectweb/fractal/adl/NodeClassLoader.java 2008-06-29 14:16:17 UTC (rev 7983)
+++ trunk/fractaladl/toolchain/ast-core/src/main/java/org/objectweb/fractal/adl/NodeClassLoader.java 2008-06-30 08:59:50 UTC (rev 7984)
@@ -77,18 +77,32 @@
final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
cw.visit(V1_1, ACC_PUBLIC, owner, null, superClass, itfs);
- final MethodVisitor icv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null,
- null);
+ final MethodVisitor icv = cw.visitMethod(ACC_PUBLIC, "<init>",
+ "(Ljava/lang/String;)V", null, null);
icv.visitVarInsn(ALOAD, 0);
- icv.visitLdcInsn(astNodeType);
+ icv.visitVarInsn(ALOAD, 1);
icv.visitMethodInsn(INVOKESPECIAL, superClass, "<init>",
"(Ljava/lang/String;)V");
+ final MethodVisitor icv2 = cw.visitMethod(ACC_PUBLIC, "<init>", "()V",
+ null, null);
+ icv2.visitVarInsn(ALOAD, 0);
+ icv2.visitLdcInsn(astNodeType);
+ icv2.visitMethodInsn(INVOKESPECIAL, owner, "<init>",
+ "(Ljava/lang/String;)V");
+ icv2.visitInsn(RETURN);
+ icv2.visitMaxs(0, 0);
+
final MethodVisitor ani = cw.visitMethod(ACC_PUBLIC, "astNewInstance",
"()L" + node + ";", null, null);
ani.visitTypeInsn(NEW, owner);
ani.visitInsn(DUP);
- ani.visitMethodInsn(INVOKESPECIAL, owner, "<init>", "()V");
+ ani.visitVarInsn(ALOAD, 0);
+ ani.visitMethodInsn(INVOKEVIRTUAL, owner, "astGetType",
+ "()Ljava/lang/String;");
+ ani
+ .visitMethodInsn(INVOKESPECIAL, owner, "<init>",
+ "(Ljava/lang/String;)V");
ani.visitInsn(ARETURN);
ani.visitMaxs(0, 0);
--- trunk/fractaladl/toolchain/ast-core/src/main/java/org/objectweb/fractal/adl/NodeFactory.java (rev 0)
+++ trunk/fractaladl/toolchain/ast-core/src/main/java/org/objectweb/fractal/adl/NodeFactory.java 2008-06-30 08:59:50 UTC (rev 7984)
@@ -0,0 +1,61 @@
+/***
+ * Fractal ADL Parser
+ * Copyright (C) 2008 STMicroelectronics
+ *
+ * This library 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 2 of the License, or (at your option) any later version.
+ *
+ * This library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Contact: fractal@xxxxxxxxxxxxx
+ *
+ * Author: Matthieu Leclercq
+ */
+
+package org.objectweb.fractal.adl;
+
+/**
+ * Interface to create AST node instance from a set of AST Node interface.
+ */
+public interface NodeFactory {
+
+ /** The default name of this interface. */
+ String ITF_NAME = "node-factory";
+
+ /**
+ * Creates a new AST Node instance that implements the given interfaces and
+ * that have the given {@link Node#astGetType() nodeType}.
+ *
+ * @param nodeType the node type.
+ * @param interfaces the AST interfaces that must be implemented by the
+ * created node.
+ * @return a node instance.
+ * @throws ClassNotFoundException if one of the interfaces can't be found.
+ */
+ Node newNode(String nodeType, String... interfaces)
+ throws ClassNotFoundException;
+
+ /**
+ * Gets the class loader used by this node factory.
+ *
+ * @return the class loader used by this node factory.
+ */
+ ClassLoader getClassLoader();
+
+ /**
+ * Sets the class loader used by this node factory.
+ *
+ * @param loader the class loader used by this node factory.
+ */
+ void setClassLoader(ClassLoader loader);
+
+}
--- trunk/fractaladl/toolchain/ast-core/src/main/java/org/objectweb/fractal/adl/NodeFactoryImpl.java (rev 0)
+++ trunk/fractaladl/toolchain/ast-core/src/main/java/org/objectweb/fractal/adl/NodeFactoryImpl.java 2008-06-30 08:59:50 UTC (rev 7984)
@@ -0,0 +1,121 @@
+/***
+ * Fractal ADL Parser
+ * Copyright (C) 2008 STMicroelectronics
+ *
+ * This library 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 2 of the License, or (at your option) any later version.
+ *
+ * This library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Contact: fractal@xxxxxxxxxxxxx
+ *
+ * Author: Matthieu Leclercq
+ */
+
+package org.objectweb.fractal.adl;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.Type;
+
+/**
+ * Default implementation of the {@link NodeFactory} interface.
+ */
+public class NodeFactoryImpl implements NodeFactory {
+
+ protected ClassLoader classLoader = getClass().getClassLoader();
+ SimpleNodeClassLoader nodeClassLoader;
+
+ // ---------------------------------------------------------------------------
+ // Implementation of the XMLNodeFactory interface
+ // ---------------------------------------------------------------------------
+
+ public Node newNode(final String nodeType, final String... interfaces)
+ throws ClassNotFoundException {
+ if (nodeClassLoader == null)
+ nodeClassLoader = new SimpleNodeClassLoader(classLoader);
+
+ final Class<? extends Node> c = nodeClassLoader.getNodeClass(interfaces);
+ try {
+ return c.getConstructor(String.class).newInstance(nodeType);
+ } catch (final Exception e) {
+ throw new Error("An error occurs while instantiating Node", e);
+ }
+ }
+
+ public ClassLoader getClassLoader() {
+ return classLoader;
+ }
+
+ public void setClassLoader(final ClassLoader loader) {
+ if (loader != classLoader) {
+ classLoader = loader;
+ nodeClassLoader = null;
+ }
+ }
+
+ // ---------------------------------------------------------------------------
+ // Inner classes
+ // ---------------------------------------------------------------------------
+
+ static class SimpleNodeClassLoader extends NodeClassLoader {
+
+ final Map<NodeClassId, Class<? extends Node>> classes = new HashMap<NodeClassId, Class<? extends Node>>();
+
+ SimpleNodeClassLoader(final ClassLoader parent) {
+ super(parent);
+ }
+
+ @SuppressWarnings("unchecked")
+ Class<? extends Node> getNodeClass(final String... itfs)
+ throws ClassNotFoundException {
+ Class<? extends Node> c = classes.get(itfs);
+ if (c != null) {
+ final String name = "org.objectweb.fractal.adl.Node" + classes.size();
+ final ClassWriter cw = generateClass(name, name, Type
+ .getInternalName(AbstractNode.class), itfs);
+
+ c = (Class<? extends Node>) defineClass(name, cw.toByteArray());
+ classes.put(new NodeClassId(itfs), c);
+ }
+ return c;
+ }
+ }
+
+ static final class NodeClassId {
+ final String[] itfs;
+
+ NodeClassId(final String[] itfs) {
+ this.itfs = itfs;
+ }
+
+ @Override
+ public int hashCode() {
+ return Arrays.deepHashCode(itfs);
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == this) return true;
+
+ if (obj instanceof String[])
+ return Arrays.equals(itfs, (String[]) obj);
+ else if (obj instanceof NodeClassId)
+ return Arrays.equals(itfs, ((NodeClassId) obj).itfs);
+ else
+ return false;
+ }
+ }
+}
--- trunk/fractaladl/toolchain/ast-core/src/main/java/org/objectweb/fractal/adl/NodeUtil.java 2008-06-29 14:16:17 UTC (rev 7983)
+++ trunk/fractaladl/toolchain/ast-core/src/main/java/org/objectweb/fractal/adl/NodeUtil.java 2008-06-30 08:59:50 UTC (rev 7984)
@@ -23,6 +23,9 @@
package org.objectweb.fractal.adl;
+import java.util.IdentityHashMap;
+import java.util.Map;
+
/**
* An helper class that provides a method to easily clone and cast AST node.
*/
@@ -54,11 +57,16 @@
}
/**
- * Clone the given {@link Node} and its sub nodes recursively.
+ * Clone the given {@link Node} and its sub nodes recursively. <br>
+ * <b>Warning</b>: this method consider that the given node is the root of a
+ * <b>tree graph</b> (i.e. any transitive sub node of the given node is the
+ * sub node of one and only one node). Use {@link #cloneGraph(Node)} method if
+ * this condition is not true.
*
* @param <T> The type of the node.
* @param node the root of the tree to clone.
* @return a clone of the given tree of node.
+ * @see #cloneGraph(Node)
*/
public static <T extends Node> T cloneTree(final T node) {
final T newNode = cloneNodeState(node);
@@ -73,7 +81,41 @@
return newNode;
}
+ /**
+ * Clone the given {@link Node} and its sub nodes recursively. This method
+ * handles shared nodes correctly.
+ *
+ * @param <T> The type of the node.
+ * @param node the root of the graph to clone.
+ * @return a clone of the given graph of node.
+ */
+ public static <T extends Node> T cloneGraph(final T node) {
+ return cloneGraph(node, new IdentityHashMap<Node, Node>());
+ }
+
@SuppressWarnings("unchecked")
+ private static <T extends Node> T cloneGraph(final T node,
+ final Map<Node, Node> clonedNodes) {
+ T clone = (T) clonedNodes.get(node);
+
+ if (clone == null) {
+ clone = cloneNodeState(node);
+
+ // add sub nodes
+ for (final String subNodeType : node.astGetNodeTypes()) {
+ for (final Node subNode : node.astGetNodes(subNodeType)) {
+ if (subNode != null)
+ clone.astAddNode(cloneGraph(subNode, clonedNodes));
+ }
+ }
+
+ clonedNodes.put(node, clone);
+ }
+
+ return clone;
+ }
+
+ @SuppressWarnings("unchecked")
private static <T extends Node> T cloneNodeState(final T node) {
// first create a new node instance
final T newNode = (T) node.astNewInstance();
--- trunk/fractaladl/toolchain/ast-core/src/main/java/org/objectweb/fractal/adl/io/NodeInputStream.java 2008-06-29 14:16:17 UTC (rev 7983)
+++ trunk/fractaladl/toolchain/ast-core/src/main/java/org/objectweb/fractal/adl/io/NodeInputStream.java 2008-06-30 08:59:50 UTC (rev 7984)
@@ -123,7 +123,6 @@
*/
public synchronized void reset() throws IOException {
nodeClassIds.clear();
- in.reset();
}
/**
@@ -221,10 +220,17 @@
node.astSetAttributes(attributes);
// read decorations
- final int nbDecoration = in.readInt();
- for (int i = 0; i < nbDecoration; i++) {
+ byte decoState;
+ while ((decoState = in.readByte()) != NodeOutputStream.END_OF_DECO) {
final String name = in.readUTF();
- final Object value = in.readObject();
+ Object value;
+ if (decoState == NodeOutputStream.OBJ_DECO) {
+ value = in.readObject();
+ } else if (decoState == NodeOutputStream.NODE_DECO) {
+ value = readNode();
+ } else {
+ throw new IOException("Stream Error");
+ }
node.astSetDecoration(name, value);
}
--- trunk/fractaladl/toolchain/ast-core/src/main/java/org/objectweb/fractal/adl/io/NodeOutputStream.java 2008-06-29 14:16:17 UTC (rev 7983)
+++ trunk/fractaladl/toolchain/ast-core/src/main/java/org/objectweb/fractal/adl/io/NodeOutputStream.java 2008-06-30 08:59:50 UTC (rev 7984)
@@ -45,6 +45,11 @@
protected static final byte NULL_REF = (byte) 0x10;
protected static final byte NEW_NODE = (byte) 0x11;
protected static final byte NODE_REF = (byte) 0x12;
+
+ protected static final byte OBJ_DECO = (byte) 0x20;
+ protected static final byte NODE_DECO = (byte) 0x21;
+ protected static final byte END_OF_DECO = (byte) 0x22;
+
protected static final byte NEW_CLASS = (byte) 0x70;
protected static final byte CLASS_REF = (byte) 0x71;
@@ -190,24 +195,22 @@
}
// write node decorations
-
- // count number of serializable decoration
- int nbDecoration = 0;
- for (final Object decoration : node.astGetDecorations().values()) {
- if (decoration instanceof Serializable) nbDecoration++;
- }
- // write number of decoration
- out.writeInt(nbDecoration);
- // write decorations
for (final Map.Entry<String, Object> decoration : node.astGetDecorations()
.entrySet()) {
- // serialize only Serializable decorations
- if (!(decoration.getValue() instanceof Serializable)) continue;
-
- // assert that decoration name is not null, use writeUTF .
- out.writeUTF(decoration.getKey());
- out.writeObject(decoration.getValue());
+ final Object deco = decoration.getValue();
+ if (deco == null || deco instanceof Serializable) {
+ out.writeByte(OBJ_DECO);
+ // assert that decoration name is not null, use writeUTF .
+ out.writeUTF(decoration.getKey());
+ out.writeObject(deco);
+ } else if (deco instanceof Node) {
+ out.writeByte(NODE_DECO);
+ // assert that decoration name is not null, use writeUTF .
+ out.writeUTF(decoration.getKey());
+ writeNode((Node) deco);
+ }
}
+ out.writeByte(END_OF_DECO);
// write sub nodes
--- trunk/fractaladl/toolchain/ast-core/src/main/java/org/objectweb/fractal/adl/merger/MergeException.java 2008-06-29 14:16:17 UTC (rev 7983)
+++ trunk/fractaladl/toolchain/ast-core/src/main/java/org/objectweb/fractal/adl/merger/MergeException.java 2008-06-30 08:59:50 UTC (rev 7984)
@@ -58,11 +58,22 @@
/**
* Constructs a new {@link MergeException}.
*
+ * @param e the exception that caused this exception.
+ */
+
+ public MergeException(final Throwable e) {
+ super(e);
+ src = ""
+ }
+
+ /**
+ * Constructs a new {@link MergeException}.
+ *
* @param msg a detail message.
* @param e the exception that caused this exception.
*/
- public MergeException(final String msg, final Exception e) {
+ public MergeException(final String msg, final Throwable e) {
super(msg, e);
src = ""
}
@@ -75,7 +86,7 @@
* @param e the exception that caused this exception.
*/
- public MergeException(final String msg, final Node src, final Exception e) {
+ public MergeException(final String msg, final Node src, final Throwable e) {
super(msg, e);
this.src = ""
}
--- trunk/fractaladl/toolchain/ast-core/src/main/java/org/objectweb/fractal/adl/merger/NodeMergerImpl.java 2008-06-29 14:16:17 UTC (rev 7983)
+++ trunk/fractaladl/toolchain/ast-core/src/main/java/org/objectweb/fractal/adl/merger/NodeMergerImpl.java 2008-06-30 08:59:50 UTC (rev 7984)
@@ -60,9 +60,9 @@
*/
private final Map<Class<?>, Map<String, SubNodeArity>> subNodeArityCache = new IdentityHashMap<Class<?>, Map<String, SubNodeArity>>();
- // -------------------------------------------------------------------------
+ // ---------------------------------------------------------------------------
// Constructor
- // -------------------------------------------------------------------------
+ // ---------------------------------------------------------------------------
/**
* Default constructor.
@@ -76,6 +76,10 @@
mergeClassLoader = new MergeClassLoader(classLoader);
}
+ // ---------------------------------------------------------------------------
+ // Implementation of the NodeMerger interface
+ // ---------------------------------------------------------------------------
+
public Node merge(final Node elem, final Node superElem,
final Map<String, String> idAttributes) throws MergeException {
final Map<Node, MergeInfo> infos = new HashMap<Node, MergeInfo>();
@@ -95,7 +99,7 @@
return n;
}
- private MergeInfo computeMergeInfos(final Node elem, final Node superElem,
+ protected MergeInfo computeMergeInfos(final Node elem, final Node superElem,
final Map<Node, MergeInfo> infos, final Map<String, String> idAttributes)
throws MergeException {
MergeInfo info = infos.get(elem);
@@ -149,92 +153,98 @@
assert superNodes.length <= 1;
assert nodes.length <= 1;
- if (superNodes.length > 0 && superNodes[0] != null) {
+ final Node node = (nodes.length > 0) ? nodes[0] : null;
+ final Node superNode = (superNodes.length > 0) ? superNodes[0] : null;
+
+ if (superNode != null) {
// there is a node in 'superNodes'
- if (nodes.length == 0 || nodes[0] == null) {
+ if (node == null) {
// there is no node in 'nodes'
- info.addSubNodeInfo(computeMergeInfos(superNodes[0], infos));
+ computeInhertedSubNodeMergeInfos(superNode, info, nodeType, infos);
} else {
// there is a node both in 'nodes' and 'superNodes'. merge them
- info.addSubNodeInfo(computeMergeInfos(nodes[0], superNodes[0],
- infos, idAttributes));
+ computeMergedSubNodesMergeInfos(node, superNode, info, infos,
+ idAttributes, nodeType);
}
- } else if (nodes.length > 0 && nodes[0] != null) {
- // there is a node only in 'nodes'
- info.addSubNodeInfo(computeMergeInfos(nodes[0], infos));
+ } else if (node != null) {
+ computeSubNodeMergeInfos(node, info, nodeType, infos);
}
} else { // arity == SubNodeArity.MANY
- // get the name of the attribute that identify the one sub node of type
- // 'nodeType' among others.
- final String nameAttr = idAttributes.get(nodeType);
- if (nameAttr == null) {
- // there is no attribute that identify sub nodes, do not merge nodes
- for (final Node n : superNodes)
- info.addSubNodeInfo(computeMergeInfos(n, infos));
- for (final Node n : nodes)
- info.addSubNodeInfo(computeMergeInfos(n, infos));
+ final Set<Node> nodeSet = new HashSet<Node>();
+ for (final Node node : nodes)
+ nodeSet.add(node);
- } else { // nameAttr != null
- // there is an attribute that identify sub nodes, find a node of
- // 'nodes' and a node of 'superNodes' that have the same value for
- // this attribute.
- superNodeLoop : for (final Node superNode : superNodes) {
- // get the value of attribute 'nameAttr' of node 'superNode'
- final String superName = superNode.astGetAttributes().get(nameAttr);
- // Check that the value is not null
- if (superName != null) {
- // for each node in 'Nodes'
- for (final Node node : nodes) {
- // get the value of attribute 'nameAttr' of node 'node'
- final String name = node.astGetAttributes().get(nameAttr);
- // Check that the value is not null
- if (name == null) continue;
+ // For each superNode, find a node among 'nodes' that overrides it.
+ for (final Node superNode : superNodes) {
+ final Node overridingNode = findOverridingNode(superNode, nodes,
+ nodeType, idAttributes);
- if (name.equals(superName)) {
- // 'name' and 'superName' are equals, merge 'node' and
- // 'superNode'
- info.addSubNodeInfo(computeMergeInfos(node, superNode, infos,
- idAttributes));
- // then continue with the next 'superNode'
- continue superNodeLoop;
- }
- }
- }
- // no node in 'nodes' has the same name as 'superName'
- // superNode is not merged
- info.addSubNodeInfo(computeMergeInfos(superNode, infos));
+ if (overridingNode != null) {
+ computeMergedSubNodesMergeInfos(overridingNode, superNode, info,
+ infos, idAttributes, nodeType);
+ nodeSet.remove(overridingNode);
+ } else {
+ computeInhertedSubNodeMergeInfos(superNode, info, nodeType, infos);
}
+ }
- // find node in 'nodes' that are not merged with a node in
- // 'superNodes'
- nodeLoop : for (final Node node : nodes) {
- // get the value of attribute 'nameAttr' of node 'node'
- final String name = node.astGetAttributes().get(nameAttr);
- if (name != null) {
- for (final Node superNode : superNodes) {
- // get the value of attribute 'nameAttr' of node 'superNode'
- final String superName = superNode.astGetAttributes().get(
- nameAttr);
- if (superName != null && name.equals(superName)) {
- // 'node' and 'superNode' has the same name, they are merged
- // skip and continue with the next 'node'
- continue nodeLoop;
- }
- }
- }
+ // for each nodes that are not merged with a supernode
+ for (final Node node : nodeSet) {
+ computeSubNodeMergeInfos(node, info, nodeType, infos);
+ }
+ }
+ }
+ return info;
+ }
- // no node in 'superNodes' has the same name as 'name'
- // node is not merged.
- info.addSubNodeInfo(computeMergeInfos(node, infos));
+ protected Node findOverridingNode(final Node superNode, final Node[] nodes,
+ final String nodeType, final Map<String, String> idAttributes) {
+ // get the name of the attribute that identify the one sub node of
+ // type 'nodeType' among others.
+ final String nameAttr = idAttributes.get(nodeType);
+ if (nameAttr != null) {
+ // get the value of attribute 'nameAttr' of node 'superNode'
+ final String superName = superNode.astGetAttributes().get(nameAttr);
+ // Check that the value is not null
+ if (superName != null) {
+ // for each node in 'Nodes'
+ for (final Node node : nodes) {
+ // get the value of attribute 'nameAttr' of node 'node'
+ final String name = node.astGetAttributes().get(nameAttr);
+ // Check that the value is not null
+ if (name == null) continue;
+
+ if (name.equals(superName)) {
+ return node;
}
}
}
}
- return info;
+ return null;
}
- private MergeInfo computeMergeInfos(final Node node,
+ protected void computeSubNodeMergeInfos(final Node subNode,
+ final MergeInfo parentInfo, final String subNodeType,
final Map<Node, MergeInfo> infos) throws MergeException {
+ parentInfo.addSubNodeInfo(computeMergeInfos(subNode, infos));
+ }
+
+ protected void computeInhertedSubNodeMergeInfos(final Node inheritedSubNode,
+ final MergeInfo parentInfo, final String subNodeType,
+ final Map<Node, MergeInfo> infos) throws MergeException {
+ parentInfo.addSubNodeInfo(computeMergeInfos(inheritedSubNode, infos));
+ }
+
+ protected void computeMergedSubNodesMergeInfos(final Node subNode,
+ final Node inheritedSubNode, final MergeInfo parentInfo,
+ final Map<Node, MergeInfo> infos, final Map<String, String> idAttributes,
+ final String subNodeType) throws MergeException {
+ parentInfo.addSubNodeInfo(computeMergeInfos(subNode, inheritedSubNode,
+ infos, idAttributes));
+ }
+
+ protected MergeInfo computeMergeInfos(final Node node,
+ final Map<Node, MergeInfo> infos) throws MergeException {
MergeInfo info = infos.get(node);
if (info == null) {
info = new MergeInfo(node);
@@ -250,7 +260,7 @@
return info;
}
- private Node initMergedNodes(final MergeInfo info,
+ protected Node initMergedNodes(final MergeInfo info,
final Map<Node, MergeInfo> infos) throws MergeException {
if (info.done) {
return info.result;
@@ -313,11 +323,11 @@
for (final MergeInfo subNodeInfo : info.getSubNodeInfos()) {
result.astAddNode(initMergedNodes(subNodeInfo, infos));
}
- return info.result;
+ return result;
}
/** The Arity of a sub node. */
- private enum SubNodeArity {
+ protected enum SubNodeArity {
/** one sub node. */
ONE,
/** many sub nodes. */
@@ -399,12 +409,13 @@
return nodeArity;
}
- private static class MergeInfo implements Iterable<Node>, Iterator<Node> {
+ protected static class MergeInfo {
+
// the node that must be merged with the 'superNodes'.
Node elem;
// Most of the time, 'elem' node will be merged with only one node (there
- // are more that 1 node only in case of charing). For optimization purpose,
+ // are more that 1 node only in case of sharing). For optimization purpose,
// add a field for storing the first node. Additional nodes (if any) will be
// stored in 'additionalSuperElems'.
Node superElem;
@@ -425,9 +436,7 @@
Set<Class<? extends Node>> nodeClasses;
// state of the iterator.
- boolean modification;
- boolean superElemReturned;
- Iterator<Node> additionalSuperElemsIterator;
+ final SuperElemIterator superElemIterator = new SuperElemIterator();
MergeInfo(final Node elem) {
assert elem != null;
@@ -437,7 +446,7 @@
// This method is used if 2 elements override the same superElement (i.e. in
// case of shared component).
void resetElem(final Node newElem) {
- modification = true;
+ superElemIterator.modification = true;
assert newElem != null;
assert elem != null;
final Node oldElem = elem;
@@ -471,7 +480,7 @@
}
boolean addSuperNode(final Node superNode) {
- modification = true;
+ superElemIterator.modification = true;
assert superNode != null;
final boolean r;
if (superElem == null) {
@@ -496,9 +505,8 @@
return r;
}
- Iterable<Node> getSuperNodes() {
- // use this object has an iterable of superNodes (optimization)
- return this;
+ protected Iterable<Node> getSuperNodes() {
+ return superElemIterator;
}
void addSubNodeInfo(final MergeInfo subNodeInfo) {
@@ -508,7 +516,7 @@
}
@SuppressWarnings("unchecked")
- List<MergeInfo> getSubNodeInfos() {
+ protected List<MergeInfo> getSubNodeInfos() {
if (subNodeInfos == null) return Collections.EMPTY_LIST;
return subNodeInfos;
}
@@ -533,62 +541,71 @@
}
// Implementation of the Iterable interface
+ private final class SuperElemIterator
+ implements
+ Iterable<Node>,
+ Iterator<Node> {
- public Iterator<Node> iterator() {
- // use this object has an iterator of superNodes (optimization)
- // WARNING: concurrent iterations are not supported.
- resetIterator();
- return this;
- }
+ boolean modification;
+ boolean superElemReturned;
+ Iterator<Node> additionalSuperElemsIterator;
- // Implementation of the Iterator interface
- public boolean hasNext() {
- if (modification) throw new ConcurrentModificationException();
- if (superElemReturned) {
- assert superElem != null;
- if (additionalSuperElemsIterator == null) {
- if (additionalSuperElems == null) {
- return false;
+ public Iterator<Node> iterator() {
+ // use this object has an iterator of superNodes (optimization)
+ // WARNING: concurrent iterations are not supported.
+ resetIterator();
+ return this;
+ }
+
+ // Implementation of the Iterator interface
+ public boolean hasNext() {
+ if (modification) throw new ConcurrentModificationException();
+ if (superElemReturned) {
+ assert superElem != null;
+ if (additionalSuperElemsIterator == null) {
+ if (additionalSuperElems == null) {
+ return false;
+ } else {
+ return additionalSuperElems.size() > 0;
+ }
} else {
- return additionalSuperElems.size() > 0;
+ return additionalSuperElemsIterator.hasNext();
}
} else {
- return additionalSuperElemsIterator.hasNext();
+ return superElem != null;
}
- } else {
- return superElem != null;
}
- }
- public Node next() {
- if (modification) throw new ConcurrentModificationException();
- if (superElemReturned) {
- assert superElem != null;
- if (additionalSuperElemsIterator == null) {
- if (additionalSuperElems == null) {
+ public Node next() {
+ if (modification) throw new ConcurrentModificationException();
+ if (superElemReturned) {
+ assert superElem != null;
+ if (additionalSuperElemsIterator == null) {
+ if (additionalSuperElems == null) {
+ throw new NoSuchElementException();
+ } else {
+ additionalSuperElemsIterator = additionalSuperElems.iterator();
+ }
+ }
+ return additionalSuperElemsIterator.next();
+ } else {
+ if (superElem == null) {
throw new NoSuchElementException();
- } else {
- additionalSuperElemsIterator = additionalSuperElems.iterator();
}
+ superElemReturned = true;
+ return superElem;
}
- return additionalSuperElemsIterator.next();
- } else {
- if (superElem == null) {
- throw new NoSuchElementException();
- }
- superElemReturned = true;
- return superElem;
}
- }
- public void remove() {
- throw new UnsupportedOperationException();
- }
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
- private void resetIterator() {
- superElemReturned = false;
- additionalSuperElemsIterator = null;
- modification = false;
+ private void resetIterator() {
+ superElemReturned = false;
+ additionalSuperElemsIterator = null;
+ modification = false;
+ }
}
}
--- trunk/fractaladl/toolchain/ast-core/src/main/java/org/objectweb/fractal/adl/xml/XMLNodeFactory.java 2008-06-29 14:16:17 UTC (rev 7983)
+++ trunk/fractaladl/toolchain/ast-core/src/main/java/org/objectweb/fractal/adl/xml/XMLNodeFactory.java 2008-06-30 08:59:50 UTC (rev 7984)
@@ -29,10 +29,12 @@
import org.xml.sax.SAXException;
/**
- * Interface to create AST node instance
+ * Interface to create AST node instance. AST Node structures are described in a
+ * DTD file.
*/
public interface XMLNodeFactory {
- /** The default name of this interface */
+
+ /** The default name of this interface. */
String ITF_NAME = "node-factory";
/**
@@ -56,14 +58,14 @@
/**
* Gets the class loader used by the XML node factory.
- *
+ *
* @return the class loader used by the XML node factory.
*/
ClassLoader getClassLoader();
/**
* Sets the class loader used by the XML node factory.
- *
+ *
* @param loader the class loader used by the XML node factory.
*/
void setClassLoader(ClassLoader loader);
| <-- Date Index --> | <-- Thread Index --> |
Powered by MHonArc.
Copyright © 2006-2007, OW2 Consortium | contact | webmaster.