package fr.lteconsulting.hexa.rebind;
import java.io.PrintWriter;
import java.util.HashMap;
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.JGenericType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JParameter;
import com.google.gwt.core.ext.typeinfo.JParameterizedType;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.JTypeParameter;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;
import fr.lteconsulting.hexa.client.comm.CustomMethod;
import fr.lteconsulting.hexa.client.comm.FieldName;
public class DataProxyGenerator extends Generator
{
private String genMethodPrototype( JMethod method )
{
StringBuilder sb = new StringBuilder();
sb.append( "public " + method.getReturnType().getParameterizedQualifiedSourceName() + " " + method.getName() + "( " );
for( int i = 0; i < method.getParameters().length; i++ )
{
JParameter param = method.getParameters()[i];
sb.append( param.getType().getParameterizedQualifiedSourceName() + " " + param.getName() );
if( i < method.getParameters().length - 1 )
sb.append( ", " );
}
sb.append( " )" );
return sb.toString();
}
// HexaDate fields
HashMap<String, String> hexaDateFields = new HashMap<String, String>();
String registerHexaDateVariable( String fieldName )
{
String variableName = hexaDateFields.get( fieldName );
if( variableName == null )
{
variableName = "hexaDate_" + hexaDateFields.size();
hexaDateFields.put( fieldName, variableName );
}
return variableName;
}
void generateHexaDateVariables( SourceWriter sw )
{
for( String variableName : hexaDateFields.values() )
sw.println( "HexaDate " + variableName + " = null;" );
}
// HexaTime fields
HashMap<String, String> hexaTimeFields = new HashMap<String, String>();
String registerHexaTimeVariable( String fieldName )
{
String variableName = hexaTimeFields.get( fieldName );
if( variableName == null )
{
variableName = "hexaTime_" + hexaTimeFields.size();
hexaTimeFields.put( fieldName, variableName );
}
return variableName;
}
void generateHexaTimeVariables( SourceWriter sw )
{
for( String variableName : hexaTimeFields.values() )
sw.println( "HexaTime " + variableName + " = null;" );
}
// HexaDateTime fields
HashMap<String, String> hexaDateTimeFields = new HashMap<String, String>();
String registerHexaDateTimeVariable( String fieldName )
{
String variableName = hexaDateTimeFields.get( fieldName );
if( variableName == null )
{
variableName = "hexaDateTime_" + hexaDateTimeFields.size();
hexaDateTimeFields.put( fieldName, variableName );
}
return variableName;
}
void generateHexaDateTimeVariables( SourceWriter sw )
{
for( String variableName : hexaDateTimeFields.values() )
sw.println( "HexaDateTime " + variableName + " = null;" );
}
@Override
public String generate( TreeLogger logger, GeneratorContext context, String requestedClass ) throws UnableToCompleteException
{
logger.log( TreeLogger.INFO, "Generate '" + requestedClass, null );
TypeOracle typeOracle = context.getTypeOracle();
JClassType requestedType = typeOracle.findType( requestedClass );
if( requestedType == null )
{
logger.log( TreeLogger.ERROR, "Type '" + requestedClass + "' has not been found by the Oracle", null );
throw new UnableToCompleteException();
}
String className = requestedType.getName() + "Impl";
String fullClassName = requestedClass + "Impl";
String packageName = requestedType.getPackage().getName();
PrintWriter printWriter = context.tryCreate( logger, packageName, className );
if( printWriter == null )
{
logger.log( TreeLogger.DEBUG, requestedClass + " : CANNOT CREATE PRINT WRITER", null );
return fullClassName;
}
// Get type parameters informations so that we generate a fitting class
String parameterizedTypeExt = "";
String typeExt = "";
JGenericType genericType = requestedType.isGenericType();
if( genericType != null )
{
parameterizedTypeExt = "<";
typeExt = "<";
JTypeParameter[] tps = genericType.getTypeParameters();
boolean needComa = false;
for( int i = 0; i < tps.length; i++ )
{
if( needComa )
{
parameterizedTypeExt += ", ";
typeExt += ", ";
}
needComa = true;
JTypeParameter tp = tps[i];
parameterizedTypeExt += tp.getName() + " extends ";
typeExt += tp.getName();
JClassType[] cts = tp.getBounds();
boolean needAnd = false;
for( int j = 0; j < cts.length; j++ )
{
if( needAnd )
parameterizedTypeExt += " & ";
needAnd = true;
JClassType ct = cts[j];
parameterizedTypeExt += ct.getName();
}
}
parameterizedTypeExt += ">";
typeExt += ">";
}
ClassSourceFileComposerFactory composerFactory = new ClassSourceFileComposerFactory( packageName, className + parameterizedTypeExt );
composerFactory.addImport( "com.google.gwt.core.client.GWT" );
composerFactory.addImport( "fr.lteconsulting.hexa.client.comm.DataProxy" );
composerFactory.addImport( "fr.lteconsulting.hexa.client.comm.GenericJSO" );
composerFactory.addImport( "fr.lteconsulting.hexa.client.comm.ResponseJSO" );
composerFactory.addImport( "java.util.ArrayList" );
composerFactory.addImport( "com.google.gwt.core.client.JsArray" );
composerFactory.addImport( "fr.lteconsulting.hexa.client.common.HexaDate" );
composerFactory.addImport( "fr.lteconsulting.hexa.client.common.HexaTime" );
composerFactory.addImport( "fr.lteconsulting.hexa.client.common.HexaDateTime" );
composerFactory.addImport( "com.google.gwt.core.client.JavaScriptObject" );
composerFactory.addImport( "com.google.gwt.json.client.JSONObject" );
composerFactory.addImplementedInterface( requestedClass + typeExt );
SourceWriter sw = composerFactory.createSourceWriter( context, printWriter );
if( sw == null )
{
// logger.log( TreeLogger.WARN, requestedClass +
// " : CANNOT CREATE SOURCEWRITER", null );
return fullClassName; // null, already generated
}
sw.println( "private GenericJSO jso = null;" );
JMethod[] methods = requestedType.getMethods();
sw.println( "@Override public String toString() {" );
sw.indent();
sw.println( "return new JSONObject(jso).toString();" );
sw.outdent();
sw.println( "}" );
sw.println( "public void init( GenericJSO jso ) {" );
sw.indent();
sw.println( "this.jso = jso;" );
sw.outdent();
sw.println( "}" );
for( JMethod method : methods )
{
FieldName fnAnnotation = method.getAnnotation( FieldName.class );
CustomMethod cmAnnotation = method.getAnnotation( CustomMethod.class );
if( cmAnnotation != null )
{
sw.println( "public " + method.getReturnType().getSimpleSourceName() + " " + method.getName() + "() {" );
sw.indent();
sw.println( cmAnnotation.body() );
sw.outdent();
sw.println( "}" );
}
else if( fnAnnotation != null )
{
String methodPrototype = genMethodPrototype( method );
sw.println( methodPrototype );
sw.println( "{" );
// sw.println( "public " +
// method.getReturnType().getParameterizedQualifiedSourceName()
// + " " + method.getName() + "() {" );
sw.indent();
if( method.getReturnType().getSimpleSourceName().compareTo( "HexaDate" ) == 0 )
{
String variableName = registerHexaDateVariable( fnAnnotation.fieldName() );
sw.println( "if( " + variableName + " == null ) " + variableName + " = new HexaDate( jso.getString( \"" + fnAnnotation.fieldName() + "\" ) );" );
sw.println( "return " + variableName + ";" );
}
else if( method.getReturnType().getSimpleSourceName().compareTo( "HexaTime" ) == 0 )
{
String variableName = registerHexaTimeVariable( fnAnnotation.fieldName() );
sw.println( "if( " + variableName + " == null ) " + variableName + " = new HexaTime( jso.getString( \"" + fnAnnotation.fieldName() + "\" ) );" );
sw.println( "return " + variableName + ";" );
// sw.println( "return new HexaTime( jso.getString( \"" +
// fnAnnotation.fieldName() + "\" ) );" );
}
else if( method.getReturnType().getSimpleSourceName().compareTo( "HexaDateTime" ) == 0 )
{
String variableName = registerHexaDateTimeVariable( fnAnnotation.fieldName() );
sw.println( "if( " + variableName + " == null ) " + variableName + " = new HexaDateTime( jso.getString( \"" + fnAnnotation.fieldName() + "\" ) );" );
sw.println( "return " + variableName + ";" );
// sw.println( "return new HexaDateTime( jso.getString( \""
// + fnAnnotation.fieldName() + "\" ) );" );
}
else if( isJSOType( method.getReturnType() ) )
{
sw.println( "return jso.getGenericJSO( \"" + fnAnnotation.fieldName() + "\" ).cast();" );
}
//else if( !method.getReturnType().getSimpleSourceName().equals( "ArrayList" ) )
else if( ! ( method.getReturnType().getQualifiedSourceName().equals( "java.util.ArrayList" ) || method.getReturnType().getQualifiedSourceName().equals( "java.util.List" ) ) )
{
String jsoType = method.getReturnType().getSimpleSourceName();
if( method.getReturnType().getSimpleSourceName().compareTo( "int" ) == 0 )
jsoType = "Int";
else if( method.getReturnType().getSimpleSourceName().compareTo( "Integer" ) == 0 )
jsoType = "Integer";
else if( method.getReturnType().getSimpleSourceName().compareTo( "boolean" ) == 0 )
jsoType = "Boolean";
else if( method.getReturnType().getSimpleSourceName().compareTo( "double" ) == 0 )
jsoType = "Double";
sw.println( "return jso.get" + jsoType + "( \"" + fnAnnotation.fieldName() + "\" );" );
}
else
{
JParameterizedType ptype = method.getReturnType().isParameterized();
JClassType[] typeArgs = ptype.getTypeArgs();
assert (typeArgs.length == 1);
String type = typeArgs[0].getParameterizedQualifiedSourceName();
String field = fnAnnotation.fieldName();
sw.println( "ArrayList<" + type + "> res = new ArrayList<" + type + ">();" );
sw.println( "JsArray<GenericJSO> jsos = jso.getArray( \"" + field + "\" );" );
sw.println( "for( int i=0; i<jsos.length(); i++ ) {" );
sw.println( " " + type + " elem = GWT.create( " + type + ".class );" );
sw.println( " elem.init( jsos.get(i) );" );
sw.println( " res.add( elem );" );
sw.println( "}" );
sw.println( "return res;" );
}
sw.outdent();
sw.println( "}" );
}
}
generateHexaDateVariables( sw );
generateHexaTimeVariables( sw );
generateHexaDateTimeVariables( sw );
sw.commit( logger );
return fullClassName;
}
boolean isJSOType( JType type )
{
JClassType cType = type.isClass();
if( cType == null )
cType = type.isInterface();
if( cType == null )
return false;
for( JClassType t = cType; t != null; t = t.getSuperclass() )
{
// sw.println( "// supertype : " + t.getSimpleSourceName() );
JTypeParameter typeParam = t.isTypeParameter();
if( typeParam != null )
{
// sw.println( "// which is a type parameter" );
JClassType[] bounds = typeParam.getBounds();
for( int b = 0; b < bounds.length; b++ )
{
// sw.println( "// which is bound to : " +
// bounds[b].getSimpleSourceName() );
if( bounds[b].getSimpleSourceName().compareTo( "JavaScriptObject" ) == 0 )
return true;
}
}
if( t.getSimpleSourceName().compareTo( "JavaScriptObject" ) == 0 )
return true;
}
return false;
}
}