Coverage Report - org.mule.module.scripting.component.Scriptable
 
Classes in this File Line Coverage Branch Coverage Complexity
Scriptable
76%
68/89
69%
18/26
2.048
 
 1  
 /*
 2  
  * $Id: Scriptable.java 11884 2008-06-02 10:44:30Z rossmason $
 3  
  * --------------------------------------------------------------------------------------
 4  
  * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
 5  
  *
 6  
  * The software in this package is published under the terms of the CPAL v1.0
 7  
  * license, a copy of which has been included with this distribution in the
 8  
  * LICENSE.txt file.
 9  
  */
 10  
 
 11  
 package org.mule.module.scripting.component;
 12  
 
 13  
 import org.mule.MuleServer;
 14  
 import org.mule.DefaultMuleEventContext;
 15  
 import org.mule.transport.NullPayload;
 16  
 import org.mule.api.MuleEvent;
 17  
 import org.mule.api.lifecycle.Initialisable;
 18  
 import org.mule.api.lifecycle.InitialisationException;
 19  
 import org.mule.api.transformer.TransformerException;
 20  
 import org.mule.api.transport.MessageAdapter;
 21  
 import org.mule.config.i18n.CoreMessages;
 22  
 import org.mule.config.i18n.MessageFactory;
 23  
 import org.mule.util.CollectionUtils;
 24  
 import org.mule.util.IOUtils;
 25  
 import org.mule.util.StringUtils;
 26  
 
 27  
 import java.io.IOException;
 28  
 import java.io.InputStream;
 29  
 import java.io.InputStreamReader;
 30  
 import java.io.Reader;
 31  
 import java.io.StringReader;
 32  
 import java.util.Iterator;
 33  
 import java.util.Map;
 34  
 import java.util.Properties;
 35  
 
 36  
 import javax.script.Bindings;
 37  
 import javax.script.Compilable;
 38  
 import javax.script.CompiledScript;
 39  
 import javax.script.ScriptEngine;
 40  
 import javax.script.ScriptEngineManager;
 41  
 import javax.script.ScriptException;
 42  
 
 43  
 import org.apache.commons.logging.Log;
 44  
 import org.apache.commons.logging.LogFactory;
 45  
 
 46  
 /**
 47  
  * A JSR 223 Script service. Allows any JSR 223 compliant script engines such as
 48  
  * JavaScript, Groovy or Rhino to be embedded as Mule components.
 49  
  */
 50  136
 public class Scriptable implements Initialisable
 51  
 {
 52  
     /** The actual body of the script */
 53  
     private String scriptText;
 54  
     
 55  
     /** A file from which the script will be loaded */
 56  
     private String scriptFile;
 57  
     
 58  
     /** Parameters to be made available to the script as variables */
 59  
     private Properties properties;
 60  
 
 61  
     /** The name of the JSR 223 scripting engine (e.g., "groovy") */
 62  
     private String scriptEngineName;
 63  
 
 64  
     /////////////////////////////////////////////////////////////////////////////
 65  
     // Internal variables, not exposed as properties
 66  
     /////////////////////////////////////////////////////////////////////////////
 67  
 
 68  
     /** A compiled version of the script, if the scripting engine supports it */
 69  
     private CompiledScript compiledScript;
 70  
     
 71  
     private ScriptEngine scriptEngine;
 72  
     private ScriptEngineManager scriptEngineManager;
 73  
     
 74  136
     protected transient Log logger = LogFactory.getLog(getClass());
 75  
     
 76  
     public void initialise() throws InitialisationException
 77  
     {
 78  136
         scriptEngineManager = new ScriptEngineManager();
 79  
 
 80  
         // Create scripting engine
 81  136
         if (scriptEngineName != null)
 82  
         {
 83  110
             scriptEngine = createScriptEngineByName(scriptEngineName);
 84  110
             if (scriptEngine == null)
 85  
             {
 86  0
                 throw new InitialisationException(MessageFactory.createStaticMessage("Scripting engine '" + scriptEngineName + "' not found.  Available engines are: " + listAvailableEngines()), this);
 87  
             }
 88  
         }
 89  
         // Determine scripting engine to use by file extension
 90  26
         else if (scriptFile != null)
 91  
         {
 92  26
             int i = scriptFile.lastIndexOf(".");
 93  26
             if (i > -1)
 94  
             {
 95  26
                 logger.info("Script Engine name not set. Guessing by file extension.");
 96  26
                 String ext = scriptFile.substring(i + 1);
 97  26
                 scriptEngine = createScriptEngineByExtension(ext);
 98  26
                 if (scriptEngine == null)
 99  
                 {
 100  0
                     throw new InitialisationException(MessageFactory.createStaticMessage("File extension '" + ext + "' does not map to a scripting engine.  Available engines are: " + listAvailableEngines()), this);
 101  
                 }
 102  
                 else
 103  
                 {
 104  26
                     setScriptEngineName(scriptEngine.getFactory().getEngineName());
 105  
                 }
 106  
             }
 107  
         }
 108  
 
 109  
         Reader script;
 110  
         // Load script from variable
 111  136
         if (StringUtils.isNotBlank(scriptText))
 112  
         {
 113  78
             script = new StringReader(scriptText);
 114  
         }
 115  
         // Load script from file
 116  58
         else if (scriptFile != null)
 117  
         {
 118  
             InputStream is;
 119  
             try
 120  
             {
 121  58
                 is = IOUtils.getResourceAsStream(scriptFile, getClass());
 122  
             }
 123  0
             catch (IOException e)
 124  
             {
 125  0
                 throw new InitialisationException(CoreMessages.cannotLoadFromClasspath(scriptFile), e, this);
 126  58
             }
 127  58
             if (is == null)
 128  
             {
 129  0
                 throw new InitialisationException(CoreMessages.cannotLoadFromClasspath(scriptFile), this);
 130  
             }
 131  58
             script = new InputStreamReader(is);
 132  58
         }
 133  
         else
 134  
         {
 135  0
             throw new InitialisationException(CoreMessages.propertiesNotSet("scriptText, scriptFile"), this);
 136  
         }
 137  
 
 138  
         // Pre-compile script if scripting engine supports compilation.
 139  136
         if (scriptEngine instanceof Compilable)
 140  
         {
 141  
             try
 142  
             {
 143  136
                 compiledScript = ((Compilable) scriptEngine).compile(script);
 144  
             }
 145  0
             catch (ScriptException e)
 146  
             {
 147  0
                 throw new InitialisationException(e, this);
 148  136
             }
 149  
         }
 150  
 
 151  
 
 152  136
     }
 153  
 
 154  
     public void populateDefaultBindings(Bindings bindings)
 155  
     {
 156  70
         if (properties != null)
 157  
         {
 158  4
             bindings.putAll((Map) properties);
 159  
         }
 160  70
         bindings.put("log", logger);
 161  
         //A place holder for a retuen result if the script doesn't return a result.
 162  
         //The script can overwrite this binding
 163  70
         bindings.put("result", NullPayload.getInstance());
 164  70
         bindings.put("muleContext", MuleServer.getMuleContext());
 165  70
     }
 166  
 
 167  
     public void populateBindings(Bindings bindings, Object payload)
 168  
     {
 169  2
         populateDefaultBindings(bindings);
 170  2
         bindings.put("payload", payload);
 171  
         //For backward compatability. Usually used by the script transformer since
 172  
         //src maps with the argument passed into the transformer
 173  2
         bindings.put("src", payload);
 174  2
     }
 175  
     
 176  
     public void populateBindings(Bindings bindings, MessageAdapter message)
 177  
     {
 178  42
         populateDefaultBindings(bindings);
 179  42
         bindings.put("message", message);
 180  
         //This will get overwritten if populateBindings(Bindings bindings, MuleEvent event) is called
 181  
         //and not this method directly.
 182  42
         bindings.put("payload", message.getPayload());
 183  
         //For backward compatability
 184  42
         bindings.put("src", message.getPayload());
 185  
 
 186  
         // Set any message properties as variables for the script.
 187  
         String propertyName;
 188  42
         for (Iterator iterator = message.getPropertyNames().iterator(); iterator.hasNext();)
 189  
         {
 190  86
             propertyName = (String)iterator.next();
 191  86
             bindings.put(propertyName, message.getProperty(propertyName));
 192  
         }
 193  42
     }
 194  
 
 195  
     public void populateBindings(Bindings bindings, MuleEvent event)
 196  
     {
 197  16
         populateBindings(bindings, event.getMessage());
 198  16
         bindings.put("originalPayload", event.getMessage().getPayload());
 199  
 
 200  
         try
 201  
         {
 202  16
             bindings.put("payload", event.transformMessage());
 203  
         }
 204  0
         catch (TransformerException e)
 205  
         {
 206  0
             logger.warn(e);
 207  16
         }
 208  
         
 209  16
         bindings.put("eventContext", new DefaultMuleEventContext(event));
 210  16
         bindings.put("id", event.getId());
 211  16
         bindings.put("service", event.getService());
 212  16
     }
 213  
     
 214  
     public Object runScript(Bindings bindings) throws ScriptException
 215  
     {
 216  
         Object result;
 217  70
         if (compiledScript != null)
 218  
         {
 219  70
             result = compiledScript.eval(bindings);
 220  
         }
 221  
         else
 222  
         {
 223  0
             result = scriptEngine.eval(scriptText, bindings);
 224  
         }
 225  
         
 226  
         // The result of the script can be returned directly or it can
 227  
         // be set as the variable "result".
 228  68
         if (result == null)
 229  
         {
 230  26
             result = bindings.get("result");
 231  
         }
 232  68
         return result;
 233  
     }
 234  
 
 235  
     protected ScriptEngine createScriptEngineByName(String name)
 236  
     {
 237  110
         return scriptEngineManager.getEngineByName(name);
 238  
     }
 239  
 
 240  
     protected ScriptEngine createScriptEngineByExtension(String ext)
 241  
     {
 242  26
         return scriptEngineManager.getEngineByExtension(ext);
 243  
     }
 244  
 
 245  
     protected String listAvailableEngines()
 246  
     {
 247  0
         return CollectionUtils.toString(scriptEngineManager.getEngineFactories(), false);
 248  
     }
 249  
 
 250  
     ////////////////////////////////////////////////////////////////////////////////
 251  
     // Getters and setters
 252  
     ////////////////////////////////////////////////////////////////////////////////
 253  
 
 254  
     public String getScriptText()
 255  
     {
 256  0
         return scriptText;
 257  
     }
 258  
 
 259  
     public void setScriptText(String scriptText)
 260  
     {
 261  78
         this.scriptText = scriptText;
 262  78
     }
 263  
 
 264  
     public String getScriptFile()
 265  
     {
 266  0
         return scriptFile;
 267  
     }
 268  
 
 269  
     public void setScriptFile(String scriptFile)
 270  
     {
 271  58
         this.scriptFile = scriptFile;
 272  58
     }
 273  
 
 274  
     public void setScriptEngineName(String scriptEngineName)
 275  
     {
 276  136
         this.scriptEngineName = scriptEngineName;
 277  136
     }
 278  
 
 279  
     public String getScriptEngineName()
 280  
     {
 281  0
         return scriptEngineName;
 282  
     }
 283  
     
 284  
     public Properties getProperties()
 285  
     {
 286  0
         return properties;
 287  
     }
 288  
 
 289  
     public void setProperties(Properties properties)
 290  
     {
 291  24
         this.properties = properties;
 292  24
     }
 293  
     
 294  
     public ScriptEngine getScriptEngine()
 295  
     {
 296  70
         return scriptEngine;
 297  
     }
 298  
 
 299  
     protected void setScriptEngine(ScriptEngine scriptEngine)
 300  
     {
 301  0
         this.scriptEngine = scriptEngine;
 302  0
     }
 303  
 
 304  
     protected CompiledScript getCompiledScript()
 305  
     {
 306  0
         return compiledScript;
 307  
     }
 308  
 
 309  
     protected void setCompiledScript(CompiledScript compiledScript)
 310  
     {
 311  0
         this.compiledScript = compiledScript;
 312  0
     }
 313  
 }