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.InputStream;
020 import java.io.InputStreamReader;
021 import java.io.Reader;
022 import java.io.StringReader;
023 import java.io.StringWriter;
024 import java.util.Map;
025 import java.util.Properties;
026
027 import org.apache.camel.Exchange;
028 import org.apache.camel.ExchangePattern;
029 import org.apache.camel.Message;
030 import org.apache.camel.component.ResourceBasedEndpoint;
031 import org.apache.camel.util.ExchangeHelper;
032 import org.apache.camel.util.ObjectHelper;
033 import org.apache.velocity.VelocityContext;
034 import org.apache.velocity.app.Velocity;
035 import org.apache.velocity.app.VelocityEngine;
036 import org.apache.velocity.context.Context;
037 import org.apache.velocity.runtime.log.CommonsLogLogChute;
038 import org.springframework.core.io.Resource;
039
040 /**
041 * @version $Revision: 829724 $
042 */
043 public class VelocityEndpoint extends ResourceBasedEndpoint {
044 private VelocityEngine velocityEngine;
045 private boolean loaderCache = true;
046 private String encoding;
047 private String propertiesFile;
048
049 public VelocityEndpoint() {
050 }
051
052 public VelocityEndpoint(String uri, VelocityComponent component, String resourceUri) {
053 super(uri, component, resourceUri, null);
054 }
055
056 @Override
057 public boolean isSingleton() {
058 return true;
059 }
060
061 @Override
062 public ExchangePattern getExchangePattern() {
063 return ExchangePattern.InOut;
064 }
065
066 @Override
067 protected String createEndpointUri() {
068 return "velocity:" + getResourceUri();
069 }
070
071 private synchronized VelocityEngine getVelocityEngine() throws Exception {
072 if (velocityEngine == null) {
073 velocityEngine = new VelocityEngine();
074 Properties properties = new Properties();
075 // load the velocity properties from property file
076 if (ObjectHelper.isNotEmpty(getPropertiesFile())) {
077 Resource resource = getResourceLoader().getResource(getPropertiesFile());
078 InputStream reader = resource.getInputStream();
079 properties.load(reader);
080 log.info("Loaded the velocity configuration file " + getPropertiesFile());
081 }
082
083 properties.setProperty(Velocity.FILE_RESOURCE_LOADER_CACHE, isLoaderCache() ? "true" : "false");
084 properties.setProperty(Velocity.RUNTIME_LOG_LOGSYSTEM_CLASS, CommonsLogLogChute.class.getName());
085 properties.setProperty(CommonsLogLogChute.LOGCHUTE_COMMONS_LOG_NAME, VelocityEndpoint.class.getName());
086 velocityEngine.init(properties);
087
088 }
089 return velocityEngine;
090 }
091
092 public void setVelocityEngine(VelocityEngine velocityEngine) {
093 this.velocityEngine = velocityEngine;
094
095 }
096
097 public boolean isLoaderCache() {
098 return loaderCache;
099 }
100
101 /**
102 * Enables / disables the velocity resource loader cache which is enabled by default
103 *
104 * @param loaderCache a flag to enable/disable the cache
105 */
106 public void setLoaderCache(boolean loaderCache) {
107 this.loaderCache = loaderCache;
108 }
109
110 public void setEncoding(String encoding) {
111 this.encoding = encoding;
112 }
113
114 public String getEncoding() {
115 return encoding;
116 }
117
118 public void setPropertiesFile(String file) {
119 propertiesFile = file;
120 }
121
122 public String getPropertiesFile() {
123 return propertiesFile;
124 }
125
126 public VelocityEndpoint findOrCreateEndpoint(String uri, String newResourceUri) {
127 String newUri = uri.replace(getResourceUri(), newResourceUri);
128 if (log.isDebugEnabled()) {
129 log.debug("Getting endpoint with URI: " + newUri);
130 }
131 return (VelocityEndpoint) getCamelContext().getEndpoint(newUri);
132 }
133
134 @SuppressWarnings("unchecked")
135 @Override
136 protected void onExchange(Exchange exchange) throws Exception {
137 String path = getResourceUri();
138 ObjectHelper.notNull(path, "resourceUri");
139
140 String newResourceUri = exchange.getIn().getHeader(VelocityConstants.VELOCITY_RESOURCE_URI, String.class);
141 if (newResourceUri != null) {
142 exchange.getIn().removeHeader(VelocityConstants.VELOCITY_RESOURCE_URI);
143
144 if (log.isDebugEnabled()) {
145 log.debug(VelocityConstants.VELOCITY_RESOURCE_URI + " set to " + newResourceUri + " creating new endpoint to handle exchange");
146 }
147 VelocityEndpoint newEndpoint = findOrCreateEndpoint(getEndpointUri(), newResourceUri);
148 newEndpoint.onExchange(exchange);
149 return;
150 }
151
152 Resource resource = null;
153 Reader reader;
154 String content = exchange.getIn().getHeader(VelocityConstants.VELOCITY_TEMPLATE, String.class);
155 if (content != null) {
156 // use content from header
157 reader = new StringReader(content);
158 if (log.isDebugEnabled()) {
159 log.debug("Velocity content read from header " + VelocityConstants.VELOCITY_TEMPLATE + " for endpoint " + getEndpointUri());
160 }
161 // remove the header to avoid it being propagated in the routing
162 exchange.getIn().removeHeader(VelocityConstants.VELOCITY_TEMPLATE);
163 } else {
164 // use resource from endpoint configuration
165 resource = getResource();
166 ObjectHelper.notNull(resource, "resource");
167 if (log.isDebugEnabled()) {
168 log.debug("Velocity content read from resource " + resource + " with resourceUri: " + path + " for endpoint " + getEndpointUri());
169 }
170 reader = getEncoding() != null ? new InputStreamReader(getResourceAsInputStream(), getEncoding()) : new InputStreamReader(getResourceAsInputStream());
171 }
172
173 // getResourceAsInputStream also considers the content cache
174 StringWriter buffer = new StringWriter();
175 String logTag = getClass().getName();
176 Map variableMap = ExchangeHelper.createVariableMap(exchange);
177 Context velocityContext = new VelocityContext(variableMap);
178
179 // let velocity parse and generate the result in buffer
180 VelocityEngine engine = getVelocityEngine();
181 if (log.isDebugEnabled()) {
182 log.debug("Velocity is evaluating using velocity context: " + variableMap);
183 }
184 engine.evaluate(velocityContext, buffer, logTag, reader);
185
186 // now lets output the results to the exchange
187 Message out = exchange.getOut();
188 out.setBody(buffer.toString());
189
190 Map<String, Object> headers = (Map<String, Object>) velocityContext.get("headers");
191 for (String key : headers.keySet()) {
192 out.setHeader(key, headers.get(key));
193 }
194 }
195
196 }