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