Author: davidb Date: Tue Dec 8 18:42:15 2015 New Revision: 1718669 URL: http://svn.apache.org/viewvc?rev=1718669&view=rev Log: FELIX-5112 ClassCastException when deploying an OBR Resource already present in the runtime
Cleaned up code Committed on behalf of @skahmann with many thanks. Contributed via https://github.com/apache/felix/pull/44 Modified: felix/trunk/bundlerepository/src/main/java/org/apache/felix/bundlerepository/impl/LazyLocalResourceImpl.java felix/trunk/bundlerepository/src/main/java/org/apache/felix/bundlerepository/impl/ResolverImpl.java Modified: felix/trunk/bundlerepository/src/main/java/org/apache/felix/bundlerepository/impl/LazyLocalResourceImpl.java URL: http://svn.apache.org/viewvc/felix/trunk/bundlerepository/src/main/java/org/apache/felix/bundlerepository/impl/LazyLocalResourceImpl.java?rev=1718669&r1=1718668&r2=1718669&view=diff ============================================================================== --- felix/trunk/bundlerepository/src/main/java/org/apache/felix/bundlerepository/impl/LazyLocalResourceImpl.java (original) +++ felix/trunk/bundlerepository/src/main/java/org/apache/felix/bundlerepository/impl/LazyLocalResourceImpl.java Tue Dec 8 18:42:15 2015 @@ -18,23 +18,16 @@ */ package org.apache.felix.bundlerepository.impl; -import java.util.Dictionary; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.StringTokenizer; - import org.apache.felix.bundlerepository.Capability; import org.apache.felix.bundlerepository.LocalResource; import org.apache.felix.bundlerepository.Requirement; import org.apache.felix.bundlerepository.Resource; import org.apache.felix.utils.log.Logger; import org.osgi.framework.Bundle; -import org.osgi.framework.Constants; import org.osgi.framework.InvalidSyntaxException; -import org.osgi.framework.ServiceReference; import org.osgi.framework.Version; -import org.osgi.framework.wiring.BundleRevision; + +import java.util.Map; public class LazyLocalResourceImpl implements LocalResource { Modified: felix/trunk/bundlerepository/src/main/java/org/apache/felix/bundlerepository/impl/ResolverImpl.java URL: http://svn.apache.org/viewvc/felix/trunk/bundlerepository/src/main/java/org/apache/felix/bundlerepository/impl/ResolverImpl.java?rev=1718669&r1=1718668&r2=1718669&view=diff ============================================================================== --- felix/trunk/bundlerepository/src/main/java/org/apache/felix/bundlerepository/impl/ResolverImpl.java (original) +++ felix/trunk/bundlerepository/src/main/java/org/apache/felix/bundlerepository/impl/ResolverImpl.java Tue Dec 8 18:42:15 2015 @@ -34,19 +34,18 @@ public class ResolverImpl implements Res private final BundleContext m_context; private final Logger m_logger; private final Repository[] m_repositories; - private final Set m_addedSet = new HashSet(); - private final Set m_addedRequirementSet = new HashSet(); - private final Set m_globalCapabilities = new HashSet(); - private final Set m_failedSet = new HashSet(); - private final Set m_resolveSet = new HashSet(); - private final Set m_requiredSet = new HashSet(); - private final Set m_optionalSet = new HashSet(); - private final Map m_reasonMap = new HashMap(); - private final Set m_unsatisfiedSet = new HashSet(); + private final Set<Resource> m_addedSet = new HashSet<Resource>(); + private final Set<Requirement> m_addedRequirementSet = new HashSet<Requirement>(); + private final Set<Capability> m_globalCapabilities = new HashSet<Capability>(); + private final Set<Resource> m_failedSet = new HashSet<Resource>(); + private final Set<Resource> m_resolveSet = new HashSet<Resource>(); + private final Set<Resource> m_requiredSet = new HashSet<Resource>(); + private final Set<Resource> m_optionalSet = new HashSet<Resource>(); + private final Map<Resource, List<Reason>> m_reasonMap = new HashMap<Resource, List<Reason>>(); + private final Set<Reason> m_unsatisfiedSet = new HashSet<Reason>(); private boolean m_resolved = false; private long m_resolveTimeStamp; private int m_resolutionFlags; - private int m_deployFlags; public ResolverImpl(BundleContext context, Repository[] repositories, Logger logger) { @@ -63,7 +62,7 @@ public class ResolverImpl implements Res public synchronized Resource[] getAddedResources() { - return (Resource[]) m_addedSet.toArray(new Resource[m_addedSet.size()]); + return m_addedSet.toArray(new Resource[m_addedSet.size()]); } public synchronized void add(Requirement requirement) @@ -74,7 +73,7 @@ public class ResolverImpl implements Res public synchronized Requirement[] getAddedRequirements() { - return (Requirement[]) m_addedRequirementSet.toArray(new Requirement[m_addedRequirementSet.size()]); + return m_addedRequirementSet.toArray(new Requirement[m_addedRequirementSet.size()]); } public void addGlobalCapability(Capability capability) @@ -84,14 +83,14 @@ public class ResolverImpl implements Res public Capability[] getGlobalCapabilities() { - return (Capability[]) m_globalCapabilities.toArray(new Capability[m_globalCapabilities.size()]); + return m_globalCapabilities.toArray(new Capability[m_globalCapabilities.size()]); } public synchronized Resource[] getRequiredResources() { if (m_resolved) { - return (Resource[]) m_requiredSet.toArray(new Resource[m_requiredSet.size()]); + return m_requiredSet.toArray(new Resource[m_requiredSet.size()]); } throw new IllegalStateException("The resources have not been resolved."); } @@ -100,7 +99,7 @@ public class ResolverImpl implements Res { if (m_resolved) { - return (Resource[]) m_optionalSet.toArray(new Resource[m_optionalSet.size()]); + return m_optionalSet.toArray(new Resource[m_optionalSet.size()]); } throw new IllegalStateException("The resources have not been resolved."); } @@ -109,8 +108,8 @@ public class ResolverImpl implements Res { if (m_resolved) { - List l = (List) m_reasonMap.get(resource); - return l != null ? (Reason[]) l.toArray(new Reason[l.size()]) : null; + List<Reason> l = m_reasonMap.get(resource); + return l != null ? l.toArray(new Reason[l.size()]) : null; } throw new IllegalStateException("The resources have not been resolved."); } @@ -119,7 +118,7 @@ public class ResolverImpl implements Res { if (m_resolved) { - return (Reason[]) m_unsatisfiedSet.toArray(new Reason[m_unsatisfiedSet.size()]); + return m_unsatisfiedSet.toArray(new Reason[m_unsatisfiedSet.size()]); } throw new IllegalStateException("The resources have not been resolved."); } @@ -202,14 +201,10 @@ public class ResolverImpl implements Res if (!m_addedRequirementSet.isEmpty() || !m_globalCapabilities.isEmpty()) { ResourceImpl fake = new ResourceImpl(); - for (Iterator iter = m_globalCapabilities.iterator(); iter.hasNext();) - { - Capability cap = (Capability) iter.next(); + for (Capability cap : m_globalCapabilities) { fake.addCapability(cap); } - for (Iterator iter = m_addedRequirementSet.iterator(); iter.hasNext();) - { - Requirement req = (Requirement) iter.next(); + for (Requirement req : m_addedRequirementSet) { fake.addRequire(req); } if (!resolve(fake, locals, remotes, false)) @@ -219,10 +214,8 @@ public class ResolverImpl implements Res } // Loop through each resource in added list and resolve. - for (Iterator iter = m_addedSet.iterator(); iter.hasNext(); ) - { - if (!resolve((Resource) iter.next(), locals, remotes, false)) - { + for (Resource aM_addedSet : m_addedSet) { + if (!resolve(aM_addedSet, locals, remotes, false)) { // If any resource does not resolve, then the // entire result will be false. result = false; @@ -270,88 +263,68 @@ public class ResolverImpl implements Res if (reqs != null) { Resource candidate; - for (int reqIdx = 0; reqIdx < reqs.length; reqIdx++) - { + for (Requirement req : reqs) { // Do not resolve optional requirements - if ((m_resolutionFlags & NO_OPTIONAL_RESOURCES) != 0 && reqs[reqIdx].isOptional()) - { + if ((m_resolutionFlags & NO_OPTIONAL_RESOURCES) != 0 && req.isOptional()) { continue; } - candidate = searchResources(reqs[reqIdx], m_addedSet); - if (candidate == null) - { - candidate = searchResources(reqs[reqIdx], m_requiredSet); - } - if (candidate == null) - { - candidate = searchResources(reqs[reqIdx], m_optionalSet); - } - if (candidate == null) - { - candidate = searchResources(reqs[reqIdx], m_resolveSet); - } - if (candidate == null) - { - List candidateCapabilities = searchResources(reqs[reqIdx], locals); - candidateCapabilities.addAll(searchResources(reqs[reqIdx], remotes)); + candidate = searchResources(req, m_addedSet); + if (candidate == null) { + candidate = searchResources(req, m_requiredSet); + } + if (candidate == null) { + candidate = searchResources(req, m_optionalSet); + } + if (candidate == null) { + candidate = searchResources(req, m_resolveSet); + } + if (candidate == null) { + List<ResourceCapability> candidateCapabilities = searchResources(req, locals); + candidateCapabilities.addAll(searchResources(req, remotes)); // Determine the best candidate available that // can resolve. - while ((candidate == null) && !candidateCapabilities.isEmpty()) - { + while ((candidate == null) && !candidateCapabilities.isEmpty()) { ResourceCapability bestCapability = getBestCandidate(candidateCapabilities); // Try to resolve the best resource. - if (resolve(bestCapability.getResource(), locals, remotes, optional || reqs[reqIdx].isOptional())) - { + if (resolve(bestCapability.getResource(), locals, remotes, optional || req.isOptional())) { candidate = bestCapability.getResource(); - } - else - { + } else { candidateCapabilities.remove(bestCapability); } } } - if ((candidate == null) && !reqs[reqIdx].isOptional()) - { + if ((candidate == null) && !req.isOptional()) { // The resolve failed. result = false; // Associated the current resource to the requirement // in the unsatisfied requirement set. - m_unsatisfiedSet.add(new ReasonImpl(resource, reqs[reqIdx])); - } - else if (candidate != null) - { + m_unsatisfiedSet.add(new ReasonImpl(resource, req)); + } else if (candidate != null) { // Try to resolve the candidate. - if (resolve(candidate, locals, remotes, optional || reqs[reqIdx].isOptional())) - { + if (resolve(candidate, locals, remotes, optional || req.isOptional())) { // The resolved succeeded; record the candidate // as either optional or required. - if (optional || reqs[reqIdx].isOptional()) - { + if (optional || req.isOptional()) { m_optionalSet.add(candidate); m_resolveSet.remove(candidate); - } - else - { + } else { m_requiredSet.add(candidate); m_optionalSet.remove(candidate); m_resolveSet.remove(candidate); } // Add the reason why the candidate was selected. - List reasons = (List) m_reasonMap.get(candidate); - if (reasons == null) - { - reasons = new ArrayList(); + List<Reason> reasons = m_reasonMap.get(candidate); + if (reasons == null) { + reasons = new ArrayList<Reason>(); m_reasonMap.put(candidate, reasons); } - reasons.add(new ReasonImpl(resource, reqs[reqIdx])); - } - else - { + reasons.add(new ReasonImpl(resource, req)); + } else { result = false; } } @@ -369,20 +342,16 @@ public class ResolverImpl implements Res return result; } - private Resource searchResources(Requirement req, Set resourceSet) + private Resource searchResources(Requirement req, Set<Resource> resourceSet) { - for (Iterator iter = resourceSet.iterator(); iter.hasNext(); ) - { + for (Resource aResourceSet : resourceSet) { checkInterrupt(); - Resource resource = (Resource) iter.next(); - Capability[] caps = resource.getCapabilities(); - for (int capIdx = 0; (caps != null) && (capIdx < caps.length); capIdx++) - { - if (req.isSatisfied(caps[capIdx])) - { + Capability[] caps = aResourceSet.getCapabilities(); + for (int capIdx = 0; (caps != null) && (capIdx < caps.length); capIdx++) { + if (req.isSatisfied(caps[capIdx])) { // The requirement is already satisfied an existing // resource, return the resource. - return resource; + return aResourceSet; } } } @@ -396,9 +365,9 @@ public class ResolverImpl implements Res * @param resources list of resources to look at * @return all resources meeting the given requirement */ - private List searchResources(Requirement req, Resource[] resources) + private List<ResourceCapability> searchResources(Requirement req, Resource[] resources) { - List matchingCapabilities = new ArrayList(); + List<ResourceCapability> matchingCapabilities = new ArrayList<ResourceCapability>(); for (int resIdx = 0; (resources != null) && (resIdx < resources.length); resIdx++) { @@ -428,65 +397,52 @@ public class ResolverImpl implements Res * @param caps * @return */ - private ResourceCapability getBestCandidate(List caps) + private ResourceCapability getBestCandidate(List<ResourceCapability> caps) { Version bestVersion = null; ResourceCapability best = null; boolean bestLocal = false; - for(int capIdx = 0; capIdx < caps.size(); capIdx++) - { - ResourceCapability current = (ResourceCapability) caps.get(capIdx); - boolean isCurrentLocal = current.getResource().isLocal(); + for (ResourceCapability cap : caps) { + boolean isCurrentLocal = cap.getResource().isLocal(); - if (best == null) - { - best = current; + if (best == null) { + best = cap; bestLocal = isCurrentLocal; - Object v = current.getCapability().getPropertiesAsMap().get(Resource.VERSION); - if ((v != null) && (v instanceof Version)) - { + Object v = cap.getCapability().getPropertiesAsMap().get(Resource.VERSION); + if ((v != null) && (v instanceof Version)) { bestVersion = (Version) v; } - } - else if ((m_resolutionFlags & DO_NOT_PREFER_LOCAL) != 0 || !bestLocal || isCurrentLocal) - { - Object v = current.getCapability().getPropertiesAsMap().get(Resource.VERSION); + } else if ((m_resolutionFlags & DO_NOT_PREFER_LOCAL) != 0 || !bestLocal || isCurrentLocal) { + Object v = cap.getCapability().getPropertiesAsMap().get(Resource.VERSION); // If there is no version, then select the resource // with the greatest number of capabilities. if ((v == null) && (bestVersion == null) - && (best.getResource().getCapabilities().length - < current.getResource().getCapabilities().length)) - { - best = current; + && (best.getResource().getCapabilities().length + < cap.getResource().getCapabilities().length)) { + best = cap; bestLocal = isCurrentLocal; bestVersion = null; - } - else if ((v != null) && (v instanceof Version)) - { + } else if ((v != null) && (v instanceof Version)) { // If there is no best version or if the current // resource's version is lower, then select it. - if ((bestVersion == null) || (bestVersion.compareTo((Version) v) < 0)) - { - best = current; + if ((bestVersion == null) || (bestVersion.compareTo((Version) v) < 0)) { + best = cap; bestLocal = isCurrentLocal; bestVersion = (Version) v; } // If the current resource version is equal to the // best - else if ((bestVersion != null) && (bestVersion.compareTo((Version) v) == 0)) - { + else if ((bestVersion.compareTo((Version) v) == 0)) { // If the symbolic name is the same, use the highest // bundle version. if ((best.getResource().getSymbolicName() != null) - && best.getResource().getSymbolicName().equals( - current.getResource().getSymbolicName())) - { + && best.getResource().getSymbolicName().equals( + cap.getResource().getSymbolicName())) { if (best.getResource().getVersion().compareTo( - current.getResource().getVersion()) < 0) - { - best = current; + cap.getResource().getVersion()) < 0) { + best = cap; bestLocal = isCurrentLocal; bestVersion = (Version) v; } @@ -494,9 +450,8 @@ public class ResolverImpl implements Res // Otherwise select the one with the greatest // number of capabilities. else if (best.getResource().getCapabilities().length - < current.getResource().getCapabilities().length) - { - best = current; + < cap.getResource().getCapabilities().length) { + best = cap; bestLocal = isCurrentLocal; bestVersion = (Version) v; } @@ -518,7 +473,6 @@ public class ResolverImpl implements Res public synchronized void deploy(int flags) { - m_deployFlags = flags; // Must resolve if not already resolved. if (!m_resolved && !resolve(flags)) { @@ -540,138 +494,114 @@ public class ResolverImpl implements Res } // Eliminate duplicates from target, required, optional resources. - Map deployMap = new HashMap(); + Set<Resource> resourceSet = new HashSet<Resource>(); Resource[] resources = getAddedResources(); for (int i = 0; (resources != null) && (i < resources.length); i++) { - deployMap.put(resources[i], resources[i]); + resourceSet.add(resources[i]); } resources = getRequiredResources(); for (int i = 0; (resources != null) && (i < resources.length); i++) { - deployMap.put(resources[i], resources[i]); + resourceSet.add(resources[i]); } if ((flags & NO_OPTIONAL_RESOURCES) == 0) { resources = getOptionalResources(); for (int i = 0; (resources != null) && (i < resources.length); i++) { - deployMap.put(resources[i], resources[i]); + resourceSet.add(resources[i]); } } - Resource[] deployResources = (Resource[]) - deployMap.keySet().toArray(new Resource[deployMap.size()]); + Resource[] deployResources = resourceSet.toArray(new Resource[resourceSet.size()]); // List to hold all resources to be started. - List startList = new ArrayList(); + List<Bundle> startList = new ArrayList<Bundle>(); // Deploy each resource, which will involve either finding a locally // installed resource to update or the installation of a new version // of the resource to be deployed. - for (int i = 0; i < deployResources.length; i++) - { + for (Resource deployResource : deployResources) { // For the resource being deployed, see if there is an older // version of the resource already installed that can potentially // be updated. - LocalResource localResource = findUpdatableLocalResource(deployResources[i]); + LocalResource localResource = findUpdatableLocalResource(deployResource); // If a potentially updatable older version was found, // then verify that updating the local resource will not // break any of the requirements of any of the other // resources being deployed. if ((localResource != null) && - isResourceUpdatable(localResource, deployResources[i], deployResources)) - { + isResourceUpdatable(localResource, deployResource, deployResources)) { // Only update if it is a different version. - if (!localResource.equals(deployResources[i])) - { + if (!localResource.equals(deployResource)) { // Update the installed bundle. - try - { + try { // stop the bundle before updating to prevent // the bundle update from throwing due to not yet // resolved dependencies boolean doStartBundle = (flags & START) != 0; - if (localResource.getBundle().getState() == Bundle.ACTIVE) - { + if (localResource.getBundle().getState() == Bundle.ACTIVE) { doStartBundle = true; localResource.getBundle().stop(); } - localResource.getBundle().update(FileUtil.openURL(new URL(deployResources[i].getURI()))); + localResource.getBundle().update(FileUtil.openURL(new URL(deployResource.getURI()))); // If necessary, save the updated bundle to be // started later. - if (doStartBundle) - { + if (doStartBundle) { Bundle bundle = localResource.getBundle(); - if (!isFragmentBundle(bundle)) - { + if (!isFragmentBundle(bundle)) { startList.add(bundle); } } - } - catch (Exception ex) - { + } catch (Exception ex) { m_logger.log( - Logger.LOG_ERROR, - "Resolver: Update error - " + getBundleName(localResource.getBundle()), - ex); + Logger.LOG_ERROR, + "Resolver: Update error - " + getBundleName(localResource.getBundle()), + ex); return; } } - } - else - { + } else { // Install the bundle. - try - { + try { // Perform the install, but do not use the actual // bundle JAR URL for the bundle location, since this will // limit OBR's ability to manipulate bundle versions. Instead, // use a unique timestamp as the bundle location. - URL url = new URL(deployResources[i].getURI()); - if (url != null) - { - Bundle bundle = m_context.installBundle( + URL url = new URL(deployResource.getURI()); + Bundle bundle = m_context.installBundle( "obr://" - + deployResources[i].getSymbolicName() - + "/-" + System.currentTimeMillis(), + + deployResource.getSymbolicName() + + "/-" + System.currentTimeMillis(), FileUtil.openURL(url)); - // If necessary, save the installed bundle to be - // started later. - if ((flags & START) != 0) - { - if (!isFragmentBundle(bundle)) - { - startList.add(bundle); - } + // If necessary, save the installed bundle to be + // started later. + if ((flags & START) != 0) { + if (!isFragmentBundle(bundle)) { + startList.add(bundle); } } - } - catch (Exception ex) - { + } catch (Exception ex) { m_logger.log( - Logger.LOG_ERROR, - "Resolver: Install error - " + deployResources[i].getSymbolicName(), - ex); + Logger.LOG_ERROR, + "Resolver: Install error - " + deployResource.getSymbolicName(), + ex); return; } } } - for (int i = 0; i < startList.size(); i++) - { - try - { - ((Bundle) startList.get(i)).start(); - } - catch (BundleException ex) - { + for (Bundle aStartList : startList) { + try { + aStartList.start(); + } catch (BundleException ex) { m_logger.log( - Logger.LOG_ERROR, - "Resolver: Start error - " + ((Bundle) startList.get(i)).getSymbolicName(), - ex); + Logger.LOG_ERROR, + "Resolver: Start error - " + aStartList.getSymbolicName(), + ex); } } } @@ -694,20 +624,15 @@ public class ResolverImpl implements Res // Determine if any other versions of the specified resource // already installed. LocalResource[] localResources = findLocalResources(resource.getSymbolicName()); - if (localResources != null) - { - // Since there are local resources with the same symbolic - // name installed, then we must determine if we can - // update an existing resource or if we must install - // another one. Loop through all local resources with same - // symbolic name and find the first one that can be updated - // without breaking constraints of existing local resources. - for (int i = 0; i < localResources.length; i++) - { - if (isResourceUpdatable(localResources[i], resource, localResources)) - { - return localResources[i]; - } + // Since there are local resources with the same symbolic + // name installed, then we must determine if we can + // update an existing resource or if we must install + // another one. Loop through all local resources with same + // symbolic name and find the first one that can be updated + // without breaking constraints of existing local resources. + for (LocalResource localResource : localResources) { + if (isResourceUpdatable(localResource, resource, localResources)) { + return localResource; } } return null; @@ -722,16 +647,14 @@ public class ResolverImpl implements Res { LocalResource[] localResources = getLocalResources(); - List matchList = new ArrayList(); - for (int i = 0; i < localResources.length; i++) - { - String localSymName = localResources[i].getSymbolicName(); - if ((localSymName != null) && localSymName.equals(symName)) - { - matchList.add(localResources[i]); + List<LocalResource> matchList = new ArrayList<LocalResource>(); + for (LocalResource localResource : localResources) { + String localSymName = localResource.getSymbolicName(); + if ((localSymName != null) && localSymName.equals(symName)) { + matchList.add(localResource); } } - return (LocalResource[]) matchList.toArray(new LocalResource[matchList.size()]); + return matchList.toArray(new LocalResource[matchList.size()]); } private boolean isResourceUpdatable( @@ -753,21 +676,17 @@ public class ResolverImpl implements Res { return false; } - for (int reqIdx = 0; reqIdx < reqs.length; reqIdx++) - { + for (Requirement req : reqs) { boolean satisfied = false; - for (int capIdx = 0; !satisfied && (capIdx < caps.length); capIdx++) - { - if (reqs[reqIdx].isSatisfied(caps[capIdx])) - { + for (int capIdx = 0; !satisfied && (capIdx < caps.length); capIdx++) { + if (req.isSatisfied(caps[capIdx])) { satisfied = true; } } // If any of the previously resolved requirements cannot // be resolved, then the resource is not updatable. - if (!satisfied) - { + if (!satisfied) { return false; } } @@ -783,26 +702,26 @@ public class ResolverImpl implements Res Capability[] caps = resource.getCapabilities(); if ((caps != null) && (caps.length > 0)) { - List reqList = new ArrayList(); - for (int capIdx = 0; capIdx < caps.length; capIdx++) - { + List<Requirement> reqList = new ArrayList<Requirement>(); + for (Capability cap : caps) { boolean added = false; - for (int resIdx = 0; !added && (resIdx < resources.length); resIdx++) - { - Requirement[] reqs = resources[resIdx].getRequirements(); - for (int reqIdx = 0; - (reqs != null) && (reqIdx < reqs.length); - reqIdx++) - { - if (reqs[reqIdx].isSatisfied(caps[capIdx])) - { - added = true; - reqList.add(reqs[reqIdx]); + + for (Resource aResource : resources) { + Requirement[] reqs = aResource.getRequirements(); + + if (reqs != null) { + for (Requirement req : reqs) { + if (req.isSatisfied(cap)) { + added = true; + reqList.add(req); + } } } + + if (added) break; } } - return (Requirement[]) reqList.toArray(new Requirement[reqList.size()]); + return reqList.toArray(new Requirement[reqList.size()]); } return null; }