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    }