/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.cxf.aegis.type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.URI;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.Source;
import org.w3c.dom.Document;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.cxf.aegis.DatabindingException;
import org.apache.cxf.aegis.type.basic.Base64Type;
import org.apache.cxf.aegis.type.basic.BigDecimalType;
import org.apache.cxf.aegis.type.basic.BigIntegerType;
import org.apache.cxf.aegis.type.basic.BooleanType;
import org.apache.cxf.aegis.type.basic.CalendarType;
import org.apache.cxf.aegis.type.basic.CharacterType;
import org.apache.cxf.aegis.type.basic.DateTimeType;
import org.apache.cxf.aegis.type.basic.DoubleType;
import org.apache.cxf.aegis.type.basic.FloatType;
import org.apache.cxf.aegis.type.basic.IntType;
import org.apache.cxf.aegis.type.basic.LongType;
import org.apache.cxf.aegis.type.basic.ObjectType;
import org.apache.cxf.aegis.type.basic.ShortType;
import org.apache.cxf.aegis.type.basic.SqlDateType;
import org.apache.cxf.aegis.type.basic.StringType;
import org.apache.cxf.aegis.type.basic.TimeType;
import org.apache.cxf.aegis.type.basic.TimestampType;
import org.apache.cxf.aegis.type.basic.URIType;
import org.apache.cxf.aegis.type.mtom.AbstractXOPType;
import org.apache.cxf.aegis.type.mtom.DataHandlerType;
import org.apache.cxf.aegis.type.mtom.DataSourceType;
import org.apache.cxf.aegis.type.xml.DocumentType;
import org.apache.cxf.aegis.type.xml.JDOMDocumentType;
import org.apache.cxf.aegis.type.xml.JDOMElementType;
import org.apache.cxf.aegis.type.xml.SourceType;
import org.apache.cxf.aegis.type.xml.XMLStreamReaderType;
import org.apache.cxf.binding.soap.Soap11;
import org.apache.cxf.common.classloader.ClassLoaderUtils;
import org.apache.cxf.common.util.SOAPConstants;
import org.apache.cxf.common.util.XMLSchemaQNames;
import org.jdom.Element;
/**
* Contains type mappings for java/qname pairs.
*/
public class DefaultTypeMapping implements TypeMapping {
private static final Log LOG = LogFactory.getLog(DefaultTypeMapping.class);
private Map<Class, Type> class2Type;
private Map<QName, Type> xml2Type;
private Map<Class, QName> class2xml;
private TypeMapping nextTM;
private TypeCreator typeCreator;
private String identifierURI;
public DefaultTypeMapping(String identifierURI, TypeMapping defaultTM) {
this(identifierURI);
this.nextTM = defaultTM;
}
public DefaultTypeMapping() {
this(SOAPConstants.XSD);
}
public DefaultTypeMapping(String identifierURI) {
this.identifierURI = identifierURI;
class2Type = Collections.synchronizedMap(new HashMap<Class, Type>());
class2xml = Collections.synchronizedMap(new HashMap<Class, QName>());
xml2Type = Collections.synchronizedMap(new HashMap<QName, Type>());
}
public boolean isRegistered(Class javaType) {
boolean registered = class2Type.containsKey(javaType);
if (!registered && nextTM != null) {
registered = nextTM.isRegistered(javaType);
}
return registered;
}
public boolean isRegistered(QName xmlType) {
boolean registered = xml2Type.containsKey(xmlType);
if (!registered && nextTM != null) {
registered = nextTM.isRegistered(xmlType);
}
return registered;
}
public void register(Class javaType, QName xmlType, Type type) {
type.setSchemaType(xmlType);
type.setTypeClass(javaType);
register(type);
}
public void register(Type type) {
type.setTypeMapping(this);
/*
* -- prb@codehaus.org; changing this to only register the type for
* actions that it supports, and it could be none.
*/
if (type.getTypeClass() != null) {
class2xml.put(type.getTypeClass(), type.getSchemaType());
class2Type.put(type.getTypeClass(), type);
}
if (type.getSchemaType() != null) {
xml2Type.put(type.getSchemaType(), type);
}
if (type.getTypeClass() == null && type.getSchemaType() == null) {
LOG.warn("The type " + type.getClass().getName()
+ " supports neither serialization (non-null TypeClass)"
+ " nor deserialization (non-null SchemaType).");
}
}
public void removeType(Type type) {
if (!xml2Type.containsKey(type.getSchemaType())) {
nextTM.removeType(type);
} else {
xml2Type.remove(type.getSchemaType());
class2Type.remove(type.getTypeClass());
class2xml.remove(type.getTypeClass());
}
}
/**
* @see org.apache.cxf.aegis.type.TypeMapping#getType(java.lang.Class)
*/
public Type getType(Class javaType) {
Type type = class2Type.get(javaType);
if (type == null && nextTM != null) {
type = nextTM.getType(javaType);
}
return type;
}
/**
* @see org.apache.cxf.aegis.type.TypeMapping#getType(javax.xml.namespace.QName)
*/
public Type getType(QName xmlType) {
Type type = xml2Type.get(xmlType);
if (type == null && nextTM != null) {
type = nextTM.getType(xmlType);
}
return type;
}
/**
* @see org.apache.cxf.aegis.type.TypeMapping#getTypeQName(java.lang.Class)
*/
public QName getTypeQName(Class clazz) {
QName qname = class2xml.get(clazz);
if (qname == null && nextTM != null) {
qname = nextTM.getTypeQName(clazz);
}
return qname;
}
public TypeCreator getTypeCreator() {
return typeCreator;
}
public void setTypeCreator(TypeCreator typeCreator) {
this.typeCreator = typeCreator;
typeCreator.setTypeMapping(this);
}
public TypeMapping getParent() {
return nextTM;
}
private static void defaultRegister(TypeMapping tm, boolean defaultNillable, Class class1, QName name,
Type type) {
if (!defaultNillable) {
type.setNillable(false);
}
tm.register(class1, name, type);
}
private static void fillStandardMappings(TypeMapping tm, boolean defaultNillable,
boolean enableMtomXmime) {
defaultRegister(tm, defaultNillable, BigDecimal.class, XMLSchemaQNames.XSD_DECIMAL,
new BigDecimalType());
defaultRegister(tm, defaultNillable, BigInteger.class, XMLSchemaQNames.XSD_INTEGER,
new BigIntegerType());
defaultRegister(tm, defaultNillable, Boolean.class, XMLSchemaQNames.XSD_BOOLEAN,
new BooleanType());
defaultRegister(tm, defaultNillable, Calendar.class, XMLSchemaQNames.XSD_DATETIME,
new CalendarType());
defaultRegister(tm, defaultNillable, Character.class, Soap11.ENCODED_CHAR, new CharacterType());
defaultRegister(tm, defaultNillable, Date.class, XMLSchemaQNames.XSD_DATETIME, new DateTimeType());
defaultRegister(tm, defaultNillable, Document.class, XMLSchemaQNames.XSD_ANY, new DocumentType());
defaultRegister(tm, defaultNillable, Element.class, XMLSchemaQNames.XSD_ANY,
new JDOMElementType());
defaultRegister(tm, defaultNillable, Float.class, XMLSchemaQNames.XSD_FLOAT, new FloatType());
defaultRegister(tm, defaultNillable, Double.class, XMLSchemaQNames.XSD_DOUBLE, new DoubleType());
defaultRegister(tm, defaultNillable, Integer.class, XMLSchemaQNames.XSD_INT, new IntType());
defaultRegister(tm, defaultNillable, Long.class, XMLSchemaQNames.XSD_LONG, new LongType());
defaultRegister(tm, defaultNillable, Object.class, XMLSchemaQNames.XSD_ANY, new ObjectType());
defaultRegister(tm, defaultNillable, Short.class, XMLSchemaQNames.XSD_SHORT, new ShortType());
defaultRegister(tm, defaultNillable, Source.class, XMLSchemaQNames.XSD_ANY, new SourceType());
defaultRegister(tm, defaultNillable, String.class, XMLSchemaQNames.XSD_STRING, new StringType());
defaultRegister(tm, defaultNillable, Time.class, XMLSchemaQNames.XSD_TIME, new TimeType());
defaultRegister(tm, defaultNillable, Timestamp.class, XMLSchemaQNames.XSD_DATETIME,
new TimestampType());
defaultRegister(tm, defaultNillable, URI.class, XMLSchemaQNames.XSD_URI, new URIType());
defaultRegister(tm, defaultNillable, XMLStreamReader.class, XMLSchemaQNames.XSD_ANY,
new XMLStreamReaderType());
defaultRegister(tm, defaultNillable, boolean.class, XMLSchemaQNames.XSD_BOOLEAN,
new BooleanType());
defaultRegister(tm, defaultNillable, byte[].class, XMLSchemaQNames.XSD_BASE64, new Base64Type());
defaultRegister(tm, defaultNillable, double.class, XMLSchemaQNames.XSD_DOUBLE, new DoubleType());
defaultRegister(tm, defaultNillable, float.class, XMLSchemaQNames.XSD_FLOAT, new FloatType());
defaultRegister(tm, defaultNillable, int.class, XMLSchemaQNames.XSD_INT, new IntType());
defaultRegister(tm, defaultNillable, short.class, XMLSchemaQNames.XSD_SHORT, new ShortType());
defaultRegister(tm, defaultNillable, long.class, XMLSchemaQNames.XSD_LONG, new LongType());
defaultRegister(tm, defaultNillable, java.sql.Date.class, XMLSchemaQNames.XSD_DATETIME,
new SqlDateType());
defaultRegister(tm, defaultNillable, org.jdom.Document.class, XMLSchemaQNames.XSD_ANY,
new JDOMDocumentType());
QName mtomBase64 = XMLSchemaQNames.XSD_BASE64;
if (enableMtomXmime) {
mtomBase64 = AbstractXOPType.XML_MIME_BASE64;
}
defaultRegister(tm, defaultNillable, DataSource.class, mtomBase64,
new DataSourceType(enableMtomXmime, null));
defaultRegister(tm, defaultNillable, DataHandler.class, mtomBase64,
new DataHandlerType(enableMtomXmime, null));
}
public static DefaultTypeMapping createSoap11TypeMapping(boolean defaultNillable,
boolean enableMtomXmime) {
// Create a Type Mapping for SOAP 1.1 Encoding
DefaultTypeMapping soapTM = new DefaultTypeMapping(Soap11.SOAP_ENCODING_URI);
fillStandardMappings(soapTM, defaultNillable, enableMtomXmime);
defaultRegister(soapTM, defaultNillable, boolean.class, Soap11.ENCODED_BOOLEAN, new BooleanType());
defaultRegister(soapTM, defaultNillable, int.class, Soap11.ENCODED_INT, new IntType());
defaultRegister(soapTM, defaultNillable, short.class, Soap11.ENCODED_SHORT, new ShortType());
defaultRegister(soapTM, defaultNillable, double.class, Soap11.ENCODED_DOUBLE, new DoubleType());
defaultRegister(soapTM, defaultNillable, float.class, Soap11.ENCODED_FLOAT, new FloatType());
defaultRegister(soapTM, defaultNillable, long.class, Soap11.ENCODED_LONG, new LongType());
defaultRegister(soapTM, defaultNillable, char.class, Soap11.ENCODED_CHAR, new CharacterType());
defaultRegister(soapTM, defaultNillable, Character.class, Soap11.ENCODED_CHAR, new CharacterType());
defaultRegister(soapTM, defaultNillable, String.class, Soap11.ENCODED_STRING, new StringType());
defaultRegister(soapTM, defaultNillable, Boolean.class, Soap11.ENCODED_BOOLEAN, new BooleanType());
defaultRegister(soapTM, defaultNillable, Integer.class, Soap11.ENCODED_INT, new IntType());
defaultRegister(soapTM, defaultNillable, Short.class, Soap11.ENCODED_SHORT, new ShortType());
defaultRegister(soapTM, defaultNillable, Double.class, Soap11.ENCODED_DOUBLE, new DoubleType());
defaultRegister(soapTM, defaultNillable, Float.class, Soap11.ENCODED_FLOAT, new FloatType());
defaultRegister(soapTM, defaultNillable, Long.class, Soap11.ENCODED_LONG, new LongType());
defaultRegister(soapTM, defaultNillable, Date.class, Soap11.ENCODED_DATETIME, new DateTimeType());
defaultRegister(soapTM, defaultNillable, java.sql.Date.class, Soap11.ENCODED_DATETIME,
new SqlDateType());
defaultRegister(soapTM, defaultNillable, Calendar.class, Soap11.ENCODED_DATETIME, new CalendarType());
defaultRegister(soapTM, defaultNillable, byte[].class, Soap11.ENCODED_BASE64, new Base64Type());
defaultRegister(soapTM, defaultNillable, BigDecimal.class, Soap11.ENCODED_DECIMAL,
new BigDecimalType());
defaultRegister(soapTM, defaultNillable, BigInteger.class, Soap11.ENCODED_INTEGER,
new BigIntegerType());
return soapTM;
}
public static DefaultTypeMapping createDefaultTypeMapping(boolean defaultNillable,
boolean enableMtomXmime) {
// by convention, the default mapping is against the XML schema URI.
DefaultTypeMapping tm = new DefaultTypeMapping(SOAPConstants.XSD);
fillStandardMappings(tm, defaultNillable, enableMtomXmime);
registerIfAvailable(tm, defaultNillable, "javax.xml.datatype.Duration", XMLSchemaQNames.XSD_DURATION,
"org.apache.cxf.aegis.type.java5.DurationType");
registerIfAvailable(tm, defaultNillable, "javax.xml.datatype.XMLGregorianCalendar",
XMLSchemaQNames.XSD_DATE,
"org.apache.cxf.aegis.type.java5.XMLGregorianCalendarType");
registerIfAvailable(tm, defaultNillable, "javax.xml.datatype.XMLGregorianCalendar",
XMLSchemaQNames.XSD_TIME,
"org.apache.cxf.aegis.type.java5.XMLGregorianCalendarType");
registerIfAvailable(tm, defaultNillable, "javax.xml.datatype.XMLGregorianCalendar",
XMLSchemaQNames.XSD_G_DAY,
"org.apache.cxf.aegis.type.java5.XMLGregorianCalendarType");
registerIfAvailable(tm, defaultNillable, "javax.xml.datatype.XMLGregorianCalendar",
XMLSchemaQNames.XSD_G_MONTH,
"org.apache.cxf.aegis.type.java5.XMLGregorianCalendarType");
registerIfAvailable(tm, defaultNillable, "javax.xml.datatype.XMLGregorianCalendar",
XMLSchemaQNames.XSD_G_MONTH_DAY,
"org.apache.cxf.aegis.type.java5.XMLGregorianCalendarType");
registerIfAvailable(tm, defaultNillable, "javax.xml.datatype.XMLGregorianCalendar",
XMLSchemaQNames.XSD_G_YEAR,
"org.apache.cxf.aegis.type.java5.XMLGregorianCalendarType");
registerIfAvailable(tm, defaultNillable, "javax.xml.datatype.XMLGregorianCalendar",
XMLSchemaQNames.XSD_G_YEAR_MONTH,
"org.apache.cxf.aegis.type.java5.XMLGregorianCalendarType");
registerIfAvailable(tm, defaultNillable, "javax.xml.datatype.XMLGregorianCalendar",
XMLSchemaQNames.XSD_DATETIME,
"org.apache.cxf.aegis.type.java5.XMLGregorianCalendarType");
return tm;
}
private static void registerIfAvailable(TypeMapping tm, boolean defaultNillable, String className,
QName typeName, String typeClassName) {
try {
Class cls = ClassLoaderUtils.loadClass(className, DefaultTypeMapping.class);
Class typeCls = ClassLoaderUtils.loadClass(typeClassName, DefaultTypeMapping.class);
try {
Type type = (Type)typeCls.newInstance();
defaultRegister(tm, defaultNillable, cls, typeName, type);
} catch (InstantiationException e) {
throw new DatabindingException("Couldn't instantiate Type ", e);
} catch (IllegalAccessException e) {
throw new DatabindingException("Couldn't instantiate Type ", e);
}
} catch (ClassNotFoundException e) {
LOG.debug("Could not find optional Type " + className + ". Skipping.");
}
}
public String getMappingIdentifierURI() {
return identifierURI;
}
}