/** * 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.lang.reflect.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 java.util.logging.Logger; 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.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.ByteType; import org.apache.cxf.aegis.type.basic.CalendarType; import org.apache.cxf.aegis.type.basic.CharacterAsStringType; 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.logging.LogUtils; import org.apache.ws.commons.schema.constants.Constants; /** * The implementation of the Aegis type map. It maintains a map from * Java types {@link java.lang.reflect.Type} and AegisType objects, * also indexed by the XML Schema QName of each type. */ public class DefaultTypeMapping implements TypeMapping { public static final String DEFAULT_MAPPING_URI = "urn:org.apache.cxf.aegis.types"; private static final Logger LOG = LogUtils.getL7dLogger(DefaultTypeMapping.class); private Map<Type, AegisType> class2Type; private Map<QName, AegisType> xml2Type; private Map<Type, 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(DEFAULT_MAPPING_URI); } public DefaultTypeMapping(String identifierURI) { this.identifierURI = identifierURI == null ? DEFAULT_MAPPING_URI : identifierURI; class2Type = Collections.synchronizedMap(new HashMap<Type, AegisType>()); class2xml = Collections.synchronizedMap(new HashMap<Type, QName>()); xml2Type = Collections.synchronizedMap(new HashMap<QName, AegisType>()); } public boolean isRegistered(Type 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(Type javaType, QName xmlType, AegisType type) { type.setSchemaType(xmlType); type.setTypeClass(javaType); register(type); } /** * {@inheritDoc} */ public void register(AegisType type) { type.setTypeMapping(this); if (type.getType() != null) { class2xml.put(type.getType(), type.getSchemaType()); class2Type.put(type.getType(), type); } if (type.getSchemaType() != null) { xml2Type.put(type.getSchemaType(), type); } if (type.getType() == null && type.getSchemaType() == null) { LOG.warning("The type " + type.getClass().getName() + " supports neither serialization (non-null TypeClass)" + " nor deserialization (non-null SchemaType)."); } } public void removeType(AegisType type) { if (!xml2Type.containsKey(type.getSchemaType())) { nextTM.removeType(type); } else { xml2Type.remove(type.getSchemaType()); class2Type.remove(type.getType()); class2xml.remove(type.getType()); } } public AegisType getType(Type javaType) { AegisType type = class2Type.get(javaType); if (type == null && nextTM != null) { type = nextTM.getType(javaType); } return type; } public AegisType getType(QName xmlType) { AegisType type = xml2Type.get(xmlType); if (type == null && nextTM != null) { type = nextTM.getType(xmlType); } return type; } public QName getTypeQName(Type 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, AegisType type) { if (!defaultNillable) { type.setNillable(false); } tm.register(class1, name, type); } private static void fillStandardMappings(TypeMapping tm, boolean defaultNillable, boolean enableMtomXmime, boolean enableJDOM) { defaultRegister(tm, defaultNillable, BigDecimal.class, Constants.XSD_DECIMAL, new BigDecimalType()); defaultRegister(tm, defaultNillable, BigInteger.class, Constants.XSD_INTEGER, new BigIntegerType()); defaultRegister(tm, defaultNillable, Boolean.class, Constants.XSD_BOOLEAN, new BooleanType()); defaultRegister(tm, defaultNillable, Calendar.class, Constants.XSD_DATETIME, new CalendarType()); defaultRegister(tm, defaultNillable, Date.class, Constants.XSD_DATETIME, new DateTimeType()); defaultRegister(tm, defaultNillable, Float.class, Constants.XSD_FLOAT, new FloatType()); defaultRegister(tm, defaultNillable, Double.class, Constants.XSD_DOUBLE, new DoubleType()); defaultRegister(tm, defaultNillable, Integer.class, Constants.XSD_INT, new IntType()); defaultRegister(tm, defaultNillable, Long.class, Constants.XSD_LONG, new LongType()); defaultRegister(tm, defaultNillable, Object.class, Constants.XSD_ANYTYPE, new ObjectType()); defaultRegister(tm, defaultNillable, Byte.class, Constants.XSD_BYTE, new ByteType()); defaultRegister(tm, defaultNillable, Short.class, Constants.XSD_SHORT, new ShortType()); defaultRegister(tm, defaultNillable, Source.class, Constants.XSD_ANYTYPE, new SourceType()); defaultRegister(tm, defaultNillable, String.class, Constants.XSD_STRING, new StringType()); defaultRegister(tm, defaultNillable, Time.class, Constants.XSD_TIME, new TimeType()); defaultRegister(tm, defaultNillable, Timestamp.class, Constants.XSD_DATETIME, new TimestampType()); defaultRegister(tm, defaultNillable, URI.class, Constants.XSD_ANYURI, new URIType()); defaultRegister(tm, defaultNillable, XMLStreamReader.class, Constants.XSD_ANYTYPE, new XMLStreamReaderType()); defaultRegister(tm, defaultNillable, boolean.class, Constants.XSD_BOOLEAN, new BooleanType()); defaultRegister(tm, defaultNillable, byte[].class, Constants.XSD_BASE64, new Base64Type()); defaultRegister(tm, defaultNillable, double.class, Constants.XSD_DOUBLE, new DoubleType()); defaultRegister(tm, defaultNillable, float.class, Constants.XSD_FLOAT, new FloatType()); defaultRegister(tm, defaultNillable, int.class, Constants.XSD_INT, new IntType()); defaultRegister(tm, defaultNillable, short.class, Constants.XSD_SHORT, new ShortType()); defaultRegister(tm, defaultNillable, byte.class, Constants.XSD_BYTE, new ByteType()); defaultRegister(tm, defaultNillable, long.class, Constants.XSD_LONG, new LongType()); defaultRegister(tm, defaultNillable, java.sql.Date.class, Constants.XSD_DATETIME, new SqlDateType()); defaultRegister(tm, defaultNillable, java.sql.Date.class, Constants.XSD_DATE, new SqlDateType()); defaultRegister(tm, defaultNillable, Number.class, Constants.XSD_DECIMAL, new BigDecimalType()); QName mtomBase64 = Constants.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)); defaultRegister(tm, defaultNillable, Document.class, Constants.XSD_ANYTYPE, new DocumentType()); if (enableJDOM) { registerJDOMTypes(tm, defaultNillable); } } private static void registerJDOMTypes(TypeMapping tm, boolean defaultNillable) { try { Class<?> jdomDocClass = ClassLoaderUtils.loadClass("org.jdom.Document", DefaultTypeMapping.class); defaultRegister(tm, defaultNillable, jdomDocClass, Constants.XSD_ANYTYPE, new JDOMDocumentType()); } catch (ClassNotFoundException e) { // not available. } try { Class<?> jdomElementClass = ClassLoaderUtils.loadClass("org.jdom.Element", DefaultTypeMapping.class); defaultRegister(tm, defaultNillable, jdomElementClass, Constants.XSD_ANYTYPE, new JDOMElementType()); } catch (ClassNotFoundException e) { // not available. } } /** * Create a type mapping object with a stock set of mappings, including the SOAP 1.1 'encoded' * types. * @param defaultNillable whether elements are nillable by default. * @param enableMtomXmime whether to enable XMIME annotations with MTOM. * @param enableJDOM whether to add mappings for JDOM. * @return */ public static DefaultTypeMapping createSoap11TypeMapping(boolean defaultNillable, boolean enableMtomXmime, boolean enableJDOM) { // Create a AegisType Mapping for SOAP 1.1 Encoding DefaultTypeMapping soapTM = new DefaultTypeMapping(Soap11.SOAP_ENCODING_URI); fillStandardMappings(soapTM, defaultNillable, enableMtomXmime, enableJDOM); defaultRegister(soapTM, defaultNillable, boolean.class, Soap11.ENCODED_BOOLEAN, new BooleanType()); defaultRegister(soapTM, defaultNillable, char.class, Soap11.ENCODED_CHAR, new CharacterType()); 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) { return createDefaultTypeMapping( defaultNillable, enableMtomXmime, false); } /** * Create a set of default type mappings. * @param defaultNillable whether elements are nillable by default. * @param enableMtomXmime whether to enable XMIME annotations on MTOM. * @param enableJDOM whether to map JDOM types. * @return */ public static DefaultTypeMapping createDefaultTypeMapping(boolean defaultNillable, boolean enableMtomXmime, boolean enableJDOM) { // by convention, the default mapping is against the XML schema URI. DefaultTypeMapping tm = new DefaultTypeMapping(Constants.URI_2001_SCHEMA_XSD); fillStandardMappings(tm, defaultNillable, enableMtomXmime, enableJDOM); defaultRegister(tm, defaultNillable, Character.class, CharacterAsStringType.CHARACTER_AS_STRING_TYPE_QNAME, new CharacterAsStringType()); defaultRegister(tm, defaultNillable, char.class, CharacterAsStringType.CHARACTER_AS_STRING_TYPE_QNAME, new CharacterAsStringType()); defaultRegister(tm, defaultNillable, javax.xml.datatype.Duration.class, Constants.XSD_DURATION, new org.apache.cxf.aegis.type.java5.DurationType()); defaultRegister(tm, defaultNillable, javax.xml.datatype.XMLGregorianCalendar.class, Constants.XSD_DATE, new org.apache.cxf.aegis.type.java5.XMLGregorianCalendarType()); defaultRegister(tm, defaultNillable, javax.xml.datatype.XMLGregorianCalendar.class, Constants.XSD_TIME, new org.apache.cxf.aegis.type.java5.XMLGregorianCalendarType()); defaultRegister(tm, defaultNillable, javax.xml.datatype.XMLGregorianCalendar.class, Constants.XSD_DAY, new org.apache.cxf.aegis.type.java5.XMLGregorianCalendarType()); defaultRegister(tm, defaultNillable, javax.xml.datatype.XMLGregorianCalendar.class, Constants.XSD_MONTH, new org.apache.cxf.aegis.type.java5.XMLGregorianCalendarType()); defaultRegister(tm, defaultNillable, javax.xml.datatype.XMLGregorianCalendar.class, Constants.XSD_MONTHDAY, new org.apache.cxf.aegis.type.java5.XMLGregorianCalendarType()); defaultRegister(tm, defaultNillable, javax.xml.datatype.XMLGregorianCalendar.class, Constants.XSD_YEAR, new org.apache.cxf.aegis.type.java5.XMLGregorianCalendarType()); defaultRegister(tm, defaultNillable, javax.xml.datatype.XMLGregorianCalendar.class, Constants.XSD_YEARMONTH, new org.apache.cxf.aegis.type.java5.XMLGregorianCalendarType()); defaultRegister(tm, defaultNillable, javax.xml.datatype.XMLGregorianCalendar.class, Constants.XSD_DATETIME, new org.apache.cxf.aegis.type.java5.XMLGregorianCalendarType()); return tm; } public String getMappingIdentifierURI() { return identifierURI; } public void setMappingIdentifierURI(String uri) { identifierURI = uri; } }