jadex.bridge.component.DependencyResolver Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jadex-platform-bridge Show documentation
Show all versions of jadex-platform-bridge Show documentation
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.
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();
}
}
}