Previously fragments were only being attached to hosts when the host was
explicitly resolved; as part of the refactoring of the resolver, fragments
are now attached to hosts no matter how the host is resolved.
(FELIX-851, FELIX-852)
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@729091 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/Felix.java b/framework/src/main/java/org/apache/felix/framework/Felix.java
index 1d17403..8806f10 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -28,7 +28,6 @@
import org.apache.felix.framework.ext.SecurityProvider;
import org.apache.felix.framework.searchpolicy.*;
import org.apache.felix.framework.searchpolicy.PackageSource;
-import org.apache.felix.framework.searchpolicy.Resolver.ResolverState;
import org.apache.felix.framework.util.*;
import org.apache.felix.framework.util.manifestparser.*;
import org.apache.felix.moduleloader.*;
@@ -3789,13 +3788,10 @@
{
if (!m_resolverState.isResolved(rootModule))
{
- Resolver.Result result = m_resolver.resolve(m_resolverState, rootModule);
+ Map resolvedModuleWireMap = m_resolver.resolve(m_resolverState, rootModule);
// Mark all modules as resolved.
- markResolvedModules(result.m_resolvedModuleWireMap);
-
- // Attach and mark all fragments as resolved.
- attachFragments(result.m_host, result.m_fragmentMap);
+ markResolvedModules(resolvedModuleWireMap);
}
}
@@ -3854,16 +3850,34 @@
Iterator iter = resolvedModuleWireMap.entrySet().iterator();
// Iterate over the map to mark the modules as resolved and
// update our resolver data structures.
+ List fragmentList = new ArrayList();
+ List wireList = new ArrayList();
while (iter.hasNext())
{
+ fragmentList.clear();
+ wireList.clear();
+
Map.Entry entry = (Map.Entry) iter.next();
IModule module = (IModule) entry.getKey();
IWire[] wires = (IWire[]) entry.getValue();
// Only add wires attribute if some exist; export
// only modules may not have wires.
+// TODO: RESOLVER - Seems stupid that we package these up as wires to tear them apart.
if (wires.length > 0)
{
+ for (int wireIdx = 0; wireIdx < wires.length; wireIdx++)
+ {
+ if (wires[wireIdx] instanceof R4WireFragment)
+ {
+ fragmentList.add(wires[wireIdx].getExporter());
+ }
+ else
+ {
+ wireList.add(wires[wireIdx]);
+ }
+ }
+ wires = (IWire[]) wireList.toArray(new IWire[wireList.size()]);
((ModuleImpl) module).setWires(wires);
for (int wireIdx = 0; (wires != null) && (wireIdx < wires.length); wireIdx++)
{
@@ -3875,34 +3889,30 @@
m_resolverState.setResolved(module, true);
// Update the state of the module's bundle to resolved as well.
markBundleResolved(module);
+
+ // Attach and mark all fragments as resolved.
+ attachFragments(module, fragmentList);
}
}
- private void attachFragments(IModule host, Map fragmentMap)
+ private void attachFragments(IModule host, List fragmentList)
{
// Attach fragments to host module.
- if ((fragmentMap != null) && (fragmentMap.size() > 0))
+ if (fragmentList.size() > 0)
{
- List list = new ArrayList();
- for (Iterator iter = fragmentMap.entrySet().iterator(); iter.hasNext(); )
+ for (int i = 0; i < fragmentList.size(); i++)
{
- Map.Entry entry = (Map.Entry) iter.next();
- String symName = (String) entry.getKey();
- IModule[] fragments = (IModule[]) entry.getValue();
-// TODO: FRAGMENT - For now, just attach first candidate.
- list.add(fragments[0]);
-m_logger.log(Logger.LOG_DEBUG, "(FRAGMENT) WIRE: "
- + host + " -> " + symName + " -> " + fragments[0]);
+m_logger.log(Logger.LOG_DEBUG, "(FRAGMENT) WIRE: " + host + " -> hosts -> " + fragmentList.get(i));
// Update the resolver state to show the module as resolved.
- m_resolverState.setResolved(fragments[0], true);
+ m_resolverState.setResolved((IModule) fragmentList.get(i), true);
// Update the state of the module's bundle to resolved as well.
- markBundleResolved(fragments[0]);
+ markBundleResolved((IModule) fragmentList.get(i));
}
try
{
((ModuleImpl) host).attachFragments(
- (IModule[]) list.toArray(new IModule[list.size()]));
+ (IModule[]) fragmentList.toArray(new IModule[fragmentList.size()]));
}
catch (Exception ex)
{
diff --git a/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java b/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java
index c334276..8c0dbe5 100644
--- a/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java
+++ b/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java
@@ -77,10 +77,10 @@
}
}
-System.out.println("UNRESOLVED PACKAGES:");
-dumpPackageIndexMap(m_unresolvedPkgIndexMap);
-System.out.println("RESOLVED PACKAGES:");
-dumpPackageIndexMap(m_resolvedPkgIndexMap);
+//System.out.println("UNRESOLVED PACKAGES:");
+//dumpPackageIndexMap(m_unresolvedPkgIndexMap);
+//System.out.println("RESOLVED PACKAGES:");
+//dumpPackageIndexMap(m_resolvedPkgIndexMap);
}
public synchronized void removeModule(IModule module)
@@ -303,10 +303,10 @@
}
}
-System.out.println("UNRESOLVED PACKAGES:");
-dumpPackageIndexMap(m_unresolvedPkgIndexMap);
-System.out.println("RESOLVED PACKAGES:");
-dumpPackageIndexMap(m_resolvedPkgIndexMap);
+//System.out.println("UNRESOLVED PACKAGES:");
+//dumpPackageIndexMap(m_unresolvedPkgIndexMap);
+//System.out.println("RESOLVED PACKAGES:");
+//dumpPackageIndexMap(m_resolvedPkgIndexMap);
}
// TODO: FRAGMENT - Not very efficient.
diff --git a/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4WireFragment.java b/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4WireFragment.java
new file mode 100644
index 0000000..929e8af
--- /dev/null
+++ b/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4WireFragment.java
@@ -0,0 +1,112 @@
+/*
+ * 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.framework.searchpolicy;
+
+import java.net.URL;
+import java.util.Enumeration;
+
+import org.apache.felix.framework.util.Util;
+import org.apache.felix.framework.util.manifestparser.Capability;
+import org.apache.felix.moduleloader.*;
+
+// TODO: RESOLVER - This is a hack and doesn't really fit with abstraction.
+public class R4WireFragment implements IWire
+{
+ private final IModule m_importer;
+ private final IRequirement m_requirement;
+ private final IModule m_exporter;
+ private final ICapability m_capability;
+
+ public R4WireFragment(IModule host, IModule fragment)
+ {
+ m_importer = host;
+ m_requirement = null;
+ m_exporter = fragment;
+ m_capability = null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.felix.framework.searchpolicy.IWire#getImporter()
+ */
+ public IModule getImporter()
+ {
+ return m_importer;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.felix.framework.searchpolicy.IWire#getRequirement()
+ */
+ public IRequirement getRequirement()
+ {
+ return m_requirement;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.felix.framework.searchpolicy.IWire#getExporter()
+ */
+ public IModule getExporter()
+ {
+ return m_exporter;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.felix.framework.searchpolicy.IWire#getCapability()
+ */
+ public ICapability getCapability()
+ {
+ return m_capability;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.felix.framework.searchpolicy.IWire#getClass(java.lang.String)
+ */
+ public boolean hasPackage(String pkgName)
+ {
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.felix.framework.searchpolicy.IWire#getClass(java.lang.String)
+ */
+ public Class getClass(String name) throws ClassNotFoundException
+ {
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.felix.framework.searchpolicy.IWire#getResource(java.lang.String)
+ */
+ public URL getResource(String name) throws ResourceNotFoundException
+ {
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.felix.framework.searchpolicy.IWire#getResources(java.lang.String)
+ */
+ public Enumeration getResources(String name) throws ResourceNotFoundException
+ {
+ return null;
+ }
+
+ public String toString()
+ {
+ return m_importer + " -> hosts -> " + m_exporter;
+ }
+}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/searchpolicy/Resolver.java b/framework/src/main/java/org/apache/felix/framework/searchpolicy/Resolver.java
index c85efcb..55930d4 100644
--- a/framework/src/main/java/org/apache/felix/framework/searchpolicy/Resolver.java
+++ b/framework/src/main/java/org/apache/felix/framework/searchpolicy/Resolver.java
@@ -40,6 +40,7 @@
private final Logger m_logger;
// Reusable empty array.
+ private static final IModule[] m_emptyModules = new IModule[0];
private static final PackageSource[] m_emptySources = new PackageSource[0];
public Resolver(Logger logger)
@@ -51,50 +52,14 @@
// and the value is an array of wires.
// TODO: RESOLVER - The caller must ensure this is not called currently;
// this may not be important if no state is shared.
- public Result resolve(ResolverState state, IModule rootModule) throws ResolveException
+ public Map resolve(ResolverState state, IModule rootModule) throws ResolveException
{
- // This map will be used to hold the final wires for all
- // resolved modules, which can then be used to fire resolved
- // events outside of the synchronized block.
- Map fragmentMap = null;
-
// If the module is already resolved, then we can just return.
if (state.isResolved(rootModule))
{
return null;
}
- // The root module is either a host or a fragment. If it is a host,
- // then we want to go ahead and resolve it. If it is a fragment, then
- // we want to select a host and resolve the host instead.
- IModule targetFragment = null;
-// TODO: FRAGMENT - Currently we just make a single selection of the available
-// fragments or hosts and try to resolve. In case of failure, we do not
-// backtrack. We will likely want to add backtracking.
- if (Util.isFragment(rootModule))
- {
- targetFragment = rootModule;
- List hostList = state.getPotentialHosts(targetFragment);
- if (hostList.size() == 0)
- {
- throw new ResolveException("Unable to find host for fragment.", targetFragment, null);
- }
- rootModule = (IModule) hostList.get(0);
- }
-
- // Get the available fragments for the host.
- fragmentMap = state.getPotentialFragments(rootModule);
-
- // If the resolve was for a specific fragment, then
- // eliminate all other potential candidate fragments
- // of the same symbolic name.
- if (targetFragment != null)
- {
- fragmentMap.put(
- state.getBundleSymbolicName(targetFragment),
- new IModule[] { targetFragment });
- }
-
// This variable maps an unresolved module to a list of candidate
// sets, where there is one candidate set for each requirement that
// must be resolved. A candidate set contains the potential canidates
@@ -135,10 +100,7 @@
// to fire resolved events outside of the synchronized block.
// The resolved module wire map maps a module to its array of
// wires.
- // Get a map of all modules and their resolved wires.
- Map resolvedModuleWireMap =
- populateWireMap(state, candidatesMap, rootModule, new HashMap());
- return new Result(rootModule, fragmentMap, resolvedModuleWireMap);
+ return populateWireMap(state, candidatesMap, rootModule, new HashMap());
}
// TODO: RESOLVER - Fix this return type.
@@ -372,95 +334,207 @@
}
private static void populateCandidatesMap(
- ResolverState state, Map candidatesMap, IModule module)
+ ResolverState state, Map candidatesMap, IModule targetModule)
throws ResolveException
{
// Detect cycles.
- if (candidatesMap.get(module) != null)
+ if (candidatesMap.get(targetModule) != null)
{
return;
}
- // List to hold the resolving candidate sets for the module's
- // requirements.
+ // List to hold the resolving candidate sets for the target
+ // module's requirements.
List candSetList = new ArrayList();
// Even though the candidate set list is currently empty, we
// record it in the candidates map early so we can use it to
// detect cycles.
- candidatesMap.put(module, candSetList);
+ candidatesMap.put(targetModule, candSetList);
- // Loop through each requirement and calculate its resolving
- // set of candidates.
- IRequirement[] reqs = module.getDefinition().getRequirements();
- for (int reqIdx = 0; (reqs != null) && (reqIdx < reqs.length); reqIdx++)
+ // Loop through potential fragments and add each set to the
+ // candidate set; if the targetModule is a fragment then there
+ // will be no potential fragments here.
+ Map fragmentMap = state.getPotentialFragments(targetModule);
+ for (Iterator it = fragmentMap.entrySet().iterator(); it.hasNext(); )
{
- // Get the candidates from the "resolved" and "unresolved"
- // package maps. The "resolved" candidates have higher priority
- // than "unresolved" ones, so put the "resolved" candidates
- // at the front of the list of candidates.
- PackageSource[] resolved = state.getResolvedCandidates(reqs[reqIdx]);
- PackageSource[] unresolved = state.getUnresolvedCandidates(reqs[reqIdx]);
- PackageSource[] candidates = new PackageSource[resolved.length + unresolved.length];
- System.arraycopy(resolved, 0, candidates, 0, resolved.length);
- System.arraycopy(unresolved, 0, candidates, resolved.length, unresolved.length);
+ Map.Entry entry = (Map.Entry) it.next();
+ IModule[] fragments = (IModule[]) entry.getValue();
- // If we have candidates, then we need to recursively populate
+ // If we have fragment candidates, then we need to recursively populate
// the resolver map with each of them.
- ResolveException rethrow = null;
- if (candidates.length > 0)
+ if (fragments.length > 0)
{
- for (int candIdx = 0; candIdx < candidates.length; candIdx++)
+ for (int fragIdx = 0; fragIdx < fragments.length; fragIdx++)
{
try
{
- // Only populate the resolver map with modules that
- // are not already resolved.
- if (!state.isResolved(candidates[candIdx].m_module))
- {
- populateCandidatesMap(state, candidatesMap, candidates[candIdx].m_module);
- }
+ // We still need to populate the candidates for the
+ // fragment even if it is resolved, because fragments
+ // can be attached to multiple hosts and each host
+ // may end up with different wires for the fragments
+ // dependencies.
+ populateCandidatesMap(state, candidatesMap, fragments[fragIdx]);
}
catch (ResolveException ex)
{
// If we received a resolve exception, then the
- // current candidate is not resolvable for some
+ // current fragment is not resolvable for some
// reason and should be removed from the list of
- // candidates. For now, just null it.
- candidates[candIdx] = null;
- rethrow = ex;
+ // fragments. For now, just null it.
+ fragments[fragIdx] = null;
}
}
- // Remove any nulled candidates to create the final list
- // of available candidates.
- candidates = shrinkCandidateArray(candidates);
+ // Remove any nulled fragments to create the final list
+ // of potential fragment candidates.
+ fragments = shrinkModuleArray(fragments);
}
- // If no candidates exist at this point, then throw a
- // resolve exception unless the import is optional.
- if ((candidates.length == 0) && !reqs[reqIdx].isOptional())
- {
- // If we have received an exception while trying to populate
- // the resolver map, rethrow that exception since it might
- // be useful. NOTE: This is not necessarily the "only"
- // correct exception, since it is possible that multiple
- // candidates were not resolvable, but it is better than
- // nothing.
- if (rethrow != null)
- {
- throw rethrow;
- }
- else
- {
- throw new ResolveException(
- "Unable to resolve.", module, reqs[reqIdx]);
- }
- }
- else if (candidates.length > 0)
+ // All fragments, by definition, are optional so we if none of the
+ // candidates could be resolved, then just ignore them; otherwise,
+ // add the resolvable fragments to the host's candidate set.
+ if (fragments.length > 0)
{
candSetList.add(
- new CandidateSet(module, reqs[reqIdx], candidates));
+ new CandidateSet(CandidateSet.FRAGMENT, targetModule, null, fragments));
+ }
+ }
+
+ // Loop through each requirement and calculate its resolving
+ // set of candidates.
+ IRequirement[] reqs = targetModule.getDefinition().getRequirements();
+ for (int reqIdx = 0; (reqs != null) && (reqIdx < reqs.length); reqIdx++)
+ {
+ if (reqs[reqIdx].getNamespace().equals(ICapability.HOST_NAMESPACE))
+ {
+ List hostList = state.getPotentialHosts(targetModule);
+ IModule[] hosts = (IModule[]) hostList.toArray(new IModule[hostList.size()]);
+ // If we have host candidates, then we need to recursively populate
+ // the resolver map with each of them.
+ ResolveException rethrow = null;
+ if (hosts.length > 0)
+ {
+ for (int hostIdx = 0; hostIdx < hosts.length; hostIdx++)
+ {
+ try
+ {
+ // Only populate the resolver map with hosts that
+ // are not already resolved.
+ if (!state.isResolved(hosts[hostIdx]))
+ {
+ populateCandidatesMap(state, candidatesMap, hosts[hostIdx]);
+ }
+ }
+ catch (ResolveException ex)
+ {
+ // If we received a resolve exception, then the
+ // current host is not resolvable for some
+ // reason and should be removed from the list of
+ // hosts. For now, just null it.
+ hosts[hostIdx] = null;
+ rethrow = ex;
+ }
+ }
+
+ // Remove any nulled hosts to create the final list
+ // of potential host candidates.
+ hosts = shrinkModuleArray(hosts);
+ }
+
+ // If no host candidates exist at this point, then throw a
+ // resolve exception since all fragments must have a host.
+ if (hosts.length == 0)
+ {
+ // If we have received an exception while trying to populate
+ // the candidates map, rethrow that exception since it might
+ // be useful. NOTE: This is not necessarily the "only"
+ // correct exception, since it is possible that multiple
+ // candidates were not resolvable, but it is better than
+ // nothing.
+ if (rethrow != null)
+ {
+ throw rethrow;
+ }
+ else
+ {
+ throw new ResolveException(
+ "Unable to find host for fragment.",
+ targetModule, reqs[reqIdx]);
+ }
+ }
+ candSetList.add(
+ new CandidateSet(CandidateSet.HOST, targetModule, reqs[reqIdx], hosts));
+ }
+ else
+ {
+ // Get the candidates from the "resolved" and "unresolved"
+ // package maps. The "resolved" candidates have higher priority
+ // than "unresolved" ones, so put the "resolved" candidates
+ // at the front of the list of candidates.
+ PackageSource[] resolved = state.getResolvedCandidates(reqs[reqIdx]);
+ PackageSource[] unresolved = state.getUnresolvedCandidates(reqs[reqIdx]);
+ PackageSource[] candidates = new PackageSource[resolved.length + unresolved.length];
+ System.arraycopy(resolved, 0, candidates, 0, resolved.length);
+ System.arraycopy(unresolved, 0, candidates, resolved.length, unresolved.length);
+
+ // If we have candidates, then we need to recursively populate
+ // the resolver map with each of them.
+ ResolveException rethrow = null;
+ if (candidates.length > 0)
+ {
+ for (int candIdx = 0; candIdx < candidates.length; candIdx++)
+ {
+ try
+ {
+ // Only populate the resolver map with modules that
+ // are not already resolved.
+ if (!state.isResolved(candidates[candIdx].m_module))
+ {
+ populateCandidatesMap(state, candidatesMap, candidates[candIdx].m_module);
+ }
+ }
+ catch (ResolveException ex)
+ {
+ // If we received a resolve exception, then the
+ // current candidate is not resolvable for some
+ // reason and should be removed from the list of
+ // candidates. For now, just null it.
+ candidates[candIdx] = null;
+ rethrow = ex;
+ }
+ }
+
+ // Remove any nulled candidates to create the final list
+ // of available candidates.
+ candidates = shrinkCandidateArray(candidates);
+ }
+
+ // If no candidates exist at this point, then throw a
+ // resolve exception unless the import is optional.
+ if ((candidates.length == 0) && !reqs[reqIdx].isOptional())
+ {
+ // If we have received an exception while trying to populate
+ // the candidates map, rethrow that exception since it might
+ // be useful. NOTE: This is not necessarily the "only"
+ // correct exception, since it is possible that multiple
+ // candidates were not resolvable, but it is better than
+ // nothing.
+ if (rethrow != null)
+ {
+ throw rethrow;
+ }
+ else
+ {
+ throw new ResolveException(
+ "Unable to resolve.", targetModule, reqs[reqIdx]);
+ }
+ }
+ else if (candidates.length > 0)
+ {
+ candSetList.add(
+ new CandidateSet(CandidateSet.NORMAL, targetModule, reqs[reqIdx], candidates));
+ }
}
}
}
@@ -964,6 +1038,18 @@
for (int candSetIdx = 0; (candSetList != null) && (candSetIdx < candSetList.size()); candSetIdx++)
{
CandidateSet cs = (CandidateSet) candSetList.get(candSetIdx);
+// TODO: FRAGMENT - Eventually fragments will import, so the imports of a fragment
+// will need to be added to the imports of the host.
+ if (cs.m_type == CandidateSet.FRAGMENT)
+ {
+ continue;
+ }
+ else if (cs.m_type == CandidateSet.HOST)
+ {
+ // We can ignore the host candidates, since they will be
+ // taken care of when resolving the host module.
+ continue;
+ }
PackageSource ps = cs.m_candidates[cs.m_idx];
if (ps.m_capability.getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
@@ -1048,6 +1134,18 @@
for (int candSetIdx = 0; (candSetList != null) && (candSetIdx < candSetList.size()); candSetIdx++)
{
CandidateSet cs = (CandidateSet) candSetList.get(candSetIdx);
+// TODO: FRAGMENT - Eventually fragments will require bundles, so the required
+// packages of the fragment will need to be added to the host.
+ if (cs.m_type == CandidateSet.FRAGMENT)
+ {
+ continue;
+ }
+ else if (cs.m_type == CandidateSet.HOST)
+ {
+ // We can ignore the host candidates, since they will be
+ // taken care of when resolving the host module.
+ continue;
+ }
PackageSource ps = cs.m_candidates[cs.m_idx];
// If the capabaility is a module dependency, then flatten it to packages.
@@ -1164,6 +1262,18 @@
for (int candSetIdx = 0; candSetIdx < candSetList.size(); candSetIdx++)
{
CandidateSet cs = (CandidateSet) candSetList.get(candSetIdx);
+// TODO: FRAGMENT - Eventually fragments will export, so the exports of the
+// fragment will need to be added to the host.
+ if (cs.m_type == CandidateSet.FRAGMENT)
+ {
+ continue;
+ }
+ else if (cs.m_type == CandidateSet.HOST)
+ {
+ // We can ignore the host candidates, since they will be
+ // taken care of when resolving the host module.
+ continue;
+ }
PackageSource ps = cs.m_candidates[cs.m_idx];
// If the candidate is resolving a module dependency, then
@@ -1424,7 +1534,55 @@
return wireMap;
}
+ // Get the candidate set list for the importer.
List candSetList = (List) candidatesMap.get(importer);
+
+ // Check if the importer is a fragment, if so we actually want
+ // to get the host and add all fragments candidates to it.
+ if (Util.isFragment(importer))
+ {
+ // Get host candidate for the fragment.
+ IModule host = null;
+ for (int csIdx = 0; (host == null) && (csIdx < candSetList.size()); csIdx++)
+ {
+ CandidateSet cs = (CandidateSet) candSetList.get(csIdx);
+ if (cs.m_type == CandidateSet.HOST)
+ {
+ host = cs.m_modules[cs.m_idx];
+ }
+ }
+ // Instead of creating wires for the fragment, we will create them
+ // for the host.
+ importer = host;
+ // Now add the fragments candidates to the host.
+ candSetList = (List) candidatesMap.get(host);
+ for (int csIdx = 0; (host == null) && (csIdx < candSetList.size()); csIdx++)
+ {
+ CandidateSet cs = (CandidateSet) candSetList.get(csIdx);
+ if (cs.m_type == CandidateSet.FRAGMENT)
+ {
+ // Add the candidate fragment module to the cycle map
+ // with no wires, since only its host will have wires.
+ wireMap.put(cs.m_modules[cs.m_idx], new IWire[0]);
+
+ // Get the candidate fragment and loop through its candidates
+ // for resolving its dependencies.
+ List fragmentCandSetList = (List) candidatesMap.get(cs.m_modules[cs.m_idx]);
+ for (int csFragIdx = 0; csFragIdx < fragmentCandSetList.size(); csFragIdx++)
+ {
+ // Add all non-HOST candidates to the host candidate set,
+ // since the resulting wires will be for the host not
+ // the fragment.
+ CandidateSet csFrag = (CandidateSet) fragmentCandSetList.get(csFragIdx);
+ if (csFrag.m_type != CandidateSet.HOST)
+ {
+ candSetList.add(csFrag);
+ }
+ }
+ }
+ }
+ }
+
List moduleWires = new ArrayList();
List packageWires = new ArrayList();
IWire[] wires = new IWire[candSetList.size()];
@@ -1442,28 +1600,35 @@
// Create a wire for the current candidate based on the type
// of requirement it resolves.
- if (cs.m_requirement.getNamespace().equals(ICapability.MODULE_NAMESPACE))
+ if (cs.m_type == CandidateSet.FRAGMENT)
{
- moduleWires.add(new R4WireModule(
- importer,
- cs.m_requirement,
- cs.m_candidates[cs.m_idx].m_module,
- cs.m_candidates[cs.m_idx].m_capability,
- calculateCandidateRequiredPackages(importer, cs.m_candidates[cs.m_idx], candidatesMap)));
+ moduleWires.add(new R4WireFragment(importer, cs.m_modules[cs.m_idx]));
}
else
{
- // Add wire for imported package.
- packageWires.add(new R4Wire(
- importer,
- cs.m_requirement,
- cs.m_candidates[cs.m_idx].m_module,
- cs.m_candidates[cs.m_idx].m_capability));
- }
+ if (cs.m_requirement.getNamespace().equals(ICapability.MODULE_NAMESPACE))
+ {
+ moduleWires.add(new R4WireModule(
+ importer,
+ cs.m_requirement,
+ cs.m_candidates[cs.m_idx].m_module,
+ cs.m_candidates[cs.m_idx].m_capability,
+ calculateCandidateRequiredPackages(importer, cs.m_candidates[cs.m_idx], candidatesMap)));
+ }
+ else
+ {
+ // Add wire for imported package.
+ packageWires.add(new R4Wire(
+ importer,
+ cs.m_requirement,
+ cs.m_candidates[cs.m_idx].m_module,
+ cs.m_candidates[cs.m_idx].m_capability));
+ }
- // Create any necessary wires for the selected candidate module.
- wireMap = populateWireMap(
- state, candidatesMap, cs.m_candidates[cs.m_idx].m_module, wireMap);
+ // Create any necessary wires for the selected candidate module.
+ wireMap = populateWireMap(
+ state, candidatesMap, cs.m_candidates[cs.m_idx].m_module, wireMap);
+ }
}
packageWires.addAll(moduleWires);
@@ -1476,6 +1641,34 @@
// Utility methods.
//
+ private static IModule[] shrinkModuleArray(IModule[] modules)
+ {
+ if (modules == null)
+ {
+ return m_emptyModules;
+ }
+
+ // Move all non-null values to one end of the array.
+ int lower = 0;
+ for (int i = 0; i < modules.length; i++)
+ {
+ if (modules[i] != null)
+ {
+ modules[lower++] = modules[i];
+ }
+ }
+
+ if (lower == 0)
+ {
+ return m_emptyModules;
+ }
+
+ // Copy non-null values into a new array and return.
+ IModule[] newModules = new IModule[lower];
+ System.arraycopy(modules, 0, newModules, 0, lower);
+ return newModules;
+ }
+
private static PackageSource[] shrinkCandidateArray(PackageSource[] candidates)
{
if (candidates == null)
@@ -1523,30 +1716,33 @@
private static class CandidateSet
{
- public IModule m_module = null;
- public IRequirement m_requirement = null;
- public PackageSource[] m_candidates = null;
+ public static final int NORMAL = 0;
+ public static final int FRAGMENT = 1;
+ public static final int HOST = 2;
+
+ public final int m_type;
+ public final IModule m_module;
+ public final IRequirement m_requirement;
+ public final PackageSource[] m_candidates;
+ public final IModule[] m_modules;
public int m_idx = 0;
- public CandidateSet(IModule module, IRequirement requirement, PackageSource[] candidates)
+
+ public CandidateSet(int type, IModule module, IRequirement requirement, PackageSource[] candidates)
{
+ m_type = type;
m_module = module;
m_requirement = requirement;
m_candidates = candidates;
+ m_modules = null;
}
- }
- // TODO: RESOLVER - This is a hack, we need to calcualte fragments differently.
- public class Result
- {
- public final IModule m_host;
- public final Map m_fragmentMap;
- public final Map m_resolvedModuleWireMap;
-
- public Result(IModule host, Map fragmentMap, Map resolvedModuleWireMap)
+ public CandidateSet(int type, IModule module, IRequirement requirement, IModule[] fragments)
{
- m_host = host;
- m_fragmentMap = fragmentMap;
- m_resolvedModuleWireMap = resolvedModuleWireMap;
+ m_type = type;
+ m_module = module;
+ m_requirement = requirement;
+ m_candidates = null;
+ m_modules = fragments;
}
}
}
\ No newline at end of file