Package org.mule.module.scripting.component

Source Code of org.mule.module.scripting.component.Scriptable$MesssagePropertyMap

/*
* Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
* The software in this package is published under the terms of the CPAL v1.0
* license, a copy of which has been included with this distribution in the
* LICENSE.txt file.
*/
package org.mule.module.scripting.component;

import org.mule.DefaultMuleEventContext;
import org.mule.DefaultMuleMessage;
import org.mule.api.MuleContext;
import org.mule.api.MuleEvent;
import org.mule.api.MuleMessage;
import org.mule.api.context.MuleContextAware;
import org.mule.api.lifecycle.Initialisable;
import org.mule.api.lifecycle.InitialisationException;
import org.mule.api.service.Service;
import org.mule.api.transport.PropertyScope;
import org.mule.config.i18n.CoreMessages;
import org.mule.config.i18n.MessageFactory;
import org.mule.transport.NullPayload;
import org.mule.util.CollectionUtils;
import org.mule.util.IOUtils;
import org.mule.util.StringUtils;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.util.Collection;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import javax.script.Bindings;
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
* A JSR 223 Script service. Allows any JSR 223 compliant script engines such as JavaScript, Groovy or Rhino
* to be embedded as Mule components.
*/
public class Scriptable implements Initialisable, MuleContextAware
{
    /** The actual body of the script */
    private String scriptText;

    /** A file from which the script will be loaded */
    private String scriptFile;

    /** Parameters to be made available to the script as variables */
    private Properties properties;

    /** The name of the JSR 223 scripting engine (e.g., "groovy") */
    private String scriptEngineName;

    // ///////////////////////////////////////////////////////////////////////////
    // Internal variables, not exposed as properties
    // ///////////////////////////////////////////////////////////////////////////

    /** A compiled version of the script, if the scripting engine supports it */
    private CompiledScript compiledScript;

    private ScriptEngine scriptEngine;
    private ScriptEngineManager scriptEngineManager;

    private MuleContext muleContext;

    protected transient Log logger = LogFactory.getLog(getClass());

    public Scriptable()
    {
        // For Spring
    }

    public Scriptable(MuleContext muleContext)
    {
        this.muleContext = muleContext;
    }

    public void setMuleContext(MuleContext context)
    {
        this.muleContext = context;
    }

    public void initialise() throws InitialisationException
    {
        scriptEngineManager = new ScriptEngineManager();

        // Create scripting engine
        if (scriptEngineName != null)
        {
            scriptEngine = createScriptEngineByName(scriptEngineName);
            if (scriptEngine == null)
            {
                throw new InitialisationException(
                    MessageFactory.createStaticMessage("Scripting engine '" + scriptEngineName
                                                       + "' not found.  Available engines are: "
                                                       + listAvailableEngines()), this);
            }
        }
        // Determine scripting engine to use by file extension
        else if (scriptFile != null)
        {
            int i = scriptFile.lastIndexOf(".");
            if (i > -1)
            {
                logger.info("Script Engine name not set. Guessing by file extension.");
                String ext = scriptFile.substring(i + 1);
                scriptEngine = createScriptEngineByExtension(ext);
                if (scriptEngine == null)
                {
                    throw new InitialisationException(
                        MessageFactory.createStaticMessage("File extension '"
                                                           + ext
                                                           + "' does not map to a scripting engine.  Available engines are: "
                                                           + listAvailableEngines()), this);
                }
                else
                {
                    setScriptEngineName(scriptEngine.getFactory().getEngineName());
                }
            }
        }

        Reader script = null;
        try
        {
            // Load script from variable
            if (StringUtils.isNotBlank(scriptText))
            {
                script = new StringReader(scriptText);
            }
            // Load script from file
            else if (scriptFile != null)
            {
                InputStream is;
                try
                {
                    is = IOUtils.getResourceAsStream(scriptFile, getClass());
                }
                catch (IOException e)
                {
                    throw new InitialisationException(CoreMessages.cannotLoadFromClasspath(scriptFile), e, this);
                }
                if (is == null)
                {
                    throw new InitialisationException(CoreMessages.cannotLoadFromClasspath(scriptFile), this);
                }
                script = new InputStreamReader(is);
            }
            else
            {
                throw new InitialisationException(CoreMessages.propertiesNotSet("scriptText, scriptFile"), this);
            }

            // Pre-compile script if scripting engine supports compilation.
            if (scriptEngine instanceof Compilable)
            {
                try
                {
                    compiledScript = ((Compilable) scriptEngine).compile(script);
                }
                catch (ScriptException e)
                {
                    throw new InitialisationException(e, this);
                }
            }
        }
        finally
        {
            if (script != null)
            {
                try
                {
                    script.close();
                }
                catch (IOException e)
                {
                    throw new InitialisationException(e, this);
                }
            }
        }
    }

    public void populateDefaultBindings(Bindings bindings)
    {
        if (properties != null)
        {
            bindings.putAll((Map) properties);
        }
        bindings.put("log", logger);
        // A place holder for a returned result if the script doesn't return a result.
        // The script can overwrite this binding
        bindings.put("result", NullPayload.getInstance());
        bindings.put("muleContext", muleContext);
        bindings.put("registry", muleContext.getRegistry());
    }

    public void populateBindings(Bindings bindings, Object payload)
    {
        populateDefaultBindings(bindings);
        bindings.put("payload", payload);
        // For backward compatability. Usually used by the script transformer since
        // src maps with the argument passed into the transformer
        bindings.put("src", payload);
    }

    public void populateBindings(Bindings bindings, MuleMessage message)
    {
        populateDefaultBindings(bindings);
        if (message == null)
        {
            message = new DefaultMuleMessage(NullPayload.getInstance(), muleContext);
        }

        populateVariablesInOrder(bindings, message);

        bindings.put("message", message);
        // This will get overwritten if populateBindings(Bindings bindings, MuleEvent event) is called
        // and not this method directly.
        bindings.put("payload", message.getPayload());
        // For backward compatability
        bindings.put("src", message.getPayload());

        populateHeadersVariablesAndException(bindings, message);
    }

    public void populateBindings(Bindings bindings, MuleEvent event)
    {
        populateBindings(bindings, event.getMessage());
        bindings.put("originalPayload", event.getMessage().getPayload());
        bindings.put("payload", event.getMessage().getPayload());
        bindings.put("eventContext", new DefaultMuleEventContext(event));
        bindings.put("id", event.getId());
        bindings.put("flowConstruct", event.getFlowConstruct());
        if (event.getFlowConstruct() instanceof Service)
        {
            bindings.put("service", event.getFlowConstruct());
        }
    }

    private void populateHeadersVariablesAndException(Bindings bindings, MuleMessage message)
    {
        bindings.put("flowVars", new MesssagePropertyMap(message, PropertyScope.INVOCATION));
        bindings.put("sessionVars", new MesssagePropertyMap(message, PropertyScope.SESSION));

        // Only add exception is present
        if (message.getExceptionPayload() != null)
        {
            bindings.put("exception", message.getExceptionPayload().getException());
        }
        else
        {
            bindings.put("exception", null);
        }
    }

    private void populateVariablesInOrder(Bindings bindings, MuleMessage message)
    {
        for (String key : message.getSessionPropertyNames())
        {
            bindings.put(key, message.getSessionProperty(key));
        }
        for (String key : message.getInvocationPropertyNames())
        {
            bindings.put(key, message.getInvocationProperty(key));
        }
    }

    public Object runScript(Bindings bindings) throws ScriptException
    {
        Object result;
        try
        {
            RegistryLookupBindings registryLookupBindings = new RegistryLookupBindings(
                muleContext.getRegistry(), bindings);
            if (compiledScript != null)
            {
                result = compiledScript.eval(registryLookupBindings);
            }
            else
            {
                result = scriptEngine.eval(scriptText, registryLookupBindings);
            }

            // The result of the script can be returned directly or it can
            // be set as the variable "result".
            if (result == null)
            {
                result = registryLookupBindings.get("result");
            }
        }
        catch (ScriptException e)
        {
            // re-throw
            throw e;
        }
        catch (Exception ex)
        {
            throw new ScriptException(ex);
        }
        return result;
    }

    protected ScriptEngine createScriptEngineByName(String name)
    {
        return scriptEngineManager.getEngineByName(name);
    }

    protected ScriptEngine createScriptEngineByExtension(String ext)
    {
        return scriptEngineManager.getEngineByExtension(ext);
    }

    protected String listAvailableEngines()
    {
        return CollectionUtils.toString(scriptEngineManager.getEngineFactories(), false);
    }

    // //////////////////////////////////////////////////////////////////////////////
    // Getters and setters
    // //////////////////////////////////////////////////////////////////////////////

    public String getScriptText()
    {
        return scriptText;
    }

    public void setScriptText(String scriptText)
    {
        this.scriptText = scriptText;
    }

    public String getScriptFile()
    {
        return scriptFile;
    }

    public void setScriptFile(String scriptFile)
    {
        this.scriptFile = scriptFile;
    }

    public void setScriptEngineName(String scriptEngineName)
    {
        this.scriptEngineName = scriptEngineName;
    }

    public String getScriptEngineName()
    {
        return scriptEngineName;
    }

    public Properties getProperties()
    {
        return properties;
    }

    public void setProperties(Properties properties)
    {
        this.properties = properties;
    }

    public ScriptEngine getScriptEngine()
    {
        return scriptEngine;
    }

    protected void setScriptEngine(ScriptEngine scriptEngine)
    {
        this.scriptEngine = scriptEngine;
    }

    protected CompiledScript getCompiledScript()
    {
        return compiledScript;
    }

    protected void setCompiledScript(CompiledScript compiledScript)
    {
        this.compiledScript = compiledScript;
    }

    private static class MesssagePropertyMap implements Map<String, Object>
    {
        MuleMessage message;
        PropertyScope propertyScope;

        public MesssagePropertyMap(MuleMessage message, PropertyScope propertyScope)
        {
            this.message = message;
            this.propertyScope = propertyScope;
        }

        @Override
        public void clear()
        {
            message.clearProperties(propertyScope);
        }

        @Override
        public boolean containsKey(Object key)
        {
            return message.getPropertyNames(propertyScope).contains(key);
        }

        @Override
        public boolean containsValue(Object value)
        {
            throw new UnsupportedOperationException();
        }

        @Override
        public Set<java.util.Map.Entry<String, Object>> entrySet()
        {
            throw new UnsupportedOperationException();
        }

        @Override
        public Object get(Object key)
        {
            return message.getProperty((String) key, propertyScope);
        }

        @Override
        public boolean isEmpty()
        {
            return message.getPropertyNames(propertyScope).isEmpty();
        }

        @Override
        public Set<String> keySet()
        {
            return message.getPropertyNames(propertyScope);
        }

        @Override
        public Object put(String key, Object value)
        {
            if (PropertyScope.INBOUND.equals(propertyScope))
            {
                throw new UnsupportedOperationException("Inbound message properties are read-only");
            }
            else
            {
                message.setProperty(key, value, propertyScope);
                return value;
            }
        }

        @Override
        public void putAll(Map<? extends String, ? extends Object> m)
        {
            for (Map.Entry<? extends String, ? extends Object> entry : m.entrySet())
            {
                put(entry.getKey(), entry.getValue());
            }
        }

        @Override
        public Object remove(Object key)
        {
            if (PropertyScope.INBOUND.equals(propertyScope))
            {
                throw new UnsupportedOperationException("Inbound message properties are read-only");
            }
            else
            {
                return message.removeProperty((String) key, propertyScope);
            }
        }

        @Override
        public int size()
        {
            return message.getPropertyNames(propertyScope).size();
        }

        @Override
        public Collection<Object> values()
        {
            throw new UnsupportedOperationException();
        }
    }

}
TOP

Related Classes of org.mule.module.scripting.component.Scriptable$MesssagePropertyMap

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.