/* * Copyright 2010 Gal Dolber. * * 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.guit.rebind.gin; import com.google.gwt.core.client.GWT; import com.google.gwt.core.ext.CachedGeneratorResult; import com.google.gwt.core.ext.GeneratorContext; import com.google.gwt.core.ext.RebindMode; import com.google.gwt.core.ext.RebindResult; import com.google.gwt.core.ext.TreeLogger; import com.google.gwt.core.ext.UnableToCompleteException; import com.google.gwt.core.ext.typeinfo.JPackage; import com.google.gwt.inject.client.AsyncProvider; 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.rebind.ClassSourceFileComposerFactory; import com.google.gwt.user.rebind.SourceWriter; import com.google.inject.Provider; import com.guit.rebind.common.AbstractGenerator; import java.io.PrintWriter; import java.util.HashSet; import java.util.List; /** * This one is static to be accesible from any Generator, event outsiders. */ public class GinInjectorGenerator extends AbstractGenerator implements GinContext { private static final String SINGLETON_DECLARATION = "public static " + GinOracle.fullName + " SINGLETON = " + GWT.class.getCanonicalName() + ".create(" + GinOracle.fullName + ".class);"; private HashSet<String> injectedClasses = new HashSet<String>(); private HashSet<String> providedClasses = new HashSet<String>(); private HashSet<String> asyncProvidedClasses = new HashSet<String>(); private final HashSet<Class<? extends GinModule>> gmodules = new HashSet<Class<? extends GinModule>>(); @Override public void addAsyncProvidedType(String classType) { asyncProvidedClasses.add(classType); } @Override public void addInjectedType(String classType) { injectedClasses.add(classType); } @SuppressWarnings("unchecked") @Override public void addModule(String module) { try { gmodules.add((Class<? extends GinModule>) Class.forName(module)); } catch (ClassNotFoundException e) { throw new IllegalStateException(e); } } @Override public void addProvidedType(String classType) { providedClasses.add(classType); } @Override protected void generate(SourceWriter writer) throws UnableToCompleteException { } @Override public RebindResult generateIncrementally(TreeLogger logger, GeneratorContext context, String typeName) throws UnableToCompleteException { saveVariables(logger, context, typeName); if (typeOracle.findType(GinOracle.packageName, GinOracle.className) != null) { return new RebindResult(RebindMode.USE_EXISTING, GinOracle.packageName + "." + GinOracle.className); } // Clear injectedClasses.clear(); providedClasses.clear(); asyncProvidedClasses.clear(); gmodules.clear(); // Call gin contributors List<String> contributors = getConfigurationProperty("app.gin.contributor").getValues(); for (String c : contributors) { GinContributor contributor = instantiateContributor(c); contributor.collaborate(this, logger, context); } // Generate the modules string StringBuilder sb = new StringBuilder(); sb.append("({"); for (Class<?> m : gmodules) { if (sb.length() > 2) { sb.append(", "); } sb.append(m.getCanonicalName() + ".class"); } sb.append("})"); GinOracle.setModules(gmodules); ClassSourceFileComposerFactory composer = new ClassSourceFileComposerFactory(GinOracle.packageName, GinOracle.className); composer.makeInterface(); composer.addImplementedInterface(Ginjector.class.getCanonicalName()); composer.addAnnotationDeclaration("@" + GinModules.class.getCanonicalName() + sb.toString()); PrintWriter printWriter = context.tryCreate(logger, GinOracle.packageName, GinOracle.className); // Convert to linked to remove possible duplicated entries injectedClasses = findClassOrLinkedInjectionKey(injectedClasses); providedClasses = findClassOrLinkedInjectionKey(providedClasses); asyncProvidedClasses = findClassOrLinkedInjectionKey(asyncProvidedClasses); if (printWriter != null) { SourceWriter writer = composer.createSourceWriter(context, printWriter); writer.println(SINGLETON_DECLARATION); for (String classType : injectedClasses) { load(classType); writer.println(classType + " " + GinOracle.getGetterMethodName(classType) + "();"); } for (String classType : providedClasses) { load(classType); writer.println(Provider.class.getCanonicalName() + "<" + classType + "> " + GinOracle.getProviderGetterMethodName(classType) + "();"); } for (String classType : asyncProvidedClasses) { load(classType); writer.println(AsyncProvider.class.getCanonicalName() + "<" + classType + "> " + GinOracle.getAsyncProviderGetterMethodName(classType) + "();"); } writer.commit(logger); } return new RebindResult(RebindMode.USE_PARTIAL_CACHED, GinOracle.packageName + "." + GinOracle.className); } private void load(String classType) { try { GinInjectorGenerator.class.getClassLoader().loadClass(classType); } catch (Exception e) { throw new RuntimeException(e); } } private HashSet<String> findClassOrLinkedInjectionKey(HashSet<String> original) { HashSet<String> set = new HashSet<String>(); for (String c : original) { set.add(GinOracle.getClassOrLinkedInjectionKey(c)); } return set; } @Override public HashSet<String> getAsyncProvidedClasses() { return asyncProvidedClasses; } @Override public HashSet<Class<? extends GinModule>> getGModules() { return gmodules; } @Override public HashSet<String> getInjectedClasses() { return injectedClasses; } @Override public HashSet<String> getProvidedClasses() { return providedClasses; } private GinContributor instantiateContributor(String c) { try { Class<?> clazz = Class.forName(c); return (GinContributor) clazz.newInstance(); } catch (Exception e) { throw new IllegalStateException(e); } } @Override protected void processComposer(ClassSourceFileComposerFactory composer) { composer.addImplementedInterface(typeName); } }