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