com.github.gilbertotorrezan.gwtviews.rebind.PresenterGenerator.java Source code

Java tutorial

Introduction

Here is the source code for com.github.gilbertotorrezan.gwtviews.rebind.PresenterGenerator.java

Source

/*
 * The MIT License (MIT)
 * 
 * Copyright (c) 2015 Gilberto Torrezan Filho
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 * 
 */
package com.github.gilbertotorrezan.gwtviews.rebind;

import java.io.PrintWriter;
import java.util.Date;

import com.github.gilbertotorrezan.gwtviews.client.AutoPresenter;
import com.github.gilbertotorrezan.gwtviews.client.CachePolicy;
import com.github.gilbertotorrezan.gwtviews.client.CachedPresenter;
import com.github.gilbertotorrezan.gwtviews.client.Presenter;
import com.github.gilbertotorrezan.gwtviews.client.View;
import com.github.gilbertotorrezan.gwtviews.client.ViewContainer;
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.TreeLogger.Type;
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.JParameterizedType;
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.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;

/**
 * Class used by the code generator to create the default {@link Presenter}s of Views and ViewContainers.
 * 
 * @author Gilberto Torrezan Filho
 *
 * @since v.1.0.0
 * @see AutoPresenter
 */
public class PresenterGenerator extends Generator {

    @Override
    public String generate(TreeLogger logger, GeneratorContext context, String typeName)
            throws UnableToCompleteException {

        final TypeOracle typeOracle = context.getTypeOracle();
        JClassType mainType = typeOracle.findType(typeName);

        JParameterizedType parameterized = mainType.getImplementedInterfaces()[0].isParameterized();
        JClassType viewType = parameterized.getTypeArgs()[0];
        final String className = viewType.getQualifiedSourceName();

        String name = mainType.getName().substring(mainType.getName().lastIndexOf('.') + 1);
        name = name.substring(0, name.length() - "Presenter".length());
        name = name + "_" + name + "PresenterImpl";

        PrintWriter writer = context.tryCreate(logger, viewType.getPackage().getName(), name);
        if (writer == null) {
            return viewType.getPackage().getName() + "." + name;
        }

        ClassSourceFileComposerFactory factory = new ClassSourceFileComposerFactory(viewType.getPackage().getName(),
                name);
        factory.addImplementedInterface(AutoPresenter.class.getName());

        factory.addImport(Presenter.class.getPackage().getName() + ".*");
        factory.addImport("com.google.gwt.user.client.History");
        factory.addImport("com.google.gwt.core.client.GWT");
        factory.addImport("com.google.gwt.user.client.ui.Widget");
        factory.addImport("javax.annotation.Generated");
        factory.addImport("java.util.*");

        factory.addAnnotationDeclaration("@Generated(" + "value=\"" + PresenterGenerator.class.getName() + "\", "
                + "date=\"" + new Date() + "\", " + "comments=\"Generated by GWT-Views project.\")");

        View view = viewType.getAnnotation(View.class);
        ViewContainer viewContainer = viewType.getAnnotation(ViewContainer.class);

        CachePolicy cache;
        JClassType injectorType = null;
        String injectorMethod = null;
        if (view == null) {
            cache = CachePolicy.ALWAYS;
        } else {
            cache = view.cache();
        }

        if (cache == CachePolicy.SAME_URL) {
            factory.setSuperclass(CachedPresenter.class.getName());
        }

        SourceWriter sourceWriter = factory.createSourceWriter(context, writer);

        sourceWriter.println("//AUTO GENERATED FILE BY GWT-VIEWS AT " + getClass().getName() + ". DO NOT EDIT!\n");

        if (cache == CachePolicy.ALWAYS) {
            sourceWriter.println("private Widget view; //the cached view");
        }

        Class<?> injector = view == null ? void.class : view.injector();
        if (injector.equals(void.class)) {
            injector = viewContainer == null ? void.class : viewContainer.injector();
        }

        if (!injector.equals(void.class)) {
            try {
                injectorType = typeOracle.findType(injector.getName());
                injectorMethod = view != null ? view.injectorMethod() : viewContainer.injectorMethod();
                injectorMethod = getInjectorMethod(logger, injectorType, injectorMethod, className);
            } catch (Exception e) {
                logger.log(Type.ERROR, "Error loading the injector class \"" + injector.getName() + "\": " + e, e);
                throw new UnableToCompleteException();
            }
        }

        if (cache == CachePolicy.SAME_URL) {
            sourceWriter.println("\n@Override\npublic Widget createNewView(URLToken url) {");
        } else {
            sourceWriter.println("\n@Override\npublic Widget getView(URLToken url) {");
        }
        sourceWriter.indent();

        switch (cache) {
        case NEVER: {
            sourceWriter.println("//code for the CachePolicy.NEVER:");
            printInjectorMethod(sourceWriter, className, injectorType, injectorMethod);
        }
            break;
        case ALWAYS: {
            sourceWriter.println("//code for the CachePolicy.ALWAYS:");
            sourceWriter.println("if (this.view == null) {");
            sourceWriter.indent();
            printInjectorMethod(sourceWriter, className, injectorType, injectorMethod);
            sourceWriter.println("this.view = view;");
            sourceWriter.outdent();
            sourceWriter.println("}");
        }
            break;
        case SAME_URL: {
            sourceWriter.println("//code for the CachePolicy.SAME_URL:");
            printInjectorMethod(sourceWriter, className, injectorType, injectorMethod);
        }
            break;
        }

        sourceWriter.println("return view;");
        sourceWriter.outdent();
        sourceWriter.println("}\n");

        sourceWriter.outdent();
        sourceWriter.println("}\n");

        context.commit(logger, writer);

        return factory.getCreatedClassName();
    }

    private String getInjectorMethod(TreeLogger logger, JClassType injector, String injectorMethod,
            String className) throws UnableToCompleteException {
        if (injectorMethod != null && !injectorMethod.isEmpty()) {
            try {
                injector.getMethod(injectorMethod, new JType[0]);
            } catch (NotFoundException e) {
                logger.log(Type.WARN, "The injector method \"" + injectorMethod + "\" was not found on class "
                        + injector.getQualifiedSourceName());
                //a compiler error will be trigged if the method really doesn't exist
            }
            return injectorMethod;
        } else {
            String methodName = null;
            JMethod[] methods = injector.getInheritableMethods();
            for (JMethod method : methods) {
                JType returnType = method.getReturnType();
                if (returnType.getQualifiedSourceName().equals(className)) {
                    if (methodName != null) {
                        logger.log(Type.ERROR, "The injector " + injector.getName()
                                + " has more than one method with " + className
                                + " as return type. Use the \"injectorMethod\" property to specify which one should be used.");
                        throw new UnableToCompleteException();
                    }
                    methodName = method.getName();
                }
            }
            if (methodName == null) {
                logger.log(Type.INFO, "The injector " + injector.getName() + " has no methods with " + className
                        + " as return type. The View will not be injected.");
                return null;
            }
            return methodName;
        }
    }

    private void printInjectorMethod(SourceWriter sourceWriter, String className, JClassType injectorType,
            String injectorMethod) {
        if (injectorType != null && injectorMethod != null) {
            sourceWriter.println(
                    injectorType.getQualifiedSourceName() + " injector = NavigationManager.getInjectorInstance("
                            + injectorType.getQualifiedSourceName() + ".class);");
            sourceWriter.println("if (injector == null) injector = GWT.create("
                    + injectorType.getQualifiedSourceName() + ".class);");
            sourceWriter.println("Widget view = (" + className + ") injector." + injectorMethod + "();");
        } else {
            sourceWriter.println("Widget view = GWT.create( " + className + ".class);");
        }
    }

}