/*******************************************************************************
* Copyright (c) 2006-2010 eBay Inc. All Rights Reserved.
* Licensed 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
*******************************************************************************/
/**
*
*/
package org.ebayopensource.turmeric.runtime.binding;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import org.ebayopensource.turmeric.runtime.binding.exception.BindingException;
import org.ebayopensource.turmeric.runtime.binding.exception.SerializationException;
import org.ebayopensource.turmeric.runtime.binding.impl.DeserializationContextImpl;
import org.ebayopensource.turmeric.runtime.binding.impl.SerializationContextImpl;
import org.ebayopensource.turmeric.runtime.binding.impl.TypeConversionContextImpl;
import org.ebayopensource.turmeric.runtime.binding.impl.parser.NamespaceConvention;
import org.ebayopensource.turmeric.runtime.binding.schema.DataElementSchema;
import org.ebayopensource.turmeric.runtime.binding.utils.XmlSerializationSupport;
/**
* To perform serialization/deserialization, the corresponding serialization/deserialization context
* must be created first. Then a SerializerFactory/DeserializerFactory is created. Once a
* serializer/deserializer is created form the factory, feed the context to the serializer/deserializer
* results in the seialized payload or the deserialized java object.
*
* BindingFacade provides list of convenient methods to create serialization/deserialization context and
* to perform the serialization/deserialization.
*
* @author wdeng
*
*/
public class BindingFacade {
/**
* Default namespace.
*/
public static final String DEFAULT_NAMESPACE = "urn:default";
/**
* Creates and returns a IDeserializationContext of the given payload
* type, the given default namespace, the single namespace and a given
* map of all namespaces
* to prefix mappings used in the payload. The payload is encoded using
* the given charset. The caller must provide information about the root
* class, its XML name, and its element schema. Caller must also provide
* mappings of java type to their namespaces and mappings of java packages
* to their namespaces. ITypeConversionContext is optional. If provided,
* Caller can specify customized type conversion. preserve of element order
* and unordered NV format are two options that you need to provide when
* dealing with NV format. The caller also has the option
* to request the support for on-demand object node creation.
*
* @param payloadType data format type of the payload
* @param defaultNamespace the namespace to be recognized as the default so that prefix
* is skipped for elements from this namespace.
* @param ns2Prefix namespace to namespace prefix mapping.
* @param prefix2NS namespace prefix to namespace mapping.
* @param charset Charset of the payload.
* @param rootXMLName XML QName for the root element.
* @param rootClass Class object of the root java bean object.
* @param rootSchema DataElementSchema for the root object.
* @param supportObjectNode true if the context should support accessing
* the payload as DOM.
* @param preserveElementOrder Only appliable to NV format, whether the
* NV pairs in the payload ordered the same as the XML elements
* in the corresponding XML payload
* @param javaType2NS JavaType Class to namespace mapping;
* @param pkg2NS Java package to namespace mapping;
* @param typeConversion an object implemented the TypeConversion interface.
* It is intented to be used to support additional type conversion.
* However TypeConversion is being deprecated. Should pass in <code>null</code>
* @param isREST True if the payload is a rest request.
* @return an IDeserializationContext.
*/
public static IDeserializationContext createDeserializationContext(
String payloadType,
String defaultNamespace,
Map<String, List<String>> ns2Prefix,
Map<String, String> prefix2NS,
Charset charset,
QName rootXMLName,
Class rootClass,
DataElementSchema rootSchema,
boolean supportObjectNode,
boolean preserveElementOrder,
Map<Class, String> javaType2NS,
Map<String, String> pkg2NS,
ITypeConversionContext typeConversion,
boolean isREST) {
return createDeserializationContext(payloadType, defaultNamespace, ns2Prefix, prefix2NS, charset, rootXMLName,
rootClass, rootSchema, supportObjectNode, preserveElementOrder, javaType2NS, pkg2NS, typeConversion,
isREST, defaultNamespace);
}
/**
* Creates and returns a IDeserializationContext of the given payload
* type, the given default namespace, and a given map of all namespaces
* to prefix mappings used in the payload. The payload is encoded using
* the given charset. The caller must provide information about the root
* class, its XML name, and its element schema. Caller must also provide
* mappings of java type to their namespaces and mappings of java packages
* to their namespaces. ITypeConversionContext is optional. If provided,
* Caller can specify customized type conversion. preserve of element order
* and unordered NV format are two options that you need to provide when
* dealing with NV format. The caller also has the option
* to request the support for on-demand object node creation.
*
* @param payloadType data format type of the payload
* @param defaultNamespace the namespace to be recognized as the default so that prefix
* is skipped for elements from this namespace.
* @param ns2Prefix namespace to namespace prefix mapping.
* @param prefix2NS namespace prefix to namespace mapping.
* @param charset Charset of the payload.
* @param rootXMLName XML QName for the root element.
* @param rootClass Class object of the root java bean object.
* @param rootSchema DataElementSchema for the root object.
* @param supportObjectNode true if the context should support accessing
* the payload as DOM.
* @param preserveElementOrder Only appliable to NV format, whether the
* NV pairs in the payload ordered the same as the XML elements
* in the corresponding XML payload
* @param javaType2NS JavaType Class to namespace mapping;
* @param pkg2NS Java package to namespace mapping;
* @param typeConversion an object implemented the TypeConversion interface.
* It is intented to be used to support additional type conversion.
* However TypeConversion is being deprecated. Should pass in <code>null</code>
* @param isREST True if the payload is a rest request.
* @param singleNamespace the namespace of types if all the types are associated with
* only one namespace. otherwise, should leave it null.
* @return an IDeserializationContext.
*/
public static IDeserializationContext createDeserializationContext(
String payloadType,
String defaultNamespace,
Map<String, List<String>> ns2Prefix,
Map<String, String> prefix2NS,
Charset charset,
QName rootXMLName,
Class rootClass,
DataElementSchema rootSchema,
boolean supportObjectNode,
boolean preserveElementOrder,
Map<Class, String> javaType2NS,
Map<String, String> pkg2NS,
ITypeConversionContext typeConversion,
boolean isREST,
String singleNamespace) {
return new DeserializationContextImpl(payloadType, defaultNamespace, ns2Prefix, prefix2NS, charset,
rootXMLName, rootClass, rootSchema, supportObjectNode, preserveElementOrder, pkg2NS,
typeConversion, isREST, singleNamespace);
}
/**
* Creates and returns a ISerializationContext of the given payload
* type, the given default namespace and a given map of all namespaces
* to prefix mappings used in the payload. The payload is encoded using
* the given charset. The caller must provide information about the root
* class, its XML name, and its element schema. The caller must also provide
* mappings of java types to their namespaces and mappings of java packages
* to their namespaces. ITypeConversionContext is optional. If provided,
* Caller can enforce type conversion. Caller can also specify the options
* to support on-demand object node creation and
* unordered NV format.
*
* @param payloadType data format type of the payload
* @param defaultNamespace the namespace to be recognized as the default so that prefix
* is skipped for elements from this namespace.
* @param ns2Prefix namespace to namespace prefix mapping.
* @param prefix2NS namespace prefix to namespace mapping.
* @param charset Charset of the payload.
* @param rootXMLName XML QName for the root element.
* @param rootClass Class object of the root java bean object.
* @param rootSchema DataElementSchema for the root object.
* @param supportObjectNode true if the context should support accessing
* the payload as DOM.
* @param javaType2NS JavaType Class to namespace mapping;
* @param pkg2NS Java package to namespace mapping;
* @param typeConversion an object implemented the TypeConversion interface.
* It is intented to be used to support additional type conversion.
* However TypeConversion is being deprecated. Should pass in <code>null</code>
* @param isREST True if the payload is a rest request.
* @return an ISerializationContext
*/
public static ISerializationContext createSerializationContext(
String payloadType,
String defaultNamespace,
Map<String, List<String>> ns2Prefix,
Map<String, String> prefix2NS,
Charset charset,
QName rootXMLName,
Class rootClass,
DataElementSchema rootSchema,
boolean supportObjectNode,
Map<Class, String> javaType2NS,
Map<String, String> pkg2NS,
ITypeConversionContext typeConversion,
boolean isREST) {
return createSerializationContext(payloadType, defaultNamespace, ns2Prefix, prefix2NS, charset,
rootXMLName, rootClass, rootSchema, supportObjectNode, javaType2NS, pkg2NS, typeConversion,
isREST, defaultNamespace);
}
/**
* Creates and returns a ISerializationContext of the given payload
* type, the given default namespace and a given map of all namespaces
* to prefix mappings used in the payload. The payload is encoded using
* the given charset. The caller must provide information about the root
* class, its XML name, and its element schema. The caller must also provide
* mappings of java types to their namespaces and mappings of java packages
* to their namespaces. ITypeConversionContext is optional. If provided,
* Caller can enforce type conversion. Caller can also specify the options
* to support on-demand object node creation and
* unordered NV format.
*
* @param payloadType data format type of the payload
* @param defaultNamespace the namespace to be recognized as the default so that prefix
* is skipped for elements from this namespace.
* @param ns2Prefix namespace to namespace prefix mapping.
* @param prefix2NS namespace prefix to namespace mapping.
* @param charset Charset of the payload.
* @param rootXMLName XML QName for the root element.
* @param rootClass Class object of the root java bean object.
* @param rootSchema DataElementSchema for the root object.
* @param supportObjectNode true if the context should support accessing
* the payload as DOM.
* @param javaType2NS JavaType Class to namespace mapping;
* @param pkg2NS Java package to namespace mapping;
* @param typeConversion an object implemented the TypeConversion interface.
* It is intented to be used to support additional type conversion.
* However TypeConversion is being deprecated. Should pass in <code>null</code>
* @param isREST True if the payload is a rest request.
* @param singleNamespace the namespace of types if all the types are associated with
* only one namespace. otherwise, should leave it null.
* @return an ISerializationContext
*/
public static ISerializationContext createSerializationContext(
String payloadType,
String defaultNamespace,
Map<String, List<String>> ns2Prefix,
Map<String, String> prefix2NS,
Charset charset,
QName rootXMLName,
Class rootClass,
DataElementSchema rootSchema,
boolean supportObjectNode,
Map<Class, String> javaType2NS,
Map<String, String> pkg2NS,
ITypeConversionContext typeConversion,
boolean isREST,
String singleNamespace) {
return new SerializationContextImpl(payloadType, defaultNamespace, ns2Prefix, prefix2NS, charset,
rootXMLName, rootClass, rootSchema, supportObjectNode, pkg2NS, typeConversion, isREST,
singleNamespace);
}
/**
* Creates a type conversion context of the given bound types and value types.
* The context also defines the type converter adaptor class.
*
* @param boundTypes The type deserialized from payload
* @param valueTypes The type used in the final java bean object.
* @param typeConvertAdaptor The type converter adaptor class
* @return an ITypeConversionContext
*/
public static ITypeConversionContext createTypeConversionContext(
Collection<String> boundTypes,
Collection<Class> valueTypes,
Class typeConvertAdaptor) {
return new TypeConversionContextImpl(boundTypes, valueTypes, typeConvertAdaptor);
}
/**
* This is a simplified version of createSerializationContext. It uses the system's default charset,
* the default namespace prefix ('ns'), no object node support, no type conversion support, and
* no unordered NV support.
*
* @param msg The java bean object to be serialized.
* @param serFactory The SerializerFactory used to create the serializer.
* @param namespace The namespace of the root element.
* @param elementSchema A DataElementSchema that contains schema information for msg object. It is optional.
* @param msgClass Class of the msg object. It is optional if msg is not null.
* @return an ISerializationContext
*/
public static ISerializationContext createSerializationContext(Object msg,
ISerializerFactory serFactory, String namespace,
DataElementSchema elementSchema, Class msgClass) {
if (null == serFactory) {
throw new NullPointerException("ISerializaerFactory cannot be null.");
}
if (null == msg && null == msgClass) {
throw new NullPointerException("When msg is null, msgClass must be provided.");
}
List<String> namespaces = new ArrayList<String>(1);
if (null == namespace) {
namespace = DEFAULT_NAMESPACE;
}
namespaces.add(namespace);
Map<String, List<String>> ns2Prefix = new HashMap<String, List<String>>();
Map<String, String> prefix2NS = new HashMap<String, String>();
NamespaceConvention.buildNsPrefixes(namespaces, ns2Prefix, prefix2NS);
Class rootClass = msgClass == null? msg.getClass() : msgClass;
QName rootXMLName = new QName(namespace, rootClass.getSimpleName(), BindingConstants.DEFAULT_PREFIX);
Map<Class, String> javaType2NS = new HashMap<Class, String>(1);
javaType2NS.put(rootClass, namespace);
Map<String, String> pkg2NS = new HashMap<String, String>(1);
pkg2NS.put(rootClass.getPackage().getName(), namespace);
ISerializationContext serCtx = BindingFacade.createSerializationContext(
serFactory.getPayloadType(),
namespace,
ns2Prefix,
prefix2NS,
Charset.defaultCharset(),
rootXMLName,
rootClass,
elementSchema,
false,
javaType2NS,
pkg2NS,
null,
false);
return serCtx;
}
/**
* This is a simplified version of createSerializationContext. It uses the system's default charset,
* the default namespace prefix ('ns'), no object node support, no type conversion support, and
* no unordered NV support.
*
* @param msg The java bean object to be serialized.
* @param serFactory The SerializerFactory used to create the serializer.
* @param namespace The namespace of the root element.
* @return an ISerializationContext
*/
public static ISerializationContext createSerializationContext(Object msg, ISerializerFactory serFactory, String namespace) {
if (null == msg) {
throw new NullPointerException("msg cannot be null.");
}
return createSerializationContext(msg, serFactory, namespace, null, msg.getClass());
}
/**
* This is a simplified version of createDeserializationContext. It uses the system's default charset,
* the default namespace prefix ('ns'), no object node support, no type conversion support, and
* no unordered NV support.
*
* @param msg The payload to be deserialized.
* @param deserFactory The DeserializerFactory used to create the deserializer.
* @param namespace The namespace of the root element.
* @param elementSchema A DataElementSchema that contains schema information for msg object. It is optional.
* @param msgClass Class of the msg object. It is optional if msg is not null.
* @return an ISerializationContext
*/
public static IDeserializationContext createDeserializationContext(Object msg,
IDeserializerFactory deserFactory, String namespace,
DataElementSchema elementSchema, Class msgClass) {
if (null == deserFactory) {
throw new NullPointerException("ISerializaerFactory cannot be null");
}
if (null == msg && null == msgClass) {
throw new NullPointerException("When msg is null, msgClass must be provided.");
}
List<String> namespaces = new ArrayList<String>(1);
if (null == namespace) {
namespace = DEFAULT_NAMESPACE;
}
namespaces.add(namespace);
Map<String, List<String>> ns2Prefix = new HashMap<String, List<String>>();
Map<String, String> prefix2NS = new HashMap<String, String>();
NamespaceConvention.buildNsPrefixes(namespaces, ns2Prefix, prefix2NS);
Class rootClass = msgClass == null? msg.getClass() : msgClass;
QName rootXMLName = new QName(namespace, rootClass.getSimpleName(), BindingConstants.DEFAULT_PREFIX);
Map<Class, String> javaType2NS = new HashMap<Class, String>(1);
javaType2NS.put(rootClass, namespace);
Map<String, String> pkg2NS = new HashMap<String, String>(1);
pkg2NS.put(rootClass.getPackage().getName(), namespace);
IDeserializationContext deserCtx = BindingFacade.createDeserializationContext(
deserFactory.getPayloadType(),
namespace,
ns2Prefix,
prefix2NS,
Charset.defaultCharset(),
rootXMLName,
rootClass,
elementSchema,
false,
true,
javaType2NS,
pkg2NS,
null,
false);
return deserCtx;
}
/**
* This is a simplified version of createDeserializationContext. It uses the system's default charset,
* the default namespace prefix ('ns'), no object node support, no type conversion support, and
* no unordered NV support.
*
* @param msg The payload to be deserialized.
* @param deserFactory The DeserializerFactory used to create the deserializer.
* @param namespace The namespace of the root element.
* @return an IDeserializationContext
*/
public static IDeserializationContext createDeserializationContext(Object msg, IDeserializerFactory deserFactory, String namespace) {
if (null == msg) {
throw new NullPointerException("msg cannot be null.");
}
return createDeserializationContext(msg, deserFactory, namespace, null, msg.getClass());
}
/**
* This method provides a convinient way to call binding-framework to serialize an
* object into a payload of your choice.
*
* @param ctx The IDeserializationContext
* @param factory The IDeserializerFactory
* @param out The OutputStream to write the payload.
* @param msg The Java bean object to be serialized.
* @throws BindingException a BindingException
*/
public static void serialize(ISerializationContext ctx,
ISerializerFactory factory, OutputStream out, Object msg)
throws BindingException {
ISerializer ser = factory.getSerializer();
try {
XMLStreamWriter streamWriter = factory.getXMLStreamWriter(ctx, out);
streamWriter.writeStartDocument(ctx.getCharset().name(), "1.0");
ser.serialize(ctx, msg, streamWriter);
streamWriter.writeEndDocument();
streamWriter.close();
} catch (XMLStreamException e) {
throw new SerializationException(e);
}
}
/**
* A convenient method to serialize an object into xml payload using the given
* charset.
*
* @param obj - the object to be serialized.
* @param charsetName - the name of the charset to use.
* @return the serialized xml payload.
* @throws BindingException a BindingException.
*/
public static String serializeToXML(final Object obj, final String charsetName)
throws BindingException {
return XmlSerializationSupport.serialize(obj, charsetName);
}
/**
* A convenient method to serialize an object into xml payload using the given
* charset.
*
* @param obj - the object to be serialized.
* @param charset - the charset.
* @return the serialized xml payload.
* @throws BindingException a BindingException.
*/
public static String serializeToXML(final Object obj, final Charset charset)
throws BindingException {
return XmlSerializationSupport.serialize(obj, charset);
}
/**
* A convenient method to serialize an object into xml payload using the given
* charset.
*
* @param obj - the object to be serialized.
* @param charsetName - the name of the charset to use.
* @param os - the output stream to write the payload.
* @throws BindingException a BindingException.
*/
public static void serializeToXML(
final Object obj, final String charsetName, final OutputStream os)
throws BindingException {
XmlSerializationSupport.serialize(obj, charsetName, os);
}
/**
* A convenient method to serialize an object into xml payload using the given
* charset.
*
* @param obj - the object to be serialized.
* @param charset - the charset.
* @param os - the output stream to write the payload.
* @throws BindingException a BindingException.
*/
public static void serializeToXML(
final Object obj, final Charset charset, final OutputStream os)
throws BindingException {
XmlSerializationSupport.serialize(obj, charset, os);
}
/**
* This method provides a convinient way to call binding-framework to deserialize
* a payload into its corresponding java object.
*
* @param ctx The IDeserializationContext
* @param factory The IDeserializerFactory
* @param payload the payload to be deserialized.
* @return Java bean object deserialized from the payload.
* @throws BindingException a BindingException.
*/
public static Object deserialize(IDeserializationContext ctx,
IDeserializerFactory factory, String payload)
throws BindingException {
IDeserializer deser = factory.getDeserializer();
InputStream is = new ByteArrayInputStream(payload.getBytes());
XMLStreamReader xsr = factory.getXMLStreamReader(ctx, is);
return deser.deserialize(ctx, xsr);
}
/**
* A convenient method to deserialize an XML payload to Java bean of the given
* root class with the given charset.
* @param <T> - the type of the root java object to be created
* @param xml - the incoming XML payload.
* @param charsetName - the charset name of the XML payload.
* @param rootClz - the type of the root java object.
* @return - The java object deserialized from the xml payload.
* @throws BindingException a BindingException.
*/
public static <T> T deserializeFromXML(
final String xml, final String charsetName, final Class<T> rootClz)
throws BindingException {
return XmlSerializationSupport.deserialize(xml, charsetName, rootClz);
}
/**
* A convenient method to deserialize an XML payload to Java bean of the given
* root class with the given charset.
* @param <T> - the type of the root java object to be created
* @param xml - the incoming XML payload.
* @param charset - the charset of the XML payload.
* @param rootClz - the type of the root java object.
* @return - The java object deserialized from the xml payload.
* @throws BindingException a BindingException.
*/
public static <T> T deserializeFromXML(
final String xml, final Charset charset, final Class<T> rootClz)
throws BindingException {
return XmlSerializationSupport.deserialize(xml, charset, rootClz);
}
/**
* A convenient method to deserialize an XML payload to Java bean of the given
* root class with the given charset.
* @param <T> - the type of the root java object to be created
* @param is - the incoming XML payload stream.
* @param charsetName - the charset name of the XML payload.
* @param rootClz - the type of the root java object.
* @return - The java object deserialized from the xml payload.
* @throws BindingException a BindingException.
*/
public static <T> T deserializeFromXML(
final InputStream is, final String charsetName, final Class<T> rootClz)
throws BindingException {
return XmlSerializationSupport.deserialize(is, charsetName, rootClz);
}
/**
* A convenient method to deserialize an XML payload to Java bean of the given
* root class with the given charset.
* @param <T> - the type of the root java object to be created
* @param is - the incoming XML payload stream.
* @param charset - the charset of the XML payload.
* @param rootClz - the type of the root java object.
* @return - The java object deserialized from the xml payload.
* @throws BindingException a BindingException.
*/
public static <T> T deserializeFromXML(
final InputStream is, final Charset charset, final Class<T> rootClz)
throws BindingException {
return XmlSerializationSupport.deserialize(is, charset, rootClz);
}
/**
* The set of serializeToXML methods caches their ISerializerFactory based on the root class
* name. clearSerializerFactoryCache clears cache for ISerializerFactory
*/
public static void clearSerializerFactoryCache() {
XmlSerializationSupport.clearSerializerFactoryCache();
}
/**
* The set of serializeToXML methods caches their IDeserializerFactory based on the root class
* name. clearDeserializerFactoryCache clears cache for IDeserializerFactory
*/
public static void clearDeserializerFactoryCache() {
XmlSerializationSupport.clearDeserializerFactoryCache();
}
}