You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by je...@apache.org on 2017/11/17 23:22:25 UTC
[geode] branch develop updated: Revert "GEODE-3007: Simplify
support for custom GFSH commands (#1042)" (#1072)
This is an automated email from the ASF dual-hosted git repository.
jensdeppe pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/geode.git
The following commit(s) were added to refs/heads/develop by this push:
new 2b21e2b Revert "GEODE-3007: Simplify support for custom GFSH commands (#1042)" (#1072)
2b21e2b is described below
commit 2b21e2bd6a3ba7fbcd9a2d8e93ae2aef852689ad
Author: Jens Deppe <jd...@pivotal.io>
AuthorDate: Fri Nov 17 15:22:22 2017 -0800
Revert "GEODE-3007: Simplify support for custom GFSH commands (#1042)" (#1072)
This reverts commit 0e5dd6ba45519463147337c8265db15e8f1840fc.
---
geode-assembly/build.gradle | 2 +
.../cli/commands/StatusLocatorRealGfshTest.java | 1 +
.../geode/distributed/ConfigurationProperties.java | 3 -
.../internal/AbstractDistributionConfig.java | 3 +
.../distributed/internal/DistributionConfig.java | 28 ++
.../internal/DistributionConfigImpl.java | 21 +-
.../internal/beans/MemberMBeanBridge.java | 3 +-
.../management/internal/cli/CommandManager.java | 307 +++++++++++++++++----
.../geode/management/internal/cli/GfshParser.java | 8 +-
.../geode/management/internal/cli/help/Helper.java | 63 ++---
.../internal/cli/remote/MemberCommandService.java | 3 +-
.../cli/remote/OnlineCommandProcessor.java | 16 +-
.../internal/cli/util/ClasspathScanLoadHelper.java | 23 +-
.../internal/DistributionConfigJUnitTest.java | 4 +-
.../cli/ClasspathScanLoadHelperJUnitTest.java | 27 +-
.../internal/cli/CommandManagerJUnitTest.java | 156 ++++++++++-
.../internal/cli/commands/CliCommandTestBase.java | 4 +-
.../cli/remote/OnlineCommandProcessorTest.java | 6 +-
.../org.springframework.shell.core.CommandMarker | 8 +
.../org.springframework.shell.core.CommandMarker | 2 +
20 files changed, 537 insertions(+), 151 deletions(-)
diff --git a/geode-assembly/build.gradle b/geode-assembly/build.gradle
index 4615a6b..1f139a5 100755
--- a/geode-assembly/build.gradle
+++ b/geode-assembly/build.gradle
@@ -198,12 +198,14 @@ def cp = {
it.contains('snappy') ||
it.contains('jgroups') ||
it.contains('netty') ||
+
// dependencies from geode-lucene
it.contains('lucene-analyzers-common') ||
it.contains('lucene-core') ||
it.contains('lucene-queries') ||
it.contains('lucene-queryparser') ||
it.contains('lucene-analyzers-phonetic') ||
+
// dependencies from geode-protobuf
it.contains('protobuf-java')
}
diff --git a/geode-assembly/src/test/java/org/apache/geode/management/internal/cli/commands/StatusLocatorRealGfshTest.java b/geode-assembly/src/test/java/org/apache/geode/management/internal/cli/commands/StatusLocatorRealGfshTest.java
index 94ddc8f..7e7b2bd 100644
--- a/geode-assembly/src/test/java/org/apache/geode/management/internal/cli/commands/StatusLocatorRealGfshTest.java
+++ b/geode-assembly/src/test/java/org/apache/geode/management/internal/cli/commands/StatusLocatorRealGfshTest.java
@@ -30,6 +30,7 @@ public class StatusLocatorRealGfshTest {
@Test
public void statusLocatorSucceedsWhenConnected() throws Exception {
GfshScript.of("start locator --name=locator1").execute(gfshRule);
+
GfshScript.of("connect", "status locator --name=locator1").execute(gfshRule);
}
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/ConfigurationProperties.java b/geode-core/src/main/java/org/apache/geode/distributed/ConfigurationProperties.java
index 4944e98..649bfad 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/ConfigurationProperties.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/ConfigurationProperties.java
@@ -1860,10 +1860,7 @@ public interface ConfigurationProperties {
* <U>Default</U>: <code>""</code>
* </p>
* <U>Since</U>: GemFire 8.0
- *
- * @deprecated Since Geode 1.4 (See GEODE-3007)
*/
- @Deprecated()
String USER_COMMAND_PACKAGES = "user-command-packages";
/**
* The static String definition of the <i>"off-heap-memory-size"</i> property <a
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/AbstractDistributionConfig.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/AbstractDistributionConfig.java
index 7c5929c..43c5cb4 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/AbstractDistributionConfig.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/AbstractDistributionConfig.java
@@ -1018,6 +1018,9 @@ public abstract class AbstractDistributionConfig extends AbstractConfig
m.put(GROUPS,
"A comma separated list of all the groups this member belongs to." + " Defaults to \"\".");
+ m.put(USER_COMMAND_PACKAGES,
+ "A comma separated list of the names of the packages containing classes that implement user commands.");
+
m.put(JMX_MANAGER,
"If true then this member is willing to be a jmx manager. Defaults to false except on a locator.");
m.put(JMX_MANAGER_START,
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionConfig.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionConfig.java
index 3aeb19f..eabe6cc 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionConfig.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionConfig.java
@@ -387,6 +387,34 @@ public interface DistributionConfig extends Config, LogConfig {
File DEFAULT_DEPLOY_WORKING_DIR = new File(System.getProperty("user.dir"));
/**
+ * Returns the value of the {@link ConfigurationProperties#USER_COMMAND_PACKAGES} property
+ */
+ @ConfigAttributeGetter(name = USER_COMMAND_PACKAGES)
+ String getUserCommandPackages();
+
+ /**
+ * Sets the system's user command path.
+ *
+ * @throws IllegalArgumentException if the specified value is not acceptable.
+ * @throws org.apache.geode.UnmodifiableException if this attribute can not be modified.
+ * @throws org.apache.geode.GemFireIOException if the set failure is caused by an error when
+ * writing to the system's configuration file.
+ */
+ @ConfigAttributeSetter(name = USER_COMMAND_PACKAGES)
+ void setUserCommandPackages(String value);
+
+ /**
+ * The name of the {@link ConfigurationProperties#USER_COMMAND_PACKAGES} property.
+ */
+ @ConfigAttribute(type = String.class)
+ String USER_COMMAND_PACKAGES_NAME = USER_COMMAND_PACKAGES;
+
+ /**
+ * The default value of the {@link ConfigurationProperties#USER_COMMAND_PACKAGES} property
+ */
+ String DEFAULT_USER_COMMAND_PACKAGES = "";
+
+ /**
* Returns the value of the {@link ConfigurationProperties#LOG_FILE} property
*
* @return <code>null</code> if logging information goes to standard out
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionConfigImpl.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionConfigImpl.java
index 0c13480..cceeaf9 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionConfigImpl.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionConfigImpl.java
@@ -625,6 +625,8 @@ public class DistributionConfigImpl extends AbstractDistributionConfig implement
private Map<String, ConfigSource> sourceMap =
Collections.synchronizedMap(new HashMap<String, ConfigSource>());
+ protected String userCommandPackages = DEFAULT_USER_COMMAND_PACKAGES;
+
/**
* "off-heap-memory-size" with value of "" or "<size>[g|m]"
*/
@@ -757,6 +759,7 @@ public class DistributionConfigImpl extends AbstractDistributionConfig implement
this.redisPort = other.getRedisPort();
this.redisBindAddress = other.getRedisBindAddress();
this.redisPassword = other.getRedisPassword();
+ this.userCommandPackages = other.getUserCommandPackages();
// following added for 8.0
this.enableSharedConfiguration = other.getEnableClusterConfiguration();
@@ -1831,6 +1834,10 @@ public class DistributionConfigImpl extends AbstractDistributionConfig implement
return this.asyncMaxQueueSize;
}
+ public String getUserCommandPackages() {
+ return this.userCommandPackages;
+ }
+
public int getHttpServicePort() {
return this.httpServicePort;
}
@@ -1855,6 +1862,10 @@ public class DistributionConfigImpl extends AbstractDistributionConfig implement
this.startDevRestApi = value;
}
+ public void setUserCommandPackages(String value) {
+ this.userCommandPackages = value;
+ }
+
public boolean getDeltaPropagation() {
return this.deltaPropagation;
}
@@ -3002,8 +3013,9 @@ public class DistributionConfigImpl extends AbstractDistributionConfig implement
.append(sslTrustStore, that.sslTrustStore)
.append(sslTrustStorePassword, that.sslTrustStorePassword)
.append(locatorSSLAlias, that.locatorSSLAlias).append(sslDefaultAlias, that.sslDefaultAlias)
- .append(sourceMap, that.sourceMap).append(offHeapMemorySize, that.offHeapMemorySize)
- .append(shiroInit, that.shiroInit).isEquals();
+ .append(sourceMap, that.sourceMap).append(userCommandPackages, that.userCommandPackages)
+ .append(offHeapMemorySize, that.offHeapMemorySize).append(shiroInit, that.shiroInit)
+ .isEquals();
}
/**
@@ -3071,8 +3083,9 @@ public class DistributionConfigImpl extends AbstractDistributionConfig implement
.append(sslCiphers).append(sslRequireAuthentication).append(sslKeyStore)
.append(sslKeyStoreType).append(sslKeyStorePassword).append(sslTrustStore)
.append(sslTrustStorePassword).append(sslWebServiceRequireAuthentication)
- .append(locatorSSLAlias).append(sslDefaultAlias).append(sourceMap).append(offHeapMemorySize)
- .append(lockMemory).append(shiroInit).append(modifiable).toHashCode();
+ .append(locatorSSLAlias).append(sslDefaultAlias).append(sourceMap)
+ .append(userCommandPackages).append(offHeapMemorySize).append(lockMemory).append(shiroInit)
+ .append(modifiable).toHashCode();
}
/**
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/beans/MemberMBeanBridge.java b/geode-core/src/main/java/org/apache/geode/management/internal/beans/MemberMBeanBridge.java
index f84799f..2a6565a 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/beans/MemberMBeanBridge.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/beans/MemberMBeanBridge.java
@@ -338,7 +338,8 @@ public class MemberMBeanBridge {
this.config = system.getConfig();
try {
- this.commandProcessor = new OnlineCommandProcessor(cache.getSecurityService());
+ this.commandProcessor =
+ new OnlineCommandProcessor(system.getProperties(), cache.getSecurityService());
} catch (Exception e) {
commandServiceInitError = e.getMessage();
logger.info(LogMarker.CONFIG, "Command processor could not be initialized. {}",
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/CommandManager.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/CommandManager.java
index 0b13d62..44617d3 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/CommandManager.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/CommandManager.java
@@ -14,93 +14,293 @@
*/
package org.apache.geode.management.internal.cli;
+import static org.apache.geode.distributed.ConfigurationProperties.USER_COMMAND_PACKAGES;
-import static java.util.stream.Collectors.toSet;
-
-import java.util.Objects;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+import java.util.ServiceConfigurationError;
+import java.util.ServiceLoader;
import java.util.Set;
-import java.util.stream.Stream;
+import java.util.StringTokenizer;
+import org.springframework.shell.converters.EnumConverter;
+import org.springframework.shell.converters.SimpleFileConverter;
import org.springframework.shell.core.CommandMarker;
import org.springframework.shell.core.Converter;
+import org.springframework.shell.core.MethodTarget;
+import org.springframework.shell.core.annotation.CliAvailabilityIndicator;
+import org.springframework.shell.core.annotation.CliCommand;
+import org.apache.geode.distributed.ConfigurationProperties;
+import org.apache.geode.distributed.internal.DistributionConfig;
+import org.apache.geode.internal.ClassPathLoader;
+import org.apache.geode.management.internal.cli.commands.GfshCommand;
import org.apache.geode.management.internal.cli.help.Helper;
import org.apache.geode.management.internal.cli.shell.Gfsh;
import org.apache.geode.management.internal.cli.util.ClasspathScanLoadHelper;
/**
+ *
* this only takes care of loading all available command markers and converters from the application
*
* @since GemFire 7.0
*/
public class CommandManager {
- // Skip some of the Converters from Spring Shell for our customization
- private static final Set<String> EXCLUDED_CLASSES =
- Stream.of("-org.springframework.shell.converters.SimpleFileConverter",
- "-org.springframework.shell.converters.FileConverter",
- "-org.springframework.shell.converters.EnumConverter",
- "-org.springframework.shell.commands.ExitCommands",
- "-org.springframework.shell.commands.HelpCommands",
- "-org.springframework.shell.commands.VersionCommands",
- "-org.springframework.shell.commands.ConsoleCommands").collect(toSet());
-
- private final LogWrapper logWrapper = LogWrapper.getInstance();
- private final Set<CommandMarker> commandMarkers;
- private final Set<Converter> converters;
- private final Helper helper;
+ 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 static final Object INSTANCE_LOCK = new Object();
+
+ private final Helper helper = new Helper();
+
+ private final List<Converter<?>> converters = new ArrayList<Converter<?>>();
+ private final List<CommandMarker> commandMarkers = new ArrayList<>();
+ private Properties cacheProperties;
+ private LogWrapper logWrapper;
+
+ /**
+ * this constructor is used from Gfsh VM. We are getting the user-command-package from system
+ * environment. used by Gfsh.
+ */
public CommandManager() {
- helper = new Helper();
- converters = loadConverters();
- commandMarkers = loadCommandMarkers();
+ this(null);
}
- private Set<Converter> loadConverters() {
- Set<Converter> converters = instantiateAllClassesImplementing(Converter.class);
- raiseExceptionIfEmpty(converters, "converters");
+ /**
+ * this is used when getting the instance in a cache server. We are getting the
+ * user-command-package from distribution properties. used by OnlineCommandProcessor.
+ */
+ public CommandManager(final Properties cacheProperties) {
+ if (cacheProperties != null) {
+ this.cacheProperties = cacheProperties;
+ }
+ logWrapper = LogWrapper.getInstance();
+ loadCommands();
+ }
- converters.forEach(this::setContextIfCommandManagerAware);
- return converters;
+ private static void raiseExceptionIfEmpty(Set<Class<?>> foundClasses, String errorFor)
+ throws IllegalStateException {
+ if (foundClasses == null || foundClasses.isEmpty()) {
+ throw new IllegalStateException(
+ "Required " + errorFor + " classes were not loaded. Check logs for errors.");
+ }
}
- private Set<CommandMarker> loadCommandMarkers() {
- Set<CommandMarker> commandMarkers = instantiateAllClassesImplementing(CommandMarker.class);
- raiseExceptionIfEmpty(commandMarkers, "commandMarkers");
+ private void loadUserCommands() {
+ final Set<String> userCommandPackages = new HashSet<String>();
- commandMarkers.forEach(this::setContextIfCommandManagerAware);
- commandMarkers.forEach(helper::registerCommand);
- return commandMarkers;
+ // 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<Class<?>> foundClasses = ClasspathScanLoadHelper
+ .scanPackageForClassesImplementing(userCommandPackage, CommandMarker.class);
+ 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 (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<CommandMarker> 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 <T> Set<T> instantiateAllClassesImplementing(Class<T> implementedInterface) {
- Set<Class<? extends T>> classes = ClasspathScanLoadHelper.scanClasspathForClassesImplementing(
- implementedInterface, EXCLUDED_CLASSES.toArray(new String[0]));
- return classes.stream().map(this::instantiateClass).filter(Objects::nonNull).collect(toSet());
+ private void loadCommands() {
+ loadUserCommands();
+
+ loadPluginCommands();
+ loadGeodeCommands();
+ loadConverters();
}
- private <T> T instantiateClass(Class<T> classToInstantiate) {
+ private void loadConverters() {
+ Set<Class<?>> foundClasses;
+ // Converters
try {
- return classToInstantiate.newInstance();
- } catch (Exception e) {
- logWrapper.warning("Could not load command or converter from: " + classToInstantiate, e);
+ foundClasses = ClasspathScanLoadHelper.scanPackageForClassesImplementing(
+ "org.apache.geode.management.internal.cli.converters", Converter.class);
+ for (Class<?> klass : foundClasses) {
+ try {
+ Converter<?> object = (Converter<?>) klass.newInstance();
+ add(object);
+
+ } catch (Exception e) {
+ logWrapper.warning(
+ "Could not load Converter from: " + klass + " due to " + e.getLocalizedMessage()); // continue
+ }
+ }
+ raiseExceptionIfEmpty(foundClasses, "Converters");
+
+ // Spring shell's converters
+ foundClasses = ClasspathScanLoadHelper.scanPackageForClassesImplementing(
+ "org.springframework.shell.converters", Converter.class);
+ for (Class<?> klass : foundClasses) {
+ if (!SHL_CONVERTERS_TOSKIP.contains(klass)) {
+ try {
+ 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 (IllegalStateException e) {
+ logWrapper.warning(e.getMessage(), e);
+ throw e;
}
- return null;
}
- private void setContextIfCommandManagerAware(Object commandOrConverter) {
- if (CommandManagerAware.class.isAssignableFrom(commandOrConverter.getClass())) {
- ((CommandManagerAware) commandOrConverter).setCommandManager(this);
+ private void loadGeodeCommands() {
+ // CommandMarkers
+ Set<Class<?>> foundClasses;
+ try {
+ // geode's commands
+ foundClasses = ClasspathScanLoadHelper.scanPackageForClassesImplementing(
+ GfshCommand.class.getPackage().getName(), CommandMarker.class);
+
+ 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");
+
+ // do not add Spring shell's commands for now. When we add it, we need to tell the parser that
+ // these are offline commands.
+ } catch (IllegalStateException e) {
+ logWrapper.warning(e.getMessage(), e);
+ throw e;
}
}
- private static void raiseExceptionIfEmpty(Set<?> foundClasses, String classType)
- throws IllegalStateException {
- if (foundClasses == null || foundClasses.isEmpty()) {
- throw new IllegalStateException("No " + classType + " were loaded. Check logs for errors.");
+ /** Skip some of the Converters from Spring Shell for our customization */
+ private static List<Class> SHL_CONVERTERS_TOSKIP = new ArrayList();
+ static {
+ // skip springs SimpleFileConverter to use our own FilePathConverter
+ SHL_CONVERTERS_TOSKIP.add(SimpleFileConverter.class);
+ // skip spring's EnumConverter to use our own EnumConverter
+ SHL_CONVERTERS_TOSKIP.add(EnumConverter.class);
+ }
+
+ public List<Converter<?>> getConverters() {
+ return converters;
+ }
+
+ public List<CommandMarker> getCommandMarkers() {
+ return commandMarkers;
+ }
+
+ /**
+ * Method to add new Converter
+ *
+ * @param converter
+ */
+ void add(Converter<?> converter) {
+ if (CommandManagerAware.class.isAssignableFrom(converter.getClass())) {
+ ((CommandManagerAware) converter).setCommandManager(this);
+ }
+ converters.add(converter);
+ }
+
+ /**
+ * Method to add new Commands to the parser
+ *
+ * @param commandMarker
+ */
+ void add(CommandMarker commandMarker) {
+ if (CommandManagerAware.class.isAssignableFrom(commandMarker.getClass())) {
+ ((CommandManagerAware) commandMarker).setCommandManager(this);
+ }
+ commandMarkers.add(commandMarker);
+ for (Method method : commandMarker.getClass().getMethods()) {
+ CliCommand cliCommand = method.getAnnotation(CliCommand.class);
+ CliAvailabilityIndicator availability = method.getAnnotation(CliAvailabilityIndicator.class);
+ if (cliCommand == null && availability == null) {
+ continue;
+ }
+
+ if (cliCommand != null) {
+ helper.addCommand(cliCommand, method);
+ }
+
+ if (availability != null) {
+ helper.addAvailabilityIndicator(availability, new MethodTarget(method, commandMarker));
+ }
}
}
+ public Helper getHelper() {
+ return helper;
+ }
+
public String obtainHelp(String buffer) {
int terminalWidth = -1;
Gfsh gfsh = Gfsh.getCurrentInstance();
@@ -114,15 +314,4 @@ public class CommandManager {
return helper.getHint(topic);
}
- public Set<Converter> getConverters() {
- return converters;
- }
-
- public Set<CommandMarker> getCommandMarkers() {
- return commandMarkers;
- }
-
- public Helper getHelper() {
- return helper;
- }
}
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/GfshParser.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/GfshParser.java
index 4d3b546..4fc7d4e 100755
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/GfshParser.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/GfshParser.java
@@ -57,14 +57,10 @@ public class GfshParser extends SimpleParser {
add(command);
}
- for (Converter converter : commandManager.getConverters()) {
+ for (Converter<?> converter : commandManager.getConverters()) {
if (converter.getClass().isAssignableFrom(ArrayConverter.class)) {
ArrayConverter arrayConverter = (ArrayConverter) converter;
- HashSet<Converter<?>> converters = new HashSet<>();
- for (Converter c : commandManager.getConverters()) {
- converters.add(c);
- }
- arrayConverter.setConverters(converters);
+ arrayConverter.setConverters(new HashSet<>(commandManager.getConverters()));
}
add(converter);
}
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/help/Helper.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/help/Helper.java
index ec6f4e3..917f3e4 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/help/Helper.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/help/Helper.java
@@ -14,10 +14,9 @@
*/
package org.apache.geode.management.internal.cli.help;
-import static java.util.stream.Collectors.joining;
-
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
@@ -28,7 +27,6 @@ import java.util.Set;
import java.util.TreeMap;
import org.apache.commons.lang.StringUtils;
-import org.springframework.shell.core.CommandMarker;
import org.springframework.shell.core.MethodTarget;
import org.springframework.shell.core.annotation.CliAvailabilityIndicator;
import org.springframework.shell.core.annotation.CliCommand;
@@ -67,7 +65,8 @@ public class Helper {
private final Map<String, Topic> topics = new HashMap<>();
private final Map<String, Method> commands = new TreeMap<String, Method>();
- private final Map<String, MethodTarget> availabilityIndicators = new HashMap<>();
+ private final Map<String, MethodTarget> availabilityIndicators =
+ new HashMap<String, MethodTarget>();
public Helper() {
initTopic(CliStrings.DEFAULT_TOPIC_GEODE, CliStrings.DEFAULT_TOPIC_GEODE__DESC);
@@ -95,25 +94,7 @@ public class Helper {
topics.put(topic, new Topic(topic, desc));
}
- public void registerCommand(CommandMarker commandMarker) {
- for (Method method : commandMarker.getClass().getMethods()) {
- CliCommand cliCommand = method.getAnnotation(CliCommand.class);
- CliAvailabilityIndicator availability = method.getAnnotation(CliAvailabilityIndicator.class);
- if (cliCommand == null && availability == null) {
- continue;
- }
-
- if (cliCommand != null) {
- addCommand(cliCommand, method);
- }
-
- if (availability != null) {
- addAvailabilityIndicator(availability, new MethodTarget(method, commandMarker));
- }
- }
- }
-
- protected void addCommand(CliCommand command, Method commandMethod) {
+ public void addCommand(CliCommand command, Method commandMethod) {
// put all the command synonyms in the command map
Arrays.stream(command.value()).forEach(cmd -> {
commands.put(cmd, commandMethod);
@@ -139,8 +120,7 @@ public class Helper {
});
}
- private void addAvailabilityIndicator(CliAvailabilityIndicator availability,
- MethodTarget target) {
+ public void addAvailabilityIndicator(CliAvailabilityIndicator availability, MethodTarget target) {
Arrays.stream(availability.value()).forEach(command -> {
availabilityIndicators.put(command, target);
});
@@ -172,7 +152,9 @@ public class Helper {
builder.append(CliStrings.HINT__MSG__TOPICS_AVAILABLE).append(GfshParser.LINE_SEPARATOR)
.append(GfshParser.LINE_SEPARATOR);
- topics.keySet().stream().sorted()
+ List<String> sortedTopics = new ArrayList<>(topics.keySet());
+ Collections.sort(sortedTopics);
+ sortedTopics.stream()
.forEachOrdered(topic -> builder.append(topic).append(GfshParser.LINE_SEPARATOR));
return builder.toString();
}
@@ -183,7 +165,8 @@ public class Helper {
}
builder.append(topic.desc).append(GfshParser.LINE_SEPARATOR).append(GfshParser.LINE_SEPARATOR);
- topic.relatedCommands.stream().sorted().forEach(command -> builder.append(command.command)
+ Collections.sort(topic.relatedCommands);
+ topic.relatedCommands.stream().forEachOrdered(command -> builder.append(command.command)
.append(": ").append(command.desc).append(GfshParser.LINE_SEPARATOR));
return builder.toString();
}
@@ -192,7 +175,7 @@ public class Helper {
return topics.keySet();
}
- private boolean isAvailable(String command) {
+ boolean isAvailable(String command) {
MethodTarget target = availabilityIndicators.get(command);
if (target == null) {
return true;
@@ -278,12 +261,16 @@ public class Helper {
HelpBlock optionNode = new HelpBlock(getPrimaryKey(cliOption));
String help = cliOption.help();
optionNode.addChild(new HelpBlock((StringUtils.isNotBlank(help) ? help : "")));
-
- String synonyms = getSynonyms(cliOption).stream().collect(joining(","));
- if (StringUtils.isNotEmpty(synonyms)) {
- optionNode.addChild(new HelpBlock(SYNONYMS_SUB_NAME + synonyms));
+ if (getSynonyms(cliOption).size() > 0) {
+ StringBuilder builder = new StringBuilder();
+ for (String string : getSynonyms(cliOption)) {
+ if (builder.length() > 0) {
+ builder.append(",");
+ }
+ builder.append(string);
+ }
+ optionNode.addChild(new HelpBlock(SYNONYMS_SUB_NAME + builder.toString()));
}
-
optionNode.addChild(
new HelpBlock(REQUIRED_SUB_NAME + ((cliOption.mandatory()) ? TRUE_TOKEN : FALSE_TOKEN)));
if (!isNullOrBlank(cliOption.specifiedDefaultValue())) {
@@ -372,14 +359,18 @@ public class Helper {
}
private static List<String> getSynonyms(CliOption option) {
+ List<String> synonyms = new ArrayList<>();
String[] keys = option.key();
if (keys.length < 2)
- return Collections.emptyList();
+ return synonyms;
// if the primary key is empty (like sh and help command), then there should be no synonyms.
if ("".equals(keys[0]))
- return Collections.emptyList();
+ return synonyms;
- return Arrays.asList(keys).subList(1, keys.length);
+ for (int i = 1; i < keys.length; i++) {
+ synonyms.add(keys[i]);
+ }
+ return synonyms;
}
private static boolean isNullOrBlank(String value) {
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/remote/MemberCommandService.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/remote/MemberCommandService.java
index a4c6f59..6130117 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/remote/MemberCommandService.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/remote/MemberCommandService.java
@@ -35,7 +35,8 @@ public class MemberCommandService extends CommandService {
public MemberCommandService(InternalCache cache) throws CommandServiceException {
this.cache = cache;
try {
- this.onlineCommandProcessor = new OnlineCommandProcessor(cache.getSecurityService());
+ this.onlineCommandProcessor = new OnlineCommandProcessor(
+ cache.getDistributedSystem().getProperties(), cache.getSecurityService());
} catch (Exception e) {
throw new CommandServiceException("Could not load commands.", e);
}
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/remote/OnlineCommandProcessor.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/remote/OnlineCommandProcessor.java
index 38ab364..7fa4acb 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/remote/OnlineCommandProcessor.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/remote/OnlineCommandProcessor.java
@@ -18,6 +18,7 @@ import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Map;
+import java.util.Properties;
import org.springframework.shell.core.Parser;
import org.springframework.shell.event.ParseResult;
@@ -25,6 +26,7 @@ import org.springframework.util.StringUtils;
import org.apache.geode.annotations.TestingOnly;
import org.apache.geode.internal.security.SecurityService;
+import org.apache.geode.internal.security.SecurityServiceFactory;
import org.apache.geode.management.cli.CliMetaData;
import org.apache.geode.management.cli.CommandProcessingException;
import org.apache.geode.management.cli.Result;
@@ -47,14 +49,20 @@ public class OnlineCommandProcessor {
private final SecurityService securityService;
- public OnlineCommandProcessor(SecurityService securityService)
+ @TestingOnly
+ public OnlineCommandProcessor() throws ClassNotFoundException, IOException {
+ this(new Properties(), SecurityServiceFactory.create());
+ }
+
+ public OnlineCommandProcessor(Properties cacheProperties, SecurityService securityService)
throws ClassNotFoundException, IOException {
- this(securityService, new CommandExecutor());
+ this(cacheProperties, securityService, new CommandExecutor());
}
@TestingOnly
- public OnlineCommandProcessor(SecurityService securityService, CommandExecutor commandExecutor) {
- this.gfshParser = new GfshParser(new CommandManager());
+ public OnlineCommandProcessor(Properties cacheProperties, SecurityService securityService,
+ CommandExecutor commandExecutor) {
+ this.gfshParser = new GfshParser(new CommandManager(cacheProperties));
this.executor = commandExecutor;
this.securityService = securityService;
}
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/util/ClasspathScanLoadHelper.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/util/ClasspathScanLoadHelper.java
index 11da4b2..046d890 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/util/ClasspathScanLoadHelper.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/util/ClasspathScanLoadHelper.java
@@ -21,7 +21,6 @@ import java.util.HashSet;
import java.util.Set;
import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner;
-import io.github.lukehutch.fastclasspathscanner.matchprocessor.ImplementingClassMatchProcessor;
/**
* Utility class to scan class-path & load classes.
@@ -29,26 +28,18 @@ import io.github.lukehutch.fastclasspathscanner.matchprocessor.ImplementingClass
* @since GemFire 7.0
*/
public class ClasspathScanLoadHelper {
-
- public static <T> Set<Class<? extends T>> scanClasspathForClassesImplementing(
- Class<T> implementedInterface, String... packageSpec) {
- return scanPackageForClassesImplementing(implementedInterface, packageSpec);
- }
-
- public static <T> Set<Class<? extends T>> scanPackageForClassesImplementing(
- Class<T> implementedInterface, String... packageSpec) {
- Set<Class<? extends T>> classesImplementing = new HashSet<>();
- ImplementingClassMatchProcessor<T> matchProcessor = classesImplementing::add;
-
- new FastClasspathScanner(packageSpec)
- .matchClassesImplementing(implementedInterface, matchProcessor).scan();
+ public static Set<Class<?>> scanPackageForClassesImplementing(String packageToScan,
+ Class<?> implementedInterface) {
+ Set<Class<?>> classesImplementing = new HashSet<>();
+ new FastClasspathScanner(packageToScan)
+ .matchClassesImplementing(implementedInterface, classesImplementing::add).scan();
return classesImplementing.stream().filter(ClasspathScanLoadHelper::isInstantiable)
.collect(toSet());
}
- private static <T> boolean isInstantiable(Class<T> classToInstantiate) {
- int modifiers = classToInstantiate.getModifiers();
+ private static boolean isInstantiable(Class<?> klass) {
+ int modifiers = klass.getModifiers();
return !Modifier.isAbstract(modifiers) && !Modifier.isInterface(modifiers)
&& Modifier.isPublic(modifiers);
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/internal/DistributionConfigJUnitTest.java b/geode-core/src/test/java/org/apache/geode/distributed/internal/DistributionConfigJUnitTest.java
index e874898..7e5f83f 100644
--- a/geode-core/src/test/java/org/apache/geode/distributed/internal/DistributionConfigJUnitTest.java
+++ b/geode-core/src/test/java/org/apache/geode/distributed/internal/DistributionConfigJUnitTest.java
@@ -99,7 +99,7 @@ public class DistributionConfigJUnitTest {
@Test
public void testGetAttributeNames() {
String[] attNames = AbstractDistributionConfig._getAttNames();
- assertEquals(156, attNames.length);
+ assertEquals(attNames.length, 157);
List boolList = new ArrayList();
List intList = new ArrayList();
@@ -135,7 +135,7 @@ public class DistributionConfigJUnitTest {
// are.
assertEquals(29, boolList.size());
assertEquals(33, intList.size());
- assertEquals(85, stringList.size());
+ assertEquals(86, stringList.size());
assertEquals(5, fileList.size());
assertEquals(4, otherList.size());
}
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/ClasspathScanLoadHelperJUnitTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/ClasspathScanLoadHelperJUnitTest.java
index e48c8d2..1dfd61d 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/ClasspathScanLoadHelperJUnitTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/ClasspathScanLoadHelperJUnitTest.java
@@ -14,8 +14,7 @@
*/
package org.apache.geode.management.internal.cli;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
import java.util.Set;
@@ -36,36 +35,36 @@ public class ClasspathScanLoadHelperJUnitTest {
private final String PACKAGE_NAME = "org.apache.geode.management.internal.cli.domain";
private final String WRONG_PACKAGE_NAME = "org.apache.geode.management.internal.cli.domain1";
- private final Class INTERFACE1 = Interface1.class;
- private final Class NO_IMPL_INTERFACE = Versionable.class;
- private final Class INTERFACE2 = Interface2.class;
- private final Class IMPL1 = Impl1.class;
- private final Class IMPL2 = Impl12.class;
- private final Class ABSTRACT_IMPL = AbstractImpl.class;
+ private final Class<?> INTERFACE1 = Interface1.class;
+ private final Class<?> NO_IMPL_INTERFACE = Versionable.class;
+ private final Class<?> INTERFACE2 = Interface2.class;
+ private final Class<?> IMPL1 = Impl1.class;
+ private final Class<?> IMPL2 = Impl12.class;
+ private final Class<?> ABSTRACT_IMPL = AbstractImpl.class;
@Test
public void testLoadAndGet() throws Exception {
Set<Class<?>> classLoaded =
- ClasspathScanLoadHelper.scanPackageForClassesImplementing(INTERFACE1, PACKAGE_NAME);
+ ClasspathScanLoadHelper.scanPackageForClassesImplementing(PACKAGE_NAME, INTERFACE1);
assertEquals(2, classLoaded.size());
assertTrue(classLoaded.contains(IMPL1));
assertTrue(classLoaded.contains(IMPL2));
classLoaded =
- ClasspathScanLoadHelper.scanPackageForClassesImplementing(INTERFACE2, PACKAGE_NAME);
+ ClasspathScanLoadHelper.scanPackageForClassesImplementing(PACKAGE_NAME, INTERFACE2);
assertEquals(1, classLoaded.size());
assertTrue(classLoaded.contains(IMPL2));
classLoaded =
- ClasspathScanLoadHelper.scanPackageForClassesImplementing(INTERFACE2, WRONG_PACKAGE_NAME);
+ ClasspathScanLoadHelper.scanPackageForClassesImplementing(WRONG_PACKAGE_NAME, INTERFACE2);
assertEquals(0, classLoaded.size());
classLoaded =
- ClasspathScanLoadHelper.scanPackageForClassesImplementing(NO_IMPL_INTERFACE, PACKAGE_NAME);
+ ClasspathScanLoadHelper.scanPackageForClassesImplementing(PACKAGE_NAME, NO_IMPL_INTERFACE);
assertEquals(0, classLoaded.size());
- classLoaded = ClasspathScanLoadHelper.scanPackageForClassesImplementing(NO_IMPL_INTERFACE,
- WRONG_PACKAGE_NAME);
+ classLoaded = ClasspathScanLoadHelper.scanPackageForClassesImplementing(WRONG_PACKAGE_NAME,
+ NO_IMPL_INTERFACE);
assertEquals(0, classLoaded.size());
}
}
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/CommandManagerJUnitTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/CommandManagerJUnitTest.java
index c65ff04..8133471 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/CommandManagerJUnitTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/CommandManagerJUnitTest.java
@@ -18,12 +18,20 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import java.util.List;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.springframework.shell.core.CommandMarker;
+import org.springframework.shell.core.Completion;
+import org.springframework.shell.core.Converter;
+import org.springframework.shell.core.MethodTarget;
+import org.springframework.shell.core.annotation.CliAvailabilityIndicator;
import org.springframework.shell.core.annotation.CliCommand;
+import org.springframework.shell.core.annotation.CliOption;
+import org.apache.geode.management.cli.CliMetaData;
import org.apache.geode.management.cli.Result;
import org.apache.geode.management.internal.security.ResourceOperation;
import org.apache.geode.security.ResourcePermission.Operation;
@@ -35,6 +43,49 @@ import org.apache.geode.test.junit.categories.UnitTest;
*/
@Category(UnitTest.class)
public class CommandManagerJUnitTest {
+
+ private static final String COMMAND1_NAME = "command1";
+ private static final String COMMAND1_NAME_ALIAS = "command1_alias";
+ private static final String COMMAND2_NAME = "c2";
+
+ private static final String COMMAND1_HELP = "help for " + COMMAND1_NAME;
+ // ARGUMENTS
+ private static final String ARGUMENT1_NAME = "argument1";
+ private static final String ARGUMENT1_HELP = "help for argument1";
+ private static final String ARGUMENT1_CONTEXT = "context for argument 1";
+ private static final Completion[] ARGUMENT1_COMPLETIONS =
+ {new Completion("arg1"), new Completion("arg1alt")};
+ private static final String ARGUMENT2_NAME = "argument2";
+ private static final String ARGUMENT2_CONTEXT = "context for argument 2";
+ private static final String ARGUMENT2_HELP = "help for argument2";
+ private static final String ARGUMENT2_UNSPECIFIED_DEFAULT_VALUE =
+ "{unspecified default value for argument2}";
+ private static final Completion[] ARGUMENT2_COMPLETIONS =
+ {new Completion("arg2"), new Completion("arg2alt")};
+
+ // OPTIONS
+ private static final String OPTION1_NAME = "option1";
+ private static final String OPTION1_SYNONYM = "opt1";
+ private static final String OPTION1_HELP = "help for option1";
+ private static final String OPTION1_CONTEXT = "context for option1";
+ private static final String OPTION1_SPECIFIED_DEFAULT_VALUE =
+ "{specified default value for option1}";
+ private static final Completion[] OPTION1_COMPLETIONS =
+ {new Completion("option1"), new Completion("option1Alternate")};
+ private static final String OPTION2_NAME = "option2";
+ private static final String OPTION2_HELP = "help for option2";
+ private static final String OPTION2_CONTEXT = "context for option2";
+ private static final String OPTION2_SPECIFIED_DEFAULT_VALUE =
+ "{specified default value for option2}";
+ private static final String OPTION3_NAME = "option3";
+ private static final String OPTION3_SYNONYM = "opt3";
+ private static final String OPTION3_HELP = "help for option3";
+ private static final String OPTION3_CONTEXT = "context for option3";
+ private static final String OPTION3_SPECIFIED_DEFAULT_VALUE =
+ "{specified default value for option3}";
+ private static final String OPTION3_UNSPECIFIED_DEFAULT_VALUE =
+ "{unspecified default value for option3}";
+
private CommandManager commandManager;
@Before
@@ -60,6 +111,11 @@ public class CommandManagerJUnitTest {
assertNotNull(commandManager);
}
+ /**
+ * Tests {@link CommandManager#loadPluginCommands()}.
+ *
+ * @since GemFire 8.1
+ */
@Test
public void testCommandManagerLoadPluginCommands() throws Exception {
assertNotNull(commandManager);
@@ -67,10 +123,97 @@ public class CommandManagerJUnitTest {
// see META-INF/services/org.springframework.shell.core.CommandMarker service loader file.
assertTrue("Should find listed plugin.",
commandManager.getHelper().getCommands().contains("mock plugin command"));
- assertThat(
- commandManager.getCommandMarkers().stream().anyMatch(c -> c instanceof MockPluginCommand));
+ assertTrue("Should not find unlisted plugin.",
+ !commandManager.getHelper().getCommands().contains("mock plugin command unlisted"));
+ }
+
+ /**
+ * class that represents dummy commands
+ */
+ public static class Commands implements CommandMarker {
+
+ @CliCommand(value = {COMMAND1_NAME, COMMAND1_NAME_ALIAS}, help = COMMAND1_HELP)
+ @CliMetaData(shellOnly = true, relatedTopic = {"relatedTopicOfCommand1"})
+ @ResourceOperation(resource = Resource.CLUSTER, operation = Operation.READ)
+ public static String command1(
+ @CliOption(key = ARGUMENT1_NAME, optionContext = ARGUMENT1_CONTEXT, help = ARGUMENT1_HELP,
+ mandatory = true) String argument1,
+ @CliOption(key = ARGUMENT2_NAME, optionContext = ARGUMENT2_CONTEXT, help = ARGUMENT2_HELP,
+ unspecifiedDefaultValue = ARGUMENT2_UNSPECIFIED_DEFAULT_VALUE) String argument2,
+ @CliOption(key = {OPTION1_NAME, OPTION1_SYNONYM}, help = OPTION1_HELP, mandatory = true,
+ optionContext = OPTION1_CONTEXT,
+ specifiedDefaultValue = OPTION1_SPECIFIED_DEFAULT_VALUE) String option1,
+ @CliOption(key = {OPTION2_NAME}, help = OPTION2_HELP, optionContext = OPTION2_CONTEXT,
+ specifiedDefaultValue = OPTION2_SPECIFIED_DEFAULT_VALUE) String option2,
+ @CliOption(key = {OPTION3_NAME, OPTION3_SYNONYM}, help = OPTION3_HELP,
+ optionContext = OPTION3_CONTEXT,
+ unspecifiedDefaultValue = OPTION3_UNSPECIFIED_DEFAULT_VALUE,
+ specifiedDefaultValue = OPTION3_SPECIFIED_DEFAULT_VALUE) String option3) {
+ return null;
+ }
+
+ @CliCommand(value = {COMMAND2_NAME})
+ @ResourceOperation(resource = Resource.CLUSTER, operation = Operation.READ)
+ public static String command2() {
+ return null;
+ }
+
+ @CliCommand(value = {"testParamConcat"})
+ @ResourceOperation(resource = Resource.CLUSTER, operation = Operation.READ)
+ public static Result testParamConcat(@CliOption(key = {"string"}) String string,
+ @CliOption(key = {"stringArray"}) String[] stringArray,
+ @CliOption(key = {"integer"}) Integer integer,
+ @CliOption(key = {"colonArray"}) String[] colonArray) {
+ return null;
+ }
+
+ @CliCommand(value = {"testMultiWordArg"})
+ @ResourceOperation(resource = Resource.CLUSTER, operation = Operation.READ)
+ public static Result testMultiWordArg(@CliOption(key = "arg1") String arg1,
+ @CliOption(key = "arg2") String arg2) {
+ return null;
+ }
+
+ @CliAvailabilityIndicator({COMMAND1_NAME})
+ public boolean isAvailable() {
+ return true; // always available on server
+ }
}
+ /**
+ * Used by testCommandManagerLoadPluginCommands
+ */
+ private static class SimpleConverter implements Converter<String> {
+
+ @Override
+ public boolean supports(Class<?> type, String optionContext) {
+ return type.isAssignableFrom(String.class);
+ }
+
+ @Override
+ public String convertFromText(String value, Class<?> targetType, String optionContext) {
+ return value;
+ }
+
+ @Override
+ public boolean getAllPossibleValues(List<Completion> completions, Class<?> targetType,
+ String existingData, String context, MethodTarget target) {
+ if (context.equals(ARGUMENT1_CONTEXT)) {
+ for (Completion completion : ARGUMENT1_COMPLETIONS) {
+ completions.add(completion);
+ }
+ } else if (context.equals(ARGUMENT2_CONTEXT)) {
+ for (Completion completion : ARGUMENT2_COMPLETIONS) {
+ completions.add(completion);
+ }
+ } else if (context.equals(OPTION1_CONTEXT)) {
+ for (Completion completion : OPTION1_COMPLETIONS) {
+ completions.add(completion);
+ }
+ }
+ return true;
+ }
+ }
public static class MockPluginCommand implements CommandMarker {
@CliCommand(value = "mock plugin command")
@@ -79,4 +222,13 @@ public class CommandManagerJUnitTest {
return null;
}
}
+
+ public static class MockPluginCommandUnlisted implements CommandMarker {
+ @CliCommand(value = "mock plugin command unlisted")
+ @ResourceOperation(resource = Resource.CLUSTER, operation = Operation.READ)
+ public Result mockPluginCommandUnlisted() {
+ return null;
+ }
+ }
+
}
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CliCommandTestBase.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CliCommandTestBase.java
index d799932..5714829 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CliCommandTestBase.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CliCommandTestBase.java
@@ -27,9 +27,9 @@ import java.io.IOException;
import java.io.PrintStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
+import java.util.List;
import java.util.Map;
import java.util.Properties;
-import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -80,7 +80,7 @@ public abstract class CliCommandTestBase extends JUnit4CacheTestCase {
public static boolean checkIfCommandsAreLoadedOrNot() {
CommandManager manager = new CommandManager();
- Set<CommandMarker> commands = manager.getCommandMarkers();
+ List<CommandMarker> commands = manager.getCommandMarkers();
return commands.size() >= 1;
}
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/remote/OnlineCommandProcessorTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/remote/OnlineCommandProcessorTest.java
index db7176b..df00cf1 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/remote/OnlineCommandProcessorTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/remote/OnlineCommandProcessorTest.java
@@ -21,6 +21,8 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import java.util.Properties;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
@@ -34,6 +36,7 @@ import org.apache.geode.test.junit.categories.UnitTest;
@Category(UnitTest.class)
public class OnlineCommandProcessorTest {
+ Properties properties;
SecurityService securityService;
CommandExecutor executor;
OnlineCommandProcessor onlineCommandProcessor;
@@ -41,12 +44,13 @@ public class OnlineCommandProcessorTest {
@Before
public void before() {
+ properties = new Properties();
securityService = mock(SecurityService.class);
executor = mock(CommandExecutor.class);
result = mock(Result.class);
when(executor.execute(any())).thenReturn(result);
- onlineCommandProcessor = new OnlineCommandProcessor(securityService, executor);
+ onlineCommandProcessor = new OnlineCommandProcessor(properties, securityService, executor);
}
diff --git a/geode-core/src/test/resources/META-INF/services/org.springframework.shell.core.CommandMarker b/geode-core/src/test/resources/META-INF/services/org.springframework.shell.core.CommandMarker
new file mode 100644
index 0000000..1bb7c6d
--- /dev/null
+++ b/geode-core/src/test/resources/META-INF/services/org.springframework.shell.core.CommandMarker
@@ -0,0 +1,8 @@
+# Mock command for org.apache.geode.management.internal.cli.CommandManagerJUnitTest.testLoadPluginCommands
+org.apache.geode.management.internal.cli.CommandManagerJUnitTest$MockPluginCommand
+# Should cause ServiceConfigurationException while iterating.
+#TODO jbarrett - causes tests to be marked as failed because of exception in log org.apache.geode.management.internal.cli.CommandManagerJUnitTest$MockPluginCommandNotFound
+
+
+# Mock Extension commands
+org.apache.geode.internal.cache.extension.mock.MockExtensionCommands
\ No newline at end of file
diff --git a/geode-lucene/src/main/resources/META-INF/services/org.springframework.shell.core.CommandMarker b/geode-lucene/src/main/resources/META-INF/services/org.springframework.shell.core.CommandMarker
new file mode 100644
index 0000000..0879e15
--- /dev/null
+++ b/geode-lucene/src/main/resources/META-INF/services/org.springframework.shell.core.CommandMarker
@@ -0,0 +1,2 @@
+# Lucene Extensions command
+org.apache.geode.cache.lucene.internal.cli.LuceneIndexCommands
\ No newline at end of file
--
To stop receiving notification emails like this one, please contact
['"commits@geode.apache.org" <co...@geode.apache.org>'].