Package net.raymanoz.command

Source Code of net.raymanoz.command.MigrateCommand$Helper

package net.raymanoz.command;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import net.raymanoz.config.Configuration;
import net.raymanoz.config.ScriptStatus;
import net.raymanoz.domain.SchemaVersion;
import net.raymanoz.io.File;
import net.raymanoz.migrate.SchemaVersionRepository;
import net.raymanoz.migrate.Script;
import net.raymanoz.migrate.ScriptList;
import net.raymanoz.ui.UserInteractionStrategy;
import net.raymanoz.util.ScriptCalculator;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class MigrateCommand implements Command, MigrateCallBack {

  final public static String[] OVERRIDE_PROP_SWITCH_NAMES = new String[]{"properties", "p"};
  private static final Log LOG = LogFactory.getLog(MigrateCommand.class);
 
  static final String COMMAND_STRING = "migrate";
  static class Helper {
    long scriptsToBeApplied(SchemaVersion version, ScriptList scriptlist){
      return new ScriptCalculator(version, scriptlist).scriptsToBeApplied();
    }
  }
 
  private final CommandAssembler assembler;
  private final SchemaVersionRepository repository;
  private final Configuration configuration;
  private final UserInteractionStrategy interactionStrategy;
  private final Helper helper;
 
  MigrateCommand(SchemaVersionRepository repository, Configuration configuration, CommandAssembler assembler, Helper helper) {
    this.repository = repository;
    this.configuration = configuration;
    this.assembler = assembler;
    this.interactionStrategy = configuration.getUserInteractionStrategy();
    this.helper = helper;
  }

  public MigrateCommand(SchemaVersionRepository repository, Configuration configuration, CommandAssembler assembler) {
    this(repository, configuration, assembler, new Helper());
  }

  public void execute(String[] args) {
    execute();
  }
   
  public void execute() {
    if (interactionStrategy.startUIProcess(this)) return;
    summary();
    doMigration();
  }
 
  private ArrayList<ScriptList> scripts = new ArrayList<ScriptList>();
  private SchemaVersion version;
  private int scriptsToBeApplied = -1;

  SchemaVersion version(){
    if (version == null) version = repository.getVersion();
    return version;
  }

 
  List<ScriptList> scripts(){
    if (scripts.size() > 0) return scripts;
    version = version();
    repository.validateNoOtherLaterActivity(version);

    for (long dbver = version.getDBVersion(); dbver <= configuration.getLatestDBVersion(); dbver++) {
      File scriptsDir = configuration.getScriptDirectory(dbver);
      ScriptList scriptlist = assembler.newScriptList(scriptsDir.listFiles(), dbver);
      scripts.add(scriptlist);
    }
    return scripts;
  }

  final static String VERSION_LOG_MESSAGE_FMT = "%d scripts found for version %d, %d to be applied";
  final static String ALL_VERSIONS_LOG_MESSAGE_FMT = "%d scripts found for %d versions, %d to be applied";
  final static String STARTUP_STATUS_MESSAGE_FMT = "Schema DB version at startup: %d patch %d";
  final static String COMPLETED_STATUS_MESSAGE_FMT = "Schema DB version now: %d patch %d";

  private void logAndAppend(StringBuilder builder, String message){
    if (message == null||message.trim().isEmpty()) return;
    LOG.info(message);
    builder.append(message);
    builder.append("\n");
  }

  private void logAndAppend(StringBuilder builder, String messageFmt, Object ... args){
    logAndAppend(builder, String.format(messageFmt, args));
  }
 
  public String summary(){
    StringBuilder builder = new StringBuilder();
    LOG.info(configuration.getMigrationMessage());

    SchemaVersion ver = version();
    logAndAppend(builder, STARTUP_STATUS_MESSAGE_FMT, ver.getDBVersion(), ver.getPatchNo());
    scriptsToBeApplied = 0;
    long totalScripts = 0;
    for (ScriptList scriptlist: scripts()){
      totalScripts += scriptlist.size();
      long thisToApplied = helper.scriptsToBeApplied(ver, scriptlist);
      scriptsToBeApplied += thisToApplied;
      logAndAppend(builder, VERSION_LOG_MESSAGE_FMT, scriptlist.size(), scriptlist.DBVersion(), thisToApplied);
    }
    if (scripts.size() != 1) {
      logAndAppend(builder, ALL_VERSIONS_LOG_MESSAGE_FMT, totalScripts, scripts.size(), scriptsToBeApplied);
    }
    return builder.toString();
  }
 
  final static String SCRIPT_APPLICATION_STATUS_MESSAGE_FMT = "script (%d of %d): %s - %s";
 
  @Override
  public int noScriptsToMigrate() {
    if (scriptsToBeApplied < 0) summary();
    return scriptsToBeApplied;
  }

  private void logAndSendStatus(ScriptStatus status, Script script){
    LOG.info(status + ", " + script.description());
    interactionStrategy.scriptStatusMessage(scriptIdx, script, status);
  }

  private int scriptIdx = 0;
  private int scriptsApplied = 0;
  private int scriptsSkipped = 0;

  boolean alreadyMigrated(Script script){
    final long thisPatchNo = script.getPatch();
    final long thisDBver = script.getDBVersion();
    return (thisDBver < version().getDBVersion() || thisDBver == version().getDBVersion() && thisPatchNo <= version().getPatchNo());
  }
 
  boolean migrate(Script script){
    if (alreadyMigrated(script)) return true;
    final long thisPatchNo = script.getPatch();
    final long thisDBver = script.getDBVersion();
    SchemaVersion version = version();
    repository.validateNoOtherActivity(thisDBver, thisPatchNo);
    scriptIdx++;
    logAndSendStatus(ScriptStatus.STARTED, script);
    repository.recordStartPatch(script);
    ScriptStatus status = script.execute(interactionStrategy);
    repository.recordFinishPatch(script, status);
   
    logAndSendStatus(status, script);
    version.setDBVersion(thisDBver);
    version.setPatchNo(thisPatchNo);
    switch (status){
      case COMPLETED:
        scriptsApplied++;
        return true;
      case SKIPPED:
        scriptsSkipped++;
        return true;
    }
    return false;
  }
 
  private boolean migrateScripts(){
    for (ScriptList scriptlist : scripts()) {
      for (Script script : scriptlist) {
        if (!migrate(script)) return false;
       }
    }
    return true;
  }
 
  void closeConnection(){
    try {
      configuration.getConnection().close();
    } catch (Exception e) {
      LOG.error(e);
      interactionStrategy.errorMessage("Closing connection threw: " + e.getMessage());
    }       
  }
 
  public void doMigration() {
    boolean allMigrated = false;
    scriptIdx = 0;
    scriptsApplied = 0;
    scriptsSkipped = 0;
    final StringBuilder builder = new StringBuilder();
    SchemaVersion ver = version();
    final String startUpState = String.format(STARTUP_STATUS_MESSAGE_FMT, ver.getDBVersion(), ver.getPatchNo())
    try {
      allMigrated = migrateScripts();
      ver = repository.getVersion();
      logAndAppend(builder, startUpState);
      logAndAppend(builder, COMPLETED_STATUS_MESSAGE_FMT, ver.getDBVersion(), ver.getPatchNo());
    } finally {
      closeConnection();
      logAndAppend(builder, "%d script%s applied", scriptsApplied, ((scriptsApplied!=1)?"s":""));
      if (scriptsSkipped > 0) {
        logAndAppend(builder, "%d script%s skipped", scriptsSkipped, ((scriptsSkipped!=1)?"s":""));
        logAndAppend(builder, "%d script%s in total", scriptIdx, ((scriptIdx !=1)?"s":""));
      }
      interactionStrategy.completed(builder.toString(), allMigrated);
    }   
  }

  void addPropertiesNeedingValues(Script script, Set<String> variables){
    if (alreadyMigrated(script)) return;
    variables.addAll(script.variablesRequiringDialog());
  }
 
  @Override
  public Set<String> variablesRequiringDialogInOutstanding() {
    Set<String> result = new  HashSet<String>();
    for (ScriptList scriptlist : scripts()) {
      for (Script script : scriptlist) {
        addPropertiesNeedingValues(script, result);
       }
    }
    return result;
  }
 
  public String getCommandString() {
    return COMMAND_STRING;
  }

  @Override
  public String[] helpMessage() {
    return new String[]{
        "[--" + OVERRIDE_PROP_SWITCH_NAMES[0] + " override.properties]",
        "Performs a migration to the top revision",
        "when override.properties is specified this is searched first for ",
        "any configuration values.  If a value is not found in ",
        "override.properties, uMigrate.properties will then be checked"
    };
  }

}
TOP

Related Classes of net.raymanoz.command.MigrateCommand$Helper

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.