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

org.apache.geode.management.internal.cli.multistep.CLIMultiStepHelper Maven / Gradle / Ivy

Go to download

Apache Geode provides a database-like consistency model, reliable transaction processing and a shared-nothing architecture to maintain very low latency performance with high concurrency processing

There is a newer version: 1.15.1
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
 * agreements. See the NOTICE file distributed with this work for additional information regarding
 * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the License. You may obtain a
 * copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package org.apache.geode.management.internal.cli.multistep;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.geode.LogWriter;
import org.apache.geode.cache.CacheFactory;
import org.apache.geode.management.cli.Result;
import org.apache.geode.management.internal.cli.CliUtil;
import org.apache.geode.management.internal.cli.CommandRequest;
import org.apache.geode.management.internal.cli.GfshParseResult;
import org.apache.geode.management.internal.cli.LogWrapper;
import org.apache.geode.management.internal.cli.i18n.CliStrings;
import org.apache.geode.management.internal.cli.json.GfJsonException;
import org.apache.geode.management.internal.cli.json.GfJsonObject;
import org.apache.geode.management.internal.cli.remote.CommandExecutionContext;
import org.apache.geode.management.internal.cli.result.CommandResult;
import org.apache.geode.management.internal.cli.result.CompositeResultData;
import org.apache.geode.management.internal.cli.result.CompositeResultData.SectionResultData;
import org.apache.geode.management.internal.cli.result.ResultBuilder;
import org.apache.geode.management.internal.cli.result.ResultData;
import org.apache.geode.management.internal.cli.result.TabularResultData;
import org.apache.geode.management.internal.cli.shell.Gfsh;

import org.springframework.shell.event.ParseResult;
import org.springframework.util.ReflectionUtils;

/**
 * Utility class to abstract CompositeResultData for Multi-step commands Also contain execution
 * strategy for multi-step commands
 * 
 * 
 */
public class CLIMultiStepHelper {

  public static final String STEP_SECTION = "STEP_SECTION";
  public static final String PAGE_SECTION = "PAGE_SECTION";
  public static final String ARG_SECTION = "ARG_SECTION";
  public static final String NEXT_STEP_NAME = "NEXT_STEP_NAME";
  public static final String NEXT_STEP_ARGS = "NEXT_STEP_ARGS";
  public static final String NEXT_STEP_NAMES = "NEXT_STEP_NAMES";
  public static final String STEP_ARGS = "stepArgs";
  public static final int DEFAULT_PAGE_SIZE = 20;

  public static Object execCLISteps(LogWrapper logWrapper, Gfsh shell, ParseResult parseResult) {
    CLIStep[] steps = (CLIStep[]) ReflectionUtils.invokeMethod(parseResult.getMethod(),
        parseResult.getInstance(), parseResult.getArguments());
    if (steps != null) {
      boolean endStepReached = false;
      int stepNumber = 0;
      CLIStep nextStep = steps[stepNumber];
      Result lastResult = null;
      SectionResultData nextStepArgs = null;
      while (!endStepReached) {
        try {
          Result result = executeStep(logWrapper, shell, nextStep, parseResult, nextStepArgs);
          String nextStepString = null;
          nextStepString = getNextStep(result);
          nextStepArgs = extractArgumentsForNextStep(result);
          if (!"END".equals(nextStepString)) {
            String step = nextStepString;
            boolean stepFound = false;
            for (CLIStep s : steps)
              if (step.equals(s.getName())) {
                nextStep = s;
                stepFound = true;
              }
            if (!stepFound) {
              return ResultBuilder.buildResult(ResultBuilder.createErrorResultData()
                  .addLine("Wrong step name returned by previous step : " + step));
            }
          } else {
            lastResult = result;
            endStepReached = true;
          }

        } catch (CLIStepExecption e) {
          endStepReached = true;
          lastResult = e.getResult();
        }
      }
      return lastResult;
    } else {
      Gfsh.println("Command returned null steps");
      return ResultBuilder.buildResult(ResultBuilder.createErrorResultData()
          .addLine("Multi-step command Return NULL STEP Array"));
    }
  }

  private static Result executeStep(final LogWrapper logWrapper, final Gfsh shell,
      final CLIStep nextStep, final ParseResult parseResult, final SectionResultData nextStepArgs) {
    try {
      if (nextStep instanceof CLIRemoteStep) {
        if (shell.isConnectedAndReady()) {
          if (GfshParseResult.class.isInstance(parseResult)) {
            GfshParseResult gfshParseResult = (GfshParseResult) parseResult;
            // this makes sure that "quit" step will correctly update the environment with empty
            // stepArgs
            if (nextStepArgs != null) {
              GfJsonObject argsJSon = nextStepArgs.getSectionGfJsonObject();
              shell.setEnvProperty(CLIMultiStepHelper.STEP_ARGS, argsJSon.toString());
            }
            CommandRequest commandRequest = new CommandRequest(gfshParseResult, shell.getEnv());
            commandRequest
                .setCustomInput(changeStepName(gfshParseResult.getUserInput(), nextStep.getName()));
            commandRequest.getCustomParameters().put(CliStrings.QUERY__STEPNAME,
                nextStep.getName());

            String json = (String) shell.getOperationInvoker().processCommand(commandRequest);

            return ResultBuilder.fromJson(json);
          } else {
            throw new IllegalArgumentException("Command Configuration/Definition error.");
          }
        } else {
          try {
            throw new Exception();
          } catch (Exception ex) {
            ex.printStackTrace();
          }
          throw new IllegalStateException(
              "Can't execute a remote command without connection. Use 'connect' first to connect.");
        }
      } else {
        Map args = CommandExecutionContext.getShellEnv();
        if (args == null) {
          args = new HashMap();
          CommandExecutionContext.setShellEnv(args);
        }
        if (nextStepArgs != null) {
          GfJsonObject argsJSon = nextStepArgs.getSectionGfJsonObject();
          Gfsh.getCurrentInstance().setEnvProperty(CLIMultiStepHelper.STEP_ARGS,
              argsJSon.toString());
        }
        return nextStep.exec();
      }
    } catch (CLIStepExecption e) {
      logWrapper.severe("CLIStep " + nextStep.getName() + " failed aborting command");
      throw e;
    }
  }

  private static String changeStepName(String userInput, String stepName) {
    int i = userInput.indexOf("--step-name=");
    if (i == -1) {
      return userInput + " --step-name=" + stepName;
    } else {
      // TODO this is a dangerous assumption... to assume the "--step-name" query command option is
      // the last parameter
      // specified!
      return userInput.substring(0, i) + "--step-name=" + stepName;
    }
  }

  public static SectionResultData extractArgumentsForNextStep(Result result) {
    CommandResult cResult = (CommandResult) result;
    if (ResultData.TYPE_COMPOSITE.equals(cResult.getType())) {
      CompositeResultData rd = (CompositeResultData) cResult.getResultData();
      SectionResultData data = rd.retrieveSection(CLIMultiStepHelper.ARG_SECTION);
      return data;
    } else {
      if (ResultData.TYPE_ERROR.equals(cResult.getType())) {
        throw new CLIStepExecption(cResult);
      } else {
        throw new StepExecutionException("Step returned result of type other than "
            + ResultData.TYPE_COMPOSITE + " Type " + cResult.getType());
      }
    }
  }

  public static String getNextStep(Result cdata) {
    CommandResult cResult = (CommandResult) cdata;
    if (ResultData.TYPE_COMPOSITE.equals(cResult.getType())) {
      CompositeResultData rd = (CompositeResultData) cResult.getResultData();
      SectionResultData section = rd.retrieveSection(CLIMultiStepHelper.STEP_SECTION);
      String nextStep = (String) section.retrieveObject(CLIMultiStepHelper.NEXT_STEP_NAME);
      return nextStep;
    } else {
      if (ResultData.TYPE_ERROR.equals(cResult.getType())) {
        throw new CLIStepExecption(cResult);
      } else {
        throw new RuntimeException("Step returned result of type other than "
            + ResultData.TYPE_COMPOSITE + " Type " + cResult.getType());
      }
    }
  }

  public static CommandResult getDisplayResultFromArgs(GfJsonObject args) {
    SectionResultData sectionData = new SectionResultData(args);
    CompositeResultData data = ResultBuilder.createCompositeResultData();
    data.addSection(sectionData);
    return (CommandResult) ResultBuilder.buildResult(data);
  }

  public static GfJsonObject getStepArgs() {
    Map args = null;
    if (CliUtil.isGfshVM) {
      args = Gfsh.getCurrentInstance().getEnv();
    } else {
      args = CommandExecutionContext.getShellEnv();
    }
    if (args == null)
      return null;
    String stepArg = args.get(CLIMultiStepHelper.STEP_ARGS);
    if (stepArg == null)
      return null;
    GfJsonObject object;
    try {
      object = new GfJsonObject(stepArg);
    } catch (GfJsonException e) {
      throw new RuntimeException("Error converting arguments section into json object");
    }
    return object;
  }

  public static Result createSimpleStepResult(String nextStep) {
    CompositeResultData result = ResultBuilder.createCompositeResultData();
    SectionResultData section = result.addSection(STEP_SECTION);
    section.addData(NEXT_STEP_NAME, nextStep);
    return ResultBuilder.buildResult(result);
  }

  public static Object chooseStep(CLIStep[] steps, String stepName) {
    if ("ALL".equals(stepName)) {
      return steps;
    } else {
      for (CLIStep s : steps)
        if (stepName.equals(s.getName())) {
          return s.exec();
        }
      return null;
    }
  }

  public static Result createStepSeqResult(CLIStep[] steps) {
    CompositeResultData result = ResultBuilder.createCompositeResultData();
    SectionResultData section = result.addSection(STEP_SECTION);
    section.addData(NEXT_STEP_NAME, steps[0].getName());
    String[] array = new String[steps.length];
    for (int i = 0; i < steps.length; i++) {
      array[i] = steps[i++].getName();
    }
    section.addData(NEXT_STEP_NAMES, array);
    return ResultBuilder.buildResult(result);
  }

  public static Result createEmptyResult(String step) {
    CompositeResultData result = ResultBuilder.createCompositeResultData();
    SectionResultData section = result.addSection(STEP_SECTION);
    section.addData(NEXT_STEP_NAME, step);
    return ResultBuilder.buildResult(result);
  }

  public static Result createPageResult(String fields[], Object values[], String step,
      String[] header, Object[][] table) {
    CompositeResultData result = ResultBuilder.createCompositeResultData();
    SectionResultData section = result.addSection(STEP_SECTION);
    section.addData(NEXT_STEP_NAME, step);
    SectionResultData page = result.addSection(ARG_SECTION);

    if (fields.length != values.length)
      throw new RuntimeException("Fields array and its value arraylength dont match");
    for (int i = 0; i < fields.length; i++) {
      page.addData(fields[i], values[i]);
    }
    createPageTableAndBanner(page, header, table);
    return ResultBuilder.buildResult(result);
  }

  public static Result createPageResult(List fields,
      @SuppressWarnings("rawtypes") List values, String step, String[] header, Object[][] table) {
    CompositeResultData result = ResultBuilder.createCompositeResultData();
    SectionResultData section = result.addSection(STEP_SECTION);
    section.addData(NEXT_STEP_NAME, step);
    SectionResultData page = result.addSection(ARG_SECTION);

    if (fields.size() != values.size())
      throw new RuntimeException("Fields array and its value arraylength dont match");
    for (int i = 0; i < fields.size(); i++) {
      page.addData(fields.get(i), values.get(i));
    }
    createPageTableAndBanner(page, header, table);
    return ResultBuilder.buildResult(result);
  }

  private static void createPageTableAndBanner(SectionResultData page, String[] header,
      Object[][] table) {
    TabularResultData resultData = page.addTable();
    int columns = header.length;
    for (int i = 0; i < table.length; i++) {
      int rowLength = table[i].length;
      if (rowLength != columns)
        throw new RuntimeException("Row contains more than " + columns + " :  " + rowLength);
    }

    for (int i = 0; i < table.length; i++) {
      for (int j = 0; j < columns; j++) {
        resultData.accumulate(header[j], table[i][j]);
      }
    }
  }

  public static Result createBannerResult(String fields[], Object values[], String step) {
    CompositeResultData result = ResultBuilder.createCompositeResultData();
    SectionResultData section = result.addSection(STEP_SECTION);
    section.addData(NEXT_STEP_NAME, step);
    SectionResultData page = result.addSection(ARG_SECTION);
    if (fields.length != values.length) {
      throw new RuntimeException("Fields array and its value arraylength dont match");
    }
    for (int i = 0; i < fields.length; i++) {
      page.addData(fields[i], values[i]);
    }
    return ResultBuilder.buildResult(result);
  }

  public static Result createBannerResult(List fields,
      @SuppressWarnings("rawtypes") List values, String step) {
    CompositeResultData result = ResultBuilder.createCompositeResultData();
    SectionResultData section = result.addSection(STEP_SECTION);
    section.addData(NEXT_STEP_NAME, step);
    SectionResultData page = result.addSection(ARG_SECTION);
    if (fields.size() != values.size()) {
      throw new RuntimeException("Fields array and its value arraylength dont match");
    }
    for (int i = 0; i < fields.size(); i++) {
      page.addData(fields.get(i), values.get(i));
    }
    return ResultBuilder.buildResult(result);
  }

  public static void logFine(String msg) {
    Gfsh.println(msg);
    // TODO Use gemfire Logging for code path running on manager
  }

  public static abstract class LocalStep implements CLIStep {
    private String name = null;
    protected Object[] commandArguments = null;

    public LocalStep(String name, Object[] arguments) {
      this.name = name;
      this.commandArguments = arguments;
    }

    public String getName() {
      return name;
    }
  }

  @SuppressWarnings("serial")
  public static abstract class RemoteStep implements CLIRemoteStep {
    private String name = null;
    protected Object[] commandArguments = null;

    public RemoteStep(String name, Object[] arguments) {
      this.name = name;
      this.commandArguments = arguments;
    }

    public String getName() {
      return name;
    }
  }

  public static class StepExecutionException extends RuntimeException {
    private static final long serialVersionUID = 1L;
    private String message;

    public StepExecutionException(String message) {
      LogWriter logger = CacheFactory.getAnyInstance().getLogger();
      logger.severe(message);
      this.message = message;
    }

    @Override
    public String getMessage() {
      return StepExecutionException.class.getName();
    }

    public String getStepExecutionExceptionMessage() {
      return message;
    }

  }


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy