Modified: felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/prototype/ProtoResolver.java URL: http://svn.apache.org/viewvc/felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/prototype/ProtoResolver.java?rev=885920&r1=885919&r2=885920&view=diff ============================================================================== --- felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/prototype/ProtoResolver.java (original) +++ felix/sandbox/rickhall/resolver/src/main/java/org/apache/felix/resolver/prototype/ProtoResolver.java Tue Dec 1 20:50:51 2009 @@ -20,6 +20,7 @@ import org.apache.felix.resolver.*; import java.util.ArrayList; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -27,6 +28,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.TreeSet; import org.apache.felix.resolver.cs.Capability; import org.apache.felix.resolver.cs.CapabilitySet; @@ -34,9 +36,22 @@ { private final List<Module> m_moduleList; private final CapabilitySet m_pkgCapSet; + private final Map<Module, Map<String, Blame>> m_moduleConstraintCache = + new HashMap<Module, Map<String, Blame>>(); + private final Map<Module, Map<String, Blame>> m_resolvingConstraintCache = + new HashMap<Module, Map<String, Blame>>(); + private final Map<ExportedPackage, Map<String, Blame>> m_resolvedConstraintCache = + new HashMap<ExportedPackage, Map<String, Blame>>(); + private Map<Module, Map<String, Object>> m_verifyCache = + new HashMap<Module, Map<String, Object>>(); + + private static final Map<String, Long> m_invokeCounts = new HashMap<String, Long>(); + + private static boolean m_isInvokeCount = false; public ProtoResolver(List<Module> moduleList) { +System.out.println("+++ PROTO RESOLVER"); m_moduleList = moduleList; List indices = new ArrayList(); indices.add("package"); @@ -49,6 +64,9 @@ m_pkgCapSet.addCapability(exports.get(expIdx)); } } + + String v = System.getProperty("invoke.count"); + m_isInvokeCount = (v == null) ? false : Boolean.valueOf(v); } public Module getModule(String name) @@ -69,7 +87,11 @@ public Map<Module, List<Wire>> resolve(Module module) { -System.out.println("+++ PROTO RESOLVER"); + m_invokeCounts.clear(); + m_moduleConstraintCache.clear(); + m_resolvingConstraintCache.clear(); + m_resolvedConstraintCache.clear(); + m_verifyCache.clear(); Map<ImportedPackage, Set<Capability>> candidateMap = resolve( module, null, @@ -78,39 +100,66 @@ new HashMap<String, Blame>(), new HashMap<Module, Boolean>()); +if (m_isInvokeCount) +{ + System.out.println("INVOKE COUNTS " + m_invokeCounts); +} return populateWireMap(module, candidateMap, new HashMap<Module, List<Wire>>()); } private Map<ImportedPackage, Set<Capability>> resolve( - Module module, ImportedPackage ipGoal, Module blameModule, + Module module, ExportedPackage epGoal, Module blameModule, Map<ImportedPackage, Set<Capability>> candidateMap, - Map<String, Blame> existingConstraints, + Map<String, Blame> existingConstrains, Map<Module, Boolean> 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); + } + try { - // If module is already resolved, then we are done. + // If the module is already resolved, then do nothing. if (!module.isResolved()) { + // Copy the existing constraints, since we need to be able + // to freely modify them. + Map<String, Blame> existingConstraintsCopy = + new HashMap<String, Blame>(existingConstrains); + try { - // If the cycle map already contains the module, then verify - // consistency again and then just return. - if (cycleMap.containsKey(module)) + // If the module is in the process of being resolved, then + // we are going to want to just return the candidate map + // to break the cycle. + Boolean found = cycleMap.get(module); + if (found != null) { - // Make sure any merged constraints do not conflict with passed in constraints. - if (cycleMap.get(module).booleanValue()) + // If the modules is in the process of being resolved, but + // we have already selected all candidates for it, then we + // need to verify consistency before returning the + // candidate map. + if (found.booleanValue()) { + Map<String, Blame> currentConstraints = - calculatePackageConstraints(module, blameModule); - checkConsistency(module, ipGoal, candidateMap, - existingConstraints, currentConstraints); + calculateResolvingConstraints(module, blameModule); + checkConsistency(module, epGoal, candidateMap, + existingConstraintsCopy, currentConstraints); + existingConstrains.putAll(existingConstraintsCopy); } return candidateMap; } + + // Add the module to the cycle map; use Boolean.FALSE to + // mark it as in the process of being resolved. cycleMap.put(module, Boolean.FALSE); - // Keep track of the starting module. + // If this is the starting module, then remember it. if (m_rootModule == null) { m_rootModule = module; @@ -119,170 +168,132 @@ // Find candidates for all imports for the target module. List<ImportedPackage> imports = module.getImports(); - for (int impIdx = 0; impIdx < imports.size(); impIdx++) + for (ImportedPackage ip : imports) { // If we are using a permutated candidate map, then the target // module's candidates may have already been calculated, so use // those instead, otherwise find the matching providers. - if (candidateMap.get(imports.get(impIdx)) == null) + if (candidateMap.get(ip) == null) { - Set<Capability> exporters = findExporters(imports.get(impIdx)); + Set<Capability> exporters = findExporters(ip); if (exporters.size() == 0) { throw new RuntimeException("Unable to resolve " + module - + ": missing requirement " + imports.get(impIdx)); + + ": missing requirement " + ip); } - candidateMap.put(imports.get(impIdx), exporters); + candidateMap.put(ip, exporters); } } // Calculate current package constraints for the target module. Map<String, Blame> currentConstraints = - calculatePackageConstraints(module, blameModule); - // Make copy of current package constraints, since we may need - // to revert if a candidate resolve fails. - Map <String, Blame> currentConstraintsOrig = + calculateConstraints(module, blameModule); + + // Make copy of current package constraints, since we need to + // be able to freely modify, but we may need to revert if a + // candidate resolve fails. + Map <String, Blame> currentConstraintsCopy = new HashMap<String, Blame>(currentConstraints); // Verify current candidates are resolvable and consistent. boolean repeat; do { - do - { - repeat = false; + repeat = false; - // Loop through all of the target module's imports and v - for (int impIdx = 0; impIdx < imports.size(); impIdx++) + // Loop through all of the target module's imports and v + for (ImportedPackage ip : imports) + { + // Get the current candidate capability for the current import. + Set<Capability> exporters = candidateMap.get(ip); + Iterator<Capability> itExporters = exporters.iterator(); + Capability cap = itExporters.next(); +//System.out.println("+++ RESOLVING " + cap + " FOR " + module); + try { - // Get the current candidate for the import. - Set<Capability> exporters = candidateMap.get(imports.get(impIdx)); - // If the current candidate is already resolved, then try - // to merge packages while verifying constraints. - Iterator<Capability> itExporters = exporters.iterator(); - Capability cap = itExporters.next(); + // If current candidate is resolved, then try to merge + // in its constraints with the existing constraints. if (cap.getModule().isResolved()) { - // HERE WE WILL NEED TO TRY TO MERGE THE CANDIDATE. + mergeResolvedConstraints( + module, candidateMap, currentConstraintsCopy, + (ExportedPackage) cap); + } + // If current candidate is the same as the module being + // resolved, then just directly add it as a constraint. + else if (cap.getModule().equals(module)) + { + currentConstraintsCopy.put( + cap.getName(), new Blame((ExportedPackage) cap, blameModule)); } // If the current candidate is not resolved, then try to resolve // it, which will also merge packages while verify constraints. - else if (!cap.getModule().isResolved()) + else { - try - { - resolve( - cap.getModule(), - imports.get(impIdx), - module, - candidateMap, - currentConstraints, - cycleMap); - } - // If we have a constraint conflict, then the current candidate - // should be removed, since it conflicts with an existing choice. - // If we are at the root, we should try the next permutated - // candidate map if possible. - catch (ResolverConflictException ex) - { -//System.out.println("RCE " + ex); + resolve( + cap.getModule(), + (ExportedPackage) cap, + module, + candidateMap, + currentConstraintsCopy, + cycleMap); + } + } + // If we have a resolve exception, then the current candidate + // should be removed. If we are at the root, we should try the + // next permutated candidate map if there are no more candidates. + catch (ResolveException ex) + { +System.out.println("RE " + ex); +ex.printStackTrace(); //System.out.println("Current candidate map : " + candidateMap); - // Remove offending candidate. - itExporters.remove(); + // Remove offending candidate. + itExporters.remove(); //System.out.println("Updated candidate map : " + candidateMap); - if (!itExporters.hasNext()) - { - // TODO: PROTO RESOLVER - Maybe this should be moved. - if ((module == m_rootModule) && (m_candidatePermutations.size() > 0)) - { - currentConstraints.clear(); - currentConstraints.putAll(currentConstraintsOrig); - candidateMap = m_candidatePermutations.remove(0); + if (!itExporters.hasNext()) + { + // TODO: PROTO RESOLVER - Maybe this should be moved. + if ((module == m_rootModule) && (m_candidatePermutations.size() > 0)) + { + currentConstraintsCopy.clear(); + currentConstraintsCopy.putAll(currentConstraints); + candidateMap = m_candidatePermutations.remove(0); //System.out.println("+++ TRYING ALTERNATIVE: " + candidateMap); - repeat = true; - } - else - { - candidateMap.remove(imports.get(impIdx)); - throw new ResolveException("Unresolved constraint " - + imports.get(impIdx) - + " in " + module); - } - } - else - { - repeat = true; - } - break; + // Flush various caches for new candidates. + m_resolvingConstraintCache.clear(); + m_verifyCache.clear(); + repeat = true; } - // If we cannot resolve the candidate, then the current candidate - // should be removed. If we are at the root, we should try the - // next permutated candidate map if possible. - catch (ResolveException ex) + else { -//System.out.println("RE " + ex); -//System.out.println("Current candidate map : " + candidateMap); - // Remove offending candidate. - itExporters.remove(); -//System.out.println("Updated candidate map : " + candidateMap); - if (!itExporters.hasNext()) - { - // TODO: PROTO RESOLVER - Maybe this should be moved. - if ((module == m_rootModule) && (m_candidatePermutations.size() > 0)) - { - currentConstraints.clear(); - currentConstraints.putAll(currentConstraintsOrig); - candidateMap = m_candidatePermutations.remove(0); -//System.out.println("+++ TRYING ALTERNATIVE: " + candidateMap); - repeat = true; - } - else - { - candidateMap.remove(imports.get(impIdx)); - throw new ResolveException("Unresolved constraint " - + imports.get(impIdx) - + " in " + module); - } - } - else - { - repeat = true; - } - break; + candidateMap.remove(ip); + throw new ResolveException("Unresolved constraint " + + ip + " in " + module); } } + else + { + repeat = true; + } + break; } } - while (repeat); } while (repeat); - // Make sure any candidate constraints merged with the current constraints - // do not conflict with existing in constraints. - checkConsistency(module, ipGoal, candidateMap, existingConstraints, currentConstraints); - - // Merge current constraints with existing constraints. - for (Iterator<Entry<String, Blame>> it = currentConstraints.entrySet().iterator(); - it.hasNext(); ) - { - Entry<String, Blame> entry = it.next(); - if ((ipGoal == null) || m_pkgCapSet.matches(entry.getValue().m_exportedPackage, ipGoal.getFilter())) - { - Blame blame = existingConstraints.get(entry.getKey()); - if ((blame != null) - && !blame.m_blameModules.contains(entry.getValue().m_blameModules.get(0))) - { - blame.m_blameModules.add(entry.getValue().m_blameModules.get(0)); - } - else if (blame == null) - { - existingConstraints.put(entry.getKey(), entry.getValue()); - } - mergeUses(entry.getValue().m_exportedPackage, - existingConstraints, currentConstraints, - new HashMap<ExportedPackage, ExportedPackage>()); - } - } + // At this point, we have selected a candidate capability for + // every import, so we need to merge the calculated constraints + // with the existing constraints, checking the consistency + // while we do it. +//System.out.println("+++ existingConstraints: " + existingConstraintsCopy); +//System.out.println("+++ currentConstraints : " + currentConstraints); + checkConsistency( + module, epGoal, candidateMap, existingConstraintsCopy, currentConstraintsCopy); + // If we are here, then the candidates were consistent with + // existing constraints, so cache the result. + m_resolvingConstraintCache.put(module, existingConstraintsCopy); + // Finally, modify the original existing constraints. + existingConstrains.putAll(existingConstraintsCopy); } catch (RuntimeException ex) { @@ -292,8 +303,10 @@ } } + // Update the cycle map to mark the module as finished. cycleMap.put(module, Boolean.TRUE); + // Return the updated candidate map. return candidateMap; } finally @@ -306,30 +319,129 @@ } } + private Map<String, Blame> calculateResolvingConstraints(Module module, Module blameModule) + { + Map<String, Blame> constraints = m_resolvingConstraintCache.get(module); + + // Make a copy of the cached result to set the blame module correctly. + HashMap<String, Blame> constraintsCopy = new HashMap<String, Blame>(); + for (Iterator<Map.Entry<String, Blame>> it = constraints.entrySet().iterator(); + it.hasNext(); ) + { + Entry<String, Blame> entry = it.next(); + if (entry.getValue().m_exportedPackage.getModule() == module) + { + constraintsCopy.put( + entry.getKey(), new Blame(entry.getValue().m_exportedPackage, blameModule)); + } + else + { + constraintsCopy.put(entry.getKey(), entry.getValue()); + } + } + + return constraintsCopy; + } + private Set<Capability> findExporters(ImportedPackage ip) { - return m_pkgCapSet.match(ip.getFilter()); + 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); + } + + Set<Capability> result = new TreeSet(new Comparator() { + public int compare(Object arg1, Object arg2) + { + ExportedPackage ep1 = (ExportedPackage) arg1; + ExportedPackage ep2 = (ExportedPackage) arg2; + int c = ep1.getName().compareTo(ep2.getName()); + if (c == 0) + { + Version v1 = (ep1.getAttribute("version") == null) + ? Version.emptyVersion + : (Version) ep1.getAttribute("version").getValue(); + Version v2 = (ep1.getAttribute("version") == null) + ? Version.emptyVersion + : (Version) ep1.getAttribute("version").getValue(); + // Compare these in reverse order, since we want + // highest version to have priority. + c = v2.compareTo(v1); + if (c == 0) + { + c = ep1.getModule().getName().compareTo(ep2.getModule().getName()); + } + } + return c; + } + }); + result.addAll(m_pkgCapSet.match(ip.getFilter())); + return result; } - private Map<String, Blame> calculatePackageConstraints( + private Map<String, Blame> calculateConstraints( Module module, Module blameModule) { - Map<String, Blame> pkgMap = new HashMap<String, Blame>(); - List<ExportedPackage> exports = module.getExports(); - for (int i = 0; i < exports.size(); i++) + 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<String, Blame> constraints = m_moduleConstraintCache.get(module); + + // If the constraints aren't cached, then calculate them. + if (constraints == null) + { + constraints = new HashMap<String, Blame>(); + + List<ExportedPackage> exports = module.getExports(); + for (int i = 0; i < exports.size(); i++) + { + // TODO: PROTO RESOLVER - Assume if a module imports the same package it + // exports that the import will overlap the export. + if (!hasOverlappingImport(module, exports.get(i))) + { + constraints.put(exports.get(i).getName(), new Blame(exports.get(i), blameModule)); + } + } + + // Cache answer. + m_moduleConstraintCache.put(module, constraints); + } + // If they are cached, then we need to make a copy to set the + // blame module correctly. + else { - // TODO: PROTO RESOLVER - Assume if a module imports the same package it - // exports that the import will overlap the export. - if (!hasOverlappingImport(module, exports.get(i))) + HashMap<String, Blame> constraintsCopy = new HashMap<String, Blame>(); + for (Iterator<Map.Entry<String, Blame>> it = constraints.entrySet().iterator(); + it.hasNext(); ) { - pkgMap.put(exports.get(i).getName(), new Blame(exports.get(i), blameModule)); + Entry<String, Blame> entry = it.next(); + constraintsCopy.put( + entry.getKey(), new Blame(entry.getValue().m_exportedPackage, blameModule)); } + constraints = constraintsCopy; } - return pkgMap; + + return constraints; } private boolean hasOverlappingImport(Module module, ExportedPackage ep) { + 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<ImportedPackage> imports = module.getImports(); for (int i = 0; i < imports.size(); i++) { @@ -341,23 +453,189 @@ return false; } + private void mergeResolvedConstraints( + Module blameModule, Map<ImportedPackage, Set<Capability>> candidateMap, + Map<String, Blame> currentConstraints, ExportedPackage epTarget) + { + 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<String, Blame> actualConstraints = calculateResolvedConstraints(blameModule, epTarget); + verifyUses(blameModule, epTarget.getName(), + candidateMap, currentConstraints, actualConstraints, + new HashMap<String, List<Module>>()); +//System.out.println("+++ ACTUAL FOR " + epTarget + " = " + actualConstraints); + // Merge current constraints with existing constraints. + for (Iterator<Entry<String, Blame>> it = actualConstraints.entrySet().iterator(); + it.hasNext(); ) + { + Entry<String, Blame> entry = it.next(); + Blame current = currentConstraints.get(entry.getKey()); + if ((current != null) + && !current.m_exportedPackage.equals(entry.getValue().m_exportedPackage)) + { + throw new ResolveConflictException("Unable to resolve " + + blameModule + ": constraint conflict with '" + + current.m_exportedPackage.getName() + "' between " + current + " and " + + entry.getValue()); + } + else if (current == null) + { + currentConstraints.put(entry.getKey(), entry.getValue()); + } + } + } + + private Map<String, Blame> calculateResolvedConstraints( + Module blameModule, ExportedPackage epTarget) + { + 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); + } + +//System.out.println("+++ CALC FOR " + epTarget); + Map<String, Blame> constraints = m_resolvedConstraintCache.get(epTarget); + + // If the constraints aren't cached, then calculate them. + if (constraints == null) + { + constraints = new HashMap<String, Blame>(); + + // The capability itself is a constraint, so add it. + constraints.put(epTarget.getName(), new Blame(epTarget, blameModule)); + + // Calculate implied constraints. + calculateResolvedUsesConstraints( + epTarget, + constraints, + new HashMap<ExportedPackage, ExportedPackage>()); + + // Cache answer. + m_resolvedConstraintCache.put(epTarget, constraints); + } + // If they are cached, then we need to make a copy to set the + // blame module correctly. + else + { + HashMap<String, Blame> constraintsCopy = new HashMap<String, Blame>(); + for (Iterator<Map.Entry<String, Blame>> it = constraints.entrySet().iterator(); + it.hasNext(); ) + { + Entry<String, Blame> entry = it.next(); + if (entry.getValue().m_exportedPackage.getModule() == epTarget.getModule()) + { + constraintsCopy.put( + entry.getKey(), new Blame(entry.getValue().m_exportedPackage, blameModule)); + } + else + { + constraintsCopy.put(entry.getKey(), entry.getValue()); + } + } + constraints = constraintsCopy; + } + + return constraints; + } + + private void calculateResolvedUsesConstraints( + ExportedPackage epTarget, Map<String, Blame> constraints, + Map<ExportedPackage, ExportedPackage> 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 (cycleMap.containsKey(epTarget)) + { + return; + } + cycleMap.put(epTarget, epTarget); + + List<String> uses = epTarget.getUses(); + for (int usesIdx = 0; usesIdx < uses.size(); usesIdx++) + { + // We need to find the source of the package name for the current target. + // It can either be from an importer or an exporter. + ExportedPackage epSource = null; + + // Search the target module's wires for the package. + for (int wireIdx = 0; + (epSource == null) && (wireIdx < epTarget.getModule().getWires().size()); + wireIdx++) + { + if (epTarget.getModule().getWires().get(wireIdx) + .getExportedPackage().getName().equals(uses.get(usesIdx))) + { + epSource = epTarget.getModule().getWires().get(wireIdx).getExportedPackage(); + } + } + + // If we couldn't find a wire for the package, then search the target + // modules exports. + for (int expIdx = 0; + (epSource == null) && (expIdx < epTarget.getModule().getExports().size()); + expIdx++) + { + if (epTarget.getModule().getExports().get(expIdx).getName().equals(uses.get(usesIdx))) + { + epSource = epTarget.getModule().getExports().get(expIdx); + } + } + + if (epSource != null) + { + constraints.put(uses.get(usesIdx), new Blame(epSource, epTarget.getModule())); + calculateResolvedUsesConstraints(epSource, constraints, cycleMap); + } + } + } + private void checkConsistency( - Module targetModule, ImportedPackage ipGoal, Map<ImportedPackage, Set<Capability>> candidateMap, - Map<String, Blame> existingConstraints, Map<String, Blame> currentConstraints) + Module targetModule, ExportedPackage epGoal, Map<ImportedPackage, + Set<Capability>> candidateMap, Map<String, Blame> existingConstraints, + Map<String, Blame> currentConstraints) - throws ResolverConflictException + throws ResolveConflictException { + 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); + } + //System.out.println("Goal: " + ipGoal); //System.out.println("Candidate map: " + candidateMap); //System.out.println(targetModule + " current : " + currentConstraints); //System.out.println(spaces(targetModule.toString()) + " existing : " + existingConstraints); // Find matching providing for requirement. - for (Iterator<Entry<String, Blame>> it = currentConstraints.entrySet().iterator(); it.hasNext(); ) + if (epGoal != null) { - Entry<String, Blame> entry = it.next(); - Blame current = entry.getValue(); - if ((ipGoal == null) || m_pkgCapSet.matches(current.m_exportedPackage, ipGoal.getFilter())) + verifyUses(targetModule, epGoal.getName(), + candidateMap, existingConstraints, currentConstraints, + new HashMap<String, List<Module>>()); + } + else + { + for (Iterator<Entry<String, Blame>> it = currentConstraints.entrySet().iterator(); + it.hasNext(); ) { + Entry<String, Blame> entry = it.next(); verifyUses(targetModule, entry.getKey(), candidateMap, existingConstraints, currentConstraints, new HashMap<String, List<Module>>()); @@ -372,6 +650,26 @@ Map<String, Blame> existingConstraints, Map<String, Blame> currentConstraints, 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 cache for answer. + Map<String, Object> answers = m_verifyCache.get(targetModule); + if (answers != null) + { + Object result = answers.get(pkgName); + if (result != null) + { + return; + } + } + + // Check for cycles. List<Module> list = cycleMap.get(pkgName); if ((list != null) && list.contains(targetModule)) { @@ -403,32 +701,42 @@ boolean invalid = false; for (int blameIdx = 0; blameIdx < existing.m_blameModules.size(); blameIdx++) { - List<ImportedPackage> blameImports = existing.m_blameModules.get(blameIdx).getImports(); - for (int impIdx = 0; impIdx < blameImports.size(); impIdx++) + // If the blamed module is already resolved, then there is no point + // in trying to permutate its candidates, since it is already wired + // to them. + if (!existing.m_blameModules.get(blameIdx).isResolved()) { - // TODO: PROTO RESOLVER - Not efficient at all. - // TODO: PROTO RESOLVER - This comment out part is too narrow, since it could - // also check for other candidates that imply the conficting package. - // Works for scenario 9, but it fails for scenario 1. -// if (blameImports.get(impIdx).getName().equals(pkgName) -// && candidateMapCopy.get(blameImports.get(impIdx)).contains(existing.m_provider)) - // TODO: PROTO RESOLVER - This comment out part is too broad, since it removes - // the conflicting module from all candidate lists. - // Works for scenario 1, but fails for scenario 9. -//System.out.println("CHECKING " + candidateMapCopy.get(blameImports.get(impIdx)) + " FOR " + existing.m_exportedPackage); - for (Iterator<Capability> cmIt = - candidateMapCopy.get(blameImports.get(impIdx)).iterator(); - cmIt.hasNext(); ) + List<ImportedPackage> blameImports = + existing.m_blameModules.get(blameIdx).getImports(); + for (int impIdx = 0; impIdx < blameImports.size(); impIdx++) { - if (cmIt.next().getModule().equals(existing.m_exportedPackage.getModule())) + // TODO: PROTO RESOLVER - Not efficient at all. + // TODO: PROTO RESOLVER - This comment out part is too narrow, since it could + // also check for other candidates that imply the conficting package. + // Works for scenario 9, but it fails for scenario 1. +// if (blameImports.get(impIdx).getName().equals(pkgName) +// && candidateMapCopy.get(blameImports.get(impIdx)).contains(existing.m_provider)) + // TODO: PROTO RESOLVER - This comment out part is too broad, since it removes + // the conflicting module from all candidate lists. + // Works for scenario 1, but fails for scenario 9. +//System.out.println("CHECKING " + candidateMapCopy.get(blameImports.get(impIdx)) + " FOR " + existing.m_exportedPackage); +//System.out.println("+++ candidateMapCopy " + candidateMapCopy); +//System.out.println("+++ blameImports.get(impIdx) " + blameImports.get(impIdx)); +//System.out.println("+++ candidateMapCopy.get(blameImports.get(impIdx)) " + candidateMapCopy.get(blameImports.get(impIdx))); + for (Iterator<Capability> cmIt = + candidateMapCopy.get(blameImports.get(impIdx)).iterator(); + cmIt.hasNext(); ) { - cmIt.remove(); - modified = true; - if (candidateMapCopy.get(blameImports.get(impIdx)).size() == 0) + if (cmIt.next().getModule().equals(existing.m_exportedPackage.getModule())) { - invalid = true; + cmIt.remove(); + modified = true; + if (candidateMapCopy.get(blameImports.get(impIdx)).size() == 0) + { + invalid = true; + } + break; } - break; } } } @@ -449,7 +757,8 @@ // TODO: PROTO RESOLVER - We could perhaps check to see if the candidate permutation // is even viable, e.g., the conflicting candidate may be the only candidate // so the resulting permutation may not be resolveable. - throw new ResolverConflictException("Unable to resolve " + + throw new ResolveConflictException("Unable to resolve " + targetModule + ": constraint conflict with '" + pkgName + "' between " + current + " and " + existing); @@ -463,12 +772,38 @@ verifyUses(targetModule, uses.get(usesIdx), candidateMap, existingConstraints, currentConstraints, cycleMap); } + // Now we can merge constraints, since there was no issue. + if ((existing != null) + && !existing.m_blameModules.contains(current.m_blameModules.get(0))) + { + existing.m_blameModules.add(current.m_blameModules.get(0)); + } + else if (existing == null) + { +// TODO: PROTO RESOLVER - Not clear if we can re-use "current" since it might get modified. + existingConstraints.put(pkgName, current); + } + } + + if (answers == null) + { + answers = new HashMap<String, Object>(); + m_verifyCache.put(targetModule, answers); } + answers.put(pkgName, Boolean.TRUE); } private static Map<ImportedPackage, Set<Capability>> copyCandidateMap( Map<ImportedPackage, 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); + } + Map<ImportedPackage, Set<Capability>> copy = new HashMap<ImportedPackage, Set<Capability>>(); for (Iterator<Entry<ImportedPackage, Set<Capability>>> it = candidateMap.entrySet().iterator(); it.hasNext(); ) @@ -479,48 +814,18 @@ return copy; } - private static void mergeUses(ExportedPackage ep, Map<String, Blame> existingConstraints, - Map<String, Blame> currentConstraints, Map<ExportedPackage, ExportedPackage> cycleMap) - { - if (cycleMap.containsKey(ep)) - { - return; - } - cycleMap.put(ep, ep); - - if (ep.getUses().size() > 0) - { - for (Iterator<Entry<String, Blame>> it = currentConstraints.entrySet().iterator(); - it.hasNext(); ) - { - Entry<String, Blame> entry = it.next(); - for (int usesIdx = 0; usesIdx < ep.getUses().size(); usesIdx++) - { - if (entry.getKey().equals(ep.getUses().get(usesIdx))) - { - Blame blame = existingConstraints.get(entry.getKey()); - if ((blame != null) - && !blame.m_blameModules.contains(entry.getValue().m_blameModules.get(0))) - { - blame.m_blameModules.add(entry.getValue().m_blameModules.get(0)); - } - else if (blame == null) - { - existingConstraints.put(entry.getKey(), entry.getValue()); - } - mergeUses(entry.getValue().m_exportedPackage, - existingConstraints, currentConstraints, - cycleMap); - } - } - } - } - } - private static Map<Module, List<Wire>> populateWireMap( Module module, Map<ImportedPackage, Set<Capability>> candidateMap, 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 (wireMap.get(module) == null) { List<Wire> moduleWires = new ArrayList<Wire>();
