// names must be preserved.
final String generatedSimpleSourceName = generateSimpleSourceName(sourceType.getName())
+ locale;
// Begin writing the generated source.
final ClassSourceFileComposerFactory f = new ClassSourceFileComposerFactory(
sourceType.getPackage().getName(), generatedSimpleSourceName);
// The generated class needs to be able to determine the module base URL
f.addImport(GWT.class.getName());
f.addImport(ResourcePrototype.class.getName());
// Determine the interface to implement
if (sourceType.isInterface() != null) {
f.addImplementedInterface(sourceType.getQualifiedSourceName());
} else {
// The incoming type wasn't a plain interface, we don't support
// abstract base classes
logger.log(TreeLogger.ERROR, sourceType.getQualifiedSourceName()
+ " is not an interface.", null);
throw new UnableToCompleteException();
}
// All source gets written through this Writer
final PrintWriter out = context.tryCreate(logger,
sourceType.getPackage().getName(), generatedSimpleSourceName);
// Aggregates the field names of the resources for use with
// ResourceBundle.getResources()
List<String> fieldNames = new ArrayList<String>();
// If an implementation already exists, we don't need to do any work
if (out != null) {
// We really use a SourceWriter since it's convenient
final SourceWriter sw = f.createSourceWriter(context, out);
JMethod[] methods = sourceType.getMethods();
Map<Class<? extends ResourceGenerator>, List<JMethod>> resourceGenerators = new HashMap<Class<? extends ResourceGenerator>, List<JMethod>>();
ResourceContext resourceContext = createResourceContext(logger, context,
sourceType, sw);
// First assemble all of the ResourceGenerators that we may need for the
// type
for (JMethod m : methods) {
JClassType returnType = m.getReturnType().isClassOrInterface();
if (returnType == null) {
logger.log(TreeLogger.ERROR, "Cannot implement " + m.getName()
+ ": not a class or interface.", null);
throw new UnableToCompleteException();
}
Class<? extends ResourceGenerator> clazz = findResourceGenerator(
logger, typeOracle, m);
List<JMethod> generatorMethods;
if (resourceGenerators.containsKey(clazz)) {
generatorMethods = resourceGenerators.get(clazz);
} else {
generatorMethods = new ArrayList<JMethod>();
resourceGenerators.put(clazz, generatorMethods);
}
generatorMethods.add(m);
}
// Run the ResourceGenerator code
for (Map.Entry<Class<? extends ResourceGenerator>, List<JMethod>> entry : resourceGenerators.entrySet()) {
Class<? extends ResourceGenerator> generatorClass = entry.getKey();
List<JMethod> generatorMethods = entry.getValue();
// Create the ResourceGenerator
ResourceGenerator rg;
try {
rg = generatorClass.newInstance();
rg.init(logger.branch(TreeLogger.DEBUG,
"Initializing ResourceGenerator", null), resourceContext);
} catch (InstantiationException e) {
logger.log(TreeLogger.ERROR,
"Unable to initialize ResourceGenerator", e);
throw new UnableToCompleteException();
} catch (IllegalAccessException e) {
logger.log(TreeLogger.ERROR,
"Unable to instantiate ResourceGenerator. "
+ "Does it have a public default constructor?", e);
throw new UnableToCompleteException();
}
// Prepare the ResourceGenerator by telling it all methods that it is
// expected to produce.
for (JMethod m : generatorMethods) {
rg.prepare(logger.branch(TreeLogger.DEBUG, "Preparing method "
+ m.getName(), null), m);
}
// Write all field values
rg.writeFields(logger.branch(TreeLogger.DEBUG, "Writing fields", null));
// Create the instance variables in the IRB subclass by calling
// writeAssignment() on the ResourceGenerator
for (JMethod m : generatorMethods) {
// Strip off all but the access modifiers
sw.print(m.getReadableDeclaration(false, true, true, true, true));
sw.println(" {");
sw.indent();
String fieldName = (m.getName() + "_instance").toUpperCase();
fieldNames.add(fieldName);
sw.println("return " + fieldName + ";");
sw.outdent();
sw.println("}");
sw.print("private final "
+ m.getReturnType().getQualifiedSourceName() + " " + fieldName
+ " = ");
rg.writeAssignment(logger.branch(TreeLogger.DEBUG,
"Writing assignment for " + m.getName(), null), m);
sw.println(";");
}
// Finalize the ResourceGenerator
rg.finish(logger.branch(TreeLogger.DEBUG,
"Finishing ResourceGenerator", null));
}
// Complete the IRB contract
sw.println("public ResourcePrototype[] getResources() {");
sw.indent();
sw.println("return new ResourcePrototype[] {");
sw.indent();
for (String fieldName : fieldNames) {
sw.println(fieldName + ",");
}
sw.outdent();
sw.println("};");
sw.outdent();
sw.println("}");
// Allow map-style lookup
sw.println("public native ResourcePrototype "
+ "getResource(String name) /*-{");
sw.indent();
sw.println("switch (name) {");
sw.indent();
for (JMethod m : methods) {
sw.println("case '" + m.getName() + "': return this.@"
+ f.getCreatedClassName() + "::"
+ (m.getName() + "_instance").toUpperCase() + ";");
}
sw.outdent();
sw.println("}");
sw.println("return null;");
sw.outdent();
sw.println("}-*/;");
// Write the generated code to disk
sw.commit(logger);
}
// Return the name of the concrete class
return f.getCreatedClassName();
}