/*
* Smart GWT (GWT for SmartClient)
* Copyright 2008 and beyond, Isomorphic Software, Inc.
*
* Smart GWT is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License version 3
* is published by the Free Software Foundation. Smart GWT is also
* available under typical commercial license terms - see
* http://smartclient.com/license
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package com.smartgwt.rebind;
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.*;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;
import com.smartgwt.client.bean.BeanFactory;
import com.smartgwt.client.widgets.BaseWidget;
import com.smartgwt.client.core.DataClass;
import com.smartgwt.rebind.BeanClass;
import java.io.PrintWriter;
public class MetaBeanFactoryGenerator extends Generator {
public String getSimpleFactoryName (JClassType interfaceType) {
StringBuilder builder = new StringBuilder();
JClassType iterator = interfaceType;
while (iterator != null) {
if (iterator != interfaceType) builder.insert(0, "_");
builder.insert(0, iterator.getSimpleSourceName());
iterator = iterator.getEnclosingType();
}
builder.append("Impl");
return builder.toString();
}
public String getFactoryPackage (JClassType interfaceType) {
return interfaceType.getPackage().getName();
}
public String generate(TreeLogger logger, GeneratorContext context, String typeName) throws UnableToCompleteException {
TypeOracle typeOracle = context.getTypeOracle();
JClassType metaFactoryType = typeOracle.findType(typeName);
final String genPackageName = getFactoryPackage(metaFactoryType);
final String genClassName = getSimpleFactoryName(metaFactoryType);
ClassSourceFileComposerFactory composer = new ClassSourceFileComposerFactory(genPackageName, genClassName);
composer.addImplementedInterface(typeName);
composer.addImport(com.smartgwt.client.bean.BeanFactory.class.getCanonicalName());
PrintWriter printWriter = context.tryCreate(logger, genPackageName, genClassName);
if (printWriter != null) {
SourceWriter sourceWriter = composer.createSourceWriter(context, printWriter);
sourceWriter.println("// This class lovingly generated by " + MetaBeanFactoryGenerator.class.getCanonicalName() + "\n");
StringBuilder functions = new StringBuilder();
// Our constructor ... will be called by GWT.create()
sourceWriter.println(genClassName + " () {");
sourceWriter.indent();
JClassType beanFactoryType = typeOracle.findType(BeanFactory.class.getCanonicalName()).isClass();
JClassType baseWidgetType = typeOracle.findType(BaseWidget.class.getCanonicalName()).isClass();
JClassType dataClassType = typeOracle.findType(DataClass.class.getCanonicalName()).isClass();
// Iterate over the methods defined on the interface
for (JMethod method : metaFactoryType.getMethods()) {
if (method.getParameters().length != 0) {
logger.log(Type.ERROR, typeName + "::" + method.getName() + " should have no parameters.");
throw new UnableToCompleteException();
}
JParameterizedType returnType = method.getReturnType().isParameterized();
if (returnType == null) {
logger.log(Type.ERROR, typeName + "::" + method.getName() + " has a non-parameterized return type.");
throw new UnableToCompleteException();
}
if (returnType.getBaseType() != beanFactoryType) {
logger.log(Type.ERROR, typeName + "::" + method.getName() + " does not have BeanFactory<> as its return type.");
throw new UnableToCompleteException();
}
JClassType[] typeArgs = returnType.getTypeArgs();
if (typeArgs.length != 1) {
logger.log(Type.ERROR, typeName + "::" + method.getName() + " should have a return type with one parameterized type.");
throw new UnableToCompleteException();
}
JClassType beanClassType = typeArgs[0];
if (
!baseWidgetType.isAssignableFrom(beanClassType) &&
!dataClassType.isAssignableFrom(beanClassType)
) {
logger.log(Type.ERROR, typeName + "::" + method.getName() + ": for now, factories can only be created for Canvas or DataClass and subclasses.");
throw new UnableToCompleteException();
}
BeanClass beanClass = new BeanClass(beanClassType);
beanClass.generateFactory(logger, context);
// We have to instantiate the factory to register it in the BeanFactory static API
sourceWriter.println(beanClass.getQualifiedFactoryName() + ".create(false);");
// And we'll need to generate the function!
functions.append(
"\n\n@Override public BeanFactory<" +
beanClassType.getQualifiedSourceName() +
"> " + method.getName() + "() {\n " +
"return (BeanFactory<" +
beanClassType.getQualifiedSourceName() +
">) BeanFactory.getFactory(" +
beanClassType.getQualifiedSourceName() +
".class);\n}"
);
}
sourceWriter.outdent();
sourceWriter.println("}");
sourceWriter.println(functions.toString());
sourceWriter.commit(logger);
}
return composer.getCreatedClassName();
}
}