001: /*
002: * Copyright 2005-2007 The Kuali Foundation.
003: *
004: * Licensed under the Educational Community License, Version 1.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.opensource.org/licenses/ecl1.php
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.kuali.core.service.impl;
018:
019: import java.io.StringWriter;
020: import java.lang.reflect.Field;
021: import java.util.ArrayList;
022: import java.util.Iterator;
023: import java.util.List;
024:
025: import javax.xml.transform.OutputKeys;
026: import javax.xml.transform.Result;
027: import javax.xml.transform.Source;
028: import javax.xml.transform.Transformer;
029: import javax.xml.transform.TransformerException;
030: import javax.xml.transform.TransformerFactory;
031: import javax.xml.transform.dom.DOMSource;
032: import javax.xml.transform.stream.StreamResult;
033:
034: import org.apache.commons.logging.Log;
035: import org.apache.commons.logging.LogFactory;
036: import org.apache.ojb.broker.core.proxy.ListProxyDefaultImpl;
037: import org.apache.ojb.broker.core.proxy.ProxyHelper;
038: import org.kuali.core.service.PersistenceService;
039: import org.kuali.core.service.XmlObjectSerializerService;
040: import org.kuali.rice.KNSServiceLocator;
041: import org.springframework.transaction.annotation.Transactional;
042:
043: import com.thoughtworks.xstream.XStream;
044: import com.thoughtworks.xstream.converters.MarshallingContext;
045: import com.thoughtworks.xstream.converters.UnmarshallingContext;
046: import com.thoughtworks.xstream.converters.reflection.ObjectAccessException;
047: import com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider;
048: import com.thoughtworks.xstream.converters.reflection.ReflectionConverter;
049: import com.thoughtworks.xstream.converters.reflection.ReflectionProvider;
050: import com.thoughtworks.xstream.io.HierarchicalStreamReader;
051: import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
052: import com.thoughtworks.xstream.mapper.Mapper;
053:
054: /**
055: * This class is the service implementation for the XmlObjectSerializer structure. This is the default implementation that gets
056: * delivered with Kuali. It utilizes the XStream open source libraries and framework.
057: *
058: *
059: */
060: @Transactional
061: public class XmlObjectSerializerServiceImpl implements
062: XmlObjectSerializerService {
063: private static final Log LOG = LogFactory
064: .getLog(XmlObjectSerializerServiceImpl.class);
065:
066: private PersistenceService persistenceService;
067:
068: private XStream xstream;
069:
070: public XmlObjectSerializerServiceImpl() {
071: xstream = new XStream(new ProxyAwareJavaReflectionProvider());
072: xstream.registerConverter(new ProxyConverter(xstream
073: .getMapper(), xstream.getReflectionProvider()));
074: }
075:
076: /**
077: * @see org.kuali.core.service.XmlObjectSerializer#toXml(java.lang.Object)
078: */
079: public String toXml(Object object) {
080: if (LOG.isDebugEnabled()) {
081: LOG.debug("toXml(" + object + ") : \n"
082: + xstream.toXML(object));
083: }
084: return xstream.toXML(object);
085: }
086:
087: /**
088: * @see org.kuali.core.service.XmlObjectSerializer#fromXml(java.lang.String)
089: */
090: public Object fromXml(String xml) {
091: if (LOG.isDebugEnabled()) {
092: LOG.debug("fromXml() : \n" + xml);
093: }
094: if (xml != null) {
095: xml = xml
096: .replaceAll("--EnhancerByCGLIB--[0-9a-f]{0,8}", "");
097: }
098: return xstream.fromXML(xml);
099: }
100:
101: public String writeNode(org.w3c.dom.Node node, boolean indent)
102: throws TransformerException {
103: Source source = new DOMSource(node);
104: StringWriter writer = new StringWriter();
105: Result result = new StreamResult(writer);
106: Transformer transformer = TransformerFactory.newInstance()
107: .newTransformer();
108: transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION,
109: "yes");
110: if (indent) {
111: transformer.setOutputProperty(OutputKeys.INDENT, "yes");
112: }
113: transformer.transform(source, result);
114: return writer.toString();
115: }
116:
117: public class ProxyConverter extends ReflectionConverter {
118: public ProxyConverter(Mapper mapper,
119: ReflectionProvider reflectionProvider) {
120: super (mapper, reflectionProvider);
121: }
122:
123: public boolean canConvert(Class clazz) {
124: return clazz.getName().indexOf("CGLIB") > -1
125: || clazz
126: .getName()
127: .equals(
128: "org.apache.ojb.broker.core.proxy.ListProxyDefaultImpl");
129: }
130:
131: public void marshal(Object obj,
132: HierarchicalStreamWriter writer,
133: MarshallingContext context) {
134: if (obj instanceof ListProxyDefaultImpl) {
135: List copiedList = new ArrayList();
136: List proxiedList = (List) obj;
137: for (Iterator iter = proxiedList.iterator(); iter
138: .hasNext();) {
139: copiedList.add(iter.next());
140: }
141: context.convertAnother(copiedList);
142: //super.marshal(copiedList, writer, context);
143: } else {
144: super .marshal(
145: getPersistenceService().resolveProxy(obj),
146: writer, context);
147: }
148: }
149:
150: public Object unmarshal(HierarchicalStreamReader reader,
151: UnmarshallingContext context) {
152: return null;
153: }
154: }
155:
156: public class ProxyAwareJavaReflectionProvider extends
157: PureJavaReflectionProvider {
158:
159: public ProxyAwareJavaReflectionProvider() {
160: super ();
161: }
162:
163: /**
164: * @see com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider#visitSerializableFields(java.lang.Object, com.thoughtworks.xstream.converters.reflection.ReflectionProvider.Visitor)
165: */
166: @Override
167: public void visitSerializableFields(Object object,
168: Visitor visitor) {
169: for (Iterator iterator = fieldDictionary
170: .serializableFieldsFor(object.getClass()); iterator
171: .hasNext();) {
172: Field field = (Field) iterator.next();
173: if (!fieldModifiersSupported(field)) {
174: continue;
175: }
176: validateFieldAccess(field);
177: Object value = null;
178: try {
179: value = field.get(object);
180: if (value != null && ProxyHelper.isProxy(value)) {
181: value = getPersistenceService().resolveProxy(
182: value);
183: }
184: } catch (IllegalArgumentException e) {
185: throw new ObjectAccessException(
186: "Could not get field " + field.getClass()
187: + "." + field.getName(), e);
188: } catch (IllegalAccessException e) {
189: throw new ObjectAccessException(
190: "Could not get field " + field.getClass()
191: + "." + field.getName(), e);
192: }
193: visitor.visit(field.getName(), field.getType(), field
194: .getDeclaringClass(), value);
195: }
196: }
197:
198: }
199:
200: public PersistenceService getPersistenceService() {
201: if (persistenceService == null) {
202: persistenceService = KNSServiceLocator
203: .getPersistenceService();
204: }
205: return persistenceService;
206: }
207:
208: }
|