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.builder.xml;
018
019 import java.io.File;
020 import java.io.IOException;
021 import java.io.InputStream;
022 import java.net.URL;
023 import java.util.HashMap;
024 import java.util.Map;
025 import java.util.Set;
026
027 import javax.xml.parsers.ParserConfigurationException;
028 import javax.xml.transform.Result;
029 import javax.xml.transform.Source;
030 import javax.xml.transform.Transformer;
031 import javax.xml.transform.TransformerConfigurationException;
032 import javax.xml.transform.stream.StreamSource;
033
034 import org.apache.camel.Exchange;
035 import org.apache.camel.ExpectedBodyTypeException;
036 import org.apache.camel.Message;
037 import org.apache.camel.Processor;
038 import org.apache.camel.RuntimeTransformException;
039 import org.apache.camel.converter.jaxp.XmlConverter;
040
041 import static org.apache.camel.util.ObjectHelper.notNull;
042
043 /**
044 * Creates a <a href="http://activemq.apache.org/camel/processor.html">Processor</a>
045 * which performs an XSLT transformation of the IN message body
046 *
047 * @version $Revision: 531854 $
048 */
049 public class XsltBuilder implements Processor {
050 private Map<String, Object> parameters = new HashMap<String, Object>();
051 private XmlConverter converter = new XmlConverter();
052 private Transformer transformer;
053 private ResultHandler resultHandler = new StringResultHandler();
054 private boolean failOnNullBody = true;
055
056 public XsltBuilder() {
057 }
058
059 public XsltBuilder(Transformer transformer) {
060 this.transformer = transformer;
061 }
062
063 @Override
064 public String toString() {
065 return "XSLT[" + transformer + "]";
066 }
067
068 public synchronized void process(Exchange exchange) throws Exception {
069 Transformer transformer = getTransformer();
070 if (transformer == null) {
071 throw new IllegalArgumentException("No transformer configured!");
072 }
073 configureTransformer(transformer, exchange);
074 Source source = getSource(exchange);
075 Result result = resultHandler.getResult();
076 transformer.transform(source, result);
077 resultHandler.setBody(exchange.getIn());
078 }
079
080 // Builder methods
081 // -------------------------------------------------------------------------
082
083 /**
084 * Creates an XSLT processor using the given transformer instance
085 */
086 public static XsltBuilder xslt(Transformer transformer) {
087 return new XsltBuilder(transformer);
088 }
089
090 /**
091 * Creates an XSLT processor using the given XSLT source
092 */
093 public static XsltBuilder xslt(Source xslt) throws TransformerConfigurationException {
094 notNull(xslt, "xslt");
095 XsltBuilder answer = new XsltBuilder();
096 answer.setTransformerSource(xslt);
097 return answer;
098 }
099
100 /**
101 * Creates an XSLT processor using the given XSLT source
102 */
103 public static XsltBuilder xslt(File xslt) throws TransformerConfigurationException {
104 notNull(xslt, "xslt");
105 return xslt(new StreamSource(xslt));
106 }
107
108 /**
109 * Creates an XSLT processor using the given XSLT source
110 */
111 public static XsltBuilder xslt(URL xslt) throws TransformerConfigurationException, IOException {
112 notNull(xslt, "xslt");
113 return xslt(xslt.openStream());
114 }
115
116 /**
117 * Creates an XSLT processor using the given XSLT source
118 */
119 public static XsltBuilder xslt(InputStream xslt) throws TransformerConfigurationException, IOException {
120 notNull(xslt, "xslt");
121 return xslt(new StreamSource(xslt));
122 }
123
124 /**
125 * Sets the output as being a byte[]
126 */
127 public XsltBuilder outputBytes() {
128 setResultHandler(new StreamResultHandler());
129 return this;
130 }
131
132 /**
133 * Sets the output as being a String
134 */
135 public XsltBuilder outputString() {
136 setResultHandler(new StringResultHandler());
137 return this;
138 }
139
140 /**
141 * Sets the output as being a DOM
142 */
143 public XsltBuilder outputDOM() {
144 setResultHandler(new DomResultHandler());
145 return this;
146 }
147
148 public XsltBuilder parameter(String name, Object value) {
149 parameters.put(name, value);
150 return this;
151 }
152
153 // Properties
154 // -------------------------------------------------------------------------
155
156 public Map<String, Object> getParameters() {
157 return parameters;
158 }
159
160 public void setParameters(Map<String, Object> parameters) {
161 this.parameters = parameters;
162 }
163
164 public Transformer getTransformer() {
165 return transformer;
166 }
167
168 public void setTransformer(Transformer transformer) {
169 this.transformer = transformer;
170 }
171
172 public boolean isFailOnNullBody() {
173 return failOnNullBody;
174 }
175
176 public void setFailOnNullBody(boolean failOnNullBody) {
177 this.failOnNullBody = failOnNullBody;
178 }
179
180 public ResultHandler getResultHandler() {
181 return resultHandler;
182 }
183
184 public void setResultHandler(ResultHandler resultHandler) {
185 this.resultHandler = resultHandler;
186 }
187
188 public void setTransformerSource(Source source) throws TransformerConfigurationException {
189 setTransformer(converter.getTransformerFactory().newTransformer(source));
190 }
191
192 // Implementation methods
193 // -------------------------------------------------------------------------
194
195 /**
196 * Converts the inbound body to a {@link Source}
197 */
198 protected Source getSource(Exchange exchange) {
199 Message in = exchange.getIn();
200 Source source = in.getBody(Source.class);
201 if (source == null) {
202 if (isFailOnNullBody()) {
203 throw new ExpectedBodyTypeException(exchange, Source.class);
204 } else {
205 try {
206 source = converter.toSource(converter.createDocument());
207 } catch (ParserConfigurationException e) {
208 throw new RuntimeTransformException(e);
209 }
210 }
211 }
212 return source;
213 }
214
215 /**
216 * Configures the transformerwith exchange specific parameters
217 */
218 protected void configureTransformer(Transformer transformer, Exchange exchange) {
219 transformer.clearParameters();
220
221 addParameters(transformer, exchange.getProperties());
222 addParameters(transformer, exchange.getIn().getHeaders());
223 addParameters(transformer, getParameters());
224
225 transformer.setParameter("exchange", exchange);
226 transformer.setParameter("in", exchange.getIn());
227 transformer.setParameter("out", exchange.getOut());
228 }
229
230 protected void addParameters(Transformer transformer, Map<String, Object> map) {
231 Set<Map.Entry<String, Object>> propertyEntries = map.entrySet();
232 for (Map.Entry<String, Object> entry : propertyEntries) {
233 transformer.setParameter(entry.getKey(), entry.getValue());
234 }
235 }
236 }