This is an automated email from the ASF dual-hosted git repository.

dragonyliu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ratis.git


The following commit(s) were added to refs/heads/master by this push:
     new aa7ec7b01 RATIS-1941. Do not print reflections log message in shell. 
(#972)
aa7ec7b01 is described below

commit aa7ec7b01016252c58278bca848ddf3598c7baf6
Author: Tsz-Wo Nicholas Sze <[email protected]>
AuthorDate: Mon Nov 27 22:41:36 2023 -0800

    RATIS-1941. Do not print reflections log message in shell. (#972)
---
 ratis-shell/pom.xml                                |   5 -
 .../java/org/apache/ratis/shell/cli/Command.java   |   7 +-
 .../org/apache/ratis/shell/cli/sh/RatisShell.java  |  54 ++++----
 ratis-test/pom.xml                                 |   7 +
 .../apache/ratis/shell/cli/sh/TestRatisShell.java  | 145 +++++++++++++++++++++
 5 files changed, 180 insertions(+), 38 deletions(-)

diff --git a/ratis-shell/pom.xml b/ratis-shell/pom.xml
index 967f24980..78ab6679f 100644
--- a/ratis-shell/pom.xml
+++ b/ratis-shell/pom.xml
@@ -48,11 +48,6 @@
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-simple</artifactId>
     </dependency>
-    <dependency>
-      <groupId>org.reflections</groupId>
-      <artifactId>reflections</artifactId>
-      <version>0.10.2</version>
-    </dependency>
   </dependencies>
   <build>
     <plugins>
diff --git a/ratis-shell/src/main/java/org/apache/ratis/shell/cli/Command.java 
b/ratis-shell/src/main/java/org/apache/ratis/shell/cli/Command.java
index 606e55c35..ae4e70107 100644
--- a/ratis-shell/src/main/java/org/apache/ratis/shell/cli/Command.java
+++ b/ratis-shell/src/main/java/org/apache/ratis/shell/cli/Command.java
@@ -32,7 +32,7 @@ import java.util.Optional;
 /**
  * An interface for all the commands that can be run from a shell.
  */
-public interface Command extends Closeable {
+public interface Command extends Comparable<Command>, Closeable {
 
   /**
    * Gets the command name as input from the shell.
@@ -41,6 +41,11 @@ public interface Command extends Closeable {
    */
   String getCommandName();
 
+  @Override
+  default int compareTo(Command that) {
+    return this.getCommandName().compareTo(that.getCommandName());
+  }
+
   /**
    * @return the supported {@link Options} of the command
    */
diff --git 
a/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/RatisShell.java 
b/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/RatisShell.java
index 54f613210..2e53e3191 100644
--- a/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/RatisShell.java
+++ b/ratis-shell/src/main/java/org/apache/ratis/shell/cli/sh/RatisShell.java
@@ -19,19 +19,35 @@ package org.apache.ratis.shell.cli.sh;
 
 import org.apache.ratis.shell.cli.AbstractShell;
 import org.apache.ratis.shell.cli.Command;
+import org.apache.ratis.shell.cli.sh.command.AbstractParentCommand;
 import org.apache.ratis.shell.cli.sh.command.Context;
-import org.apache.ratis.util.ReflectionUtils;
-import org.reflections.Reflections;
+import org.apache.ratis.shell.cli.sh.command.ElectionCommand;
+import org.apache.ratis.shell.cli.sh.command.GroupCommand;
+import org.apache.ratis.shell.cli.sh.command.LocalCommand;
+import org.apache.ratis.shell.cli.sh.command.PeerCommand;
+import org.apache.ratis.shell.cli.sh.command.SnapshotCommand;
 
 import java.io.PrintStream;
-import java.lang.reflect.Modifier;
-import java.util.HashMap;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
 import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
 
 /**
  * Shell for manage ratis group.
  */
 public class RatisShell extends AbstractShell {
+  static final List<Function<Context, AbstractParentCommand>> 
PARENT_COMMAND_CONSTRUCTORS
+      = Collections.unmodifiableList(Arrays.asList(
+          PeerCommand::new, GroupCommand::new, ElectionCommand::new, 
SnapshotCommand::new, LocalCommand::new));
+
+  static List<AbstractParentCommand> allParentCommands(Context context) {
+    return PARENT_COMMAND_CONSTRUCTORS.stream()
+        .map(constructor -> constructor.apply(context))
+        .collect(Collectors.toList());
+  }
 
   /**
    * Manage ratis shell command.
@@ -54,33 +70,7 @@ public class RatisShell extends AbstractShell {
 
   @Override
   protected Map<String, Command> loadCommands(Context context) {
-    return loadCommands(RatisShell.class.getPackage().getName(),
-        new Class[] {Context.class},
-        new Object[] {getCloser().register(context)});
-  }
-
-  /**
-   * Get instances of all subclasses of {@link Command} in a sub-package 
called "command" the given
-   * package.
-   *
-   * @param pkgName package prefix to look in
-   * @param classArgs type of args to instantiate the class
-   * @param objectArgs args to instantiate the class
-   * @return a mapping from command name to command instance
-   */
-  private Map<String, Command> loadCommands(String pkgName, Class[] classArgs,
-      Object[] objectArgs) {
-    Map<String, Command> commandsMap = new HashMap<>();
-    Reflections reflections = new Reflections(pkgName);
-    for (Class<? extends Command> cls : 
reflections.getSubTypesOf(Command.class)) {
-      // Add commands from <pkgName>.command.*
-      if (cls.getPackage().getName().equals(pkgName + ".command")
-          && !Modifier.isAbstract(cls.getModifiers())) {
-        // Only instantiate a concrete class
-        final Command cmd = ReflectionUtils.newInstance(cls, classArgs, 
objectArgs);
-        commandsMap.put(cmd.getCommandName(), cmd);
-      }
-    }
-    return commandsMap;
+    return allParentCommands(context).stream()
+        .collect(Collectors.toMap(Command::getCommandName, 
Function.identity()));
   }
 }
diff --git a/ratis-test/pom.xml b/ratis-test/pom.xml
index f18b984d0..40b6b2ec2 100644
--- a/ratis-test/pom.xml
+++ b/ratis-test/pom.xml
@@ -100,6 +100,13 @@
       </exclusions>
     </dependency>
 
+    <dependency>
+      <groupId>org.reflections</groupId>
+      <artifactId>reflections</artifactId>
+      <version>0.10.2</version>
+      <scope>test</scope>
+    </dependency>
+
     <dependency>
       <groupId>org.bouncycastle</groupId>
       <artifactId>bcprov-jdk18on</artifactId>
diff --git 
a/ratis-test/src/test/java/org/apache/ratis/shell/cli/sh/TestRatisShell.java 
b/ratis-test/src/test/java/org/apache/ratis/shell/cli/sh/TestRatisShell.java
new file mode 100644
index 000000000..6e2227647
--- /dev/null
+++ b/ratis-test/src/test/java/org/apache/ratis/shell/cli/sh/TestRatisShell.java
@@ -0,0 +1,145 @@
+/*
+ * 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.ratis.shell.cli.sh;
+
+import org.apache.ratis.BaseTest;
+import org.apache.ratis.shell.cli.Command;
+import org.apache.ratis.shell.cli.sh.command.AbstractParentCommand;
+import org.apache.ratis.shell.cli.sh.command.Context;
+import org.apache.ratis.shell.cli.sh.command.ElectionCommand;
+import org.apache.ratis.shell.cli.sh.command.GroupCommand;
+import org.apache.ratis.shell.cli.sh.command.LocalCommand;
+import org.apache.ratis.shell.cli.sh.command.PeerCommand;
+import org.apache.ratis.shell.cli.sh.command.SnapshotCommand;
+import org.apache.ratis.util.ReflectionUtils;
+import org.junit.Assert;
+import org.junit.Test;
+import org.reflections.Reflections;
+
+import java.io.PrintStream;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+
+/**
+ * Test {@link RatisShell}
+ */
+public class TestRatisShell extends BaseTest {
+  static final PrintStream OUT = System.out;
+  static final Class<?>[] ARG_CLASSES = new Class[] {Context.class};
+
+  static void assertCommand(String message, Command expected, Command 
computed) {
+    Assert.assertEquals(message, expected.getClass(), computed.getClass());
+    Assert.assertEquals(message, expected.getCommandName(), 
computed.getCommandName());
+  }
+
+  static void assertCommands(List<Command> expected, List<Command> computed) {
+    Assert.assertEquals(expected.size(), computed.size());
+    for(int i = 0; i < expected.size(); i++) {
+      assertCommand("Command " + i, expected.get(i), computed.get(i));
+    }
+  }
+
+  @Test
+  public void testFullParentCommandList() throws Exception {
+    final List<Command> expected = new 
ArrayList<>(loadCommands(RatisShell.class.getPackage().getName() + ".command"));
+    Collections.sort(expected);
+
+    try(RatisShell shell = new RatisShell(OUT)) {
+      final List<Command> computed = new ArrayList<>(shell.getCommands());
+      Collections.sort(computed);
+
+      assertCommands(expected, computed);
+    }
+  }
+
+  @Test
+  public void testFullPeerCommandList() {
+    runTestFullCommandList(PeerCommand::new);
+  }
+
+  @Test
+  public void testFullGroupCommandList() {
+    runTestFullCommandList(GroupCommand::new);
+  }
+
+  @Test
+  public void testFullElectionCommandList() {
+    runTestFullCommandList(ElectionCommand::new);
+  }
+
+  @Test
+  public void testFullSnapshotCommandList() {
+    runTestFullCommandList(SnapshotCommand::new);
+  }
+
+  @Test
+  public void testFullLocalCommandList() {
+    runTestFullCommandList(LocalCommand::new);
+  }
+
+  static void runTestFullCommandList(Function<Context, AbstractParentCommand> 
parentCommandConstructor) {
+    final AbstractParentCommand parent = parentCommandConstructor.apply(new 
Context(OUT));
+    final List<Command> computed = new 
ArrayList<>(parent.getSubCommands().values());
+    Collections.sort(computed);
+
+    Assert.assertFalse(computed.isEmpty());
+
+    final Package pkg = computed.iterator().next().getClass().getPackage();
+    final List<Command> expected = new ArrayList<>(loadCommands(pkg));
+    Collections.sort(expected);
+
+    assertCommands(expected, computed);
+  }
+
+  static Collection<Command> loadCommands(Package pkg) {
+    return loadCommands(pkg.getName());
+  }
+
+  static Collection<Command> loadCommands(String pkgName) {
+    return oldLoadCommands(pkgName, ARG_CLASSES, new Object[]{new 
Context(OUT)}).values();
+  }
+
+  /**
+   * Get instances of all subclasses of {@link Command} in the given package.
+   *
+   * @param pkgName package prefix to look in
+   * @param classArgs type of args to instantiate the class
+   * @param objectArgs args to instantiate the class
+   * @return a mapping from command name to command instance
+   */
+  static Map<String, Command> oldLoadCommands(String pkgName, Class<?>[] 
classArgs, Object[] objectArgs) {
+    Map<String, Command> commandsMap = new HashMap<>();
+    Reflections reflections = new Reflections(pkgName);
+    for (Class<? extends Command> cls : 
reflections.getSubTypesOf(Command.class)) {
+      // Add commands from <pkgName>.*
+      if (cls.getPackage().getName().equals(pkgName)
+          && !Modifier.isAbstract(cls.getModifiers())) {
+        // Only instantiate a concrete class
+        final Command cmd = ReflectionUtils.newInstance(cls, classArgs, 
objectArgs);
+        commandsMap.put(cmd.getCommandName(), cmd);
+      }
+    }
+    return commandsMap;
+  }
+}

Reply via email to