use of org.osgi.service.resolver.HostedCapability in project felix by apache.
the class Candidates method prepare.
/**
* Merges fragments into their hosts. It does this by wrapping all host
* modules and attaching their selected fragments, removing all unselected
* fragment modules, and replacing all occurrences of the original fragments
* in the internal data structures with the wrapped host modules instead.
* Thus, fragment capabilities and requirements are merged into the
* appropriate host and the candidates for the fragment now become
* candidates for the host. Likewise, any module depending on a fragment now
* depend on the host. Note that this process is sort of like
* multiplication, since one fragment that can attach to two hosts
* effectively gets multiplied across the two hosts. So, any modules being
* satisfied by the fragment will end up having the two hosts as potential
* candidates, rather than the single fragment.
*
* @return ResolutionError if the removal of any unselected fragments
* result in the root module being unable to resolve.
*/
public ResolutionError prepare() {
// Maps a host capability to a map containing its potential fragments;
// the fragment map maps a fragment symbolic name to a map that maps
// a version to a list of fragments requirements matching that symbolic
// name and version.
Map<Capability, Map<String, Map<Version, List<Requirement>>>> hostFragments = getHostFragments();
// This method performs the following steps:
// 1. Select the fragments to attach to a given host.
// 2. Wrap hosts and attach fragments.
// 3. Remove any unselected fragments. This is necessary because
// other revisions may depend on the capabilities of unselected
// fragments, so we need to remove the unselected fragments and
// any revisions that depends on them, which could ultimately cause
// the entire resolve to fail.
// 4. Replace all fragments with any host it was merged into
// (effectively multiplying it).
// * This includes setting candidates for attached fragment
// requirements as well as replacing fragment capabilities
// with host's attached fragment capabilities.
// Steps 1 and 2
List<WrappedResource> hostResources = new ArrayList<WrappedResource>();
List<Resource> unselectedFragments = new ArrayList<Resource>();
for (Entry<Capability, Map<String, Map<Version, List<Requirement>>>> hostEntry : hostFragments.entrySet()) {
// Step 1
Capability hostCap = hostEntry.getKey();
Map<String, Map<Version, List<Requirement>>> fragments = hostEntry.getValue();
List<Resource> selectedFragments = new ArrayList<Resource>();
for (Entry<String, Map<Version, List<Requirement>>> fragEntry : fragments.entrySet()) {
boolean isFirst = true;
for (Entry<Version, List<Requirement>> versionEntry : fragEntry.getValue().entrySet()) {
for (Requirement hostReq : versionEntry.getValue()) {
// each fragment with a given symbolic name.
if (isFirst) {
selectedFragments.add(hostReq.getResource());
isFirst = false;
} else // For any fragment that wasn't selected, remove the
// current host as a potential host for it and remove it
// as a dependent on the host. If there are no more
// potential hosts for the fragment, then mark it as
// unselected for later removal.
{
m_dependentMap.get(hostCap).remove(hostReq);
CandidateSelector hosts = removeCandidate(hostReq, hostCap);
if (hosts.isEmpty()) {
unselectedFragments.add(hostReq.getResource());
}
}
}
}
}
// Step 2
WrappedResource wrappedHost = new WrappedResource(hostCap.getResource(), selectedFragments);
hostResources.add(wrappedHost);
m_allWrappedHosts.put(hostCap.getResource(), wrappedHost);
}
// Step 3
for (Resource fragment : unselectedFragments) {
removeResource(fragment, new FragmentNotSelectedError(fragment));
}
// First copy candidates for wrapped requirements to the host.
for (WrappedResource hostResource : hostResources) {
for (Requirement r : hostResource.getRequirements(null)) {
Requirement origReq = ((WrappedRequirement) r).getDeclaredRequirement();
CandidateSelector cands = m_candidateMap.get(origReq);
if (cands != null) {
if (cands instanceof ShadowList) {
m_candidateMap.put(r, ShadowList.deepCopy((ShadowList) cands));
} else {
m_candidateMap.put(r, cands.copy());
}
for (Capability cand : cands.getRemainingCandidates()) {
Set<Requirement> dependents = m_dependentMap.get(cand);
dependents.remove(origReq);
dependents.add(r);
}
}
}
}
for (WrappedResource hostResource : hostResources) {
// from the merged host.
for (Capability c : hostResource.getCapabilities(null)) {
// really be attached to the original host, not the wrapper.
if (!c.getNamespace().equals(HostNamespace.HOST_NAMESPACE)) {
Capability origCap = ((HostedCapability) c).getDeclaredCapability();
// Note that you might think we could remove the original cap
// from the dependent map, but you can't since it may come from
// a fragment that is attached to multiple hosts, so each host
// will need to make their own copy.
CopyOnWriteSet<Requirement> dependents = m_dependentMap.get(origCap);
if (dependents != null) {
dependents = new CopyOnWriteSet<Requirement>(dependents);
m_dependentMap.put(c, dependents);
for (Requirement r : dependents) {
// We have synthesized hosted capabilities for all
// fragments that have been attached to hosts by
// wrapping the host bundle and their attached
// fragments. We need to use the ResolveContext to
// determine the proper priority order for hosted
// capabilities since the order may depend on the
// declaring host/fragment combination. However,
// internally we completely wrap the host revision
// and make all capabilities/requirements point back
// to the wrapped host not the declaring host. The
// ResolveContext expects HostedCapabilities to point
// to the declaring revision, so we need two separate
// candidate lists: one for the ResolveContext with
// HostedCapabilities pointing back to the declaring
// host and one for the resolver with HostedCapabilities
// pointing back to the wrapped host. We ask the
// ResolveContext to insert its appropriate HostedCapability
// into its list, then we mirror the insert into a
// shadow list with the resolver's HostedCapability.
// We only need to ask the ResolveContext to find
// the insert position for fragment caps since these
// were synthesized and we don't know their priority.
// However, in the resolver's candidate list we need
// to replace all caps with the wrapped caps, no
// matter if they come from the host or fragment,
// since we are completing replacing the declaring
// host and fragments with the wrapped host.
CandidateSelector cands = m_candidateMap.get(r);
ShadowList shadow;
if (!(cands instanceof ShadowList)) {
shadow = ShadowList.createShadowList(cands);
m_candidateMap.put(r, shadow);
cands = shadow;
} else {
shadow = (ShadowList) cands;
}
// shadow copy of the list accordingly.
if (!origCap.getResource().equals(hostResource.getDeclaredResource())) {
shadow.insertHostedCapability(m_session.getContext(), (HostedCapability) c, new SimpleHostedCapability(hostResource.getDeclaredResource(), origCap));
} else // If the original capability is from the host, then
// we just need to replace it in the shadow list.
{
shadow.replace(origCap, c);
}
}
}
}
}
}
// selecting fragments/singletons.
for (Resource resource : m_session.getMandatoryResources()) {
if (!isPopulated(resource)) {
return getResolutionError(resource);
}
}
populateSubstitutables();
m_candidateMap.trim();
m_dependentMap.trim();
// mark the selectors as unmodifiable now
m_candidateSelectorsUnmodifiable.set(true);
return null;
}
use of org.osgi.service.resolver.HostedCapability in project rt.equinox.framework by eclipse.
the class Candidates method prepare.
/**
* Merges fragments into their hosts. It does this by wrapping all host
* modules and attaching their selected fragments, removing all unselected
* fragment modules, and replacing all occurrences of the original fragments
* in the internal data structures with the wrapped host modules instead.
* Thus, fragment capabilities and requirements are merged into the
* appropriate host and the candidates for the fragment now become
* candidates for the host. Likewise, any module depending on a fragment now
* depend on the host. Note that this process is sort of like
* multiplication, since one fragment that can attach to two hosts
* effectively gets multiplied across the two hosts. So, any modules being
* satisfied by the fragment will end up having the two hosts as potential
* candidates, rather than the single fragment.
*
* @return ResolutionError if the removal of any unselected fragments
* result in the root module being unable to resolve.
*/
public ResolutionError prepare() {
// Maps a host capability to a map containing its potential fragments;
// the fragment map maps a fragment symbolic name to a map that maps
// a version to a list of fragments requirements matching that symbolic
// name and version.
Map<Capability, Map<String, Map<Version, List<Requirement>>>> hostFragments = getHostFragments();
// This method performs the following steps:
// 1. Select the fragments to attach to a given host.
// 2. Wrap hosts and attach fragments.
// 3. Remove any unselected fragments. This is necessary because
// other revisions may depend on the capabilities of unselected
// fragments, so we need to remove the unselected fragments and
// any revisions that depends on them, which could ultimately cause
// the entire resolve to fail.
// 4. Replace all fragments with any host it was merged into
// (effectively multiplying it).
// * This includes setting candidates for attached fragment
// requirements as well as replacing fragment capabilities
// with host's attached fragment capabilities.
// Steps 1 and 2
List<WrappedResource> hostResources = new ArrayList<WrappedResource>();
List<Resource> unselectedFragments = new ArrayList<Resource>();
for (Entry<Capability, Map<String, Map<Version, List<Requirement>>>> hostEntry : hostFragments.entrySet()) {
// Step 1
Capability hostCap = hostEntry.getKey();
Map<String, Map<Version, List<Requirement>>> fragments = hostEntry.getValue();
List<Resource> selectedFragments = new ArrayList<Resource>();
for (Entry<String, Map<Version, List<Requirement>>> fragEntry : fragments.entrySet()) {
boolean isFirst = true;
for (Entry<Version, List<Requirement>> versionEntry : fragEntry.getValue().entrySet()) {
for (Requirement hostReq : versionEntry.getValue()) {
// each fragment with a given symbolic name.
if (isFirst) {
selectedFragments.add(hostReq.getResource());
isFirst = false;
} else // For any fragment that wasn't selected, remove the
// current host as a potential host for it and remove it
// as a dependent on the host. If there are no more
// potential hosts for the fragment, then mark it as
// unselected for later removal.
{
m_dependentMap.get(hostCap).remove(hostReq);
CandidateSelector hosts = removeCandidate(hostReq, hostCap);
if (hosts.isEmpty()) {
unselectedFragments.add(hostReq.getResource());
}
}
}
}
}
// Step 2
WrappedResource wrappedHost = new WrappedResource(hostCap.getResource(), selectedFragments);
hostResources.add(wrappedHost);
m_allWrappedHosts.put(hostCap.getResource(), wrappedHost);
}
// Step 3
for (Resource fragment : unselectedFragments) {
removeResource(fragment, new FragmentNotSelectedError(fragment));
}
// First copy candidates for wrapped requirements to the host.
for (WrappedResource hostResource : hostResources) {
for (Requirement r : hostResource.getRequirements(null)) {
Requirement origReq = ((WrappedRequirement) r).getDeclaredRequirement();
CandidateSelector cands = m_candidateMap.get(origReq);
if (cands != null) {
if (cands instanceof ShadowList) {
m_candidateMap.put(r, ShadowList.deepCopy((ShadowList) cands));
} else {
m_candidateMap.put(r, cands.copy());
}
for (Capability cand : cands.getRemainingCandidates()) {
Set<Requirement> dependents = m_dependentMap.get(cand);
dependents.remove(origReq);
dependents.add(r);
}
}
}
}
for (WrappedResource hostResource : hostResources) {
// from the merged host.
for (Capability c : hostResource.getCapabilities(null)) {
// really be attached to the original host, not the wrapper.
if (!c.getNamespace().equals(HostNamespace.HOST_NAMESPACE)) {
Capability origCap = ((HostedCapability) c).getDeclaredCapability();
// Note that you might think we could remove the original cap
// from the dependent map, but you can't since it may come from
// a fragment that is attached to multiple hosts, so each host
// will need to make their own copy.
CopyOnWriteSet<Requirement> dependents = m_dependentMap.get(origCap);
if (dependents != null) {
dependents = new CopyOnWriteSet<Requirement>(dependents);
m_dependentMap.put(c, dependents);
for (Requirement r : dependents) {
// We have synthesized hosted capabilities for all
// fragments that have been attached to hosts by
// wrapping the host bundle and their attached
// fragments. We need to use the ResolveContext to
// determine the proper priority order for hosted
// capabilities since the order may depend on the
// declaring host/fragment combination. However,
// internally we completely wrap the host revision
// and make all capabilities/requirements point back
// to the wrapped host not the declaring host. The
// ResolveContext expects HostedCapabilities to point
// to the declaring revision, so we need two separate
// candidate lists: one for the ResolveContext with
// HostedCapabilities pointing back to the declaring
// host and one for the resolver with HostedCapabilities
// pointing back to the wrapped host. We ask the
// ResolveContext to insert its appropriate HostedCapability
// into its list, then we mirror the insert into a
// shadow list with the resolver's HostedCapability.
// We only need to ask the ResolveContext to find
// the insert position for fragment caps since these
// were synthesized and we don't know their priority.
// However, in the resolver's candidate list we need
// to replace all caps with the wrapped caps, no
// matter if they come from the host or fragment,
// since we are completing replacing the declaring
// host and fragments with the wrapped host.
CandidateSelector cands = m_candidateMap.get(r);
ShadowList shadow;
if (!(cands instanceof ShadowList)) {
shadow = ShadowList.createShadowList(cands);
m_candidateMap.put(r, shadow);
cands = shadow;
} else {
shadow = (ShadowList) cands;
}
// shadow copy of the list accordingly.
if (!origCap.getResource().equals(hostResource.getDeclaredResource())) {
shadow.insertHostedCapability(m_session.getContext(), (HostedCapability) c, new SimpleHostedCapability(hostResource.getDeclaredResource(), origCap));
} else // If the original capability is from the host, then
// we just need to replace it in the shadow list.
{
shadow.replace(origCap, c);
}
}
}
}
}
}
// selecting fragments/singletons.
for (Resource resource : m_session.getMandatoryResources()) {
if (!isPopulated(resource)) {
return getResolutionError(resource);
}
}
populateSubstitutables();
m_candidateMap.trim();
m_dependentMap.trim();
// mark the selectors as unmodifiable now
m_candidateSelectorsUnmodifiable.set(true);
return null;
}
Aggregations