/*
* Copyright (c) 2008-2009 GWT Mosaic Georgios J. Georgopolos.
*
* 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 org.gwt.mosaic.application.rebind;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import org.gwt.beansbinding.core.client.AutoBinding;
import org.gwt.beansbinding.core.client.BeanProperty;
import org.gwt.beansbinding.core.client.Binding;
import org.gwt.beansbinding.core.client.Bindings;
import org.gwt.mosaic.actions.client.Action;
import org.gwt.mosaic.actions.client.ActionMap;
import org.gwt.mosaic.actions.client.CommandAction;
import org.gwt.mosaic.application.client.Application;
import org.gwt.mosaic.application.client.CmdAction;
import org.gwt.mosaic.application.client.util.ApplicationFramework;
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.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JParameter;
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.client.Command;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;
/**
*
* @author georgopoulos.georgios(at)gmail.com
*
*/
public class ApplicationFrameworkGenerator extends Generator {
protected static class CmdActionDescriptor {
public String name;
public String description;
public String image;
public String enabledProperty;
public String selectedProperty;
public JMethod method;
public JClassType classType;
public CmdActionDescriptor(String name, JMethod method, JClassType classType) {
this.name = name;
this.method = method;
this.classType = classType;
}
}
protected List<CmdActionDescriptor> cmdActionDescriptorList = new ArrayList<CmdActionDescriptor>();
private TreeLogger logger;
private GeneratorContext context;
@Override
public String generate(TreeLogger logger, GeneratorContext context,
String typeName) throws UnableToCompleteException {
this.logger = logger;
this.context = context;
// Get the objects to examine
JClassType classType = null;
try {
classType = context.getTypeOracle().getType(Application.class.getName());
} catch (NotFoundException e) {
logger.log(TreeLogger.ERROR, "Cannot find class "
+ Application.class.getName(), e);
throw new UnableToCompleteException();
}
JClassType[] foundClassTypes = classType.getSubtypes();
if (foundClassTypes != null && foundClassTypes.length > 0) {
for (JClassType t : foundClassTypes) {
if (t.isAbstract()) {
continue;
}
examine(t);
}
if (cmdActionDescriptorList.size() > 0) {
return doGenerate(typeName);
}
}
return null;
}
private String doGenerate(String typeName) throws UnableToCompleteException {
TypeOracle typeOracle = context.getTypeOracle();
try {
JClassType type = typeOracle.getType(typeName);
String packageName = type.getPackage().getName();
String simpleClassName = type.getSimpleSourceName();
String className = simpleClassName + "Initializer";
String qualifiedBeanClassName = packageName + "." + className;
SourceWriter sourceWriter = getSourceWriter(packageName, className, type);
if (sourceWriter == null) {
return qualifiedBeanClassName;
}
sourceWriter.println("@Override");
sourceWriter.println("public void setupActions() {");
sourceWriter.indent();
sourceWriter.println("final ActionMap actionMap = Application.getInstance().getContext().getActionMap();");
sourceWriter.println("CommandAction action;");
for (CmdActionDescriptor descriptor : cmdActionDescriptorList) {
sourceWriter.println("// ============ CmdAction: " + descriptor.name
+ " ============");
sourceWriter.println("{");
sourceWriter.indent();
sourceWriter.println("final "
+ descriptor.classType.getErasedType().getQualifiedSourceName()
+ " application = ("
+ descriptor.classType.getErasedType().getQualifiedSourceName()
+ ") Application.getInstance();");
sourceWriter.println("action = new CommandAction((("
+ descriptor.classType.getErasedType().getQualifiedSourceName()
+ "Constants) application.getContext().getConstants())."
+ descriptor.name + "(), new Command() {");
sourceWriter.indent();
sourceWriter.println("public void execute() {");
sourceWriter.indent();
sourceWriter.println("application." + descriptor.method.getName()
+ "();");
sourceWriter.outdent();
sourceWriter.println("}");
sourceWriter.outdent();
sourceWriter.println("});");
// resource injection
if (descriptor.description != null) {
sourceWriter.println("action.putValue(Action.SHORT_DESCRIPTION, (("
+ descriptor.classType.getErasedType().getQualifiedSourceName()
+ "Constants) application.getContext().getConstants())."
+ descriptor.description + "());");
}
if (descriptor.image != null) {
sourceWriter.println("action.putValue(Action.SMALL_ICON, (("
+ descriptor.classType.getErasedType().getQualifiedSourceName()
+ "ClientBundle) application.getContext().getClientBundle())."
+ descriptor.image + "());");
}
if (descriptor.selectedProperty != null) {
sourceWriter.println("Binding binding = Bindings.createAutoBinding(AutoBinding.UpdateStrategy.READ_WRITE, application, BeanProperty.<"
+ descriptor.classType.getErasedType().getQualifiedSourceName()
+ ", String> create(\""
+ descriptor.selectedProperty
+ "\"), action, BeanProperty.<Action, String> create(\"selected\"));");
sourceWriter.println("binding.bind();");
}
if (descriptor.enabledProperty != null) {
sourceWriter.println("Binding binding = Bindings.createAutoBinding(AutoBinding.UpdateStrategy.READ_WRITE, application, BeanProperty.<"
+ descriptor.classType.getErasedType().getQualifiedSourceName()
+ ", String> create(\""
+ descriptor.enabledProperty
+ "\"), action, BeanProperty.<Action, String> create(\"enabled\"));");
sourceWriter.println("binding.bind();");
}
sourceWriter.println("actionMap.put(\"" + descriptor.name
+ "\", action);");
sourceWriter.outdent();
sourceWriter.println("}");
}
sourceWriter.outdent();
sourceWriter.println("}");
sourceWriter.commit(logger);
return qualifiedBeanClassName;
} catch (Exception e) {
logger.log(TreeLogger.ERROR, "Unable to generate code for " + typeName, e);
throw new UnableToCompleteException();
}
}
protected SourceWriter getSourceWriter(String packageName, String className,
JClassType superType) {
PrintWriter printWriter = context.tryCreate(logger, packageName, className);
if (printWriter == null) {
return null;
}
ClassSourceFileComposerFactory composerFactory = new ClassSourceFileComposerFactory(
packageName, className);
composerFactory.addImport(ApplicationFramework.class.getName());
composerFactory.addImport(Application.class.getName());
composerFactory.addImport(Action.class.getName());
composerFactory.addImport(ActionMap.class.getName());
composerFactory.addImport(CommandAction.class.getName());
composerFactory.addImport(Command.class.getName());
composerFactory.addImport(Window.class.getName());
composerFactory.addImport(Binding.class.getName());
composerFactory.addImport(Bindings.class.getName());
composerFactory.addImport(BeanProperty.class.getName());
composerFactory.addImport(AutoBinding.class.getName());
composerFactory.setSuperclass(ApplicationFramework.class.getName());
return composerFactory.createSourceWriter(context, printWriter);
}
protected void examine(JClassType t) {
logger.log(TreeLogger.INFO, "Examining " + t.getQualifiedSourceName());
lookupForCmdActionAnnotations(t);
logger.log(TreeLogger.INFO, t.getQualifiedSourceName() + " done");
}
protected boolean isActionMethod(JMethod method) {
if (!method.isPublic() || !method.isAnnotationPresent(CmdAction.class)) {
return false;
}
JType returnType = method.getReturnType();
if (returnType == null
|| !"void".equals(returnType.getErasedType().getQualifiedSourceName())) {
return false;
}
JParameter[] parameters = method.getParameters();
if (parameters == null || parameters.length != 0) {
return false;
}
return true;
}
protected List<JMethod> getActionMethods(JClassType type) {
List<JMethod> list = new ArrayList<JMethod>();
JMethod[] methods = type.getOverridableMethods();
if (methods != null) {
for (JMethod method : methods) {
if (isActionMethod(method)) {
list.add(method);
}
}
}
return list;
}
protected void lookupForCmdActionAnnotations(JClassType t) {
List<JMethod> methods = getActionMethods(t);
if (methods != null) {
for (JMethod method : methods) {
CmdActionDescriptor cmdActionDescriptor = new CmdActionDescriptor(
method.getName(), method, t);
CmdAction cmdAction = method.getAnnotation(CmdAction.class);
if (cmdAction.name() != null && cmdAction.name().length() > 0) {
cmdActionDescriptor.name = cmdAction.name();
}
if (cmdAction.description() != null
&& cmdAction.description().length() > 0) {
cmdActionDescriptor.description = cmdAction.description();
}
if (cmdAction.image() != null && cmdAction.image().length() > 0) {
cmdActionDescriptor.image = cmdAction.image();
}
if (cmdAction.enabledProperty() != null
&& cmdAction.enabledProperty().length() > 0) {
cmdActionDescriptor.enabledProperty = cmdAction.enabledProperty();
}
if (cmdAction.selectedProperty() != null
&& cmdAction.selectedProperty().length() > 0) {
cmdActionDescriptor.selectedProperty = cmdAction.selectedProperty();
}
cmdActionDescriptorList.add(cmdActionDescriptor);
}
}
}
}