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