root/trunk/src/java/org/jcoderz/commons/util/JaxbUtil.java

Revision 1011, 13.4 kB (checked in by amandel, 4 years ago)

Aligned svn keyword settings.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1/*
2 * $Id$
3 *
4 * Copyright 2006, The jCoderZ.org Project. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 *    * Redistributions of source code must retain the above copyright
11 *      notice, this list of conditions and the following disclaimer.
12 *    * Redistributions in binary form must reproduce the above
13 *      copyright notice, this list of conditions and the following
14 *      disclaimer in the documentation and/or other materials
15 *      provided with the distribution.
16 *    * Neither the name of the jCoderZ.org Project nor the names of
17 *      its contributors may be used to endorse or promote products
18 *      derived from this software without specific prior written
19 *      permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33 package org.jcoderz.commons.util;
34
35import java.io.ByteArrayOutputStream;
36import java.util.ArrayList;
37import java.util.Collections;
38import java.util.HashMap;
39import java.util.List;
40import java.util.Map;
41import java.util.logging.Level;
42import java.util.logging.Logger;
43
44import javax.xml.bind.JAXBContext;
45import javax.xml.bind.JAXBException;
46import javax.xml.bind.Marshaller;
47import javax.xml.bind.Unmarshaller;
48import javax.xml.bind.ValidationEvent;
49import javax.xml.bind.ValidationEventHandler;
50import javax.xml.bind.ValidationEventLocator;
51
52import org.jcoderz.commons.ArgumentMalformedException;
53import org.jcoderz.commons.RteLogMessage;
54import org.xml.sax.InputSource;
55
56
57/**
58 * Utility class to simplify JAXB marshalling/unmarshalling.
59 * @author Albrecht Messner
60 */
61public final class JaxbUtil
62{
63   private static final Map JAXB_CONTEXT_MAP = new HashMap();
64
65
66   private JaxbUtil ()
67   {
68      // avoid instantiation of utility class
69   }
70
71   /**
72    * Returns a JAXB context for the given context path. Contexts are
73    * cached in a hash map.
74    * @param contextPath the JAXB context path
75    * @return the jaxb context for the given context path
76    * @throws JAXBException if the context could not be retrieved
77    */
78   public static synchronized JAXBContext getJaxbContext (String contextPath)
79         throws JAXBException
80   {
81      JAXBContext ctx = (JAXBContext) JAXB_CONTEXT_MAP.get(contextPath);
82      if (ctx == null)
83      {
84         ctx = JAXBContext.newInstance(contextPath);
85         JAXB_CONTEXT_MAP.put(contextPath, ctx);
86      }
87      return ctx;
88   }
89
90   /**
91    * Unmarshals the given InputSource and returns the unmarshalled object
92    * along with the validation event collector.
93    * @param data the data to unmarshal
94    * @param ctxPath the context path from which the JAXBContext is created
95    *       to create an unmarshaller
96    * @return the unmarshalled object along with its validation events
97    * @throws JAXBException if unmarshalling or validation fails.
98    */
99   public static UnmarshalResult unmarshal (InputSource data, String ctxPath)
100         throws JAXBException
101   {
102      final JAXBContext ctx = getJaxbContext(ctxPath);
103      return unmarshal(data, ctx);
104   }
105
106   /**
107    * Unmarshals the given InputSource and returns the unmarshalled object
108    * along with the validation event collector.
109    * @param data the data to unmarshal
110    * @param ctx the JAXBContext from which the unmarshaller should be
111    *       retrieved
112    * @return the unmarshalled object along with its validation events
113    * @throws JAXBException if unmarshalling or validation fails.
114    */
115   public static UnmarshalResult unmarshal (InputSource data, JAXBContext ctx)
116         throws JAXBException
117   {
118      final Unmarshaller unmarsh = ctx.createUnmarshaller();
119      unmarsh.setValidating(true);
120      final ValidationEventCollector evtHandler
121            = new ValidationEventCollector();
122      unmarsh.setEventHandler(evtHandler);
123      final Object parsedData = unmarsh.unmarshal(data);
124      return new UnmarshalResult(parsedData, evtHandler);
125   }
126
127   /**
128    * Serializes (marshals) a given JAXB object and returns the result as
129    * byte array, along with the validation events collected during
130    * marshalling.
131    * @param data the object to marshal
132    * @param contextPath the context path to retrieve the corresponding JAXB
133    *       context for.
134    * @return the marshalled object and marshalling events
135    * @throws JAXBException if marshalling or validation fails.
136    */
137   public static MarshalResult marshal (Object data, String contextPath)
138         throws JAXBException
139   {
140      final JAXBContext ctx = getJaxbContext(contextPath);
141      return marshal(data, ctx);
142   }
143
144   /**
145    * Serializes (marshals) a given JAXB object and returns the result as
146    * byte array, along with the validation events collected during
147    * marshalling.
148    * @param data the object to marshal
149    * @param ctx the JAXBContext from which the unmarshaller can be retrieved.
150    * @return the marshalled object and marshalling events
151    * @throws JAXBException if marshalling or validation fails.
152    */
153   public static MarshalResult marshal (Object data, JAXBContext ctx)
154         throws JAXBException
155   {
156      final Marshaller marsh = ctx.createMarshaller();
157      final ValidationEventCollector evtHandler
158            = new ValidationEventCollector();
159      marsh.setEventHandler(evtHandler);
160      final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
161      marsh.marshal(data, outStream);
162      final MarshalResult result
163            = new MarshalResult(outStream.toByteArray(), evtHandler);
164      return result;
165   }
166
167   /**
168    * Holds the Result of an unmarshal operation.
169    * @author Albrecht Messner
170    */
171   public static class UnmarshalResult
172   {
173      private final Object mParsedData;
174      private final ValidationEventCollector mValidationEvents;
175
176      UnmarshalResult (Object parsedData, ValidationEventCollector evtHandler)
177      {
178         mParsedData = parsedData;
179         mValidationEvents = evtHandler;
180      }
181
182      /**
183       * Returns the parsed (unmarshalled) object.
184       * @return the parsed (unmarshalled) object.
185       */
186      public Object getParsedData ()
187      {
188         return mParsedData;
189      }
190
191      /**
192       * Returns the validation events of the unmarshal operation.
193       * @return the validation events of the unmarshal operation.
194       */
195      public ValidationEventCollector getValidationEvents ()
196      {
197         return mValidationEvents;
198      }
199   }
200
201   /**
202    * Holds the Result of an Marshal operation.
203    * @author Albrecht Messner
204    */
205   public static class MarshalResult
206   {
207      private final byte[] mMarshalledData;
208      private final ValidationEventCollector mValidationEvents;
209
210      MarshalResult (byte[] marshalledData, ValidationEventCollector evtHandler)
211      {
212         mMarshalledData = marshalledData;
213         mValidationEvents = evtHandler;
214      }
215
216      /**
217       * Returns the marshalled object.
218       * @return the marshalled object.
219       */
220      public byte[] getMarshalledData ()
221      {
222         return mMarshalledData;
223      }
224
225      /**
226       * Returns the validation events of the marshal operation.
227       * @return the validation events of the marshal operation.
228       */
229      public ValidationEventCollector getValidationEvents ()
230      {
231         return mValidationEvents;
232      }
233   }
234
235   /**
236    * Validation handler for JAXB.
237    *
238    * @author Michael Griffel
239    */
240   public static class ValidationEventCollector
241         implements ValidationEventHandler
242   {
243      private static final String CLASSNAME
244            = ValidationEventCollector.class.getName();
245
246      private static final Logger logger = Logger.getLogger(CLASSNAME);
247
248      private final List mEvents = new ArrayList();
249
250      /**
251       * Returns all the collected errors and warnings or an empty list
252       * if there weren't any. The result is an unmodifiable list.
253       *
254       * @return all the collected errors and warnings or an empty list
255       *      if there weren't any. The result is an unmodifiable list.
256       */
257      public List getEvents ()
258      {
259         return Collections.unmodifiableList(mEvents);
260      }
261
262      /**
263       * Clear all collected errors and warnings.
264       */
265      public void reset ()
266      {
267         mEvents.clear();
268      }
269
270      /**
271       * Returns true if this event collector contains at least one
272       * ValidationEvent.
273       *
274       * @return true if this event collector contains at least one
275       *         ValidationEvent, false otherwise
276       */
277      public boolean hasEvents ()
278      {
279         return mEvents.size() != 0;
280      }
281
282      /** {@inheritDoc} */
283      public boolean handleEvent (ValidationEvent event)
284      {
285         final String methodName = "handleEvent";
286         if (logger.isLoggable(Level.FINER))
287         {
288            logger.entering(CLASSNAME, methodName, event);
289            logger.finer("Event details: "
290                  + eventToString(new StringBuffer(), event));
291         }
292
293         mEvents.add(event);
294
295         final boolean doContinue
296               = event.getSeverity() != ValidationEvent.FATAL_ERROR;
297
298         if (logger.isLoggable(Level.FINER))
299         {
300            logger.exiting(CLASSNAME, methodName, String.valueOf(doContinue));
301         }
302         return doContinue;
303      }
304
305      /**
306       * Returns a summary of the validation events as String.
307       * @return a summary of the validation events as String.
308       */
309      public String toString ()
310      {
311         final StringBuffer sb = new StringBuffer();
312         for (int i = 0; i < mEvents.size(); ++i)
313         {
314            sb.append('[');
315            sb.append(i + 1);
316            sb.append('/');
317            sb.append(mEvents.size());
318            sb.append("] ");
319            final ValidationEvent e = (ValidationEvent) mEvents.get(i);
320            eventToString(sb, e);
321         }
322         return sb.toString().trim();
323      }
324
325      private StringBuffer eventToString (
326            final StringBuffer sb, final ValidationEvent e)
327      {
328         appendLocator(sb, e.getLocator());
329
330         if (e.getLinkedException() != null)
331         {
332            appendLinkedException(sb, e);
333         }
334         else
335         {
336            sb.append(e.getMessage());
337         }
338         appendSpace(sb);
339
340         return sb;
341      }
342
343      private void appendLinkedException (final StringBuffer sb,
344            final ValidationEvent e)
345      {
346         final String causeMessage = e.getLinkedException().getMessage();
347         if (!e.getMessage().equals(causeMessage))
348         {
349            if (e.getLinkedException() instanceof ArgumentMalformedException)
350            {
351               final ArgumentMalformedException ame
352                     = (ArgumentMalformedException) e.getLinkedException();
353               sb.append("The Argument ");
354               sb.append(getParameter(
355                     ame, RteLogMessage.ArgumentMalformed.PARAM_ARGUMENT_NAME));
356               sb.append(" with the value '");
357               sb.append(getParameter(ame,
358                     RteLogMessage.ArgumentMalformed.PARAM_ARGUMENT_VALUE));
359               sb.append("' is malformed. ");
360               sb.append(getParameter(
361                     ame, RteLogMessage.ArgumentMalformed.PARAM_HINT));
362            }
363            else
364            {
365               sb.append(e.getMessage());
366               if (causeMessage != null)
367               {
368                  sb.append(" Cause: ");
369                  sb.append(causeMessage);
370               }
371            }
372         }
373         else
374         {
375            sb.append(e.getMessage());
376         }
377      }
378
379      private void appendLocator (final StringBuffer sb,
380            ValidationEventLocator locator)
381      {
382         if (locator != null)
383         {
384            if (locator.getObject() != null)
385            {
386              sb.append("Object: ");
387              sb.append(locator.getObject());
388              appendSpace(sb);
389            }
390            if (locator.getNode() != null)
391            {
392              sb.append("Node: ");
393              sb.append(locator.getObject());
394              appendSpace(sb);
395            }
396            if (locator.getOffset() >= 0)
397            {
398               sb.append("Offset: ");
399               sb.append(locator.getOffset());
400               appendSpace(sb);
401            }
402         }
403      }
404
405      /** Simply appends a spece to the given StringBuffer. */
406      private final StringBuffer appendSpace (final StringBuffer sb)
407      {
408         return sb.append(' ');
409      }
410
411      private String getParameter (ArgumentMalformedException ex, String name)
412      {
413         final List parameters = ex.getParameter(name);
414         final String result;
415         if (parameters != null)
416         {
417            result = (String) parameters.get(0);
418         }
419         else
420         {
421            result = "";
422         }
423         return result;
424      }
425   }
426
427}
Note: See TracBrowser for help on using the browser.