Return-Path: Delivered-To: apmail-felix-commits-archive@www.apache.org Received: (qmail 87068 invoked from network); 27 Jan 2010 20:54:49 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 27 Jan 2010 20:54:49 -0000 Received: (qmail 67392 invoked by uid 500); 27 Jan 2010 20:52:35 -0000 Delivered-To: apmail-felix-commits-archive@felix.apache.org Received: (qmail 67376 invoked by uid 500); 27 Jan 2010 20:52:34 -0000 Mailing-List: contact commits-help@felix.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@felix.apache.org Delivered-To: mailing list commits@felix.apache.org Received: (qmail 67365 invoked by uid 99); 27 Jan 2010 20:52:33 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 27 Jan 2010 20:52:33 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 27 Jan 2010 20:52:29 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 3A81A23888EC; Wed, 27 Jan 2010 20:52:07 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r903824 - in /felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework: Felix.java FelixResolverState.java ModuleImpl.java resolver/Resolver.java resolver/ResolverImpl.java Date: Wed, 27 Jan 2010 20:52:07 -0000 To: commits@felix.apache.org From: rickhall@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20100127205207.3A81A23888EC@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: rickhall Date: Wed Jan 27 20:52:06 2010 New Revision: 903824 URL: http://svn.apache.org/viewvc?rev=903824&view=rev Log: Add initial support for dynamic imports. Modified: felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/Felix.java felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/FelixResolverState.java felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/ModuleImpl.java felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/resolver/Resolver.java felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java Modified: felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/Felix.java URL: http://svn.apache.org/viewvc/felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/Felix.java?rev=903824&r1=903823&r2=903824&view=diff ============================================================================== --- felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/Felix.java (original) +++ felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/Felix.java Wed Jan 27 20:52:06 2010 @@ -3906,25 +3906,23 @@ } } - public Wire resolveDynamicImport(Module importer, String pkgName) throws ResolveException + public Wire resolve(Module module, String pkgName) throws ResolveException { Wire candidateWire = null; -// TODO: FELIX3 - Fix dynamic imports! -/* - // We cannot dynamically import if the module is already resolved or - // if it is not allowed, so check that first. Note: We check if the + // We cannot dynamically import if the module is not already resolved + // or if it is not allowed, so check that first. Note: We check if the // dynamic import is allowed without holding any locks, but this is // okay since the resolver will double check later after we have // acquired the global lock below. - if (importer.isResolved() - && (Resolver.findAllowedDynamicImport(importer, pkgName) != null)) + if (module.isResolved() + && (ResolverImpl.findAllowedDynamicImport(m_resolverState, module, pkgName) != null)) { // Acquire global lock. boolean locked = acquireGlobalLock(); if (!locked) { throw new ResolveException( - "Unable to acquire global lock for resolve.", importer, null); + "Unable to acquire global lock for resolve.", module, null); } try @@ -3933,42 +3931,34 @@ // dynamically importing the package, which can happen if two // threads are racing to do so. If we have an existing wire, // then just return it instead. - IWire[] wires = importer.getWires(); - for (int i = 0; (wires != null) && (i < wires.length); i++) + List wires = module.getWires(); + for (int i = 0; (wires != null) && (i < wires.size()); i++) { - if (wires[i].hasPackage(pkgName)) + if (wires.get(i).hasPackage(pkgName)) { - return wires[i]; + return wires.get(i); } } - Object[] result = m_resolver.resolveDynamicImport(m_resolverState, importer, pkgName); - if (result != null) + Map> wireMap = + m_resolver.resolve(m_resolverState, module, pkgName); + + if ((wireMap != null) && wireMap.containsKey(module)) { - candidateWire = (IWire) result[0]; - Map resolvedModuleWireMap = (Map) result[1]; + List dynamicWires = wireMap.remove(module); + candidateWire = dynamicWires.get(0); // Mark all modules as resolved. - markResolvedModules(resolvedModuleWireMap); + markResolvedModules(wireMap); // Dynamically add new wire to importing module. if (candidateWire != null) { - wires = importer.getWires(); - IWire[] newWires = null; - if (wires == null) - { - newWires = new IWire[1]; - } - else - { - newWires = new IWire[wires.length + 1]; - System.arraycopy(wires, 0, newWires, 0, wires.length); - } - - newWires[newWires.length - 1] = candidateWire; - ((ModuleImpl) importer).setWires(newWires); -m_logger.log(Logger.LOG_DEBUG, "DYNAMIC WIRE: " + newWires[newWires.length - 1]); + wires = new ArrayList(wires.size() + 1); + wires.addAll(module.getWires()); + wires.add(candidateWire); + ((ModuleImpl) module).setWires(wires); +m_logger.log(Logger.LOG_DEBUG, "DYNAMIC WIRE: " + wires.get(wires.size() - 1)); } } } @@ -3978,7 +3968,7 @@ releaseGlobalLock(); } } -*/ + return candidateWire; } Modified: felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/FelixResolverState.java URL: http://svn.apache.org/viewvc/felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/FelixResolverState.java?rev=903824&r1=903823&r2=903824&view=diff ============================================================================== --- felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/FelixResolverState.java (original) +++ felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/FelixResolverState.java Wed Jan 27 20:52:06 2010 @@ -770,7 +770,8 @@ } } - /*public */synchronized List getModules() +// TODO: FELIX3 - Try to eliminate this. + public synchronized List getModules() { return m_modules; } Modified: felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/ModuleImpl.java URL: http://svn.apache.org/viewvc/felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/ModuleImpl.java?rev=903824&r1=903823&r2=903824&view=diff ============================================================================== --- felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/ModuleImpl.java (original) +++ felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/ModuleImpl.java Wed Jan 27 20:52:06 2010 @@ -935,7 +935,7 @@ Wire wire = null; try { - wire = m_resolver.resolveDynamicImport(this, pkgName); + wire = m_resolver.resolve(this, pkgName); } catch (ResolveException ex) { @@ -1342,7 +1342,7 @@ Wire wire = null; try { - wire = m_resolver.resolveDynamicImport(this, pkgName); + wire = m_resolver.resolve(this, pkgName); } catch (ResolveException ex) { Modified: felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/resolver/Resolver.java URL: http://svn.apache.org/viewvc/felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/resolver/Resolver.java?rev=903824&r1=903823&r2=903824&view=diff ============================================================================== --- felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/resolver/Resolver.java (original) +++ felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/resolver/Resolver.java Wed Jan 27 20:52:06 2010 @@ -29,6 +29,7 @@ public interface Resolver { Map> resolve(ResolverState state, Module module); + Map> resolve(ResolverState state, Module module, String pkgName); public static interface ResolverState { Modified: felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java URL: http://svn.apache.org/viewvc/felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java?rev=903824&r1=903823&r2=903824&view=diff ============================================================================== --- felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java (original) +++ felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java Wed Jan 27 20:52:06 2010 @@ -28,12 +28,16 @@ import java.util.Set; import java.util.StringTokenizer; import java.util.TreeSet; +import org.apache.felix.framework.FelixResolverState; import org.apache.felix.framework.Logger; +import org.apache.felix.framework.capabilityset.Attribute; import org.apache.felix.framework.capabilityset.Capability; import org.apache.felix.framework.capabilityset.CapabilitySet; +import org.apache.felix.framework.capabilityset.Directive; import org.apache.felix.framework.capabilityset.Module; import org.apache.felix.framework.capabilityset.Requirement; import org.apache.felix.framework.capabilityset.Wire; +import org.apache.felix.framework.util.manifestparser.RequirementImpl; // 1. Treat hard pkg constraints separately from implied package constraints // 2. Map pkg constraints to a set of capabilities, not a single capability. @@ -81,6 +85,8 @@ if (!module.isResolved()) { + m_candidatePermutations.clear(); + System.out.println("+++ RESOLVING " + module); Map> candidateMap = new HashMap>(); @@ -100,6 +106,7 @@ try { findConsistentCandidates( + false, module, new ArrayList(), candidateMap, @@ -132,27 +139,158 @@ return wireMap; } + public Map> resolve(ResolverState state, Module module, String pkgName) + { + Capability candidate = null; + + // We can only create a dynamic import if the following + // conditions are met: + // 1. The specified module is resolved. + // 2. The package in question is not already imported. + // 3. The package in question is not accessible via require-bundle. + // 4. The package in question is not exported by the bundle. + // 5. The package in question matches a dynamic import of the bundle. + // The following call checks all of these conditions and returns + // a matching dynamic requirement if possible. + Requirement dynReq = findAllowedDynamicImport(state, module, pkgName); + if (dynReq != null) + { + m_candidatePermutations.clear(); + + Map modulePkgMap = new HashMap(); + +System.out.println("+++ DYNAMICALLY RESOLVING " + module + " - " + dynReq); + Map> candidateMap = + new HashMap>(); + + populateDynamicCandidates(state, module, dynReq, candidateMap, new HashSet()); + m_candidatePermutations.add(candidateMap); + ResolveException rethrow = null; + + do + { + rethrow = null; + + candidateMap = m_candidatePermutations.remove(0); +dumpCandidateMap(state, candidateMap); + + try + { + findConsistentCandidates( + true, + module, + new ArrayList(), + candidateMap, + modulePkgMap, + new HashMap()); + } + catch (ResolveException ex) + { + rethrow = ex; + System.out.println("RE: " + ex); + } + } + while ((rethrow != null) && (m_candidatePermutations.size() > 0)); + + if (rethrow != null) + { + throw rethrow; + } +//dumpModulePkgMap(modulePkgMap); + Map> wireMap = + populateDynamicWireMap( + module, pkgName, modulePkgMap, new HashMap>()); + + return wireMap; + } + + return null; + } + + // TODO: FELIX3 - It would be nice to make this private. + public static Requirement findAllowedDynamicImport( + ResolverState state, Module module, String pkgName) + { + // Unresolved modules cannot dynamically import, nor can the default + // package be dynamically imported. + if (!module.isResolved() || pkgName.length() == 0) + { + return null; + } + + // If any of the module exports this package, then we cannot + // attempt to dynamically import it. + List caps = module.getCapabilities(); + for (int i = 0; (caps != null) && (i < caps.size()); i++) + { + if (caps.get(i).getNamespace().equals(Capability.PACKAGE_NAMESPACE) + && caps.get(i).getAttribute(Capability.PACKAGE_ATTR).getValue().equals(pkgName)) + { + return null; + } + } + // If any of our wires have this package, then we cannot + // attempt to dynamically import it. + List wires = module.getWires(); + for (int i = 0; (wires != null) && (i < wires.size()); i++) + { + if (wires.get(i).hasPackage(pkgName)) + { + return null; + } + } + + // Loop through the importer's dynamic requirements to determine if + // there is a matching one for the package from which we want to + // load a class. + List dirs = new ArrayList(0); + List attrs = new ArrayList(1); + attrs.add(new Attribute(Capability.PACKAGE_ATTR, pkgName, false)); + Requirement req = new RequirementImpl(Capability.PACKAGE_NAMESPACE, dirs, attrs); + Set candidates = state.getCandidates(module, req); + List dynamics = module.getDynamicRequirements(); + for (int dynIdx = 0; + (candidates.size() > 0) && (dynIdx < dynamics.size()); + dynIdx++) + { + for (Capability cap : candidates) + { + if (CapabilitySet.matches(cap, dynamics.get(dynIdx).getFilter())) + { + return dynamics.get(dynIdx); + } + } + } + + return null; + } + private static void dumpCandidateMap( ResolverState state, Map> candidateMap) { -/* - System.out.println("=== CANDIDATE MAP ==="); - for (Module module : ((ResolverStateImpl) state).getModules()) + System.out.println("=== BEGIN CANDIDATE MAP ==="); + for (Module module : ((FelixResolverState) state).getModules()) { - if (!module.isResolved()) + System.out.println(" " + module + + " (" + (module.isResolved() ? "RESOLVED)" : "UNRESOLVED)")); + for (Requirement req : module.getRequirements()) { - System.out.println(" " + module); - for (Requirement req : module.getRequirements()) + Set candidates = candidateMap.get(req); + if ((candidates != null) && (candidates.size() > 0)) { - Set candidates = candidateMap.get(req); - if ((candidates != null) && (candidates.size() > 0)) - { - System.out.println(" " + req + ": " + candidates); - } + System.out.println(" " + req + ": " + candidates); + } + } + for (Requirement req : module.getDynamicRequirements()) + { + Set candidates = candidateMap.get(req); + if ((candidates != null) && (candidates.size() > 0)) + { + System.out.println(" " + req + ": " + candidates); } } } -*/ + System.out.println("=== END CANDIDATE MAP ==="); } private static void dumpModulePkgMap(Map modulePkgMap) @@ -251,8 +389,61 @@ } } + private static void populateDynamicCandidates( + ResolverState state, Module module, Requirement dynReq, + Map> candidateMap, Set cycles) + { + if (m_isInvokeCount) + { + String methodName = new Exception().fillInStackTrace().getStackTrace()[0].getMethodName(); + Long count = m_invokeCounts.get(methodName); + count = (count == null) ? new Long(1) : new Long(count.longValue() + 1); + m_invokeCounts.put(methodName, count); + } + + // Detect cycles. + if (cycles.contains(module)) + { + return; + } + cycles.add(module); + + // Find candidates for all requirements for the target module. + Set candidates = state.getCandidates(module, dynReq); + for (Iterator itCandCap = candidates.iterator(); itCandCap.hasNext(); ) + { + Capability candCap = itCandCap.next(); + if (!candCap.getModule().isResolved()) + { + try + { + populateCandidates(state, candCap.getModule(), candidateMap, cycles); + } + catch (ResolveException ex) + { +System.out.println("RE: Candidate not resolveable: " + ex); + itCandCap.remove(); + } + } + } + + // Put candidates for all requirements into the global candidate map. + if (candidates.size() > 0) + { + candidateMap.put(dynReq, candidates); + + // Add existing wires as candidates. + for (Wire wire : module.getWires()) + { + Set cs = new TreeSet(); + cs.add(wire.getCapability()); + candidateMap.put(wire.getRequirement(), cs); + } + } + } + private void findConsistentCandidates( - Module module, List incomingReqs, Map> candidateMap, + boolean dynamic, Module module, List incomingReqs, Map> candidateMap, Map modulePkgMap, Map cycleMap) { if (m_isInvokeCount) @@ -273,7 +464,7 @@ //System.out.println("+++ RESOLVING " + module); calculateExportedPackages(module, incomingReqs, modulePkgMap); - if (module.isResolved()) + if (!dynamic && module.isResolved()) { // Packages pkgs = modulePkgMap.get(module); // calculateResolvedPackages(module, incomingReqs, pkgs); @@ -281,6 +472,7 @@ { // Try to resolve the candidate. findConsistentCandidates( + false, wire.getCapability().getModule(), incomingReqs, candidateMap, @@ -303,7 +495,8 @@ } else { - List reqs = module.getRequirements(); + List reqs = new ArrayList(module.getRequirements()); + reqs.addAll(module.getDynamicRequirements()); for (Requirement req : reqs) { // Get the candidates for the current requirement. @@ -325,6 +518,7 @@ { // Try to resolve the candidate. findConsistentCandidates( + false, candCap.getModule(), outgoingReqs, candidateMap, @@ -679,7 +873,7 @@ System.out.println("+++ MERGING CB " + candBlame + " SB " + candSourceBlame); // usedCaps.add(new Blame(candBlame.m_reqs, sourceBlame.m_cap)); usedCaps.add(candSourceBlame); - return; +// return; } else if (!current.isResolved()) { @@ -697,7 +891,7 @@ else if ((currentImportedBlame != null) && !isCompatible(currentImportedBlame.m_cap, candSourceBlame.m_cap, modulePkgMap)) { - //System.out.println("+++ CIB " + currentImportedBlame + " SB " + sourceBlame); +//System.out.println("+++ CIB " + currentImportedBlame + " SB " + sourceBlame); // Try to remove the previously selected candidate associated // with the requirement blamed for adding the constraint. This // Permutate the candidate map. @@ -712,7 +906,7 @@ Iterator it = candidates.iterator(); it.next(); it.remove(); - // TODO: PROTO3 RESOLVER - We could check before doing the candidate map copy. +// TODO: PROTO3 RESOLVER - We could check before doing the candidate map copy. if (candidates.size() > 0) { m_candidatePermutations.add(copy); @@ -729,6 +923,9 @@ + candSourceBlame, null, null); } } + + verifyAndMergeUses(current, currentPkgs, candSourceBlame, + modulePkgMap, candidateMap, cycleMap); } } } @@ -767,43 +964,6 @@ return sources; } - private static void calculateResolvedPackages( - Module module, List incomingReqs, Packages pkgs) - { - for (Wire wire : module.getWires()) - { - if (wire.getCapability().getNamespace().equals(Capability.PACKAGE_NAMESPACE)) - { - pkgs.m_importedPkgs.put( - (String) wire.getCapability().getAttribute(Capability.PACKAGE_ATTR).getValue(), - new Blame(incomingReqs, wire.getCapability())); - calculateResolvedUses(wire.getCapability(), pkgs.m_usedPkgs); - } - else if (wire.getCapability().getNamespace().equals(Capability.MODULE_NAMESPACE)) - { - for (Capability cap : wire.getCapability().getModule().getCapabilities()) - { - if (cap.getNamespace().equals(Capability.PACKAGE_ATTR)) - { - String pkgName = (String) cap.getAttribute(Capability.PACKAGE_ATTR).getValue(); - List requiredBlames = pkgs.m_requiredPkgs.get(pkgName); - if (requiredBlames == null) - { - requiredBlames = new ArrayList(); - pkgs.m_requiredPkgs.put(pkgName, requiredBlames); - } - requiredBlames.add(new Blame(incomingReqs, cap)); - calculateResolvedUses(wire.getCapability(), pkgs.m_usedPkgs); - } - } - } - } - } - - private static void calculateResolvedUses(Capability cap, Map> usedPkgs) - { - } - private static Map> copyCandidateMap( Map> candidateMap) { @@ -911,6 +1071,49 @@ return wireMap; } + private static Map> populateDynamicWireMap( + Module module, String pkgName, Map modulePkgMap, + Map> wireMap) + { + if (m_isInvokeCount) + { + String methodName = new Exception().fillInStackTrace().getStackTrace()[0].getMethodName(); + Long count = m_invokeCounts.get(methodName); + count = (count == null) ? new Long(1) : new Long(count.longValue() + 1); + m_invokeCounts.put(methodName, count); + } + + wireMap.put(module, m_emptyWires); + + List packageWires = new ArrayList(); + + Packages pkgs = modulePkgMap.get(module); + for (Entry entry : pkgs.m_importedPkgs.entrySet()) + { + if (!entry.getValue().m_cap.getModule().isResolved()) + { + populateWireMap(entry.getValue().m_cap.getModule(), modulePkgMap, wireMap); + } + + // Ignore modules that import themselves. + if (!module.equals(entry.getValue().m_cap.getModule()) + && entry.getValue().m_cap.getAttribute( + Capability.PACKAGE_ATTR).getValue().equals(pkgName)) + { + packageWires.add( + new WireImpl( + module, + entry.getValue().m_reqs.get(0), + entry.getValue().m_cap.getModule(), + entry.getValue().m_cap)); + } + } + + wireMap.put(module, packageWires); + + return wireMap; + } + private static Capability getModuleCapability(Module module) { for (Capability cap : module.getCapabilities())