/** Populates the result from the graph traversal state. */
  private void assembleResult(ResolveState resolveState, DependencyGraphVisitor listener) {
    listener.start(resolveState.root);

    // Visit the nodes
    for (ConfigurationNode resolvedConfiguration : resolveState.getConfigurationNodes()) {
      if (resolvedConfiguration.isSelected()) {
        resolvedConfiguration.validate();
        listener.visitNode(resolvedConfiguration);
      }
    }
    // Visit the edges
    for (ConfigurationNode resolvedConfiguration : resolveState.getConfigurationNodes()) {
      if (resolvedConfiguration.isSelected()) {
        listener.visitEdge(resolvedConfiguration);
      }
    }

    listener.finish(resolveState.root);
  }
 public DependencyEdge(
     ConfigurationNode from,
     DependencyMetaData dependencyMetaData,
     ModuleResolutionFilter resolutionFilter,
     ResolveState resolveState) {
   this.from = from;
   this.dependencyMetaData = dependencyMetaData;
   this.resolutionFilter = resolutionFilter;
   this.resolveState = resolveState;
   selector = resolveState.getSelector(dependencyMetaData);
 }
 private ModuleVersionSelectorResolveState(
     DependencyMetaData dependencyMetaData,
     DependencyToComponentIdResolver resolver,
     ResolveState resolveState) {
   this.dependencyMetaData = dependencyMetaData;
   this.resolver = resolver;
   this.resolveState = resolveState;
   targetModule =
       resolveState.getModule(
           new DefaultModuleIdentifier(
               dependencyMetaData.getRequested().getGroup(),
               dependencyMetaData.getRequested().getName()));
 }
 public void restart(ModuleVersionResolveState selected) {
   // Restarting this configuration after conflict resolution.
   // If this configuration belongs to the select version, queue ourselves up for traversal.
   // If not, then remove our incoming edges, which triggers them to be moved across to the
   // selected configuration
   if (moduleRevision == selected) {
     resolveState.onMoreSelected(this);
   } else {
     for (DependencyEdge dependency : incomingEdges) {
       dependency.restart(selected);
     }
     incomingEdges.clear();
   }
 }
    private void calculateTargetConfigurations() {
      targetConfigurations.clear();
      ComponentResolveMetaData targetModuleVersion = targetModuleRevision.getMetaData();
      if (targetModuleVersion == null) {
        // Broken version
        return;
      }

      Set<ConfigurationMetaData> targetConfigurations =
          resolveState.dependencyToConfigurationResolver.resolveTargetConfigurations(
              dependencyMetaData, from.metaData, targetModuleVersion);
      for (ConfigurationMetaData targetConfiguration : targetConfigurations) {
        ConfigurationNode targetConfigurationNode =
            resolveState.getConfigurationNode(targetModuleRevision, targetConfiguration.getName());
        this.targetConfigurations.add(targetConfigurationNode);
      }
    }
    /** @return The module version, or null if there is a failure to resolve this selector. */
    public ModuleVersionResolveState resolveModuleRevisionId() {
      if (targetModuleRevision != null) {
        return targetModuleRevision;
      }
      if (failure != null) {
        return null;
      }

      idResolveResult = new DefaultBuildableComponentIdResolveResult();
      resolver.resolve(dependencyMetaData, idResolveResult);
      if (idResolveResult.getFailure() != null) {
        failure = idResolveResult.getFailure();
        return null;
      }

      targetModuleRevision = resolveState.getRevision(idResolveResult.getModuleVersionId());
      targetModuleRevision.addResolver(this);
      targetModuleRevision.selectionReason = idResolveResult.getSelectionReason();
      targetModule = targetModuleRevision.module;
      targetModule.addSelector(this);

      return targetModuleRevision;
    }
 public void removeIncomingEdge(DependencyEdge dependencyEdge) {
   incomingEdges.remove(dependencyEdge);
   resolveState.onFewerSelected(this);
 }
 public void addIncomingEdge(DependencyEdge dependencyEdge) {
   incomingEdges.add(dependencyEdge);
   resolveState.onMoreSelected(this);
 }
  /**
   * Traverses the dependency graph, resolving conflicts and building the paths from the root
   * configuration.
   */
  private void traverseGraph(
      final ResolveState resolveState, final ConflictHandler conflictHandler) {
    resolveState.onMoreSelected(resolveState.root);

    List<DependencyEdge> dependencies = new ArrayList<DependencyEdge>();
    while (resolveState.peek() != null || conflictHandler.hasConflicts()) {
      if (resolveState.peek() != null) {
        ConfigurationNode node = resolveState.pop();
        LOGGER.debug("Visiting configuration {}.", node);

        // Calculate the outgoing edges of this configuration
        dependencies.clear();
        node.visitOutgoingDependencies(dependencies);

        for (DependencyEdge dependency : dependencies) {
          LOGGER.debug("Visiting dependency {}", dependency);

          // Resolve dependency to a particular revision
          ModuleVersionResolveState moduleRevision = dependency.resolveModuleRevisionId();
          if (moduleRevision == null) {
            // Failed to resolve.
            continue;
          }
          ModuleIdentifier moduleId = moduleRevision.id.getModule();

          // Check for a new conflict
          if (moduleRevision.state == ModuleState.New) {
            ModuleResolveState module = resolveState.getModule(moduleId);

            // A new module revision. Check for conflict
            PotentialConflict c = conflictHandler.registerModule(module);
            if (!c.conflictExists()) {
              // No conflict. Select it for now
              LOGGER.debug("Selecting new module version {}", moduleRevision);
              module.select(moduleRevision);
            } else {
              // We have a conflict
              LOGGER.debug("Found new conflicting module version {}", moduleRevision);

              // Deselect the currently selected version, and remove all outgoing edges from the
              // version
              // This will propagate through the graph and prune configurations that are no longer
              // required
              // For each module participating in the conflict (many times there is only one
              // participating module that has multiple versions)
              c.withParticipatingModules(
                  new Action<ModuleIdentifier>() {
                    public void execute(ModuleIdentifier module) {
                      ModuleVersionResolveState previouslySelected =
                          resolveState.getModule(module).clearSelection();
                      if (previouslySelected != null) {
                        for (ConfigurationNode configuration : previouslySelected.configurations) {
                          configuration.deselect();
                        }
                      }
                    }
                  });
            }
          }

          dependency.attachToTargetConfigurations();
        }
      } else {
        // We have some batched up conflicts. Resolve the first, and continue traversing the graph
        conflictHandler.resolveNextConflict(
            new Action<ConflictResolutionResult>() {
              public void execute(final ConflictResolutionResult result) {
                result
                    .getConflict()
                    .withParticipatingModules(
                        new Action<ModuleIdentifier>() {
                          public void execute(ModuleIdentifier moduleIdentifier) {
                            ModuleVersionResolveState selected = result.getSelected();
                            // Restart each configuration. For the evicted configuration, this means
                            // moving incoming dependencies across to the
                            // matching selected configuration. For the select configuration, this
                            // mean traversing its dependencies.
                            resolveState.getModule(moduleIdentifier).restart(selected);
                          }
                        });
              }
            });
      }
    }
  }