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

org.apache.geode.management.internal.cli.CommandManager 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;

import org.apache.geode.distributed.ConfigurationProperties;
import org.apache.geode.distributed.internal.DistributionConfig;
import org.apache.geode.internal.ClassPathLoader;
import org.apache.geode.management.cli.CliMetaData;
import org.apache.geode.management.internal.cli.annotation.CliArgument;
import org.apache.geode.management.internal.cli.help.CliTopic;
import org.apache.geode.management.internal.cli.parser.*;
import org.apache.geode.management.internal.cli.parser.jopt.JoptOptionParser;
import org.apache.geode.management.internal.cli.util.ClasspathScanLoadHelper;
import org.springframework.shell.core.CommandMarker;
import org.springframework.shell.core.Converter;
import org.springframework.shell.core.annotation.CliAvailabilityIndicator;
import org.springframework.shell.core.annotation.CliCommand;
import org.springframework.shell.core.annotation.CliOption;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.*;
import java.util.Map.Entry;

import static org.apache.geode.distributed.ConfigurationProperties.*;

/**
 * 
 * @since GemFire 7.0
 */
public class CommandManager {
  // 1. Load Commands, availability indicators - Take from GfshParser
  // 2. Load Converters - Take from GfshParser
  // 3. Load Result Converters - Add

  private static final Object INSTANCE_LOCK = new Object();
  private static CommandManager INSTANCE = null;
  public static final String USER_CMD_PACKAGES_PROPERTY =
      DistributionConfig.GEMFIRE_PREFIX + USER_COMMAND_PACKAGES;
  public static final String USER_CMD_PACKAGES_ENV_VARIABLE = "GEMFIRE_USER_COMMAND_PACKAGES";

  private Properties cacheProperties;

  private LogWrapper logWrapper;

  private CommandManager(final boolean loadDefaultCommands, final Properties cacheProperties)
      throws ClassNotFoundException, IOException {
    if (cacheProperties != null) {
      this.cacheProperties = cacheProperties;
    }

    logWrapper = LogWrapper.getInstance();
    if (loadDefaultCommands) {
      loadCommands();

      if (logWrapper.fineEnabled()) {
        logWrapper.fine("Commands Loaded: " + commands.keySet());
        logWrapper
            .fine("Command Availability Indicators Loaded: " + availabilityIndicators.keySet());
        logWrapper.fine("Converters Loaded: " + converters);
      }
    }
  }

  private void loadUserCommands() throws ClassNotFoundException, IOException {
    final Set userCommandPackages = new HashSet();

    // Find by packages specified by the system property
    if (System.getProperty(USER_CMD_PACKAGES_PROPERTY) != null) {
      StringTokenizer tokenizer =
          new StringTokenizer(System.getProperty(USER_CMD_PACKAGES_PROPERTY), ",");
      while (tokenizer.hasMoreTokens()) {
        userCommandPackages.add(tokenizer.nextToken());
      }
    }

    // Find by packages specified by the environment variable
    if (System.getenv().containsKey(USER_CMD_PACKAGES_ENV_VARIABLE)) {
      StringTokenizer tokenizer =
          new StringTokenizer(System.getenv().get(USER_CMD_PACKAGES_ENV_VARIABLE), ",");
      while (tokenizer.hasMoreTokens()) {
        userCommandPackages.add(tokenizer.nextToken());
      }
    }

    // Find by packages specified in the distribution config
    if (this.cacheProperties != null) {
      String cacheUserCmdPackages =
          this.cacheProperties.getProperty(ConfigurationProperties.USER_COMMAND_PACKAGES);
      if (cacheUserCmdPackages != null && !cacheUserCmdPackages.isEmpty()) {
        StringTokenizer tokenizer = new StringTokenizer(cacheUserCmdPackages, ",");
        while (tokenizer.hasMoreTokens()) {
          userCommandPackages.add(tokenizer.nextToken());
        }
      }
    }

    // Load commands found in all of the packages
    for (String userCommandPackage : userCommandPackages) {
      try {
        Set> foundClasses =
            ClasspathScanLoadHelper.loadAndGet(userCommandPackage, CommandMarker.class, true);
        for (Class klass : foundClasses) {
          try {
            add((CommandMarker) klass.newInstance());
          } catch (Exception e) {
            logWrapper.warning("Could not load User Commands from: " + klass + " due to "
                + e.getLocalizedMessage()); // continue
          }
        }
        raiseExceptionIfEmpty(foundClasses, "User Command");
      } catch (ClassNotFoundException e) {
        logWrapper.warning("Could not load User Commands due to " + e.getLocalizedMessage());
        throw e;
      } catch (IOException e) {
        logWrapper.warning("Could not load User Commands due to " + e.getLocalizedMessage());
        throw e;
      } catch (IllegalStateException e) {
        logWrapper.warning(e.getMessage(), e);
        throw e;
      }
    }
  }

  /**
   * Loads commands via {@link ServiceLoader} from {@link ClassPathLoader}.
   * 
   * @since GemFire 8.1
   */
  private void loadPluginCommands() {
    final Iterator iterator = ServiceLoader
        .load(CommandMarker.class, ClassPathLoader.getLatest().asClassLoader()).iterator();
    while (iterator.hasNext()) {
      try {
        final CommandMarker commandMarker = iterator.next();
        try {
          add(commandMarker);
        } catch (Exception e) {
          logWrapper.warning("Could not load Command from: " + commandMarker.getClass() + " due to "
              + e.getLocalizedMessage(), e); // continue
        }
      } catch (ServiceConfigurationError e) {
        logWrapper.severe("Could not load Command: " + e.getLocalizedMessage(), e); // continue
      }
    }
  }

  private void loadCommands() throws ClassNotFoundException, IOException {
    loadUserCommands();

    loadPluginCommands();

    // CommandMarkers
    Set> foundClasses = null;
    try {
      foundClasses = ClasspathScanLoadHelper.loadAndGet(
          "org.apache.geode.management.internal.cli.commands", CommandMarker.class, true);
      for (Class klass : foundClasses) {
        try {
          add((CommandMarker) klass.newInstance());
        } catch (Exception e) {
          logWrapper.warning(
              "Could not load Command from: " + klass + " due to " + e.getLocalizedMessage()); // continue
        }
      }
      raiseExceptionIfEmpty(foundClasses, "Commands");
    } catch (ClassNotFoundException e) {
      logWrapper.warning("Could not load Commands due to " + e.getLocalizedMessage());
      throw e;
    } catch (IOException e) {
      logWrapper.warning("Could not load Commands due to " + e.getLocalizedMessage());
      throw e;
    } catch (IllegalStateException e) {
      logWrapper.warning(e.getMessage(), e);
      throw e;
    }

    // Converters
    try {
      foundClasses = ClasspathScanLoadHelper
          .loadAndGet("org.apache.geode.management.internal.cli.converters", Converter.class, true);
      for (Class klass : foundClasses) {
        try {
          add((Converter) klass.newInstance());
        } catch (Exception e) {
          logWrapper.warning(
              "Could not load Converter from: " + klass + " due to " + e.getLocalizedMessage()); // continue
        }
      }
      raiseExceptionIfEmpty(foundClasses, "Converters");
    } catch (ClassNotFoundException e) {
      logWrapper.warning("Could not load Converters due to " + e.getLocalizedMessage());
      throw e;
    } catch (IOException e) {
      logWrapper.warning("Could not load Converters due to " + e.getLocalizedMessage());
      throw e;
    } catch (IllegalStateException e) {
      logWrapper.warning(e.getMessage(), e);
      throw e;
    }

    // Roo's Converters
    try {
      foundClasses = ClasspathScanLoadHelper.loadAndGet("org.springframework.shell.converters",
          Converter.class, true);
      for (Class klass : foundClasses) {
        try {
          if (!SHL_CONVERTERS_TOSKIP.contains(klass.getName())) {
            add((Converter) klass.newInstance());
          }
        } catch (Exception e) {
          logWrapper.warning(
              "Could not load Converter from: " + klass + " due to " + e.getLocalizedMessage()); // continue
        }
      }
      raiseExceptionIfEmpty(foundClasses, "Basic Converters");
    } catch (ClassNotFoundException e) {
      logWrapper.warning("Could not load Default Converters due to " + e.getLocalizedMessage());// TODO
                                                                                                // -
                                                                                                // Abhishek:
                                                                                                // Should
                                                                                                // these
                                                                                                // converters
                                                                                                // be
                                                                                                // moved
                                                                                                // in
                                                                                                // GemFire?
      throw e;
    } catch (IOException e) {
      logWrapper.warning("Could not load Default Converters due to " + e.getLocalizedMessage());// TODO
                                                                                                // -
                                                                                                // Abhishek:
                                                                                                // Should
                                                                                                // these
                                                                                                // converters
                                                                                                // be
                                                                                                // moved
                                                                                                // in
                                                                                                // GemFire?
      throw e;
    } catch (IllegalStateException e) {
      logWrapper.warning(e.getMessage(), e);
      throw e;
    }
  }

  private static void raiseExceptionIfEmpty(Set> foundClasses, String errorFor)
      throws IllegalStateException {
    if (foundClasses == null || foundClasses.isEmpty()) {
      throw new IllegalStateException(
          "Required " + errorFor + " classes were not loaded. Check logs for errors.");
    }
  }

  public static CommandManager getInstance() throws ClassNotFoundException, IOException {
    return getInstance(true);
  }

  public static CommandManager getInstance(Properties cacheProperties)
      throws ClassNotFoundException, IOException {
    return getInstance(true, cacheProperties);
  }

  // For testing.
  public static void clearInstance() {
    synchronized (INSTANCE_LOCK) {
      INSTANCE = null;
    }
  }

  // This method exists for test code use only ...
  /* package */static CommandManager getInstance(boolean loadDefaultCommands)
      throws ClassNotFoundException, IOException {
    return getInstance(loadDefaultCommands, null);
  }

  private static CommandManager getInstance(boolean loadDefaultCommands, Properties cacheProperties)
      throws ClassNotFoundException, IOException {
    synchronized (INSTANCE_LOCK) {
      if (INSTANCE == null) {
        INSTANCE = new CommandManager(loadDefaultCommands, cacheProperties);
      }
      return INSTANCE;
    }
  }

  public static CommandManager getExisting() {
    // if (INSTANCE == null) {
    // throw new IllegalStateException("CommandManager doesn't exist.");
    // }
    return INSTANCE;
  }

  /** Skip some of the Converters from Spring Shell for our customization */
  private static List SHL_CONVERTERS_TOSKIP = new ArrayList();
  static {
    // Over-ridden by cggm.internal.cli.converters.BooleanConverter
    SHL_CONVERTERS_TOSKIP.add("org.springframework.shell.converters.BooleanConverter");
    // Over-ridden by cggm.internal.cli.converters.EnumConverter
    SHL_CONVERTERS_TOSKIP.add("org.springframework.shell.converters.EnumConverter");
  }

  /**
   * List of converters which should be populated first before any command can be added
   */
  private final List> converters = new ArrayList>();

  /**
   * Map of command string and actual CommandTarget object
   * 
   * This map can also be implemented as a trie to support command abbreviation
   */
  private final Map commands = new TreeMap();

  /**
   * This method will store the all the availabilityIndicators
   */
  private final Map availabilityIndicators =
      new HashMap();

  /**
   */
  private final Map topics = new TreeMap();

  /**
   * Method to add new Converter
   * 
   * @param converter
   */
  public void add(Converter converter) {
    converters.add(converter);
  }

  /**
   * Method to add new Commands to the parser
   * 
   * @param commandMarker
   */
  public void add(CommandMarker commandMarker) {
    // First we need to find out all the methods marked with
    // Command annotation
    Method[] methods = commandMarker.getClass().getMethods();
    for (Method method : methods) {
      if (method.getAnnotation(CliCommand.class) != null) {

        //
        // First Build the option parser
        //

        // Create the empty LinkedLists for storing the argument and
        // options
        LinkedList arguments = new LinkedList();
        LinkedList




© 2015 - 2024 Weber Informatics LLC | Privacy Policy