You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by tj...@apache.org on 2016/05/31 21:02:08 UTC
svn commit: r1746343 - in
/felix/trunk/resolver/src/main/java/org/apache/felix/resolver:
Candidates.java ResolverImpl.java util/CandidateSelector.java
util/CopyOnWriteList.java util/OpenHashMapList.java util/ShadowList.java
Author: tjwatson
Date: Tue May 31 21:02:07 2016
New Revision: 1746343
URL: http://svn.apache.org/viewvc?rev=1746343&view=rev
Log:
FELIX-5254: Improve structure of permutations to use unmodifiable capability lists
Added:
felix/trunk/resolver/src/main/java/org/apache/felix/resolver/util/CandidateSelector.java (with props)
Removed:
felix/trunk/resolver/src/main/java/org/apache/felix/resolver/util/CopyOnWriteList.java
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
felix/trunk/resolver/src/main/java/org/apache/felix/resolver/util/OpenHashMapList.java
felix/trunk/resolver/src/main/java/org/apache/felix/resolver/util/ShadowList.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=1746343&r1=1746342&r2=1746343&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 Tue May 31 21:02:07 2016
@@ -20,6 +20,8 @@ package org.apache.felix.resolver;
import java.util.*;
import java.util.Map.Entry;
+import java.util.concurrent.atomic.AtomicBoolean;
+
import org.apache.felix.resolver.ResolverImpl.PermutationType;
import org.apache.felix.resolver.ResolverImpl.ResolveSession;
import org.apache.felix.resolver.util.*;
@@ -47,7 +49,7 @@ class Candidates
// Maps a capability to requirements that match it.
private final OpenHashMapSet<Capability, Requirement> m_dependentMap;
// Maps a requirement to the capability it matches.
- private final OpenHashMapList<Requirement, Capability> m_candidateMap;
+ private final OpenHashMapList m_candidateMap;
// Maps a bundle revision to its associated wrapped revision; this only happens
// when a revision being resolved has fragments to attach to it.
private final Map<Resource, WrappedResource> m_allWrappedHosts;
@@ -57,20 +59,23 @@ class Candidates
private final Map<Capability, Requirement> m_subtitutableMap;
private final OpenHashMapSet<Requirement, Capability> m_delta;
+ private final AtomicBoolean m_candidateSelectorsUnmodifiable;
/**
* Private copy constructor used by the copy() method.
*/
private Candidates(
ResolveSession session,
+ AtomicBoolean candidateSelectorsUnmodifiable,
OpenHashMapSet<Capability, Requirement> dependentMap,
- OpenHashMapList<Requirement, Capability> candidateMap,
+ OpenHashMapList candidateMap,
Map<Resource, WrappedResource> wrappedHosts,
OpenHashMap<Resource, PopulateResult> populateResultCache,
Map<Capability, Requirement> substitutableMap,
OpenHashMapSet<Requirement, Capability> delta)
{
m_session = session;
+ m_candidateSelectorsUnmodifiable = candidateSelectorsUnmodifiable;
m_dependentMap = dependentMap;
m_candidateMap = candidateMap;
m_allWrappedHosts = wrappedHosts;
@@ -85,8 +90,9 @@ class Candidates
public Candidates(ResolveSession session)
{
m_session = session;
+ m_candidateSelectorsUnmodifiable = new AtomicBoolean(false);
m_dependentMap = new OpenHashMapSet<Capability, Requirement>();
- m_candidateMap = new OpenHashMapList<Requirement, Capability>();
+ m_candidateMap = new OpenHashMapList();
m_allWrappedHosts = new HashMap<Resource, WrappedResource>();
m_populateResultCache = new OpenHashMap<Resource, PopulateResult>();
m_subtitutableMap = new OpenHashMap<Capability, Requirement>();
@@ -301,16 +307,16 @@ class Candidates
{
continue;
}
- List<Capability> substitutes = m_candidateMap.get(req);
+ CandidateSelector substitutes = m_candidateMap.get(req);
if (substitutes != null && !substitutes.isEmpty())
{
- String packageName = (String) substitutes.get(0).getAttributes().get(PackageNamespace.PACKAGE_NAMESPACE);
+ String packageName = (String) substitutes.getCurrentCandidate().getAttributes().get(PackageNamespace.PACKAGE_NAMESPACE);
List<Capability> exportedPackages = exportNames.get(packageName);
if (exportedPackages != null)
{
// The package is exported;
// Check if the requirement only has the bundle's own export as candidates
- if (!exportedPackages.containsAll(substitutes))
+ if (!exportedPackages.containsAll(substitutes.getRemainingCandidates()))
{
for (Capability exportedPackage : exportedPackages)
{
@@ -355,13 +361,13 @@ class Candidates
{
for (Requirement dependent : dependents)
{
- List<Capability> candidates = m_candidateMap.get(dependent);
+ CandidateSelector candidates = m_candidateMap.get(dependent);
if (candidates != null)
{
candidates:
- for (Iterator<Capability> iCandidates = candidates.iterator(); iCandidates.hasNext();)
+ while (!candidates.isEmpty())
{
- Capability candidate = iCandidates.next();
+ Capability candidate = candidates.getCurrentCandidate();
Integer candidateStatus = substituteStatuses.get(candidate);
if (candidateStatus == null)
{
@@ -375,7 +381,7 @@ class Candidates
case SUBSTITUTED:
default:
// Need to remove any substituted that comes before an exported candidate
- iCandidates.remove();
+ candidates.removeCurrentCandidate();
// continue to next candidate
break;
}
@@ -429,10 +435,10 @@ class Candidates
// mark as processing to detect cycles
substituteStatuses.put(substitutableCap, PROCESSING);
// discover possible substitutes
- List<Capability> substitutes = m_candidateMap.get(substitutableReq);
+ CandidateSelector substitutes = m_candidateMap.get(substitutableReq);
if (substitutes != null)
{
- for (Capability substituteCandidate : substitutes)
+ for (Capability substituteCandidate : substitutes.getRemainingCandidates())
{
if (substituteCandidate.getResource().equals(substitutableCap.getResource()))
{
@@ -468,10 +474,10 @@ class Candidates
populate(toPopulate);
- CopyOnWriteList<Capability> caps = m_candidateMap.get(m_session.getDynamicRequirement());
+ CandidateSelector caps = m_candidateMap.get(m_session.getDynamicRequirement());
if (caps != null)
{
- m_session.getDynamicCandidates().retainAll(caps);
+ m_session.getDynamicCandidates().retainAll(caps.getRemainingCandidates());
}
else
{
@@ -653,7 +659,7 @@ class Candidates
private void addCandidates(Requirement req, List<Capability> candidates)
{
// Record the candidates.
- m_candidateMap.put(req, new CopyOnWriteList<Capability>(candidates));
+ m_candidateMap.put(req, new CandidateSelector(candidates, m_candidateSelectorsUnmodifiable));
for (Capability cap : candidates)
{
m_dependentMap.getOrCompute(cap).add(req);
@@ -699,29 +705,29 @@ class Candidates
*/
public List<Capability> getCandidates(Requirement req)
{
- List<Capability> candidates = m_candidateMap.get(req);
+ CandidateSelector candidates = m_candidateMap.get(req);
if (candidates != null)
{
- return Collections.unmodifiableList(candidates);
+ return candidates.getRemainingCandidates();
}
return null;
}
public Capability getFirstCandidate(Requirement req)
{
- List<Capability> candidates = m_candidateMap.get(req);
+ CandidateSelector candidates = m_candidateMap.get(req);
if (candidates != null && !candidates.isEmpty())
{
- return candidates.get(0);
+ return candidates.getCurrentCandidate();
}
return null;
}
public void removeFirstCandidate(Requirement req)
{
- List<Capability> candidates = m_candidateMap.get(req);
+ CandidateSelector candidates = m_candidateMap.get(req);
// Remove the conflicting candidate.
- Capability cap = candidates.remove(0);
+ Capability cap = candidates.removeCurrentCandidate();
if (candidates.isEmpty())
{
m_candidateMap.remove(req);
@@ -731,14 +737,16 @@ class Candidates
capPath.add(cap);
}
- public List<Capability> clearCandidates(Requirement req, Collection<Capability> caps)
+ public CandidateSelector clearMultipleCardinalityCandidates(Requirement req, Collection<Capability> caps)
{
- List<Capability> l = m_candidateMap.get(req);
- l.removeAll(caps);
- // Update candidates delta with the removed capabilities.
- CopyOnWriteSet<Capability> capPath = m_delta.getOrCompute(req);
- capPath.addAll(caps);
- return l;
+ // this is a special case where we need to completely replace the CandidateSelector
+ // this method should never be called from normal Candidates permutations
+ CandidateSelector candidates = m_candidateMap.get(req);
+ List<Capability> remaining = new ArrayList<Capability>(candidates.getRemainingCandidates());
+ remaining.removeAll(caps);
+ candidates = new CandidateSelector(remaining, m_candidateSelectorsUnmodifiable);
+ m_candidateMap.put(req, candidates);
+ return candidates;
}
/**
@@ -815,8 +823,7 @@ class Candidates
else
{
m_dependentMap.get(hostCap).remove(hostReq);
- List<Capability> hosts = m_candidateMap.get(hostReq);
- hosts.remove(hostCap);
+ CandidateSelector hosts = removeCandidate(hostReq, hostCap);
if (hosts.isEmpty())
{
unselectedFragments.add(hostReq.getResource());
@@ -889,39 +896,36 @@ class Candidates
// matter if they come from the host or fragment,
// since we are completing replacing the declaring
// host and fragments with the wrapped host.
- List<Capability> cands = m_candidateMap.get(r);
+ CandidateSelector cands = m_candidateMap.get(r);
+ ShadowList shadow;
if (!(cands instanceof ShadowList))
{
- ShadowList<Capability> shadow = new ShadowList<Capability>(cands);
+ shadow = ShadowList.createShadowList(cands);
m_candidateMap.put(r, shadow);
cands = shadow;
}
+ else
+ {
+ shadow = (ShadowList) cands;
+ }
// If the original capability is from a fragment, then
// ask the ResolveContext to insert it and update the
// shadow copy of the list accordingly.
if (!origCap.getResource().equals(hostResource.getDeclaredResource()))
{
- List<Capability> original = ((ShadowList<Capability>) cands).getOriginal();
- int removeIdx = original.indexOf(origCap);
- if (removeIdx != -1)
- {
- original.remove(removeIdx);
- cands.remove(removeIdx);
- }
- int insertIdx = m_session.getContext().insertHostedCapability(
- original,
- new SimpleHostedCapability(
- hostResource.getDeclaredResource(),
- origCap));
- cands.add(insertIdx, c);
+ shadow.insertHostedCapability(
+ m_session.getContext(),
+ (HostedCapability) c,
+ new SimpleHostedCapability(
+ hostResource.getDeclaredResource(),
+ origCap));
}
// If the original capability is from the host, then
// we just need to replace it in the shadow list.
else
{
- int idx = cands.indexOf(origCap);
- cands.set(idx, c);
+ shadow.replace(origCap, c);
}
}
}
@@ -932,11 +936,11 @@ class Candidates
for (Requirement r : hostResource.getRequirements(null))
{
Requirement origReq = ((WrappedRequirement) r).getDeclaredRequirement();
- List<Capability> cands = m_candidateMap.get(origReq);
+ CandidateSelector cands = m_candidateMap.get(origReq);
if (cands != null)
{
- m_candidateMap.put(r, new CopyOnWriteList<Capability>(cands));
- for (Capability cand : cands)
+ m_candidateMap.put(r, cands.copy());
+ for (Capability cand : cands.getRemainingCandidates())
{
Set<Requirement> dependents = m_dependentMap.get(cand);
dependents.remove(origReq);
@@ -962,6 +966,8 @@ class Candidates
m_candidateMap.trim();
m_dependentMap.trim();
+ // mark the selectors as unmodifiable now
+ m_candidateSelectorsUnmodifiable.set(true);
return null;
}
@@ -973,11 +979,11 @@ class Candidates
{
Map<Capability, Map<String, Map<Version, List<Requirement>>>> hostFragments =
new HashMap<Capability, Map<String, Map<Version, List<Requirement>>>>();
- for (Entry<Requirement, CopyOnWriteList<Capability>> entry : m_candidateMap.fast())
+ for (Entry<Requirement, CandidateSelector> entry : m_candidateMap.fast())
{
Requirement req = entry.getKey();
- List<Capability> caps = entry.getValue();
- for (Capability cap : caps)
+ CandidateSelector caps = entry.getValue();
+ for (Capability cap : caps.getRemainingCandidates())
{
// Keep track of hosts and associated fragments.
if (req.getNamespace().equals(HostNamespace.HOST_NAMESPACE))
@@ -1072,10 +1078,10 @@ class Candidates
*/
private void remove(Requirement req)
{
- List<Capability> candidates = m_candidateMap.remove(req);
+ CandidateSelector candidates = m_candidateMap.remove(req);
if (candidates != null)
{
- for (Capability cap : candidates)
+ for (Capability cap : candidates.getRemainingCandidates())
{
Set<Requirement> dependents = m_dependentMap.get(cap);
if (dependents != null)
@@ -1102,8 +1108,7 @@ class Candidates
{
for (Requirement r : dependents)
{
- List<Capability> candidates = m_candidateMap.get(r);
- candidates.remove(c);
+ CandidateSelector candidates = removeCandidate(r, c);
if (candidates.isEmpty())
{
m_candidateMap.remove(r);
@@ -1123,6 +1128,12 @@ class Candidates
}
}
+ private CandidateSelector removeCandidate(Requirement req, Capability cap) {
+ CandidateSelector candidates = m_candidateMap.get(req);
+ candidates.remove(cap);
+ return candidates;
+ }
+
/**
* Creates a copy of the Candidates object. This is used for creating
* permutations when package space conflicts are discovered.
@@ -1133,7 +1144,8 @@ class Candidates
{
return new Candidates(
m_session,
- m_dependentMap.deepClone(),
+ m_candidateSelectorsUnmodifiable,
+ m_dependentMap,
m_candidateMap.deepClone(),
m_allWrappedHosts,
m_populateResultCache,
@@ -1145,7 +1157,7 @@ class Candidates
{
// Create set of all revisions from requirements.
Set<Resource> resources = new CopyOnWriteSet<Resource>();
- for (Entry<Requirement, CopyOnWriteList<Capability>> entry
+ for (Entry<Requirement, CandidateSelector> entry
: m_candidateMap.entrySet())
{
resources.add(entry.getKey().getResource());
@@ -1162,8 +1174,8 @@ class Candidates
: resource.getRequirements(null);
for (Requirement req : reqs)
{
- List<Capability> candidates = m_candidateMap.get(req);
- if ((candidates != null) && (candidates.size() > 0))
+ CandidateSelector candidates = m_candidateMap.get(req);
+ if ((candidates != null) && (!candidates.isEmpty()))
{
System.out.println(" " + req + ": " + candidates);
}
@@ -1173,8 +1185,8 @@ class Candidates
: Util.getDynamicRequirements(resource.getRequirements(null));
for (Requirement req : reqs)
{
- List<Capability> candidates = m_candidateMap.get(req);
- if ((candidates != null) && (candidates.size() > 0))
+ CandidateSelector candidates = m_candidateMap.get(req);
+ if ((candidates != null) && (!candidates.isEmpty()))
{
System.out.println(" " + req + ": " + candidates);
}
@@ -1196,8 +1208,8 @@ class Candidates
public boolean canRemoveCandidate(Requirement req)
{
- List<Capability> candidates = m_candidateMap.get(req);
- return ((candidates != null) && (candidates.size() > 1 || Util.isOptional(req)));
+ CandidateSelector candidates = m_candidateMap.get(req);
+ return ((candidates != null) && (candidates.getRemainingCandidateCount() > 1 || Util.isOptional(req)));
}
static class DynamicImportFailed extends ResolutionError {
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=1746343&r1=1746342&r2=1746343&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 Tue May 31 21:02:07 2016
@@ -24,6 +24,7 @@ import java.util.Map.Entry;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.felix.resolver.util.ArrayMap;
+import org.apache.felix.resolver.util.CandidateSelector;
import org.apache.felix.resolver.util.OpenHashMap;
import org.osgi.framework.namespace.*;
import org.osgi.resource.*;
@@ -219,7 +220,7 @@ public class ResolverImpl implements Res
{
// Check the root requirement to see if it is a multiple cardinality
// requirement.
- List<Capability> candidates = null;
+ CandidateSelector candidates = null;
Requirement req = usedBlame.m_reqs.get(0);
if (Util.isMultiple(req))
{
@@ -231,7 +232,7 @@ public class ResolverImpl implements Res
}
// Get the current candidate list and remove all the offending root
// cause candidates from a copy of the current permutation.
- candidates = m_multipleCardCandidates.clearCandidates(req, usedBlames.getRootCauses(req));
+ candidates = m_multipleCardCandidates.clearMultipleCardinalityCandidates(req, usedBlames.getRootCauses(req));
}
// We only are successful if there is at least one candidate left
// for the requirement
Added: felix/trunk/resolver/src/main/java/org/apache/felix/resolver/util/CandidateSelector.java
URL: http://svn.apache.org/viewvc/felix/trunk/resolver/src/main/java/org/apache/felix/resolver/util/CandidateSelector.java?rev=1746343&view=auto
==============================================================================
--- felix/trunk/resolver/src/main/java/org/apache/felix/resolver/util/CandidateSelector.java (added)
+++ felix/trunk/resolver/src/main/java/org/apache/felix/resolver/util/CandidateSelector.java Tue May 31 21:02:07 2016
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.resolver.util;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.osgi.resource.Capability;
+
+public class CandidateSelector {
+ private final AtomicBoolean isUnmodifiable;
+ protected final List<Capability> unmodifiable;
+ private int currentIndex = 0;
+
+ public CandidateSelector(List<Capability> candidates, AtomicBoolean isUnmodifiable) {
+ this.isUnmodifiable = isUnmodifiable;
+ this.unmodifiable = new ArrayList<Capability>(candidates);
+ }
+
+ protected CandidateSelector(CandidateSelector candidateSelector) {
+ this.isUnmodifiable = candidateSelector.isUnmodifiable;
+ this.unmodifiable = candidateSelector.unmodifiable;
+ this.currentIndex = candidateSelector.currentIndex;
+ }
+
+ public CandidateSelector copy() {
+ return new CandidateSelector(this);
+ }
+
+ public int getRemainingCandidateCount() {
+ return unmodifiable.size() - currentIndex;
+ }
+
+ public Capability getCurrentCandidate() {
+ return currentIndex < unmodifiable.size() ? unmodifiable.get(currentIndex) : null;
+ }
+
+ public List<Capability> getRemainingCandidates() {
+ return Collections.unmodifiableList(unmodifiable.subList(currentIndex, unmodifiable.size()));
+ }
+
+ public boolean isEmpty() {
+ return unmodifiable.size() <= currentIndex;
+ }
+
+ public Capability removeCurrentCandidate() {
+ Capability current = getCurrentCandidate();
+ if (current != null) {
+ currentIndex += 1;
+ }
+ return current;
+ }
+
+ public String toString() {
+ return getRemainingCandidates().toString();
+ }
+
+ public int remove(Capability cap) {
+ checkModifiable();
+ int index = unmodifiable.indexOf(cap);
+ if (index != -1) {
+ unmodifiable.remove(index);
+ }
+ return index;
+ }
+
+ protected void checkModifiable() {
+ if (isUnmodifiable.get()) {
+ throw new IllegalStateException("Trying to mutate after candidates have been prepared.");
+ }
+ }
+}
Propchange: felix/trunk/resolver/src/main/java/org/apache/felix/resolver/util/CandidateSelector.java
------------------------------------------------------------------------------
svn:executable = *
Modified: felix/trunk/resolver/src/main/java/org/apache/felix/resolver/util/OpenHashMapList.java
URL: http://svn.apache.org/viewvc/felix/trunk/resolver/src/main/java/org/apache/felix/resolver/util/OpenHashMapList.java?rev=1746343&r1=1746342&r2=1746343&view=diff
==============================================================================
--- felix/trunk/resolver/src/main/java/org/apache/felix/resolver/util/OpenHashMapList.java (original)
+++ felix/trunk/resolver/src/main/java/org/apache/felix/resolver/util/OpenHashMapList.java Tue May 31 21:02:07 2016
@@ -18,7 +18,9 @@
*/
package org.apache.felix.resolver.util;
-public class OpenHashMapList<K, V> extends OpenHashMap<K, CopyOnWriteList<V>> {
+import org.osgi.resource.Requirement;
+
+public class OpenHashMapList extends OpenHashMap<Requirement, CandidateSelector> {
public OpenHashMapList() {
super();
@@ -28,21 +30,15 @@ public class OpenHashMapList<K, V> exten
super(initialCapacity);
}
- @SuppressWarnings("unchecked")
- public OpenHashMapList<K, V> deepClone() {
- OpenHashMapList<K, V> copy = (OpenHashMapList<K, V>) super.clone();
+ public OpenHashMapList deepClone() {
+ OpenHashMapList copy = (OpenHashMapList) super.clone();
Object[] values = copy.value;
for (int i = values.length; i-- > 0;) {
if (values[i] != null) {
- values[i] = new CopyOnWriteList<V>((CopyOnWriteList<V>) values[i]);
+ values[i] = ((CandidateSelector) values[i]).copy();
}
}
return copy;
}
- @Override
- protected CopyOnWriteList<V> compute(K key) {
- return new CopyOnWriteList<V>();
- }
-
}
Modified: felix/trunk/resolver/src/main/java/org/apache/felix/resolver/util/ShadowList.java
URL: http://svn.apache.org/viewvc/felix/trunk/resolver/src/main/java/org/apache/felix/resolver/util/ShadowList.java?rev=1746343&r1=1746342&r2=1746343&view=diff
==============================================================================
--- felix/trunk/resolver/src/main/java/org/apache/felix/resolver/util/ShadowList.java (original)
+++ felix/trunk/resolver/src/main/java/org/apache/felix/resolver/util/ShadowList.java Tue May 31 21:02:07 2016
@@ -18,23 +18,52 @@
*/
package org.apache.felix.resolver.util;
+import java.util.ArrayList;
import java.util.List;
-import org.apache.felix.resolver.util.CopyOnWriteList;
+import org.osgi.resource.Capability;
+import org.osgi.service.resolver.HostedCapability;
+import org.osgi.service.resolver.ResolveContext;
-public class ShadowList<T> extends CopyOnWriteList<T>
+public class ShadowList extends CandidateSelector
{
- private final List<T> m_original;
+ public static ShadowList createShadowList(CandidateSelector original) {
+ return new ShadowList(original);
+ }
+
+ private final List<Capability> m_original;
- public ShadowList(List<T> original)
+ private ShadowList(CandidateSelector original)
{
super(original);
- m_original = original;
+ m_original = new ArrayList<Capability>(original.getRemainingCandidates());
}
- public List<T> getOriginal()
+ private ShadowList(CandidateSelector shadow, List<Capability> original)
{
- return m_original;
+ super(shadow);
+ m_original = original;
}
+ public ShadowList copy() {
+ return new ShadowList(this, m_original);
+ }
+
+ public void insertHostedCapability(ResolveContext context, HostedCapability wrappedCapability, HostedCapability toInsertCapability) {
+ checkModifiable();
+ int removeIdx = m_original.indexOf(toInsertCapability.getDeclaredCapability());
+ if (removeIdx != -1)
+ {
+ m_original.remove(removeIdx);
+ unmodifiable.remove(removeIdx);
+ }
+ int insertIdx = context.insertHostedCapability(m_original, toInsertCapability);
+ unmodifiable.add(insertIdx, wrappedCapability);
+ }
+
+ public void replace(Capability origCap, Capability c) {
+ checkModifiable();
+ int idx = unmodifiable.indexOf(origCap);
+ unmodifiable.set(idx, c);
+ }
}
\ No newline at end of file