All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.xmlvm.util.ObjectHierarchyHelper Maven / Gradle / Ivy

There is a newer version: 0.96-beta4
Show newest version
/* Copyright (c) 2002-2011 by XMLVM.org
 *
 * Project Info:  http://www.xmlvm.org
 *
 * This program 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.1 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
 * USA.
 */

package org.xmlvm.util;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.xmlvm.Log;
import org.xmlvm.main.Arguments;
import org.xmlvm.proc.XmlvmResource;
import org.xmlvm.proc.XmlvmResource.Type;
import org.xmlvm.proc.XmlvmResource.XmlvmInvokeInstruction;
import org.xmlvm.proc.XmlvmResource.XmlvmMemberReadWrite;
import org.xmlvm.proc.XmlvmResource.XmlvmMethod;
import org.xmlvm.proc.lib.LibraryLoader;
import org.xmlvm.util.comparators.ClassNameComparator;
import org.xmlvm.util.comparators.XmlvmMethodComparator;

/**
 * This class helps the VtableOutputProcess in loading/maintaining/retrieving
 * classes in the object hierarchy. The whole object hierarchy is loaded into a
 * graph structure to ease traversal
 */
public class ObjectHierarchyHelper
{

	private static final String TAG= ObjectHierarchyHelper.class.getSimpleName();
	private static final int CHILD= 0;
	private static final int PARENT= 1;

	private GraphNode root= new GraphNode();

	/**
	 * Map containing all nodes of the object hierarchy tree
	 */
	private Map treeIndex= new HashMap();

	/**
	 * Resources loaded through the xmlvm pipeline until the creation of the
	 * hierarchy helper
	 */
	private Map preloadedResources= new HashMap();

	/**
	 * Graph containing all interfaces as nodes and edges between them in case
	 * they are implemented by the same object
	 */
	private Map conflictGraph= new HashMap();

	private Arguments arguments;

	public ObjectHierarchyHelper(Map resourcePool, Arguments arguments)
	{
		this.arguments= arguments;

		preloadedResources= resourcePool;

		// Insert all preloaded resources
		for (XmlvmResource resource : resourcePool.values())
		{
			if (resource.getType() != Type.CONST_POOL)
			{
				insertResource(resource);
			}
		}

		// Insert all referenced resources
		for (XmlvmResource resource : resourcePool.values())
		{
			if (resource.getType() == Type.CONST_POOL)
			{
				continue;
			}

			// Insert all resources referenced by vtable instructions into
			// the tree
			for (XmlvmMethod method : resource.getMethods())
			{
				for (XmlvmInvokeInstruction instruction : method.getVtableInvokeInstructions())
				{
					String className= instruction.getClassType();
					if (className.indexOf("[]") != -1)
					{
						className= "java.lang.Object";
					}
					getXmlvmResource(className);
				}
			}

			// Insert all resources referenced by invoke-super,
			// invoke-static and
			// member read/write instructions into the tree
			List invokeInstructions= new ArrayList();
			List memberReadWriteInstructions= new ArrayList();
			resource.collectInstructions(invokeInstructions, memberReadWriteInstructions);
			for (XmlvmInvokeInstruction instr : invokeInstructions)
			{
				String classType= instr.getClassType();
				getXmlvmResource(classType);
			}
			for (XmlvmMemberReadWrite instr : memberReadWriteInstructions)
			{
				String classType= instr.getClassType();
				getXmlvmResource(classType);
			}
		}
		Log.debug(TAG, "Done building object tree");
	}

	/**
	 * Checks if a method is overridden in any parent or child classes
	 * 
	 * @param resource
	 *            The class the method belongs to
	 * @param method
	 *            Method which needs to be checked for overrides
	 * @return True if method is overridden otherwise false
	 */
	public boolean isOverridden(String fullName, XmlvmMethod method)
	{
		GraphNode node= getNode(fullName);
		return isOverridden(node, method, CHILD) || isOverridden(node, method, PARENT);
	}

	/**
	 * Checks if a method is overriding any parent class method
	 * 
	 * @param resource
	 *            The class the method belongs to
	 * @param method
	 *            Method which needs to be checked for overriding
	 * @return True if method is overriding a parent class method otherwise false
	 */
	public boolean isOverridding(String fullName, XmlvmMethod method)
	{
		GraphNode node= getNode(fullName);
		Set toCheck= node.getParents();

		for (GraphNode current : toCheck)
		{
			// Check if method is overridden
			XmlvmResource childClass= current.getResource();
			if (!childClass.isInterface())
			{
				for (XmlvmMethod each : childClass.getMethods())
				{
					if (each.doesOverrideMethod(method))
					{
						return true;
					}
				}

				// Recursively call for all children
				if (isOverridding(childClass.getFullName(), method))
				{
					return true;
				}
			}
		}
		return false;
	}

	/**
	 * Checks if a method is overridden
	 * 
	 * @param node
	 *            The class the method belongs to
	 * @param method
	 *            Method which needs to be checked for overrides
	 * @param parentOrChild
	 *            Should be either CHILD or PARENT (0 or 1) to determine in
	 *            which direction the graph should be searched
	 * @return
	 */
	private boolean isOverridden(GraphNode node, XmlvmMethod method, int parentOrChild)
	{
		Set toCheck;
		if (parentOrChild == CHILD)
		{
			toCheck= node.getChildren();
		}
		else
		{
			toCheck= node.getParents();
		}

		for (GraphNode current : toCheck)
		{
			// Check if method is overridden
			XmlvmResource childClass= current.getResource();
			for (XmlvmMethod each : childClass.getMethods())
			{
				if (each.doesOverrideMethod(method))
				{
					return true;
				}
			}
			// Recursively call for all children
			if (isOverridden(current, method, parentOrChild))
			{
				return true;
			}
		}
		return false;

	}

	/**
	 * Get a XmlvmResource from the object hierarchy. The XmlvmResource will be
	 * loaded through the library loader if it wasn't already loaded
	 * 
	 * @param fullName
	 *            The full name of the resource (e.g. java.lang.String)
	 * @return XmlvmResource
	 */
	public XmlvmResource getXmlvmResource(String fullName)
	{
		GraphNode graphNode= getNode(fullName);
		return graphNode == null ? null : graphNode.getResource();
	}

	/**
	 * Get the GraphNode of an XmlvmResource. Load the resource if it isn't
	 * already in the graph
	 * 
	 * @param fullName
	 *            XmlvmResource of the class you want to insert
	 * @param root
	 *            Root node of the object hierarchy tree
	 */
	private GraphNode getNode(String fullName)
	{
		if (!treeIndex.containsKey(fullName))
		{
			XmlvmResource resource= loadResource(fullName);
			if (resource != null)
			{
				insertResource(resource);
			}
			else
			{
				Log.error("Couldn't create node for " + fullName);
			}
		}
		return treeIndex.get(fullName);
	}

	/**
	 * Insert a class and all its super classes and interfaces into the object
	 * hierarchy tree
	 * 
	 * @param resource
	 *            Resource to insert into the graph
	 * @return GraphNode in which the resource was inserted into the graph
	 */
	private GraphNode insertResource(XmlvmResource resource)
	{
		String fullName= resource.getFullName();
		if (!treeIndex.containsKey(fullName))
		{
			Log.debug(TAG, "Inserting " + resource.getFullName() + " into object tree");
			GraphNode newNode= null;
			if (resource.isInterface())
			{
				newNode= insertInterface(resource);
			}
			else
			{
				newNode= insertClass(resource);
				addInterfaces(newNode, resource);
			}
			treeIndex.put(resource.getFullName(), newNode);
			return newNode;
		}
		else
		{
			return treeIndex.get(fullName);
		}
	}

	/**
	 * Insert a class (not an interfacce!) into the object hierarchy
	 * 
	 * @param resource
	 *            Resource to insert into the graph
	 * @return GraphNode in which the resource was inserted into the graph
	 */
	private GraphNode insertClass(XmlvmResource resource)
	{
		String superType= resource.getSuperTypeName();

		// If we don't have a super type (=> java.lang.Object) we are the root
		if (superType == null || superType.equals(""))
		{
			root.setResource(resource);
			return root;
		}
		else
		{
			// Find the base class in the tree and add yourself as a child
			GraphNode superNode= getNode(superType);
			GraphNode newNode= new GraphNode(resource);
			superNode.add(newNode);
			return newNode;
		}
	}

	/**
	 * Insert an interface into the object hierarchy. Even though all interfaces
	 * extend java.lang.Object in the end there is no link between
	 * java.lang.Object and the interface added.
	 * 
	 * @param resource
	 *            Resource to insert into the graph
	 * @return GraphNode in which the resource was inserted into the graph
	 */
	private GraphNode insertInterface(XmlvmResource resource)
	{
		GraphNode newNode= new GraphNode(resource);
		addInterfaces(newNode, resource);
		return newNode;
	}

	/**
	 * Insert interfaces into the object hierarchy which are extended by another
	 * interface or class
	 *
	 * @param newNode GraphNode in which to insert the resource into the graph
	 * @param resource Resource to insert into the graph
	 */
	private void addInterfaces(GraphNode newNode, XmlvmResource resource)
	{
		String interfaces= resource.getInterfaces();
		if (interfaces != null && !interfaces.equals(""))
		{
			for (String interfaceName : interfaces.split("\\,"))
			{
				// Try to find the interface in the existing tree
				GraphNode interfaceNode= getNode(interfaceName);
				interfaceNode.add(newNode);
			}
		}
	}

	/**
	 * Check if the resource was already loaded through the pipeline before the
	 * ObjectHierarchyHelper was created or load the class through the
	 * LibraryLoader otherwise
	 * 
	 * @param fullName
	 *            Full name of the class (e.g. java.lang.String)
	 * @return XmlvmResource of the class
	 */
	private XmlvmResource loadResource(String fullName)
	{
		if (preloadedResources.containsKey(fullName))
		{
			return preloadedResources.get(fullName);
		}
		else
		{
			Log.debug(TAG, "Loading JDK class: " + fullName);
			LibraryLoader loader= new LibraryLoader(arguments);
			XmlvmResource resource= loader.load(fullName);
			return resource;
		}
	}

	/**
	 * Load all children of a class recursively
	 * 
	 * @param fullName
	 *            Full name of the class (e.g. java.lang.String)
	 * @return Set containing all children of the class as XmlvmResource
	 */
	public Set getChildrenRecursive(String fullName)
	{
		Set children= getChildrenRecursive(getNode(fullName));
		Set ret= new HashSet();
		for (GraphNode node : children)
		{
			ret.add(node.getResource());
		}
		return ret;
	}

	/**
	 * Load all children of a class recursively
	 * 
	 * @param node
	 *            GraphNode of the class
	 * @return Set containing the GraphNodes for all children of the class
	 */
	private Set getChildrenRecursive(GraphNode node)
	{
		Set children= new HashSet();
		for (GraphNode parent : node.getChildren())
		{
			children.add(parent);
			children.addAll(getChildrenRecursive(parent));
		}
		return children;
	}

	/**
	 * Load all parents of a class recursively
	 * 
	 * @param fullName
	 *            Full name of the class (e.g. java.lang.String)
	 * @return Set containing all parents of the class as XmlvmResource
	 */
	public Set getParentsRecursive(String fullName)
	{
		Set parents= getParentsRecursive(getNode(fullName));
		Set ret= new HashSet();
		for (GraphNode node : parents)
		{
			ret.add(node.getResource());
		}
		return ret;
	}

	/**
	 * Load all parents of a class recursively
	 * 
	 * @param node
	 *            GraphNode of the class
	 * @return Set containing the GraphNodes for all parents of the class
	 */
	private Set getParentsRecursive(GraphNode node)
	{
		Set parents= new HashSet();
		for (GraphNode parent : node.getParents())
		{
			parents.add(parent);
			parents.addAll(getParentsRecursive(parent));
		}
		return parents;
	}

	/**
	 * Load all interfaces of a class recursively
	 * 
	 * @param fullName
	 *            Full name of the class (e.g. java.lang.String)
	 * @return Set containing all interfaces of the class as XmlvmResource
	 */
	public Set getInterfacesRecursive(String fullName)
	{
		Set interfaces= getParentsRecursive(getNode(fullName));
		Set ret= new HashSet();
		for (GraphNode node : interfaces)
		{
			if (node.getResource().isInterface())
			{
				ret.add(node.getResource());
			}
		}
		return ret;
	}

	/**
	 * If an abstract class implements an interface and the method is not
	 * implemented or declared in the class or parent classes redeclare it. This
	 * makes sure a vtable entry gets created in cases like the following:
	 * 
	 * interface X { x(): } abstract class A implements X {} class B extends A
	 * {}
	 * 
	 * interface X { x(): } interface A extends X {} class C implements A {}
	 * 
	 * For this call we need an index #define XMLVM_ITABLE_IDX_B_a__;
	 * 
	 * Java doesn't force redeclaration of the interface method x() in class A
	 * because it's abstract but to support this call
	 * 
	 * A a = new B(); a.x();
	 * 
	 * we need to create an vtable index of this method in A. To achieve that we
	 * explicitly redeclare the interface method in A.
	 */
	public void redeclareInterfaceMethodsInAbstractClasses()
	{
		for (GraphNode node : treeIndex.values())
		{
			if (node.getResource().isAbstract())
			{

				Set interfaces= getInterfacesRecursive(node.getResource().getFullName());
				Set interfaceMethods= new HashSet();
				for (XmlvmResource ifaceResource : interfaces)
				{
					interfaceMethods.addAll(ifaceResource.getMethods());
				}

				Set parents= getParentsRecursive(node);
				Set classMethods= new HashSet();
				classMethods.addAll(node.getResource().getMethods());
				for (GraphNode parent : parents)
				{
					if (!parent.getResource().isInterface())
					{
						classMethods.addAll(parent.getResource().getMethods());
					}
				}

				List methods= new ArrayList(interfaceMethods);
				Collections.sort(methods, new XmlvmMethodComparator());

				outer: for (XmlvmMethod ifaceMethod : methods)
				{
					for (XmlvmMethod classMethod : classMethods)
					{
						if (ifaceMethod.doesOverrideMethod(classMethod))
						{
							continue outer;
						}
					}
					classMethods.add(ifaceMethod);
					node.getResource().addMethod(ifaceMethod).setSynthetic(true);
				}
			}
		}
	}

	/**
	 * Calculates valid interface indices for all interface methods through
	 * selector coloring. This method is described here:
	 * 
	 * R. Dixon, T. McKee, M. Vaughan, and P. Schweizer. 1989. A fast method
	 * dispatcher for compiled languages with multiple inheritance. SIGPLAN Not.
	 * 24, 10 (September 1989), 211-214. DOI=10.1145/74878.74900
	 * http://doi.acm.org/10.1145/74878.74900
	 */
	public void calculateInterfaceIndices()
	{
		buildConflictGraph();
		Log.debug(TAG, "Built interface conflict graph containing " + conflictGraph.size() + " interfaces");
		int lastStartingNumber= colorConflictGraph();
		Log.debug(TAG, "Colored graph with highest starting index " + lastStartingNumber);
		verifyConflictGraph();
		Log.debug(TAG, "Verified correctness of coloring for " + conflictGraph.size() + " interfaces");
		Log.debug(TAG, "Done calculating interface indices");
	}

	/**
	 * Build a conflict graph where every node represents an interface and every
	 * edge between two nodes represents that two classes/interfaces implement
	 * this interface and therefore there is a conflict
	 */
	private void buildConflictGraph()
	{
		for (GraphNode node : treeIndex.values())
		{
			String fullName= node.getResource().getFullName();
			if (node.getResource().isInterface())
			{
				ColoredGraphNode newNode= new ColoredGraphNode(node.getResource());
				conflictGraph.put(fullName, newNode);
				Log.debug(TAG, "Added " + fullName + " to conflict graph");
			}
		}
		for (GraphNode node : treeIndex.values())
		{
			processNodeForConflictGraph(node);
		}
	}

	/**
	 * Load all interfaces of a node and create edges between them
	 * 
	 * @param node
	 *            Node to process
	 */
	private void processNodeForConflictGraph(GraphNode node)
	{
		// Add the node to the conflict graph if we don't already have it
		List conflictingInterfaces= new ArrayList();
		for (XmlvmResource interfaceResource : getInterfacesRecursive(node.getResource().getFullName()))
		{
			String fullName= interfaceResource.getFullName();
			conflictingInterfaces.add(conflictGraph.get(fullName));
		}

		for (ColoredGraphNode connectFromNode : conflictingInterfaces)
		{
			for (ColoredGraphNode connectToNode : conflictingInterfaces)
			{
				if (!connectFromNode.getResource().getFullName().equals(connectToNode.getResource().getFullName()))
				{
					connectToNode.add(connectFromNode);
				}
			}
		}
	}

	/**
	 * Compare ColoredGraphNodes by their resource's full class name, sorting
	 * core library packages first.
	 */
	private static class ColoredGraphNodeComparator implements Comparator
	{
		private static Comparator comparator= new ClassNameComparator();

		public int compare(ColoredGraphNode n1, ColoredGraphNode n2)
		{
			return comparator.compare(n1.getResource().getFullName(), n2.getResource().getFullName());
		}
	}

	/**
	 * Color the graph (assign indices to all interface methods) starting with
	 * interfaces in core/priority packages, and then sorting by class name
	 */
	private int colorConflictGraph()
	{
		int maxColor= 0;
		Collection values= conflictGraph.values();
		List orderedNodes= new ArrayList();
		for (ColoredGraphNode node : values)
		{
			orderedNodes.add(node);
		}

		Collections.sort(orderedNodes, new ColoredGraphNodeComparator());

		for (ColoredGraphNode node : orderedNodes)
		{
			int nodeMaxColor= colorNode(node);
			maxColor= Math.max(nodeMaxColor, maxColor);
		}
		return maxColor;
	}

	/**
	 * Color a specific node in the class. To pick the color for a method use
	 * the lowest available index in the neighborhood of the node
	 * 
	 * @param node
	 *            Node to be colored
	 */
	private int colorNode(ColoredGraphNode node)
	{
		List usedColors= new ArrayList();
		for (ColoredGraphNode neighbor : node.getNeighbors())
		{
			usedColors.addAll(neighbor.getColors());
		}

		int current= 0;
		List methods= node.getResource().getMethodsSorted();
		for (XmlvmMethod method : methods)
		{
			if (method.isStatic())
			{
				node.getColors().add(-1);
			}
			else
			{
				while (usedColors.contains(current))
				{
					current++;
				}
				node.getColors().add(current);
				current++;
			}
		}
		return current;
	}

	/**
	 * Verify that the coloring algorithm produced a valid coloring by checking
	 * color intersections between nodes and that every method was assigned a
	 * color
	 */
	public void verifyConflictGraph()
	{
		for (ColoredGraphNode node : conflictGraph.values())
		{
			if (node.getResource().getMethods().size() != node.getColors().size())
			{
				throw new RuntimeException("Not every method in interface " + node.getResource().getFullName() + " is assigned a color!");
			}

			List usedColors= new ArrayList();
			for (ColoredGraphNode neighbor : node.getNeighbors())
			{
				usedColors.addAll(neighbor.getColors());
			}

			for (int currentColor : node.getColors())
			{
				if (usedColors.contains(currentColor))
				{
					throw new RuntimeException("Color conflict with neighbor in interface " + node.getResource().getFullName() + "!");
				}
			}
		}
	}

	/**
	 * Compare GraphNodes by their resource's full name, sorting core library
	 * packages first.
	 */
	private static class GraphNodeComparator implements Comparator
	{
		private static Comparator comparator= new ClassNameComparator();

		public int compare(GraphNode n1, GraphNode n2)
		{
			return comparator.compare(n1.getResource().getFullName(), n2.getResource().getFullName());
		}
	}

	/**
	 * Set interface table information. Specifically, set the interface table
	 * size on XmlvmResources and the interface table index on XmlvmMethods
	 */
	public void computeInterfaceTableInformation()
	{
		int itableSizeTotal= 0, itableCount= 0;

		List nodes= new ArrayList(treeIndex.values());
		Collections.sort(nodes, new GraphNodeComparator());
		for (GraphNode node : nodes)
		{
			if (!node.getResource().isInterface())
			{
				Set interfaces= getInterfacesRecursive(node.getResource().getFullName());
				int maxIndex= -1;
				for (XmlvmResource iface : interfaces)
				{
					List ifaceMethods= iface.getMethodsSorted();
					for (XmlvmMethod m : ifaceMethods)
					{
						maxIndex= Math.max(maxIndex, getInterfaceIndex(iface, m, ifaceMethods));
					}
				}
				maxIndex++;
				node.getResource().setInterfaceTableSize(Integer.valueOf(maxIndex));

				itableCount++;
				itableSizeTotal+= maxIndex;
			}
		}

		Log.debug(TAG, "The average itable size is " + ((double) itableSizeTotal) / itableCount);

		List orderedNodes= new ArrayList(conflictGraph.values());
		Collections.sort(orderedNodes, new ColoredGraphNodeComparator());
		for (ColoredGraphNode node : orderedNodes)
		{
			// Add all symbols for own methods
			computeMethodItableIndex(node);
		}
	}

	/**
	 * Determine the interface table index, if any, for the node's resource's methods
	 * @param node Node for which we want to retrieve the interface indices
	 */
	private void computeMethodItableIndex(ColoredGraphNode node)
	{
		int index= 0;
		List methods= node.getResource().getMethodsSorted();
		for (XmlvmMethod method : methods)
		{
			if (method.isStatic())
			{
				continue;
			}
			int color= node.getColors().get(index);
			method.setInterfaceTableIndex(Integer.valueOf(color));
			index++;
		}
	}

	/**
	 * Get the interface index for a method
	 * 
	 * @param iface
	 *            Interface containing the method
	 * @param m
	 *            XmlvmMethod for which we want the index
	 * @param ifaceMethods
	 *            Sorted methods of iface
	 * @return Interface index of the method
	 */
	public int getInterfaceIndex(XmlvmResource iface, XmlvmMethod m, List ifaceMethods)
	{
		ColoredGraphNode node= conflictGraph.get(iface.getFullName());
		int interfaceIndex= -1;
		for (int i= 0; i < ifaceMethods.size(); i++)
		{
			if (ifaceMethods.get(i).doesOverrideMethod(m))
			{
				interfaceIndex= node.getColors().get(i);
				break;
			}
		}

		String parameterList= "";
		for (String parameter : m.getParameterTypes())
		{
			parameterList+= parameter + " ";
		}
		Log.debug(TAG, "Interface index for " + iface.getFullName() + " " + m.getName() + "(" + parameterList + ") = " + interfaceIndex);
		return interfaceIndex;
	}

	/**
	 * Escape a Java resource name to what it will be named in C
	 * @param resourceName the resource name
	 * @return an escaped name of the resource
	 */
	public static String escapeName(String resourceName)
	{
		return resourceName.replace('.', '_').replace('$', '_');
	}

	/**
	 * Returns a name-mangled signature of the given parameterTypes.
	 * 
	 * @return
	 */
	public static String getParameterString(List parameterTypes)
	{
		StringBuilder parameterString= new StringBuilder(parameterTypes.size() * 16);//average of tutorial
		if (parameterTypes.size() > 0)
		{
			for (String parameter : parameterTypes)
			{
				parameterString.append("_");
				int i= parameter.indexOf('[');
				// dim == number of dimensions
				int dim= (i == -1) ? 0 : (parameter.length() - i) / 2;
				parameter= parameter.replaceAll("\\[\\]", "");
				parameter= escapeName(parameter);
				parameterString.append(parameter);
				if (dim > 0)
				{
					parameterString.append("_").append(dim).append("ARRAY");
				}
			}
		}
		return parameterString.toString();
	}

	/**
	 * Class representing a vertex containing a XmlvmResource in a directed
	 * Graph
	 */
	private class GraphNode
	{

		private XmlvmResource resource;
		private Set children= new HashSet();
		private Set parents= new HashSet();

		public GraphNode()
		{
		}

		public GraphNode(XmlvmResource resource)
		{
			this.resource= resource;
		}

		public XmlvmResource getResource()
		{
			return this.resource;
		}

		public void setResource(XmlvmResource resource)
		{
			this.resource= resource;
		}

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

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

		public void add(GraphNode newNode)
		{
			children.add(newNode);
			newNode.parents.add(this);
		}

	}

	/**
	 * Class representing a vertex containing a XmlvmResource in an undirected
	 * Graph being able to store multiple colors (Integer) per vertex
	 */
	private class ColoredGraphNode
	{

		private XmlvmResource resource;
		private Set neighbors= new HashSet();
		private List colors= new ArrayList();

		public ColoredGraphNode(XmlvmResource resource)
		{
			this.resource= resource;
		}

		public List getColors()
		{
			return colors;
		}

		public XmlvmResource getResource()
		{
			return this.resource;
		}

		public Set getNeighbors()
		{
			return this.neighbors;
		}

		public void add(ColoredGraphNode newNode)
		{
			neighbors.add(newNode);
			newNode.neighbors.add(this);
		}

	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy