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 */ 017package org.apache.camel.component.language; 018 019import java.io.IOException; 020import java.io.InputStream; 021import java.io.UnsupportedEncodingException; 022import java.net.URLEncoder; 023 024import org.apache.camel.Component; 025import org.apache.camel.Consumer; 026import org.apache.camel.Expression; 027import org.apache.camel.Processor; 028import org.apache.camel.Producer; 029import org.apache.camel.RuntimeCamelException; 030import org.apache.camel.component.ResourceEndpoint; 031import org.apache.camel.spi.Language; 032import org.apache.camel.spi.Metadata; 033import org.apache.camel.spi.UriEndpoint; 034import org.apache.camel.spi.UriParam; 035import org.apache.camel.spi.UriPath; 036import org.apache.camel.util.IOHelper; 037import org.apache.camel.util.ObjectHelper; 038import org.apache.camel.util.ResourceHelper; 039 040/** 041 * The language component allows you to send a message to an endpoint which executes a script by any of the supported Languages in Camel. 042 * 043 * By having a component to execute language scripts, it allows more dynamic routing capabilities. 044 * For example by using the Routing Slip or Dynamic Router EIPs you can send messages to language endpoints 045 * where the script is dynamic defined as well. 046 * 047 * This component is provided out of the box in camel-core and hence no additional JARs is needed. 048 * You only have to include additional Camel components if the language of choice mandates it, 049 * such as using Groovy or JavaScript languages. 050 */ 051@UriEndpoint(firstVersion = "2.5.0", scheme = "language", title = "Language", syntax = "language:languageName:resourceUri", producerOnly = true, label = "core,script") 052public class LanguageEndpoint extends ResourceEndpoint { 053 private Language language; 054 private Expression expression; 055 private boolean contentResolvedFromResource; 056 @UriPath(enums = "bean,constant,el,exchangeProperty,file,groovy,header,javascript,jsonpath,jxpath,mvel,ognl,php,python" 057 + ",ref,ruby,simple,spel,sql,terser,tokenize,xpath,xquery,xtokenize") 058 @Metadata(required = "true") 059 private String languageName; 060 // resourceUri is optional in the language endpoint 061 @UriPath(description = "Path to the resource, or a reference to lookup a bean in the Registry to use as the resource") 062 @Metadata(required = "false") 063 private String resourceUri; 064 @UriParam 065 private String script; 066 @UriParam(defaultValue = "true") 067 private boolean transform = true; 068 @UriParam 069 private boolean binary; 070 @UriParam 071 private boolean cacheScript; 072 073 public LanguageEndpoint() { 074 // enable cache by default 075 setContentCache(true); 076 } 077 078 public LanguageEndpoint(String endpointUri, Component component, Language language, Expression expression, String resourceUri) { 079 super(endpointUri, component, resourceUri); 080 this.language = language; 081 this.expression = expression; 082 // enable cache by default 083 setContentCache(true); 084 } 085 086 public Producer createProducer() throws Exception { 087 ObjectHelper.notNull(getCamelContext(), "CamelContext", this); 088 089 if (language == null && languageName != null) { 090 language = getCamelContext().resolveLanguage(languageName); 091 } 092 093 ObjectHelper.notNull(language, "language", this); 094 if (cacheScript && expression == null && script != null) { 095 script = resolveScript(script); 096 expression = language.createExpression(script); 097 } 098 099 return new LanguageProducer(this); 100 } 101 102 public Consumer createConsumer(Processor processor) throws Exception { 103 throw new RuntimeCamelException("Cannot consume to a LanguageEndpoint: " + getEndpointUri()); 104 } 105 106 /** 107 * Resolves the script. 108 * 109 * @param script script or uri for a script to load 110 * @return the script 111 * @throws IOException is thrown if error loading the script 112 */ 113 protected String resolveScript(String script) throws IOException { 114 String answer; 115 if (ResourceHelper.hasScheme(script)) { 116 InputStream is = loadResource(script); 117 answer = getCamelContext().getTypeConverter().convertTo(String.class, is); 118 IOHelper.close(is); 119 } else { 120 answer = script; 121 } 122 123 return answer; 124 } 125 126 public boolean isSingleton() { 127 return true; 128 } 129 130 @Override 131 protected String createEndpointUri() { 132 String s = script; 133 try { 134 s = URLEncoder.encode(s, "UTF-8"); 135 } catch (UnsupportedEncodingException e) { 136 // ignore 137 } 138 return languageName + ":" + s; 139 } 140 141 public Language getLanguage() { 142 return language; 143 } 144 145 public Expression getExpression() { 146 if (isContentResolvedFromResource() && isContentCacheCleared()) { 147 return null; 148 } 149 return expression; 150 } 151 152 public void setExpression(Expression expression) { 153 this.expression = expression; 154 } 155 156 public boolean isTransform() { 157 return transform; 158 } 159 160 /** 161 * Whether or not the result of the script should be used as message body. 162 * <p/> 163 * This options is default <tt>true</tt>. 164 * 165 * @param transform <tt>true</tt> to use result as new message body, <tt>false</tt> to keep the existing message body 166 */ 167 public void setTransform(boolean transform) { 168 this.transform = transform; 169 } 170 171 public boolean isBinary() { 172 return binary; 173 } 174 175 /** 176 * Whether the script is binary content or text content. 177 * <p/> 178 * By default the script is read as text content (eg <tt>java.lang.String</tt>) 179 * 180 * @param binary <tt>true</tt> to read the script as binary, instead of text based. 181 */ 182 public void setBinary(boolean binary) { 183 this.binary = binary; 184 } 185 186 /** 187 * Sets the name of the language to use 188 * 189 * @param languageName the name of the language 190 */ 191 public void setLanguageName(String languageName) { 192 this.languageName = languageName; 193 } 194 195 /** 196 * Path to the resource, or a reference to lookup a bean in the Registry to use as the resource 197 * 198 * @param resourceUri the resource path 199 */ 200 @Override 201 public void setResourceUri(String resourceUri) { 202 super.setResourceUri(resourceUri); 203 } 204 205 @Override 206 public String getResourceUri() { 207 return super.getResourceUri(); 208 } 209 210 /** 211 * Sets the script to execute 212 * 213 * @param script the script 214 */ 215 public void setScript(String script) { 216 this.script = script; 217 } 218 219 public String getScript() { 220 return script; 221 } 222 223 public boolean isContentResolvedFromResource() { 224 return contentResolvedFromResource; 225 } 226 227 public void setContentResolvedFromResource(boolean contentResolvedFromResource) { 228 this.contentResolvedFromResource = contentResolvedFromResource; 229 } 230 231 public boolean isCacheScript() { 232 return cacheScript; 233 } 234 235 /** 236 * Whether to cache the compiled script and reuse 237 * <p/> 238 * Notice reusing the script can cause side effects from processing one Camel 239 * {@link org.apache.camel.Exchange} to the next {@link org.apache.camel.Exchange}. 240 */ 241 public void setCacheScript(boolean cacheScript) { 242 this.cacheScript = cacheScript; 243 } 244 245 public void clearContentCache() { 246 super.clearContentCache(); 247 // must also clear expression and script 248 expression = null; 249 script = null; 250 } 251 252}