You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by ri...@apache.org on 2010/01/20 17:44:14 UTC
svn commit: r901272 [2/2] - in
/felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix:
framework/ framework/candidateset/ framework/resolver/
framework/searchpolicy/ framework/util/ framework/util/manifestparser/
moduleloader/
Added: felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java?rev=901272&view=auto
==============================================================================
--- felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java (added)
+++ felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java Wed Jan 20 16:44:13 2010
@@ -0,0 +1,949 @@
+/*
+ * 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.resolver;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeSet;
+import org.apache.felix.resolver.CandidateComparator;
+import org.apache.felix.resolver.Module;
+import org.apache.felix.resolver.ResolveException;
+import org.apache.felix.resolver.Resolver;
+import org.apache.felix.resolver.ResolverStateImpl;
+import org.apache.felix.resolver.Wire;
+import org.apache.felix.resolver.cs.Capability;
+import org.apache.felix.resolver.cs.CapabilitySet;
+import org.apache.felix.resolver.cs.Requirement;
+
+// 1. Treat hard pkg constraints separately from implied package constraints
+// 2. Map pkg constraints to a set of capabilities, not a single capability.
+// 3. Uses constraints cannot conflict with other uses constraints, only with hard constraints.
+public class ResolverImpl implements Resolver
+{
+ private static final Map<String, Long> m_invokeCounts = new HashMap<String, Long>();
+ private static boolean m_isInvokeCount = false;
+
+ public ResolverImpl()
+ {
+System.out.println("+++ PROTO3 RESOLVER");
+ String v = System.getProperty("invoke.count");
+ m_isInvokeCount = (v == null) ? false : Boolean.valueOf(v);
+ }
+
+ private final List<Map<Requirement, Set<Capability>>> m_candidatePermutations =
+ new ArrayList<Map<Requirement, Set<Capability>>>();
+
+ public Map<Module, List<Wire>> resolve(ResolverState state, Module module)
+ {
+ if (m_isInvokeCount)
+ {
+ String methodName = new Exception().fillInStackTrace().getStackTrace()[0].getMethodName();
+ Long count = m_invokeCounts.get(methodName);
+ count = (count == null) ? new Long(1) : new Long(count.longValue() + 1);
+ m_invokeCounts.put(methodName, count);
+ }
+
+ Map<Module, Packages> modulePkgMap = new HashMap<Module, Packages>();
+
+ if (!module.isResolved())
+ {
+System.out.println("+++ RESOLVING " + module);
+ Map<Requirement, Set<Capability>> candidateMap =
+ new HashMap<Requirement, Set<Capability>>();
+
+ populateCandidates(state, module, candidateMap, new HashSet<Module>());
+ m_candidatePermutations.add(candidateMap);
+
+ ResolveException rethrow = null;
+
+ do
+ {
+ rethrow = null;
+
+ candidateMap = m_candidatePermutations.remove(0);
+dumpCandidateMap(state, candidateMap);
+
+ try
+ {
+ findConsistentCandidates(
+ module,
+ new ArrayList(),
+ candidateMap,
+ modulePkgMap,
+ new HashMap<Module, Object>());
+ }
+ catch (ResolveException ex)
+ {
+ rethrow = ex;
+ System.out.println("RE: " + ex);
+ }
+ }
+ while ((rethrow != null) && (m_candidatePermutations.size() > 0));
+
+ if (rethrow != null)
+ {
+ throw rethrow;
+ }
+//dumpModulePkgMap(modulePkgMap);
+ }
+
+ Map<Module, List<Wire>> wireMap =
+ populateWireMap(module, modulePkgMap, new HashMap<Module, List<Wire>>());
+
+ if (m_isInvokeCount)
+ {
+ System.out.println("INVOKE COUNTS " + m_invokeCounts);
+ }
+
+ return wireMap;
+ }
+
+ private static void dumpCandidateMap(
+ ResolverState state, Map<Requirement, Set<Capability>> candidateMap)
+ {
+ System.out.println("=== CANDIDATE MAP ===");
+ for (Module module : ((ResolverStateImpl) state).getModules())
+ {
+ if (!module.isResolved())
+ {
+ System.out.println(" " + module);
+ for (Requirement req : module.getRequirements())
+ {
+ Set<Capability> candidates = candidateMap.get(req);
+ if ((candidates != null) && (candidates.size() > 0))
+ {
+ System.out.println(" " + req + ": " + candidates);
+ }
+ }
+ }
+ }
+ }
+
+ private static void dumpModulePkgMap(Map<Module, Packages> modulePkgMap)
+ {
+ System.out.println("+++MODULE PKG MAP+++");
+ for (Entry<Module, Packages> entry : modulePkgMap.entrySet())
+ {
+ dumpModulePkgs(entry.getKey(), entry.getValue());
+ }
+ }
+
+ private static void dumpModulePkgs(Module module, Packages packages)
+ {
+ System.out.println(module + " (" + (module.isResolved() ? "RESOLVED)" : "UNRESOLVED)"));
+ System.out.println(" EXPORTED");
+ for (Entry<String, Blame> entry : packages.m_exportedPkgs.entrySet())
+ {
+ System.out.println(" " + entry.getKey() + " - " + entry.getValue());
+ }
+ System.out.println(" IMPORTED");
+ for (Entry<String, Blame> entry : packages.m_importedPkgs.entrySet())
+ {
+ System.out.println(" " + entry.getKey() + " - " + entry.getValue());
+ }
+ System.out.println(" REQUIRED");
+ for (Entry<String, List<Blame>> entry : packages.m_requiredPkgs.entrySet())
+ {
+ System.out.println(" " + entry.getKey() + " - " + entry.getValue());
+ }
+ System.out.println(" USED");
+ for (Entry<String, List<Blame>> entry : packages.m_usedPkgs.entrySet())
+ {
+ System.out.println(" " + entry.getKey() + " - " + entry.getValue());
+ }
+ }
+
+ private static void populateCandidates(
+ ResolverState state, Module module,
+ Map<Requirement, Set<Capability>> candidateMap, Set<Module> cycles)
+ {
+ if (m_isInvokeCount)
+ {
+ String methodName = new Exception().fillInStackTrace().getStackTrace()[0].getMethodName();
+ Long count = m_invokeCounts.get(methodName);
+ count = (count == null) ? new Long(1) : new Long(count.longValue() + 1);
+ m_invokeCounts.put(methodName, count);
+ }
+
+ // Detect cycles.
+ if (cycles.contains(module))
+ {
+ return;
+ }
+ cycles.add(module);
+
+ // Store candidates in a local map first, just in case the module
+ // is not resolvable.
+ Map<Requirement, Set<Capability>> localCandidateMap = new HashMap();
+
+ // Find candidates for all requirements for the target module.
+ List<Requirement> reqs = module.getRequirements();
+ for (Requirement req : reqs)
+ {
+ Set<Capability> candidates = state.getCandidates(module, req);
+ for (Iterator<Capability> itCandCap = candidates.iterator(); itCandCap.hasNext(); )
+ {
+ Capability candCap = itCandCap.next();
+ if (!candCap.getModule().isResolved())
+ {
+ try
+ {
+ populateCandidates(state, candCap.getModule(), candidateMap, cycles);
+ }
+ catch (ResolveException ex)
+ {
+System.out.println("RE: Candidate not resolveable: " + ex);
+ itCandCap.remove();
+ }
+ }
+ }
+ if ((candidates.size() == 0) && !req.isOptional())
+ {
+ throw new ResolveException("Unable to resolve " + module
+ + ": missing requirement " + req);
+ }
+ else if (candidates.size() > 0)
+ {
+ localCandidateMap.put(req, candidates);
+ }
+ }
+
+ // Put candidates for all requirements into the global candidate map.
+ if (localCandidateMap.size() > 0)
+ {
+ candidateMap.putAll(localCandidateMap);
+ }
+ }
+
+ private void findConsistentCandidates(
+ Module module, List<Requirement> incomingReqs, Map<Requirement, Set<Capability>> candidateMap,
+ Map<Module, Packages> modulePkgMap, Map<Module, Object> cycleMap)
+ {
+ if (m_isInvokeCount)
+ {
+ String methodName = new Exception().fillInStackTrace().getStackTrace()[0].getMethodName();
+ Long count = m_invokeCounts.get(methodName);
+ count = (count == null) ? new Long(1) : new Long(count.longValue() + 1);
+ m_invokeCounts.put(methodName, count);
+ }
+
+ // If the module is in the cycle map, then just return.
+ if (cycleMap.containsKey(module))
+ {
+ return;
+ }
+ cycleMap.put(module, module);
+
+//System.out.println("+++ RESOLVING " + module);
+ calculateExportedPackages(module, incomingReqs, modulePkgMap);
+
+ if (module.isResolved())
+ {
+// Packages pkgs = modulePkgMap.get(module);
+// calculateResolvedPackages(module, incomingReqs, pkgs);
+ for (Wire wire : module.getWires())
+ {
+ // Try to resolve the candidate.
+ findConsistentCandidates(
+ wire.getCapability().getModule(),
+ incomingReqs,
+ candidateMap,
+ modulePkgMap,
+ cycleMap);
+
+ // If we are here, the candidate was consistent. Try to
+ // merge the candidate into the target module's packages.
+ mergeCandidatePackages(
+ module,
+ incomingReqs,
+ wire.getCapability(),
+ modulePkgMap,
+ candidateMap);
+
+ // If we are here, we merged the candidate successfully,
+ // so we can continue with the next requirement
+ break;
+ }
+ }
+ else
+ {
+ List<Requirement> reqs = module.getRequirements();
+ for (Requirement req : reqs)
+ {
+ // Get the candidates for the current requirement.
+ Set<Capability> candCaps = candidateMap.get(req);
+ // Optional requirements may not have any candidates.
+ if (candCaps == null)
+ {
+ continue;
+ }
+
+ List<Requirement> outgoingReqs = new ArrayList<Requirement>(incomingReqs);
+ outgoingReqs.add(req);
+
+ for (Iterator<Capability> it = candCaps.iterator(); it.hasNext(); )
+ {
+ Capability candCap = it.next();
+System.out.println("+++ TRYING CAND " + candCap + " FOR " + req);
+ try
+ {
+ // Try to resolve the candidate.
+ findConsistentCandidates(
+ candCap.getModule(),
+ outgoingReqs,
+ candidateMap,
+ modulePkgMap,
+ cycleMap);
+
+ // If we are here, the candidate was consistent. Try to
+ // merge the candidate into the target module's packages.
+ mergeCandidatePackages(
+ module,
+ outgoingReqs,
+ candCap,
+ modulePkgMap,
+ candidateMap);
+
+ // If we are here, we merged the candidate successfully,
+ // so we can continue with the next requirement
+ break;
+ }
+ catch (ResolveException ex)
+ {
+System.out.println("RE: " + ex);
+ex.printStackTrace();
+// it.remove();
+ if (!it.hasNext() && !req.isOptional())
+ {
+// candidateMap.remove(req);
+ throw new ResolveException("Unresolved constraint "
+ + req + " in " + module);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private static void calculateExportedPackages(
+ Module module, List<Requirement> incomingReqs, Map<Module, Packages> modulePkgMap)
+ {
+ if (m_isInvokeCount)
+ {
+ String methodName = new Exception().fillInStackTrace().getStackTrace()[0].getMethodName();
+ Long count = m_invokeCounts.get(methodName);
+ count = (count == null) ? new Long(1) : new Long(count.longValue() + 1);
+ m_invokeCounts.put(methodName, count);
+ }
+
+ Packages packages = new Packages();
+
+ List<Capability> caps = module.getCapabilities();
+
+ if (caps.size() > 0)
+ {
+ for (int i = 0; i < caps.size(); i++)
+ {
+// TODO: PROTO3 RESOLVER - Assume if a module imports the same package it
+// exports that the import will overlap the export.
+ if (caps.get(i).getNamespace().equals(Capability.PACKAGE_NAMESPACE)
+ && !hasOverlappingImport(module, caps.get(i)))
+ {
+ packages.m_exportedPkgs.put(
+ (String) caps.get(i).getAttribute(Capability.PACKAGE_ATTR).getValue(),
+ new Blame(incomingReqs, caps.get(i)));
+ }
+ }
+ }
+
+ modulePkgMap.put(module, packages);
+ }
+
+ private static boolean hasOverlappingImport(Module module, Capability cap)
+ {
+ if (m_isInvokeCount)
+ {
+ String methodName = new Exception().fillInStackTrace().getStackTrace()[0].getMethodName();
+ Long count = m_invokeCounts.get(methodName);
+ count = (count == null) ? new Long(1) : new Long(count.longValue() + 1);
+ m_invokeCounts.put(methodName, count);
+ }
+
+ List<Requirement> reqs = module.getRequirements();
+ for (int i = 0; i < reqs.size(); i++)
+ {
+ if (reqs.get(i).getNamespace().equals(Capability.PACKAGE_NAMESPACE)
+ && CapabilitySet.matches(cap, reqs.get(i).getFilter()))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void mergeCandidatePackages(
+ Module current, List<Requirement> outgoingReqs,
+ Capability candCap, Map<Module, Packages> modulePkgMap,
+ Map<Requirement, Set<Capability>> candidateMap)
+ {
+ if (m_isInvokeCount)
+ {
+ String methodName = new Exception().fillInStackTrace().getStackTrace()[0].getMethodName();
+ Long count = m_invokeCounts.get(methodName);
+ count = (count == null) ? new Long(1) : new Long(count.longValue() + 1);
+ m_invokeCounts.put(methodName, count);
+ }
+
+ if (candCap.getNamespace().equals(Capability.PACKAGE_NAMESPACE))
+ {
+ mergeCandidatePackage(
+ current, false, new Blame(outgoingReqs, candCap), modulePkgMap, candidateMap);
+ }
+ else if (candCap.getNamespace().equals(Capability.MODULE_NAMESPACE))
+ {
+ // Get the candidate's package space to determine which packages
+ // will be visible to the current module.
+ Packages candPkgs = modulePkgMap.get(candCap.getModule());
+
+// TODO: PROTO3 RESOLVER - For now assume only exports, but eventually we also
+// have to support re-exported packages.
+ for (Entry<String, Blame> entry : candPkgs.m_exportedPkgs.entrySet())
+ {
+ mergeCandidatePackage(
+ current,
+ true,
+ new Blame(outgoingReqs, entry.getValue().m_cap),
+ modulePkgMap,
+ candidateMap);
+ }
+ }
+ }
+
+ private void mergeCandidatePackage(
+ Module current, boolean requires,
+ Blame candBlame, Map<Module, Packages> modulePkgMap,
+ Map<Requirement, Set<Capability>> candidateMap)
+ {
+ if (m_isInvokeCount)
+ {
+ String methodName = new Exception().fillInStackTrace().getStackTrace()[0].getMethodName();
+ Long count = m_invokeCounts.get(methodName);
+ count = (count == null) ? new Long(1) : new Long(count.longValue() + 1);
+ m_invokeCounts.put(methodName, count);
+ }
+
+// TODO: PROTO3 RESOLVER - Check for merging where module imports from itself,
+// then it should be listed as an export.
+ if (candBlame.m_cap.getNamespace().equals(Capability.PACKAGE_NAMESPACE))
+ {
+System.out.println("+++ MERGING " + candBlame.m_cap + " INTO " + current);
+ String pkgName = (String)
+ candBlame.m_cap.getAttribute(Capability.PACKAGE_ATTR).getValue();
+
+ // Since this capability represents a package, it will become
+ // a hard constraint on the module's package space, so we need
+ // to make sure it doesn't conflict with any other hard constraints
+ // or any other uses constraints.
+
+ //
+ // First, check to see if the capability conflicts with
+ // any existing hard constraints.
+ //
+
+ Packages currentPkgs = modulePkgMap.get(current);
+ Blame currentExportedBlame = currentPkgs.m_exportedPkgs.get(pkgName);
+ Blame currentImportedBlame = currentPkgs.m_importedPkgs.get(pkgName);
+ List<Blame> currentRequiredBlames = currentPkgs.m_requiredPkgs.get(pkgName);
+
+ if (!requires &&
+ (((currentExportedBlame != null) && !currentExportedBlame.m_cap.equals(candBlame.m_cap))
+ || ((currentImportedBlame != null) && !currentImportedBlame.m_cap.equals(candBlame.m_cap))
+ || ((currentRequiredBlames != null) && !currentRequiredBlames.contains(candBlame))))
+ {
+ throw new ResolveException("Constraint violation between "
+ + current + " and " + candBlame.m_cap.getModule()
+ + " for " + pkgName);
+ }
+
+ //
+ // Second, check to see if the capability conflicts with
+ // any existing uses constraints
+ //
+
+ Packages currentPkgsCopy = currentPkgs;
+
+ if (!current.isResolved())
+ {
+ List<Blame> currentUsedBlames = currentPkgs.m_usedPkgs.get(pkgName);
+ checkExistingUsesConstraints(
+ current, pkgName, currentUsedBlames, candBlame, modulePkgMap, candidateMap);
+
+ //
+ // Last, check to see if any uses constraints implied by the
+ // candidate conflict with any of the existing hard constraints.
+ //
+
+ // For now, create a copy of the module's package space and
+ // add the current candidate to the imported packages.
+ currentPkgsCopy = new Packages(currentPkgs);
+ }
+
+ if (requires)
+ {
+ if (currentRequiredBlames == null)
+ {
+ currentRequiredBlames = new ArrayList<Blame>();
+ currentPkgsCopy.m_requiredPkgs.put(pkgName, currentRequiredBlames);
+ }
+// TODO: PROTO2 RESOLVER - This is potentially modifying the original, we need to modify a copy.
+ currentRequiredBlames.add(candBlame);
+ }
+ else
+ {
+ currentPkgsCopy.m_importedPkgs.put(pkgName, candBlame);
+ }
+// if not resolved
+ // Verify and merge the candidate's transitive uses constraints.
+ verifyAndMergeUses(
+ current,
+ currentPkgsCopy,
+ candBlame,
+ modulePkgMap,
+ candidateMap,
+ new HashMap<String, List<Module>>());
+
+ // If we are here, then there were no conflict, so we should update
+ // the module's package space.
+ if (!current.isResolved())
+ {
+ currentPkgs.m_exportedPkgs.putAll(currentPkgsCopy.m_exportedPkgs);
+ currentPkgs.m_importedPkgs.putAll(currentPkgsCopy.m_importedPkgs);
+ currentPkgs.m_requiredPkgs.putAll(currentPkgsCopy.m_requiredPkgs);
+ currentPkgs.m_usedPkgs.putAll(currentPkgsCopy.m_usedPkgs);
+ }
+dumpModulePkgs(current, currentPkgs);
+ }
+ }
+
+ private void checkExistingUsesConstraints(
+ Module current, String pkgName, List<Blame> currentUsedBlames,
+ Blame candBlame, Map<Module, Packages> modulePkgMap,
+ Map<Requirement, Set<Capability>> candidateMap)
+ {
+ for (int i = 0; (currentUsedBlames != null) && (i < currentUsedBlames.size()); i++)
+ {
+//System.out.println("+++ CHECK " + candBlame + " IN EXISTING " + currentUsedBlames.get(i));
+ if (!isCompatible(currentUsedBlames.get(i).m_cap, candBlame.m_cap, modulePkgMap))
+ {
+ // Try to remove the previously selected candidate associated
+ // with the requirement blamed for adding the constraint. This
+ // blamed requirement may be null if the bundle itself is
+ // exports the package imposing the uses constraint.
+ if ((currentUsedBlames.get(i).m_reqs != null)
+ && (currentUsedBlames.get(i).m_reqs.size() != 0))
+ {
+ // Permutate the candidate map.
+ for (int reqIdx = 0; reqIdx < currentUsedBlames.get(i).m_reqs.size(); reqIdx++)
+ {
+ Map<Requirement, Set<Capability>> copy = copyCandidateMap(candidateMap);
+ Set<Capability> candidates =
+ copy.get(currentUsedBlames.get(i).m_reqs.get(reqIdx));
+ Iterator it = candidates.iterator();
+ it.next();
+ it.remove();
+// TODO: PROTO3 RESOLVER - We could check before doing the candidate map copy.
+ if (candidates.size() > 0)
+ {
+ m_candidatePermutations.add(copy);
+ }
+ }
+ }
+
+ throw new ResolveException("Constraint violation for package '" + pkgName
+ + "' when resolving module " + current
+ + " between existing constraint "
+ + currentUsedBlames.get(i)
+ + " and candidate constraint "
+ + candBlame);
+ }
+ }
+ }
+
+// TODO: PROTO3 RESOLVER - We end up with duplicates in uses constraints,
+// see scenario 2 for an example.
+ private void verifyAndMergeUses(
+ Module current, Packages currentPkgs,
+ Blame candBlame, Map<Module, Packages> modulePkgMap,
+ Map<Requirement, Set<Capability>> candidateMap,
+ Map<String, List<Module>> cycleMap)
+ {
+ if (m_isInvokeCount)
+ {
+ String methodName = new Exception().fillInStackTrace().getStackTrace()[0].getMethodName();
+ Long count = m_invokeCounts.get(methodName);
+ count = (count == null) ? new Long(1) : new Long(count.longValue() + 1);
+ m_invokeCounts.put(methodName, count);
+ }
+
+ // Check for cycles.
+ String pkgName = (String)
+ candBlame.m_cap.getAttribute(Capability.PACKAGE_ATTR).getValue();
+ List<Module> list = cycleMap.get(pkgName);
+ if ((list != null) && list.contains(current))
+ {
+ return;
+ }
+ list = (list == null) ? new ArrayList<Module>() : list;
+ list.add(current);
+ cycleMap.put(pkgName, list);
+
+//System.out.println("+++ VERIFYING USES " + current + " FOR " + candBlame);
+ for (Capability candSourceCap : getPackageSources(candBlame.m_cap, modulePkgMap, new ArrayList<Capability>()))
+ {
+ for (String usedPkgName : candSourceCap.getUses())
+ {
+ Blame currentExportedBlame = currentPkgs.m_exportedPkgs.get(usedPkgName);
+ Blame currentImportedBlame = currentPkgs.m_importedPkgs.get(usedPkgName);
+// TODO: PROTO3 RESOLVER - What do we do with required packages?
+ List<Blame> currentRequiredBlames = currentPkgs.m_requiredPkgs.get(usedPkgName);
+
+ Packages candSourcePkgs = modulePkgMap.get(candSourceCap.getModule());
+System.out.println("+++ candSourceCap " + candSourceCap);
+System.out.println("+++ candSourceCap.getModule() " + candSourceCap.getModule() + " (" + candSourceCap.getModule().isResolved() + ")");
+System.out.println("+++ candSourcePkgs " + candSourcePkgs);
+System.out.println("+++ candSourcePkgs.m_exportedPkgs " + candSourcePkgs.m_exportedPkgs);
+ Blame candSourceBlame = candSourcePkgs.m_exportedPkgs.get(usedPkgName);
+ candSourceBlame = (candSourceBlame != null)
+ ? candSourceBlame
+ : candSourcePkgs.m_importedPkgs.get(usedPkgName);
+// sourceCap = (sourceCap != null)
+// ? sourceCap
+// : sourcePkgs.m_requiredPkgs.get(usedPkgName);
+
+ // If the candidate doesn't actually have a constraint for
+ // the used package, then just ignore it since this is likely
+ // an error in its metadata.
+ if (candSourceBlame == null)
+ {
+ return;
+ }
+
+ // If there is no current mapping for this package, then
+ // we can just return.
+ if ((currentExportedBlame == null)
+ && (currentImportedBlame == null)
+ && (currentRequiredBlames == null))
+ {
+ List<Blame> usedCaps = currentPkgs.m_usedPkgs.get(usedPkgName);
+ if (usedCaps == null)
+ {
+ usedCaps = new ArrayList<Blame>();
+ currentPkgs.m_usedPkgs.put(usedPkgName, usedCaps);
+ }
+System.out.println("+++ MERGING CB " + candBlame + " SB " + candSourceBlame);
+// usedCaps.add(new Blame(candBlame.m_reqs, sourceBlame.m_cap));
+ usedCaps.add(candSourceBlame);
+ return;
+ }
+ else if (!current.isResolved())
+ {
+ if ((currentExportedBlame != null)
+ && !isCompatible(currentExportedBlame.m_cap, candSourceBlame.m_cap, modulePkgMap))
+ {
+ throw new ResolveException(
+ "Constraint violation for package '" + usedPkgName
+ + "' when resolving module " + current
+ + " between existing constraint "
+ + currentExportedBlame
+ + " and candidate constraint "
+ + candSourceBlame);
+ }
+ else if ((currentImportedBlame != null)
+ && !isCompatible(currentImportedBlame.m_cap, candSourceBlame.m_cap, modulePkgMap))
+ {
+ //System.out.println("+++ CIB " + currentImportedBlame + " SB " + sourceBlame);
+ // Try to remove the previously selected candidate associated
+ // with the requirement blamed for adding the constraint. This
+ // Permutate the candidate map.
+ if (currentImportedBlame.m_reqs.size() != 0)
+ {
+ // Permutate the candidate map.
+ for (int reqIdx = 0; reqIdx < currentImportedBlame.m_reqs.size(); reqIdx++)
+ {
+ Map<Requirement, Set<Capability>> copy = copyCandidateMap(candidateMap);
+ Set<Capability> candidates =
+ copy.get(currentImportedBlame.m_reqs.get(reqIdx));
+ Iterator it = candidates.iterator();
+ it.next();
+ it.remove();
+ // TODO: PROTO3 RESOLVER - We could check before doing the candidate map copy.
+ if (candidates.size() > 0)
+ {
+ m_candidatePermutations.add(copy);
+ }
+ }
+ }
+
+ throw new ResolveException(
+ "Constraint violation for package '" + usedPkgName
+ + "' when resolving module " + current
+ + " between existing constraint "
+ + currentImportedBlame
+ + " and candidate constraint "
+ + candSourceBlame);
+ }
+ }
+ }
+ }
+ }
+
+ private static boolean isCompatible(
+ Capability currentCap, Capability candCap, Map<Module, Packages> modulePkgMap)
+ {
+ if ((currentCap != null) && (candCap != null))
+ {
+ List<Capability> currentSources = getPackageSources(currentCap, modulePkgMap, new ArrayList<Capability>());
+ List<Capability> candSources = getPackageSources(candCap, modulePkgMap, new ArrayList<Capability>());
+//System.out.println("+++ currentSources " + currentSources + " - candSources " + candSources);
+ return currentSources.containsAll(candSources) || candSources.containsAll(currentSources);
+ }
+ return true;
+ }
+
+ private static List<Capability> getPackageSources(
+ Capability cap, Map<Module, Packages> modulePkgMap, List<Capability> sources)
+ {
+ if (cap.getNamespace().equals(Capability.PACKAGE_NAMESPACE))
+ {
+ Packages pkgs = modulePkgMap.get(cap.getModule());
+ sources.add(cap);
+ String pkgName = cap.getAttribute(Capability.PACKAGE_ATTR).getValue().toString();
+ List<Blame> required = pkgs.m_requiredPkgs.get(pkgName);
+ if (required != null)
+ {
+ for (Blame blame : required)
+ {
+ getPackageSources(blame.m_cap, modulePkgMap, sources);
+ }
+ }
+ }
+
+ return sources;
+ }
+
+ private static void calculateResolvedPackages(
+ Module module, List<Requirement> incomingReqs, Packages pkgs)
+ {
+ for (Wire wire : module.getWires())
+ {
+ if (wire.getCapability().getNamespace().equals(Capability.PACKAGE_NAMESPACE))
+ {
+ pkgs.m_importedPkgs.put(
+ (String) wire.getCapability().getAttribute(Capability.PACKAGE_ATTR).getValue(),
+ new Blame(incomingReqs, wire.getCapability()));
+ calculateResolvedUses(wire.getCapability(), pkgs.m_usedPkgs);
+ }
+ else if (wire.getCapability().getNamespace().equals(Capability.MODULE_NAMESPACE))
+ {
+ for (Capability cap : wire.getCapability().getModule().getCapabilities())
+ {
+ if (cap.getNamespace().equals(Capability.PACKAGE_ATTR))
+ {
+ String pkgName = (String) cap.getAttribute(Capability.PACKAGE_ATTR).getValue();
+ List<Blame> requiredBlames = pkgs.m_requiredPkgs.get(pkgName);
+ if (requiredBlames == null)
+ {
+ requiredBlames = new ArrayList<Blame>();
+ pkgs.m_requiredPkgs.put(pkgName, requiredBlames);
+ }
+ requiredBlames.add(new Blame(incomingReqs, cap));
+ calculateResolvedUses(wire.getCapability(), pkgs.m_usedPkgs);
+ }
+ }
+ }
+ }
+ }
+
+ private static void calculateResolvedUses(Capability cap, Map<String, List<Blame>> usedPkgs)
+ {
+ }
+
+ private static Map<Requirement, Set<Capability>> copyCandidateMap(
+ Map<Requirement, Set<Capability>> candidateMap)
+ {
+ Map<Requirement, Set<Capability>> copy =
+ new HashMap<Requirement, Set<Capability>>();
+ for (Entry<Requirement, Set<Capability>> entry : candidateMap.entrySet())
+ {
+ Set<Capability> candidates = new TreeSet(new CandidateComparator());
+ candidates.addAll(entry.getValue());
+ copy.put(entry.getKey(), candidates);
+ }
+ return copy;
+ }
+
+ private static Map<Module, List<Wire>> populateWireMap(
+ Module module, Map<Module, Packages> modulePkgMap,
+ Map<Module, List<Wire>> wireMap)
+ {
+ if (m_isInvokeCount)
+ {
+ String methodName = new Exception().fillInStackTrace().getStackTrace()[0].getMethodName();
+ Long count = m_invokeCounts.get(methodName);
+ count = (count == null) ? new Long(1) : new Long(count.longValue() + 1);
+ m_invokeCounts.put(methodName, count);
+ }
+
+ if (!module.isResolved() && (wireMap.get(module) == null))
+ {
+ List<Wire> moduleWires = new ArrayList<Wire>();
+ wireMap.put(module, moduleWires);
+
+ Packages pkgs = modulePkgMap.get(module);
+ for (Entry<String, Blame> entry : pkgs.m_importedPkgs.entrySet())
+ {
+ if (!entry.getValue().m_cap.getModule().isResolved())
+ {
+ populateWireMap(entry.getValue().m_cap.getModule(), modulePkgMap, wireMap);
+ }
+
+ // Ignore modules that import themselves.
+ if (!module.equals(entry.getValue().m_cap.getModule()))
+ {
+ moduleWires.add(
+ new Wire(module,
+ entry.getValue().m_reqs.get(entry.getValue().m_reqs.size() - 1),
+ entry.getValue().m_cap.getModule(),
+ entry.getValue().m_cap));
+ }
+ }
+ List<Requirement> rbReqs = new ArrayList<Requirement>();
+ for (Requirement req : module.getRequirements())
+ {
+ if (req.getNamespace().equals(Capability.MODULE_NAMESPACE))
+ {
+ rbReqs.add(req);
+ }
+ }
+ if (!rbReqs.isEmpty())
+ {
+ Map<Requirement, Capability> rbMap = new HashMap<Requirement, Capability>();
+ for (Entry<String, List<Blame>> entry : pkgs.m_requiredPkgs.entrySet())
+ {
+ for (Blame blame : entry.getValue())
+ {
+ for (Requirement rbReq : rbReqs)
+ {
+ if (blame.m_reqs.get(blame.m_reqs.size() - 1).equals(rbReq))
+ {
+ rbMap.put(rbReq, getModuleCapability(blame.m_cap.getModule()));
+ if (!blame.m_cap.getModule().isResolved())
+ {
+ populateWireMap(
+ blame.m_cap.getModule(), modulePkgMap, wireMap);
+ }
+ break;
+ }
+ }
+ }
+
+ // Ignore modules that import themselves.
+ for (Entry<Requirement, Capability> rbEntry : rbMap.entrySet())
+ {
+ if (!module.equals(rbEntry.getValue().getModule()))
+ {
+ moduleWires.add(
+ new Wire(module,
+ rbEntry.getKey(),
+ rbEntry.getValue().getModule(),
+ rbEntry.getValue()));
+ }
+ }
+ }
+ }
+ }
+ return wireMap;
+ }
+
+ private static Capability getModuleCapability(Module module)
+ {
+ for (Capability cap : module.getCapabilities())
+ {
+ if (cap.getNamespace().equals(Capability.MODULE_NAMESPACE))
+ {
+ return cap;
+ }
+ }
+ return null;
+ }
+
+ private static class Packages
+ {
+ public final Map<String, Blame> m_exportedPkgs
+ = new HashMap<String, Blame>();
+ public final Map<String, Blame> m_importedPkgs
+ = new HashMap<String, Blame>();
+ public final Map<String, List<Blame>> m_requiredPkgs
+ = new HashMap<String, List<Blame>>();
+ public final Map<String, List<Blame>> m_usedPkgs
+ = new HashMap<String, List<Blame>>();
+
+ public Packages()
+ {
+ }
+
+ public Packages(Packages packages)
+ {
+ m_exportedPkgs.putAll(packages.m_exportedPkgs);
+ m_importedPkgs.putAll(packages.m_importedPkgs);
+ m_requiredPkgs.putAll(packages.m_requiredPkgs);
+ m_usedPkgs.putAll(packages.m_usedPkgs);
+ }
+ }
+
+ private static class Blame
+ {
+ public final List<Requirement> m_reqs;
+ public final Capability m_cap;
+
+ public Blame(List<Requirement> reqs, Capability cap)
+ {
+ m_reqs = reqs;
+ m_cap = cap;
+ }
+
+ public String toString()
+ {
+ return m_cap.getModule() + "." + m_cap.getAttribute(Capability.PACKAGE_ATTR).getValue()
+ + " BLAMED ON " + m_reqs;
+ }
+
+ public boolean equals(Object o)
+ {
+ return (o instanceof Blame) && m_reqs.equals(((Blame) o).m_reqs)
+ && m_cap.equals(((Blame) o).m_cap);
+ }
+ }
+}
\ No newline at end of file
Added: felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/resolver/ResolverStateImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/resolver/ResolverStateImpl.java?rev=901272&view=auto
==============================================================================
--- felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/resolver/ResolverStateImpl.java (added)
+++ felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/resolver/ResolverStateImpl.java Wed Jan 20 16:44:13 2010
@@ -0,0 +1,101 @@
+/*
+ * 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.resolver;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+import org.apache.felix.resolver.Resolver.ResolverState;
+import org.apache.felix.resolver.cs.Capability;
+import org.apache.felix.resolver.cs.CapabilitySet;
+import org.apache.felix.resolver.cs.Requirement;
+import org.apache.felix.resolver.manifestparser.Constants;
+
+public class ResolverStateImpl implements ResolverState
+{
+ private final List<Module> m_modules;
+ private final CapabilitySet m_pkgCapSet;
+ private final CapabilitySet m_modCapSet;
+
+ public ResolverStateImpl(List<Module> modules)
+ {
+ m_modules = modules;
+
+ List indices = new ArrayList();
+ indices.add(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE);
+ m_modCapSet = new CapabilitySet(indices);
+
+ indices = new ArrayList();
+ indices.add(Capability.PACKAGE_ATTR);
+ m_pkgCapSet = new CapabilitySet(indices);
+
+ for (int modIdx = 0; modIdx < m_modules.size(); modIdx++)
+ {
+ List<Capability> caps = m_modules.get(modIdx).getCapabilities();
+ for (int capIdx = 0; capIdx < caps.size(); capIdx++)
+ {
+ if (caps.get(capIdx).getNamespace().equals(Capability.MODULE_NAMESPACE))
+ {
+ m_modCapSet.addCapability(caps.get(capIdx));
+ }
+ else if (caps.get(capIdx).getNamespace().equals(Capability.PACKAGE_NAMESPACE))
+ {
+ m_pkgCapSet.addCapability(caps.get(capIdx));
+ }
+ else
+ {
+ System.err.println(
+ "Ignoring unknown capability: " + caps.get(capIdx).getNamespace());
+ }
+ }
+ }
+ }
+
+ public List<Module> getModules()
+ {
+ return m_modules;
+ }
+
+ public Set<Capability> getCandidates(Module module, Requirement req)
+ {
+ return getUnresolvedCandidates(module, req);
+ }
+
+ private Set<Capability> getUnresolvedCandidates(Module module, Requirement req)
+ {
+ Set<Capability> result = new TreeSet(new CandidateComparator());
+
+ if (req.getNamespace().equals(Capability.MODULE_NAMESPACE))
+ {
+ result.addAll(m_modCapSet.match(req.getFilter()));
+ }
+ else if (req.getNamespace().equals(Capability.PACKAGE_NAMESPACE))
+ {
+ result.addAll(m_pkgCapSet.match(req.getFilter()));
+ }
+
+ return result;
+ }
+
+ private Set<Capability> getResolvedCandidates(Module module, Requirement req)
+ {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+}
\ No newline at end of file
Added: felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/resolver/StatefulResolver.java
URL: http://svn.apache.org/viewvc/felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/resolver/StatefulResolver.java?rev=901272&view=auto
==============================================================================
--- felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/resolver/StatefulResolver.java (added)
+++ felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/resolver/StatefulResolver.java Wed Jan 20 16:44:13 2010
@@ -0,0 +1,74 @@
+/*
+ * 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.resolver;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+public class StatefulResolver
+{
+ private final Resolver m_resolver;
+ private final ResolverStateImpl m_state;
+
+ public StatefulResolver(Resolver resolver, ResolverStateImpl state)
+ {
+ m_resolver = resolver;
+ m_state = state;
+ }
+
+ public ResolverStateImpl getState()
+ {
+ return m_state;
+ }
+
+ public void resolve(Module module)
+ {
+ System.out.println("Target: " + module + " (" + module.getRequirements().size() + ")");
+ long starttime = System.currentTimeMillis();
+ Map<Module, List<Wire>> wireMap = m_resolver.resolve(m_state, module);
+ long endtime = System.currentTimeMillis();
+ System.out.println("Resolve time: " + (endtime - starttime));
+ System.out.println("Modules resolved: " + wireMap.size());
+
+ // Mark all modules as resolved.
+ markResolvedModules(wireMap);
+ }
+
+ private void markResolvedModules(Map<Module, List<Wire>> wireMap)
+ {
+ if (wireMap != null)
+ {
+ // Iterate over the map to mark the modules as resolved and
+ // update our resolver data structures.
+ for (Entry<Module, List<Wire>> entry : wireMap.entrySet())
+ {
+ // 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.
+ List<Wire> wires = entry.getValue();
+ for (int wireIdx = 0; wireIdx < wires.size(); wireIdx++)
+ {
+ System.out.println("WIRE: " + wires.get(wireIdx));
+ }
+ entry.getKey().resolve(wires);
+ }
+ }
+ }
+}
\ No newline at end of file
Modified: felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/util/Util.java
URL: http://svn.apache.org/viewvc/felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/util/Util.java?rev=901272&r1=901271&r2=901272&view=diff
==============================================================================
--- felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/util/Util.java (original)
+++ felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/util/Util.java Wed Jan 20 16:44:13 2010
@@ -25,9 +25,12 @@
import java.util.List;
import java.util.Map;
import java.util.Properties;
+import org.apache.felix.framework.candidateset.Capability;
+import org.apache.felix.framework.candidateset.CapabilitySet;
+import org.apache.felix.framework.candidateset.Module;
+import org.apache.felix.framework.candidateset.Requirement;
+import org.apache.felix.framework.candidateset.Wire;
-import org.apache.felix.framework.util.manifestparser.Capability;
-import org.apache.felix.moduleloader.*;
import org.osgi.framework.Bundle;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
@@ -229,15 +232,15 @@
return allow;
}
- public static ICapability getSatisfyingCapability(IModule m, IRequirement req)
+ public static Capability getSatisfyingCapability(Module m, Requirement req)
{
- ICapability[] caps = m.getCapabilities();
- for (int i = 0; (caps != null) && (i < caps.length); i++)
+ List<Capability> caps = m.getCapabilities();
+ for (int i = 0; (caps != null) && (i < caps.size()); i++)
{
- if (caps[i].getNamespace().equals(req.getNamespace()) &&
- req.isSatisfied(caps[i]))
+ if (caps.get(i).getNamespace().equals(req.getNamespace())
+ && CapabilitySet.matches(caps.get(i), req.getFilter()))
{
- return caps[i];
+ return caps.get(i);
}
}
return null;
@@ -250,29 +253,29 @@
* @param namespace capability namespace
* @return array of matching capabilities or empty if none found
*/
- public static ICapability[] getCapabilityByNamespace(IModule module, String namespace)
+ public static List<Capability> getCapabilityByNamespace(Module module, String namespace)
{
- final List matching = new ArrayList();
- final ICapability[] caps = module.getCapabilities();
- for (int capIdx = 0; (caps != null) && (capIdx < caps.length); capIdx++)
+ final List<Capability> matching = new ArrayList();
+ final List<Capability> caps = module.getCapabilities();
+ for (int capIdx = 0; (caps != null) && (capIdx < caps.size()); capIdx++)
{
- if (caps[capIdx].getNamespace().equals(namespace))
+ if (caps.get(capIdx).getNamespace().equals(namespace))
{
- matching.add(caps[capIdx]);
+ matching.add(caps.get(capIdx));
}
}
- return (ICapability[]) matching.toArray(new ICapability[matching.size()]);
+ return matching;
}
- public static IWire getWire(IModule m, String name)
+ public static Wire getWire(Module m, String name)
{
- IWire[] wires = m.getWires();
- for (int i = 0; (wires != null) && (i < wires.length); i++)
+ List<Wire> wires = m.getWires();
+ for (int i = 0; (wires != null) && (i < wires.size()); i++)
{
- if (wires[i].getCapability().getNamespace().equals(ICapability.PACKAGE_NAMESPACE) &&
- ((Capability) wires[i].getCapability()).getPackageName().equals(name))
+ if (wires.get(i).getCapability().getNamespace().equals(Capability.PACKAGE_NAMESPACE) &&
+ wires.get(i).getCapability().getAttribute(Capability.PACKAGE_ATTR).getValue().equals(name))
{
- return wires[i];
+ return wires.get(i);
}
}
return null;
@@ -522,13 +525,12 @@
* @return <code>true</code> if the module declares a fragment host, <code>false</code>
* otherwise.
*/
- public static boolean isFragment(IModule module)
+ public static boolean isFragment(Module module)
{
Map headerMap = module.getHeaders();
return headerMap.containsKey(Constants.FRAGMENT_HOST);
}
-
//
// The following substring-related code was lifted and modified
// from the LDAP parser code.
Modified: felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java
URL: http://svn.apache.org/viewvc/felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java?rev=901272&r1=901271&r2=901272&view=diff
==============================================================================
--- felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java (original)
+++ felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java Wed Jan 20 16:44:13 2010
@@ -736,18 +736,18 @@
* @return <tt>null</tt> if there are no native libraries, a zero-length
* array if no libraries matched, or an array of selected libraries.
**/
- public R4Library[] getLibraries()
+ public List<R4Library> getLibraries()
{
- R4Library[] libs = null;
+ ArrayList<R4Library> libs = null;
try
{
R4LibraryClause clause = getSelectedLibraryClause();
if (clause != null)
{
String[] entries = clause.getLibraryEntries();
- libs = new R4Library[entries.length];
+ libs = new ArrayList<R4Library>(entries.length);
int current = 0;
- for (int i = 0; i < libs.length; i++)
+ for (int i = 0; i < libs.size(); i++)
{
String name = getName(entries[i]);
boolean found = false;
@@ -757,23 +757,18 @@
}
if (!found)
{
- libs[current++] = new R4Library(
+ libs.add(new R4Library(
clause.getLibraryEntries()[i],
clause.getOSNames(), clause.getProcessors(), clause.getOSVersions(),
- clause.getLanguages(), clause.getSelectionFilter());
+ clause.getLanguages(), clause.getSelectionFilter()));
}
}
- if (current < libs.length)
- {
- R4Library[] tmp = new R4Library[current];
- System.arraycopy(libs, 0, tmp, 0, current);
- libs = tmp;
- }
+ libs.trimToSize();
}
}
catch (Exception ex)
{
- libs = new R4Library[0];
+ libs = new ArrayList<R4Library>(0);
}
return libs;
}
Added: felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/util/manifestparser/ParsedHeaderClause.java
URL: http://svn.apache.org/viewvc/felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/util/manifestparser/ParsedHeaderClause.java?rev=901272&view=auto
==============================================================================
--- felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/util/manifestparser/ParsedHeaderClause.java (added)
+++ felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/util/manifestparser/ParsedHeaderClause.java Wed Jan 20 16:44:13 2010
@@ -0,0 +1,37 @@
+/*
+ * 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.util.manifestparser;
+
+import java.util.List;
+import org.apache.felix.framework.candidateset.Attribute;
+import org.apache.felix.framework.candidateset.Directive;
+
+public class ParsedHeaderClause
+{
+ public final List<String> m_paths;
+ public final List<Directive> m_dirs;
+ public final List<Attribute> m_attrs;
+
+ public ParsedHeaderClause(List<String> paths, List<Directive> dirs, List<Attribute> attrs)
+ {
+ m_paths = paths;
+ m_dirs = dirs;
+ m_attrs = attrs;
+ }
+}
\ No newline at end of file