ClassTree.java Source code

Java tutorial

Introduction

Here is the source code for ClassTree.java

Source

/*
 * The contents of this file are subject to the Sapient Public License
 * Version 1.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 * http://carbon.sf.net/License.html.
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
 * the specific language governing rights and limitations under the License.
 *
 * The Original Code is The Carbon Component Framework.
 *
 * The Initial Developer of the Original Code is Sapient Corporation
 *
 * Copyright (C) 2003 Sapient Corporation. All Rights Reserved.
 */

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * This class creates a tree structure that maps inheritance hierarchies of
 * classes. A developer can place any number of classes into this object and
 * retrieve the closest super class or the class itself.
 *
 *
 * Copyright 2001 Sapient
 * @since EJFW 2.7
 * @author Greg Hinkle, January 2001
 * @version $Revision: 1.4 $($Author: dvoet $ / $Date: 2003/05/05 21:21:23 $)
 */
public class ClassTree {

    protected ClassTreeNode bottom;

    /**
     * Constructs a ClassTree that represents all classes and interfaces that
     * are generalizations of the provided class. This ends up with a tree
     * structure of the inheritance hierarchy for that provided class all the
     * way up to java.lang.Object.
     * @param specificClass The class to build the tree for.
     */
    public ClassTree(Class specificClass) {
        this.bottom = ClassTreeNode.buildNode(specificClass);

    }

    public ClassTreeNode getBottom() {
        return this.bottom;
    }

    /**
     * Constructs an ordered list starting at the highest (most general) class
     * in the tree and moving down the tree, ensuring no generalization comes
     * after one of its specializations.
     * @return a list ordered as above
     */
    public List getOrderedList() {
        List list = new ArrayList();
        list.add(getBottom());

        buildList(getBottom(), list);

        Collections.sort(list);

        // Refactor list into a list of classes from a list of ClassTreeNodes
        for (int i = 0; i < list.size(); i++) {
            ClassTreeNode node = (ClassTreeNode) list.get(i);
            list.set(i, node.getObjectClass());
        }

        // Reverse the list so that the top class in the hierarchy comes first
        Collections.reverse(list);

        return list;
    }

    /**
     * Build breadth first in order to maintain sudo ordering as per
     * class declarations (i.e. if A implements B, C... B is closer in the
     * chain to A than C is, because B comes first in the implements clause.
     *
     * Note that the list coming out here is preordered, but not natural
     * ordered. (i.e. some classes are out of order in relation to classes
     * they have direct relationships with. This is later fixed by a sort
     * on the list by natural ordering. Collecitons.sort, does preserve
     * the preordering for nodes that have no relationship.
     *
     * @param node the node to be browsed.
     * @param output this list is altered to add the contents as they are
     *   browsed in breadth-first order. Start with a list containing only
     *   the bottom node.
     */
    private void buildList(ClassTreeNode node, List output) {

        for (int i = 0; i < node.getParents().size(); i++) {
            ClassTreeNode parent = (ClassTreeNode) node.getParents().get(i);
            if (!output.contains(parent)) {
                output.add(parent);
            }
        }

        List parents = node.getParents();
        for (int i = 0; i < parents.size(); i++) {
            ClassTreeNode parent = (ClassTreeNode) parents.get(i);
            buildList(parent, output);
        }
    }

    /**
     * Inner class representing each node in the tree. Holds references to the
     * nodes children, parent and provides the Comparable interface for sorting
     * by inheritance hierarchy.
     */
    public static class ClassTreeNode implements Comparable {
        /** The class of this node */
        protected Class objectClass;

        /** The map of children classes to their class names */
        protected List children;

        /** A reference to the parent node of this node */
        protected List parents;

        /**
         * Constructs a ClassTreeNode with the given Class.
         *
         * @param objectClass the Class of the node
         */
        public ClassTreeNode(Class objectClass) {
            this.children = new ArrayList();
            this.objectClass = objectClass;
            this.parents = new ArrayList();

        }

        public static ClassTreeNode buildNode(Class objectClass) {
            Map allNodes = new HashMap();
            return buildNode(objectClass, allNodes);
        }

        protected static ClassTreeNode buildNode(Class objectClass, Map allNodes) {
            ClassTreeNode node;
            if (allNodes.containsKey(objectClass)) {
                node = (ClassTreeNode) allNodes.get(objectClass);
            } else {
                node = new ClassTreeNode(objectClass);
                allNodes.put(objectClass, node);
            }

            // Add the implemented interfaces...
            Class[] superInterfaces = objectClass.getInterfaces();
            for (int i = 0; i < superInterfaces.length; i++) {
                Class superInterface = superInterfaces[i];
                ClassTreeNode parent = buildNode(superInterface);
                node.addParent(parent);
            }

            // Add the superclass after the interfaces...
            Class superClass = objectClass.getSuperclass();
            if (superClass != null) {
                ClassTreeNode parent = buildNode(superClass);
                node.addParent(parent);
            }
            return node;
        }

        public List getParents() {
            return this.parents;
        }

        public void addParent(ClassTreeNode node) {
            this.parents.add(node);
            node.addChild(this);
        }

        public boolean removeChild(ClassTreeNode node) {
            return this.children.remove(node);
        }

        public void addChild(ClassTreeNode node) {
            this.children.add(node);
        }

        public List getChildren() {
            return this.children;
        }

        public boolean equals(Object obj) {
            return ((ClassTreeNode) obj).getObjectClass().equals(this.objectClass);
        }

        public Class getObjectClass() {
            return this.objectClass;
        }

        public String getClassName() {
            return this.objectClass.getName();
        }

        public int hashCode() {
            return this.objectClass.hashCode();
        }

        /**
         * Compares one class to another class by their inheritance tree.
         *
         * @return an integer representing the comparison results as follows:<br>
         *    2  if this is a subclass of past in object<br>
         *    -2 if this is a superclass of past in object<br>
         *    0 if they are not related (and in relation to sorting, equal)<br>
         *    0  if they are the same<br>
         */
        public int compareTo(Object obj) {
            Class objClass = ((ClassTreeNode) obj).getObjectClass();

            if (objClass.equals(this.objectClass)) {
                return 0;
            } else if (this.objectClass.isAssignableFrom(objClass)) {
                return 2;
            } else if (objClass.isAssignableFrom(this.objectClass)) {
                return -2;
            } else {
                return 0;
            }
        }
    } // End of ClassTree$ClassTreeNode

}