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