package fr.lteconsulting.hexa.rebind;
import java.io.PrintWriter;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.ConcurrentHashMap;
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.NotFoundException;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.resources.client.CssResource.ClassName;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;
import fr.lteconsulting.hexa.client.css.annotation.HexaCssExtra;
/**
* Generates a file reporting use of Css classes
*
*/
public class HexaCssGenerator extends Generator
{
// Context and logger for code generation
protected TreeLogger logger = null;
protected GeneratorContext context = null;
TypeOracle typeOracle;
protected String typeName = null;
protected JClassType type = null;
private ConcurrentHashMap<String,String> classMapping = new ConcurrentHashMap<>();
@Override
public String generate( TreeLogger logger, GeneratorContext context, String typeName ) throws UnableToCompleteException
{
this.logger = logger;
this.context = context;
this.typeName = typeName;
if( typeName == null )
return null;
typeOracle = context.getTypeOracle();
try
{
type = typeOracle.getType( typeName );
}
catch( NotFoundException e )
{
e.printStackTrace();
throw new RuntimeException( e );
}
return generate();
}
protected String generate()
{
String generatedClassName = typeName.replaceAll( "\\.", "_" ) + "_HexaCssImpl";
generateClass( generatedClassName );
return type.getPackage().getName() + "." + generatedClassName;
}
private boolean generateClass( String name )
{
String packageName = type.getPackage().getName();
// get print writer that receives the source code
PrintWriter printWriter = null;
printWriter = context.tryCreate( logger, packageName, name );
// print writer if null, source code has ALREADY been generated, return
if( printWriter == null )
return false;
// init composer, set class properties, create source writer
ClassSourceFileComposerFactory composer = new ClassSourceFileComposerFactory( packageName, name );
composer.addImplementedInterface( type.getQualifiedSourceName() );
SourceWriter sourceWriter = composer.createSourceWriter( context, printWriter );
// generate the List<String> getMethods(); method
for( JMethod m : type.getMethods() )
{
String shrinkedName = getMethodSignature( m );
sourceWriter.println( "public String " + m.getName() + "() { return \"" + shrinkedName + "\"; }" );
}
// close generated class
sourceWriter.outdent();
sourceWriter.println( "}" );
// commit generated class
context.commit( logger, printWriter );
// commit compilation artifact
try
{
HexaCssArtifact artifact = new HexaCssArtifact( classMapping );
context.commitArtifact( logger, artifact );
}
catch( UnableToCompleteException e )
{
e.printStackTrace();
}
return true;
}
private String getMethodSignature( JMethod method )
{
String normalName;
ClassName classNameAnnotation = method.getAnnotation( ClassName.class );
if( classNameAnnotation != null )
{
normalName = classNameAnnotation.value();
}
else
{
HexaCssExtra hexaAnnotation = method.getAnnotation( HexaCssExtra.class );
if(hexaAnnotation!=null)
normalName = hexaAnnotation.name();
else
normalName = cssClassPrefix() + method.getName();
}
String shrinkedName = classMapping.get( normalName );
if( shrinkedName == null )
{
shrinkedName = "h" + generateClassSignature( normalName );
classMapping.put( normalName, shrinkedName );
}
return shrinkedName;
}
private String generateClassSignature( String className )
{
try
{
MessageDigest md = MessageDigest.getInstance("SHA1");
md.update( className.getBytes() );
byte[] output = md.digest();
return bytesToHex(output).substring( 0, 6 );
}
catch( NoSuchAlgorithmException e )
{
e.printStackTrace();
return null;
}
}
private static String bytesToHex(byte[] b)
{
char hexDigit[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F' };
StringBuffer buf = new StringBuffer();
for( int j = 0; j < b.length; j++ )
{
buf.append(hexDigit[(b[j] >> 4) & 0x0f]);
buf.append(hexDigit[b[j] & 0x0f]);
}
return buf.toString();
}
private String cssClassPrefix()
{
String res = type.getQualifiedSourceName().replaceAll( "\\.", "-" ).replaceAll( "\\$", "-" ) + "-";
if( res.endsWith( "-Css-" ) )
return res.substring( 0, res.length() - 4 );
return res;
}
}