Coverage Report - org.apache.camel.builder.script.ScriptBuilder
 
Classes in this File Line Coverage Branch Coverage Complexity
ScriptBuilder
50% 
77% 
0
 
 1  
 /**
 2  
  * Licensed to the Apache Software Foundation (ASF) under one or more
 3  
  * contributor license agreements.  See the NOTICE file distributed with
 4  
  * this work for additional information regarding copyright ownership.
 5  
  * The ASF licenses this file to You under the Apache License, Version 2.0
 6  
  * (the "License"); you may not use this file except in compliance with
 7  
  * the License.  You may obtain a copy of the License at
 8  
  *
 9  
  *      http://www.apache.org/licenses/LICENSE-2.0
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 package org.apache.camel.builder.script;
 18  
 
 19  
 import java.io.File;
 20  
 import java.io.IOException;
 21  
 import java.io.InputStreamReader;
 22  
 import java.net.URL;
 23  
 
 24  
 import javax.script.Compilable;
 25  
 import javax.script.CompiledScript;
 26  
 import javax.script.ScriptContext;
 27  
 import javax.script.ScriptEngine;
 28  
 import javax.script.ScriptEngineManager;
 29  
 import javax.script.ScriptException;
 30  
 
 31  
 import org.apache.camel.Exchange;
 32  
 import org.apache.camel.Expression;
 33  
 import org.apache.camel.Predicate;
 34  
 import org.apache.camel.Processor;
 35  
 import org.apache.camel.converter.ObjectConverter;
 36  
 import org.apache.commons.logging.Log;
 37  
 import org.apache.commons.logging.LogFactory;
 38  
 
 39  
 import org.springframework.core.io.FileSystemResource;
 40  
 import org.springframework.core.io.Resource;
 41  
 import org.springframework.core.io.UrlResource;
 42  
 
 43  
 /**
 44  
  * A builder class for creating {@link Processor}, {@link Expression} and
 45  
  * {@link Predicate} objects using the JSR 223 scripting engine.
 46  
  * 
 47  
  * @version $Revision: 563665 $
 48  
  */
 49  9
 public class ScriptBuilder<E extends Exchange> implements Expression<E>, Predicate<E>, Processor {
 50  1
     private static final transient Log LOG = LogFactory.getLog(ScriptBuilder.class);
 51  
 
 52  
     private String scriptEngineName;
 53  
     private Resource scriptResource;
 54  
     private String scriptText;
 55  
     private ScriptEngine engine;
 56  
     private CompiledScript compiledScript;
 57  
 
 58  13
     public ScriptBuilder(String scriptEngineName) {
 59  13
         this.scriptEngineName = scriptEngineName;
 60  13
     }
 61  
 
 62  
     public ScriptBuilder(String scriptEngineName, String scriptText) {
 63  13
         this(scriptEngineName);
 64  13
         this.scriptText = scriptText;
 65  13
     }
 66  
 
 67  
     public ScriptBuilder(String scriptEngineName, Resource scriptResource) {
 68  0
         this(scriptEngineName);
 69  0
         this.scriptResource = scriptResource;
 70  0
     }
 71  
 
 72  
     @Override
 73  
     public String toString() {
 74  20
         return getScriptDescription();
 75  
     }
 76  
 
 77  
     public Object evaluate(E exchange) {
 78  6
         return evaluateScript(exchange);
 79  
     }
 80  
 
 81  
     public boolean matches(E exchange) {
 82  6
         Object scriptValue = evaluateScript(exchange);
 83  6
         return matches(exchange, scriptValue);
 84  
     }
 85  
 
 86  
     public void assertMatches(String text, E exchange) throws AssertionError {
 87  3
         Object scriptValue = evaluateScript(exchange);
 88  3
         if (!matches(exchange, scriptValue)) {
 89  0
             throw new AssertionError(this + " failed on " + exchange + " as script returned <" + scriptValue + ">");
 90  
         }
 91  3
     }
 92  
 
 93  
     public void process(Exchange exchange) {
 94  1
         evaluateScript(exchange);
 95  1
     }
 96  
 
 97  
     // Builder API
 98  
     // -------------------------------------------------------------------------
 99  
 
 100  
     /**
 101  
      * Sets the attribute on the context so that it is available to the script
 102  
      * as a variable in the {@link ScriptContext#ENGINE_SCOPE}
 103  
      * 
 104  
      * @param name the name of the attribute
 105  
      * @param value the attribute value
 106  
      * @return this builder
 107  
      */
 108  
     public ScriptBuilder attribute(String name, Object value) {
 109  1
         getScriptContext().setAttribute(name, value, ScriptContext.ENGINE_SCOPE);
 110  1
         return this;
 111  
     }
 112  
 
 113  
     // Create any scripting language builder recognised by JSR 223
 114  
     // -------------------------------------------------------------------------
 115  
 
 116  
     /**
 117  
      * Creates a script builder for the named language and script contents
 118  
      * 
 119  
      * @param language the language to use for the script
 120  
      * @param scriptText the script text to be evaluted
 121  
      * @return the builder
 122  
      */
 123  
     public static ScriptBuilder script(String language, String scriptText) {
 124  0
         return new ScriptBuilder(language, scriptText);
 125  
     }
 126  
 
 127  
     /**
 128  
      * Creates a script builder for the named language and script
 129  
      * 
 130  
      * @{link Resource}
 131  
      * @param language the language to use for the script
 132  
      * @param scriptResource the resource used to load the script
 133  
      * @return the builder
 134  
      */
 135  
     public static ScriptBuilder script(String language, Resource scriptResource) {
 136  0
         return new ScriptBuilder(language, scriptResource);
 137  
     }
 138  
 
 139  
     /**
 140  
      * Creates a script builder for the named language and script
 141  
      * 
 142  
      * @{link File}
 143  
      * @param language the language to use for the script
 144  
      * @param scriptFile the file used to load the script
 145  
      * @return the builder
 146  
      */
 147  
     public static ScriptBuilder script(String language, File scriptFile) {
 148  0
         return new ScriptBuilder(language, new FileSystemResource(scriptFile));
 149  
     }
 150  
 
 151  
     /**
 152  
      * Creates a script builder for the named language and script
 153  
      * 
 154  
      * @{link URL}
 155  
      * @param language the language to use for the script
 156  
      * @param scriptURL the URL used to load the script
 157  
      * @return the builder
 158  
      */
 159  
     public static ScriptBuilder script(String language, URL scriptURL) {
 160  0
         return new ScriptBuilder(language, new UrlResource(scriptURL));
 161  
     }
 162  
 
 163  
     // Groovy
 164  
     // -------------------------------------------------------------------------
 165  
 
 166  
     /**
 167  
      * Creates a script builder for the groovy script contents
 168  
      * 
 169  
      * @param scriptText the script text to be evaluted
 170  
      * @return the builder
 171  
      */
 172  
     public static ScriptBuilder groovy(String scriptText) {
 173  9
         return new ScriptBuilder("groovy", scriptText);
 174  
     }
 175  
 
 176  
     /**
 177  
      * Creates a script builder for the groovy script
 178  
      * 
 179  
      * @{link Resource}
 180  
      * @param scriptResource the resource used to load the script
 181  
      * @return the builder
 182  
      */
 183  
     public static ScriptBuilder groovy(Resource scriptResource) {
 184  0
         return new ScriptBuilder("groovy", scriptResource);
 185  
     }
 186  
 
 187  
     /**
 188  
      * Creates a script builder for the groovy script
 189  
      * 
 190  
      * @{link File}
 191  
      * @param scriptFile the file used to load the script
 192  
      * @return the builder
 193  
      */
 194  
     public static ScriptBuilder groovy(File scriptFile) {
 195  0
         return new ScriptBuilder("groovy", new FileSystemResource(scriptFile));
 196  
     }
 197  
 
 198  
     /**
 199  
      * Creates a script builder for the groovy script
 200  
      * 
 201  
      * @{link URL}
 202  
      * @param scriptURL the URL used to load the script
 203  
      * @return the builder
 204  
      */
 205  
     public static ScriptBuilder groovy(URL scriptURL) {
 206  0
         return new ScriptBuilder("groovy", new UrlResource(scriptURL));
 207  
     }
 208  
 
 209  
     // JavaScript
 210  
     // -------------------------------------------------------------------------
 211  
 
 212  
     /**
 213  
      * Creates a script builder for the JavaScript/ECMAScript script contents
 214  
      * 
 215  
      * @param scriptText the script text to be evaluted
 216  
      * @return the builder
 217  
      */
 218  
     public static ScriptBuilder javaScript(String scriptText) {
 219  0
         return new ScriptBuilder("js", scriptText);
 220  
     }
 221  
 
 222  
     /**
 223  
      * Creates a script builder for the JavaScript/ECMAScript script
 224  
      * 
 225  
      * @{link Resource}
 226  
      * @param scriptResource the resource used to load the script
 227  
      * @return the builder
 228  
      */
 229  
     public static ScriptBuilder javaScript(Resource scriptResource) {
 230  0
         return new ScriptBuilder("js", scriptResource);
 231  
     }
 232  
 
 233  
     /**
 234  
      * Creates a script builder for the JavaScript/ECMAScript script
 235  
      * 
 236  
      * @{link File}
 237  
      * @param scriptFile the file used to load the script
 238  
      * @return the builder
 239  
      */
 240  
     public static ScriptBuilder javaScript(File scriptFile) {
 241  0
         return new ScriptBuilder("js", new FileSystemResource(scriptFile));
 242  
     }
 243  
 
 244  
     /**
 245  
      * Creates a script builder for the JavaScript/ECMAScript script
 246  
      * 
 247  
      * @{link URL}
 248  
      * @param scriptURL the URL used to load the script
 249  
      * @return the builder
 250  
      */
 251  
     public static ScriptBuilder javaScript(URL scriptURL) {
 252  0
         return new ScriptBuilder("js", new UrlResource(scriptURL));
 253  
     }
 254  
 
 255  
     // PHP
 256  
     // -------------------------------------------------------------------------
 257  
 
 258  
     /**
 259  
      * Creates a script builder for the PHP script contents
 260  
      * 
 261  
      * @param scriptText the script text to be evaluted
 262  
      * @return the builder
 263  
      */
 264  
     public static ScriptBuilder php(String scriptText) {
 265  0
         return new ScriptBuilder("php", scriptText);
 266  
     }
 267  
 
 268  
     /**
 269  
      * Creates a script builder for the PHP script
 270  
      * 
 271  
      * @{link Resource}
 272  
      * @param scriptResource the resource used to load the script
 273  
      * @return the builder
 274  
      */
 275  
     public static ScriptBuilder php(Resource scriptResource) {
 276  0
         return new ScriptBuilder("php", scriptResource);
 277  
     }
 278  
 
 279  
     /**
 280  
      * Creates a script builder for the PHP script
 281  
      * 
 282  
      * @{link File}
 283  
      * @param scriptFile the file used to load the script
 284  
      * @return the builder
 285  
      */
 286  
     public static ScriptBuilder php(File scriptFile) {
 287  0
         return new ScriptBuilder("php", new FileSystemResource(scriptFile));
 288  
     }
 289  
 
 290  
     /**
 291  
      * Creates a script builder for the PHP script
 292  
      * 
 293  
      * @{link URL}
 294  
      * @param scriptURL the URL used to load the script
 295  
      * @return the builder
 296  
      */
 297  
     public static ScriptBuilder php(URL scriptURL) {
 298  0
         return new ScriptBuilder("php", new UrlResource(scriptURL));
 299  
     }
 300  
 
 301  
     // Python
 302  
     // -------------------------------------------------------------------------
 303  
 
 304  
     /**
 305  
      * Creates a script builder for the Python script contents
 306  
      * 
 307  
      * @param scriptText the script text to be evaluted
 308  
      * @return the builder
 309  
      */
 310  
     public static ScriptBuilder python(String scriptText) {
 311  0
         return new ScriptBuilder("python", scriptText);
 312  
     }
 313  
 
 314  
     /**
 315  
      * Creates a script builder for the Python script
 316  
      * 
 317  
      * @{link Resource}
 318  
      * @param scriptResource the resource used to load the script
 319  
      * @return the builder
 320  
      */
 321  
     public static ScriptBuilder python(Resource scriptResource) {
 322  0
         return new ScriptBuilder("python", scriptResource);
 323  
     }
 324  
 
 325  
     /**
 326  
      * Creates a script builder for the Python script
 327  
      * 
 328  
      * @{link File}
 329  
      * @param scriptFile the file used to load the script
 330  
      * @return the builder
 331  
      */
 332  
     public static ScriptBuilder python(File scriptFile) {
 333  0
         return new ScriptBuilder("python", new FileSystemResource(scriptFile));
 334  
     }
 335  
 
 336  
     /**
 337  
      * Creates a script builder for the Python script
 338  
      * 
 339  
      * @{link URL}
 340  
      * @param scriptURL the URL used to load the script
 341  
      * @return the builder
 342  
      */
 343  
     public static ScriptBuilder python(URL scriptURL) {
 344  0
         return new ScriptBuilder("python", new UrlResource(scriptURL));
 345  
     }
 346  
 
 347  
     // Ruby/JRuby
 348  
     // -------------------------------------------------------------------------
 349  
 
 350  
     /**
 351  
      * Creates a script builder for the Ruby/JRuby script contents
 352  
      * 
 353  
      * @param scriptText the script text to be evaluted
 354  
      * @return the builder
 355  
      */
 356  
     public static ScriptBuilder ruby(String scriptText) {
 357  0
         return new ScriptBuilder("jruby", scriptText);
 358  
     }
 359  
 
 360  
     /**
 361  
      * Creates a script builder for the Ruby/JRuby script
 362  
      * 
 363  
      * @{link Resource}
 364  
      * @param scriptResource the resource used to load the script
 365  
      * @return the builder
 366  
      */
 367  
     public static ScriptBuilder ruby(Resource scriptResource) {
 368  0
         return new ScriptBuilder("jruby", scriptResource);
 369  
     }
 370  
 
 371  
     /**
 372  
      * Creates a script builder for the Ruby/JRuby script
 373  
      * 
 374  
      * @{link File}
 375  
      * @param scriptFile the file used to load the script
 376  
      * @return the builder
 377  
      */
 378  
     public static ScriptBuilder ruby(File scriptFile) {
 379  0
         return new ScriptBuilder("jruby", new FileSystemResource(scriptFile));
 380  
     }
 381  
 
 382  
     /**
 383  
      * Creates a script builder for the Ruby/JRuby script
 384  
      * 
 385  
      * @{link URL}
 386  
      * @param scriptURL the URL used to load the script
 387  
      * @return the builder
 388  
      */
 389  
     public static ScriptBuilder ruby(URL scriptURL) {
 390  0
         return new ScriptBuilder("jruby", new UrlResource(scriptURL));
 391  
     }
 392  
 
 393  
     // Properties
 394  
     // -------------------------------------------------------------------------
 395  
     public ScriptEngine getEngine() {
 396  33
         checkInitialised();
 397  33
         return engine;
 398  
     }
 399  
 
 400  
     public CompiledScript getCompiledScript() {
 401  0
         return compiledScript;
 402  
     }
 403  
 
 404  
     public String getScriptText() {
 405  0
         return scriptText;
 406  
     }
 407  
 
 408  
     public void setScriptText(String scriptText) {
 409  0
         this.scriptText = scriptText;
 410  0
     }
 411  
 
 412  
     public String getScriptEngineName() {
 413  0
         return scriptEngineName;
 414  
     }
 415  
 
 416  
     /**
 417  
      * Returns a description of the script
 418  
      * 
 419  
      * @return the script description
 420  
      */
 421  
     public String getScriptDescription() {
 422  21
         if (scriptText != null) {
 423  21
             return scriptEngineName + ": " + scriptText;
 424  0
         } else if (scriptResource != null) {
 425  0
             return scriptEngineName + ": " + scriptResource.getDescription();
 426  
         } else {
 427  0
             return scriptEngineName + ": null script";
 428  
         }
 429  
     }
 430  
 
 431  
     /**
 432  
      * Access the script context so that it can be configured such as adding
 433  
      * attributes
 434  
      */
 435  
     public ScriptContext getScriptContext() {
 436  17
         return getEngine().getContext();
 437  
     }
 438  
 
 439  
     /**
 440  
      * Sets the context to use by the script
 441  
      */
 442  
     public void setScriptContext(ScriptContext scriptContext) {
 443  0
         getEngine().setContext(scriptContext);
 444  0
     }
 445  
 
 446  
     public Resource getScriptResource() {
 447  0
         return scriptResource;
 448  
     }
 449  
 
 450  
     public void setScriptResource(Resource scriptResource) {
 451  0
         this.scriptResource = scriptResource;
 452  0
     }
 453  
 
 454  
     // Implementation methods
 455  
     // -------------------------------------------------------------------------
 456  
     protected void checkInitialised() {
 457  49
         if (scriptText == null && scriptResource == null) {
 458  0
             throw new IllegalArgumentException("Neither scriptText or scriptResource are specified");
 459  
         }
 460  49
         if (engine == null) {
 461  13
             engine = createScriptEngine();
 462  
         }
 463  49
         if (compiledScript == null) {
 464  13
             if (engine instanceof Compilable) {
 465  13
                 compileScript((Compilable)engine);
 466  
             }
 467  
         }
 468  49
     }
 469  
 
 470  
     protected boolean matches(E exchange, Object scriptValue) {
 471  9
         return ObjectConverter.toBoolean(scriptValue);
 472  
     }
 473  
 
 474  
     protected ScriptEngine createScriptEngine() {
 475  13
         ScriptEngineManager manager = new ScriptEngineManager();
 476  13
         return manager.getEngineByName(scriptEngineName);
 477  
     }
 478  
 
 479  
     protected void compileScript(Compilable compilable) {
 480  
         try {
 481  13
             if (scriptText != null) {
 482  13
                 compiledScript = compilable.compile(scriptText);
 483  13
             } else if (scriptResource != null) {
 484  0
                 compiledScript = compilable.compile(createScriptReader());
 485  
             }
 486  0
         } catch (ScriptException e) {
 487  0
             if (LOG.isDebugEnabled()) {
 488  0
                 LOG.debug("Script compile failed: " + e, e);
 489  
             }
 490  0
             throw createScriptCompileException(e);
 491  0
         } catch (IOException e) {
 492  0
             throw createScriptCompileException(e);
 493  13
         }
 494  13
     }
 495  
 
 496  
     protected synchronized Object evaluateScript(Exchange exchange) {
 497  
         try {
 498  16
             getScriptContext();
 499  16
             populateBindings(getEngine(), exchange);
 500  16
             return runScript();
 501  1
         } catch (ScriptException e) {
 502  1
             if (LOG.isDebugEnabled()) {
 503  0
                 LOG.debug("Script evaluation failed: " + e, e);
 504  
             }
 505  1
             throw createScriptEvaluationException(e.getCause());
 506  0
         } catch (IOException e) {
 507  0
             throw createScriptEvaluationException(e);
 508  
         }
 509  
     }
 510  
 
 511  
     protected Object runScript() throws ScriptException, IOException {
 512  16
         checkInitialised();
 513  16
         if (compiledScript != null) {
 514  16
             return compiledScript.eval();
 515  
         } else {
 516  0
             if (scriptText != null) {
 517  0
                 return getEngine().eval(scriptText);
 518  
             } else {
 519  0
                 return getEngine().eval(createScriptReader());
 520  
             }
 521  
         }
 522  
     }
 523  
 
 524  
     protected void populateBindings(ScriptEngine engine, Exchange exchange) {
 525  16
         ScriptContext context = engine.getContext();
 526  16
         int scope = ScriptContext.ENGINE_SCOPE;
 527  16
         context.setAttribute("context", exchange.getContext(), scope);
 528  16
         context.setAttribute("exchange", exchange, scope);
 529  16
         context.setAttribute("request", exchange.getIn(), scope);
 530  16
         context.setAttribute("response", exchange.getOut(), scope);
 531  16
     }
 532  
 
 533  
     protected InputStreamReader createScriptReader() throws IOException {
 534  
         // TODO consider character sets?
 535  0
         return new InputStreamReader(scriptResource.getInputStream());
 536  
     }
 537  
 
 538  
     protected ScriptEvaluationException createScriptCompileException(Exception e) {
 539  0
         return new ScriptEvaluationException("Failed to compile: " + getScriptDescription() + ". Cause: " + e, e);
 540  
     }
 541  
 
 542  
     protected ScriptEvaluationException createScriptEvaluationException(Throwable e) {
 543  1
         return new ScriptEvaluationException("Failed to evaluate: " + getScriptDescription() + ". Cause: " + e, e);
 544  
     }
 545  
 
 546  
 }