View Javadoc

1   /**********************************************************************
2    * CastorAdapter.java
3    * created on 11.03.2005 by netseeker
4    * $Source: /cvsroot/ejoe/EJOE/src/de/netseeker/ejoe/adapter/CastorAdapter.java,v $
5    * $Date: 2007/11/17 11:20:34 $
6    * $Revision: 1.23 $
7    *********************************************************************/
8   package de.netseeker.ejoe.adapter;
9   
10  import java.io.IOException;
11  import java.io.InputStream;
12  import java.io.InputStreamReader;
13  import java.io.OutputStream;
14  import java.io.OutputStreamWriter;
15  import java.io.Writer;
16  import java.net.URL;
17  
18  import org.castor.mapping.BindingType;
19  import org.exolab.castor.mapping.Mapping;
20  import org.exolab.castor.mapping.MappingException;
21  import org.exolab.castor.xml.ClassDescriptorResolverFactory;
22  import org.exolab.castor.xml.Marshaller;
23  import org.exolab.castor.xml.Unmarshaller;
24  import org.exolab.castor.xml.util.XMLClassDescriptorResolverImpl;
25  
26  import de.netseeker.ejoe.EJConstants;
27  import de.netseeker.ejoe.io.IOUtil;
28  
29  /***
30   * An adapter for (de)serializing objects via the Castor XML library. This adapter implementation uses the performance
31   * hints described in the Castor Marshalling FAQ, that means it does:
32   * <ul>
33   * <li>reuse the castor mapping repository</li>
34   * <li>cache the class desciptors of already marshalled/unmarshalled objects</li>
35   * <li>disable validation per default</li>
36   * </ul>
37   * Furthermore it does reuse one Unmarshaller instance.
38   * 
39   * @link http://castor.codehaus.org/xml-faq.html#How-can-I-speed-up-marshalling/unmarshalling-performance
40   * @link http://castor.codehaus.org/
41   * @author netseeker
42   */
43  public class CastorAdapter extends BaseAdapter
44  {
45      private static final long                     serialVersionUID = 1L;
46  
47      private Mapping                               _mapping;
48  
49      private transient Unmarshaller                _unmarshaller;
50  
51      private static XMLClassDescriptorResolverImpl _cdr;
52  
53      private boolean                               _validate        = false;
54  
55      static
56      {
57          if ( _cdr == null )
58          {
59              _cdr = (XMLClassDescriptorResolverImpl) ClassDescriptorResolverFactory
60                      .createClassDescriptorResolver( BindingType.XML );
61          }
62      }
63  
64      /***
65       * Creates a new instance of this adapter.
66       */
67      public CastorAdapter()
68      {
69          try
70          {
71              initCastor( false );
72          }
73          catch ( MappingException e )
74          {
75              // can't happen
76          }
77      }
78  
79      /***
80       * Creates a new instance of this adapter. Castor validation is enabled/disabled according to the given value.
81       * 
82       * @param validate either Castor validation should be enabled or not.
83       */
84      public CastorAdapter(boolean validate)
85      {
86          try
87          {
88              initCastor( validate );
89          }
90          catch ( MappingException e )
91          {
92              // can't happen
93          }
94      }
95  
96      /***
97       * Creates a new instance of this adapter using the given Castor mapping.
98       * 
99       * @param mapping existing Castor mapping to use
100      * @throws MappingException
101      */
102     public CastorAdapter(Mapping mapping) throws MappingException
103     {
104         _mapping = mapping;
105         initCastor( false );
106     }
107 
108     /***
109      * Creates a new instance of this adapter using the Castor mapping loaded from the given mapping file.
110      * 
111      * @param pathToMappingFile path of the Castor mapping file to use
112      * @throws IOException
113      * @throws MappingException
114      */
115     public CastorAdapter(String pathToMappingFile) throws IOException, MappingException
116     {
117         this();
118         _mapping = new Mapping();
119         _mapping.loadMapping( pathToMappingFile );
120         initCastor( false );
121     }
122 
123     /***
124      * Creates a new instance of this adapter using the Castor mapping loaded from the given mapping file.
125      * 
126      * @param pathToMappingFile path of the Castor mapping file to use
127      * @throws IOException
128      * @throws MappingException
129      */
130     public CastorAdapter(URL pathToMappingFile) throws IOException, MappingException
131     {
132         this();
133         _mapping = new Mapping();
134         _mapping.loadMapping( pathToMappingFile );
135         initCastor( false );
136     }
137 
138     /***
139      * Either enables or disables Castors validation feature.
140      * 
141      * @param enable
142      */
143     public void setValidation( boolean enable )
144     {
145         _unmarshaller.setValidation( enable );
146     }
147 
148     private void initCastor( boolean validate ) throws MappingException
149     {
150         _validate = validate;
151 
152         // _cdr = new XMLClassDescriptorResolverImpl();
153         if ( _mapping != null )
154         {
155             _unmarshaller = new Unmarshaller( _mapping );
156         }
157         else
158         {
159             _unmarshaller = new Unmarshaller();
160         }
161         // _unmarshaller.setResolver(_cdr);
162         _unmarshaller.setValidation( validate );
163 
164         _unmarshaller.setResolver( _cdr );
165     }
166 
167     private Unmarshaller getUnMarshaller()
168     {
169         if ( this._unmarshaller == null )
170         {
171             try
172             {
173                 initCastor( _validate );
174             }
175             catch ( MappingException e )
176             {
177                 // can't happen
178             }
179         }
180 
181         return _unmarshaller;
182     }
183 
184     /*
185      * (non-Javadoc)
186      * 
187      * @see de.netseeker.ejoe.adapter.SerializeAdapter#read(java.io.InputStream)
188      */
189     public Object read( InputStream in ) throws Exception
190     {
191         InputStreamReader reader = new InputStreamReader( in, EJConstants.EJOE_DEFAULT_CHARSET ); 
192         try
193         {
194             return getUnMarshaller().unmarshal( reader );
195         }
196         finally
197         {
198             IOUtil.closeQuiet( reader );
199         }
200     }
201 
202     /*
203      * (non-Javadoc)
204      * 
205      * @see de.netseeker.ejoe.adapter.SerializeAdapter#write(java.lang.Object, java.io.OutputStream)
206      */
207     public void write( Object obj, OutputStream out ) throws Exception
208     {
209         Writer writer = new OutputStreamWriter( out, EJConstants.EJOE_DEFAULT_CHARSET );
210         Marshaller marshaller = new Marshaller( writer );
211         try
212         {
213             if ( _mapping != null )
214             {
215                 marshaller.setMapping( _mapping );
216             }
217             // marshaller.setResolver(_cdr);
218             marshaller.setValidation( false );
219             marshaller.setSuppressXSIType( false );
220             marshaller.setUseXSITypeAtRoot( true );
221             marshaller.setMarshalExtendedType( true );
222             marshaller.setResolver( _cdr );
223             marshaller.marshal( obj );
224         }
225         finally
226         {
227             IOUtil.closeQuiet( writer );
228         }
229     }
230 
231     /*
232      * (non-Javadoc)
233      * 
234      * @see de.netseeker.ejoe.adapter.SerializeAdapter#handleClassLoaderChange(java.lang.ClassLoader)
235      */
236     public void handleClassLoaderChange( ClassLoader classLoader )
237     {
238         _unmarshaller.setClassLoader( classLoader );
239     }
240 
241     /*
242      * (non-Javadoc)
243      * 
244      * @see de.netseeker.ejoe.adapter.BaseAdapter#requiresCustomEOFHandling()
245      */
246     public boolean requiresCustomEOFHandling()
247     {
248         return true;
249     }
250 
251     /*
252      * (non-Javadoc)
253      * 
254      * @see de.netseeker.ejoe.adapter.BaseAdapter#getContentType()
255      */
256     public String getContentType()
257     {
258         return "text/xml";
259     }
260 }