View Javadoc
1   /*
2    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
3    * The software in this package is published under the terms of the CPAL v1.0
4    * license, a copy of which has been included with this distribution in the
5    * LICENSE.txt file.
6    */
7   package org.mule.module.xml.transformer;
8   
9   import org.mule.util.ClassUtils;
10  
11  import com.thoughtworks.xstream.XStream;
12  import com.thoughtworks.xstream.converters.Converter;
13  import com.thoughtworks.xstream.converters.SingleValueConverter;
14  import com.thoughtworks.xstream.converters.collections.MapConverter;
15  import com.thoughtworks.xstream.io.HierarchicalStreamDriver;
16  import com.thoughtworks.xstream.mapper.Mapper;
17  
18  import java.util.Map;
19  import java.util.Set;
20  
21  import org.apache.commons.logging.Log;
22  import org.apache.commons.logging.LogFactory;
23  
24  /**
25   * Initializes the XStream utility for converting Objects to XML and XML to Objects.
26   */
27  // @Immutable
28  public class XStreamFactory
29  {
30      public static final String XSTREAM_DOM_DRIVER = "com.thoughtworks.xstream.io.xml.DomDriver";
31      public static final String XSTREAM_DOM4J_DRIVER = "com.thoughtworks.xstream.io.xml.Dom4JDriver";
32      public static final String XSTREAM_JDOM_DRIVER = "com.thoughtworks.xstream.io.xml.JDomDriver";
33      public static final String XSTREAM_STAX_DRIVER = "com.thoughtworks.xstream.io.xml.StaxDriver";
34      public static final String XSTREAM_XPP_DRIVER = "com.thoughtworks.xstream.io.xml.XppDriver";
35  
36      private static final Log logger = LogFactory.getLog(XStreamFactory.class);
37  
38      private final XStream xstream;
39  
40      public XStreamFactory() throws ClassNotFoundException, InstantiationException, IllegalAccessException
41      {
42          this(XSTREAM_XPP_DRIVER, null, null);
43      }
44  
45      public XStreamFactory(String driverClassName, Map<String, Class<?>> aliases, Set<Class <? extends Converter>> converters)
46          throws ClassNotFoundException, InstantiationException, IllegalAccessException
47      {
48          Class<?> driverClass = ClassUtils.loadClass(driverClassName, this.getClass());
49          xstream = new XStream((HierarchicalStreamDriver) driverClass.newInstance());
50  
51          // We must always register this converter as the Mule Message uses
52          // ConcurrentHashMaps, but XStream currently does not support them out of the
53          // box.
54          xstream.registerConverter(new XStreamFactory.ConcurrentHashMapConverter(xstream.getMapper()), -1);
55  
56          registerAliases(aliases);
57          registerConverters(converters);
58      }
59  
60      private void registerAliases(Map<String, Class<?>> aliases)
61      {
62          if (aliases != null)
63          {
64              for (Map.Entry<String, Class<?>> entry : aliases.entrySet())
65              {
66                  xstream.alias(entry.getKey(), entry.getValue());
67              }
68          }
69      }
70  
71      private void registerConverters(Set<Class <? extends Converter>> converters) throws InstantiationException, IllegalAccessException
72      {
73          if (converters != null)
74          {
75              for (Class<?> converter : converters)
76              {
77                  Object converterInstance = converter.newInstance();
78                  if (converterInstance instanceof Converter)
79                  {
80                      xstream.registerConverter((Converter) converterInstance);
81                  }
82                  else if (converterInstance instanceof SingleValueConverter)
83                  {
84                      xstream.registerConverter((SingleValueConverter) converterInstance);
85                  }
86                  else
87                  {
88                      logger.warn("Invalid converter class specified - ignoring: " + converter.getName());
89                  }
90              }
91          }
92      }
93  
94      public final XStream getInstance()
95      {
96          return xstream;
97      }
98  
99      private class ConcurrentHashMapConverter extends MapConverter
100     {
101         public ConcurrentHashMapConverter(Mapper mapper) throws ClassNotFoundException
102         {
103             super(mapper);
104         }
105 
106         @Override
107         @SuppressWarnings("rawtypes")
108         public boolean canConvert(Class aClass)
109         {
110             String className = aClass.getName();
111             return className.equals("java.util.concurrent.ConcurrentHashMap")
112                             || className.equals("edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap");
113         }
114     }
115 }