1   package org.kuali.rice.krad.service.impl;
2   
3   import com.thoughtworks.xstream.XStream;
4   import com.thoughtworks.xstream.converters.MarshallingContext;
5   import com.thoughtworks.xstream.converters.UnmarshallingContext;
6   import com.thoughtworks.xstream.converters.collections.CollectionConverter;
7   import com.thoughtworks.xstream.converters.reflection.ObjectAccessException;
8   import com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider;
9   import com.thoughtworks.xstream.converters.reflection.ReflectionConverter;
10  import com.thoughtworks.xstream.converters.reflection.ReflectionProvider;
11  import com.thoughtworks.xstream.io.HierarchicalStreamReader;
12  import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
13  import com.thoughtworks.xstream.mapper.Mapper;
14  import org.apache.commons.logging.Log;
15  import org.apache.commons.logging.LogFactory;
16  import org.apache.ojb.broker.core.proxy.ListProxyDefaultImpl;
17  import org.apache.ojb.broker.core.proxy.SetProxyDefaultImpl;
18  import org.kuali.rice.krad.service.KRADServiceLocator;
19  import org.kuali.rice.krad.service.PersistenceService;
20  import org.kuali.rice.krad.service.XmlObjectSerializerService;
21  
22  import java.lang.reflect.Field;
23  import java.util.*;
24  
25  
26  
27  
28  public class XmlObjectSerializerServiceImpl implements XmlObjectSerializerService {
29      private static final Log LOG = LogFactory.getLog(XmlObjectSerializerServiceImpl.class);
30  
31  
32      private PersistenceService persistenceService;
33  
34      private XStream xstream;
35  
36      public XmlObjectSerializerServiceImpl() {
37          xstream = new XStream(new ProxyAwareJavaReflectionProvider());
38          xstream.registerConverter(new ProxyConverter(xstream.getMapper(), xstream.getReflectionProvider()));
39          xstream.addDefaultImplementation(ArrayList.class, ListProxyDefaultImpl.class);
40  
41          
42          
43          xstream.registerConverter(new ListProxyDefaultImplConverter(xstream.getMapper()));
44          xstream.registerConverter(new SetProxyDefaultImplConverter(xstream.getMapper()));
45      }
46  
47      
48  
49  
50  
51      public String toXml(Object object) {
52          if (LOG.isDebugEnabled()) {
53              LOG.debug("toXml(" + object + ") : \n" + xstream.toXML(object));
54          }
55          return xstream.toXML(object);
56      }
57  
58      
59  
60  
61  
62      public Object fromXml(String xml) {
63          if (LOG.isDebugEnabled()) {
64              LOG.debug("fromXml() : \n" + xml);
65          }
66          if (xml != null) {
67              xml = xml.replaceAll("--EnhancerByCGLIB--[0-9a-f]{0,8}", "");
68          }
69          return xstream.fromXML(xml);
70      }
71  
72      
73  
74  
75  
76      public class ProxyConverter extends ReflectionConverter {
77          public ProxyConverter(Mapper mapper, ReflectionProvider reflectionProvider) {
78              super(mapper, reflectionProvider);
79          }
80  
81          @Override
82          
83          
84          @SuppressWarnings("unchecked")
85          public boolean canConvert(Class clazz) {
86              return clazz.getName().contains("CGLIB");
87          }
88  
89          @Override
90          public void marshal(Object obj, HierarchicalStreamWriter writer, MarshallingContext context) {
91              super.marshal(getPersistenceService().resolveProxy(obj), writer, context);
92          }
93  
94          
95      }
96  
97      public class ProxyAwareJavaReflectionProvider extends PureJavaReflectionProvider {
98  
99          public ProxyAwareJavaReflectionProvider() {
100             super();
101         }
102 
103         
104 
105 
106         @Override
107         public void visitSerializableFields(Object object, Visitor visitor) {
108             for (Iterator iterator = fieldDictionary.fieldsFor(object.getClass()); iterator.hasNext(); ) {
109                 Field field = (Field) iterator.next();
110                 if (!fieldModifiersSupported(field)) {
111                     continue;
112                 }
113                 validateFieldAccess(field);
114                 Object value = null;
115                 try {
116                     value = field.get(object);
117                     if (value != null && getPersistenceService().isProxied(value)) {
118                         value = getPersistenceService().resolveProxy(value);
119                     }
120                 } catch (IllegalArgumentException e) {
121                     throw new ObjectAccessException("Could not get field " + field.getClass() + "." + field.getName(), e);
122                 } catch (IllegalAccessException e) {
123                     throw new ObjectAccessException("Could not get field " + field.getClass() + "." + field.getName(), e);
124                 }
125                 visitor.visit(field.getName(), field.getType(), field.getDeclaringClass(), value);
126             }
127         }
128 
129 
130     }
131 
132     public PersistenceService getPersistenceService() {
133         if (persistenceService == null) {
134             persistenceService = KRADServiceLocator.getPersistenceService();
135         }
136         return persistenceService;
137     }
138 
139 
140     
141 
142 
143 
144     private static class ListProxyDefaultImplConverter extends CollectionConverter {
145 
146         ListProxyDefaultImplConverter(Mapper mapper) {
147             super(mapper);
148         }
149 
150         @Override
151         @SuppressWarnings("unchecked")
152         public boolean canConvert(Class type) {
153             return ListProxyDefaultImpl.class.equals(type);
154         }
155 
156         
157 
158 
159         @Override
160         @SuppressWarnings("unchecked")
161         public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
162 
163             
164             ArrayList altered = new ArrayList((List) source);
165             
166             super.marshal(altered, writer, context);
167         }
168 
169         
170 
171 
172 
173 
174 
175         @Override
176         @SuppressWarnings("unchecked")
177         public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
178 
179             ArrayList result = null;
180 
181             while (reader.hasMoreChildren()) {
182                 try {
183                     reader.moveDown();
184 
185                     if (reader.getNodeName().startsWith("_")) {
186                         
187                     } else {
188                         if (result == null) {
189                             result = new ArrayList();
190                         } 
191                         addCurrentElementToCollection(reader, context, result, result);
192                     }
193                 } finally {
194                     reader.moveUp();
195                 }
196             }
197 
198             return result;
199         }
200     }
201 
202 
203     
204 
205 
206 
207     private static class SetProxyDefaultImplConverter extends CollectionConverter {
208 
209         SetProxyDefaultImplConverter(Mapper mapper) {
210             super(mapper);
211         }
212 
213         @Override
214         @SuppressWarnings("unchecked")
215         public boolean canConvert(Class type) {
216             return SetProxyDefaultImpl.class.equals(type);
217         }
218 
219         
220 
221 
222         @Override
223         @SuppressWarnings("unchecked")
224         public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
225 
226             
227             HashSet altered = new HashSet((Set) source);
228             
229             super.marshal(altered, writer, context);
230         }
231 
232         
233 
234 
235 
236 
237 
238         @Override
239         @SuppressWarnings("unchecked")
240         public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
241 
242             HashSet result = null;
243 
244             while (reader.hasMoreChildren()) {
245                 try {
246                     reader.moveDown();
247 
248                     if (reader.getNodeName().startsWith("_")) {
249                         
250                     } else {
251                         if (result == null) {
252                             result = new HashSet();
253                         } 
254                         addCurrentElementToCollection(reader, context, result, result);
255                     }
256                 } finally {
257                     reader.moveUp();
258                 }
259             }
260 
261             return result;
262         }
263     }
264 }