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

Java tutorial

Introduction

Here is the source code for com.github.gilbertotorrezan.gwtviews.rebind.NavigationManagerGenerator.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.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.github.gilbertotorrezan.gwtviews.client.HasViews;
import com.github.gilbertotorrezan.gwtviews.client.NavigationManager;
import com.github.gilbertotorrezan.gwtviews.client.Presenter;
import com.github.gilbertotorrezan.gwtviews.client.URLInterceptor;
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.TypeOracle;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;

/**
 * Class used by the code generator to create the {@link NavigationManager}.
 * 
 * @author Gilberto Torrezan Filho
 *
 * @since v.1.0.0
 */
public class NavigationManagerGenerator extends Generator {

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

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

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

        ClassSourceFileComposerFactory factory = new ClassSourceFileComposerFactory(mainType.getPackage().getName(),
                mainType.getName() + "Impl");
        factory.addImplementedInterface(typeName);

        factory.addImport(Presenter.class.getPackage().getName() + ".*");
        factory.addImport("com.google.gwt.user.client.History");
        factory.addImport("com.google.gwt.user.client.ui.Widget");
        factory.addImport("com.google.gwt.user.client.ui.Panel");
        factory.addImport("com.google.gwt.http.client.URL");
        factory.addImport("com.google.gwt.user.client.rpc.AsyncCallback");
        factory.addImport("com.google.gwt.core.client.*");
        factory.addImport("com.google.gwt.event.logical.shared.*");
        factory.addImport("com.github.gilbertotorrezan.gwtviews.client.analytics.*");
        factory.addImport("javax.annotation.Generated");
        factory.addImport("java.util.*");

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

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

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

        sourceWriter.println("private Panel rootContainer;");
        sourceWriter.println("private UserPresenceManager userPresenceManager;");
        sourceWriter.println("private URLTokenFactory tokenFactory = new URLTokenFactory();");
        sourceWriter.println("private final Map<String, Presenter<?>> presentersMap = new HashMap<>();");
        sourceWriter.println("private URLToken currentToken = tokenFactory.createToken(\"\");");
        sourceWriter.println("private URLInterceptor currentInterceptor;\n");

        List<ViewPage> viewPages = new ArrayList<>();
        Map<String, HasViewPages> viewContainers = new HashMap<>();

        Set<ViewPage> viewsInNeedOfPresenters = new LinkedHashSet<>();
        Set<HasViewPages> containersInNeedOfPresenters = new LinkedHashSet<>();

        ViewPage defaultViewPage = null;
        ViewPage notFoundViewPage = null;
        HasViewPages defaultViewContainerPage = null;

        JClassType containerType = typeOracle.findType(HasViews.class.getName());

        JClassType[] types = typeOracle.getTypes();
        for (JClassType type : types) {
            if (type.isAnnotationPresent(View.class)) {
                View view = type.getAnnotation(View.class);
                if (shouldForceEmptyConstructor(view) && !type.isDefaultInstantiable()) {
                    logger.log(Type.WARN, type.getName() + " must have an empty constructor to be a valid "
                            + View.class.getSimpleName() + ".");
                    continue;
                }
                ViewPage page = new ViewPage(view, type);
                viewPages.add(page);
                if (view.defaultView()) {
                    defaultViewPage = page;
                }
                if (view.notFoundView()) {
                    notFoundViewPage = page;
                }
            } else if (type.isAnnotationPresent(ViewContainer.class)) {
                if (!type.isAssignableTo(containerType)) {
                    logger.log(Type.WARN, type.getName() + " must implement " + containerType.getName()
                            + " to be a valid " + ViewContainer.class.getSimpleName() + ".");
                    continue;
                }
                ViewContainer container = type.getAnnotation(ViewContainer.class);
                if (shouldForceEmptyConstructor(container) && !type.isDefaultInstantiable()) {
                    logger.log(Type.WARN, type.getName() + " must have an empty constructor to be a valid "
                            + ViewContainer.class.getSimpleName() + ".");
                    continue;
                }
                HasViewPages hasViews = new HasViewPages(container, type);
                viewContainers.put(type.getQualifiedSourceName(), hasViews);
                if (container.defaultContainer()) {
                    defaultViewContainerPage = hasViews;
                }
            }
        }

        if (defaultViewPage == null) {
            logger.log(Type.ERROR, "No default view page defined!");
            throw new UnableToCompleteException();
        }

        if (defaultViewContainerPage == null && viewContainers.size() > 1) {
            logger.log(Type.ERROR, "There are more than one " + ViewContainer.class.getSimpleName()
                    + " but no one is the default!");
            throw new UnableToCompleteException();
        }

        if (defaultViewContainerPage == null && !viewContainers.isEmpty()) {
            defaultViewContainerPage = viewContainers.values().iterator().next();
        }

        sourceWriter.println("public void onValueChange(ValueChangeEvent<String> event){");
        sourceWriter.indent();
        sourceWriter.println("final URLToken token = tokenFactory.createToken(event.getValue());");

        sourceWriter.println("if (currentInterceptor != null){");
        sourceWriter.indent();

        sourceWriter.println("History.newItem(currentToken.toString(), false);");
        sourceWriter.println("currentInterceptor.onUrlChanged(currentToken, token, new URLInterceptorCallback(){");
        sourceWriter.indent();
        sourceWriter.println("@Override\npublic void proceedTo(URLToken destination){");
        sourceWriter.indent();
        sourceWriter.println("History.newItem(destination.toString(), false);");
        sourceWriter.println("proceedToImpl(destination);");
        sourceWriter.outdent();
        sourceWriter.println("}");

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

        sourceWriter.println("return;");
        sourceWriter.outdent();
        sourceWriter.println("}");

        sourceWriter.println("this.proceedToImpl(token);");

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

        sourceWriter.println("private void proceedToImpl(final URLToken token){");
        sourceWriter.indent();

        sourceWriter.println("this.currentToken = token;");

        sourceWriter.println("switch (token.getId()){");
        sourceWriter.indent();

        int defaultViewIndex = -1;
        int notFoundViewIndex = -1;

        for (int i = 0; i < viewPages.size(); i++) {
            ViewPage viewPage = viewPages.get(i);
            final View view = viewPage.getView();
            logger.log(Type.DEBUG, "Processing view " + view.value() + "...");

            if (view.defaultView()) {
                defaultViewIndex = i;
                sourceWriter.println("case \"\":");
            }
            if (view.notFoundView()) {
                notFoundViewIndex = i;
            }

            sourceWriter.println("case \"" + view.value() + "\": {");
            sourceWriter.indent();

            if (!view.publicAccess()) {
                sourceWriter.println("if (userPresenceManager != null) {");
                sourceWriter.indent();

                if (view.rolesAllowed() != null && view.rolesAllowed().length > 0) {
                    String[] roles = view.rolesAllowed();
                    StringBuilder params = new StringBuilder("new String[]{ ");
                    String sep = "";
                    for (String role : roles) {
                        params.append(sep).append("\"").append(role).append("\"");
                        sep = ", ";
                    }
                    params.append(" }");
                    sourceWriter.println("userPresenceManager.isUserInAnyRole(token, " + params.toString()
                            + ", new AsyncCallback<Boolean>(){");
                } else {
                    sourceWriter.println(
                            "userPresenceManager.isUserInAnyRole(token, new String[0], new AsyncCallback<Boolean>(){");
                }
                sourceWriter.indent();
                sourceWriter.println("@Override");
                sourceWriter.println("public void onSuccess(Boolean allowed){");
                sourceWriter.indent();
                sourceWriter.println("if (allowed == null || !allowed){");
                sourceWriter.indent();
                sourceWriter.println("URLToken nextToken = tokenFactory.createToken(\""
                        + defaultViewPage.getView().value() + "\");");
                sourceWriter.println("nextToken.setParameter(\"next\", URL.encodeQueryString(token.toString()));");
                sourceWriter.println("nextToken.go();");
                sourceWriter.outdent();
                sourceWriter.println("}");
                sourceWriter.println("else {");
                sourceWriter.indent();
                sourceWriter.println("showPresenter" + i + "(token);");
                sourceWriter.outdent();
                sourceWriter.println("}");
                sourceWriter.outdent();
                sourceWriter.println("}");
                sourceWriter.println("@Override");
                sourceWriter.println("public void onFailure(Throwable error){");
                sourceWriter.indent();
                sourceWriter.println("GWT.log(\"Error loading view: \" + error, error);");
                sourceWriter.println("URLToken nextToken = tokenFactory.createToken(\""
                        + defaultViewPage.getView().value() + "\");");
                sourceWriter.println("nextToken.setParameter(\"next\", URL.encodeQueryString(token.toString()));");
                sourceWriter.println("nextToken.go();");
                sourceWriter.outdent();
                sourceWriter.println("}");
                sourceWriter.outdent();
                sourceWriter.println("});");

                sourceWriter.println("return;");
                sourceWriter.outdent();
                sourceWriter.println("}");
            }

            sourceWriter.println("showPresenter" + i + "(token);");
            sourceWriter.outdent();
            sourceWriter.println("}\nbreak;");
        }

        sourceWriter.println("default: {");
        sourceWriter.indent();

        if (notFoundViewPage != null) {
            sourceWriter.println("//NotFound View");
            sourceWriter.println("showPresenter" + notFoundViewIndex + "(tokenFactory.createToken(\""
                    + notFoundViewPage.getView().value() + "\"));");
        } else {
            sourceWriter.println("//Default View");
            sourceWriter.println("History.newItem(\"" + defaultViewPage.getView().value() + "\", false);");
            sourceWriter.println("showPresenter" + defaultViewIndex + "(tokenFactory.createToken(\""
                    + defaultViewPage.getView().value() + "\"));");
        }
        sourceWriter.outdent();
        sourceWriter.println("}\nbreak;");
        sourceWriter.outdent();
        sourceWriter.println("}");

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

        for (int i = 0; i < viewPages.size(); i++) {
            ViewPage viewPage = viewPages.get(i);
            final View view = viewPage.getView();

            sourceWriter.println("/** Method to show the presenter of the " + view.value() + " view. */");
            sourceWriter.println("private void showPresenter" + i + "(final URLToken token) {");
            sourceWriter.indent();

            sourceWriter.println("GWT.runAsync(new RunAsyncCallback() {");
            sourceWriter.indent();

            sourceWriter.println("public void onSuccess() {");
            sourceWriter.indent();

            sourceWriter.println("UniversalAnalyticsTracker.sendPageView(token.toString());");
            sourceWriter.println("Presenter<?> presenter = presentersMap.get(\"" + view.value() + "\");");
            sourceWriter.println("if (presenter == null) {");
            sourceWriter.indent();

            Class<? extends Presenter> customPresenter = view.customPresenter();
            if (!Presenter.class.equals(customPresenter)) {
                sourceWriter.println("presenter = GWT.create(" + customPresenter.getName() + ".class);");
            } else {
                viewsInNeedOfPresenters.add(viewPage);
                sourceWriter.println("presenter = (Presenter<?>) GWT.create(" + viewPage.getType().getName()
                        + "Presenter.class);");
            }
            sourceWriter.println("presentersMap.put(\"" + view.value() + "\", presenter);");
            sourceWriter.outdent();
            sourceWriter.println("}");
            sourceWriter.println("Widget widget = presenter.getView(token);");

            Class<? extends URLInterceptor> urlInterceptor = view.urlInterceptor();
            if (!URLInterceptor.class.equals(urlInterceptor)) {
                String interceptorName = urlInterceptor.getName();
                if (interceptorName.equals(viewPage.getType().getQualifiedSourceName())) {
                    sourceWriter.println("currentInterceptor = (URLInterceptor) widget;");
                } else if (interceptorName.equals(customPresenter.getName())) {
                    sourceWriter.println("currentInterceptor = (URLInterceptor) presenter;");
                } else {
                    sourceWriter
                            .println("currentInterceptor = GWT.create(" + urlInterceptor.getName() + ".class);");
                }
            } else {
                sourceWriter.println("currentInterceptor = null;");
            }

            boolean usesViewContainer = view.usesViewContainer();
            if (usesViewContainer && !viewContainers.isEmpty()) {
                Class<?> viewContainer = view.viewContainer();
                HasViewPages hasViews;
                if (HasViews.class.equals(viewContainer)) {
                    hasViews = defaultViewContainerPage;
                } else {
                    hasViews = viewContainers.get(viewContainer.getName());
                }

                if (hasViews == null) {
                    logger.log(Type.ERROR,
                            viewContainer.getName() + " is not a valid " + ViewContainer.class.getSimpleName()
                                    + " for " + View.class.getSimpleName() + " "
                                    + viewPage.getType().getQualifiedSourceName() + ".");
                    throw new UnableToCompleteException();
                }
                sourceWriter.println("Presenter<?> containerPresenter = presentersMap.get(\""
                        + hasViews.getType().getQualifiedSourceName() + "\");");
                sourceWriter.println("if (containerPresenter == null) {");
                sourceWriter.indent();
                if (!Presenter.class.equals(hasViews.getContainer().customPresenter())) {
                    sourceWriter.println("containerPresenter = GWT.create("
                            + hasViews.getContainer().customPresenter().getName() + ".class);");
                } else {
                    containersInNeedOfPresenters.add(hasViews);
                    sourceWriter.println("containerPresenter = (Presenter<?>) GWT.create("
                            + hasViews.getType().getName() + "Presenter.class);");
                }
                sourceWriter.println("presentersMap.put(\"" + hasViews.getType().getQualifiedSourceName()
                        + "\", containerPresenter);");
                sourceWriter.outdent();
                sourceWriter.println("}");
                sourceWriter.println("Widget container = containerPresenter.getView(token);");
                sourceWriter.println("((" + HasViews.class.getName() + ") container).showView(token, widget);");
                sourceWriter.println("if (container.getParent() == null){");
                sourceWriter.indent();
                sourceWriter.println("rootContainer.clear();");
                sourceWriter.println("rootContainer.add(container);");
                sourceWriter.outdent();
                sourceWriter.println("}");
            } else {
                sourceWriter.println("rootContainer.clear();");
                sourceWriter.println("rootContainer.add(widget);");
            }
            sourceWriter.outdent();
            sourceWriter.println("}");
            sourceWriter.println(
                    "public void onFailure(Throwable reason) { GWT.log(\"Error on loading presenter with token: \"+token, reason); }");
            sourceWriter.outdent();
            sourceWriter.println("});");

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

        sourceWriter.println("@Override\npublic void clearCache() {");
        sourceWriter.indent();
        sourceWriter.println("presentersMap.clear();");
        sourceWriter.outdent();
        sourceWriter.println("}\n");

        sourceWriter.println("@Override\npublic void clearCache(String tokenId) {");
        sourceWriter.indent();
        sourceWriter.println("presentersMap.remove(tokenId);");
        sourceWriter.outdent();
        sourceWriter.println("}\n");

        sourceWriter.println("@Override\npublic void setRootContainer(Panel container) {");
        sourceWriter.indent();
        sourceWriter.println("this.rootContainer = container;");
        sourceWriter.outdent();
        sourceWriter.println("}\n");

        sourceWriter.println("@Override\npublic void setUserPresenceManager(UserPresenceManager umanager) {");
        sourceWriter.indent();
        sourceWriter.println("this.userPresenceManager = umanager;");
        sourceWriter.outdent();
        sourceWriter.println("}\n");

        sourceWriter.println("@Override\npublic void setURLTokenFactory(URLTokenFactory tokenFactory) {");
        sourceWriter.indent();
        sourceWriter.println("this.tokenFactory = tokenFactory;");
        sourceWriter.outdent();
        sourceWriter.println("}\n");

        sourceWriter.println("@Override\npublic URLTokenFactory getURLTokenFactory() {");
        sourceWriter.indent();
        sourceWriter.println("return this.tokenFactory;");
        sourceWriter.outdent();
        sourceWriter.println("}\n");

        sourceWriter.println("//View presenters");
        for (ViewPage viewPage : viewsInNeedOfPresenters) {
            sourceWriter.println("public static interface " + viewPage.getType().getName()
                    + "Presenter extends AutoPresenter<" + viewPage.getType().getQualifiedSourceName() + ">{}");
        }
        if (!containersInNeedOfPresenters.isEmpty()) {
            sourceWriter.println("\n//ViewContainer presenters");
            for (HasViewPages container : containersInNeedOfPresenters) {
                sourceWriter.println("public static interface " + container.getType().getName()
                        + "Presenter extends AutoPresenter<" + container.getType().getQualifiedSourceName()
                        + ">{}");
            }
        }

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

        context.commit(logger, writer);

        return factory.getCreatedClassName();
    }

    private boolean shouldForceEmptyConstructor(View view) {
        return Presenter.class.equals(view.customPresenter()) && void.class.equals(view.injector());
    }

    private boolean shouldForceEmptyConstructor(ViewContainer vc) {
        return Presenter.class.equals(vc.customPresenter()) && void.class.equals(vc.injector());
    }

    private class ViewPage {
        private final View view;
        private final JClassType type;

        public ViewPage(View view, JClassType type) {
            this.view = view;
            this.type = type;
        }

        public View getView() {
            return view;
        }

        public JClassType getType() {
            return type;
        }
    }

    private class HasViewPages {
        private final ViewContainer container;
        private final JClassType type;

        public HasViewPages(ViewContainer container, JClassType type) {
            this.container = container;
            this.type = type;
        }

        public ViewContainer getContainer() {
            return container;
        }

        public JClassType getType() {
            return type;
        }
    }

}