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