/*********************************************************************
* CastorAdapter.java
* created on 11.03.2005 by netseeker
* $Source: /cvsroot/ejoe/EJOE/src/de/netseeker/ejoe/adapter/CastorAdapter.java,v $
* $Date: 2007/11/17 11:20:34 $
* $Revision: 1.23 $
*********************************************************************/
package de.netseeker.ejoe.adapter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.URL;
import org.castor.mapping.BindingType;
import org.exolab.castor.mapping.Mapping;
import org.exolab.castor.mapping.MappingException;
import org.exolab.castor.xml.ClassDescriptorResolverFactory;
import org.exolab.castor.xml.Marshaller;
import org.exolab.castor.xml.Unmarshaller;
import org.exolab.castor.xml.util.XMLClassDescriptorResolverImpl;
import de.netseeker.ejoe.EJConstants;
import de.netseeker.ejoe.io.IOUtil;
/**
* An adapter for (de)serializing objects via the Castor XML library. This adapter implementation uses the performance
* hints described in the Castor Marshalling FAQ, that means it does:
* <ul>
* <li>reuse the castor mapping repository</li>
* <li>cache the class desciptors of already marshalled/unmarshalled objects</li>
* <li>disable validation per default</li>
* </ul>
* Furthermore it does reuse one Unmarshaller instance.
*
* @link http://castor.codehaus.org/xml-faq.html#How-can-I-speed-up-marshalling/unmarshalling-performance
* @link http://castor.codehaus.org/
* @author netseeker
*/
public class CastorAdapter extends BaseAdapter
{
private static final long serialVersionUID = 1L;
private Mapping _mapping;
private transient Unmarshaller _unmarshaller;
private static XMLClassDescriptorResolverImpl _cdr;
private boolean _validate = false;
static
{
if ( _cdr == null )
{
_cdr = (XMLClassDescriptorResolverImpl) ClassDescriptorResolverFactory
.createClassDescriptorResolver( BindingType.XML );
}
}
/**
* Creates a new instance of this adapter.
*/
public CastorAdapter()
{
try
{
initCastor( false );
}
catch ( MappingException e )
{
// can't happen
}
}
/**
* Creates a new instance of this adapter. Castor validation is enabled/disabled according to the given value.
*
* @param validate either Castor validation should be enabled or not.
*/
public CastorAdapter(boolean validate)
{
try
{
initCastor( validate );
}
catch ( MappingException e )
{
// can't happen
}
}
/**
* Creates a new instance of this adapter using the given Castor mapping.
*
* @param mapping existing Castor mapping to use
* @throws MappingException
*/
public CastorAdapter(Mapping mapping) throws MappingException
{
_mapping = mapping;
initCastor( false );
}
/**
* Creates a new instance of this adapter using the Castor mapping loaded from the given mapping file.
*
* @param pathToMappingFile path of the Castor mapping file to use
* @throws IOException
* @throws MappingException
*/
public CastorAdapter(String pathToMappingFile) throws IOException, MappingException
{
this();
_mapping = new Mapping();
_mapping.loadMapping( pathToMappingFile );
initCastor( false );
}
/**
* Creates a new instance of this adapter using the Castor mapping loaded from the given mapping file.
*
* @param pathToMappingFile path of the Castor mapping file to use
* @throws IOException
* @throws MappingException
*/
public CastorAdapter(URL pathToMappingFile) throws IOException, MappingException
{
this();
_mapping = new Mapping();
_mapping.loadMapping( pathToMappingFile );
initCastor( false );
}
/**
* Either enables or disables Castors validation feature.
*
* @param enable
*/
public void setValidation( boolean enable )
{
_unmarshaller.setValidation( enable );
}
private void initCastor( boolean validate ) throws MappingException
{
_validate = validate;
// _cdr = new XMLClassDescriptorResolverImpl();
if ( _mapping != null )
{
_unmarshaller = new Unmarshaller( _mapping );
}
else
{
_unmarshaller = new Unmarshaller();
}
// _unmarshaller.setResolver(_cdr);
_unmarshaller.setValidation( validate );
_unmarshaller.setResolver( _cdr );
}
private Unmarshaller getUnMarshaller()
{
if ( this._unmarshaller == null )
{
try
{
initCastor( _validate );
}
catch ( MappingException e )
{
// can't happen
}
}
return _unmarshaller;
}
/*
* (non-Javadoc)
*
* @see de.netseeker.ejoe.adapter.SerializeAdapter#read(java.io.InputStream)
*/
public Object read( InputStream in ) throws Exception
{
InputStreamReader reader = new InputStreamReader( in, EJConstants.EJOE_DEFAULT_CHARSET );
try
{
return getUnMarshaller().unmarshal( reader );
}
finally
{
IOUtil.closeQuiet( reader );
}
}
/*
* (non-Javadoc)
*
* @see de.netseeker.ejoe.adapter.SerializeAdapter#write(java.lang.Object, java.io.OutputStream)
*/
public void write( Object obj, OutputStream out ) throws Exception
{
Writer writer = new OutputStreamWriter( out, EJConstants.EJOE_DEFAULT_CHARSET );
Marshaller marshaller = new Marshaller( writer );
try
{
if ( _mapping != null )
{
marshaller.setMapping( _mapping );
}
// marshaller.setResolver(_cdr);
marshaller.setValidation( false );
marshaller.setSuppressXSIType( false );
marshaller.setUseXSITypeAtRoot( true );
marshaller.setMarshalExtendedType( true );
marshaller.setResolver( _cdr );
marshaller.marshal( obj );
}
finally
{
IOUtil.closeQuiet( writer );
}
}
/*
* (non-Javadoc)
*
* @see de.netseeker.ejoe.adapter.SerializeAdapter#handleClassLoaderChange(java.lang.ClassLoader)
*/
public void handleClassLoaderChange( ClassLoader classLoader )
{
_unmarshaller.setClassLoader( classLoader );
}
/*
* (non-Javadoc)
*
* @see de.netseeker.ejoe.adapter.BaseAdapter#requiresCustomEOFHandling()
*/
public boolean requiresCustomEOFHandling()
{
return true;
}
/*
* (non-Javadoc)
*
* @see de.netseeker.ejoe.adapter.BaseAdapter#getContentType()
*/
public String getContentType()
{
return "text/xml";
}
}