com.gwtplatform.mvp.rebind.GinjectorGenerator Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2011 ArcBees 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.gwtplatform.mvp.rebind;
import java.io.PrintWriter;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.inject.Provider;
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.shared.GWT;
import com.google.gwt.inject.client.AsyncProvider;
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.Guice;
import com.google.inject.Injector;
import com.google.web.bindery.event.shared.EventBus;
import com.gwtplatform.common.rebind.Logger;
import com.gwtplatform.mvp.client.annotations.DefaultGatekeeper;
import com.gwtplatform.mvp.client.annotations.ProxyCodeSplit;
import com.gwtplatform.mvp.client.annotations.ProxyCodeSplitBundle;
import com.gwtplatform.mvp.client.annotations.ProxyCodeSplitBundle.NoOpProviderBundle;
import com.gwtplatform.mvp.client.annotations.ProxyStandard;
import com.gwtplatform.mvp.client.annotations.UseGatekeeper;
import com.gwtplatform.mvp.client.proxy.PlaceManager;
import com.gwtplatform.mvp.rebind.velocity.GenerateFormFactorGinjectors;
import com.gwtplatform.mvp.rebind.velocity.RebindModule;
/**
* Will generate a Ginjector from Ginjector.
*/
public class GinjectorGenerator extends AbstractGenerator {
static final String GIN_GINJECTOR_ANNOTATION = "gin.ginjector.annotation";
static final String DEFAULT_NAME = "ClientGinjector";
static final String DEFAULT_FQ_NAME = DEFAULT_PACKAGE + "." + DEFAULT_NAME;
private static final String SINGLETON_DECLARATION
= "static ClientGinjector SINGLETON = ((GinjectorProvider) GWT.create(GinjectorProvider.class)).get();";
private static final String GETTER_METHOD = "%s get%s();";
private static final String GETTER_PROVIDER_METHOD = "%s<%s> get%s();";
private static final String DEFAULT_GATEKEEPER = "@%s";
private final ProviderBundleGenerator providerBundleGenerator = new ProviderBundleGenerator();
private final JClassType boostrapper;
public GinjectorGenerator(JClassType bootstrapper) {
this.boostrapper = bootstrapper;
}
@Override
public String generate(TreeLogger treeLogger, GeneratorContext generatorContext, String typeName)
throws UnableToCompleteException {
setTypeOracle(generatorContext.getTypeOracle());
setTreeLogger(treeLogger);
setPropertyOracle(generatorContext.getPropertyOracle());
PrintWriter printWriter = tryCreatePrintWriter(generatorContext);
if (printWriter == null) {
return typeName;
}
try {
PresenterDefinitions presenterDefinitions = new PresenterDefinitions();
findAllPresenters(presenterDefinitions);
ClassSourceFileComposerFactory composer = initComposer();
writeMandatoryGetterImports(composer);
writePresenterImports(composer, presenterDefinitions);
SourceWriter sourceWriter = composer.createSourceWriter(generatorContext, printWriter);
writeMandatoryGetter(sourceWriter);
writePresentersGetter(sourceWriter, presenterDefinitions);
writeBundleGetters(sourceWriter, presenterDefinitions.getCodeSplitBundlePresenters(), generatorContext);
Injector injector = Guice.createInjector(new RebindModule(new Logger(treeLogger), generatorContext));
writeFormFactors(injector);
closeDefinition(sourceWriter);
return DEFAULT_FQ_NAME;
} finally {
printWriter.close();
}
}
private PrintWriter tryCreatePrintWriter(GeneratorContext generatorContext) throws UnableToCompleteException {
setClassName(DEFAULT_NAME);
setPackageName(DEFAULT_PACKAGE);
return generatorContext.tryCreate(getTreeLogger(), getPackageName(), getClassName());
}
private void findAllPresenters(PresenterDefinitions presenterDefinitions) throws UnableToCompleteException {
List> annotations = findGinjectorAnnotations();
for (JClassType type : getTypeOracle().getTypes()) {
if (type.isAnnotationPresent(ProxyStandard.class)) {
presenterDefinitions.addStandardPresenter(type.getEnclosingType());
} else if (type.isAnnotationPresent(ProxyCodeSplit.class)) {
presenterDefinitions.addCodeSplitPresenter(type.getEnclosingType());
} else if (type.isAnnotationPresent(ProxyCodeSplitBundle.class)) {
ProxyCodeSplitBundle annotation = type.getAnnotation(ProxyCodeSplitBundle.class);
verifyCodeSplitBundleConfiguration(type.getName(), annotation);
presenterDefinitions.addCodeSplitBundlePresenter(annotation.value(), type.getEnclosingType());
}
if (type.isAnnotationPresent(UseGatekeeper.class)) {
presenterDefinitions.addGatekeeper(getType(type.getAnnotation(UseGatekeeper.class).value().getName()));
} else if (type.isAnnotationPresent(DefaultGatekeeper.class)) {
presenterDefinitions.addGatekeeper(type);
}
for (Class extends Annotation> annotation : annotations) {
if (type.isAnnotationPresent(annotation)) {
presenterDefinitions.addStandardPresenter(type);
break;
}
}
}
}
private List> findGinjectorAnnotations() throws UnableToCompleteException {
List> annotations = new ArrayList>();
List values = findConfigurationProperty(GIN_GINJECTOR_ANNOTATION).getValues();
for (String value : values) {
String annotationClassName = value.trim();
if (!annotationClassName.isEmpty()) {
try {
annotations.add(Class.forName(annotationClassName).asSubclass(Annotation.class));
} catch (ClassNotFoundException e) {
getTreeLogger().log(TreeLogger.ERROR, "Cannot find the class '" + annotationClassName
+ "' used in '" + GIN_GINJECTOR_ANNOTATION + "' property.");
throw new UnableToCompleteException();
} catch (ClassCastException e) {
getTreeLogger().log(TreeLogger.ERROR, "Class '" + annotationClassName + "' used in '"
+ GIN_GINJECTOR_ANNOTATION + "' property is not an Annotation.");
throw new UnableToCompleteException();
}
}
}
return annotations;
}
private void verifyCodeSplitBundleConfiguration(String presenter, ProxyCodeSplitBundle annotation)
throws UnableToCompleteException {
if (annotation.value().isEmpty()) {
getTreeLogger().log(TreeLogger.ERROR, "Cannot find the bundle value used with @"
+ ProxyCodeSplitBundle.class.getSimpleName() + " on presenter '" + presenter + "'.");
throw new UnableToCompleteException();
}
if (annotation.id() != -1 || !annotation.bundleClass().equals(NoOpProviderBundle.class)) {
getTreeLogger().log(TreeLogger.WARN, "ID and bundleClass used with @" + ProxyCodeSplitBundle.class
.getSimpleName()
+ " on presenter '" + presenter + "' are ignored since bundles are automatically generated");
}
}
private ClassSourceFileComposerFactory initComposer() throws UnableToCompleteException {
ClassSourceFileComposerFactory composer = new ClassSourceFileComposerFactory(getPackageName(), getClassName());
composer.addImport(Ginjector.class.getCanonicalName());
composer.makeInterface();
composer.addImplementedInterface(Ginjector.class.getSimpleName());
addExtensionInterfaces(composer);
return composer;
}
private void addExtensionInterfaces(ClassSourceFileComposerFactory composer) throws UnableToCompleteException {
List values = findConfigurationProperty(GIN_GINJECTOR_EXTENSION).getValues();
for (String extension : values) {
if (!extension.isEmpty()) {
final JClassType extensionType = getType(extension.trim());
composer.addImport(extensionType.getQualifiedSourceName());
composer.addImplementedInterface(extensionType.getName());
}
}
}
private void writeMandatoryGetterImports(ClassSourceFileComposerFactory composer) {
composer.addImport(GWT.class.getCanonicalName());
composer.addImport(EventBus.class.getCanonicalName());
composer.addImport(PlaceManager.class.getCanonicalName());
composer.addImport(boostrapper.getQualifiedSourceName());
}
private void writePresenterImports(ClassSourceFileComposerFactory composer,
PresenterDefinitions presenterDefinitions) {
if (presenterDefinitions.getStandardPresenters().size() > 0) {
composer.addImport(Provider.class.getCanonicalName());
}
if (presenterDefinitions.getCodeSplitPresenters().size() > 0 ||
presenterDefinitions.getCodeSplitBundlePresenters().size() > 0) {
composer.addImport(AsyncProvider.class.getCanonicalName());
}
}
private void writeMandatoryGetter(SourceWriter sourceWriter) {
sourceWriter.println(SINGLETON_DECLARATION);
sourceWriter.println();
String eventBusName = EventBus.class.getSimpleName();
sourceWriter.println(String.format(GETTER_METHOD, eventBusName, eventBusName));
sourceWriter.println();
String placeManagerName = PlaceManager.class.getSimpleName();
sourceWriter.println(String.format(GETTER_METHOD, placeManagerName, placeManagerName));
sourceWriter.println();
String bootstrapperName = boostrapper.getSimpleSourceName();
sourceWriter.println(String.format(GETTER_METHOD, bootstrapperName, bootstrapperName));
}
private void writePresentersGetter(SourceWriter sourceWriter, PresenterDefinitions presenterDefinitions) {
writeGatekeeperGetterFromList(sourceWriter, presenterDefinitions.getGatekeepers());
writePresenterGettersFromList(sourceWriter, presenterDefinitions.getStandardPresenters(),
Provider.class.getSimpleName());
writePresenterGettersFromList(sourceWriter, presenterDefinitions.getCodeSplitPresenters(),
AsyncProvider.class.getSimpleName());
}
private void writeBundleGetters(SourceWriter sourceWriter, Map> bundles,
GeneratorContext generatorContext) throws UnableToCompleteException {
for (Entry> entry : bundles.entrySet()) {
providerBundleGenerator.setPresenters(entry.getValue());
providerBundleGenerator.setPackageName(getPackageName());
String bundleName = providerBundleGenerator.generate(getTreeLogger(), generatorContext, entry.getKey());
sourceWriter.println();
sourceWriter.println(String.format(GETTER_PROVIDER_METHOD, AsyncProvider.class.getSimpleName(), bundleName,
getSimpleNameFromTypeName(bundleName)));
}
}
private void writeGatekeeperGetterFromList(SourceWriter sourceWriter, Collection gatekeepers) {
for (JClassType gatekeeper : gatekeepers) {
String name = gatekeeper.getQualifiedSourceName();
sourceWriter.println();
if (gatekeeper.isAnnotationPresent(DefaultGatekeeper.class)) {
sourceWriter.println(String.format(DEFAULT_GATEKEEPER, DefaultGatekeeper.class.getCanonicalName()));
}
sourceWriter.println(String.format(GETTER_METHOD, name, name.replaceAll("\\.", "")));
}
}
private void writePresenterGettersFromList(SourceWriter sourceWriter, Collection presenters,
String providerTypeName) {
for (JClassType presenter : presenters) {
String name = presenter.getQualifiedSourceName();
sourceWriter.println();
sourceWriter.println(String.format(GETTER_PROVIDER_METHOD, providerTypeName, name,
name.replaceAll("\\.", "")));
}
}
private void writeFormFactors(Injector injector) throws UnableToCompleteException {
GenerateFormFactorGinjectors generateFormFactorGinjectors
= injector.getInstance(GenerateFormFactorGinjectors.class);
try {
generateFormFactorGinjectors.generate();
} catch (Exception e) {
throw new UnableToCompleteException();
}
}
}