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

jadex.bridge.component.DependencyResolver Maven / Gradle / Ivy

Go to download

Jadex bridge is a base package for kernels and platforms, i.e., it is used by both and provides commonly used interfaces and classes for active components and their management.

There is a newer version: 4.0.267
Show newest version
package jadex.bridge.component;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import jadex.commons.transformation.traverser.SCloner;

/**
 *  The dependency resolver can be used to find a valid
 *  execution order of elements with dependencies.
 */
public class DependencyResolver 
{
	/** The nodes with dependencies. */
	protected Map> nodes;
	
	/** The set of empty nodes. */
	protected Set nodeps;
	
	/**
	 *  Create a new dependency resolver.
	 */
	public DependencyResolver() 
	{
		this.nodes = new LinkedHashMap>();
		this.nodeps = new LinkedHashSet();
	}
	
	/**
	 *  Add a dependency that a depends on b.
	 *  @param a Then source node.
	 *  @param b The node the source depends on.
	 */
	public void addDependency(T a, T b)
	{
		if(a==null || b==null)
			throw new IllegalArgumentException("Object must not null.");
		
		NodeInfo nia = getNodeInfo(a);
		nia.getMyDeps().add(b);
		NodeInfo nib = getNodeInfo(b);
		nib.getOtherDeps().add(a);
		
		Set t = new HashSet(nia.getMyDeps());
		t.retainAll(nia.getOtherDeps());
		if(t.size()>0)
			throw new RuntimeException("error cycle detected: "+nia);
		
		t = new HashSet(nib.getMyDeps());
		t.retainAll(nib.getOtherDeps());
		if(t.size()>0)
			throw new RuntimeException("error cycle detected: "+nib);
		
		// Update nodeps
		nodeps.remove(a);
		if(!hasDependencies(b))
			nodeps.add(b);
	}
	
	/**
	 *  Remove a dependency that a depends on b.
	 *  @param a Then source node.
	 *  @param b The node the source depends on.
	 */
	public void removeDependency(T a, T b)
	{
		NodeInfo nia = getNodeInfo(a);
		if(!nia.getMyDeps().remove(b))
			throw new RuntimeException("Cannot remove dependency");
		NodeInfo nib = getNodeInfo(b);
		if(!nib.getOtherDeps().remove(a))
			throw new RuntimeException("Cannot remove dependency");
		
		// Update nodeps
		if(!hasDependencies(a))
			nodeps.add(a);
	}
	
	/**
	 *  Resolve the DAG and deliver a valid order of nodes.
	 *  @return A valid list of nodes.
	 */
	public List resolveDependencies(boolean keep)
	{
		List ret = new ArrayList();
		
		DependencyResolver dr2 = !keep? null: (DependencyResolver)SCloner.clone(this);
//		DependencyResolver dr2 = !keep? null: (DependencyResolver)Traverser.traverseObject(this, null, Traverser.getDefaultProcessors(), null, true, null);
		
		while(!nodes.isEmpty())
		{
			if(nodeps.size()==0)
				throw new RuntimeException("Dependency resolution problem.");
			T node = nodeps.iterator().next();
			ret.add(node);
			
			NodeInfo nia = getNodeInfo(node);
			for(T dep: (T[])nia.getOtherDeps().toArray(new Object[0]))
			{
				removeDependency(dep, node);
			}
			nodeps.remove(node);
			nodes.remove(node);
		}
		
		// reset
		if(keep)
		{
			nodes = dr2.getNodes();
			nodeps = dr2.getNodeps();
		}
		
//		System.out.println("Resolved: "+ret);
		
		return ret;
	}
	
	/**
	 *  Resolve the DAG and deliver a valid order of nodes with sets of nodes for same levels.
	 *  @return A valid list of set of nodes.
	 */
	public List> resolveDependenciesWithLevel()
	{
		List> ret = new ArrayList>();
		
		while(!nodes.isEmpty())
		{
			if(nodeps.size()==0)
				throw new RuntimeException("Dependency resolution problem.");
			
			Iterator it = nodeps.iterator();
			Set level = new HashSet();
			while(it.hasNext())
			{
				T node = it.next();
				level.add(node);
			}
			ret.add(level);
			
			for(T node: level)
			{
				NodeInfo nia = getNodeInfo(node);
				for(T dep: (T[])nia.getOtherDeps().toArray(new Object[0]))
				{
					removeDependency(dep, node);
				}
				nodeps.remove(node);
				nodes.remove(node);
			}
		}
		
		return ret;
	}
	
	/**
	 *  Add a node (without dependency). 
	 *  @param node The node id.
	 */
	public void addNode(T node)
	{
		getNodeInfo(node);
		
		// add to nodeps
		if(!hasDependencies(node))
		{
			nodeps.add(node);
		}
	}
	
	/**
	 *  Clear the resolver.
	 */
	public void clear()
	{
		this.nodes.clear();
		this.nodeps.clear();
	}
	
	/**
	 *  Get the node info for the node id.
	 *  @param node The node id.
	 *  @return The node info.
	 */
	protected NodeInfo getNodeInfo(T node)
	{
		NodeInfo ni = nodes.get(node);
		if(ni==null)
		{
			ni = new NodeInfo();
			nodes.put(node, ni);
		}
		return ni;
	}
	
	/**
	 *  Test if a node has dependencies.
	 *  @return True, if dependencies exist.
	 */
	protected boolean hasDependencies(T node)
	{
		return nodes.containsKey(node) && nodes.get(node).getMyDeps().size()>0;
	}
	
	/**
	 *  Get the nodes.
	 *  @return The nodes
	 */
	public Map> getNodes()
	{
		return nodes;
	}
	
	/**
	 *  The nodes to set.
	 *  @param nodes The nodes to set
	 */
	public void setNodes(Map> nodes)
	{
		this.nodes = nodes;
	}

	/**
	 *  Get the nodeps.
	 *  @return The nodeps
	 */
	public Set getNodeps()
	{
		return nodeps;
	}

	/**
	 *  The nodeps to set.
	 *  @param nodeps The nodeps to set
	 */
	public void setNodeps(Set nodeps)
	{
		this.nodeps = nodeps;
	}

	/**
	 *  The main for testing. 
	 */
	public static void main(String[] args) 
	{
		DependencyResolver dr = new DependencyResolver();
//		dr.addDependency("a", "b");
//		dr.addDependency("b", "c");
//		dr.addDependency("c", "d");
//		System.out.println(dr.resolveDependencies());

		dr.clear();
		
		dr.addDependency("c", "a");
		dr.addDependency("d", "b");
		dr.addDependency("e", "c");
		dr.addDependency("e", "d");
		dr.addDependency("f", "a");
		dr.addDependency("f", "b");
		dr.addDependency("g", "e");
		dr.addDependency("g", "f");
		dr.addDependency("h", "g");
		dr.addDependency("i", "a");
		dr.addDependency("j", "b");
		System.out.println(dr.resolveDependencies(true));
	}
	
	
	/**
	 *  Info object for a node.
	 */
	public static class NodeInfo
	{
		/** The set of nodes this node depends on. */
		protected Set mydeps;
		
		/** The set of nodes depending on this node. */
		protected Set otherdeps;

		/**
		 *  Create a node info.
		 */
		public NodeInfo() 
		{
			this.mydeps = new HashSet();
			this.otherdeps = new HashSet();
		}

		/**
		 *  Get the mydeps.
		 *  @return The mydeps.
		 */
		public Set getMyDeps() 
		{
			return mydeps;
		}

		/**
		 *  Set the mydeps to set.
		 *  @param mydeps The mydeps to set.
		 */
		public void setMyDeps(Set mydeps) 
		{
			this.mydeps = mydeps;
		}

		/**
		 *  Get the otherdeps.
		 *  @return The otherdeps.
		 */
		public Set getOtherDeps() 
		{
			return otherdeps;
		}

		/**
		 *  Set the otherdeps to set.
		 *  @param otherdeps The otherdeps to set.
		 */
		public void setOtherDeps(Set otherdeps) 
		{
			this.otherdeps = otherdeps;
		}
		
		/**
		 *  Get a string representation.
		 */
		public String toString()
		{
			return "pre: "+getMyDeps()+", post: "+getOtherDeps();
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy