
org.distributeme.generator.jsonrpc.ClientServiceImplGenerator Maven / Gradle / Ivy
package org.distributeme.generator.jsonrpc;
import com.sun.mirror.apt.Filer;
import com.sun.mirror.declaration.AnnotationMirror;
import com.sun.mirror.declaration.AnnotationValue;
import com.sun.mirror.declaration.MethodDeclaration;
import com.sun.mirror.declaration.ParameterDeclaration;
import com.sun.mirror.declaration.TypeDeclaration;
import com.sun.mirror.type.ReferenceType;
import org.apache.commons.lang.StringUtils;
import org.distributeme.annotation.DistributeMe;
import org.distributeme.annotation.DontRoute;
import org.distributeme.annotation.FailBy;
import org.distributeme.annotation.Route;
import org.distributeme.core.ClientSideCallContext;
import org.distributeme.core.Defaults;
import org.distributeme.core.exception.DistributemeRuntimeException;
import org.distributeme.core.exception.ServiceUnavailableException;
import org.distributeme.core.interceptor.InterceptionPhase;
import org.distributeme.core.routing.Router;
import org.distributeme.generator.logwriter.LogWriter;
import org.distributeme.generator.logwriter.SysErrorLogWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Generator for json-rpc based client stubs.
*
* @author lrosenberg
*/
public class ClientServiceImplGenerator extends AbstractJsonRpcGenerator implements JsonRpcGenerator {
private static Logger log = LoggerFactory.getLogger(ClientServiceImplGenerator.class);
private final Filer filer;
public ClientServiceImplGenerator(final Filer file) {
this.filer = file;
}
@Override
public void generate(TypeDeclaration type) throws IOException {
PrintWriter writer = filer.createSourceFile(getPackageName(type) + "." + getClientStubName(type));
setWriter(writer);
//logging annotation resolving
LogWriter logWriter = null;
//System.out.println("====================");
try {
AnnotationMirror logWriterMirror = findMirror(type, DistributeMe.class);
AnnotationValue logWriterClazzValue = findLogWriterValue(logWriterMirror);
//System.out.println("Type: "+type+", Mirror "+logWriterMirror+", clazzValue: "+logWriterClazzValue+", allvalues: "+logWriterMirror.getElementValues());
String logWriterClazzName = null;
if (logWriterClazzValue == null) {
logWriterClazzName = SysErrorLogWriter.class.getName();
} else {
logWriterClazzName = "" + logWriterClazzValue.getValue();
}
logWriter = (LogWriter) (Class.forName(logWriterClazzName).newInstance());
//System.out.println("@@@ created log writer "+logWriter);
} catch (Exception e) {
log.warn("Still have this stupid exception...", e);
logWriter = new SysErrorLogWriter();
}
//System.out.println("====================");
String loggerInitialization = logWriter.createLoggerInitialization(getStubName(type));
if (loggerInitialization != null && loggerInitialization.length() > 0) {
writeStatement(loggerInitialization);
}
emptyline();
DistributeMe ann = type.getAnnotation(DistributeMe.class);
writePackage(type);
emptyline();
writeImport(Logger.class);
writeImport(LoggerFactory.class);
writeImport(List.class);
writeImport(Map.class);
writeImport(getInterfaceFullName(type));
writeImport("cz.eman.jsonrpc.shared.JsonTransformer");
writeImport("cz.eman.jsonrpc.shared.bo.JsonRpcNormalResponse");
writeImport("cz.eman.jsonrpc.shared.bo.JsonRpcErrorResponse");
writeImport("cz.eman.jsonrpc.shared.bo.JsonRpcRequest");
writeImport("org.codehaus.jackson.JsonNode");
writeImport("org.codehaus.jackson.map.ObjectMapper");
writeImport("org.codehaus.jackson.node.ArrayNode");
writeImport("org.codehaus.jackson.node.JsonNodeFactory");
writeImport(ClientSideCallContext.class);
writeImport(org.distributeme.core.DiscoveryMode.class);
writeImport("org.distributeme.core.RegistryUtil");
writeImport("org.distributeme.core.ServiceDescriptor");
writeImport("org.distributeme.core.exception.NoConnectionToServerException");
writeImport("org.distributeme.core.failing.FailDecision");
writeImport("org.distributeme.core.failing.FailingStrategy");
writeImport("org.mortbay.io.ByteArrayBuffer");
writeImport("org.mortbay.jetty.client.ContentExchange");
writeImport("org.mortbay.jetty.client.HttpClient");
writeImport("java.io.IOException");
writeImport("java.util.concurrent.ConcurrentHashMap");
writeImport("java.util.concurrent.ConcurrentMap");
writeImport("java.util.concurrent.atomic.AtomicInteger");
writeImport("java.util.ArrayList");
writeImport("java.util.HashMap");
writeImport("java.util.List");
writeImport("java.util.Map");
writeImport("java.util.Collection");
writeImport("java.util.concurrent.ConcurrentHashMap");
writeImport("java.util.concurrent.ConcurrentMap");
writeImport("java.util.concurrent.ConcurrentMap");
writeImport("java.util.concurrent.atomic.AtomicInteger");
writeImport("org.distributeme.core.concurrencycontrol.ConcurrencyControlStrategy");
writeImport("org.distributeme.core.interceptor.ClientSideRequestInterceptor");
writeImport("org.distributeme.core.interceptor.InterceptionContext");
writeImport("org.distributeme.core.interceptor.InterceptionPhase");
writeImport("org.distributeme.core.interceptor.InterceptorRegistry");
writeImport("org.distributeme.core.interceptor.InterceptorResponse");
writeImport("org.distributeme.core.exception.DistributemeRuntimeException");
writeImport("org.distributeme.core.exception.NoConnectionToServerException");
writeImport("org.distributeme.core.exception.ServiceUnavailableException");
writeImport(Defaults.class);
emptyline();
writeString("public class " + getClientStubName(type) + " implements " + getServerInterfaceName(type) + "," + getInterfaceName(type) + " {");
increaseIdent();
emptyline();
writeStatement("private static Logger log = LoggerFactory.getLogger(" + getClientStubName(type) + ".class)");
emptyline();
writeStatement("private " + type.getQualifiedName() + " implementation");
emptyline();
writeStatement("private long lastAccess");
writeStatement("private long created");
emptyline();
writeStatement("private volatile ConcurrentMap delegates = new ConcurrentHashMap()");
emptyline();
writeStatement("private DiscoveryMode discoveryMode = DiscoveryMode.AUTO");
writeStatement("private HttpClient client");
AnnotationMirror clazzWideRoute = findMirror(type, Route.class);
if (clazzWideRoute != null) {
//System.out.println("Class wide router "+Router.class.getName());
writeCommentLine("Class wide router ");
writeStatement("private final " + Router.class.getName() + " clazzWideRouter");
} else {
writeCommentLine("No class-wide-router set, skipping.");
}
emptyline();
/***** CONCURRENCY START *****/
List concurrencyControlAnnotations = writeConcurrencyControlDeclarations(type);
/***** CONCURRENCY END *****/
Collection extends MethodDeclaration> methods = getAllDeclaredMethods(type);
writeCommentLine("Method wide routers if applicable ");
Map routedMethods = new HashMap();
Map routerParameters = new HashMap();
for (MethodDeclaration method : methods) {
AnnotationMirror methodRoute = findMirror(method, Route.class);
if (methodRoute != null) {
//System.out.println("Will write "+Router.class.getName()+" "+getMethodRouterName(method));
writeStatement("private final " + Router.class.getName() + " " + getMethodRouterName(method));
routedMethods.put(method, findRouterClassValue(methodRoute));
routerParameters.put(method, findRouterParameterValue(methodRoute));
}
}
writeCommentLine("Method wide routers END ");
emptyline();
writeCommentLine("Failing");
writeCommentLine("Class wide failing strategy ");
AnnotationMirror clazzWideFailingStrategyAnnotation = findMirror(type, FailBy.class);
String clazzWideFailingStrategyName = null;
if (clazzWideFailingStrategyAnnotation != null) {
clazzWideFailingStrategyName = "" + findMethodValue(clazzWideFailingStrategyAnnotation, "strategyClass").getValue();
}
if (clazzWideFailingStrategyName != null) {
writeStatement("private FailingStrategy clazzWideFailingStrategy = new " + clazzWideFailingStrategyName + "()");
} else {
writeStatement("private FailingStrategy clazzWideFailingStrategy = " + Defaults.class.getSimpleName() + ".getDefaultFailingStrategy()");
}
emptyline();
for (MethodDeclaration method : methods) {
AnnotationMirror methodFailingStrategyAnnotation = findMirror(method, FailBy.class);
String methodFailingStrategyName;
if (methodFailingStrategyAnnotation != null) {
methodFailingStrategyName = "" + findMethodValue(methodFailingStrategyAnnotation, "strategyClass").getValue();
writeStatement("private FailingStrategy " + getFailingStrategyVariableName(method) + " = new " + methodFailingStrategyName + "()");
} else {
writeStatement("private FailingStrategy " + getFailingStrategyVariableName(method) + " = clazzWideFailingStrategy");
}
}
writeCommentLine("Failing end");
emptyline();
writeStatement("private ServiceDescriptor lookupDescriptor");
writeStatement("private AtomicInteger requestID = new AtomicInteger(0)");
emptyline();
writeString("public " + getClientStubName(type) + "(" + type.getQualifiedName() + " anImplementation){");
increaseIdent();
writeStatement("created = System.currentTimeMillis()");
writeStatement("implementation = anImplementation");
writeStatement("discoveryMode = DiscoveryMode.AUTO");
closeBlock();
emptyline();
writeString("private " + getClientStubName(type) + "(final ServiceDescriptor lookupDescriptor){");
increaseIdent();
writeStatement("this.lookupDescriptor = lookupDescriptor");
closeBlock();
// parameters
Map primitiveTypes = new HashMap();
primitiveTypes.put("long", "Long");
primitiveTypes.put("int", "Integer");
for (MethodDeclaration method : methods) {
String methodDecl = getSkeletonMethodDeclaration(method);
writeString("public " + methodDecl + "{");
increaseIdent();
writeStatement("ArrayNode jsonNode = JsonNodeFactory.instance.arrayNode()");
writeStatement("ObjectMapper m = new ObjectMapper()");
for (ParameterDeclaration p : method.getParameters()) {
String call = "";
if (primitiveTypes.containsKey(p.getType().toString())) {
writeStatement("jsonNode.add(" + p.getSimpleName() + ")");
} else if (p.getType().toString().contains("[]")) {
writeStatement("ArrayNode jsonArrayNode = JsonNodeFactory.instance.arrayNode()");
writeString("for(byte byte1 : " + p.getSimpleName() + ") {");
increaseIdent();
writeStatement("jsonArrayNode.add(byte1)");
decreaseIdent();
writeString("}");
writeStatement("jsonNode.add(jsonArrayNode)");
} else {
writeStatement("jsonNode.add(m.valueToTree(" + p.getSimpleName() + "))");
}
if (!StringUtils.isEmpty(call)) {
writeStatement(call);
}
}
writeStatement("jsonNode.add(m.valueToTree(__transportableCallContext))");
writeStatement("final List retList = new ArrayList()");
String call = "";
if (primitiveTypes.containsKey(method.getReturnType().toString())) {
writeString("try {");
writeStatement("String response = callHttpClient(\"" + method.getSimpleName() + "\", jsonNode)");
writeStatement("if(response == null) return null");
writeStatement("final List tempRetList = (List) JsonTransformer.toObject(response, List.class)");
writeStatement("retList.add(" + primitiveTypes.get(method.getReturnType().toString()) + ".valueOf(String.valueOf(tempRetList.get(0))))");
writeStatement("retList.add(tempRetList.get(1))");
writeStatement("return retList");
writeString("} catch (IOException e) {");
writeIncreasedStatement("log.error(\"" + method.getSimpleName() + "()\", e)");
writeIncreasedStatement("throw new RuntimeException(e)");
writeString("}");
} else if (method.getReturnType().toString().equals("void")) {
call += "callHttpClient(\"" + method.getSimpleName() + "\", jsonNode);\n";
call += "return retList";
} else {
writeString("try {");
writeStatement("String response = callHttpClient(\"" + method.getSimpleName() + "\", jsonNode)");
writeStatement("if(response == null) return null");
writeStatement("final List tempRetList = (List) JsonTransformer.toObject(response, List.class)");
writeStatement("JsonNode arrayNode = m.readTree(response)");
writeStatement("retList.add(m.readValue(arrayNode.get(0), " + method.getReturnType() + ".class))");
writeStatement("retList.add(tempRetList.get(1))");
writeStatement("return retList");
writeString("} catch (IOException e) {");
writeIncreasedStatement("log.error(\"" + method.getSimpleName() + "()\", e)");
writeIncreasedStatement("throw new RuntimeException(e)");
writeString("}");
}
if (!StringUtils.isEmpty(call)) {
writeStatement(call);
}
closeBlock();//method end
emptyline();
}
emptyline();
// returns
for (MethodDeclaration method : methods) {
writeString("public " + getStubMethodDeclaration(method) + "{");
increaseIdent();
StringBuilder callToPrivate = new StringBuilder(method.getSimpleName() + "(");
for (ParameterDeclaration p : method.getParameters()) {
callToPrivate.append(p.getSimpleName());
callToPrivate.append(", ");
}
writeStatement((isVoidReturn(method) ? "" : "return ") + callToPrivate.toString() + "(ClientSideCallContext)null)");
closeBlock("public " + getStubMethodDeclaration(method));
emptyline();
}
emptyline();
for (MethodDeclaration method : methods) {
StringBuilder callToPrivate = new StringBuilder(method.getSimpleName() + "(");
for (ParameterDeclaration p : method.getParameters()) {
callToPrivate.append(p.getSimpleName());
callToPrivate.append(", ");
}
//writeStatement((isVoidReturn(method) ? "" : "return ")+callToPrivate.toString()+"(ClientSideCallContext)null)");
String methodDecl = getInternalStubMethodDeclaration(method);
writeString("public " + methodDecl + "{");
increaseIdent();
writeStatement("List __fromServerSide = null;");
writeStatement("Exception exceptionInMethod = null");
writeString("if (diMeCallContext == null)");
writeIncreasedStatement("diMeCallContext = new ClientSideCallContext(" + quote(method.getSimpleName()) + ")");
writeString("if (discoveryMode==DiscoveryMode.AUTO && diMeCallContext.getServiceId()==null)");
writeIncreasedStatement("diMeCallContext.setServiceId(" + getConstantsName(type) + ".getServiceId())");
emptyline();
writeStatement("HashMap __transportableCallContext = diMeCallContext.getTransportableCallContext()");
//interceptors, phase 1
boolean interceptionEnabled = true; //later can be configured via annotation.
writeCommentLine("Initialize interceptors");
writeStatement("List diMeInterceptors = InterceptorRegistry.getInstance().getClientSideRequestInterceptors()");
writeStatement("InterceptionContext diMeInterceptionContext = new InterceptionContext()");
// writeInterceptionBlock(InterceptionPhase.BEFORE_CLIENT, method);
//concurrency control
writeCommentLine("Concurrency control, client side - start");
writeStatement(getCCStrategyVariableName(method) + ".notifyClientSideCallStarted(diMeCallContext)");
emptyline();
if (interceptionEnabled) {
//create parameters
writeStatement("ArrayList
© 2015 - 2025 Weber Informatics LLC | Privacy Policy