Skip to content

Commit

Permalink
add MotanAsync annotation for async call
Browse files Browse the repository at this point in the history
  • Loading branch information
rayzhang0603 committed Mar 1, 2017
1 parent 3c7aac1 commit 6a007a4
Show file tree
Hide file tree
Showing 21 changed files with 626 additions and 28 deletions.
21 changes: 20 additions & 1 deletion motan-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
<name>motan-core</name>

<dependencies>

<dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
Expand All @@ -48,5 +47,25 @@
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>com.squareup</groupId>
<artifactId>javapoet</artifactId>
<version>1.8.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>${java.source.jdk}</source>
<target>${java.source.jdk}</target>
<encoding>${project.build.sourceEncoding}</encoding>
<compilerArgument>-proc:none</compilerArgument>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ public class MotanConstants {
public static final String DEFAULT_CHARACTER = "utf-8";
public static final int SLOW_COST = 50; // 50ms
public static final int STATISTIC_PEROID = 30; // 30 seconds
public static final String ASYNC_SUFFIX = "Async";// suffix for async call.

/**
* netty channel constants start
**/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
import com.weibo.api.motan.rpc.DefaultRequest;
import com.weibo.api.motan.rpc.Referer;
import com.weibo.api.motan.rpc.Response;
import com.weibo.api.motan.rpc.ResponseFuture;
import com.weibo.api.motan.rpc.RpcContext;
import com.weibo.api.motan.switcher.Switcher;
import com.weibo.api.motan.switcher.SwitcherService;
import com.weibo.api.motan.util.ExceptionUtil;
Expand Down Expand Up @@ -76,19 +78,25 @@ private void init() {
}

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(isLocalMethod(method)){
if("toString".equals(method.getName())){
if (isLocalMethod(method)) {
if ("toString".equals(method.getName())) {
return clustersToString();
}
throw new MotanServiceException("can not invoke local method:" + method.getName());
}
DefaultRequest request = new DefaultRequest();

request.setRequestId(RequestIdGenerator.getRequestId());
request.setArguments(args);
request.setMethodName(method.getName());
String methodName = method.getName();
boolean async = false;
if (methodName.endsWith(MotanConstants.ASYNC_SUFFIX) && method.getReturnType().equals(ResponseFuture.class)) {
methodName = MotanFrameworkUtil.removeAsyncSuffix(methodName);
async = true;
}
RpcContext.getContext().putAttribute(MotanConstants.ASYNC_SUFFIX, async);
request.setMethodName(methodName);
request.setParamtersDesc(ReflectUtil.getMethodParamDesc(method));
request.setInterfaceName(clz.getName());
request.setInterfaceName(MotanFrameworkUtil.removeAsyncSuffix(clz.getName()));
request.setAttachment(URLParamType.requestIdFromClient.getName(), String.valueOf(RequestIdGenerator.getRequestIdFromClient()));

// 当 referer配置多个protocol的时候,比如A,B,C,
Expand All @@ -113,7 +121,11 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
URLParamType.throwException.getValue()));
try {
response = cluster.call(request);
return response.getValue();
if (async && response instanceof ResponseFuture) {
return response;
} else {
return response.getValue();
}
} catch (RuntimeException e) {
if (ExceptionUtil.isBizException(e)) {
Throwable t = e.getCause();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright 2009-2016 Weibo, Inc.
*
* Licensed 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 com.weibo.api.motan.rpc;

public interface ResponseFuture extends Future, Response{
public void onSuccess(Response response);

This comment has been minimized.

Copy link
@thermosym

thermosym Mar 4, 2017

Contributor

'public' is redundant for interface methods

This comment has been minimized.

Copy link
@rayzhang0603

rayzhang0603 Mar 6, 2017

Author Collaborator

removed. thx :)


public void onFailure(Response response) ;

public long getCreateTime();
}
15 changes: 13 additions & 2 deletions motan-core/src/main/java/com/weibo/api/motan/rpc/URL.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.weibo.api.motan.common.MotanConstants;
import com.weibo.api.motan.common.URLParamType;
import com.weibo.api.motan.exception.MotanServiceException;
import com.weibo.api.motan.util.MotanFrameworkUtil;

/**
* <pre>
Expand Down Expand Up @@ -63,7 +64,7 @@ public URL(String protocol, String host, int port, String path, Map<String, Stri
this.protocol = protocol;
this.host = host;
this.port = port;
this.path = path;
this.path = removeAsyncPath(path);
this.parameters = parameters;
}

Expand Down Expand Up @@ -177,7 +178,7 @@ public String getPath() {
}

public void setPath(String path) {
this.path = path;
this.path = removeAsyncPath(path);
}

public String getVersion() {
Expand Down Expand Up @@ -483,5 +484,15 @@ private Map<String, Number> getNumbers() {
}
return numbers;
}

/**
* because async call in client path with Async suffix,we need
* remove Async suffix in path for subscribe.
* @param path
* @return
*/
private String removeAsyncPath(String path){
return MotanFrameworkUtil.removeAsyncSuffix(path);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright 2009-2016 Weibo, Inc.
*
* Licensed 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 com.weibo.api.motan.transport.async;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
*
* @Description async request annotation
* @author zhanglei
* @date Feb 21, 2017
*
*/
@Documented
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
public @interface MotanAsync {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
/*
* Copyright 2009-2016 Weibo, Inc.
*
* Licensed 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 com.weibo.api.motan.transport.async;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.TypeParameterElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.tools.Diagnostic;

import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeVariableName;
import com.weibo.api.motan.common.MotanConstants;
import com.weibo.api.motan.rpc.ResponseFuture;

/**
*
* @Description create a {interfaceName}Async class with all method add a 'Async' suffix. TODO
* support methods inherited from superinterfaces
* @author zhanglei
* @date Feb 24, 2017
*
*/
@SupportedSourceVersion(SourceVersion.RELEASE_6)
@SupportedAnnotationTypes({"com.weibo.api.motan.transport.async.MotanAsync"})
public class MotanAsyncProcessor extends AbstractProcessor {
protected static String ASYNC = MotanConstants.ASYNC_SUFFIX;
protected static String SRC_DIR = "src/main/java/";
protected static String TARGET_DIR = "target/generated-sources/annotations/";

public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
}

@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
if (roundEnv.processingOver()) {
return true;
}
for (Element elem : roundEnv.getElementsAnnotatedWith(MotanAsync.class)) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "MotanAsyncProcessor will process " + elem.toString());
try {
writeAsyncClass(elem);
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "MotanAsyncProcessor done for " + elem.toString());
} catch (Exception e) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING,
"MotanAsyncProcessor process " + elem.toString() + " fail. exception:" + e.getMessage());
e.printStackTrace();
}
}
return true;
}

private void writeAsyncClass(Element elem) throws ClassNotFoundException, IOException, Exception {

if (elem.getKind().isInterface()) {
TypeElement interfaceClazz = (TypeElement) elem;
String className = interfaceClazz.getSimpleName().toString();
TypeSpec.Builder classBuilder =
TypeSpec.interfaceBuilder(className + ASYNC).addModifiers(Modifier.PUBLIC)
.addSuperinterface(TypeName.get(elem.asType()));

// add class generic type
classBuilder.addTypeVariables(getTypeNames(interfaceClazz.getTypeParameters()));

// add direct method
addMethods(interfaceClazz, classBuilder);

// add method form superinterface
addSuperInterfaceMethods(interfaceClazz.getInterfaces(), classBuilder);

// write class
JavaFile javaFile =
JavaFile.builder(processingEnv.getElementUtils().getPackageOf(interfaceClazz).getQualifiedName().toString(),
classBuilder.build()).build();

javaFile.writeTo(new File(System.getProperty("basedir"), TARGET_DIR));

} else {
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,
"MotanAsyncProcessor not process, because " + elem.toString() + " not a interface.");
}
}

private void addMethods(TypeElement interfaceClazz, TypeSpec.Builder classBuilder) {
List<? extends Element> elements = interfaceClazz.getEnclosedElements();
if (elements != null && !elements.isEmpty()) {
for (Element e : elements) {
if (ElementKind.METHOD.equals(e.getKind())) {
ExecutableElement method = (ExecutableElement) e;
MethodSpec.Builder methodBuilder =
MethodSpec.methodBuilder(method.getSimpleName().toString() + ASYNC)
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT).returns(ResponseFuture.class)
.addTypeVariables(getTypeNames(method.getTypeParameters()));
// add method params
List<? extends VariableElement> vars = method.getParameters();
for (VariableElement var : vars) {
methodBuilder.addParameter(ParameterSpec.builder(TypeName.get(var.asType()), var.getSimpleName().toString())
.build());
}
classBuilder.addMethod(methodBuilder.build());
}
}
}
}

private List<TypeVariableName> getTypeNames(List<? extends TypeParameterElement> types) {
List<TypeVariableName> result = new ArrayList<TypeVariableName>();
if (types != null && !types.isEmpty()) {
for (TypeParameterElement type : types) {
result.add(TypeVariableName.get(type));
}
}
return result;
}

private void addSuperInterfaceMethods(List<? extends TypeMirror> superInterfaces, TypeSpec.Builder classBuilder) {
if (superInterfaces != null && !superInterfaces.isEmpty()) {
for (TypeMirror tm : superInterfaces) {
try {
if (tm.getKind().equals(TypeKind.DECLARED)) {
TypeElement de = (TypeElement) ((DeclaredType) tm).asElement();
addMethods(de, classBuilder);
addSuperInterfaceMethods(de.getInterfaces(), classBuilder);
}
} catch (Exception e) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING,
"MotanAsyncProcessor process superinterface " + tm.toString() + " fail. exception:" + e.getMessage());
e.printStackTrace();
}
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -256,5 +256,12 @@ public static RegistryConfig getDefaultRegistryConfig(){
return local;
}

public static String removeAsyncSuffix(String path){
if(path != null && path.endsWith(MotanConstants.ASYNC_SUFFIX)){
return path.substring(0, path.length() - MotanConstants.ASYNC_SUFFIX.length());
}
return path;
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
com.weibo.api.motan.transport.async.MotanAsyncProcessor
Loading

0 comments on commit 6a007a4

Please sign in to comment.