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

com.gemstone.gemfire.management.internal.cli.GfshParser Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2010-2015 Pivotal Software, Inc. All rights reserved.
 *
 * Licensed 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. See accompanying
 * LICENSE file.
 */
package com.gemstone.gemfire.management.internal.cli;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.logging.Logger;
import java.util.regex.Pattern;

import org.springframework.shell.core.AbstractShell;
import org.springframework.shell.core.Completion;
import org.springframework.shell.core.Converter;
import org.springframework.shell.core.MethodTarget;
import org.springframework.shell.core.Parser;
import org.springframework.shell.event.ParseResult;

import com.gemstone.gemfire.management.cli.CommandProcessingException;
import com.gemstone.gemfire.management.internal.cli.exceptions.CliCommandOptionException;
import com.gemstone.gemfire.management.internal.cli.exceptions.CliException;
import com.gemstone.gemfire.management.internal.cli.exceptions.ExceptionHandler;
import com.gemstone.gemfire.management.internal.cli.help.format.NewHelp;
import com.gemstone.gemfire.management.internal.cli.help.utils.HelpUtils;
import com.gemstone.gemfire.management.internal.cli.i18n.CliStrings;
import com.gemstone.gemfire.management.internal.cli.parser.Argument;
import com.gemstone.gemfire.management.internal.cli.parser.AvailabilityTarget;
import com.gemstone.gemfire.management.internal.cli.parser.CommandTarget;
import com.gemstone.gemfire.management.internal.cli.parser.GfshMethodTarget;
import com.gemstone.gemfire.management.internal.cli.parser.MethodParameter;
import com.gemstone.gemfire.management.internal.cli.parser.Option;
import com.gemstone.gemfire.management.internal.cli.parser.OptionSet;
import com.gemstone.gemfire.management.internal.cli.parser.Parameter;
import com.gemstone.gemfire.management.internal.cli.parser.ParserUtils;
import com.gemstone.gemfire.management.internal.cli.parser.SyntaxConstants;
import com.gemstone.gemfire.management.internal.cli.parser.preprocessor.PreprocessorUtils;
import com.gemstone.gemfire.management.internal.cli.parser.preprocessor.TrimmedInput;
import com.gemstone.gemfire.management.internal.cli.shell.Gfsh;
import com.gemstone.gemfire.management.internal.cli.util.CLIConsoleBufferUtil;
import com.gemstone.gemfire.management.internal.cli.util.spring.StringUtils;

/**
 * Implementation of the {@link Parser} interface for GemFire SHell (gfsh)
 * requirements.
 *
 * @author Nikhil Jadhav
 * @author Abhishek Chaudhari
 * @since 7.0
 */
public class GfshParser implements Parser {
  public static final String LINE_SEPARATOR = System.getProperty("line.separator");

  // Constants used while finding command targets for help
  private final static Short EXACT_TARGET     = (short)0;
  private final static Short MATCHING_TARGETS = (short)1;

  // Make use of LogWrapper
  private static final LogWrapper logWrapper = LogWrapper.getInstance();

  // private CliStringResourceBundle cliStringBundle;
  private CommandManager commandManager;

  /**
   * Used for warning messages
   */
  // TODO Investigating using GemFire logging.
  private final Logger consoleLogger;

  public GfshParser(CommandManager commandManager) {
    // cliStringBundle = new
    // CliStringResourceBundle("com/gemstone/gemfire/management/internal/cli/i18n/CliStringResourceBundle");
    this.commandManager = commandManager;
    if (CliUtil.isGfshVM()) {
      consoleLogger = Logger.getLogger(this.getClass().getCanonicalName());
    } else {
      consoleLogger = logWrapper.getLogger();
    }
  }

  // ///////////////// Parser interface Methods Start //////////////////////////
  // ////////////////////// Implemented Methods ////////////////////////////////
  /**
   * Populates a list of completion candidates. See
   * {@link Parser#complete(String, int, List)} for details.
   *
   * @param buffer
   * @param cursor
   * @param completionCandidates
   * @return new cursor position
   */
  public int complete(String buffer, int cursor,
      List completionCandidates) {
    final List candidates = new ArrayList();
    final int result = completeAdvanced(buffer, cursor, candidates);
    for (final Completion completion : candidates) {
      completionCandidates.add(completion.getValue());
    }
    return result;
  }

  /**
   * Populates a list of completion candidates.
   *
   * @param buffer
   * @param cursor
   * @param completionCandidates
   * @return new cursor position
   */
  public int completeAdvanced(String buffer, int cursor,
      List completionCandidates) {
    // Currently, support for auto-completion
    // in between is not supported, only if the
    // cursor is at the end

    if (cursor <= buffer.length() - 1
        && !PreprocessorUtils.containsOnlyWhiteSpaces(buffer.substring(cursor))
        || (ParserUtils.contains(buffer, SyntaxConstants.COMMAND_DELIMITER))) {
      return cursor;
    }

    int desiredCursorPosition = 0;

    try {
      TrimmedInput simpleTrim = PreprocessorUtils.simpleTrim(buffer);
      desiredCursorPosition += simpleTrim.getNoOfSpacesRemoved();
      List targets = locateTargets(simpleTrim.getString());
      if (targets.size() > 1) {
        String padding = desiredCursorPosition != 0 ? ParserUtils.getPadding(desiredCursorPosition) : "";
        // This means that what the user has entered matches
        // the beginning of many commands
        for (CommandTarget commandTarget : targets) {
          completionCandidates.add(new Completion(padding + commandTarget
              .getGfshMethodTarget().getKey()));
        }
      } else {
        if (targets.size() == 1) {
          CommandTarget commandTarget = targets.get(0);
          // Only one command matches but we still have to check
          // whether the user has properly entered it or not
          if (simpleTrim.getString().length() >= commandTarget
              .getGfshMethodTarget().getKey().length()) {
            /* int position = */
            return completeParameters(commandTarget, desiredCursorPosition
                + commandTarget.getGfshMethodTarget().getKey().length(),
                commandTarget.getGfshMethodTarget().getRemainingBuffer(),
                cursor, completionCandidates);
            /*
             * updateCompletionCandidates(completionCandidates, buffer,
             * position); return 0;
             */
          } else {
            String padding = desiredCursorPosition != 0 ? ParserUtils.getPadding(desiredCursorPosition) : "";
            // User has still not entered the command name properly,
            // we need to populate the completionCandidates list
            completionCandidates.add(new Completion(padding + commandTarget
                .getGfshMethodTarget().getKey()));
          }
        }
      }

    } catch (IllegalArgumentException e) {
      logWrapper.warning(CliUtil.stackTraceAsString(e));
    } catch (IllegalAccessException e) {
      logWrapper.warning(CliUtil.stackTraceAsString(e));
    } catch (InvocationTargetException e) {
      logWrapper.warning(CliUtil.stackTraceAsString(e));
    } catch (RuntimeException e) {
      logWrapper.warning(CliUtil.stackTraceAsString(e));
    }
    // Returning 0 for exceptions too. This will break the completors' loop in
    // jline.ConsoleReader.complete() & will return false
    return 0;
  }

  @SuppressWarnings("unused")
  private void updateCompletionCandidates(
      List completionCandidates, String buffer, int position) {
    List temp = new ArrayList();
    while (completionCandidates.size() > 0) {
      temp.add(completionCandidates.remove(0));
    }
    for (Completion completion : temp) {
      completionCandidates.add(new Completion(buffer.substring(0, position)
          + completion.getValue(), completion.getFormattedValue(), completion
          .getHeading(), completion.getOrder()));
    }
  }

  private int completeParameters(CommandTarget commandTarget, int cursorStart,
      String remainingBuffer, int cursor, List completionCandidates) {
    int desiredCursorPosition = cursorStart;
    // Factor for remainingBuffer
    boolean sizeReduced = false;
    // We need to work modify the flow according to the CliException
    // generated. For that we will need a reference to the Exception
    // CliException reference
    CliCommandOptionException coe = null;
    OptionSet userOptionSet = null;
    try {
      // We need to remove the space which separates command from the
      // parameters
      if (remainingBuffer.length() > 0) {
        remainingBuffer = remainingBuffer.substring(1);
        sizeReduced = true;
      }

      userOptionSet = commandTarget.getOptionParser().parse(remainingBuffer);
    } catch (CliException ce) {
      if (ce instanceof CliCommandOptionException) {
        coe = (CliCommandOptionException) ce;
        coe.setCommandTarget(commandTarget);
        userOptionSet = coe.getOptionSet();
      }
    }

    // Contains mandatory options which have not been specified
    List




© 2015 - 2024 Weber Informatics LLC | Privacy Policy