package eu.dnetlib.miscutils.hstree; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Queue; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * This class implement statically typed complete tree of finite depth. The type signature of each tree node determines * fully the depth and the types of all the children. * *
* class MyTree extends TreeNode<RootPayload, L1Payload, TreeNode<L1Payload, L2Payload, TreeNode<L2Payload, Void, NilTreeNode>>> { * * } ** * However since java doesn't have type inferencing we'll have to write often the full type of intermediate nodes, * especially during tree construction. Thus it's recommended that you split the chain into a number of dummy classes, * serving only to the purpuse of declaring the type chain: * *
* class MyTree extends TreeNode<RootPayload, L1Payload, L1Tree> { * } * * class L1Tree extends TreeNode<L1Payload, L2Payload, L2Tree> { * } * * class L2Tree extends TreeNode<L2Payload, Void, NilTreeNode> { * } ** * NOTE: you could keep the whole definition inside a single file using inner classes. * * @author marko * * @param
TreeNode(T resource)
constructor only because it would force any implementor of "alias" subclasses
* of TreeNode to provide a dummy implementation of the constructor calling super(resource)
*
* However the constructor is protected because users should only create objects through addChild
or in
* alternative they should provide they own constructor ovverrides.
*/
protected TreeNode() {
// no action
}
/**
* However the constructor is protected because users should only create objects through addChild
or in
* alternative they should provide they own constructor ovverrides.
*
* @param resource
* payload
*/
protected TreeNode(final T resource) {
this.resource = resource;
}
/**
* Call this method to add a child node.
*
* Only the payload is needed, the tree node will be constructed automatically and it will be returned.
*
* * L1Child c1 = root.addChild(new L1Resource()); * c1.addChild(new L2Resource()); * c1.addChild(new L2Resource()).addChild(new L3Resource()); ** * @param resource * payload * @return the new node */ @SuppressWarnings("unchecked") public C addChild(final N resource) { try { if (childNodeType.equals(NilTreeNode.class)) throw new IllegalStateException(CHILDR_UNDER_LEAF); C test; try { test = childNodeType.newInstance(); test.setResource(resource); } catch (InstantiationException e) { /* * handle the situation when someone wants to create a one argument constructor hiding the default * constructor provided by the base class. Nodes should normally be constructed using addChild but we * don't want to force users to do it, and if they do it they shouldn't be punished with obscure * InstantiationException caused by our evil usage of reflection. Of course we should do much more here * in order to be more robust in the general case. */ try { test = (C) childNodeType.getConstructors()[0].newInstance(resource); // NOPMD } catch (InvocationTargetException e1) { throw new IllegalStateException(e1); } catch (InstantiationException e1) { throw new IllegalStateException(e1); } } getChildren().add(test); return test; } catch (IllegalArgumentException e) { throw new IllegalStateException(e); } catch (SecurityException e) { throw new IllegalStateException(e); } catch (IllegalAccessException e) { throw new IllegalStateException(e); } } /** * This method is especially useful for leaf nodes when you want to append several children to the same parent node, * without having to declare a temporary variable to hold the parent node (which could have long and ugly type) * * @param resource * @return the parent node */ public TreeNode