* and if so, we can skip further execution and return immediately.
*/
if (checkPropertyCacheability(logger, generatorContext)
&& checkSourceTypeCacheability(generatorContext)
&& checkDependentResourceCacheability(logger, generatorContext, null)) {
return new RebindResult(RebindStatus.USE_ALL_CACHED, typeName);
}
// The TypeOracle knows about all types in the type system
TypeOracle typeOracle = generatorContext.getTypeOracle();
// Get a reference to the type that the generator should implement
JClassType sourceType = typeOracle.findType(typeName);
// Ensure that the requested type exists
if (sourceType == null) {
logger.log(TreeLogger.ERROR, "Could not find requested typeName");
throw new UnableToCompleteException();
} else if (sourceType.isInterface() == null) {
// 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();
}
/*
* This associates the methods to implement with the ResourceGenerator class
* that will generate the implementations of those methods.
*/
Map<Class<? extends ResourceGenerator>, List<JMethod>> taskList = createTaskList(
logger, typeOracle, sourceType);
/*
* Check the resource generators associated with our taskList, and see if
* they all support generator result caching.
*/
boolean canBeCacheable = checkResourceGeneratorCacheability(
generatorContext, taskList);
/*
* Additional objects that hold state during the generation process.
*/
AbstractResourceContext resourceContext = createResourceContext(logger,
generatorContext, sourceType);
FieldsImpl fields = new FieldsImpl();
RequirementsImpl requirements = new RequirementsImpl(
generatorContext.getPropertyOracle(), canBeCacheable);
resourceContext.setRequirements(requirements);
doAddFieldsAndRequirements(logger, generatorContext, fields, requirements);
/*
* Add our source type (and it's supertypes) as a requirement. Note further
* types may be added during the processing of the taskList.
*/
requirements.addTypeHierarchy(sourceType);
/*
* Initialize the ResourceGenerators and prepare them for subsequent code
* generation.
*/
Map<ResourceGenerator, List<JMethod>> generators = initAndPrepare(logger,
taskList, resourceContext, requirements);
/*
* Now that the ResourceGenerators have been initialized and prepared, we
* can compute the actual name of the implementation class in order to
* ensure that we use a distinct name between permutations.
*/
String generatedSimpleSourceName = generateSimpleSourceName(logger,
resourceContext, requirements);
String packageName = sourceType.getPackage().getName();
String createdClassName = packageName + "." + generatedSimpleSourceName;
PrintWriter out = generatorContext.tryCreate(logger, packageName,
generatedSimpleSourceName);
// If an implementation already exists, we don't need to do any work
if (out != null) {
// There is actual work to do
doCreateBundleForPermutation(logger, generatorContext, fields,
generatedSimpleSourceName);
// Begin writing the generated source.
ClassSourceFileComposerFactory f = new ClassSourceFileComposerFactory(
packageName, generatedSimpleSourceName);
// The generated class needs to be able to determine the module base URL
f.addImport(GWT.class.getName());
// Used by the map methods
f.addImport(ResourcePrototype.class.getName());
// The whole point of this exercise
f.addImplementedInterface(sourceType.getQualifiedSourceName());
// All source gets written through this Writer
SourceWriter sw = f.createSourceWriter(generatorContext, out);
// Set the now-calculated simple source name
resourceContext.setSimpleSourceName(generatedSimpleSourceName);
JParameterizedType hashMapStringResource = getHashMapStringResource(typeOracle);
String resourceMapField = fields.define(hashMapStringResource, "resourceMap");
// Write a static instance for use by the static initializers.
sw.print("private static " + generatedSimpleSourceName + " ");
sw.println(INSTANCE_NAME + " = new " + generatedSimpleSourceName + "();");
// Write the generated code to disk
createFieldsAndAssignments(logger, sw, generators, resourceContext,
fields);
// Print the accumulated field definitions
sw.println(fields.getCode());
/*
* The map-accessor methods use JSNI and need a fully-qualified class
* name, but should not include any sub-bundles.
*/
taskList.remove(BundleResourceGenerator.class);
writeMapMethods(sw, taskList, hashMapStringResource, resourceMapField);
sw.commit(logger);
}
finish(logger, resourceContext, generators.keySet());
doFinish(logger);
if (canBeCacheable) {
// remember the current set of required properties, and their values
CachedPropertyInformation cpi = new CachedPropertyInformation(logger,
generatorContext.getPropertyOracle(),
requirements.getPermutationAxes(),
requirements.getConfigurationPropertyNames());
// remember the type signatures for required source types
Map<String, String> cti = requirements.getTypeSignatures();
// remember the required resources
Map<String, URL> cri = requirements.getResolvedResources();
// create data map to be returned the next time the generator is run
CachedClientDataMap data = new CachedClientDataMap();
data.put(CACHED_PROPERTY_INFORMATION, cpi);
data.put(CACHED_RESOURCE_INFORMATION, cri);
data.put(CACHED_TYPE_INFORMATION, cti);
// Return a new cacheable result
return new RebindResult(RebindStatus.USE_ALL_NEW, createdClassName, data);
} else {
// If we can't be cacheable, don't return a cacheable result
return new RebindResult(RebindStatus.USE_ALL_NEW_WITH_NO_CACHING,
createdClassName);
}
}