View Javadoc

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