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: 630591 $
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 ResultHandlerFactory resultHandlerFactory = new StringResultHandlerFactory();
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            ResultHandler resultHandler = resultHandlerFactory.createResult();
076            Result result = resultHandler.getResult();
077    
078            // lets copy the headers before we invoke the transform in case they modify them
079            Message out = exchange.getOut(true);
080            out.copyFrom(exchange.getIn());
081    
082            transformer.transform(source, result);
083            resultHandler.setBody(out);
084        }
085    
086        // Builder methods
087        // -------------------------------------------------------------------------
088    
089        /**
090         * Creates an XSLT processor using the given transformer instance
091         */
092        public static XsltBuilder xslt(Transformer transformer) {
093            return new XsltBuilder(transformer);
094        }
095    
096        /**
097         * Creates an XSLT processor using the given XSLT source
098         */
099        public static XsltBuilder xslt(Source xslt) throws TransformerConfigurationException {
100            notNull(xslt, "xslt");
101            XsltBuilder answer = new XsltBuilder();
102            answer.setTransformerSource(xslt);
103            return answer;
104        }
105    
106        /**
107         * Creates an XSLT processor using the given XSLT source
108         */
109        public static XsltBuilder xslt(File xslt) throws TransformerConfigurationException {
110            notNull(xslt, "xslt");
111            return xslt(new StreamSource(xslt));
112        }
113    
114        /**
115         * Creates an XSLT processor using the given XSLT source
116         */
117        public static XsltBuilder xslt(URL xslt) throws TransformerConfigurationException, IOException {
118            notNull(xslt, "xslt");
119            return xslt(xslt.openStream());
120        }
121    
122        /**
123         * Creates an XSLT processor using the given XSLT source
124         */
125        public static XsltBuilder xslt(InputStream xslt) throws TransformerConfigurationException, IOException {
126            notNull(xslt, "xslt");
127            return xslt(new StreamSource(xslt));
128        }
129    
130        /**
131         * Sets the output as being a byte[]
132         */
133        public XsltBuilder outputBytes() {
134            setResultHandlerFactory(new StreamResultHandlerFactory());
135            return this;
136        }
137    
138        /**
139         * Sets the output as being a String
140         */
141        public XsltBuilder outputString() {
142            setResultHandlerFactory(new StringResultHandlerFactory());
143            return this;
144        }
145    
146        /**
147         * Sets the output as being a DOM
148         */
149        public XsltBuilder outputDOM() {
150            setResultHandlerFactory(new DomResultHandlerFactory());
151            return this;
152        }
153    
154        public XsltBuilder parameter(String name, Object value) {
155            parameters.put(name, value);
156            return this;
157        }
158    
159        // Properties
160        // -------------------------------------------------------------------------
161    
162        public Map<String, Object> getParameters() {
163            return parameters;
164        }
165    
166        public void setParameters(Map<String, Object> parameters) {
167            this.parameters = parameters;
168        }
169    
170        public Transformer getTransformer() {
171            return transformer;
172        }
173    
174        public void setTransformer(Transformer transformer) {
175            this.transformer = transformer;
176        }
177    
178        public boolean isFailOnNullBody() {
179            return failOnNullBody;
180        }
181    
182        public void setFailOnNullBody(boolean failOnNullBody) {
183            this.failOnNullBody = failOnNullBody;
184        }
185    
186        public ResultHandlerFactory getResultHandlerFactory() {
187            return resultHandlerFactory;
188        }
189    
190        public void setResultHandlerFactory(ResultHandlerFactory resultHandlerFactory) {
191            this.resultHandlerFactory = resultHandlerFactory;
192        }
193    
194        /**
195         * Sets the XSLT transformer from a Source
196         */
197        public void setTransformerSource(Source source) throws TransformerConfigurationException {
198            setTransformer(converter.getTransformerFactory().newTransformer(source));
199        }
200    
201        /**
202         * Sets the XSLT transformer from a File
203         */
204        public void setTransformerFile(File xslt) throws TransformerConfigurationException {
205            setTransformerSource(new StreamSource(xslt));
206        }
207    
208        /**
209         * Sets the XSLT transformer from a URL
210         */
211        public void setTransformerURL(URL url) throws TransformerConfigurationException, IOException {
212            notNull(url, "url");
213            setTransformerInputStream(url.openStream());
214        }
215    
216        /**
217         * Sets the XSLT transformer from the given input stream
218         */
219        public void setTransformerInputStream(InputStream in) throws TransformerConfigurationException, IOException {
220            notNull(in, "in");
221            setTransformerSource(new StreamSource(in));
222        }
223    
224        public XmlConverter getConverter() {
225            return converter;
226        }
227    
228        public void setConverter(XmlConverter converter) {
229            this.converter = converter;
230        }
231    
232        // Implementation methods
233        // -------------------------------------------------------------------------
234    
235        /**
236         * Converts the inbound body to a {@link Source}
237         */
238        protected Source getSource(Exchange exchange) {
239            Message in = exchange.getIn();
240            Source source = in.getBody(Source.class);
241            if (source == null) {
242                if (isFailOnNullBody()) {
243                    throw new ExpectedBodyTypeException(exchange, Source.class);
244                } else {
245                    try {
246                        source = converter.toSource(converter.createDocument());
247                    } catch (ParserConfigurationException e) {
248                        throw new RuntimeTransformException(e);
249                    }
250                }
251            }
252            return source;
253        }
254    
255        /**
256         * Configures the transformerwith exchange specific parameters
257         */
258        protected void configureTransformer(Transformer transformer, Exchange exchange) {
259            transformer.clearParameters();
260    
261            addParameters(transformer, exchange.getProperties());
262            addParameters(transformer, exchange.getIn().getHeaders());
263            addParameters(transformer, getParameters());
264    
265            transformer.setParameter("exchange", exchange);
266            transformer.setParameter("in", exchange.getIn());
267            transformer.setParameter("out", exchange.getOut());
268        }
269    
270        protected void addParameters(Transformer transformer, Map<String, Object> map) {
271            Set<Map.Entry<String, Object>> propertyEntries = map.entrySet();
272            for (Map.Entry<String, Object> entry : propertyEntries) {
273                String key = entry.getKey();
274                Object value = entry.getValue();
275                if (value != null) {
276                    transformer.setParameter(key, value);
277                }
278            }
279        }
280    }