001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.camel.dataformat.xstream;
018
019 import java.io.InputStream;
020 import java.io.OutputStream;
021 import java.lang.reflect.Constructor;
022 import java.lang.reflect.Method;
023 import java.util.List;
024 import java.util.Map;
025 import java.util.Map.Entry;
026
027 import javax.xml.stream.XMLStreamException;
028
029 import com.thoughtworks.xstream.XStream;
030 import com.thoughtworks.xstream.converters.Converter;
031 import com.thoughtworks.xstream.io.HierarchicalStreamReader;
032 import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
033
034 import org.apache.camel.Exchange;
035 import org.apache.camel.converter.jaxp.StaxConverter;
036 import org.apache.camel.spi.ClassResolver;
037 import org.apache.camel.spi.DataFormat;
038 import org.apache.camel.util.ObjectHelper;
039
040 /**
041 * An abstract class which implement <a href="http://camel.apache.org/data-format.html">data format</a>
042 * ({@link DataFormat}) interface which leverage the XStream library for XML or JSON's marshaling and unmarshaling
043 *
044 * @version $Revision: 962504 $
045 */
046 public abstract class AbstractXStreamWrapper implements DataFormat {
047
048 private XStream xstream;
049 private StaxConverter staxConverter;
050 private List<String> converters;
051 private Map<String, String> aliases;
052 private Map<String, String[]> implicitCollections;
053
054 public AbstractXStreamWrapper() {
055 }
056
057 public AbstractXStreamWrapper(XStream xstream) {
058 this.xstream = xstream;
059 }
060
061 public XStream getXStream(ClassResolver resolver) {
062 if (xstream == null) {
063 xstream = createXStream(resolver);
064 }
065 return xstream;
066 }
067
068 public void setXStream(XStream xstream) {
069 this.xstream = xstream;
070 }
071
072 protected XStream createXStream(ClassResolver resolver) {
073 xstream = new XStream();
074
075 try {
076 if (this.implicitCollections != null) {
077 for (Entry<String, String[]> entry : this.implicitCollections.entrySet()) {
078 for (String name : entry.getValue()) {
079 xstream.addImplicitCollection(resolver.resolveMandatoryClass(entry.getKey()), name);
080 }
081 }
082 }
083
084 if (this.aliases != null) {
085 for (Entry<String, String> entry : this.aliases.entrySet()) {
086 xstream.alias(entry.getKey(), resolver.resolveMandatoryClass(entry.getValue()));
087 }
088 }
089
090 if (this.converters != null) {
091 for (String name : this.converters) {
092 Class<Converter> converterClass = resolver.resolveMandatoryClass(name, Converter.class);
093 Converter converter;
094
095 Constructor con = null;
096 try {
097 con = converterClass.getDeclaredConstructor(new Class[] {XStream.class});
098 } catch (Exception e) {
099 //swallow as we null check in a moment.
100 }
101 if (con != null) {
102 converter = (Converter) con.newInstance(xstream);
103 } else {
104 converter = converterClass.newInstance();
105 try {
106 Method method = converterClass.getMethod("setXStream", new Class[] {XStream.class});
107 if (method != null) {
108 ObjectHelper.invokeMethod(method, converter, xstream);
109 }
110 } catch (Throwable e) {
111 // swallow, as it just means the user never add an XStream setter, which is optional
112 }
113 }
114
115 xstream.registerConverter(converter);
116 }
117 }
118 } catch (Exception e) {
119 throw new RuntimeException("Unable to build XStream instance", e);
120 }
121
122 return xstream;
123 }
124
125 public StaxConverter getStaxConverter() {
126 if (staxConverter == null) {
127 staxConverter = new StaxConverter();
128 }
129 return staxConverter;
130 }
131
132 public void setStaxConverter(StaxConverter staxConverter) {
133 this.staxConverter = staxConverter;
134 }
135
136 public List<String> getConverters() {
137 return converters;
138 }
139
140 public void setConverters(List<String> converters) {
141 this.converters = converters;
142 }
143
144 public Map<String, String> getAliases() {
145 return aliases;
146 }
147
148 public void setAliases(Map<String, String> aliases) {
149 this.aliases = aliases;
150 }
151
152 public Map<String, String[]> getImplicitCollections() {
153 return implicitCollections;
154 }
155
156 public void setImplicitCollections(Map<String, String[]> implicitCollections) {
157 this.implicitCollections = implicitCollections;
158 }
159
160 public XStream getXstream() {
161 return xstream;
162 }
163
164 public void setXstream(XStream xstream) {
165 this.xstream = xstream;
166 }
167
168 public void marshal(Exchange exchange, Object body, OutputStream stream) throws Exception {
169 HierarchicalStreamWriter writer = createHierarchicalStreamWriter(exchange, body, stream);
170 try {
171 getXStream(exchange.getContext().getClassResolver()).marshal(body, writer);
172 } finally {
173 writer.close();
174 }
175 }
176
177 public Object unmarshal(Exchange exchange, InputStream stream) throws Exception {
178 HierarchicalStreamReader reader = createHierarchicalStreamReader(exchange, stream);
179 try {
180 return getXStream(exchange.getContext().getClassResolver()).unmarshal(reader);
181 } finally {
182 reader.close();
183 }
184 }
185
186 protected abstract HierarchicalStreamWriter createHierarchicalStreamWriter(
187 Exchange exchange, Object body, OutputStream stream) throws XMLStreamException;
188
189 protected abstract HierarchicalStreamReader createHierarchicalStreamReader(
190 Exchange exchange, InputStream stream) throws XMLStreamException;
191 }