Java tutorial
/** * 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.util.List; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.core.ext.BadPropertyValueException; 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.user.rebind.ClassSourceFileComposerFactory; import com.google.gwt.user.rebind.SourceWriter; import com.gwtplatform.mvp.client.Bootstrapper; import com.gwtplatform.mvp.client.DelayedBindRegistry; import com.gwtplatform.mvp.client.PreBootstrapper; /** * Will generate a {@link com.gwtplatform.mvp.client.ApplicationController}. If the user wants his Generator to be * generated by GWTP, this Application controller will make sure that the Ginjector is used to trigger the initial * revealCurrentPlace() from the place manager. */ public class ApplicationControllerGenerator extends AbstractGenerator { private static final String PROPERTY_BOOTSTRAPPER_EMPTY = "Required configuration property 'gwtp.bootstrapper' can not be empty!."; private static final String PROPERTY_NOT_FOUND = "Undefined configuration property '%s'."; private static final String TYPE_NOT_FOUND = "The type '%s' was not found."; private static final String HINT_URL = "https://github.com/ArcBees/GWTP/wiki/Bootstrapping"; private static final String DOES_NOT_EXTEND_INTERFACE = "'%s' doesn't implement the '%s' interface. See " + HINT_URL; private static final String PROPERTY_NAME_BOOTSTRAPPER = "gwtp.bootstrapper"; private static final String PROPERTY_NAME_PREBOOTSTRAPPER = "gwtp.prebootstrapper"; private static final String SUFFIX = "Impl"; private static final String OVERRIDE = "@Override"; private static final String INJECT_METHOD = "public void init() {"; private static final String DELAYED_BIND = "%s.bind(%s.SINGLETON);"; private static final String ONBOOTSTRAP = "%s.SINGLETON.get%s().onBootstrap();"; private static final String ONPREBOOTSTRAP = "new %s().onPreBootstrap();"; private static final String SCHEDULE_DEFERRED_1 = "Scheduler.get().scheduleDeferred(new ScheduledCommand() {"; private static final String SCHEDULE_DEFERRED_2 = "public void execute() {"; private static final String ONMODULE_LOAD = "public void onModuleLoad() {"; private static final String INIT = "init();"; @Override public String generate(TreeLogger treeLogger, GeneratorContext generatorContext, String typeName) throws UnableToCompleteException { setTypeOracle(generatorContext.getTypeOracle()); setPropertyOracle(generatorContext.getPropertyOracle()); setTreeLogger(treeLogger); setTypeClass(getType(typeName)); PrintWriter printWriter = tryCreatePrintWriter(generatorContext, SUFFIX); if (printWriter == null) { return typeName + SUFFIX; } try { JClassType preBootstrapper = getPreBootstrapper(); ClassSourceFileComposerFactory composer = initComposer(preBootstrapper); SourceWriter sw = composer.createSourceWriter(generatorContext, printWriter); JClassType bootstrapper = getBootstrapper(); String ginjectorName = new GinjectorGenerator(bootstrapper).generate(getTreeLogger(), generatorContext, GinjectorGenerator.DEFAULT_FQ_NAME); writeInit(sw, ginjectorName, preBootstrapper, bootstrapper); closeDefinition(sw); return getPackageName() + "." + getClassName(); } finally { printWriter.close(); } } private ClassSourceFileComposerFactory initComposer(JClassType preBootstrapper) { ClassSourceFileComposerFactory composer = new ClassSourceFileComposerFactory(getPackageName(), getClassName()); composer.addImport(getTypeClass().getQualifiedSourceName()); if (preBootstrapper != null) { composer.addImport(preBootstrapper.getQualifiedSourceName()); composer.addImport(Scheduler.class.getCanonicalName()); composer.addImport(ScheduledCommand.class.getCanonicalName()); } composer.addImplementedInterface(getTypeClass().getName()); composer.addImport(DelayedBindRegistry.class.getCanonicalName()); return composer; } /** * @return The required implementation of {@link Bootstrapper} to use. */ private JClassType getBootstrapper() throws UnableToCompleteException { String typeName = lookupTypeNameByProperty(PROPERTY_NAME_BOOTSTRAPPER); if (typeName == null) { getTreeLogger().log(TreeLogger.ERROR, PROPERTY_BOOTSTRAPPER_EMPTY); throw new UnableToCompleteException(); } return findAndVerifyType(typeName, Bootstrapper.class); } /** * @return The optional implementation of {@link PreBootstrapper} or <code>null</code>. */ private JClassType getPreBootstrapper() throws UnableToCompleteException { String typeName = lookupTypeNameByProperty(PROPERTY_NAME_PREBOOTSTRAPPER); if (typeName == null) { return null; } return findAndVerifyType(typeName, PreBootstrapper.class); } /** * Retrieve the given single-valued property. * * <code>null</code> if the properties' value is empty. */ private String lookupTypeNameByProperty(String propertyName) throws UnableToCompleteException { try { List<String> values = getPropertyOracle().getConfigurationProperty(propertyName).getValues(); if (values.size() != 0) { String typeName = values.get(0); if (typeName != null && !typeName.trim().isEmpty()) { return typeName; } } } catch (BadPropertyValueException e) { getTreeLogger().log(TreeLogger.ERROR, String.format(PROPERTY_NOT_FOUND, propertyName)); throw new UnableToCompleteException(); } return null; } /** * Find the Java type by the given class name and verify that it extends the given interface. */ private JClassType findAndVerifyType(String typeName, Class<?> interfaceClass) throws UnableToCompleteException { JClassType type = getTypeOracle().findType(typeName); if (type == null) { getTreeLogger().log(TreeLogger.ERROR, String.format(TYPE_NOT_FOUND, typeName)); throw new UnableToCompleteException(); } JClassType interfaceType = getType(interfaceClass.getName()); if (!type.isAssignableTo(interfaceType)) { getTreeLogger().log(TreeLogger.ERROR, String.format(DOES_NOT_EXTEND_INTERFACE, typeName, interfaceClass.getSimpleName())); throw new UnableToCompleteException(); } return type; } private void writeInit(SourceWriter sw, String generatorName, JClassType preBootstrapper, JClassType bootstrapper) { sw.println(OVERRIDE); sw.println(INJECT_METHOD); sw.indent(); if (preBootstrapper != null) { sw.println(ONPREBOOTSTRAP, preBootstrapper.getSimpleSourceName()); sw.println(); sw.println(SCHEDULE_DEFERRED_1); sw.indent(); sw.println(OVERRIDE); sw.println(SCHEDULE_DEFERRED_2); sw.indent(); } sw.println(String.format(DELAYED_BIND, DelayedBindRegistry.class.getSimpleName(), generatorName)); sw.println(); sw.println(String.format(ONBOOTSTRAP, generatorName, bootstrapper.getSimpleSourceName())); sw.outdent(); sw.println("}"); if (preBootstrapper != null) { sw.outdent(); sw.println("});"); sw.outdent(); sw.println("}"); } sw.println(OVERRIDE); sw.println(ONMODULE_LOAD); sw.indent(); sw.println(INIT); sw.outdent(); sw.println("}"); } }