public String generate(TreeLogger logger, GeneratorContext ctx,
String requestedClass) throws UnableToCompleteException {
findBaseTypes(ctx);
TypeOracle oracle = ctx.getTypeOracle();
// Find the requested class
JClassType proxyInterface = oracle.findType(requestedClass);
if (proxyInterface == null) {
logger.log(TreeLogger.ERROR, "Unable to find metadata for type '"
+ requestedClass + "'", null);
throw new UnableToCompleteException();
}
// If it's not an interface it's a custom user-made proxy class. Don't use
// generator.
if (proxyInterface.isInterface() == null) {
return null;
}
ProxyStandard proxyStandardAnnotation = proxyInterface.getAnnotation(ProxyStandard.class);
ProxyCodeSplit proxyCodeSplitAnnotation = proxyInterface.getAnnotation(ProxyCodeSplit.class);
ProxyCodeSplitBundle proxyCodeSplitBundleAnnotation = proxyInterface.getAnnotation(ProxyCodeSplitBundle.class);
int nbNonNullTags = 0;
if (proxyStandardAnnotation != null) {
nbNonNullTags++;
}
if (proxyCodeSplitAnnotation != null) {
nbNonNullTags++;
}
if (proxyCodeSplitBundleAnnotation != null) {
nbNonNullTags++;
}
// If there is no proxy tag, don't use generator.
if (nbNonNullTags == 0) {
return null;
}
// Make sure this proxy lies within a presenter
JClassType presenterClass = proxyInterface.getEnclosingType();
if (presenterClass == null
|| !presenterClass.isAssignableTo(basePresenterClass)) {
logger.log(TreeLogger.ERROR,
"Proxy must be enclosed in a class derived from '"
+ basePresenterClassName + "'", null);
throw new UnableToCompleteException();
}
String presenterClassName = presenterClass.getName();
// Watch out for more than one proxy tag
if (nbNonNullTags > 1) {
logger.log(TreeLogger.ERROR, "Proxy for '" + presenterClassName
+ "' has more than one @Proxy annotation.", null);
throw new UnableToCompleteException();
}
// Find the package, build the generated class name.
JPackage interfacePackage = proxyInterface.getPackage();
String packageName = interfacePackage == null ? ""
: interfacePackage.getName();
String implClassName = presenterClassName
+ proxyInterface.getSimpleSourceName() + "Impl";
String generatedClassName = packageName + "." + implClassName;
// Create the printWriter
PrintWriter printWriter = ctx.tryCreate(logger, packageName, implClassName);
if (printWriter == null) {
// We've already created it, so nothing to do
return generatedClassName;
}
// Find ginjector
String ginjectorClassName = null;
try {
ginjectorClassName = ctx.getPropertyOracle().getConfigurationProperty(
"gin.ginjector").getValues().get(0);
} catch (BadPropertyValueException e) {
logger.log(TreeLogger.ERROR,
"The required configuration property 'gin.ginjector' was not found.",
e);
throw new UnableToCompleteException();
}
JClassType ginjectorClass = oracle.findType(ginjectorClassName);
if (ginjectorClass == null
|| !ginjectorClass.isAssignableTo(baseGinjectorClass)) {
logger.log(TreeLogger.ERROR,
"The configuration property 'gin.ginjector' is '"
+ ginjectorClassName + "' "
+ " which doesn't identify a type inheriting from 'Ginjector'.",
null);
throw new UnableToCompleteException();
}
// Check if this proxy is also a place.
String nameToken = null;
String newPlaceCode = null; // TODO Get rid of this when we remove @PlaceInstance
String getGatekeeperMethod = null;
String title = null;
if (proxyInterface.isAssignableTo(basePlaceClass)) {
NameToken nameTokenAnnotation = proxyInterface.getAnnotation(NameToken.class);
if (nameTokenAnnotation == null) {
logger.log(TreeLogger.ERROR,
"The proxy for '" + presenterClassName
+ "' is a Place, but is not annotated with @' +"
+ NameToken.class.getSimpleName() + ".", null);
throw new UnableToCompleteException();
}
nameToken = nameTokenAnnotation.value();
UseGatekeeper gatekeeperAnnotation = proxyInterface.getAnnotation(UseGatekeeper.class);
if (gatekeeperAnnotation != null) {
String gatekeeperName = gatekeeperAnnotation.value().getCanonicalName();
JClassType customGatekeeperClass = oracle.findType(gatekeeperName);
if (customGatekeeperClass == null) {
logger.log(TreeLogger.ERROR, "The class '" + gatekeeperName
+ "' provided to @" + UseGatekeeper.class.getSimpleName()
+ " can't be found.", null);
throw new UnableToCompleteException();
}
if (!customGatekeeperClass.isAssignableTo(gatekeeperClass)) {
logger.log(TreeLogger.ERROR, "The class '" + gatekeeperName
+ "' provided to @" + UseGatekeeper.class.getSimpleName()
+ " does not inherit from '" + gatekeeperClassName + "'.", null);
throw new UnableToCompleteException();
}
// Find the appropriate get method in the Ginjector
for (JMethod method : ginjectorClass.getMethods()) {
JClassType returnType = method.getReturnType().isClassOrInterface();
if (method.getParameters().length == 0 && returnType != null
&& returnType.isAssignableTo(customGatekeeperClass)) {
getGatekeeperMethod = method.getName();
break;
}
}
if (getGatekeeperMethod == null) {
logger.log(TreeLogger.ERROR,
"The Ginjector '" + ginjectorClassName
+ "' does not have a get() method returning '"
+ gatekeeperName + "'. This is required when using @"
+ UseGatekeeper.class.getSimpleName() + ".", null);
throw new UnableToCompleteException();
}
}
if (getGatekeeperMethod == null && newPlaceCode == null
&& proxyInterface.getAnnotation(NoGatekeeper.class) == null) {
// No Gatekeeper specified, see if there is a DefaultGatekeeper defined
// in the ginjector
for (JMethod method : ginjectorClass.getMethods()) {
if (method.getAnnotation(DefaultGatekeeper.class) != null) {
JClassType returnType = method.getReturnType().isClassOrInterface();
if (getGatekeeperMethod != null) {
logger.log(TreeLogger.ERROR, "The Ginjector '"
+ ginjectorClassName
+ "' has more than one method annotated with @"
+ DefaultGatekeeper.class.getSimpleName()
+ ". This is not allowed.", null);
throw new UnableToCompleteException();
}
if (method.getParameters().length != 0 || returnType == null
|| !returnType.isAssignableTo(gatekeeperClass)) {
logger.log(
TreeLogger.ERROR,
"The method '"
+ method.getName()
+ "' in the Ginjector '"
+ ginjectorClassName
+ "' is annotated with @"
+ DefaultGatekeeper.class.getSimpleName()
+ " but has an invalid signature. It must not take any parameter and must return a class derived from '"
+ gatekeeperClassName + "'.", null);
throw new UnableToCompleteException();
}
getGatekeeperMethod = method.getName();
}
}
}
Title titleAnnotation = proxyInterface.getAnnotation(Title.class);
if (titleAnnotation != null) {
title = titleAnnotation.value();
}
}
TitleFunctionDescription titleFunctionDescription = findTitleFunction(
logger, presenterClass, presenterClassName, ginjectorClassName,
ginjectorClass);
if (titleFunctionDescription != null && title != null) {
logger.log(TreeLogger.ERROR, "The proxy for '" + presenterClassName
+ "' is annotated with @' +" + Title.class.getSimpleName()
+ " and its presenter has a method annotated with @"
+ TitleFunction.class.getSimpleName() + ". This is not supported.",
null);
throw new UnableToCompleteException();
}
// Scan the containing class for @ProxyEvent annotated methods
List<ProxyEventDescription> proxyEvents = findProxyEvents(logger,
presenterClass, presenterClassName, ginjectorClassName, ginjectorClass);
// Check if this proxy is also a TabContentProxy.
JClassType tabContainerClass = null;
String tabContainerClassName = null;
Integer tabPriority = null;
String tabLabel = null;
TabInfoFunctionDescription tabInfoFunctionDescription = null;
String tabNameToken = null;
if (proxyInterface.isAssignableTo(tabContentProxyClass)) {
TabInfo tabInfoAnnotation = proxyInterface.getAnnotation(TabInfo.class);
tabInfoFunctionDescription = findTabInfoFunction(
logger, presenterClass, presenterClassName, ginjectorClassName,
ginjectorClass);
// Ensure @TabInfo is there exactly once
if (tabInfoAnnotation != null && tabInfoFunctionDescription != null) {
logger.log(TreeLogger.ERROR, "Presenter " + presenterClassName
+ " contains both a proxy and a method annotated with @' +"
+ TabInfo.class.getSimpleName() + ". This is illegal.", null);
throw new UnableToCompleteException();
}
if (tabInfoFunctionDescription != null) {
tabInfoAnnotation = tabInfoFunctionDescription.annotation;
}
if (tabInfoAnnotation == null) {
logger.log(TreeLogger.ERROR, "The proxy for '" + presenterClassName
+ "' is a TabContentProxy, but is not annotated with @' +"
+ TabInfo.class.getSimpleName()
+ " and its presenter has no method annotated with it either.", null);
throw new UnableToCompleteException();
}
// Extract the label if its in TabInfo
if (tabInfoAnnotation.label().length() > 0) {
tabLabel = tabInfoAnnotation.label();
}
if (tabLabel != null && tabInfoFunctionDescription != null) {
logger.log(TreeLogger.ERROR, "The @" + TabInfo.class.getSimpleName()
+ " in " + presenterClassName + " defines the 'label' parameter and"
+ " annotates a method, this is not permitted.", null);
throw new UnableToCompleteException();
}
if (tabLabel == null && tabInfoFunctionDescription == null) {
logger.log(TreeLogger.ERROR, "The @" + TabInfo.class.getSimpleName()
+ " in " + presenterClassName + " does not define the 'label' parameter and"
+ " does not annotate a method, this is not permitted.", null);
throw new UnableToCompleteException();
}
// Extract the label if its in TabInfo (it is a negative integer if not set)
if (tabInfoAnnotation.priority() >= 0) {
tabPriority = tabInfoAnnotation.priority();
}
if (tabPriority != null &&
tabInfoFunctionDescription != null && !tabInfoFunctionDescription.returnString) {
logger.log(TreeLogger.ERROR, "The @" + TabInfo.class.getSimpleName()
+ " in " + presenterClassName + " defines the 'priority' parameter and"
+ " annotates a method returning TabData, this is not permitted.", null);
throw new UnableToCompleteException();
}
if (tabPriority == null &&
(tabInfoFunctionDescription == null || tabInfoFunctionDescription.returnString)) {
logger.log(TreeLogger.ERROR, "The @" + TabInfo.class.getSimpleName()
+ " in " + presenterClassName + " does not define the 'priority' parameter and"
+ " does not annotate a method returning TabData, this is not permitted.", null);
throw new UnableToCompleteException();
}
// Find the container
tabContainerClass = oracle.findType(tabInfoAnnotation.container().getCanonicalName());
if (tabContainerClass == null) {
logger.log(TreeLogger.ERROR, "The container '"
+ tabInfoAnnotation.container().getCanonicalName()
+ "' in the proxy annotation for '" + presenterClassName
+ "' was not found.", null);