com.github.gilbertotorrezan.gwtviews.rebind.NavigationManagerGenerator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gwt-views Show documentation
Show all versions of gwt-views Show documentation
A simple but powerful View controller for GWT
The newest version!
/*
* 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> presentersMap = new HashMap<>();");
sourceWriter.println("private URLToken currentToken = tokenFactory.createToken(\"\");");
sourceWriter.println("private URLInterceptor currentInterceptor;\n");
List viewPages = new ArrayList<>();
Map viewContainers = new HashMap<>();
Set viewsInNeedOfPresenters = new LinkedHashSet<>();
Set 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 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(){");
}
else {
sourceWriter.println("userPresenceManager.isUserInAnyRole(token, new String[0], new AsyncCallback(){");
}
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;
}
}
}