package ch.unifr.pai.twice.module.rebind;
/*
* Copyright 2013 Oliver Schmid
* 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.
*/
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import ch.unifr.pai.twice.module.client.TWICEAnnotations.Configurable;
import ch.unifr.pai.twice.module.client.TWICEModule;
import ch.unifr.pai.twice.module.client.TWICEModuleInstantiator;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.RunAsyncCallback;
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.JField;
import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
import com.google.gwt.core.ext.typeinfo.NotFoundException;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;
/**
* Generator logic applied at GWT compile time to create the instantiators for modules to establish the lazy loading mechanism
*
* @author Oliver Schmid
*
*/
public class TWICEModuleGenerator extends Generator {
/**
* @param classType
* @return the class type of the actual component widget provided through the generic annotation
*/
private JClassType getGenericClass(JClassType classType) {
JClassType clazz = null;
for (JClassType intf : classType.getImplementedInterfaces()) {
if (intf.getQualifiedSourceName().equals(TWICEModule.class.getName())) {
JClassType[] generics = intf.isParameterized().getTypeArgs();
// The twice module has only one generic
for (JClassType g : generics)
clazz = g;
}
}
return clazz;
}
/*
* (non-Javadoc)
* @see com.google.gwt.core.ext.Generator#generate(com.google.gwt.core.ext.TreeLogger, com.google.gwt.core.ext.GeneratorContext, java.lang.String)
*/
@Override
public String generate(TreeLogger logger, GeneratorContext context, String typeName) throws UnableToCompleteException {
// Build a new class, that implements a "paintScreen" method
JClassType classType;
try {
classType = context.getTypeOracle().getType(typeName);
JClassType genericClass = getGenericClass(classType);
SourceWriter src = getSourceWriter(classType, context, logger);
if (src != null) {
src.println("@Override");
src.println("public " + Map.class.getName() + "<" + String.class.getName() + ", " + Object.class.getName() + "> getConfigurableFields("
+ genericClass.getQualifiedSourceName() + " instance){");
src.println(Map.class.getName() + "<" + String.class.getName() + ", " + Object.class.getName() + "> result = new " + HashMap.class.getName()
+ "<" + String.class.getName() + ", " + Object.class.getName() + ">();");
for (JField f : genericClass.getFields()) {
Configurable c = f.getAnnotation(Configurable.class);
if (c != null && !f.isFinal() && !f.isPrivate() && !f.isProtected()) {
src.println("result.put(\"" + c.value() + "\", instance." + f.getName() + ");");
}
}
src.println("return result;");
src.println("}");
src.println("@Override");
src.println("public void configure(" + Map.class.getName() + "<" + String.class.getName() + ", " + String.class.getName() + "> properties, "
+ genericClass.getQualifiedSourceName() + " instance){");
src.println("for(" + String.class.getName() + " key : properties.keySet()){");
src.println("String value = properties.get(key);");
src.println("if(key==null){");
src.println("}");
for (JField f : genericClass.getFields()) {
Configurable c = f.getAnnotation(Configurable.class);
if (c != null && !f.isFinal() && !f.isPrivate() && !f.isProtected()) {
JPrimitiveType t = f.getType().isPrimitive();
if (t != null) {
src.println("else if(key.equals(\"" + c.value() + "\")){");
switch (t) {
case INT:
src.println("instance." + f.getName() + "=" + Integer.class.getName() + ".parseInt(value);");
break;
case BOOLEAN:
src.println("instance." + f.getName() + "=" + Boolean.class.getName() + ".parseBoolean(value);");
break;
case DOUBLE:
src.println("instance." + f.getName() + "=" + Double.class.getName() + ".parseDouble(value);");
break;
case FLOAT:
src.println("instance." + f.getName() + "=" + Float.class.getName() + ".parseFloat(value);");
break;
case LONG:
src.println("instance." + f.getName() + "=" + Long.class.getName() + ".parseLong(value);");
break;
default:
throw new RuntimeException("The primitive type \"" + t.name() + "\" is not supported for configuration");
}
}
else if (f.getType().getQualifiedSourceName().equals(String.class.getName())) {
src.println("instance." + f.getName() + "=value");
}
else {
throw new RuntimeException("The type \"" + f.getType().getQualifiedSourceName() + "\" is not supported for configuration");
}
src.println("}");
}
}
src.println("}");
src.println("}");
src.println("@Override");
src.println("public " + RunAsyncCallback.class.getName() + " instantiate(final " + AsyncCallback.class.getName() + "<"
+ genericClass.getQualifiedSourceName() + "> callback){");
src.println("return new " + RunAsyncCallback.class.getName() + "(){");
src.println("@Override");
src.println("public void onSuccess(){");
src.println(genericClass.getQualifiedSourceName() + " module = " + GWT.class.getName() + ".create(" + genericClass.getQualifiedSourceName()
+ ".class);");
src.println("//start(module);");
src.println("callback.onSuccess(module);");
src.println("}");
src.println("@Override");
src.println("public void onFailure(" + Throwable.class.getName() + " reason){");
src.println("callback.onFailure(reason);");
src.println("}");
src.println("};");
src.println("}");
src.commit(logger);
}
return typeName + "Impl";
}
catch (NotFoundException e) {
e.printStackTrace();
}
return null;
}
/**
* Define the class to be generated.
*
* @param classType
* @param context
* @param logger
* @return
*/
public SourceWriter getSourceWriter(JClassType classType, GeneratorContext context, TreeLogger logger) {
String packageName = classType.getPackage().getName();
String simpleName = classType.getSimpleSourceName() + "Impl";
ClassSourceFileComposerFactory composer = new ClassSourceFileComposerFactory(packageName, simpleName);
composer.setSuperclass(classType.getName());
composer.addImplementedInterface(TWICEModuleInstantiator.class.getName() + "<" + getGenericClass(classType).getQualifiedSourceName() + ">");
PrintWriter printWriter = context.tryCreate(logger, packageName, simpleName);
if (printWriter == null) {
return null;
}
else {
SourceWriter sw = composer.createSourceWriter(context, printWriter);
return sw;
}
}
}