Java tutorial
/* * 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 java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.Vector; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.RunAsyncCallback; 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.JType; import com.google.gwt.core.ext.typeinfo.NotFoundException; import com.google.gwt.core.ext.typeinfo.TypeOracle; import com.google.gwt.inject.client.GinModule; import com.google.gwt.inject.client.GinModules; import com.google.gwt.inject.client.Ginjector; 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.inject.ConstructFromLiteral; import com.kk_electronic.kkportal.core.inject.FlexInjector; public class FlexInjectorGenerator extends Generator { private String packageName; private String className; private TypeOracle typeOracle; private TreeLogger logger; private GinModules modules; private JClassType classType; @Override public String generate(TreeLogger logger, GeneratorContext context, String typeName) throws UnableToCompleteException { this.logger = logger; try { typeOracle = context.getTypeOracle(); classType = typeOracle.getType(typeName); packageName = classType.getPackage().getName(); className = classType.getSimpleSourceName() + "Impl"; modules = classType.getAnnotation(GinModules.class); generateClass(logger, context); } catch (NotFoundException e) { logger.log(TreeLogger.ERROR, "Exception during ModuleRegistry creation.", e); throw new UnableToCompleteException(); } return packageName + "." + className; } private void generateClass(TreeLogger logger, GeneratorContext context) throws UnableToCompleteException { PrintWriter printWriter = context.tryCreate(logger, packageName, className); if (printWriter == null) { return; } ClassSourceFileComposerFactory composer = new ClassSourceFileComposerFactory(packageName, className); composer.addImport(GWT.class.getCanonicalName()); composer.addImport(RunAsyncCallback.class.getCanonicalName()); composer.addImport(Ginjector.class.getCanonicalName()); composer.addImport(GinModules.class.getCanonicalName()); composer.addImport(AsyncCallback.class.getCanonicalName()); composer.addImport(FlexInjector.class.getCanonicalName()); composer.addImport(Map.class.getCanonicalName()); composer.addImport(HashMap.class.getCanonicalName()); composer.addImplementedInterface(classType.getQualifiedSourceName()); SourceWriter sourceWriter = composer.createSourceWriter(context, printWriter); writeStatic(sourceWriter); writeGateways(sourceWriter); // writeCreate(sourceWriter); writeConstructor(sourceWriter); sourceWriter.outdent(); sourceWriter.println("}"); context.commit(logger, printWriter); } private void writeFragment(SourceWriter sw, JClassType j) { sw.println("fragmentMap.put(" + j.getQualifiedSourceName() + ".class, new FlexInjector() {"); sw.indent(); sw.println("@Override"); sw.println("public <E> void create(Class<? extends E> type, AsyncCallback<E> callback) {"); sw.indentln( "callback.onSuccess((E)injector.create$" + j.getQualifiedSourceName().replace('.', '$') + "());"); sw.println("}"); sw.outdent(); sw.println("});"); } private void writeGateways(SourceWriter sw) throws UnableToCompleteException { for (String key : getClasses().keySet()) { if (key == null) continue; sw.println("private final class fragment$" + key + " implements FlexInjector {"); sw.indent(); sw.println(); sw.println("@Override"); sw.println("public <T> void create(final Class<? extends T> type, final AsyncCallback<T> callback) {"); sw.indent(); sw.println("GWT.runAsync(new RunAsyncCallback() {"); sw.indent(); sw.println("@Override"); sw.println("public void onSuccess() {"); for (JClassType j : getClasses().get(key)) { writeFragment(sw, j); } sw.indent(); sw.println(className + ".this.create(type, callback);"); sw.outdent(); sw.println("}"); sw.println("public void onFailure(Throwable reason) {"); sw.indent(); for (JClassType j : getClasses().get(key)) { sw.println("fragmentMap.remove(" + j.getQualifiedSourceName() + ".class);"); } sw.println("callback.onFailure(reason);"); sw.outdent(); sw.println("}"); sw.outdent(); sw.println("});"); sw.outdent(); sw.println("}"); sw.outdent(); sw.println("}"); } } private void writeConstructor(SourceWriter sw) throws UnableToCompleteException { sw.println(); sw.println("@SuppressWarnings(\"unchecked\")"); sw.println("public " + className + "() {"); sw.indent(); sw.println("FlexInjector fragment;"); for (String key : getClasses().keySet()) { if (key != null) { sw.println("fragment = new fragment$" + key + "();"); for (JClassType j : getClasses().get(key)) { sw.println("fragmentMap.put(" + j.getQualifiedSourceName() + ".class, fragment);"); } } else { for (JClassType j : getClasses().get(key)) { writeFragment(sw, j); } } } sw.outdent(); sw.println("}"); } private void writeStatic(SourceWriter sw) throws UnableToCompleteException { modules.toString(); sw.print("@GinModules("); for (Class<? extends GinModule> s : modules.value()) { sw.print(s.getCanonicalName()); sw.print(".class"); } sw.println(")"); sw.println("static interface Injector extends Ginjector {"); sw.indent(); Set<JType> set = new HashSet<JType>(); for (Vector<JClassType> group : getClasses().values()) { set.addAll(group); } for (JMethod method : classType.getMethods()) { set.add(method.getReturnType()); } for (JType j : set) { sw.println( j.getQualifiedSourceName() + " create$" + j.getQualifiedSourceName().replace('.', '$') + "();"); } // for(Vector<JClassType> group : getClasses().values()){ // for(JClassType j : group){ // sw.println(j.getQualifiedSourceName() + " create$" + j.getQualifiedSourceName().replace('.', '$') + "();"); // } // } sw.outdent(); sw.println("}"); sw.println(); sw.println("private final Injector injector = GWT.create(Injector.class);"); sw.println("private Map<Class<?>, FlexInjector> fragmentMap = new HashMap<Class<?>, FlexInjector>();"); sw.println(); sw.println("@Override"); sw.println("public <T> void create(Class<? extends T> type, AsyncCallback<T> callback) {"); sw.println(" FlexInjector x = fragmentMap.get(type);"); sw.println(" if (x != null){"); sw.println(" x.create(type, callback);"); sw.println(" } else {"); // sw.println(" callback.onFailure(new ClassNotFoundException());"); sw.println(" callback.onFailure(null);"); sw.println(" GWT.log(\"Class Creation of \" + type + \" failed\");"); sw.println(" }"); sw.println("}"); } private Map<String, Vector<JClassType>> groups; private void addClass(JClassType j) { assert (this.groups != null); String key = getKeyFromClass(j); Vector<JClassType> vector = groups.get(key); if (vector == null) { vector = new Vector<JClassType>(); } vector.add(j); groups.put(key, vector); } private String getKeyFromClass(JClassType j) { ModuleGroup x = j.getAnnotation(ModuleGroup.class); if (x != null) { return x.value().replaceAll("[- ]", ""); } return null; } private Map<String, Vector<JClassType>> getClasses() throws UnableToCompleteException { if (this.groups != null) { return this.groups; } this.groups = new HashMap<String, Vector<JClassType>>(); try { typeOracle.getType(ConstructFromLiteral.class.getCanonicalName()); } catch (NotFoundException error) { logger.log(TreeLogger.ERROR, "Can't find marker interface", error); throw new UnableToCompleteException(); } for (JClassType j : typeOracle.getTypes()) { ConstructFromLiteral a = j.getAnnotation(ConstructFromLiteral.class); if (a != null) { if (a.includeConcreteClasses() && (j.isClass() != null && !j.isAbstract())) { addClass(j); } if (a.includeInterfaces() && (j.isInterface() != null)) { addClass(j); } if (a.recursive()) { for (JClassType e : j.getSubtypes()) { if (a.includeConcreteClasses() && (e.isClass() != null && !e.isAbstract())) { addClass(e); } if (a.includeInterfaces() && (e.isInterface() != null)) { addClass(e); } } } } } return groups; } }