/* * Copyright 2010 kk-electronic a/s. * * This file is part of KKPortal. * * KKPortal is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * KKPortal is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with KKPortal. If not, see <http://www.gnu.org/licenses/>. * */ package com.kk_electronic.gwt.rebind; import java.io.PrintWriter; import com.google.gwt.core.client.GWT; import com.google.gwt.core.ext.Generator; import com.google.gwt.core.ext.GeneratorContext; import com.google.gwt.core.ext.TreeLogger; import com.google.gwt.core.ext.UnableToCompleteException; import com.google.gwt.core.ext.typeinfo.JClassType; import com.google.gwt.core.ext.typeinfo.JMethod; import com.google.gwt.core.ext.typeinfo.JParameter; import com.google.gwt.core.ext.typeinfo.JParameterizedType; import com.google.gwt.core.ext.typeinfo.JPrimitiveType; import com.google.gwt.core.ext.typeinfo.JType; import com.google.gwt.core.ext.typeinfo.JWildcardType; import com.google.gwt.core.ext.typeinfo.NotFoundException; import com.google.gwt.core.ext.typeinfo.TypeOracle; import com.google.gwt.inject.client.GinModules; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.rebind.ClassSourceFileComposerFactory; import com.google.gwt.user.rebind.SourceWriter; import com.kk_electronic.kkportal.core.reflection.Injection; import com.kk_electronic.kkportal.core.rpc.DelayingDispatcher; import com.kk_electronic.kkportal.core.rpc.Dispatcher; import com.kk_electronic.kkportal.core.rpc.Request; import com.kk_electronic.kkportal.core.rpc.RpcDispatcher; public class RemoteServiceGenerator extends Generator { private String packageName; private String className; private TypeOracle typeOracle; private JClassType classType; private Class<? extends Dispatcher> dispatcher; @Override public String generate(TreeLogger logger, GeneratorContext context, String typeName) throws UnableToCompleteException { try { typeOracle = context.getTypeOracle(); classType = typeOracle.getType(typeName); if(classType.isClass() != null){ return typeName; } packageName = classType.getPackage().getName(); className = classType.getSimpleSourceName() + "Impl"; classType.getAnnotation(GinModules.class); generateClass(logger, context); } catch (NotFoundException e) { logger.log(TreeLogger.ERROR, "Exception during ClassMap creation.", e); throw new UnableToCompleteException(); } return packageName + "." + className; } private void generateClass(TreeLogger logger, GeneratorContext context) throws UnableToCompleteException, NotFoundException { PrintWriter printWriter = context.tryCreate(logger, packageName, className); if (printWriter == null){ return; } ClassSourceFileComposerFactory composer = new ClassSourceFileComposerFactory(packageName,className); dispatcher=findTargetDispatcher(classType); composer.addImport(dispatcher.getCanonicalName()); composer.addImport(Dispatcher.class.getCanonicalName()); composer.addImport(Request.class.getCanonicalName()); composer.addImport(AsyncCallback.class.getCanonicalName()); composer.addImport(DelayingDispatcher.class.getCanonicalName()); composer.addImport(Injection.class.getCanonicalName()); composer.addImport(GWT.class.getCanonicalName()); composer.addImplementedInterface(classType.getQualifiedSourceName()); SourceWriter sourceWriter = composer.createSourceWriter(context,printWriter); writeConstructor(sourceWriter); writeMethods(sourceWriter); sourceWriter.outdent(); sourceWriter.println("}"); context.commit(logger, printWriter); } private Class<? extends Dispatcher> findTargetDispatcher(JClassType classType2) { Dispatch dispatch = classType2.getAnnotation(Dispatch.class); if (dispatch != null){ return dispatch.value(); } return RpcDispatcher.class; } private void writeConstructor(SourceWriter sw) { sw.println("protected "+Dispatcher.class.getSimpleName()+" dispatcher;"); sw.println(); sw.println("public "+className+"() {"); sw.indent(); sw.println("final DelayingDispatcher d = new DelayingDispatcher();"); sw.println("this.dispatcher = d;"); sw.println("Injection.create("+dispatcher.getSimpleName()+".class, new AsyncCallback<"+dispatcher.getSimpleName()+">() {"); sw.indent(); sw.println("@Override"); sw.println("public void onFailure(Throwable caught) {"); sw.println(" GWT.log(\"Failed to load dispatcher for "+escape(classType.getSimpleSourceName())+"\");"); sw.println("}"); sw.println(""); sw.println("@Override"); sw.println("public void onSuccess("+dispatcher.getSimpleName()+" result) {"); sw.println(" d.setDispatcher(result);"); sw.println(" dispatcher = result;"); sw.println("}"); sw.outdent(); sw.println("});"); sw.outdent(); sw.println("}"); } private void writeMethods(SourceWriter sw) { JClassType[] implementedInterfaces = classType.getImplementedInterfaces(); JMethod[] methods = classType.getMethods(); int i = 0; for(JMethod method : methods){ writeMethod(sw, classType, method,i++); } for (JClassType interfaze:implementedInterfaces){ methods = interfaze.getMethods(); for(JMethod method : methods){ writeMethod(sw, interfaze, method,i++); } } } private void writeMethod(SourceWriter sw, JClassType interfaze, JMethod method, int methodnr) { JParameter[] parameters = method.getParameters(); sw.println(); sw.print("private Class<?>[] RETVAL_"+methodnr); sw.print(" = new Class<?>[]{"); writeTypeInfo(sw,parameters[parameters.length-1].getType().isParameterized().getTypeArgs()[0]); sw.println("};"); sw.println("@Override"); sw.print("public void "+method.getName()+"("); for(int i=0,c=parameters.length;i<c;i++){ if(i > 0 ){ sw.print(","); } sw.print(parameters[i].getType().getParameterizedQualifiedSourceName()); sw.print(" "); sw.print(parameters[i].getName()); } sw.println(") {"); sw.indent(); String callbackname = parameters[parameters.length-1].getName(); sw.print(Request.class.getCanonicalName() + " r = new " + Request.class.getCanonicalName() + "(" + callbackname + ", RETVAL_" + methodnr + "," + interfaze.getQualifiedSourceName() + ".class,\"" + escape(method.getName()) + "\""); for(int i=0,c=parameters.length-1;i<c;i++){ sw.print(",\""); sw.print(escape(parameters[i].getName())); sw.print("\","); sw.print(parameters[i].getName()); } sw.println(");"); //sw.print("r.setParamNames("); //for(int i=0,c=parameters.length-1;i<c;i++){ // if(i>0) sw.print(","); // sw.print("\""); // sw.print(escape(parameters[i].getName())); // sw.print("\""); //} //sw.println(");"); if(method.getReturnType().isPrimitive() == JPrimitiveType.VOID){ sw.println("dispatcher.execute(r);"); } else { sw.println("return r;"); } sw.outdent(); sw.println("}"); } private void writeTypeInfo(SourceWriter sw, JType type){ JWildcardType w = type.isWildcard(); if(w != null){ type = w.getUpperBound(); } sw.print(type.getQualifiedSourceName()+ ".class"); sw.print(","); JParameterizedType x = type.isParameterized(); if(x != null){ for(JClassType nestedType : x.getTypeArgs()){ writeTypeInfo(sw, nestedType); } } } }