View Javadoc

1   /**
2    * Copyright 2005-2013 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.krad.service.impl;
17  
18  import com.thoughtworks.xstream.XStream;
19  import com.thoughtworks.xstream.converters.MarshallingContext;
20  import com.thoughtworks.xstream.converters.UnmarshallingContext;
21  import com.thoughtworks.xstream.converters.collections.CollectionConverter;
22  import com.thoughtworks.xstream.converters.reflection.ObjectAccessException;
23  import com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider;
24  import com.thoughtworks.xstream.converters.reflection.ReflectionConverter;
25  import com.thoughtworks.xstream.converters.reflection.ReflectionProvider;
26  import com.thoughtworks.xstream.io.HierarchicalStreamReader;
27  import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
28  import com.thoughtworks.xstream.mapper.Mapper;
29  import org.apache.ojb.broker.core.proxy.ListProxyDefaultImpl;
30  import org.apache.ojb.broker.core.proxy.ProxyHelper;
31  import org.kuali.rice.krad.document.Document;
32  import org.kuali.rice.krad.service.DocumentSerializerService;
33  import org.kuali.rice.krad.service.PersistenceService;
34  import org.kuali.rice.krad.service.SerializerService;
35  import org.kuali.rice.krad.service.XmlObjectSerializerService;
36  import org.kuali.rice.krad.util.DateTimeConverter;
37  import org.kuali.rice.krad.util.documentserializer.AlwaysTruePropertySerializibilityEvaluator;
38  import org.kuali.rice.krad.util.documentserializer.PropertySerializabilityEvaluator;
39  import org.kuali.rice.krad.util.documentserializer.PropertyType;
40  import org.kuali.rice.krad.util.documentserializer.SerializationState;
41  import org.springframework.util.AutoPopulatingList;
42  
43  import java.lang.reflect.Field;
44  import java.util.ArrayList;
45  import java.util.Iterator;
46  import java.util.List;
47  
48  /**
49   * Default implementation of the {@link DocumentSerializerService}.  If no <workflowProperties> have been defined in the
50   * data dictionary for a document type (i.e. {@link Document#getDocumentPropertySerizabilityEvaluator()} returns an instance of 
51   * {@link AlwaysTruePropertySerializibilityEvaluator}), then this service will revert to using the {@link XmlObjectSerializerService}
52   * bean, which was the old way of serializing a document for routing.  If workflowProperties are defined, then this implementation
53   * will selectively serialize items.
54   */
55  public abstract class SerializerServiceBase implements SerializerService  {
56  //	private static final Log LOG = LogFactory.getLog(SerializerServiceBase.class);
57      
58      protected PersistenceService persistenceService;
59      protected XmlObjectSerializerService xmlObjectSerializerService;
60      
61      protected XStream xstream;
62      protected ThreadLocal<SerializationState> serializationStates;
63      protected ThreadLocal<PropertySerializabilityEvaluator> evaluators;
64      
65      public SerializerServiceBase() {
66          serializationStates = new ThreadLocal<SerializationState>();
67          evaluators = new ThreadLocal<PropertySerializabilityEvaluator>();
68          
69          xstream = new XStream(new ProxyAndStateAwareJavaReflectionProvider());
70          xstream.registerConverter(new ProxyConverter(xstream.getMapper(), xstream.getReflectionProvider() ));
71          xstream.addDefaultImplementation(ArrayList.class, ListProxyDefaultImpl.class);
72          xstream.addDefaultImplementation(AutoPopulatingList.class, ListProxyDefaultImpl.class);
73          xstream.registerConverter(new AutoPopulatingListConverter(xstream.getMapper()));
74          xstream.registerConverter(new DateTimeConverter());
75      }
76          
77      public class ProxyConverter extends ReflectionConverter {
78          public ProxyConverter(Mapper mapper, ReflectionProvider reflectionProvider) {
79              super(mapper, reflectionProvider);
80          }
81          public boolean canConvert(Class clazz) {
82              return clazz.getName().contains("CGLIB") || clazz.getName().equals("org.apache.ojb.broker.core.proxy.ListProxyDefaultImpl");
83          }
84  
85          public void marshal(Object obj, HierarchicalStreamWriter writer, MarshallingContext context) {
86              if (obj instanceof ListProxyDefaultImpl) { 
87                  List copiedList = new ArrayList(); 
88                  List proxiedList = (List) obj; 
89                  for (Iterator iter = proxiedList.iterator(); iter.hasNext();) { 
90                      copiedList.add(iter.next()); 
91                  } 
92                  context.convertAnother( copiedList );
93              } 
94              else { 
95                  super.marshal(getPersistenceService().resolveProxy(obj), writer, context);
96              }           
97          }
98  
99          public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
100             return null;
101         }
102     }
103     
104     public class ProxyAndStateAwareJavaReflectionProvider extends PureJavaReflectionProvider {
105         @Override
106         public void visitSerializableFields(Object object, Visitor visitor) {
107             SerializationState state = serializationStates.get();
108             PropertySerializabilityEvaluator evaluator = evaluators.get();
109             
110             for (Iterator iterator = fieldDictionary.serializableFieldsFor(object.getClass()); iterator.hasNext();) {
111                 Field field = (Field) iterator.next();
112                 if (!fieldModifiersSupported(field)) {
113                     continue;
114                 }
115                 
116                 if (ignoreField(field)) {
117                     continue;
118                 }
119                 
120                 validateFieldAccess(field);
121                 
122                 initializeField(object, field);
123                 
124                 Object value = null;
125                 try {
126                     value = field.get(object);
127                 } catch (IllegalArgumentException e) {
128                     throw new ObjectAccessException("Could not get field " + field.getClass() + "." + field.getName(), e);
129                 } catch (IllegalAccessException e) {
130                     throw new ObjectAccessException("Could not get field " + field.getClass() + "." + field.getName(), e);
131                 }
132                 
133                 if (evaluator.isPropertySerializable(state, object, field.getName(), value)) {
134                     if (value != null && ProxyHelper.isProxy(value)) {
135                         // resolve proxies after we determine that it's serializable
136                         value = getPersistenceService().resolveProxy(value);
137                     }
138                     PropertyType propertyType = evaluator.determinePropertyType(value);
139                     state.addSerializedProperty(field.getName(), propertyType);
140                     visitor.visit(field.getName(), field.getType(), field.getDeclaringClass(), value);
141                     state.removeSerializedProperty();
142                 }
143             }
144         }
145         
146         protected boolean ignoreField(Field field) {
147             return false;
148         }
149         
150         protected void initializeField(Object object, Field field) {
151         }
152     }
153 
154     public PersistenceService getPersistenceService() {
155         return this.persistenceService;
156     }
157 
158     public void setPersistenceService(PersistenceService persistenceService) {
159         this.persistenceService = persistenceService;
160     }
161     
162     public XmlObjectSerializerService getXmlObjectSerializerService() {
163         return this.xmlObjectSerializerService;
164     }
165 
166     public void setXmlObjectSerializerService(XmlObjectSerializerService xmlObjectSerializerService) {
167         this.xmlObjectSerializerService = xmlObjectSerializerService;
168     }
169     
170     protected SerializationState createNewDocumentSerializationState(Document document) {
171         return new SerializationState();
172     }
173     
174     public class AutoPopulatingListConverter extends CollectionConverter {
175 
176     	public AutoPopulatingListConverter(Mapper mapper){
177     		super(mapper);
178     	}
179 
180         @Override
181     	public boolean canConvert(Class clazz) {
182     		return clazz.equals(AutoPopulatingList.class);
183         }
184 
185     }
186 
187     
188 }
189