package org.jvnet.jaxb2_commons.xml.bind.model.concrete; import java.util.ArrayList; import java.util.Collection; import java.util.IdentityHashMap; import java.util.List; import java.util.Map; import java.util.Set; import javax.activation.MimeType; import javax.xml.namespace.QName; import org.jvnet.jaxb2_commons.lang.Validate; import org.jvnet.jaxb2_commons.xml.bind.model.MBuiltinLeafInfo; import org.jvnet.jaxb2_commons.xml.bind.model.MClassInfo; import org.jvnet.jaxb2_commons.xml.bind.model.MClassTypeInfo; import org.jvnet.jaxb2_commons.xml.bind.model.MContainer; import org.jvnet.jaxb2_commons.xml.bind.model.MElementInfo; import org.jvnet.jaxb2_commons.xml.bind.model.MElementTypeInfo; import org.jvnet.jaxb2_commons.xml.bind.model.MEnumLeafInfo; import org.jvnet.jaxb2_commons.xml.bind.model.MModelInfo; import org.jvnet.jaxb2_commons.xml.bind.model.MPackageInfo; import org.jvnet.jaxb2_commons.xml.bind.model.MPropertyInfo; import org.jvnet.jaxb2_commons.xml.bind.model.MTypeInfo; import org.jvnet.jaxb2_commons.xml.bind.model.concrete.origin.CMAnyAttributePropertyInfoOrigin; import org.jvnet.jaxb2_commons.xml.bind.model.concrete.origin.CMBuiltinLeafInfoOrigin; import org.jvnet.jaxb2_commons.xml.bind.model.concrete.origin.CMClassInfoOrigin; import org.jvnet.jaxb2_commons.xml.bind.model.concrete.origin.CMElementInfoOrigin; import org.jvnet.jaxb2_commons.xml.bind.model.concrete.origin.CMEnumConstantInfoOrigin; import org.jvnet.jaxb2_commons.xml.bind.model.concrete.origin.CMEnumLeafInfoOrigin; import org.jvnet.jaxb2_commons.xml.bind.model.concrete.origin.CMModelInfoOrigin; import org.jvnet.jaxb2_commons.xml.bind.model.concrete.origin.CMPropertyInfoOrigin; import org.jvnet.jaxb2_commons.xml.bind.model.concrete.origin.CMWildcardTypeInfoOrigin; import org.jvnet.jaxb2_commons.xml.bind.model.origin.MBuiltinLeafInfoOrigin; import org.jvnet.jaxb2_commons.xml.bind.model.origin.MClassInfoOrigin; import org.jvnet.jaxb2_commons.xml.bind.model.origin.MElementInfoOrigin; import org.jvnet.jaxb2_commons.xml.bind.model.origin.MEnumConstantInfoOrigin; import org.jvnet.jaxb2_commons.xml.bind.model.origin.MEnumLeafInfoOrigin; import org.jvnet.jaxb2_commons.xml.bind.model.origin.MModelInfoOrigin; import org.jvnet.jaxb2_commons.xml.bind.model.origin.MPropertyInfoOrigin; import org.jvnet.jaxb2_commons.xml.bind.model.origin.MWildcardTypeInfoOrigin; import com.sun.xml.bind.v2.model.core.Adapter; import com.sun.xml.bind.v2.model.core.AttributePropertyInfo; import com.sun.xml.bind.v2.model.core.BuiltinLeafInfo; import com.sun.xml.bind.v2.model.core.ClassInfo; import com.sun.xml.bind.v2.model.core.Element; import com.sun.xml.bind.v2.model.core.ElementInfo; import com.sun.xml.bind.v2.model.core.ElementPropertyInfo; import com.sun.xml.bind.v2.model.core.EnumConstant; import com.sun.xml.bind.v2.model.core.EnumLeafInfo; import com.sun.xml.bind.v2.model.core.ID; import com.sun.xml.bind.v2.model.core.MapPropertyInfo; import com.sun.xml.bind.v2.model.core.PropertyInfo; import com.sun.xml.bind.v2.model.core.ReferencePropertyInfo; import com.sun.xml.bind.v2.model.core.TypeInfo; import com.sun.xml.bind.v2.model.core.TypeInfoSet; import com.sun.xml.bind.v2.model.core.TypeRef; import com.sun.xml.bind.v2.model.core.ValuePropertyInfo; import com.sun.xml.bind.v2.model.core.WildcardTypeInfo; public abstract class CMInfoFactory<T, C extends T, TIS extends TypeInfoSet<T, C, ?, ?>, // TI extends TypeInfo<T, C>, // BLI extends BuiltinLeafInfo<T, C>, // EI extends ElementInfo<T, C>, // ELI extends EnumLeafInfo<T, C>, // EC extends EnumConstant<T, C>, // CI extends ClassInfo<T, C>, // PI extends PropertyInfo<T, C>, // API extends AttributePropertyInfo<T, C>, // VPI extends ValuePropertyInfo<T, C>, // EPI extends ElementPropertyInfo<T, C>, // RPI extends ReferencePropertyInfo<T, C>, // WTI extends WildcardTypeInfo<T, C>> { private final Map<BLI, MBuiltinLeafInfo<T, C>> builtinLeafInfos = new IdentityHashMap<BLI, MBuiltinLeafInfo<T, C>>(); private final Map<CI, MClassInfo<T, C>> classInfos = new IdentityHashMap<CI, MClassInfo<T, C>>(); private final Map<ELI, MEnumLeafInfo<T, C>> enumLeafInfos = new IdentityHashMap<ELI, MEnumLeafInfo<T, C>>(); private final Map<EI, MElementInfo<T, C>> elementInfos = new IdentityHashMap<EI, MElementInfo<T, C>>(); private final TIS typeInfoSet; public CMInfoFactory(TIS typeInfoSet) { Validate.notNull(typeInfoSet); this.typeInfoSet = typeInfoSet; } public MModelInfo<T, C> createModel() { final CMModel<T, C> model = new CMModel<T, C>( createModelInfoOrigin(typeInfoSet)); createBuiltinLeafInfos(model); createEnumLeafInfos(model); createClassInfos(model); createElementInfos(model); return model; } private void createElementInfos(final CMModel<T, C> model) { Iterable<? extends ElementInfo<T, C>> elements = typeInfoSet .getAllElements(); for (ElementInfo<T, C> element : elements) { final EI ei = (EI) element; elementInfos.put(ei, createElementInfo(ei)); } for (ElementInfo<T, C> element : elements) { model.addElementInfo(getElementInfo((EI) element)); } } private void createEnumLeafInfos(final CMModel<T, C> model) { Collection<? extends EnumLeafInfo<T, C>> enums = typeInfoSet.enums() .values(); for (EnumLeafInfo<T, C> enumLeafInfo : enums) { @SuppressWarnings("unchecked") final ELI eli = (ELI) enumLeafInfo; enumLeafInfos.put(eli, createEnumLeafInfo(eli)); } for (Map.Entry<ELI, MEnumLeafInfo<T, C>> entry : enumLeafInfos .entrySet()) { populateEnumLeafInfo(entry.getKey(), entry.getValue()); } for (EnumLeafInfo<T, C> enumLeafInfo : enums) { model.addEnumLeafInfo(getTypeInfo((ELI) enumLeafInfo)); } } private void createBuiltinLeafInfos(final CMModel<T, C> model) { Collection<? extends BuiltinLeafInfo<T, C>> builtins = typeInfoSet .builtins().values(); for (BuiltinLeafInfo<T, C> builtinLeafInfo : builtins) { @SuppressWarnings("unchecked") final BLI bli = (BLI) builtinLeafInfo; builtinLeafInfos.put(bli, createBuiltinLeafInfo(bli)); } for (BuiltinLeafInfo<T, C> builtinLeafInfo : builtins) { model.addBuiltinLeafInfo(getTypeInfo((BLI) builtinLeafInfo)); } } private void createClassInfos(final CMModel<T, C> model) { Collection<? extends ClassInfo<T, C>> beans = typeInfoSet.beans() .values(); for (ClassInfo<T, C> classInfo : beans) { @SuppressWarnings("unchecked") final CI ci = (CI) classInfo; classInfos.put(ci, createClassInfo(ci)); } for (Map.Entry<CI, MClassInfo<T, C>> entry : classInfos.entrySet()) { populateClassInfo(entry.getKey(), entry.getValue()); } for (ClassInfo<T, C> classInfo : beans) { model.addClassInfo(getTypeInfo((CI) classInfo)); } } protected MTypeInfo<T, C> getTypeInfo(PropertyInfo<T, C> propertyInfo, TI typeInfo, boolean list, Adapter<T, C> adapter, ID id, MimeType mimeType) { final MTypeInfo<T, C> ti = getTypeInfo(typeInfo); if (list) { switch (id) { case ID: final MTypeInfo<T, C> tid = new CMID<T, C>(ti.getTargetType(), ti); return new CMList<T, C>(createListType(tid.getTargetType()), tid); case IDREF: return new CMIDREFS<T, C>(createListType(ti.getTargetType()), ti); default: return new CMList<T, C>(createListType(ti.getTargetType()), ti); } } else { switch (id) { case ID: return new CMID<T, C>(ti.getTargetType(), ti); case IDREF: return new CMIDREF<T, C>(ti.getTargetType(), ti); default: return ti; } } } protected MTypeInfo<T, C> getTypeInfo(TI typeInfo) { if (typeInfo instanceof BuiltinLeafInfo) { return getTypeInfo((BLI) typeInfo); } else if (typeInfo instanceof EnumLeafInfo) { return getTypeInfo((ELI) typeInfo); } else if (typeInfo instanceof ElementInfo) { return getTypeInfo((EI) typeInfo); } else if (typeInfo instanceof WildcardTypeInfo) { return createWildcardTypeInfo((WTI) typeInfo); } else if (typeInfo instanceof ClassInfo) { return getTypeInfo((CI) typeInfo); } else { throw new UnsupportedOperationException(typeInfo.getClass() .getName()); } } private MBuiltinLeafInfo<T, C> getTypeInfo(BLI typeInfo) { return builtinLeafInfos.get(typeInfo); } private MTypeInfo<T, C> getTypeInfo(EI info) { @SuppressWarnings("unchecked") EPI p = (EPI) info.getProperty(); @SuppressWarnings("unchecked") TI contentType = (TI) info.getContentType(); return getTypeInfo(p, contentType, p.isValueList(), p.getAdapter(), p.id(), p.getExpectedMimeType()); } protected MClassInfo<T, C> getTypeInfo(CI info) { return classInfos.get(info); } private MEnumLeafInfo<T, C> getTypeInfo(ELI info) { return enumLeafInfos.get(info); } private void populateEnumLeafInfo(ELI info, MEnumLeafInfo<T, C> enumLeafInfo) { @SuppressWarnings("rawtypes") Iterable<? extends EnumConstant> _constants = info.getConstants(); @SuppressWarnings("unchecked") final Iterable<? extends EnumConstant<T, C>> enumConstants = (Iterable<? extends EnumConstant<T, C>>) _constants; for (EnumConstant<?, ?> enumConstant : enumConstants) { enumLeafInfo.addEnumConstantInfo(createEnumContantInfo( enumLeafInfo, (EC) enumConstant)); } } protected MElementInfo<T, C> getElementInfo(EI info) { return elementInfos.get(info); } protected MClassInfo<T, C> createClassInfo(CI info) { return new CMClassInfo<T, C>(createClassInfoOrigin(info), info.getClazz(), getPackage(info), getContainer(info), getLocalName(info), createBaseTypeInfo(info), info.isElement() ? info.getElementName() : null); } private void populateClassInfo(CI info, MClassInfo<T, C> classInfo) { if (info.hasAttributeWildcard()) { classInfo.addProperty(createAnyAttributePropertyInfo(classInfo)); } for (PropertyInfo<T, C> p : (List<? extends PropertyInfo<T, C>>) info .getProperties()) { classInfo.addProperty(createPropertyInfo(classInfo, (PI) p)); } } protected MClassTypeInfo<T, C> createBaseTypeInfo(CI info) { return info.getBaseClass() == null ? null : getTypeInfo((CI) info .getBaseClass()); } private MPropertyInfo<T, C> createPropertyInfo( final MClassInfo<T, C> classInfo, PI p) { if (p instanceof AttributePropertyInfo) { @SuppressWarnings("unchecked") final API api = (API) p; return createAttributePropertyInfo(classInfo, api); } else if (p instanceof ValuePropertyInfo) { @SuppressWarnings("unchecked") final VPI vpi = (VPI) p; return createValuePropertyInfo(classInfo, vpi); } else if (p instanceof ElementPropertyInfo) { @SuppressWarnings("unchecked") final EPI ep = (EPI) p; if (ep.getTypes().size() == 1) { return createElementPropertyInfo(classInfo, ep); } else { return createElementsPropertyInfo(classInfo, ep); } } else if (p instanceof ReferencePropertyInfo) { @SuppressWarnings("unchecked") final RPI rp = (RPI) p; final Set<? extends Element<T, C>> elements = rp.getElements(); if (elements.size() == 0 && rp.getWildcard() != null && (rp.getWildcard().allowDom || rp.getWildcard().allowTypedObject)) { return createAnyElementPropertyInfo(classInfo, rp); } else if (elements.size() == 1) { return createElementRefPropertyInfo(classInfo, rp); } else { return createElementRefsPropertyInfo(classInfo, rp); } } else if (p instanceof MapPropertyInfo) { // System.out.println("Map property: " + p.getName()); // MapPropertyInfo<T, C> mp = (MapPropertyInfo<T, C>) p; throw new UnsupportedOperationException(); } else { throw new AssertionError(); } } protected MPropertyInfo<T, C> createAttributePropertyInfo( final MClassInfo<T, C> classInfo, final API propertyInfo) { return new CMAttributePropertyInfo<T, C>( createPropertyInfoOrigin((PI) propertyInfo), classInfo, propertyInfo.getName(), getTypeInfo(propertyInfo), propertyInfo.getXmlName()); } protected MPropertyInfo<T, C> createValuePropertyInfo( final MClassInfo<T, C> classInfo, final VPI propertyInfo) { return new CMValuePropertyInfo<T, C>( createPropertyInfoOrigin((PI) propertyInfo), classInfo, propertyInfo.getName(), getTypeInfo(propertyInfo)); } protected MPropertyInfo<T, C> createElementPropertyInfo( final MClassInfo<T, C> classInfo, final EPI ep) { final TypeRef<T, C> typeRef = ep.getTypes().get(0); return new CMElementPropertyInfo<T, C>( createPropertyInfoOrigin((PI) ep), classInfo, ep.getName(), ep.isCollection() && !ep.isValueList(), getTypeInfo(ep, typeRef), typeRef.getTagName(), ep.getXmlName()); } protected MPropertyInfo<T, C> createElementsPropertyInfo( final MClassInfo<T, C> classInfo, final EPI ep) { List<? extends TypeRef<T, C>> types = ep.getTypes(); final Collection<MElementTypeInfo<T, C>> typedElements = new ArrayList<MElementTypeInfo<T, C>>( types.size()); for (TypeRef<T, C> typeRef : types) { typedElements.add(new CMElementTypeInfo<T, C>(typeRef.getTagName(), getTypeInfo(ep, typeRef))); } return new CMElementsPropertyInfo<T, C>( createPropertyInfoOrigin((PI) ep), classInfo, ep.getName(), ep.isCollection() && !ep.isValueList(), typedElements, ep.getXmlName()); } protected MPropertyInfo<T, C> createAnyElementPropertyInfo( final MClassInfo<T, C> classInfo, final RPI rp) { return new CMAnyElementPropertyInfo<T, C>( createPropertyInfoOrigin((PI) rp), classInfo, rp.getName(), rp.isCollection(), rp.isMixed(), rp.getWildcard().allowDom, rp.getWildcard().allowTypedObject); } protected MPropertyInfo<T, C> createElementRefPropertyInfo( final MClassInfo<T, C> classInfo, final RPI rp) { final Element<T, C> element = rp.getElements().iterator().next(); return new CMElementRefPropertyInfo<T, C>( createPropertyInfoOrigin((PI) rp), classInfo, rp.getName(), rp.isCollection(), getTypeInfo(rp, element), element.getElementName(), rp.getXmlName(), rp.isMixed(), rp.getWildcard() == null ? false : rp.getWildcard().allowDom, rp.getWildcard() == null ? false : rp.getWildcard().allowTypedObject); } protected MPropertyInfo<T, C> createElementRefsPropertyInfo( final MClassInfo<T, C> classInfo, final RPI rp) { final List<MElementTypeInfo<T, C>> typedElements = new ArrayList<MElementTypeInfo<T, C>>(); for (Element<T, C> element : rp.getElements()) { typedElements.add(new CMElementTypeInfo<T, C>(element .getElementName(), getTypeInfo(rp, element))); } return new CMElementRefsPropertyInfo<T, C>( createPropertyInfoOrigin((PI) rp), classInfo, rp.getName(), rp.isCollection(), typedElements, rp.getXmlName(), rp.isMixed(), rp.getWildcard() == null ? false : rp.getWildcard().allowDom, rp.getWildcard() == null ? false : rp.getWildcard().allowTypedObject); } protected CMAnyAttributePropertyInfo<T, C> createAnyAttributePropertyInfo( final MClassInfo<T, C> classInfo) { return new CMAnyAttributePropertyInfo<T, C>( createAnyAttributePropertyInfoOrigin(), classInfo, "otherAttributes"); } protected MTypeInfo<T, C> getTypeInfo(final ValuePropertyInfo<T, C> vp) { return getTypeInfo(vp, (TI) vp.ref().iterator().next(), vp.isCollection(), vp.getAdapter(), vp.id(), vp.getExpectedMimeType()); } protected MTypeInfo<T, C> getTypeInfo(final AttributePropertyInfo<T, C> ap) { return getTypeInfo(ap, (TI) ap.ref().iterator().next(), ap.isCollection(), ap.getAdapter(), ap.id(), ap.getExpectedMimeType()); } protected MTypeInfo<T, C> getTypeInfo(final ElementPropertyInfo<T, C> ep, final TypeRef<T, C> typeRef) { return getTypeInfo(ep, (TI) typeRef.getTarget(), ep.isValueList(), ep.getAdapter(), ep.id(), ep.getExpectedMimeType()); } protected MTypeInfo<T, C> getTypeInfo(final ReferencePropertyInfo<T, C> rp, Element<T, C> element) { return getTypeInfo(rp, (TI) element, false, rp.getAdapter(), rp.id(), rp.getExpectedMimeType()); } protected abstract MPackageInfo getPackage(CI info); protected abstract String getLocalName(CI info); protected abstract MClassInfo<T, C> getScope(CI info); protected abstract MPackageInfo getPackage(ELI info); protected abstract String getLocalName(ELI info); protected abstract String getLocalName(EI info); protected abstract MPackageInfo getPackage(EI info); protected abstract MContainer getContainer(CI info); protected abstract MContainer getContainer(EI info); protected abstract MContainer getContainer(ELI info); // protected MBuiltinLeafInfo<T, C> createBuiltinLeafInfo(BLI info) { return new CMBuiltinLeafInfo<T, C>(createBuiltinLeafInfoOrigin(info), info.getType(), info.getTypeName()); } protected MEnumLeafInfo<T, C> createEnumLeafInfo(final ELI info) { @SuppressWarnings("unchecked") final TI baseType = (TI) info.getBaseType(); return new CMEnumLeafInfo<T, C>(createEnumLeafInfoOrigin(info), info.getClazz(), getPackage(info), getContainer(info), getLocalName(info), getTypeInfo(baseType), info.getElementName()); } protected CMEnumConstantInfo<T, C> createEnumContantInfo( MEnumLeafInfo<T, C> enumLeafInfo, EC enumConstant) { return new CMEnumConstantInfo<T, C>( createEnumConstantInfoOrigin(enumConstant), enumLeafInfo, enumConstant.getLexicalValue()); } protected MElementInfo<T, C> createElementInfo(EI element) { @SuppressWarnings("unchecked") final CI scopeCI = (CI) element.getScope(); final MClassInfo<T, C> scope = element.getScope() == null ? null : getTypeInfo(scopeCI); final QName substitutionHead = element.getSubstitutionHead() == null ? null : element.getSubstitutionHead().getElementName(); final MElementInfo<T, C> elementInfo = new CMElementInfo<T, C>( createElementInfoOrigin(element), getPackage(element), getContainer(element), getLocalName(element), element.getElementName(), scope, getTypeInfo(element), substitutionHead); return elementInfo; } protected MTypeInfo<T, C> createWildcardTypeInfo(WTI info) { return new CMWildcardTypeInfo<T, C>(createWildcardTypeInfoOrigin(info), info.getType()); } protected MModelInfoOrigin createModelInfoOrigin(TIS info) { return new CMModelInfoOrigin<T, C, TIS>(info); } protected MBuiltinLeafInfoOrigin createBuiltinLeafInfoOrigin(BLI info) { return new CMBuiltinLeafInfoOrigin<T, C, BLI>(info); } protected MClassInfoOrigin createClassInfoOrigin(CI info) { return new CMClassInfoOrigin<T, C, CI>(info); } protected MPropertyInfoOrigin createAnyAttributePropertyInfoOrigin() { return new CMAnyAttributePropertyInfoOrigin(); } protected MPropertyInfoOrigin createPropertyInfoOrigin(PI info) { return new CMPropertyInfoOrigin<T, C, PI>(info); } protected MElementInfoOrigin createElementInfoOrigin(EI info) { return new CMElementInfoOrigin<T, C, EI>(info); } protected MEnumLeafInfoOrigin createEnumLeafInfoOrigin(ELI info) { return new CMEnumLeafInfoOrigin<T, C, ELI>(info); } protected MEnumConstantInfoOrigin createEnumConstantInfoOrigin(EC info) { return new CMEnumConstantInfoOrigin<T, C, EC>(info); } protected MWildcardTypeInfoOrigin createWildcardTypeInfoOrigin(WTI info) { return new CMWildcardTypeInfoOrigin<T, C, WTI>(info); } protected abstract T createListType(T elementType); }