package org.jboss.seam.init;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
/**
* Evaluates component dependencies to determine which
* components are installed.
*
* @author Norman Richards
*
*/
public class DependencyManager
{
private Map<String, Set<ComponentDescriptor>> componentDescriptors;
private Set<ComponentDescriptor> currentTestSet;
private Set<ComponentDescriptor> installedSet;
public DependencyManager(Map<String, Set<ComponentDescriptor>> componentDescriptors)
{
this.componentDescriptors = new HashMap<String, Set<ComponentDescriptor>>(componentDescriptors);
}
public Set<ComponentDescriptor> installedSet()
{
computeInstallSet();
return installedSet;
}
private static final Comparator<ComponentDescriptor> ORDER = new Comparator<ComponentDescriptor>()
{
public int compare(ComponentDescriptor x, ComponentDescriptor y)
{
return x.getName().compareTo( y.getName() );
}
};
private void computeInstallSet()
{
installedSet = new TreeSet<ComponentDescriptor>(ORDER);
Set<String> keys = componentDescriptors.keySet();
for (String key: keys) {
currentTestSet = new HashSet<ComponentDescriptor>();
if (tryToInstall(key)) {
installedSet.addAll(currentTestSet);
}
currentTestSet = null;
}
}
private boolean tryToInstall(String key)
{
Set<ComponentDescriptor> descriptors = componentDescriptors.get(key);
if (descriptors == null)
{
return false;
}
for (ComponentDescriptor descriptor : descriptors)
{
Set<ComponentDescriptor> saved = new HashSet<ComponentDescriptor>(currentTestSet);
if (tryToInstall(descriptor))
{
return true;
}
else
{
currentTestSet = saved;
}
}
return false;
}
private boolean tryToInstall(ComponentDescriptor descriptor)
{
if (isInInstallSet(descriptor.getName()))
{
return true;
}
currentTestSet.add(descriptor);
return checkAllDependencies(descriptor);
}
private boolean checkAllDependencies(ComponentDescriptor descriptor)
{
return descriptor.isInstalled() &&
checkClassDependencies(descriptor) &&
checkComponentDependencies(descriptor) &&
checkGenericDependencies(descriptor);
}
private boolean checkComponentDependencies(ComponentDescriptor descriptor)
{
String[] dependencies = descriptor.getDependencies();
if (dependencies == null)
{
return true;
}
for (String componentName: dependencies)
{
if (!tryToInstall(componentName))
{
return false;
}
}
return true;
}
private boolean checkClassDependencies(ComponentDescriptor descriptor)
{
String[] classDependencies = descriptor.getClassDependencies();
if (classDependencies == null)
{
return true;
}
for (String className: classDependencies)
{
try
{
descriptor.getComponentClass().getClassLoader().loadClass(className);
}
catch (NoClassDefFoundError e)
{
return false;
}
catch (Exception e)
{
return false;
}
}
return true;
}
private boolean checkGenericDependencies(ComponentDescriptor descriptor)
{
Class[] dependencies = descriptor.getGenericDependencies();
if (dependencies == null)
{
return true;
}
for (Class dependency: dependencies)
{
if (!isInInstallSet(dependency))
{
Set<String> searchList = findPotentialComponents(dependency);
if (!tryToSatisfyDependencyUsing(dependency, searchList))
{
return false;
}
}
}
return true;
}
private boolean tryToSatisfyDependencyUsing(Class dependency, Set<String> searchList)
{
for (String componentName:searchList)
{
Set<ComponentDescriptor> saved = new HashSet<ComponentDescriptor>(currentTestSet);
// the second check is important for edge case
if (tryToInstall(componentName) && isInInstallSet(dependency))
{
return true;
}
else
{
currentTestSet = saved;
}
}
return false;
}
private Set<String> findPotentialComponents(Class dependency)
{
Set<String> keys = new HashSet<String>();
for (String candidateKey: componentDescriptors.keySet())
{
if (componentMightSatisfy(candidateKey, dependency))
{
keys.add(candidateKey);
}
}
return keys;
}
private boolean componentMightSatisfy(String candidateKey, Class dependency)
{
for (ComponentDescriptor descriptor: componentDescriptors.get(candidateKey))
{
if (descriptor.getComponentClass().equals(dependency))
{
return true;
}
}
return false;
}
private boolean isInInstallSet(Class dependency)
{
for (ComponentDescriptor descriptor: currentTestSet)
{
if (dependency.equals(descriptor.getComponentClass()))
{
return true;
}
}
for (ComponentDescriptor descriptor: installedSet)
{
if (dependency.equals(descriptor.getComponentClass()))
{
return true;
}
}
return false;
}
// install set is already installed or the current working set
private boolean isInInstallSet(String key)
{
for (ComponentDescriptor descriptor: currentTestSet)
{
if (key.equals(descriptor.getName()))
{
return true;
}
}
for (ComponentDescriptor descriptor: installedSet)
{
if (key.equals(descriptor.getName()))
{
return true;
}
}
return false;
}
}