[Dubbo-2766]Fix 2766 and enhance the invoke command (#2801)
authorkexianjun <kexianjun1991@hotmail.com>
Tue, 11 Dec 2018 07:59:02 +0000 (15:59 +0800)
committerIan Luo <ian.luo@gmail.com>
Tue, 11 Dec 2018 07:59:02 +0000 (15:59 +0800)
* add getter and setter for ServiceConfig's interfaceName property#2353

* add interfaceName to ignoreAttributeNames and change the unit test

* delete the demo source code and update the unit test

* unchange ServiceConfig

* update unit test

* update unit test

* fix https://github.com/apache/incubator-dubbo/issues/2798 and enhance invoke command

dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/support/command/HelpTelnetHandler.java
dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/telnet/InvokeTelnetHandler.java
dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/support/DemoService.java
dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/support/DemoServiceImpl.java
dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/telnet/InvokerTelnetHandlerTest.java

index 26335f0..8432591 100644 (file)
@@ -59,9 +59,9 @@ public class HelpTelnetHandler implements TelnetHandler {
                     Help help = handler.getClass().getAnnotation(Help.class);\r
                     List<String> row = new ArrayList<String>();\r
                     String parameter = " " + extensionLoader.getExtensionName(handler) + " " + (help != null ? help.parameter().replace("\r\n", " ").replace("\n", " ") : "");\r
-                    row.add(parameter.length() > 50 ? parameter.substring(0, 50) + "..." : parameter);\r
+                    row.add(parameter.length() > 55 ? parameter.substring(0, 55) + "..." : parameter);\r
                     String summary = help != null ? help.summary().replace("\r\n", " ").replace("\n", " ") : "";\r
-                    row.add(summary.length() > 50 ? summary.substring(0, 50) + "..." : summary);\r
+                    row.add(summary.length() > 55 ? summary.substring(0, 55) + "..." : summary);\r
                     table.add(row);\r
                 }\r
             }\r
index caa9f9a..a472fb7 100644 (file)
@@ -30,8 +30,10 @@ import org.apache.dubbo.rpc.RpcInvocation;
 import org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol;
 
 import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
 
 import java.lang.reflect.Method;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
@@ -40,21 +42,21 @@ import java.util.Map;
  * InvokeTelnetHandler
  */
 @Activate
-@Help(parameter = "[service.]method(args)", summary = "Invoke the service method.", detail = "Invoke the service method.")
+@Help(parameter = "[service.]method(args) [-p parameter classes]", summary = "Invoke the service method.", detail = "Invoke the service method.")
 public class InvokeTelnetHandler implements TelnetHandler {
 
-    private static Method findMethod(Exporter<?> exporter, String method, List<Object> args) {
+    private static Method findMethod(Exporter<?> exporter, String method, List<Object> args, Class<?>[] paramClases) {
         Invoker<?> invoker = exporter.getInvoker();
         Method[] methods = invoker.getInterface().getMethods();
         for (Method m : methods) {
-            if (m.getName().equals(method) && isMatch(m.getParameterTypes(), args)) {
+            if (m.getName().equals(method) && isMatch(m.getParameterTypes(), args, paramClases)) {
                 return m;
             }
         }
         return null;
     }
 
-    private static boolean isMatch(Class<?>[] types, List<Object> args) {
+    private static boolean isMatch(Class<?>[] types, List<Object> args, Class<?>[] paramClasses) {
         if (types.length != args.size()) {
             return false;
         }
@@ -62,6 +64,10 @@ public class InvokeTelnetHandler implements TelnetHandler {
             Class<?> type = types[i];
             Object arg = args.get(i);
 
+            if (paramClasses != null && type != paramClasses[i]) {
+                return false;
+            }
+
             if (arg == null) {
                 // if the type is primitive, the method to invoke will cause NullPointerException definitely
                 // so we can offer a specified error message to the invoker in advance and avoid unnecessary invoking
@@ -83,8 +89,8 @@ public class InvokeTelnetHandler implements TelnetHandler {
                 if (!ReflectUtils.isPrimitive(type)) {
                     return false;
                 }
-                Class<?> boxedType = ReflectUtils.getBoxedClass(type);
-                if (boxedType != arg.getClass()) {
+
+                if (!ReflectUtils.isCompatible(type, arg)) {
                     return false;
                 }
             } else if (arg instanceof Map) {
@@ -121,6 +127,26 @@ public class InvokeTelnetHandler implements TelnetHandler {
             buf.append("Use default service " + service + ".\r\n");
         }
         int i = message.indexOf("(");
+        String originalMessage = message;
+        Class<?>[] paramClasses = null;
+        if (message.contains("-p")) {
+            message = originalMessage.substring(0, originalMessage.indexOf("-p")).trim();
+            String paramClassesString = originalMessage.substring(originalMessage.indexOf("-p") + 2).trim();
+            if (paramClassesString.length() > 0) {
+                String[] split = paramClassesString.split("\\s+");
+                if (split.length > 0) {
+                    paramClasses = new Class[split.length];
+                    for (int j = 0; j < split.length; j++) {
+                        try {
+                            paramClasses[j] = Class.forName(split[j]);
+                        } catch (ClassNotFoundException e) {
+                            return "Unknown parameter class for name " + split[j];
+                        }
+                    }
+
+                }
+            }
+        }
         if (i < 0 || !message.endsWith(")")) {
             return "Invalid parameters, format: service.method(args)";
         }
@@ -137,11 +163,26 @@ public class InvokeTelnetHandler implements TelnetHandler {
         } catch (Throwable t) {
             return "Invalid json argument, cause: " + t.getMessage();
         }
+        if (paramClasses != null) {
+            if (paramClasses.length != list.size()) {
+                return "Parameter's number does not match the number of parameter class";
+            }
+            List<Object> listOfActualClass = new ArrayList<>(list.size());
+            for (int ii = 0; ii < list.size(); ii++) {
+                if (list.get(ii) instanceof JSONObject) {
+                    JSONObject jsonObject = (JSONObject) list.get(ii);
+                    listOfActualClass.add(jsonObject.toJavaObject(paramClasses[ii]));
+                } else {
+                    listOfActualClass.add(list.get(ii));
+                }
+            }
+            list = listOfActualClass;
+        }
         Invoker<?> invoker = null;
         Method invokeMethod = null;
         for (Exporter<?> exporter : DubboProtocol.getDubboProtocol().getExporters()) {
             if (service == null || service.length() == 0) {
-                invokeMethod = findMethod(exporter, method, list);
+                invokeMethod = findMethod(exporter, method, list, paramClasses);
                 if (invokeMethod != null) {
                     invoker = exporter.getInvoker();
                     break;
@@ -150,7 +191,7 @@ public class InvokeTelnetHandler implements TelnetHandler {
                 if (service.equals(exporter.getInvoker().getInterface().getSimpleName())
                         || service.equals(exporter.getInvoker().getInterface().getName())
                         || service.equals(exporter.getInvoker().getUrl().getPath())) {
-                    invokeMethod = findMethod(exporter, method, list);
+                    invokeMethod = findMethod(exporter, method, list, paramClasses);
                     invoker = exporter.getInvoker();
                     break;
                 }
@@ -179,5 +220,4 @@ public class InvokeTelnetHandler implements TelnetHandler {
         }
         return buf.toString();
     }
-
 }
index ed38344..c1b03f6 100644 (file)
@@ -107,4 +107,14 @@ public class DemoServiceImpl implements DemoService {
         return a + b;
     }
 
+    @Override
+    public int getPerson(Person person) {
+        return 1;
+    }
+
+    @Override
+    public int getPerson(Person person1, Person perso2) {
+        return 2;
+    }
+
 }
\ No newline at end of file
index dc63c8b..a28bc99 100644 (file)
@@ -127,6 +127,78 @@ public class InvokerTelnetHandlerTest {
 
     @SuppressWarnings("unchecked")
     @Test
+    public void testComplexParamWithoutSpecifyParamType() throws RemotingException {
+        mockInvoker = mock(Invoker.class);
+        given(mockInvoker.getInterface()).willReturn(DemoService.class);
+        given(mockInvoker.getUrl()).willReturn(URL.valueOf("dubbo://127.0.0.1:20886/demo"));
+        given(mockInvoker.invoke(any(Invocation.class))).willReturn(new RpcResult("ok"));
+        mockChannel = mock(Channel.class);
+        given(mockChannel.getAttribute("telnet.service")).willReturn("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService");
+        given(mockChannel.getLocalAddress()).willReturn(NetUtils.toAddress("127.0.0.1:5555"));
+        given(mockChannel.getRemoteAddress()).willReturn(NetUtils.toAddress("127.0.0.1:20886"));
+
+        DubboProtocol.getDubboProtocol().export(mockInvoker);
+
+        // pass json value to parameter of Person type
+
+        String result = invoke.telnet(mockChannel, "DemoService.getPerson({\"name\":\"zhangsan\",\"age\":12})");
+        assertTrue(result.contains("No such method getPerson in service DemoService"));
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testComplexParamSpecifyParamType() throws RemotingException {
+        mockInvoker = mock(Invoker.class);
+        given(mockInvoker.getInterface()).willReturn(DemoService.class);
+        given(mockInvoker.getUrl()).willReturn(URL.valueOf("dubbo://127.0.0.1:20886/demo"));
+        given(mockInvoker.invoke(any(Invocation.class))).willReturn(new RpcResult("ok"));
+        mockChannel = mock(Channel.class);
+        given(mockChannel.getAttribute("telnet.service")).willReturn("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService");
+        given(mockChannel.getLocalAddress()).willReturn(NetUtils.toAddress("127.0.0.1:5555"));
+        given(mockChannel.getRemoteAddress()).willReturn(NetUtils.toAddress("127.0.0.1:20886"));
+
+        DubboProtocol.getDubboProtocol().export(mockInvoker);
+
+        // pass json value to parameter of Person type and specify it's type
+        // one parameter with type of Person
+        String result = invoke.telnet(mockChannel, "DemoService.getPerson({\"name\":\"zhangsan\",\"age\":12}) -p org.apache.dubbo.rpc.protocol.dubbo.support.Person");
+        assertTrue(result.contains("Use default service org.apache.dubbo.rpc.protocol.dubbo.support.DemoService.\r\n\"ok\"\r\n"));
+
+        // two parameter with type of Person
+        result = invoke.telnet(mockChannel, "DemoService.getPerson({\"name\":\"zhangsan\",\"age\":12},{\"name\":\"lisi\",\"age\":12}) " +
+                "-p org.apache.dubbo.rpc.protocol.dubbo.support.Person " +
+                "org.apache.dubbo.rpc.protocol.dubbo.support.Person");
+        assertTrue(result.contains("Use default service org.apache.dubbo.rpc.protocol.dubbo.support.DemoService.\r\n\"ok\"\r\n"));
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testComplexParamSpecifyWrongParamType() throws RemotingException {
+        mockInvoker = mock(Invoker.class);
+        given(mockInvoker.getInterface()).willReturn(DemoService.class);
+        given(mockInvoker.getUrl()).willReturn(URL.valueOf("dubbo://127.0.0.1:20886/demo"));
+        given(mockInvoker.invoke(any(Invocation.class))).willReturn(new RpcResult("ok"));
+        mockChannel = mock(Channel.class);
+        given(mockChannel.getAttribute("telnet.service")).willReturn("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService");
+        given(mockChannel.getLocalAddress()).willReturn(NetUtils.toAddress("127.0.0.1:5555"));
+        given(mockChannel.getRemoteAddress()).willReturn(NetUtils.toAddress("127.0.0.1:20886"));
+
+        DubboProtocol.getDubboProtocol().export(mockInvoker);
+
+        // pass json value to parameter of Person type
+        // wrong name of parameter class
+        String result = invoke.telnet(mockChannel, "DemoService.getPerson({\"name\":\"zhangsan\",\"age\":12}) -p wrongType");
+        assertEquals("Unknown parameter class for name wrongType", result);
+
+        // wrong number of parameter class
+        result = invoke.telnet(mockChannel, "DemoService.getPerson({\"name\":\"zhangsan\",\"age\":12},{\"name\":\"lisi\",\"age\":12}) " +
+                "-p org.apache.dubbo.rpc.protocol.dubbo.support.Person");
+        assertEquals("Parameter's number does not match the number of parameter class", result);
+    }
+
+
+    @SuppressWarnings("unchecked")
+    @Test
     public void testInvokeAutoFindMethod() throws RemotingException {
         mockInvoker = mock(Invoker.class);
         given(mockInvoker.getInterface()).willReturn(DemoService.class);