diff options
2 files changed, 218 insertions, 100 deletions
diff --git a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/GroupingChecker.java b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/GroupingChecker.java index 6b81d05c7..0f196d173 100644 --- a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/GroupingChecker.java +++ b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/GroupingChecker.java @@ -33,14 +33,14 @@ public class GroupingChecker { for (int j = 0; j < requires.length; j++) { ResolverBundle selectedSupplier = (ResolverBundle) requires[j].getSelectedSupplier(); if (selectedSupplier != null) - isConsistentInternal(bundle, selectedSupplier, new ArrayList(1), true); + isConsistentInternal(bundle, selectedSupplier, new ArrayList(1), true, null); } // process all imports ResolverImport[] imports = bundle.getImportPackages(); for (int j = 0; j < imports.length; j++) { ResolverExport selectedSupplier = (ResolverExport) imports[j].getSelectedSupplier(); if (selectedSupplier != null) - isConsistentInternal(bundle, selectedSupplier, true); + isConsistentInternal(bundle, selectedSupplier, true, null); } } @@ -48,25 +48,22 @@ public class GroupingChecker { * Verifies the uses constraint consistency for the requiringBundle with the possible matching bundle. * If an inconsistency is found the export inconsistency is returned; otherwise null is returned */ - public ResolverExport isConsistent(ResolverBundle requiringBundle, ResolverBundle matchingBundle) { - ResolverExport inConsistentExport = isConsistentInternal(requiringBundle, matchingBundle, new ArrayList(1), false); - if (inConsistentExport != null) - return inConsistentExport; - return null; + public PackageRoots[][] isConsistent(ResolverBundle requiringBundle, ResolverBundle matchingBundle) { + ArrayList results = isConsistentInternal(requiringBundle, matchingBundle, new ArrayList(1), false, null); + return results == null ? null : (PackageRoots[][]) results.toArray(new PackageRoots[results.size()][]); } - private ResolverExport isConsistentInternal(ResolverBundle requiringBundle, ResolverBundle matchingBundle, ArrayList visited, boolean dynamicImport) { + private ArrayList isConsistentInternal(ResolverBundle requiringBundle, ResolverBundle matchingBundle, ArrayList visited, boolean dynamicImport, ArrayList results) { // needed to prevent endless cycles if (visited.contains(matchingBundle)) - return null; + return results; visited.add(matchingBundle); // check that the packages exported by the matching bundle are consistent ResolverExport[] matchingExports = matchingBundle.getExportPackages(); for (int i = 0; i < matchingExports.length; i++) { if (matchingExports[i].isDropped()) continue; - if (!isConsistentInternal(requiringBundle, matchingExports[i], dynamicImport)) - return matchingExports[i]; + results = isConsistentInternal(requiringBundle, matchingExports[i], dynamicImport, results); } // check that the packages from reexported bundles are consistent BundleConstraint[] supplierRequires = matchingBundle.getRequires(); @@ -74,52 +71,47 @@ public class GroupingChecker { ResolverBundle reexported = (ResolverBundle) supplierRequires[j].getSelectedSupplier(); if (reexported == null || !((BundleSpecification) supplierRequires[j].getVersionConstraint()).isExported()) continue; - ResolverExport inConsistentExport = isConsistentInternal(requiringBundle, reexported, visited, dynamicImport); - if (inConsistentExport != null) - return inConsistentExport; + results = isConsistentInternal(requiringBundle, reexported, visited, dynamicImport, results); } - return null; + return results; } /* * Verifies the uses constraint consistency for the importingBundle with the possible matching export. * If an inconsistency is found the export returned; otherwise null is returned */ - public ResolverExport isConsistent(ResolverBundle importingBundle, ResolverExport matchingExport) { - if (!isConsistentInternal(importingBundle, matchingExport, false)) - return matchingExport; - return null; + public PackageRoots[][] isConsistent(ResolverBundle importingBundle, ResolverExport matchingExport) { + ArrayList results = isConsistentInternal(importingBundle, matchingExport, false, null); + return results == null ? null : (PackageRoots[][]) results.toArray(new PackageRoots[results.size()][]); } /* - * Verifies the uses constraint consistency for the importingBundle with the possible dynamioc matching export. + * Verifies the uses constraint consistency for the importingBundle with the possible dynamic matching export. * If an inconsistency is found the export returned; otherwise null is returned. * Dynamic imports must perform extra checks to ensure that existing wires to package roots are * consistent with the possible matching dynamic export. */ - public ResolverExport isDynamicConsistent(ResolverBundle importingBundle, ResolverExport matchingExport) { - if (!isConsistentInternal(importingBundle, matchingExport, true)) - return matchingExport; - return null; + public PackageRoots[][] isDynamicConsistent(ResolverBundle importingBundle, ResolverExport matchingExport) { + ArrayList results = isConsistentInternal(importingBundle, matchingExport, true, null); + return results == null ? null : (PackageRoots[][]) results.toArray(new PackageRoots[results.size()][]); } - private boolean isConsistentInternal(ResolverBundle importingBundle, ResolverExport matchingExport, boolean dyanamicImport) { + private ArrayList isConsistentInternal(ResolverBundle importingBundle, ResolverExport matchingExport, boolean dyanamicImport, ArrayList results) { PackageRoots exportingRoots = getPackageRoots(matchingExport.getExporter(), matchingExport.getName(), null); // check that the exports uses packages are consistent with existing package roots - if (!exportingRoots.isConsistentClassSpace(importingBundle, null)) - return false; + results = exportingRoots.isConsistentClassSpace(importingBundle, null, results); if (!dyanamicImport) - return true; + return results; // for dynamic imports we must check that each existing root is consistent with the possible matching export PackageRoots importingRoots = getPackageRoots(importingBundle, matchingExport.getName(), null); HashMap importingPackages = (HashMap) bundles.get(importingBundle); if (importingPackages != null) for (Iterator allImportingPackages = importingPackages.values().iterator(); allImportingPackages.hasNext();) { PackageRoots roots = (PackageRoots) allImportingPackages.next(); - if (roots != importingRoots && !roots.isConsistentClassSpace(exportingRoots, null)) - return false; + if (roots != importingRoots) + results = roots.isConsistentClassSpace(exportingRoots, null, results); } - return true; + return results; } /* @@ -216,11 +208,11 @@ public class GroupingChecker { bundles.clear(); } - public void remove(ResolverBundle rb) { + public void clear(ResolverBundle rb) { bundles.remove(rb); } - private class PackageRoots { + class PackageRoots { private String name; private ResolverBundle bundle; private ResolverExport[] roots; @@ -271,9 +263,9 @@ public class GroupingChecker { addRoot(packageRoots.roots[i]); } - public boolean isConsistentClassSpace(ResolverBundle importingBundle, ArrayList visited) { + public ArrayList isConsistentClassSpace(ResolverBundle importingBundle, ArrayList visited, ArrayList results) { if (roots == null) - return true; + return results; int size = roots.length; for (int i = 0; i < size; i++) { ResolverExport root = roots[i]; @@ -283,7 +275,7 @@ public class GroupingChecker { if (visited == null) visited = new ArrayList(1); if (visited.contains(this)) - return true; + return results; visited.add(this); for (int j = 0; j < uses.length; j++) { if (uses[j].equals(root.getName())) @@ -291,21 +283,23 @@ public class GroupingChecker { PackageRoots thisUsedRoots = getPackageRoots(root.getExporter(), uses[j], null); PackageRoots importingUsedRoots = getPackageRoots(importingBundle, uses[j], null); if (thisUsedRoots == importingUsedRoots) - return true; + return results; if (thisUsedRoots != nullPackageRoots && importingUsedRoots != nullPackageRoots) - if (!(subSet(thisUsedRoots.roots, importingUsedRoots.roots) || subSet(importingUsedRoots.roots, thisUsedRoots.roots))) - return false; + if (!(subSet(thisUsedRoots.roots, importingUsedRoots.roots) || subSet(importingUsedRoots.roots, thisUsedRoots.roots))) { + if (results == null) + results = new ArrayList(1); + results.add(new PackageRoots[] {this, importingUsedRoots}); + } // need to check the usedRoots consistency for transitive closure - if (!thisUsedRoots.isConsistentClassSpace(importingBundle, visited)) - return false; + results = thisUsedRoots.isConsistentClassSpace(importingBundle, visited, results); } } - return true; + return results; } - public boolean isConsistentClassSpace(PackageRoots exportingRoots, ArrayList visited) { + public ArrayList isConsistentClassSpace(PackageRoots exportingRoots, ArrayList visited, ArrayList results) { if (roots == null) - return true; + return results; int size = roots.length; for (int i = 0; i < size; i++) { ResolverExport root = roots[i]; @@ -315,7 +309,7 @@ public class GroupingChecker { if (visited == null) visited = new ArrayList(1); if (visited.contains(this)) - return true; + return results; visited.add(this); for (int j = 0; j < uses.length; j++) { if (uses[j].equals(root.getName()) || !uses[j].equals(exportingRoots.name)) @@ -323,16 +317,18 @@ public class GroupingChecker { PackageRoots thisUsedRoots = getPackageRoots(root.getExporter(), uses[j], null); PackageRoots exportingUsedRoots = getPackageRoots(exportingRoots.bundle, uses[j], null); if (thisUsedRoots == exportingRoots) - return true; + return results; if (thisUsedRoots != nullPackageRoots && exportingUsedRoots != nullPackageRoots) - if (!(subSet(thisUsedRoots.roots, exportingUsedRoots.roots) || subSet(exportingUsedRoots.roots, thisUsedRoots.roots))) - return false; + if (!(subSet(thisUsedRoots.roots, exportingUsedRoots.roots) || subSet(exportingUsedRoots.roots, thisUsedRoots.roots))) { + if (results == null) + results = new ArrayList(1); + results.add(new PackageRoots[] {this, exportingUsedRoots}); + } // need to check the usedRoots consistency for transitive closure - if (!thisUsedRoots.isConsistentClassSpace(exportingRoots, visited)) - return false; + results = thisUsedRoots.isConsistentClassSpace(exportingRoots, visited, results); } } - return true; + return results; } // TODO this is a behavioral change; before we only required 1 supplier to match; now roots must be subsets @@ -354,5 +350,13 @@ public class GroupingChecker { public boolean superSet(PackageRoots subSet) { return subSet(roots, subSet.roots); } + + public String getName() { + return name; + } + + public ResolverExport[] getRoots() { + return roots; + } } } diff --git a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/ResolverImpl.java b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/ResolverImpl.java index 75bb95f5e..2b9c5559d 100644 --- a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/ResolverImpl.java +++ b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/ResolverImpl.java @@ -12,6 +12,7 @@ import java.util.*; import org.eclipse.osgi.framework.adaptor.FrameworkAdaptor; import org.eclipse.osgi.framework.debug.Debug; import org.eclipse.osgi.framework.debug.FrameworkDebugOptions; +import org.eclipse.osgi.internal.module.GroupingChecker.PackageRoots; import org.eclipse.osgi.internal.resolver.BundleDescriptionImpl; import org.eclipse.osgi.internal.resolver.ExportPackageDescriptionImpl; import org.eclipse.osgi.service.resolver.*; @@ -35,6 +36,8 @@ public class ResolverImpl implements org.eclipse.osgi.service.resolver.Resolver public static boolean DEBUG_GENERICS = false; public static boolean DEBUG_GROUPING = false; public static boolean DEBUG_CYCLES = false; + private static int MAX_MULTIPLE_SUPPLIERS_MERGE = 10; + private static int MAX_MULTIPLE_SUPPLERS=25; private static String[][] CURRENT_EES; @@ -484,8 +487,7 @@ public class ResolverImpl implements org.eclipse.osgi.service.resolver.Resolver } private void checkUsesConstraints(ResolverBundle[] bundles, Dictionary[] platformProperties, ArrayList rejectedSingletons) { - ResolverConstraint[] multipleSuppliers = getMultipleSuppliers(bundles); - ArrayList conflictingConstraints = findBestCombination(bundles, multipleSuppliers); + ArrayList conflictingConstraints = findBestCombination(bundles); Set conflictedBundles = null; if (conflictingConstraints != null) { for (Iterator conflicts = conflictingConstraints.iterator(); conflicts.hasNext();) { @@ -522,37 +524,45 @@ public class ResolverImpl implements org.eclipse.osgi.service.resolver.Resolver } } - private ArrayList findBestCombination(ResolverBundle[] bundles, ResolverConstraint[] multipleSuppliers) { - int[] bestCombination = new int[multipleSuppliers.length]; + private ArrayList findBestCombination(ResolverBundle[] bundles) { + HashSet bundleConstraints = new HashSet(); + HashSet packageConstraints = new HashSet(); + // first tryout the initial selections + ArrayList initialConflicts = getConflicts(bundles, packageConstraints, bundleConstraints); + if (initialConflicts == null) { + groupingChecker.clear(); + return null; // the first selected have no conflicts; return without iterating over all combinations + } + ResolverConstraint[][] multipleSuppliers = getMultipleSuppliers(bundles, packageConstraints, bundleConstraints); ArrayList conflictingBundles = null; - if (multipleSuppliers.length > 0) { - conflictingBundles = findBestCombination(bundles, multipleSuppliers, bestCombination); - for (int i = 0; i < bestCombination.length; i++) - multipleSuppliers[i].setSelectedSupplier(bestCombination[i]); + if (multipleSuppliers.length > 0 && multipleSuppliers.length < MAX_MULTIPLE_SUPPLERS) { + int[] bestCombination = new int[multipleSuppliers.length]; + conflictingBundles = findBestCombination(bundles, multipleSuppliers, bestCombination, initialConflicts); + for (int i = 0; i < bestCombination.length; i++) { + for (int j = 0; j < multipleSuppliers[i].length; j++) + multipleSuppliers[i][j].setSelectedSupplier(bestCombination[i]); + } } else { - conflictingBundles = getConflicts(bundles); + // either there are no multiple suppliers or the multiple suppliers list is way to big to process in a timely manner. + conflictingBundles = initialConflicts; } // do not need to keep uses data in memory groupingChecker.clear(); return conflictingBundles; } - private void getCombination(ResolverConstraint[] multipleSuppliers, int[] combination) { + private void getCombination(ResolverConstraint[][] multipleSuppliers, int[] combination) { for (int i = 0; i < combination.length; i++) - combination[i] = multipleSuppliers[i].getSelectedSupplierIndex(); + combination[i] = multipleSuppliers[i][0].getSelectedSupplierIndex(); } - private ArrayList findBestCombination(ResolverBundle[] bundles, ResolverConstraint[] multipleSuppliers, int[] bestCombination) { - // first tryout all zeros - ArrayList bestConflicts = getConflicts(bundles); - if (bestConflicts == null) - return null; // the first selected have no conflicts; return without iterating over all combinations + private ArrayList findBestCombination(ResolverBundle[] bundles, ResolverConstraint[][] multipleSuppliers, int[] bestCombination, ArrayList bestConflicts) { // now iterate over every possible combination until either zero conflicts are found // or we have run out of combinations // if all combinations are tried then return the combination with the lowest number of conflicts int bestConflictCount = getConflictCount(bestConflicts); while (bestConflictCount != 0 && getNextCombination(multipleSuppliers)) { - ArrayList conflicts = getConflicts(bundles); + ArrayList conflicts = getConflicts(bundles, null, null); int conflictCount = getConflictCount(conflicts); if (conflictCount < bestConflictCount) { bestConflictCount = conflictCount; @@ -563,15 +573,16 @@ public class ResolverImpl implements org.eclipse.osgi.service.resolver.Resolver return bestConflicts; } - private boolean getNextCombination(ResolverConstraint[] multipleSuppliers) { - if (multipleSuppliers[0].selectNextSupplier()) - return true; // the current slot has a next supplier - multipleSuppliers[0].setSelectedSupplier(0); // reset first slot - int current = 1; + private boolean getNextCombination(ResolverConstraint[][] multipleSuppliers) { + int current = 0; while (current < multipleSuppliers.length) { - if (multipleSuppliers[current].selectNextSupplier()) - return true; - multipleSuppliers[current].setSelectedSupplier(0); // reset the current slot + if (multipleSuppliers[current][0].selectNextSupplier()) { + for (int i = 1; i < multipleSuppliers[current].length; i++) + multipleSuppliers[current][i].selectNextSupplier(); + return true; // the current slot has a next supplier + } + for (int i = 0; i < multipleSuppliers[current].length; i++) + multipleSuppliers[current][i].setSelectedSupplier(0); // reset the current slot current++; // move to the next slot } return false; @@ -588,55 +599,84 @@ public class ResolverImpl implements org.eclipse.osgi.service.resolver.Resolver return result; } - private ArrayList getConflicts(ResolverBundle[] bundles) { + private ArrayList getConflicts(ResolverBundle[] bundles, HashSet packageConstraints, HashSet bundleConstraints) { groupingChecker.clear(); ArrayList conflicts = null; - bundlesLoop: for (int i = 0; i < bundles.length; i++) { + for (int i = 0; i < bundles.length; i++) { + boolean foundConflict = false; BundleConstraint[] requires = bundles[i].getRequires(); for (int j = 0; j < requires.length; j++) { ResolverBundle selectedSupplier = (ResolverBundle) requires[j].getSelectedSupplier(); - ResolverExport conflict = selectedSupplier == null ? null : groupingChecker.isConsistent(bundles[i], selectedSupplier); + PackageRoots[][] conflict = selectedSupplier == null ? null : groupingChecker.isConsistent(bundles[i], selectedSupplier); if (conflict != null) { - if (conflicts == null) - conflicts = new ArrayList(1); - conflicts.add(requires[j]); - // continue on for optonal conflicts because we don't count them - if (!requires[j].isOptional()) - continue bundlesLoop; + addConflictNames(conflict, packageConstraints, bundleConstraints); + if (!foundConflict) { + if (conflicts == null) + conflicts = new ArrayList(1); + conflicts.add(requires[j]); + foundConflict = true; + } } } ResolverImport[] imports = bundles[i].getImportPackages(); for (int j = 0; j < imports.length; j++) { ResolverExport selectedSupplier = (ResolverExport) imports[j].getSelectedSupplier(); - ResolverExport conflict = selectedSupplier == null ? null : groupingChecker.isConsistent(bundles[i], selectedSupplier); + PackageRoots[][] conflict = selectedSupplier == null ? null : groupingChecker.isConsistent(bundles[i], selectedSupplier); if (conflict != null) { - if (conflicts == null) - conflicts = new ArrayList(1); - conflicts.add(imports[j]); - // continue on for optional conflicts because we don't count them - if (!imports[j].isOptional()) - continue bundlesLoop; + addConflictNames(conflict, packageConstraints, bundleConstraints); + if (!foundConflict) { + if (conflicts == null) + conflicts = new ArrayList(1); + conflicts.add(imports[j]); + foundConflict = true; + } } } } return conflicts; } + // records the conflict names we can use to scope down the list of multiple suppliers + private void addConflictNames(PackageRoots[][] conflict, HashSet packageConstraints, HashSet bundleConstraints) { + if (packageConstraints == null || bundleConstraints == null) + return; + for (int i = 0; i < conflict.length; i++) { + packageConstraints.add(conflict[i][0].getName()); + packageConstraints.add(conflict[i][1].getName()); + ResolverExport[] exports0 = conflict[i][0].getRoots(); + if (exports0 != null) + for (int j = 0; j < exports0.length; j++) { + ResolverBundle exporter = exports0[j].getExporter(); + if (exporter != null && exporter.getName() != null) + bundleConstraints.add(exporter.getName()); + } + ResolverExport[] exports1 = conflict[i][1].getRoots(); + if (exports1 != null) + for (int j = 0; j < exports1.length; j++) { + ResolverBundle exporter = exports1[j].getExporter(); + if (exporter != null && exporter.getName() != null) + bundleConstraints.add(exporter.getName()); + } + } + } + // get a list of resolver constraints that have multiple suppliers - private ResolverConstraint[] getMultipleSuppliers(ResolverBundle[] bundles) { - ArrayList multipleSuppliers = new ArrayList(1); + // a 2 demensional array is used each entry is a list of identical constraints that have identical suppliers. + private ResolverConstraint[][] getMultipleSuppliers(ResolverBundle[] bundles, HashSet packageConstraints, HashSet bundleConstraints) { + ArrayList multipleImportSupplierList = new ArrayList(1); + ArrayList multipleRequireSupplierList = new ArrayList(1); for (int i = 0; i < bundles.length; i++) { BundleConstraint[] requires = bundles[i].getRequires(); for (int j = 0; j < requires.length; j++) if (requires[j].getNumPossibleSuppliers() > 1) - multipleSuppliers.add(requires[j]); + multipleRequireSupplierList.add(requires[j]); ResolverImport[] imports = bundles[i].getImportPackages(); for (int j = 0; j < imports.length; j++) { if (imports[j].getNumPossibleSuppliers() > 1) { Integer eeProfile = (Integer) ((ResolverExport) imports[j].getSelectedSupplier()).getExportPackageDescription().getDirective(ExportPackageDescriptionImpl.EQUINOX_EE); if (eeProfile.intValue() < 0) { // this is a normal package; always add it - multipleSuppliers.add(imports[j]); + multipleImportSupplierList.add(imports[j]); } else { // this is a system bunde export // If other exporters of this package also require the system bundle @@ -650,7 +690,7 @@ public class ResolverImpl implements org.eclipse.osgi.service.resolver.Resolver continue; if (((ResolverExport) suppliers[suppliersIndex]).getExporter().getRequire(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME) == null) if (((ResolverExport) suppliers[suppliersIndex]).getExporter().getRequire(Constants.SYSTEM_BUNDLE_SYMBOLICNAME) == null) { - multipleSuppliers.add(imports[j]); + multipleImportSupplierList.add(imports[j]); break; } } @@ -658,7 +698,81 @@ public class ResolverImpl implements org.eclipse.osgi.service.resolver.Resolver } } } - return (ResolverConstraint[]) multipleSuppliers.toArray(new ResolverConstraint[multipleSuppliers.size()]); + ArrayList results = new ArrayList(); + if (multipleImportSupplierList.size() + multipleRequireSupplierList.size() > MAX_MULTIPLE_SUPPLIERS_MERGE) { + // we have hit a max on the multiple suppliers in the lists without merging. + // first merge the identical constraints that have identical suppliers + HashMap multipleImportSupplierMaps = new HashMap(1); + for (Iterator iMultipleImportSuppliers = multipleImportSupplierList.iterator(); iMultipleImportSuppliers.hasNext();) + addMutipleSupplierConstraint(multipleImportSupplierMaps, (ResolverConstraint) iMultipleImportSuppliers.next()); + HashMap multipleRequireSupplierMaps = new HashMap(1); + for (Iterator iMultipleRequireSuppliers = multipleRequireSupplierList.iterator(); iMultipleRequireSuppliers.hasNext();) + addMutipleSupplierConstraint(multipleRequireSupplierMaps, (ResolverConstraint) iMultipleRequireSuppliers.next()); + addMergedSuppliers(results, multipleImportSupplierMaps); + addMergedSuppliers(results, multipleRequireSupplierMaps); + // check the results to see if we have reduced the number enough + if (results.size() > MAX_MULTIPLE_SUPPLIERS_MERGE && packageConstraints != null && bundleConstraints != null) { + // we still have too big of a list; filter out constraints that are not in conflict + Iterator iResults = results.iterator(); + results = new ArrayList(); + while (iResults.hasNext()) { + ResolverConstraint[] constraints = (ResolverConstraint[]) iResults.next(); + ResolverConstraint constraint = constraints.length > 0 ? constraints[0] : null; + if (constraint instanceof ResolverImport) { + if (packageConstraints.contains(constraint.getName())) + results.add(constraints); + } else if (constraint instanceof BundleConstraint) { + if (bundleConstraints.contains(constraint.getName())) + results.add(constraints); + } + } + } + } else { + // the size is acceptable; just copy the lists as-is + for (Iterator iMultipleImportSuppliers = multipleImportSupplierList.iterator(); iMultipleImportSuppliers.hasNext();) + results.add(new ResolverConstraint[] {(ResolverConstraint) iMultipleImportSuppliers.next()}); + for (Iterator iMultipleRequireSuppliers = multipleRequireSupplierList.iterator(); iMultipleRequireSuppliers.hasNext();) + results.add(new ResolverConstraint[] {(ResolverConstraint) iMultipleRequireSuppliers.next()}); + } + return (ResolverConstraint[][]) results.toArray(new ResolverConstraint[results.size()][]); + } + + private void addMergedSuppliers(ArrayList mergedSuppliers, HashMap constraints) { + for (Iterator iConstraints = constraints.values().iterator(); iConstraints.hasNext();) { + ArrayList mergedConstraintLists = (ArrayList) iConstraints.next(); + for (Iterator mergedLists = mergedConstraintLists.iterator(); mergedLists.hasNext();) { + ArrayList constraintList = (ArrayList) mergedLists.next(); + mergedSuppliers.add(constraintList.toArray(new ResolverConstraint[constraintList.size()])); + } + } + } + + private void addMutipleSupplierConstraint(HashMap constraints, ResolverConstraint constraint) { + ArrayList mergedConstraintLists = (ArrayList) constraints.get(constraint.getName()); + if (mergedConstraintLists == null) { + mergedConstraintLists = new ArrayList(1); + ArrayList constraintList = new ArrayList(1); + constraintList.add(constraint); + mergedConstraintLists.add(constraintList); + constraints.put(constraint.getName(), mergedConstraintLists); + return; + } + for (Iterator mergedLists = mergedConstraintLists.iterator(); mergedLists.hasNext();) { + ArrayList constraintList = (ArrayList) mergedLists.next(); + ResolverConstraint mergedConstraint = (ResolverConstraint) constraintList.get(0); + VersionSupplier[] suppliers1 = constraint.getPossibleSuppliers(); + VersionSupplier[] suppliers2 = mergedConstraint.getPossibleSuppliers(); + if (suppliers1.length != suppliers2.length) + continue; + for (int i = 0; i < suppliers1.length; i++) + if (suppliers1[i] != suppliers2[i]) + continue; + constraintList.add(constraint); + return; + } + ArrayList constraintList = new ArrayList(1); + constraintList.add(constraint); + mergedConstraintLists.add(constraintList); } private void checkCycle(ArrayList cycle) { @@ -1377,7 +1491,7 @@ public class ResolverImpl implements org.eclipse.osgi.service.resolver.Resolver if (!pending) { bundleMapping.remove(bundle); - groupingChecker.remove(rb); + groupingChecker.clear(rb); } if (!pending || !bundle.isResolved()) { resolverExports.remove(rb.getExportPackages()); @@ -1400,7 +1514,7 @@ public class ResolverImpl implements org.eclipse.osgi.service.resolver.Resolver resolverBundles.remove(re); resolverGenerics.remove(re.getGenericCapabilities()); bundleMapping.remove(removedBundles[i]); - groupingChecker.remove(re); + groupingChecker.clear(re); // the bundle is removed if (removedBundles[i] == bundle.getBundle()) removed = true; |