Skip to content

Commit

Permalink
[Dubbo-2766]Fix 2766 and enhance the invoke command (#2801)
Browse files Browse the repository at this point in the history
* 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 #2798 and enhance invoke command
  • Loading branch information
kexianjun authored and beiwei30 committed Dec 11, 2018
1 parent acfc86f commit d32ff60
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ public String telnet(Channel channel, String message) {
Help help = handler.getClass().getAnnotation(Help.class);
List<String> row = new ArrayList<String>();
String parameter = " " + extensionLoader.getExtensionName(handler) + " " + (help != null ? help.parameter().replace("\r\n", " ").replace("\n", " ") : "");
row.add(parameter.length() > 50 ? parameter.substring(0, 50) + "..." : parameter);
row.add(parameter.length() > 55 ? parameter.substring(0, 55) + "..." : parameter);
String summary = help != null ? help.summary().replace("\r\n", " ").replace("\n", " ") : "";
row.add(summary.length() > 50 ? summary.substring(0, 50) + "..." : summary);
row.add(summary.length() > 55 ? summary.substring(0, 55) + "..." : summary);
table.add(row);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@
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;
Expand All @@ -40,28 +42,32 @@
* 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;
}
for (int i = 0; i < types.length; i++) {
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
Expand All @@ -83,8 +89,8 @@ private static boolean isMatch(Class<?>[] types, List<Object> args) {
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) {
Expand Down Expand Up @@ -121,6 +127,26 @@ public String telnet(Channel channel, String message) {
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)";
}
Expand All @@ -137,11 +163,26 @@ public String telnet(Channel channel, String message) {
} 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;
Expand All @@ -150,7 +191,7 @@ public String telnet(Channel channel, String message) {
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;
}
Expand Down Expand Up @@ -179,5 +220,4 @@ public String telnet(Channel channel, String message) {
}
return buf.toString();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,8 @@ public interface DemoService {

long add(int a, long b);

int getPerson(Person person);

int getPerson(Person person1, Person perso2);

}
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,14 @@ public long add(int a, long b) {
return a + b;
}

@Override
public int getPerson(Person person) {
return 1;
}

@Override
public int getPerson(Person person1, Person perso2) {
return 2;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,78 @@ public void testInvokeByPassingEnumValue() throws RemotingException {
}


@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 {
Expand Down

0 comments on commit d32ff60

Please sign in to comment.