All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.codemodder.plugins.maven.operator.CommandChain Maven / Gradle / Ivy

The newest version!
package io.codemodder.plugins.maven.operator;

import java.io.IOException;
import java.net.URISyntaxException;
import java.util.*;
import javax.xml.stream.XMLStreamException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Implements a Chain of Responsibility Pattern
 *
 * @constructor commands: Commands to Use
 */
class CommandChain {
  private static final Logger LOGGER = LoggerFactory.getLogger(CommandChain.class);

  /** Internal ArrayList of the Commands */
  private List commandList;

  private static List COMMON_COMMANDS =
      List.of(
          // Validation commands
          CheckDependencyPresent.getInstance(),
          CheckParentPackaging.getInstance(),
          // Format commands
          new FormatCommand(),
          new DiscardFormatCommand(),
          // Multipom command
          new CompositeDependencyManagement());

  private CommandChain(List commands) {
    this.commandList = commands;
  }

  /**
   * Retrieves the list of commands in the Chain.
   *
   * @return A list of Command objects in the Chain.
   */
  public List getCommandList() {
    return commandList;
  }

  /**
   * Executes the Chain of Responsibility, applying a sequence of commands on the provided
   * ProjectModel.
   *
   * @param c ProjectModel (context) on which to execute the commands.
   * @return true if all commands execute successfully, false otherwise.
   * @throws URISyntaxException If there is an issue with URIs during execution.
   * @throws IOException If an IO error occurs during execution.
   * @throws XMLStreamException If there is an issue with XML processing during execution.
   */
  public boolean execute(ProjectModel c)
      throws URISyntaxException, IOException, XMLStreamException {
    boolean done = false;
    ListIterator listIterator = commandList.listIterator();

    while (!done && listIterator.hasNext()) {
      Command nextCommand = listIterator.next();
      done = nextCommand.execute(c);

      if (done) {
        if (c.getQueryType() == QueryType.NONE && !(nextCommand instanceof SupportCommand)) {
          c.setModifiedByCommand(true);
        }

        c.setFinishedByClass(nextCommand.getClass().getName());

        break;
      }
    }

    boolean result = done;

    /** Goes Reverse Order applying the filter pattern */
    while (listIterator.previousIndex() > 0) {
      Command nextCommand = listIterator.previous();
      done = nextCommand.postProcess(c);

      if (done) {
        break;
      }
    }

    return result;
  }

  /**
   * Creates a pre-configured Chain with default commands for modifying a POM.
   *
   * @return A pre-configured Chain for modifying a POM.
   */
  public static CommandChain modifyDependency() {
    final List modifyCommands = new ArrayList<>(COMMON_COMMANDS);
    modifyCommands.addAll(
        List.of(
            SimpleUpgrade.getInstance(),
            SimpleDependencyManagement.getInstance(),
            new SimpleInsert(false)));
    return new CommandChain(modifyCommands);
  }

  /**
   * Creates a pre-configured Chain with default commands for only inserting a dependency onto a
   * POM.
   *
   * @return A pre-configured Chain.
   */
  public static CommandChain insertDependency() {
    final List insertCommands = new ArrayList<>(COMMON_COMMANDS);
    insertCommands.add(new SimpleInsert(true));
    return new CommandChain(insertCommands);
  }

  /**
   * Creates a pre-configured Chain with default commands for only updating a dependency onto a POM.
   *
   * @return A pre-configured Chain.
   */
  public static CommandChain updateDependency() {
    final List insertCommands = new ArrayList<>(COMMON_COMMANDS);
    insertCommands.addAll(
        List.of(SimpleUpgrade.getInstance(), SimpleDependencyManagement.getInstance()));

    return new CommandChain(insertCommands);
  }

  private static CommandChain filterByQueryType(
      List> commandList,
      QueryType queryType,
      List initialCommands,
      QueryTypeFilter queryTypeFilter) {
    List filteredCommands = new ArrayList<>();
    for (Pair pair : commandList) {
      if (queryTypeFilter.filter(pair.getFirst())) {
        String commandClassName = "io.codemodder.plugins.maven.operator." + pair.getSecond();

        try {
          Class commandClass = Class.forName(commandClassName);
          Command command = (Command) commandClass.newInstance();
          filteredCommands.add(command);
        } catch (final Exception e) {
          LOGGER.warn("Creating class '{}': ", commandClassName, e);
        }
      }
    }

    List commands = new ArrayList<>();
    commands.addAll(initialCommands);
    commands.addAll(filteredCommands);

    if (commands.isEmpty()) {
      throw new IllegalStateException(
          "Unable to load any available strategy for " + queryType.name());
    }

    return new CommandChain(commands);
  }

  /**
   * Creates a pre-configured Chain for dependency querying based on the specified query type.
   *
   * @param queryType The QueryType to determine the set of commands to include in the Chain.
   * @return A pre-configured Chain for dependency querying.
   */
  public static CommandChain createForDependencyQuery(QueryType queryType) {
    return filterByQueryType(
        AVAILABLE_DEPENDENCY_QUERY_COMMANDS,
        queryType,
        Arrays.asList(CheckLocalRepositoryDirCommand.CheckParentDirCommand.getInstance()),
        it -> it == queryType);
  }

  /**
   * Creates a pre-configured Chain for version querying based on the specified query type.
   *
   * @param queryType The QueryType to determine the set of commands to include in the Chain.
   * @return A pre-configured Chain for version querying.
   */
  public static CommandChain createForVersionQuery(QueryType queryType) {
    return filterByQueryType(
        AVAILABLE_QUERY_VERSION_COMMANDS,
        queryType,
        Collections.emptyList(),
        it -> it.ordinal() <= queryType.ordinal());
  }

  /**
   * Some classes won't have all available dependencies on the classpath during runtime for this
   * reason we'll use
   *
   * 
Class.forName
* * and report issues creating */ static final List> AVAILABLE_DEPENDENCY_QUERY_COMMANDS = new ArrayList<>(Arrays.asList(new Pair<>(QueryType.SAFE, "QueryByParsing"))); /** List of Commands for Version Query */ private static final List> AVAILABLE_QUERY_VERSION_COMMANDS = new ArrayList<>( Arrays.asList( new Pair<>(QueryType.SAFE, "VersionByCompilerDefinition"), new Pair<>(QueryType.SAFE, "VersionByProperty"))); private interface QueryTypeFilter { boolean filter(QueryType queryType); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy