package com.sun.xml.internal.bind.v2.model.impl;
import java.util.Collection;
import java.lang.annotation.Annotation;
import javax.activation.MimeType;
import javax.xml.bind.annotation.XmlAttachmentRef;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlID;
import javax.xml.bind.annotation.XmlIDREF;
import javax.xml.bind.annotation.XmlInlineBinaryData;
import javax.xml.bind.annotation.XmlMimeType;
import javax.xml.bind.annotation.XmlSchema;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapters;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.namespace.QName;
import com.sun.xml.internal.bind.v2.TODO;
import com.sun.xml.internal.bind.v2.model.annotation.AnnotationReader;
import com.sun.xml.internal.bind.v2.model.annotation.Locatable;
import com.sun.xml.internal.bind.v2.model.core.Adapter;
import com.sun.xml.internal.bind.v2.model.core.ID;
import com.sun.xml.internal.bind.v2.model.core.PropertyInfo;
import com.sun.xml.internal.bind.v2.model.core.TypeInfo;
import com.sun.xml.internal.bind.v2.model.core.TypeInfoSet;
import com.sun.xml.internal.bind.v2.model.nav.Navigator;
import com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationException;
import com.sun.xml.internal.bind.v2.runtime.Location;
import com.sun.xml.internal.bind.v2.runtime.SwaRefAdapter;
abstract class PropertyInfoImpl<T,C,F,M>
implements PropertyInfo<T,C>, Locatable, Comparable<PropertyInfoImpl> {
protected final PropertySeed<T,C,F,M> seed;
private final boolean isCollection;
private final ID id;
private final MimeType expectedMimeType;
private final boolean inlineBinary;
private final QName schemaType;
protected final ClassInfoImpl<T,C,F,M> parent;
private final Adapter<T,C> adapter;
protected PropertyInfoImpl(ClassInfoImpl<T,C,F,M> parent, PropertySeed<T,C,F,M> spi) {
this.seed = spi;
this.parent = parent;
if(parent==null)
throw new AssertionError();
MimeType mt = Util.calcExpectedMediaType(seed,parent.builder);
if(mt!=null && !kind().canHaveXmlMimeType) {
parent.builder.reportError(new IllegalAnnotationException(
Messages.ILLEGAL_ANNOTATION.format(XmlMimeType.class.getName()),
seed.readAnnotation(XmlMimeType.class)
));
mt = null;
}
this.expectedMimeType = mt;
this.inlineBinary = seed.hasAnnotation(XmlInlineBinaryData.class);
T t = seed.getRawType();
XmlJavaTypeAdapter xjta = getApplicableAdapter(t);
if(xjta!=null) {
isCollection = false;
adapter = new Adapter<T,C>(xjta,reader(),nav());
} else {
this.isCollection = nav().isSubClassOf(t, nav().ref(Collection.class))
|| nav().isArrayButNotByteArray(t);
xjta = getApplicableAdapter(getIndividualType());
if(xjta==null) {
XmlAttachmentRef xsa = seed.readAnnotation(XmlAttachmentRef.class);
if(xsa!=null) {
parent.builder.hasSwaRef = true;
adapter = new Adapter<T,C>(nav().asDecl(SwaRefAdapter.class),nav());
} else {
adapter = null;
xjta = seed.readAnnotation(XmlJavaTypeAdapter.class);
if(xjta!=null) {
T ad = reader().getClassValue(xjta,"value");
parent.builder.reportError(new IllegalAnnotationException(
Messages.UNMATCHABLE_ADAPTER.format(
nav().getTypeName(ad), nav().getTypeName(t)),
xjta
));
}
}
} else {
adapter = new Adapter<T,C>(xjta,reader(),nav());
}
}
this.id = calcId();
this.schemaType = Util.calcSchemaType(reader(),seed,parent.clazz,
getIndividualType(),this);
}
public ClassInfoImpl<T,C,F,M> parent() {
return parent;
}
protected final Navigator<T,C,F,M> nav() {
return parent.nav();
}
protected final AnnotationReader<T,C,F,M> reader() {
return parent.reader();
}
public T getRawType() {
return seed.getRawType();
}
public T getIndividualType() {
if(adapter!=null)
return adapter.defaultType;
T raw = getRawType();
if(!isCollection()) {
return raw;
} else {
if(nav().isArrayButNotByteArray(raw))
return nav().getComponentType(raw);
T bt = nav().getBaseClass(raw, nav().asDecl(Collection.class) );
if(nav().isParameterizedType(bt))
return nav().getTypeArgument(bt,0);
else
return nav().ref(Object.class);
}
}
public final String getName() {
return seed.getName();
}
private boolean isApplicable(XmlJavaTypeAdapter jta, T declaredType ) {
if(jta==null) return false;
T type = reader().getClassValue(jta,"type");
if(nav().isSameType(declaredType, type))
return true;
T ad = reader().getClassValue(jta,"value");
T ba = nav().getBaseClass(ad, nav().asDecl(XmlAdapter.class));
if(!nav().isParameterizedType(ba))
return true;
T inMemType = nav().getTypeArgument(ba, 1);
return nav().isSubClassOf(declaredType,inMemType);
}
private XmlJavaTypeAdapter getApplicableAdapter(T type) {
XmlJavaTypeAdapter jta = seed.readAnnotation(XmlJavaTypeAdapter.class);
if(jta!=null && isApplicable(jta,type))
return jta;
XmlJavaTypeAdapters jtas = reader().getPackageAnnotation(XmlJavaTypeAdapters.class, parent.clazz, seed );
if(jtas!=null) {
for (XmlJavaTypeAdapter xjta : jtas.value()) {
if(isApplicable(xjta,type))
return xjta;
}
}
jta = reader().getPackageAnnotation(XmlJavaTypeAdapter.class, parent.clazz, seed );
if(isApplicable(jta,type))
return jta;
C refType = nav().asDecl(type);
if(refType!=null) {
jta = reader().getClassAnnotation(XmlJavaTypeAdapter.class, refType, seed );
if(jta!=null && isApplicable(jta,type))
return jta;
}
return null;
}
public Adapter<T,C> getAdapter() {
return adapter;
}
public final String displayName() {
return nav().getClassName(parent.getClazz())+'#'+getName();
}
public final ID id() {
return id;
}
private ID calcId() {
if(seed.hasAnnotation(XmlID.class)) {
if(!nav().isSameType(getIndividualType(), nav().ref(String.class)))
parent.builder.reportError(new IllegalAnnotationException(
Messages.ID_MUST_BE_STRING.format(getName()), seed )
);
return ID.ID;
} else
if(seed.hasAnnotation(XmlIDREF.class)) {
return ID.IDREF;
} else {
return ID.NONE;
}
}
public final MimeType getExpectedMimeType() {
return expectedMimeType;
}
public final boolean inlineBinaryData() {
return inlineBinary;
}
public final QName getSchemaType() {
return schemaType;
}
public final boolean isCollection() {
return isCollection;
}
protected void link() {
if(id==ID.IDREF) {
for (TypeInfo<T,C> ti : ref()) {
if(!ti.canBeReferencedByIDREF())
parent.builder.reportError(new IllegalAnnotationException(
Messages.INVALID_IDREF.format(
parent.builder.nav.getTypeName(ti.getType())), this ));
}
}
}
public Locatable getUpstream() {
return parent;
}
public Location getLocation() {
return seed.getLocation();
}
protected final QName calcXmlName(XmlElement e) {
if(e!=null)
return calcXmlName(e.namespace(),e.name());
else
return calcXmlName("##default","##default");
}
protected final QName calcXmlName(XmlElementWrapper e) {
if(e!=null)
return calcXmlName(e.namespace(),e.name());
else
return calcXmlName("##default","##default");
}
private QName calcXmlName(String uri,String local) {
TODO.checkSpec();
if(local.length()==0 || local.equals("##default"))
local = seed.getName();
if(uri.equals("##default")) {
XmlSchema xs = reader().getPackageAnnotation( XmlSchema.class, parent.getClazz(), this );
if(xs!=null) {
switch(xs.elementFormDefault()) {
case QUALIFIED:
QName typeName = parent.getTypeName();
if(typeName!=null)
uri = typeName.getNamespaceURI();
else
uri = xs.namespace();
if(uri.length()==0)
uri = parent.builder.defaultNsUri;
break;
case UNQUALIFIED:
case UNSET:
uri = "";
}
} else {
uri = "";
}
}
return new QName(uri.intern(),local.intern());
}
public int compareTo(PropertyInfoImpl that) {
return this.getName().compareTo(that.getName());
}
public final <A extends Annotation> A readAnnotation(Class<A> annotationType) {
return seed.readAnnotation(annotationType);
}
public final boolean hasAnnotation(Class<? extends Annotation> annotationType) {
return seed.hasAnnotation(annotationType);
}
}