All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.gwtplatform.mvp.rebind.ApplicationControllerGenerator Maven / Gradle / Ivy

/*
 * 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;
import com.gwtplatform.mvp.client.fallback.ApplicationControllerFallback;
import com.gwtplatform.mvp.client.fallback.BootstrapperFallback;
import com.gwtplatform.mvp.client.fallback.PreBootstrapperFallback;

/**
 * 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 PROBLEM_GENERATING = "There was a problem generating the ApplicationController," +
            " this can be caused by bad GWT module configuration or compile errors in your source code.";
    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, either the class name is " +
            "wrong or there are compile errors in your code.";
    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();
        } catch (UnableToCompleteException e) {
            // Java compile errors can cause problems during compilation
            // for tasks like TypeOracle#findType will return null if there
            // are compile errors, we should at least hint this possibility.
            getTreeLogger().log(TreeLogger.ERROR, PROBLEM_GENERATING);

            // Return ApplicationControllerFallback class to avoid
            // swallowing the actual compiler issues if there are any.
            return ApplicationControllerFallback.class.getName();
        } 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);
        }

        JClassType type;
        try {
            type = findAndVerifyType(typeName, Bootstrapper.class);
        } catch (UnableToCompleteException ex) {
            type = findAndVerifyType(typeName, BootstrapperFallback.class);
        }
        return type;
    }

    /**
     * @return The optional implementation of {@link PreBootstrapper} or null.
     */
    private JClassType getPreBootstrapper() throws UnableToCompleteException {
        String typeName = lookupTypeNameByProperty(PROPERTY_NAME_PREBOOTSTRAPPER);
        if (typeName == null) {
            return null;
        }

        JClassType type;
        try {
            type = findAndVerifyType(typeName, PreBootstrapper.class);
        } catch (UnableToCompleteException ex) {
            type = findAndVerifyType(typeName, PreBootstrapperFallback.class);
        }
        return type;
    }

    /**
     * Retrieve the given single-valued property.
     *
     * null if the properties' value is empty.
     */
    private String lookupTypeNameByProperty(String propertyName) throws UnableToCompleteException {
        try {
            List 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("}");
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy