Return-Path: X-Original-To: apmail-felix-commits-archive@www.apache.org Delivered-To: apmail-felix-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id DF28211AC2 for ; Thu, 24 Apr 2014 19:24:11 +0000 (UTC) Received: (qmail 87003 invoked by uid 500); 24 Apr 2014 19:24:11 -0000 Delivered-To: apmail-felix-commits-archive@felix.apache.org Received: (qmail 86966 invoked by uid 500); 24 Apr 2014 19:24:11 -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 86958 invoked by uid 99); 24 Apr 2014 19:24:10 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 24 Apr 2014 19:24:10 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.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; Thu, 24 Apr 2014 19:24:09 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 0927D2388868; Thu, 24 Apr 2014 19:23:49 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1589839 - in /felix/trunk/resolver/src/main/java/org/apache/felix/resolver: Candidates.java ResolverImpl.java Date: Thu, 24 Apr 2014 19:23:48 -0000 To: commits@felix.apache.org From: rickhall@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20140424192349.0927D2388868@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: rickhall Date: Thu Apr 24 19:23:48 2014 New Revision: 1589839 URL: http://svn.apache.org/r1589839 Log: Apply patch FELIX-4493 to add support for "on demand" resource resolving. Modified: felix/trunk/resolver/src/main/java/org/apache/felix/resolver/Candidates.java felix/trunk/resolver/src/main/java/org/apache/felix/resolver/ResolverImpl.java Modified: felix/trunk/resolver/src/main/java/org/apache/felix/resolver/Candidates.java URL: http://svn.apache.org/viewvc/felix/trunk/resolver/src/main/java/org/apache/felix/resolver/Candidates.java?rev=1589839&r1=1589838&r2=1589839&view=diff ============================================================================== --- felix/trunk/resolver/src/main/java/org/apache/felix/resolver/Candidates.java (original) +++ felix/trunk/resolver/src/main/java/org/apache/felix/resolver/Candidates.java Thu Apr 24 19:23:48 2014 @@ -19,6 +19,7 @@ package org.apache.felix.resolver; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -44,7 +45,6 @@ class Candidates { public static final int MANDATORY = 0; public static final int OPTIONAL = 1; - public static final int ON_DEMAND = 2; private final Set m_mandatoryResources; // Maps a capability to requirements that match it. @@ -60,6 +60,8 @@ class Candidates // Flag to signal if fragments are present in the candidate map. private boolean m_fragmentsPresent = false; + private final Map m_validOnDemandResources; + /** * Private copy constructor used by the copy() method. * @param dependentMap the capability dependency map. @@ -72,7 +74,8 @@ class Candidates Map> dependentMap, Map> candidateMap, Map wrappedHosts, Map populateResultCache, - boolean fragmentsPresent) + boolean fragmentsPresent, + Map onDemandResources) { m_mandatoryResources = mandatoryResources; m_dependentMap = dependentMap; @@ -80,18 +83,20 @@ class Candidates m_allWrappedHosts = wrappedHosts; m_populateResultCache = populateResultCache; m_fragmentsPresent = fragmentsPresent; + m_validOnDemandResources = onDemandResources; } /** * Constructs an empty Candidates object. **/ - public Candidates() + public Candidates(Map validOnDemandResources) { m_mandatoryResources = new HashSet(); m_dependentMap = new HashMap>(); m_candidateMap = new HashMap>(); m_allWrappedHosts = new HashMap(); m_populateResultCache = new HashMap(); + m_validOnDemandResources = validOnDemandResources; } /** @@ -137,28 +142,22 @@ class Candidates return; } - // Always attempt to populate mandatory or optional revisions. - // However, for on-demand fragments only populate if their host - // is already populated. - if ((resolution != ON_DEMAND) - || (isFragment && populateFragmentOndemand(rc, resource))) + + if (resolution == MANDATORY) + { + m_mandatoryResources.add(resource); + } + try { + // Try to populate candidates for the optional revision. + populateResource(rc, resource); + } + catch (ResolutionException ex) + { + // Only throw an exception if resolution is mandatory. if (resolution == MANDATORY) { - m_mandatoryResources.add(resource); - } - try - { - // Try to populate candidates for the optional revision. - populateResource(rc, resource); - } - catch (ResolutionException ex) - { - // Only throw an exception if resolution is mandatory. - if (resolution == MANDATORY) - { - throw ex; - } + throw ex; } } } @@ -304,68 +303,28 @@ class Candidates { // Record that the revision was successfully populated. m_populateResultCache.put(resource, Boolean.TRUE); - // Merge local candidate map into global candidate map. if (localCandidateMap.size() > 0) { add(localCandidateMap); } - } - } - - private boolean populateFragmentOndemand(ResolveContext rc, Resource resource) - throws ResolutionException - { - // Create a modifiable list of the revision's requirements. - List remainingReqs = - new ArrayList(resource.getRequirements(null)); - // Find the host requirement. - Requirement hostReq = null; - for (Iterator it = remainingReqs.iterator(); - it.hasNext(); ) - { - Requirement r = it.next(); - if (r.getNamespace().equals(HostNamespace.HOST_NAMESPACE)) - { - hostReq = r; - it.remove(); - break; + if ((rc instanceof FelixResolveContext) && !Util.isFragment(resource)) { + Collection ondemandFragments = ((FelixResolveContext) rc).getOndemandResources(resource); + for (Resource fragment : ondemandFragments) { + Boolean valid = m_validOnDemandResources.get(fragment); + if (valid == null) { + // Mark this resource as a valid on demand resource + m_validOnDemandResources.put(fragment, Boolean.TRUE); + valid = Boolean.TRUE; + } + if (valid) { + // This resource is a valid on demand resource; + // populate it now, consider it optional + populate(rc, fragment, OPTIONAL); + } + } } } - // Get candidates hosts and keep any that have been populated. - List hosts = rc.findProviders(hostReq); - for (Iterator it = hosts.iterator(); it.hasNext(); ) - { - Capability host = it.next(); - if (!isPopulated(host.getResource())) - { - it.remove(); - } - } - // If there aren't any populated hosts, then we can just - // return since this fragment isn't needed. - if (hosts.isEmpty()) - { - return false; - } - - // If there are populated host candidates, then prepopulate - // the result cache with the work we've done so far. - // Record cycle count, but start at -1 since it will - // be incremented again in populate(). - Integer cycleCount = new Integer(-1); - // Create a local map for populating candidates first, just in case - // the revision is not resolvable. - Map> localCandidateMap = - new HashMap>(); - // Add the discovered host candidates to the local candidate map. - localCandidateMap.put(hostReq, hosts); - // Add these value to the result cache so we know we are - // in the middle of populating candidates for the current - // revision. - m_populateResultCache.put(resource, - new Object[] { cycleCount, localCandidateMap, remainingReqs }); - return true; } public void populateDynamic( @@ -1004,7 +963,7 @@ class Candidates return new Candidates( m_mandatoryResources, dependentMap, candidateMap, - m_allWrappedHosts, m_populateResultCache, m_fragmentsPresent); + m_allWrappedHosts, m_populateResultCache, m_fragmentsPresent, m_validOnDemandResources); } public void dump(ResolveContext rc) Modified: felix/trunk/resolver/src/main/java/org/apache/felix/resolver/ResolverImpl.java URL: http://svn.apache.org/viewvc/felix/trunk/resolver/src/main/java/org/apache/felix/resolver/ResolverImpl.java?rev=1589839&r1=1589838&r2=1589839&view=diff ============================================================================== --- felix/trunk/resolver/src/main/java/org/apache/felix/resolver/ResolverImpl.java (original) +++ felix/trunk/resolver/src/main/java/org/apache/felix/resolver/ResolverImpl.java Thu Apr 24 19:23:48 2014 @@ -122,10 +122,9 @@ public class ResolverImpl implements Res // Make copies of arguments in case we want to modify them. Collection mandatoryResources = new ArrayList(rc.getMandatoryResources()); Collection optionalResources = new ArrayList(rc.getOptionalResources()); -// TODO: RFC-112 - Need impl-specific type. -// Collection ondemandFragments = (rc instanceof ResolveContextImpl) -// ? ((ResolveContextImpl) rc).getOndemandResources() : Collections.EMPTY_LIST; - Collection ondemandFragments = Collections.EMPTY_LIST; + // keeps track of valid on demand fragments that we have seen. + // a null value or TRUE indicate it is valid + Map validOnDemandResources = new HashMap(0); boolean retry; do @@ -134,7 +133,7 @@ public class ResolverImpl implements Res try { // Create object to hold all candidates. - Candidates allCandidates = new Candidates(); + Candidates allCandidates = new Candidates(validOnDemandResources); // Populate mandatory resources; since these are mandatory // resources, failure throws a resolve exception. @@ -163,17 +162,6 @@ public class ResolverImpl implements Res } } - // Populate ondemand fragments; since these are optional - // resources, failure does not throw a resolve exception. - for (Resource resource : ondemandFragments) - { - boolean isFragment = Util.isFragment(resource); - if (isFragment) - { - allCandidates.populate(rc, resource, Candidates.ON_DEMAND); - } - } - // Merge any fragments into hosts. allCandidates.prepare(rc); @@ -302,7 +290,16 @@ public class ResolverImpl implements Res { if (faultyResources != null) { Set resourceKeys = faultyResources.keySet(); - retry = (optionalResources.removeAll(resourceKeys) || ondemandFragments.removeAll(resourceKeys)); + retry = (optionalResources.removeAll(resourceKeys)); + for (Resource faultyResource : resourceKeys) { + Boolean valid = validOnDemandResources.get(faultyResource); + if (valid != null && valid.booleanValue()) { + // This was an ondemand resource. + // Invalidate it and try again. + validOnDemandResources.put(faultyResource, Boolean.FALSE); + retry = true; + } + } // log all the resolution exceptions for the uses constraint violations for (Map.Entry usesError : faultyResources.entrySet()) { m_logger.logUsesConstraintViolation(usesError.getKey(), usesError.getValue()); @@ -379,8 +376,6 @@ public class ResolverImpl implements Res * @param host the hosting resource * @param dynamicReq the dynamic requirement * @param matches a list of matching capabilities - * @param ondemandFragments collection of on demand fragments that will - * attach to any host that is a candidate * @return The new resources and wires required to satisfy the specified * dynamic requirement. The returned map is the property of the caller and * can be modified by the caller. @@ -388,7 +383,7 @@ public class ResolverImpl implements Res */ public Map> resolve( ResolveContext rc, Resource host, Requirement dynamicReq, - List matches, Collection ondemandFragments) + List matches) throws ResolutionException { ResolveSession session = new ResolveSession(rc); @@ -413,15 +408,11 @@ public class ResolverImpl implements Res } } - // Make copy of args in case we want to modify them. - ondemandFragments = new ArrayList(ondemandFragments); - // Create all candidates pre-populated with the single candidate set - // for the resolving dynamic import of the host. - Candidates allCandidates = new Candidates(); - allCandidates.populateDynamic(rc, host, dynamicReq, matches); + Map resourcePkgMap = new HashMap(); + Map onDemandResources = new HashMap(); boolean retry; do @@ -430,15 +421,10 @@ public class ResolverImpl implements Res try { - // Try to populate optional fragments. - for (Resource r : ondemandFragments) - { - if (Util.isFragment(r)) - { - allCandidates.populate(rc, r, Candidates.ON_DEMAND); - } - } - + // Create all candidates pre-populated with the single candidate set + // for the resolving dynamic import of the host. + Candidates allCandidates = new Candidates(onDemandResources); + allCandidates.populateDynamic(rc, host, dynamicReq, matches); // Merge any fragments into hosts. allCandidates.prepare(rc); @@ -508,15 +494,13 @@ public class ResolverImpl implements Res ((WrappedRequirement) faultyReq) .getDeclaredRequirement().getResource(); } - // Try to ignore the faulty resource if it is not mandatory. - if (ondemandFragments.remove(faultyResource)) - { - retry = true; - } - else - { + Boolean valid = onDemandResources.get(faultyResource); + if (valid != null && valid.booleanValue()) { + onDemandResources.put(faultyResource, Boolean.FALSE); + retry = true; + } else { throw rethrow; - } + } } // If there is no exception to rethrow, then this was a clean // resolve, so populate the wire map.