felix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rickh...@apache.org
Subject svn commit: r373842 [2/2] - in /incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix: framework/ framework/searchpolicy/ framework/util/ moduleloader/
Date Tue, 31 Jan 2006 15:34:51 GMT
Added: incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicy.java
URL: http://svn.apache.org/viewcvs/incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicy.java?rev=373842&view=auto
==============================================================================
--- incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicy.java (added)
+++ incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicy.java Tue Jan 31 07:34:32 2006
@@ -0,0 +1,1585 @@
+package org.apache.felix.framework.searchpolicy;
+
+import java.net.URL;
+import java.util.*;
+
+import org.apache.felix.framework.Logger;
+import org.apache.felix.framework.util.SecurityManagerEx;
+import org.apache.felix.moduleloader.*;
+import org.osgi.framework.Version;
+
+public class R4SearchPolicy implements ISearchPolicy, ModuleListener
+{
+    // Array of IExport.
+    public static final String EXPORTS_ATTR = "exports";
+    // Array of IImport.
+    public static final String IMPORTS_ATTR = "imports";
+    // Array of IImport.
+    public static final String DYNAMICIMPORTS_ATTR = "dynamicimports";
+    // Array of INative.
+    public static final String LIBRARIES_ATTR = "libraries";
+    // Array of R4Wire.
+    public static final String WIRING_ATTR = "wiring";
+    // Boolean.
+    public static final String RESOLVED_ATTR = "resolved";
+
+    private Logger m_logger = null;
+    private IModuleFactory m_factory = null;
+    private Map m_availPkgMap = new HashMap();
+    private Map m_inUsePkgMap = new HashMap();
+
+    // Listener-related instance variables.
+    private static final ResolveListener[] m_emptyListeners = new ResolveListener[0];
+    private ResolveListener[] m_listeners = m_emptyListeners;
+
+    // Reusable empty arrays.
+    public static final IModule[] m_emptyModules = new IModule[0];
+    public static final R4Import[] m_emptyImports= new R4Import[0];
+    public static final R4Export[] m_emptyExports= new R4Export[0];
+    public static final R4Wire[] m_emptyWires = new R4Wire[0];
+
+    // Re-usable security manager for accessing class context.
+    private static SecurityManagerEx m_sm = new SecurityManagerEx();
+
+    public R4SearchPolicy(Logger logger)
+    {
+        m_logger = logger;
+    }
+
+    public IModuleFactory getModuleFactory()
+    {
+        return m_factory;
+    }
+
+    public void setModuleFactory(IModuleFactory factory)
+        throws IllegalStateException
+    {
+        if (m_factory == null)
+        {
+            m_factory = factory;
+            m_factory.addModuleListener(this);
+        }
+        else
+        {
+            throw new IllegalStateException("Module manager is already initialized");
+        }
+    }
+
+    public Class findClass(IModule module, String name)
+        throws ClassNotFoundException
+    {
+        // First, try to resolve the originating module.
+// TODO: Consider opimizing this call to resolve, since it is called
+// for each class load.
+        try
+        {
+            resolve(module);
+        }
+        catch (ResolveException ex)
+        {
+            // We do not use the resolve exception as the
+            // cause of the exception, since this would
+            // potentially leak internal module information.
+            throw new ClassNotFoundException(
+                name + ": cannot resolve package "
+                + ex.getPackage());
+        }
+
+        // Get the package of the target class.
+        String pkgName = Util.getClassPackage(name);
+
+        // Load all "java.*" classes from parent class loader;
+        // these packages cannot be provided by other bundles.
+        if (pkgName.startsWith("java."))
+        {
+            return this.getClass().getClassLoader().loadClass(name);
+        }
+
+        // Look in the module's imports.
+        Class clazz = findImportedClass(module, name, pkgName);
+
+        // If not found, try the module's own content.
+        if (clazz == null)
+        {
+            clazz = module.getContentLoader().getClass(name);
+
+            // If still not found, then try the module's dynamic imports.
+            if (clazz == null)
+            {
+                clazz = findDynamicallyImportedClass(module, name, pkgName);
+            }
+        }
+
+        if (clazz == null)
+        {
+            throw new ClassNotFoundException(name);
+        }
+
+        return clazz;
+    }
+
+    private Class findImportedClass(IModule module, String name, String pkgName)
+        throws ClassNotFoundException
+    {
+        // We delegate to the module's wires to find the class.
+        R4Wire[] wires = (R4Wire[]) module.getAttribute(WIRING_ATTR, m_emptyWires);
+        for (int i = 0; i < wires.length; i++)
+        {
+            // Only check when the package of the class is
+            // the same as the package for the wire.
+            if (wires[i].getExport().getName().equals(pkgName))
+            {
+                // If we find the class, then return it. Otherwise,
+                // throw an exception since the provider of the
+                // package did not have the class.
+                Class clazz = wires[i].getClass(name);
+                if (clazz != null)
+                {
+                    return clazz;
+                }
+                else
+                {
+                    throw new ClassNotFoundException(name);
+                }
+            }
+        }
+
+        return null;
+    }
+
+    private Class findDynamicallyImportedClass(
+        IModule module, String name, String pkgName)
+        throws ClassNotFoundException
+    {
+        // At this point, the module's imports were searched and so was the
+        // the module's content. Now we make an attempt to load the
+        // class via a dynamic import, if possible.
+        R4Wire wire = attemptDynamicImport(module, pkgName);
+
+        // If the dynamic import was successful, then this initial
+        // time we must directly return the result from dynamically
+        // created wire, but subsequent requests for classes in
+        // the associated package will be processed as part of
+        // normal static imports.
+        if (wire != null)
+        {
+            // If we find the class, then return it. Otherwise,
+            // throw an exception since the provider of the
+            // package did not have the class.
+            Class clazz = wire.getClass(name);
+            if (clazz != null)
+            {
+                return clazz;
+            }
+            else
+            {
+                throw new ClassNotFoundException(name);
+            }
+        }
+
+        // At this point, the class could not be found by the bundle's static
+        // or dynamic imports, nor its own resources. Before we throw
+        // an exception, we will try to determine if the instigator of the
+        // class load was a class from a bundle or not. This is necessary
+        // because the specification mandates that classes on the class path
+        // should be hidden (except for java.*), but it does allow for these
+        // classes to be exposed by the system bundle as an export. However,
+        // in some situations classes on the class path make the faulty
+        // assumption that they can access everything on the class path from
+        // every other class loader that they come in contact with. This is
+        // not true if the class loader in question is from a bundle. Thus,
+        // this code tries to detect that situation. If the class
+        // instigating the class load was NOT from a bundle, then we will
+        // make the assumption that the caller actually wanted to use the
+        // parent class loader and we will delegate to it. If the class was
+        // from a bundle, then we will enforce strict class loading rules
+        // for the bundle and throw a class not found exception.
+
+        // Get the class context to see the classes on the stack.
+        Class[] classes = m_sm.getClassContext();
+        // Start from 1 to skip security manager class.
+        for (int i = 1; i < classes.length; i++)
+        {
+            // Find the first class on the call stack that is neither
+            // a class loader or Class itself, because we want to ignore
+            // the calls to ClassLoader.loadClass() and Class.forName().
+            if (!ClassLoader.class.isAssignableFrom(classes[i]) &&
+                !Class.class.isAssignableFrom(classes[i]))
+            {
+                // If the instigating class was not from a bundle, then
+                // delegate to the parent class loader. Otherwise, break
+                // out of loop and throw an exception.
+                if (!ContentClassLoader.class.isInstance(classes[i].getClassLoader()))
+                {
+                    return this.getClass().getClassLoader().loadClass(name);
+                }
+                break;
+            }
+        }
+        
+        throw new ClassNotFoundException(name);
+    }
+
+    public URL findResource(IModule module, String name)
+        throws ResourceNotFoundException
+    {
+        // First, try to resolve the originating module.
+// TODO: Consider opimizing this call to resolve, since it is called
+// for each class load.
+        try
+        {
+            resolve(module);
+        }
+        catch (ResolveException ex)
+        {
+            // We do not use the resolve exception as the
+            // cause of the exception, since this would
+            // potentially leak internal module information.
+            throw new ResourceNotFoundException(
+                name + ": cannot resolve package "
+                + ex.getPackage());
+        }
+
+        // Get the package of the target class.
+        String pkgName = Util.getResourcePackage(name);
+
+        // Load all "java.*" classes from parent class loader;
+        // these packages cannot be provided by other bundles.
+        if (pkgName.startsWith("java."))
+        {
+            return this.getClass().getClassLoader().getResource(name);
+        }
+
+        // Look in the module's imports.
+        URL url = findImportedResource(module, name, pkgName);
+
+        // If not found, try the module's own content.
+        if (url == null)
+        {
+            url = module.getContentLoader().getResource(name);
+
+            // If still not found, then try the module's dynamic imports.
+            if (url == null)
+            {
+                url = findDynamicallyImportedResource(module, name, pkgName);
+            }
+        }
+
+        if (url == null)
+        {
+            throw new ResourceNotFoundException(name);
+        }
+
+        return url;
+    }
+
+    private URL findImportedResource(IModule module, String name, String pkgName)
+        throws ResourceNotFoundException
+    {
+        // We delegate to the module's wires to find the class.
+        R4Wire[] wires = (R4Wire[]) module.getAttribute(WIRING_ATTR, m_emptyWires);
+        for (int i = 0; i < wires.length; i++)
+        {
+            // Only check when the package of the class is
+            // the same as the package for the wire.
+            if (wires[i].getExport().getName().equals(pkgName))
+            {   
+                URL url = wires[i].getResource(name);
+                if (url != null)
+                {
+                    return url;
+                }
+                else
+                {
+                    throw new ResourceNotFoundException(name);
+                }
+            }
+        }
+    
+        return null;
+    }
+
+    private URL findDynamicallyImportedResource(
+        IModule module, String name, String pkgName)
+        throws ResourceNotFoundException
+    {
+        // At this point, the module's imports were searched and so was the
+        // the module's content. Now we make an attempt to load the
+        // class via a dynamic import, if possible.
+        R4Wire wire = attemptDynamicImport(module, pkgName);
+        
+        // If the dynamic import was successful, then this initial
+        // time we must directly return the result from dynamically
+        // created wire, but subsequent requests for resources in
+        // the associated package will be processed as part of
+        // normal static imports.
+        if (wire != null)
+        {
+            // If we find the class, then return it. Otherwise,
+            // throw an exception since the provider of the
+            // package did not have the class.
+            URL url = wire.getResource(name);
+            if (url != null)
+            {
+                return url;
+            }
+            else
+            {
+                throw new ResourceNotFoundException(name);
+            }
+        }
+    
+        // At this point, the resource could not be found by the bundle's static
+        // or dynamic imports, nor its own resources. Before we throw
+        // an exception, we will try to determine if the instigator of the
+        // resource load was a class from a bundle or not. This is necessary
+        // because the specification mandates that classes on the class path
+        // should be hidden (except for java.*), but it does allow for these
+        // classes to be exposed by the system bundle as an export. However,
+        // in some situations classes on the class path make the faulty
+        // assumption that they can access everything on the class path from
+        // every other class loader that they come in contact with. This is
+        // not true if the class loader in question is from a bundle. Thus,
+        // this code tries to detect that situation. If the class
+        // instigating the resource load was NOT from a bundle, then we will
+        // make the assumption that the caller actually wanted to use the
+        // parent class loader and we will delegate to it. If the class was
+        // from a bundle, then we will enforce strict class loading rules
+        // for the bundle and throw a resource not found exception.
+    
+        // Get the class context to see the classes on the stack.
+        Class[] classes = m_sm.getClassContext();
+        // Start from 1 to skip security manager class.
+        for (int i = 1; i < classes.length; i++)
+        {
+            // Find the first class on the call stack that is neither
+            // a class loader or Class itself, because we want to ignore
+            // the calls to ClassLoader.loadClass() and Class.forName().
+            if (!ClassLoader.class.isAssignableFrom(classes[i]) &&
+                !Class.class.isAssignableFrom(classes[i]))
+            {
+                // If the instigating class was not from a bundle, then
+                // delegate to the parent class loader. Otherwise, break
+                // out of loop and throw an exception.
+                if (!ContentClassLoader.class.isInstance(classes[i].getClassLoader()))
+                {
+                    return this.getClass().getClassLoader().getResource(name);
+                }
+                break;
+            }
+        }
+        
+        throw new ResourceNotFoundException(name);
+    }
+
+    private R4Wire attemptDynamicImport(IModule module, String pkgName)
+    {
+        R4Wire wire = null;
+        IModule candidate = null;
+
+        // There is an overriding assumption here that a package is
+        // never split across bundles. If a package can be split
+        // across bundles, then this will fail.
+
+        try
+        {
+            // Check the dynamic import specs for a match of
+            // the target package.
+            R4Import[] dynamics = (R4Import[]) module.getAttribute(DYNAMICIMPORTS_ATTR, m_emptyImports);
+            R4Import impMatch = null;
+            for (int i = 0; (impMatch == null) && (i < dynamics.length); i++)
+            {
+                // Star matches everything.
+                if (dynamics[i].getName().equals("*"))
+                {
+                    // Create a package instance without wildcard.
+                    impMatch = new R4Import(
+                        pkgName,
+                        dynamics[i].getDirectives(),
+                        dynamics[i].getAttributes());
+                }
+                // Packages ending in ".*" must match starting strings.
+                else if (dynamics[i].getName().endsWith(".*"))
+                {
+                    if (pkgName.regionMatches(
+                        0, dynamics[i].getName(), 0, dynamics[i].getName().length() - 2))
+                    {
+                        // Create a package instance without wildcard.
+                        impMatch = new R4Import(
+                            pkgName,
+                            dynamics[i].getDirectives(),
+                            dynamics[i].getAttributes());
+                    }
+                }
+                // Or we can have a precise match.
+                else
+                {
+                    if (pkgName.equals(dynamics[i].getName()))
+                    {
+                        impMatch = dynamics[i];
+                    }
+                }
+            }
+
+            // If the target package does not match any dynamically imported
+            // packages or if the module is already wired for the target package,
+            // then just return null. The module may be already wired to the target
+            // package if the class being searched for does not actually exist.
+            if ((impMatch == null) || (getWire(module, impMatch.getName()) != null))
+            {
+                return null;
+            }
+
+            // At this point, the target package has matched a dynamically
+            // imported package spec. Now we must try to find a candidate
+            // exporter for target package and add it to the module's set
+            // of wires.
+
+            // Lock module manager instance to ensure that nothing changes.
+            synchronized (m_factory)
+            {
+                // Try to add a new entry to the module's import attribute.
+                // Select the first candidate that successfully resolves.
+
+                // First check already resolved exports for a match.
+                IModule[] candidates = getCompatibleExporters(
+                    (IModule[]) m_inUsePkgMap.get(impMatch.getName()), impMatch);
+                // If there is an "in use" candidate, just take the first one.
+                if (candidates.length > 0)
+                {
+                    candidate = candidates[0];
+                }
+
+                // If there were no "in use" candidates, then try "available"
+                // candidates.
+                if (candidate == null)
+                {
+                    candidates = getCompatibleExporters(
+                        (IModule[]) m_availPkgMap.get(impMatch.getName()), impMatch);
+                    for (int candIdx = 0;
+                        (candidate == null) && (candIdx < candidates.length);
+                        candIdx++)
+                    {
+                        try
+                        {
+                            resolve(module);
+                            candidate = candidates[candIdx];
+                        }
+                        catch (ResolveException ex)
+                        {
+                        }
+                    }
+                }
+
+                // If we found a candidate, then add it to the module's
+                // wiring attribute.
+                if (candidate != null)
+                {
+                    R4Wire[] wires = (R4Wire[]) module.getAttribute(WIRING_ATTR, m_emptyWires);
+                    R4Wire[] newWires = new R4Wire[wires.length + 1];
+                    System.arraycopy(wires, 0, newWires, 0, wires.length);
+                    // Find the candidate's export package object and
+                    // use that for creating the wire; this is necessary
+                    // since it contains "uses" dependency information.
+                    wire = new R4Wire(
+                        module, candidate,
+                        getExportPackage(candidate, impMatch.getName()));
+                    newWires[wires.length] = wire;
+                    module.setAttribute(WIRING_ATTR, newWires);
+m_logger.log(Logger.LOG_DEBUG, "WIRE: [" + module + "] " + newWires[wires.length]);
+                }
+            }
+        }
+        catch (Exception ex)
+        {
+            m_logger.log(Logger.LOG_ERROR, "Unable to dynamically import package.", ex);
+        }
+
+        return wire;
+    }
+
+    public String findLibrary(IModule module, String name)
+    {
+        // Remove leading slash, if present.
+        if (name.startsWith("/"))
+        {
+            name = name.substring(1);
+        }
+
+        ILibrary[] libs = (ILibrary[])
+            module.getAttribute(R4SearchPolicy.LIBRARIES_ATTR, null);
+        for (int i = 0;
+            (libs != null) && (i < libs.length);
+            i++)
+        {
+            String path = libs[i].getPath(name);
+            if (path != null)
+            {
+                return path;
+            }
+        }
+
+        return null;
+    }
+
+    public IModule[] getAvailableExporters(R4Import pkg)
+    {
+        // Synchronized on the module manager to make sure that no
+        // modules are added, removed, or resolved.
+        synchronized (m_factory)
+        {
+            return getCompatibleExporters((IModule[]) m_availPkgMap.get(pkg.getName()), pkg);
+        }
+    }
+
+    public IModule[] getInUseExporters(R4Import pkg)
+    {
+        // Synchronized on the module manager to make sure that no
+        // modules are added, removed, or resolved.
+        synchronized (m_factory)
+        {
+            return getCompatibleExporters((IModule[]) m_inUsePkgMap.get(pkg.getName()), pkg);
+        }
+    }
+
+    public void resolve(IModule rootModule)
+        throws ResolveException
+    {
+        // If the module is already resolved, then we can just return.
+        if (((Boolean) rootModule.getAttribute(RESOLVED_ATTR, Boolean.FALSE)).booleanValue())
+        {
+            return;
+        }
+    
+        // This variable maps an unresolved module to a list of resolver
+        // nodes, where there is one resolver node for each import that
+        // must be resolved. A resolver node contains the potential
+        // candidates to resolve the import and the current selected
+        // candidate index.
+        Map resolverMap = new HashMap();
+    
+        // This map will be used to hold the final wires for all
+        // resolved modules, which can then be used to fire resolved
+        // events outside of the synchronized block.
+        Map resolvedModuleWireMap = null;
+    
+        // Synchronize on the module manager, because we don't want
+        // any modules being added or removed while we are in the
+        // middle of this operation.
+        synchronized (m_factory)
+        {
+            // The first step is to populate the resolver map. This
+            // will use the target module to populate the resolver map
+            // with all potential modules that need to be resolved as a
+            // result of resolving the target module. The key of the
+            // map is a potential module to be resolved and the value is
+            // a list of resolver nodes, one for each of the module's
+            // imports, where each resolver node contains the potential
+            // candidates for resolving the import. Not all modules in
+            // this map will be resolved, only the target module and
+            // any candidates selected to resolve its imports and the
+            // transitive imports this implies.
+            populateResolverMap(resolverMap, rootModule);
+
+            // The next step is to use the resolver map to determine if
+            // the class space for the root module is consistent. This
+            // is an iterative process that transitively walks the "uses"
+            // relationships of all currently selected potential candidates
+            // for resolving import packages checking for conflicts. If a
+            // conflict is found, it "increments" the configuration of
+            // currently selected potential candidates and tests them again.
+            // If this method returns, then it has found a consistent set
+            // of candidates; otherwise, a resolve exception is thrown if
+            // it exhausts all possible combinations and could not find a
+            // consistent class space.
+            findConsistentClassSpace(resolverMap, rootModule);
+    
+            // The final step is to create the wires for the root module and
+            // transitively all modules that are to be resolved from the
+            // selected candidates for resolving the root module's imports.
+            // When this call returns, each module's wiring and resolved
+            // attributes are set. The resulting wiring map is used below
+            // to fire resolved events outside of the synchronized block.
+            // The resolved module wire map maps a module to its array of
+            // wires.
+            resolvedModuleWireMap = createWires(resolverMap, rootModule);
+        
+//dumpAvailablePackages();
+//dumpUsedPackages();
+
+        } // End of synchronized block on module manager.
+
+        // Fire resolved events for all resolved modules;
+        // the resolved modules array will only be set if the resolve
+        // was successful after the root module was resolved.
+        if (resolvedModuleWireMap != null)
+        {
+            Iterator iter = resolvedModuleWireMap.entrySet().iterator();
+            while (iter.hasNext())
+            {
+                fireModuleResolved((IModule) ((Map.Entry) iter.next()).getKey());
+            }
+        }
+    }
+
+    private void populateResolverMap(Map resolverMap, IModule module)
+        throws ResolveException
+    {
+        // Detect cycles.
+        if (resolverMap.get(module) != null)
+        {
+            return;
+        }
+
+        // Map to hold the bundle's import packages
+        // and their respective resolving candidates.
+        List nodeList = new ArrayList();
+
+        // Even though the node list is currently emptry, we
+        // record it in the resolver map early so we can use
+        // it to detect cycles.
+        resolverMap.put(module, nodeList);
+
+        // Loop through each import and calculate its resolving
+        // set of candidates.
+        R4Import[] imports = (R4Import[]) module.getAttribute(IMPORTS_ATTR, m_emptyImports);
+        for (int impIdx = 0; impIdx < imports.length; impIdx++)
+        {
+            // Get the candidates from the "in use" and "available"
+            // package maps. Candidates "in use" have higher priority
+            // than "available" ones, so put the "in use" candidates
+            // at the front of the list of candidates.
+            IModule[] inuse = getCompatibleExporters(
+                (IModule[]) m_inUsePkgMap.get(
+                    imports[impIdx].getName()), imports[impIdx]);
+            IModule[] available = getCompatibleExporters(
+                (IModule[]) m_availPkgMap.get(
+                    imports[impIdx].getName()), imports[impIdx]);
+            IModule[] candidates = new IModule[inuse.length + available.length];
+            System.arraycopy(inuse, 0, candidates, 0, inuse.length);
+            System.arraycopy(available, 0, candidates, inuse.length, available.length);
+
+            // If we have candidates, then we need to recursively populate
+            // the resolver map with each of them.
+            ResolveException rethrow = null;
+            if (candidates.length > 0)
+            {
+                for (int candIdx = 0; candIdx < candidates.length; candIdx++)
+                {
+                    try
+                    {
+                        // Only populate the resolver map with modules that
+                        // are not already resolved.
+                        if (!((Boolean) candidates[candIdx].getAttribute(RESOLVED_ATTR, Boolean.FALSE)).booleanValue())
+                        {
+                            populateResolverMap(resolverMap, candidates[candIdx]);
+                        }
+                    }
+                    catch (ResolveException ex)
+                    {
+                        // If we received a resolve exception, then the
+                        // current candidate is not resolvable for some
+                        // reason and should be removed from the list of
+                        // candidates. For now, just null it.
+                        candidates[candIdx] = null;
+                        rethrow = ex;
+                    }
+                }
+
+                // Remove any nulled candidates to create the final list
+                // of available candidates.
+                candidates = shrinkModuleArray(candidates);
+            }
+
+            // If no candidates exist at this point, then throw a
+            // resolve exception unless the import is optional.
+            if ((candidates.length == 0) && !imports[impIdx].isOptional())
+            {
+                // If we have received an exception while trying to populate
+                // the resolver map, rethrow that exception since it might
+                // be useful. NOTE: This is not necessarily the "only"
+                // correct exception, since it is possible that multiple
+                // candidates were not resolvable, but it is better than
+                // nothing.
+                if (rethrow != null)
+                {
+                    throw rethrow;
+                }
+                else
+                {
+                    throw new ResolveException(
+                        "Unable to resolve.", module, imports[impIdx]);
+                }
+            }
+            else if (candidates.length > 0)
+            {
+                nodeList.add(
+                    new ResolverNode(module, imports[impIdx], candidates));
+            }
+        }
+    }
+
+
+//  TODO: REMOVE THESE DEBUG METHODS.
+    private void dumpAvailablePackages()
+    {
+        synchronized (this)
+        {
+            System.out.println("AVAILABLE PACKAGES:");
+            for (Iterator i = m_availPkgMap.entrySet().iterator(); i.hasNext(); )
+            {
+                Map.Entry entry = (Map.Entry) i.next();
+                System.out.println("  " + entry.getKey());
+                IModule[] modules = (IModule[]) entry.getValue();
+                for (int j = 0; j < modules.length; j++)
+                {
+                    System.out.println("    " + modules[j]);
+                }
+            }
+        }
+    }
+
+    private void dumpUsedPackages()
+    {
+        synchronized (this)
+        {
+            System.out.println("USED PACKAGES:");
+            for (Iterator i = m_inUsePkgMap.entrySet().iterator(); i.hasNext(); )
+            {
+                Map.Entry entry = (Map.Entry) i.next();
+                System.out.println("  " + entry.getKey());
+                IModule[] modules = (IModule[]) entry.getValue();
+                for (int j = 0; j < modules.length; j++)
+                {
+                    System.out.println("    " + modules[j]);
+                }
+            }
+        }
+    }
+
+    private IModule[] getCompatibleExporters(IModule[] modules, R4Import target)
+    {
+        // Create list of compatible exporters.
+        IModule[] candidates = null;
+        for (int modIdx = 0; (modules != null) && (modIdx < modules.length); modIdx++)
+        {
+            // Get the modules export package for the target package.
+            R4Export export = getExportPackage(modules[modIdx], target.getName());
+            // If compatible, then add the candidate to the list.
+            if ((export != null) && (target.isSatisfied(export)))
+            {
+                candidates = addModuleToArray(candidates, modules[modIdx]);
+            }
+        }
+        if (candidates == null)
+        {
+            return m_emptyModules;
+        }
+        return candidates;
+    }
+
+    private void findConsistentClassSpace(Map resolverMap, IModule rootModule)
+        throws ResolveException
+    {
+        List resolverList = null;
+    
+        // Test the current set of candidates to determine if they
+        // are consistent. Keep looping until we find a consistent
+        // set or an exception is thrown.
+        Map cycleMap = new HashMap();
+        while (!isClassSpaceConsistent(resolverMap, rootModule, cycleMap))
+        {
+m_logger.log(
+    Logger.LOG_DEBUG,
+    "Constraint violation detected, will try to repair.");
+
+            // The incrementCandidateConfiguration() method requires a
+            // ordered access to the resolver map, so we will create
+            // a reusable list once right here.
+            if (resolverList == null)
+            {
+                resolverList = new ArrayList();
+                for (Iterator iter = resolverMap.entrySet().iterator();
+                    iter.hasNext(); )
+                {
+                    resolverList.add((List) ((Map.Entry) iter.next()).getValue());
+                }
+            }
+    
+            // Increment the candidate configuration so we can test again.
+            incrementCandidateConfiguration(resolverList);
+    
+            // Clear the cycle map.
+            cycleMap.clear();
+        }
+    }
+
+    private boolean isClassSpaceConsistent(
+        Map resolverMap, IModule rootModule, Map cycleMap)
+    {
+        // We do not need to verify that already resolved modules
+        // have consistent class spaces because they should be
+        // consistent by definition. Also, if the root module is
+        // part of a cycle, then just assume it is true.
+        if (((Boolean) rootModule.getAttribute(RESOLVED_ATTR, Boolean.FALSE)).booleanValue() ||
+            (cycleMap.get(rootModule) != null))
+        {
+            return true;
+        }
+    
+        // Add to cycle map for future reference.
+        cycleMap.put(rootModule, rootModule);
+    
+        // Create an implicit "uses" constraint for every exported package
+        // of the root module that is not also imported; uses constraints
+        // for exported packages that are also imported will be taken
+        // care of as part of normal import package processing.
+        R4Export[] exports = (R4Export[]) rootModule.getAttribute(EXPORTS_ATTR, m_emptyExports);
+        Map usesMap = new HashMap();
+        for (int i = 0; i < exports.length; i++)
+        {
+            // Ignore exports that are also imported, since they
+            // will be taken care of when verifying import constraints.
+            if (getImportPackage(rootModule, exports[i].getName()) == null)
+            {
+                usesMap.put(exports[i].getName(), rootModule);
+            }
+        }
+    
+        // Loop through the current candidates for the module's imports
+        // (available in the resolver node list of the resolver map) and
+        // calculate the uses constraints for each of the currently
+        // selected candidates for resolving the imports. Compare each
+        // candidate's constraints to the existing constraints to check
+        // for conflicts.
+        List nodeList = (List) resolverMap.get(rootModule);
+        for (int nodeIdx = 0; nodeIdx < nodeList.size(); nodeIdx++)
+        {
+            // Verify that the current candidate does not violate
+            // any "uses" constraints of existing candidates by
+            // calculating the candidate's transitive "uses" constraints
+            // for the provided package and testing whether they
+            // overlap with existing constraints.
+    
+            // First, get the resolver node.
+            ResolverNode node = (ResolverNode) nodeList.get(nodeIdx);
+    
+            // Verify that the current candidate itself has a consistent
+            // class space.
+            if (!isClassSpaceConsistent(
+                resolverMap, node.m_candidates[node.m_idx], cycleMap))
+            {
+                return false;
+            }
+    
+            // Get the exported package from the current candidate that
+            // will be used to resolve the root module's import.
+            R4Export candidatePkg = getExportPackage(
+                node.m_candidates[node.m_idx], node.m_import.getName());
+    
+            // Calculate the "uses" dependencies implied by the candidate's
+            // exported package with respect to the currently selected
+            // candidates in the resolver map.
+            Map candUsesMap = calculateUsesDependencies(
+                resolverMap,
+                node.m_candidates[node.m_idx],
+                candidatePkg,
+                new HashMap());
+//System.out.println("MODULE " + rootModule + " USES    " + usesMap);
+//System.out.println("CANDIDATE " + node.m_candidates[node.m_idx] + " USES " + candUsesMap);
+
+            // Iterate through the root module's current set of transitive
+            // "uses" constraints and compare them with the candidate's
+            // transitive set of constraints.
+            Iterator usesIter = candUsesMap.entrySet().iterator();
+            while (usesIter.hasNext())
+            {
+                // If the candidate's uses constraints overlap with
+                // the existing uses constraints, but refer to a
+                // different provider, then the class space is not
+                // consistent; thus, return false.
+                Map.Entry entry = (Map.Entry) usesIter.next();
+                if ((usesMap.get(entry.getKey()) != null) &&
+                    (usesMap.get(entry.getKey()) != entry.getValue()))
+                {
+                    return false;
+                }
+            }
+    
+            // Since the current candidate's uses constraints did not
+            // conflict with existing constraints, merge all constraints
+            // and keep testing the remaining candidates for the other
+            // imports of the root module.
+            usesMap.putAll(candUsesMap);
+        }
+    
+        return true;
+    }
+
+    private Map calculateUsesDependencies(
+        Map resolverMap, IModule module, R4Export export, Map usesMap)
+    {
+// TODO: CAN THIS BE OPTIMIZED?
+// TODO: IS THIS CYCLE CHECK CORRECT??
+// TODO: WHAT HAPPENS THERE ARE OVERLAPS WHEN CALCULATING USES??
+//       MAKE AN EXAMPLE WHERE TWO DEPENDENCIES PROVIDE SAME PACKAGE.
+        // Make sure we are not in a cycle.
+        if (usesMap.get(export.getName()) != null)
+        {
+            return usesMap;
+        }
+
+        // The target package at least uses itself,
+        // so add it to the uses map.
+        usesMap.put(export.getName(), module);
+
+        // Get the "uses" constraints for the target export
+        // package and calculate the transitive uses constraints
+        // of any used packages.
+        String[] uses = export.getUses();
+        List nodeList = (List) resolverMap.get(module);
+
+        // We need to walk the transitive closure of "uses" relationships
+        // for the current export package to calculate the entire set of
+        // "uses" constraints.
+        for (int usesIdx = 0; usesIdx < uses.length; usesIdx++)
+        {
+            // There are two possibilities at this point: 1) we are dealing
+            // with an already resolved bundle or 2) we are dealing with a
+            // bundle that has not yet been resolved. In case 1, there will
+            // be no resolver node in the resolver map, so we just need to
+            // examine the bundle directly to determine its exact constraints.
+            // In case 2, there will be a resolver node in the resolver map,
+            // so we will use that to determine the potential constraints of
+            // potential candidate for resolving the import.
+
+            // This is case 1, described in the comment above.
+            if (nodeList == null)
+            {
+                // Get the actual exporter from the wire or if there
+                // is no wire, then get the export is from the module
+                // itself.
+                R4Wire wire = getWire(module, uses[usesIdx]);
+                if (wire != null)
+                {
+                    usesMap = calculateUsesDependencies(
+                        resolverMap, wire.getExportingModule(), wire.getExport(), usesMap);
+                }
+                else
+                {
+                    export = getExportPackage(module, uses[usesIdx]);
+                    if (export != null)
+                    {
+                        usesMap = calculateUsesDependencies(
+                            resolverMap, module, export, usesMap);
+                    }
+                }
+            }
+            // This is case 2, described in the comment above.
+            else
+            {
+                // First, get the resolver node for the "used" package.
+                ResolverNode node = null;
+                for (int nodeIdx = 0;
+                    (node == null) && (nodeIdx < nodeList.size());
+                    nodeIdx++)
+                {
+                    node = (ResolverNode) nodeList.get(nodeIdx);
+                    if (!node.m_import.getName().equals(uses[usesIdx]))
+                    {
+                        node = null;
+                    }
+                }
+    
+                // If there is a resolver node for the "used" package,
+                // then this means that the module imports the package
+                // and we need to recursively add the constraints of
+                // the potential exporting module.
+                if (node != null)
+                {
+                    usesMap = calculateUsesDependencies(
+                        resolverMap,
+                        node.m_candidates[node.m_idx],
+                        getExportPackage(node.m_candidates[node.m_idx], node.m_import.getName()),
+                        usesMap);
+                }
+                // If there was no resolver node for the "used" package,
+                // then this means that the module exports the package
+                // and we need to recursively add the constraints of this
+                // other exported package of this module.
+                else if (getExportPackage(module, uses[usesIdx]) != null)
+                {
+                    usesMap = calculateUsesDependencies(
+                        resolverMap,
+                        module,
+                        getExportPackage(module, uses[usesIdx]),
+                        usesMap);
+                }
+            }
+        }
+
+        return usesMap;
+    }
+
+    private void incrementCandidateConfiguration(List resolverList)
+        throws ResolveException
+    {
+        for (int i = 0; i < resolverList.size(); i++)
+        {
+            List nodeList = (List) resolverList.get(i);
+            for (int j = 0; j < nodeList.size(); j++)
+            {
+                ResolverNode node = (ResolverNode) nodeList.get(j);
+                // See if we can increment the node, without overflowing
+                // the candidate array bounds.
+                if ((node.m_idx + 1) < node.m_candidates.length)
+                {
+                    node.m_idx++;
+                    return;
+                }
+                // If the index will overflow the candidate array bounds,
+                // then set the index back to zero and try to increment
+                // the next candidate.
+                else
+                {
+                    node.m_idx = 0;
+                }
+            }
+        }
+        throw new ResolveException(
+            "Unable to resolve due to constraint violation.", null, null);
+    }
+
+    private Map createWires(Map resolverMap, IModule rootModule)
+    {
+        Map resolvedModuleWireMap =
+            populateWireMap(resolverMap, rootModule, new HashMap());
+        Iterator iter = resolvedModuleWireMap.entrySet().iterator();
+        while (iter.hasNext())
+        {
+            Map.Entry entry = (Map.Entry) iter.next();
+            IModule module = (IModule) entry.getKey();
+            R4Wire[] wires = (R4Wire[]) entry.getValue();
+    
+            // Set the module's resolved and wiring attribute.
+            module.setAttribute(RESOLVED_ATTR, Boolean.TRUE);
+            // Only add wires attribute if some exist; export
+            // only modules may not have wires.
+            if (wires.length > 0)
+            {
+                module.setAttribute(WIRING_ATTR, wires);
+            }
+    
+            // Remove the wire's exporting module from the "available"
+            // package map and put it into the "in use" package map;
+            // these steps may be a no-op.
+            for (int wireIdx = 0;
+                (wires != null) && (wireIdx < wires.length);
+                wireIdx++)
+            {
+m_logger.log(Logger.LOG_DEBUG, "WIRE: [" + module + "] " + wires[wireIdx]);
+                // First remove the wire module from "available" package map.
+                IModule[] modules = (IModule[]) m_availPkgMap.get(wires[wireIdx].getExport().getName());
+                modules = removeModuleFromArray(modules, wires[wireIdx].getExportingModule());
+                m_availPkgMap.put(wires[wireIdx].getExport().getName(), modules);
+    
+                // Also remove any exported packages from the "available"
+                // package map that are from the module associated with
+                // the current wires where the exported packages were not
+                // actually exported; an export may not be exported if
+                // the module also imports the same package and was wired
+                // to a different module. If the exported package is not
+                // actually exported, then we just want to remove it
+                // completely, since it cannot be used.
+                if (wires[wireIdx].getExportingModule() != module)
+                {
+                    modules = (IModule[]) m_availPkgMap.get(wires[wireIdx].getExport().getName());
+                    modules = removeModuleFromArray(modules, module);
+                    m_availPkgMap.put(wires[wireIdx].getExport().getName(), modules);
+                }
+    
+                // Add the module of the wire to the "in use" package map.
+                modules = (IModule[]) m_inUsePkgMap.get(wires[wireIdx].getExport().getName());
+                modules = addModuleToArray(modules, wires[wireIdx].getExportingModule());
+                m_inUsePkgMap.put(wires[wireIdx].getExport().getName(), modules);
+            }
+        }
+        return resolvedModuleWireMap;
+    }
+
+    private Map populateWireMap(Map resolverMap, IModule module, Map wireMap)
+    {
+        // If the module is already resolved or it is part of
+        // a cycle, then just return the wire map.
+        if (((Boolean) module.getAttribute(RESOLVED_ATTR, Boolean.FALSE)).booleanValue() ||
+            (wireMap.get(module) != null))
+        {
+            return wireMap;
+        }
+    
+        List nodeList = (List) resolverMap.get(module);
+        R4Wire[] wires = new R4Wire[nodeList.size()];
+    
+        // Put the module in the wireMap with an empty wire array;
+        // we do this early so we can use it to detect cycles.
+        wireMap.put(module, wires);
+    
+        // Loop through each resolver node and create a wire
+        // for the selected candidate for the associated import.
+        for (int nodeIdx = 0; nodeIdx < nodeList.size(); nodeIdx++)
+        {
+            // Get the import's associated resolver node.
+            ResolverNode node = (ResolverNode) nodeList.get(nodeIdx);
+    
+            // Add the candidate to the list of wires.
+            R4Export export =
+                getExportPackage(node.m_candidates[node.m_idx], node.m_import.getName());
+            wires[nodeIdx] = new R4Wire(module, node.m_candidates[node.m_idx], export);
+    
+            // Create the wires for the selected candidate module.
+            wireMap = populateWireMap(resolverMap, node.m_candidates[node.m_idx], wireMap);
+        }
+    
+        return wireMap;
+    }
+
+    //
+    // Event handling methods for validation events.
+    //
+
+    /**
+     * Adds a resolver listener to the search policy. Resolver
+     * listeners are notified when a module is resolve and/or unresolved
+     * by the search policy.
+     * @param l the resolver listener to add.
+    **/
+    public void addResolverListener(ResolveListener l)
+    {
+        // Verify listener.
+        if (l == null)
+        {
+            throw new IllegalArgumentException("Listener is null");
+        }
+
+        // Use the m_noListeners object as a lock.
+        synchronized (m_emptyListeners)
+        {
+            // If we have no listeners, then just add the new listener.
+            if (m_listeners == m_emptyListeners)
+            {
+                m_listeners = new ResolveListener[] { l };
+            }
+            // Otherwise, we need to do some array copying.
+            // Notice, the old array is always valid, so if
+            // the dispatch thread is in the middle of a dispatch,
+            // then it has a reference to the old listener array
+            // and is not affected by the new value.
+            else
+            {
+                ResolveListener[] newList = new ResolveListener[m_listeners.length + 1];
+                System.arraycopy(m_listeners, 0, newList, 0, m_listeners.length);
+                newList[m_listeners.length] = l;
+                m_listeners = newList;
+            }
+        }
+    }
+
+    /**
+     * Removes a resolver listener to this search policy.
+     * @param l the resolver listener to remove.
+    **/
+    public void removeResolverListener(ResolveListener l)
+    {
+        // Verify listener.
+        if (l == null)
+        {
+            throw new IllegalArgumentException("Listener is null");
+        }
+
+        // Use the m_emptyListeners object as a lock.
+        synchronized (m_emptyListeners)
+        {
+            // Try to find the instance in our list.
+            int idx = -1;
+            for (int i = 0; i < m_listeners.length; i++)
+            {
+                if (m_listeners[i].equals(l))
+                {
+                    idx = i;
+                    break;
+                }
+            }
+
+            // If we have the instance, then remove it.
+            if (idx >= 0)
+            {
+                // If this is the last listener, then point to empty list.
+                if (m_listeners.length == 1)
+                {
+                    m_listeners = m_emptyListeners;
+                }
+                // Otherwise, we need to do some array copying.
+                // Notice, the old array is always valid, so if
+                // the dispatch thread is in the middle of a dispatch,
+                // then it has a reference to the old listener array
+                // and is not affected by the new value.
+                else
+                {
+                    ResolveListener[] newList = new ResolveListener[m_listeners.length - 1];
+                    System.arraycopy(m_listeners, 0, newList, 0, idx);
+                    if (idx < newList.length)
+                    {
+                        System.arraycopy(m_listeners, idx + 1, newList, idx,
+                            newList.length - idx);
+                    }
+                    m_listeners = newList;
+                }
+            }
+        }
+    }
+
+    /**
+     * Fires a validation event for the specified module.
+     * @param module the module that was resolved.
+    **/
+    private void fireModuleResolved(IModule module)
+    {
+        // Event holder.
+        ModuleEvent event = null;
+
+        // Get a copy of the listener array, which is guaranteed
+        // to not be null.
+        ResolveListener[] listeners = m_listeners;
+
+        // Loop through listeners and fire events.
+        for (int i = 0; i < listeners.length; i++)
+        {
+            // Lazily create event.
+            if (event == null)
+            {
+                event = new ModuleEvent(m_factory, module);
+            }
+            listeners[i].moduleResolved(event);
+        }
+    }
+
+    /**
+     * Fires an unresolved event for the specified module.
+     * @param module the module that was unresolved.
+    **/
+    private void fireModuleUnresolved(IModule module)
+    {
+        // Event holder.
+        ModuleEvent event = null;
+
+        // Get a copy of the listener array, which is guaranteed
+        // to not be null.
+        ResolveListener[] listeners = m_listeners;
+
+        // Loop through listeners and fire events.
+        for (int i = 0; i < listeners.length; i++)
+        {
+            // Lazily create event.
+            if (event == null)
+            {
+                event = new ModuleEvent(m_factory, module);
+            }
+            listeners[i].moduleUnresolved(event);
+        }
+    }
+
+    //
+    // ModuleListener callback methods.
+    //
+
+    public void moduleAdded(ModuleEvent event)
+    {
+        // When a module is added to the system, we need to initialize
+        // its resolved and wiring attributes and add its exports to
+        // the map of available exports.
+
+        // Synchronize on the module manager, since we don't want any
+        // bundles to be installed or removed.
+        synchronized (m_factory)
+        {
+            // Add wiring attribute.
+            event.getModule().setAttribute(WIRING_ATTR, null);
+            // Add resolved attribute.
+            event.getModule().setAttribute(RESOLVED_ATTR, Boolean.FALSE);
+            // Add exports to available package map.
+            R4Export[] exports = (R4Export[]) event.getModule().getAttribute(EXPORTS_ATTR, m_emptyExports);
+            for (int i = 0; i < exports.length; i++)
+            {
+                IModule[] modules = (IModule[]) m_availPkgMap.get(exports[i].getName());
+
+                // We want to add the module into the list of available
+                // exporters in sorted order (descending version and
+                // ascending bundle identifier). Insert using a simple
+                // binary search algorithm.
+                if (modules == null)
+                {
+                    modules = new IModule[] { event.getModule() };
+                }
+                else
+                {
+                    int top = 0, bottom = modules.length - 1, middle = 0;
+                    Version middleVersion = null;
+                    while (top <= bottom)
+                    {
+                        middle = (bottom - top) / 2 + top;
+                        middleVersion = getExportPackage(
+                            modules[middle], exports[i].getName()).getVersion();
+                        // Sort in reverse version order.
+                        int cmp = middleVersion.compareTo(exports[i].getVersion());
+                        if (cmp < 0)
+                        {
+                            bottom = middle - 1;
+                        }
+                        else if (cmp == 0)
+                        {
+                            // Sort further by ascending bundle ID.
+                            long middleId = getBundleIdFromModuleId(modules[middle].getId());
+                            long exportId = getBundleIdFromModuleId(event.getModule().getId());
+                            if (middleId < exportId)
+                            {
+                                top = middle + 1;
+                            }
+                            else
+                            {
+                                bottom = middle - 1;
+                            }
+                        }
+                        else
+                        {
+                            top = middle + 1;
+                        }
+                    }
+
+                    IModule[] newMods = new IModule[modules.length + 1];
+                    System.arraycopy(modules, 0, newMods, 0, top);
+                    System.arraycopy(modules, top, newMods, top + 1, modules.length - top);
+                    newMods[top] = event.getModule();
+                    modules = newMods;
+                }
+
+                m_availPkgMap.put(exports[i].getName(), modules);
+            }
+        }
+    }
+
+    // This is duplicated from BundleInfo and probably shouldn't be,
+    // but its functionality is needed by the moduleAdded() callback.
+    private static long getBundleIdFromModuleId(String id)
+    {
+        try
+        {
+            String bundleId = (id.indexOf('.') >= 0)
+                ? id.substring(0, id.indexOf('.')) : id;
+            return Long.parseLong(bundleId);
+        }
+        catch (NumberFormatException ex)
+        {
+            return -1;
+        }
+    }
+
+    public void moduleReset(ModuleEvent event)
+    {
+        moduleRemoved(event);
+    }
+
+    public void moduleRemoved(ModuleEvent event)
+    {
+        // When a module is removed from the system, we need remove
+        // its exports from the "in use" and "available" package maps.
+
+        // Synchronize on the module manager, since we don't want any
+        // bundles to be installed or removed.
+        synchronized (m_factory)
+        {
+            // Remove exports from package maps.
+            R4Export[] exports = (R4Export[]) event.getModule().getAttribute(EXPORTS_ATTR, m_emptyExports);
+            for (int i = 0; i < exports.length; i++)
+            {
+                // Remove from "available" package map.
+                IModule[] modules = (IModule[]) m_availPkgMap.get(exports[i].getName());
+                if (modules != null)
+                {
+                    modules = removeModuleFromArray(modules, event.getModule());
+                    m_availPkgMap.put(exports[i].getName(), modules);
+                }
+                // Remove from "in use" package map.
+                modules = (IModule[]) m_inUsePkgMap.get(exports[i].getName());
+                if (modules != null)
+                {
+                    modules = removeModuleFromArray(modules, event.getModule());
+                    m_inUsePkgMap.put(exports[i].getName(), modules);
+                }
+            }
+        }
+    }
+
+    //
+    // Simple utility methods.
+    //
+
+// TODO: FIX - DETERMINE WHETHER ON IR4SearchPolicy OR NOT.
+    public static R4Export getExportPackage(IModule m, String name)
+    {
+        R4Export[] pkgs = (R4Export[]) m.getAttribute(EXPORTS_ATTR, m_emptyExports);
+        for (int i = 0; (pkgs != null) && (i < pkgs.length); i++)
+        {
+            if (pkgs[i].getName().equals(name))
+            {
+                return pkgs[i];
+            }
+        }
+        return null;
+    }
+
+// TODO: FIX - DETERMINE WHETHER ON IR4SearchPolicy OR NOT.
+    public static R4Import getImportPackage(IModule m, String name)
+    {
+        R4Import[] pkgs = (R4Import[]) m.getAttribute(IMPORTS_ATTR, m_emptyImports);
+        for (int i = 0; (pkgs != null) && (i < pkgs.length); i++)
+        {
+            if (pkgs[i].getName().equals(name))
+            {
+                return pkgs[i];
+            }
+        }
+        return null;
+    }
+
+// TODO: FIX - DETERMINE WHETHER ON IR4SearchPolicy OR NOT.
+    public static R4Wire getWire(IModule m, String name)
+    {
+        R4Wire[] wires = (R4Wire[]) m.getAttribute(WIRING_ATTR, m_emptyWires);
+        for (int i = 0; (wires != null) && (i < wires.length); i++)
+        {
+            if (wires[i].getExport().getName().equals(name))
+            {
+                return wires[i];
+            }
+        }
+        return null;
+    }
+
+    private static IModule[] addModuleToArray(IModule[] modules, IModule m)
+    {
+        // Verify that the module is not already in the array.
+        for (int i = 0; (modules != null) && (i < modules.length); i++)
+        {
+            if (modules[i] == m)
+            {
+                return modules;
+            }
+        }
+
+        if (modules != null)
+        {
+            IModule[] newModules = new IModule[modules.length + 1];
+            System.arraycopy(modules, 0, newModules, 0, modules.length);
+            newModules[modules.length] = m;
+            modules = newModules;
+        }
+        else
+        {
+            modules = new IModule[] { m };
+        }
+
+        return modules;
+    }
+
+    private static IModule[] removeModuleFromArray(IModule[] modules, IModule m)
+    {
+        if (modules == null)
+        {
+            return m_emptyModules;
+        }
+
+        int idx = -1;
+        for (int i = 0; i < modules.length; i++)
+        {
+            if (modules[i] == m)
+            {
+                idx = i;
+                break;
+            }
+        }
+
+        if (idx >= 0)
+        {
+            // If this is the module, then point to empty list.
+            if ((modules.length - 1) == 0)
+            {
+                modules = m_emptyModules;
+            }
+            // Otherwise, we need to do some array copying.
+            else
+            {
+                IModule[] newModules= new IModule[modules.length - 1];
+                System.arraycopy(modules, 0, newModules, 0, idx);
+                if (idx < newModules.length)
+                {
+                    System.arraycopy(
+                        modules, idx + 1, newModules, idx, newModules.length - idx);
+                }
+                modules = newModules;
+            }
+        }
+        return modules;
+    }
+
+    private static IModule[] shrinkModuleArray(IModule[] modules)
+    {
+        if (modules == null)
+        {
+            return m_emptyModules;
+        }
+
+        int count = 0;
+        for (int i = 0; i < modules.length; i++)
+        {
+            if (modules[i] == null)
+            {
+                count++;
+            }
+        }
+
+        if (count > 0)
+        {
+            IModule[] newModules = new IModule[modules.length - count];
+            count = 0;
+            for (int i = 0; i < modules.length; i++)
+            {
+                if (modules[i] != null)
+                {
+                    newModules[count++] = modules[i];
+                }
+            }
+            modules = newModules;
+        }
+
+        return modules;
+    }
+
+    private static class ResolverNode
+    {
+        public IModule m_module = null;
+        public R4Import m_import = null;
+        public IModule[] m_candidates = null;
+        public int m_idx = 0;
+        public boolean m_visited = false;
+        public ResolverNode(IModule module, R4Import imp, IModule[] candidates)
+        {
+            m_module = module;
+            m_import = imp;
+            m_candidates = candidates;
+            if (((Boolean) m_module.getAttribute(RESOLVED_ATTR, Boolean.FALSE)).booleanValue())
+            {
+                m_visited = true;
+            }
+        }
+    }
+}
\ No newline at end of file

Propchange: incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicy.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicy.java
------------------------------------------------------------------------------
    svn:executable = *

Copied: incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/searchpolicy/R4Wire.java (from r372830, incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/searchpolicy/WireImpl.java)
URL: http://svn.apache.org/viewcvs/incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/searchpolicy/R4Wire.java?p2=incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/searchpolicy/R4Wire.java&p1=incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/searchpolicy/WireImpl.java&r1=372830&r2=373842&rev=373842&view=diff
==============================================================================
--- incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/searchpolicy/WireImpl.java (original)
+++ incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/searchpolicy/R4Wire.java Tue Jan 31 07:34:32 2006
@@ -4,13 +4,13 @@
 
 import org.apache.felix.moduleloader.*;
 
-public class WireImpl implements IWire
+public class R4Wire
 {
     private IModule m_importer = null;
     private IModule m_exporter = null;
-    private IExport m_export= null;
+    private R4Export m_export= null;
 
-    public WireImpl(IModule importer, IModule exporter, IExport export)
+    public R4Wire(IModule importer, IModule exporter, R4Export export)
     {
         m_importer = importer;
         m_exporter = exporter;
@@ -27,7 +27,7 @@
         return m_exporter;
     }
 
-    public IExport getExport()
+    public R4Export getExport()
     {
         return m_export;
     }

Modified: incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/searchpolicy/ResolveException.java
URL: http://svn.apache.org/viewcvs/incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/searchpolicy/ResolveException.java?rev=373842&r1=373841&r2=373842&view=diff
==============================================================================
--- incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/searchpolicy/ResolveException.java (original)
+++ incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/searchpolicy/ResolveException.java Tue Jan 31 07:34:32 2006
@@ -17,7 +17,6 @@
 package org.apache.felix.framework.searchpolicy;
 
 import org.apache.felix.moduleloader.IModule;
-import org.apache.felix.moduleloader.IPackage;
 
 /**
  * <p>
@@ -31,13 +30,13 @@
 public class ResolveException extends Exception
 {
     private IModule m_module = null;
-    private IPackage m_pkg = null;
+    private R4Package m_pkg = null;
 
     /**
      * Constructs an exception with the specified message, module,
      * import identifier, import version number, and propagation flag.
     **/
-    public ResolveException(String msg, IModule module, IPackage pkg)
+    public ResolveException(String msg, IModule module, R4Package pkg)
     {
         super(msg);
         m_module = module;
@@ -53,7 +52,7 @@
         return m_module;
     }
 
-    public IPackage getPackage()
+    public R4Package getPackage()
     {
         return m_pkg;
     }

Modified: incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/searchpolicy/ResolveListener.java
URL: http://svn.apache.org/viewcvs/incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/searchpolicy/ResolveListener.java?rev=373842&r1=373841&r2=373842&view=diff
==============================================================================
--- incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/searchpolicy/ResolveListener.java (original)
+++ incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/searchpolicy/ResolveListener.java Tue Jan 31 07:34:32 2006
@@ -26,7 +26,7 @@
  * events that are generated by the <tt>R4SearchPolicy</tt>. Events
  * are fired when a module is resolved and when it is unresolved.
  * </p>
- * @see org.apache.felix.framework.searchpolicy.SearchPolicyImpl
+ * @see org.apache.felix.framework.searchpolicy.R4SearchPolicy
 **/
 public interface ResolveListener extends EventListener
 {

Modified: incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/searchpolicy/VersionRange.java
URL: http://svn.apache.org/viewcvs/incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/searchpolicy/VersionRange.java?rev=373842&r1=373841&r2=373842&view=diff
==============================================================================
--- incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/searchpolicy/VersionRange.java (original)
+++ incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/searchpolicy/VersionRange.java Tue Jan 31 07:34:32 2006
@@ -37,4 +37,26 @@
     {
         return m_isHighInclusive;
     }
+
+    public boolean isInRange(Version version)
+    {
+        // We might not have an upper end to the range.
+        if (m_high == null)
+        {
+            return (version.compareTo(m_low) >= 0);
+        }
+        else if (isLowInclusive() && isHighInclusive())
+        {
+            return (version.compareTo(m_low) >= 0) && (version.compareTo(m_high) <= 0);
+        }
+        else if (isHighInclusive())
+        {
+            return (version.compareTo(m_low) > 0) && (version.compareTo(m_high) <= 0);
+        }
+        else if (isLowInclusive())
+        {
+            return (version.compareTo(m_low) >= 0) && (version.compareTo(m_high) < 0);
+        }
+        return (version.compareTo(m_low) > 0) && (version.compareTo(m_high) < 0);
+    }
 }

Modified: incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/util/Util.java
URL: http://svn.apache.org/viewcvs/incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/util/Util.java?rev=373842&r1=373841&r2=373842&view=diff
==============================================================================
--- incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/util/Util.java (original)
+++ incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/util/Util.java Tue Jan 31 07:34:32 2006
@@ -21,7 +21,7 @@
 import java.util.List;
 
 import org.apache.felix.framework.Logger;
-import org.apache.felix.framework.searchpolicy.LibraryHeader;
+import org.apache.felix.framework.searchpolicy.R4LibraryHeader;
 
 public class Util
 {
@@ -100,7 +100,7 @@
      * @return an array of <tt>LibraryInfo</tt> objects for the
      *         passed in strings.
     **/
-    public static LibraryHeader[] parseLibraryStrings(Logger logger, String[] libStrs)
+    public static R4LibraryHeader[] parseLibraryStrings(Logger logger, String[] libStrs)
         throws IllegalArgumentException
     {
         if (libStrs == null)
@@ -112,7 +112,7 @@
 
         for (int i = 0; i < libStrs.length; i++)
         {
-            LibraryHeader[] libs = LibraryHeader.parse(logger, libStrs[i]);
+            R4LibraryHeader[] libs = R4LibraryHeader.parse(logger, libStrs[i]);
             for (int libIdx = 0;
                 (libs != null) && (libIdx < libs.length);
                 libIdx++)
@@ -126,7 +126,7 @@
             return null;
         }
 
-        return (LibraryHeader[]) libList.toArray(new LibraryHeader[libList.size()]);
+        return (R4LibraryHeader[]) libList.toArray(new R4LibraryHeader[libList.size()]);
     }
 
     private static final byte encTab[] = { 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,

Modified: incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/moduleloader/ModuleFactoryImpl.java
URL: http://svn.apache.org/viewcvs/incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/moduleloader/ModuleFactoryImpl.java?rev=373842&r1=373841&r2=373842&view=diff
==============================================================================
--- incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/moduleloader/ModuleFactoryImpl.java (original)
+++ incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/moduleloader/ModuleFactoryImpl.java Tue Jan 31 07:34:32 2006
@@ -213,33 +213,6 @@
 
     /**
      * <p>
-     * Fires an event indicating that the specified module was reset.
-     * </p>
-     * @param module the module that was reset.
-    **/
-    protected void fireModuleReset(IModule module)
-    {
-        // Event holder.
-        ModuleEvent event = null;
-
-        // Get a copy of the listener array, which is guaranteed
-        // to not be null.
-        ModuleListener[] listeners = m_listeners;
-
-        // Loop through listeners and fire events.
-        for (int i = 0; i < listeners.length; i++)
-        {
-            // Lazily create event.
-            if (event == null)
-            {
-                event = new ModuleEvent(this, module);
-            }
-            listeners[i].moduleReset(event);
-        }
-    }
-
-    /**
-     * <p>
      * Fires an event indicating that the specified module was removed
      * from the <tt>ModuleManager</tt>.
      * </p>

Modified: incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/moduleloader/ModuleListener.java
URL: http://svn.apache.org/viewcvs/incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/moduleloader/ModuleListener.java?rev=373842&r1=373841&r2=373842&view=diff
==============================================================================
--- incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/moduleloader/ModuleListener.java (original)
+++ incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/moduleloader/ModuleListener.java Tue Jan 31 07:34:32 2006
@@ -40,15 +40,6 @@
 
     /**
      * <p>
-     * This method is called after a module has been reset by the
-     * <tt>ModuleManager</tt>.
-     * </p>
-     * @param event the event object containing the event details.
-    **/
-    public void moduleReset(ModuleEvent event);
-
-    /**
-     * <p>
      * This method is called after a module is remove from the
      * <tt>ModuleManager</tt>.
      * </p>



Mime
View raw message