package com.asayama.gwt.angular.rebind;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.asayama.gwt.angular.client.Angular.SupportedRootClass;
import com.asayama.gwt.angular.client.Injector;
import com.asayama.gwt.rebind.JMethodUtils;
import com.asayama.gwt.rebind.exceptions.RebindException;
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.JField;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JType;
abstract class AbstractFactoryGenerator extends AbstractGenerator {
private static final String CLASS = AbstractFactoryGenerator.class.getName();
private static final Logger LOG = Logger.getLogger(CLASS);
@Override
public String generate(TreeLogger logger, GeneratorContext context, String qualifiedClassName) throws UnableToCompleteException {
JClassType classType = getClassType(context, qualifiedClassName);
String packageName = classType.getPackage().getName();
String className = classType.getSimpleSourceName();
JClassType supportedRootClassType = getSupportedRootClassType(context, classType);
List<JClassType> supportedClassTypes = getSupportedClassTypes(supportedRootClassType);
VelocityGenerator velocity = new VelocityGenerator(getFilename());
velocity.put("classType", classType);
velocity.put("packageName", packageName);
velocity.put("className", className);
velocity.put("supportedRootClassType", supportedRootClassType.getQualifiedSourceName());
velocity.put("supportedClassTypes", supportedClassTypes);
velocity.put("JMethodUtils", JMethodUtils.class);
ClassTypeFields classTypeFields = new ClassTypeFields();
for (JClassType supportedClassType : supportedClassTypes) {
List<Field> fieldList = new ArrayList<Field>();
for (JClassType supportedSuperClassType : supportedClassType.getFlattenedSupertypeHierarchy()) {
JField[] fields = supportedSuperClassType.getFields();
if (fields == null) {
continue;
}
for (JField field : fields) {
String cname = supportedSuperClassType.getQualifiedSourceName();
String dependency = null;
Injector.Inject inject = field.getAnnotation(Injector.Inject.class);
if (inject != null) {
dependency = inject.value();
if (dependency == null || dependency.length() == 0) {
Injector.Bind bind = field.getType().isClass().getAnnotation(Injector.Bind.class);
dependency = bind == null ? null : bind.value();
if (dependency == null || dependency.length() == 0) {
dependency = field.getType().getQualifiedSourceName();
}
}
}
String name = field.getName();
fieldList.add(new Field(field, cname, dependency, name));
}
}
classTypeFields.put(supportedClassType, fieldList);
}
velocity.put("classTypeFields", classTypeFields);
return generate(logger, context, velocity, packageName, className);
}
protected JClassType getSupportedRootClassType(GeneratorContext context, JClassType classType) {
final String METHOD = "getSupportedRootClassType(JClassType)";
JClassType supportedRootClassType = null;
SupportedRootClass a = classType.getAnnotation(SupportedRootClass.class);
Class<?> supportedRootClass = a == null ? null : a.value();
supportedRootClassType = supportedRootClass == null ? null
: getClassType(context, supportedRootClass.getName());
if (supportedRootClassType == null) {
LOG.logp(Level.WARNING, CLASS, METHOD, classType.getName()
+ " does not provide SupportedRootClass annotation. Falling"
+ " back to the legacy convention, which is deprecated as"
+ " of 0.0.69. This feature may be remved in future without"
+ " releases without further notice.");
//++ start of legacy code
// #88 the new annotation drive code to replace this section
JMethod[] methods = classType.getInheritableMethods();
for (JMethod method : methods) {
JType[] parameterTypes = method.getParameterTypes();
if (parameterTypes == null || parameterTypes.length == 0) {
continue;
}
supportedRootClassType = parameterTypes[0].isClassOrInterface();
if (supportedRootClassType != null) {
break;
}
}
//-- end of legacy code
}
if (supportedRootClassType == null) {
String m = "Unable to find the supportedRootClassType for " + classType;
LOG.logp(Level.SEVERE, CLASS, METHOD, m);
throw new RebindException(m);
}
return supportedRootClassType;
}
protected List<JClassType> getSupportedClassTypes(JClassType supportedRootClassType) {
final String METHOD = "getSupportedClassTypes(JClassType)";
JClassType[] supportedSubClassTypes = supportedRootClassType.getSubtypes();
List<JClassType> supportedClassTypes = new ArrayList<JClassType>();
if (supportedSubClassTypes != null) {
for (JClassType returnClassType : supportedSubClassTypes) {
if (returnClassType.isDefaultInstantiable()) {
supportedClassTypes.add(returnClassType);
}
}
}
if (supportedClassTypes.size() == 0) {
String m = "Unable to find supportedClassTypes for " + supportedRootClassType;
LOG.logp(Level.INFO, CLASS, METHOD, m);
}
return supportedClassTypes;
}
}