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.component.velocity;
018    
019    import java.io.InputStreamReader;
020    import java.io.Reader;
021    import java.io.StringWriter;
022    import java.util.Map;
023    
024    import org.apache.camel.Exchange;
025    import org.apache.camel.ExchangePattern;
026    import org.apache.camel.Message;
027    import org.apache.camel.component.ResourceBasedEndpoint;
028    import org.apache.camel.util.ExchangeHelper;
029    import org.apache.velocity.VelocityContext;
030    import org.apache.velocity.app.Velocity;
031    import org.apache.velocity.app.VelocityEngine;
032    import org.apache.velocity.context.Context;
033    import org.apache.velocity.runtime.log.CommonsLogLogChute;
034    import org.springframework.core.io.Resource;
035    
036    /**
037     * @version $Revision: 828294 $
038     */
039    public class VelocityEndpoint extends ResourceBasedEndpoint {
040        private final VelocityComponent component;
041        private VelocityEngine velocityEngine;
042        private boolean loaderCache = true;
043        private String encoding;
044    
045        public VelocityEndpoint(String uri, VelocityComponent component, String resourceUri, Map parameters) {
046            super(uri, component, resourceUri, null);
047            this.component = component;
048        }
049    
050        @Override
051        public boolean isSingleton() {
052            return true;
053        }
054    
055        @Override
056        public ExchangePattern getExchangePattern() {
057            return ExchangePattern.InOut;
058        }
059    
060        private synchronized VelocityEngine getVelocityEngine() throws Exception {
061            if (velocityEngine == null) {
062                velocityEngine = component.getVelocityEngine();
063                velocityEngine.setProperty(Velocity.FILE_RESOURCE_LOADER_CACHE, isLoaderCache() ? Boolean.TRUE : Boolean.FALSE);
064                velocityEngine.setProperty(Velocity.RUNTIME_LOG_LOGSYSTEM_CLASS, CommonsLogLogChute.class.getName());
065                velocityEngine.setProperty(CommonsLogLogChute.LOGCHUTE_COMMONS_LOG_NAME, VelocityEndpoint.class.getName());
066                velocityEngine.init();
067            }
068            return velocityEngine;
069        }
070    
071        public void setVelocityEngine(VelocityEngine velocityEngine) {
072            this.velocityEngine = velocityEngine;
073        }
074    
075        public boolean isLoaderCache() {
076            return loaderCache;
077        }
078    
079        /**
080         * Enables / disables the velocity resource loader cache which is enabled by default
081         *
082         * @param loaderCache a flag to enable/disable the cache
083         */
084        public void setLoaderCache(boolean loaderCache) {
085            this.loaderCache = loaderCache;
086        }
087    
088        public void setEncoding(String encoding) {
089            this.encoding = encoding;
090        }
091    
092        public String getEncoding() {
093            return encoding;
094        }
095    
096        @SuppressWarnings("unchecked")
097        @Override
098        protected void onExchange(Exchange exchange) throws Exception {
099            Resource resource = getResource();
100    
101            // getResourceAsInputStream also considers the content cache
102            Reader reader = encoding != null ? new InputStreamReader(getResourceAsInputStream(), encoding) : new InputStreamReader(getResourceAsInputStream());
103            StringWriter buffer = new StringWriter();
104            String logTag = getClass().getName();
105            Map variableMap = ExchangeHelper.createVariableMap(exchange);
106            Context velocityContext = new VelocityContext(variableMap);
107    
108            // let velocity parse and generate the result in buffer
109            VelocityEngine engine = getVelocityEngine();
110            if (log.isDebugEnabled()) {
111                log.debug("Velocity is evaluating using velocity context: " + variableMap);
112            }
113            engine.evaluate(velocityContext, buffer, logTag, reader);
114    
115            // now lets output the results to the exchange
116            Message out = exchange.getOut(true);
117            out.setBody(buffer.toString());
118            Map<String, Object> headers = (Map<String, Object>) velocityContext.get("headers");
119            for (String key : headers.keySet()) {
120                out.setHeader(key, headers.get(key));
121            }
122        }
123    
124    }