package org.jvnet.jaxb2_commons.plugin.inheritance;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import javax.xml.namespace.QName;
import org.jvnet.jaxb2_commons.plugin.AbstractParameterizablePlugin;
import org.jvnet.jaxb2_commons.plugin.inheritance.util.JavaTypeParser;
import org.jvnet.jaxb2_commons.util.CustomizationUtils;
import org.xml.sax.ErrorHandler;
import com.sun.codemodel.JClass;
import com.sun.codemodel.JCodeModel;
import com.sun.codemodel.JDefinedClass;
import com.sun.tools.xjc.Options;
import com.sun.tools.xjc.model.CClassInfo;
import com.sun.tools.xjc.model.CClassRef;
import com.sun.tools.xjc.model.CCustomizations;
import com.sun.tools.xjc.model.CElementInfo;
import com.sun.tools.xjc.model.CPluginCustomization;
import com.sun.tools.xjc.model.Model;
import com.sun.tools.xjc.outline.ClassOutline;
import com.sun.tools.xjc.outline.ElementOutline;
import com.sun.tools.xjc.outline.EnumOutline;
import com.sun.tools.xjc.outline.Outline;
import com.sun.tools.xjc.outline.PackageOutline;
import com.sun.tools.xjc.reader.xmlschema.bindinfo.BIEnum;
public class InheritancePlugin extends AbstractParameterizablePlugin {
@Override
public String getOptionName() {
return "Xinheritance";
}
@Override
public String getUsage() {
return "TBD";
}
@Override
public Collection<QName> getCustomizationElementNames() {
return Arrays.asList(Customizations.EXTENDS_ELEMENT_NAME,
Customizations.IMPLEMENTS_ELEMENT_NAME,
Customizations.OBJECT_FACTORY_ELEMENT_NAME);
}
@Override
public boolean run(Outline outline, Options opt, ErrorHandler errorHandler) {
final Map<String, JClass> knownClasses = new HashMap<String, JClass>();
final Map<JClass, CClassInfo> knownClassInfos = new IdentityHashMap<JClass, CClassInfo>();
for (final ClassOutline classOutline : outline.getClasses()) {
knownClasses.put(classOutline.implClass.fullName(),
classOutline.implClass);
knownClassInfos.put(classOutline.implClass, classOutline.target);
}
for (final ClassOutline classOutline : outline.getClasses()) {
processClassOutline(classOutline, knownClasses, knownClassInfos);
}
for (final EnumOutline enumOutline : outline.getEnums()) {
processEnumOutline(enumOutline, knownClasses);
}
for (final CElementInfo elementInfo : outline.getModel()
.getAllElements()) {
final ElementOutline elementOutline = outline
.getElement(elementInfo);
if (elementOutline != null) {
processElementOutline(elementOutline, knownClasses);
}
}
processPackageOutlines(outline, knownClasses);
return true;
}
private void processClassOutline(ClassOutline classOutline,
Map<String, JClass> knownClasses,
Map<JClass, CClassInfo> knownClassInfos) {
generateExtends(classOutline, knownClasses, knownClassInfos);
generateImplements(classOutline, knownClasses);
}
private void processEnumOutline(EnumOutline enumOutline,
Map<String, JClass> knownClasses) {
generateExtends(enumOutline, knownClasses);
generateImplements(enumOutline, knownClasses);
}
private void processElementOutline(ElementOutline elementOutline,
Map<String, JClass> knownClasses) {
generateExtends(elementOutline, knownClasses);
generateImplements(elementOutline, knownClasses);
}
private void processPackageOutlines(Outline outline,
Map<String, JClass> knownClasses) {
List<CPluginCustomization> customizations = CustomizationUtils
.findCustomizations(outline,
Customizations.OBJECT_FACTORY_ELEMENT_NAME);
for (CPluginCustomization customization : customizations) {
final ObjectFactoryCustomization objectFactoryCustomization = (ObjectFactoryCustomization) CustomizationUtils
.unmarshall(Customizations.getContext(), customization);
final String packageName = objectFactoryCustomization
.getPackageName();
if (packageName != null) {
for (PackageOutline packageOutline : outline
.getAllPackageContexts()) {
final JDefinedClass theClass = packageOutline
.objectFactory();
if (packageName.equals(packageOutline._package().name())) {
ExtendsClass extendsClass = objectFactoryCustomization
.getExtendsClass();
if (extendsClass != null) {
generateExtends(theClass, extendsClass,
knownClasses);
}
List<ImplementsInterface> implementsInterfaces = objectFactoryCustomization
.getImplementsInterface();
if (implementsInterfaces != null) {
for (ImplementsInterface implementsInterface : implementsInterfaces) {
if (implementsInterface != null) {
generateImplements(theClass,
implementsInterface, knownClasses);
}
}
}
}
}
}
}
}
private JClass generateExtends(ClassOutline classOutline,
Map<String, JClass> knownClasses,
Map<JClass, CClassInfo> knownClassInfos) {
final JDefinedClass theClass = classOutline.implClass;
final CPluginCustomization extendsClassCustomization = CustomizationUtils
.findCustomization(classOutline,
Customizations.EXTENDS_ELEMENT_NAME);
JClass targetClass = generateExtends(theClass,
extendsClassCustomization, knownClasses);
final CClassInfo classInfo = classOutline.target;
if (targetClass != null && classInfo.getBaseClass() == null
&& classInfo.getRefBaseClass() == null) {
final CClassInfo targetClassInfo = knownClassInfos.get(targetClass);
if (targetClassInfo == null && classInfo.getRefBaseClass() == null) {
final Model model = classInfo.model;
// BIEnum as BIClass is protected too much
final BIEnum decl = new BIEnum();
decl.ref = targetClass.fullName();
final CClassRef baseClass = new CClassRef(model,
classInfo.getSchemaComponent(), decl,
new CCustomizations());
classInfo.setBaseClass(baseClass);
} else if (targetClassInfo != null
&& classInfo.getBaseClass() == null) {
classInfo.setBaseClass(targetClassInfo);
}
}
return targetClass;
}
private JClass generateExtends(EnumOutline enumOutline,
Map<String, JClass> knownClasses) {
final JDefinedClass theClass = enumOutline.clazz;
final CPluginCustomization extendsClassCustomization = CustomizationUtils
.findCustomization(enumOutline,
Customizations.EXTENDS_ELEMENT_NAME);
return generateExtends(theClass, extendsClassCustomization,
knownClasses);
}
private JClass generateExtends(ElementOutline elementOutline,
Map<String, JClass> knownClasses) {
final JDefinedClass theClass = elementOutline.implClass;
final CPluginCustomization extendsClassCustomization = CustomizationUtils
.findCustomization(elementOutline,
Customizations.EXTENDS_ELEMENT_NAME);
return generateExtends(theClass, extendsClassCustomization,
knownClasses);
}
private JClass generateExtends(final JDefinedClass theClass,
final CPluginCustomization extendsClassCustomization,
Map<String, JClass> knownClasses) throws AssertionError {
if (extendsClassCustomization != null) {
final ExtendsClass extendsClass = (ExtendsClass) CustomizationUtils
.unmarshall(Customizations.getContext(),
extendsClassCustomization);
return generateExtends(theClass, extendsClass, knownClasses);
} else {
return null;
}
}
private JClass generateExtends(final JDefinedClass theClass,
final ExtendsClass extendsClass, Map<String, JClass> knownClasses) {
if (extendsClass.getClassName() != null) {
final String _class = extendsClass.getClassName();
final JClass targetClass = parseClass(_class, theClass.owner(),
knownClasses);
theClass._extends(targetClass);
return targetClass;
} else {
return null;
}
}
private List<JClass> generateImplements(ClassOutline classOutline,
Map<String, JClass> knownClasses) {
final JDefinedClass theClass = classOutline.implClass;
final List<CPluginCustomization> implementsInterfaceCustomizations = CustomizationUtils
.findCustomizations(classOutline,
Customizations.IMPLEMENTS_ELEMENT_NAME);
return generateImplements(theClass, implementsInterfaceCustomizations,
knownClasses);
}
private List<JClass> generateImplements(EnumOutline enumOutline,
Map<String, JClass> knownClasses) {
final JDefinedClass theClass = enumOutline.clazz;
final List<CPluginCustomization> implementsInterfaceCustomizations = CustomizationUtils
.findCustomizations(enumOutline,
Customizations.IMPLEMENTS_ELEMENT_NAME);
return generateImplements(theClass, implementsInterfaceCustomizations,
knownClasses);
}
private List<JClass> generateImplements(ElementOutline elementOutline,
Map<String, JClass> knownClasses) {
final JDefinedClass theClass = elementOutline.implClass;
final List<CPluginCustomization> implementsInterfaceCustomizations = CustomizationUtils
.findCustomizations(elementOutline,
Customizations.IMPLEMENTS_ELEMENT_NAME);
return generateImplements(theClass, implementsInterfaceCustomizations,
knownClasses);
}
private List<JClass> generateImplements(final JDefinedClass theClass,
final List<CPluginCustomization> implementsInterfaceCustomizations,
Map<String, JClass> knownClasses) throws AssertionError {
final List<JClass> implementedInterfaces = new ArrayList<JClass>(
implementsInterfaceCustomizations.size());
for (final CPluginCustomization implementsInterfaceCustomization : implementsInterfaceCustomizations) {
if (implementsInterfaceCustomization != null) {
final ImplementsInterface implementsInterface = (ImplementsInterface) org.jvnet.jaxb2_commons.util.CustomizationUtils
.unmarshall(Customizations.getContext(),
implementsInterfaceCustomization);
final JClass implementedInterface = generateImplements(
theClass, implementsInterface, knownClasses);
if (implementedInterface != null) {
implementedInterfaces.add(implementedInterface);
}
}
}
return implementedInterfaces;
}
private JClass generateImplements(final JDefinedClass theClass,
final ImplementsInterface implementsInterface,
Map<String, JClass> knownClasses) {
String _interface = implementsInterface.getInterfaceName();
if (_interface != null) {
final JClass targetClass = parseClass(_interface, theClass.owner(),
knownClasses);
theClass._implements(targetClass);
return targetClass;
} else {
return null;
}
}
private JClass parseClass(String _class, JCodeModel codeModel,
Map<String, JClass> knownClasses) {
return new JavaTypeParser(knownClasses).parseClass(_class, codeModel);
}
}