Package org.jboss.soa.esb.actions.scripting

Source Code of org.jboss.soa.esb.actions.scripting.ScriptingAction

/*
* JBoss, Home of Professional Open Source
* Copyright 2007, JBoss Inc., and others contributors as indicated
* by the @authors tag. All rights reserved.
* See the copyright.txt in the distribution for a
* full listing of individual contributors.
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License, v. 2.1.
* This program is distributed in the hope that it will be useful, but WITHOUT A
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License,
* v.2.1 along with this distribution; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA  02110-1301, USA.
*
* (C) 2005-2007,
*/

package org.jboss.soa.esb.actions.scripting;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;

import org.apache.bsf.BSFException;
import org.apache.bsf.BSFManager;
import org.apache.log4j.Logger;
import org.jboss.internal.soa.esb.util.StreamUtils;
import org.jboss.soa.esb.actions.AbstractActionPipelineProcessor;
import org.jboss.soa.esb.actions.ActionLifecycleException;
import org.jboss.soa.esb.actions.ActionProcessingException;
import org.jboss.soa.esb.helpers.ConfigTree;
import org.jboss.soa.esb.listeners.message.MessageDeliverException;
import org.jboss.soa.esb.message.Message;
import org.jboss.soa.esb.message.MessagePayloadProxy;
import org.jboss.soa.esb.util.ClassUtil;

/**
* <a href="http://jakarta.apache.org/bsf/">BSF</a> Scripting action pipeline processor.
* <p/>
* Based on {@link GroovyActionProcessor} by Gregory Pierce and Tom Fennelly.
* <p>
* <pre>
* &lt;action name="helloWorld" class="org.jboss.soa.esb.actions.scripting.ScriptingAction"&gt;
*     &lt;property name="script" value="/scripts/helloWorld.ext"/&gt;
*     &lt;-- The language property is not required; it is deduced via the script extension but can be overridden --&gt;
*     &lt;property name="language" value="languageDescriptor"/&gt;
* &lt;/action&gt;
* </pre>
* </p>
* The {@link Message} is bound into the script with the name "message".
* The {@link ConfigTree} is bound into the script with the name "config".
* The {@link MessagePayloadProxy} is bound into the script with the name "payloadProxy".
* The {@link Logger} is bound into the script with the name "logger".
* <p/>
* The script can also be supplied to this action as the message payload, allowing you to
* dynamically supply the action script.  For message based scripts to be executable,
* the "script" action property must be omitted and the "supportMessageBasedScripting" property must
* be set to "true".  There are obvious security issues around executing message based scripts,
* so use this feature controlled manner.
* <p/>
* The following are the supported scripting languages, although the developer
* is responsible for including the appropriate 3rd party libraries (from bsf.jar's
* org/apache/bsf/Languages.properties):
*
* <pre>
* # List of script types and their associated scripting engines
* #
* # languageDescriptor = engineClass, ext1|ext2|... {, codebaseURL, ...}
* #
* # where exti are extensions for the language. Note that we leave
* # all the engines enabled now and allow them to fail at load time.
* # This way engines can be added by just adding to the classpath
* # without having to edit this file. Cheating, really, but it works.
* #
* javascript = org.apache.bsf.engines.javascript.JavaScriptEngine, js
* jacl = org.apache.bsf.engines.jacl.JaclEngine, jacl
* netrexx = org.apache.bsf.engines.netrexx.NetRexxEngine, nrx
* java = org.apache.bsf.engines.java.JavaEngine, java
* javaclass = org.apache.bsf.engines.javaclass.JavaClassEngine, class
* bml = org.apache.bml.ext.BMLEngine, bml
* vbscript = org.apache.bsf.engines.activescript.ActiveScriptEngine, vbs
* jscript = org.apache.bsf.engines.activescript.ActiveScriptEngine, jss
* perlscript = org.apache.bsf.engines.activescript.ActiveScriptEngine, pls
* perl = org.apache.bsf.engines.perl.PerlEngine, pl
* jpython = org.apache.bsf.engines.jpython.JPythonEngine, py
* jython = org.apache.bsf.engines.jython.JythonEngine, py
* lotusscript = org.apache.bsf.engines.lotusscript.LsEngine, lss
* xslt = org.apache.bsf.engines.xslt.XSLTEngine, xslt
* pnuts = pnuts.ext.PnutsBSFEngine, pnut
* beanbasic = org.apache.bsf.engines.beanbasic.BeanBasicEngine, bb
* beanshell = bsh.util.BeanShellBSFEngine, bsh
* ruby = org.jruby.javasupport.bsf.JRubyEngine, rb
* judoscript = com.judoscript.BSFJudoEngine, judo|jud
* </pre>
*
* @author dward at jboss.org
*/
public class ScriptingAction extends AbstractActionPipelineProcessor
{

  private static Logger logger = Logger.getLogger(ScriptingAction.class);

  // this is a map of extension(s) -> language
  private static final Map<String,String> EXTN2LANG = new HashMap<String,String>();

  static
  {
    InputStream is = null;
    try
    {
      is = BSFManager.class.getClassLoader().getResourceAsStream("org/apache/bsf/Languages.properties");
      is = new BufferedInputStream(is);
      Properties props = new Properties();
      props.load(is);
      for (Enumeration<?> names = props.propertyNames(); names.hasMoreElements();)
      {
        String lang = (String)names.nextElement();
        StringTokenizer st = new StringTokenizer(props.getProperty(lang), ",");
        st.nextToken(); // throw out the engine class name
        st = new StringTokenizer(st.nextToken(), "|");
        while ( st.hasMoreTokens() ) // now get each extension
          EXTN2LANG.put(st.nextToken().trim(), lang);
      }
    }
    catch (IOException ioe) {}
    finally
    {
      try { if (is != null) is.close(); } catch (Throwable t) {}
    }
  }

  private ConfigTree config;
  private MessagePayloadProxy payloadProxy;
  private String script ;
  private String source ;
  private String language ;

  public ScriptingAction(ConfigTree config)
  {
    this.config = config;
    payloadProxy = new MessagePayloadProxy(config);
  }

  public void initialise() throws ActionLifecycleException
  {
    // attempt to get the script
    String scriptPath = getAttribute("script");
    final String source ;
    if (scriptPath == null)
    {
      boolean supportMessageBasedScripting = config.getBooleanAttribute("supportMessageBasedScripting", false);
      if(supportMessageBasedScripting)
      {
        if ( logger.isDebugEnabled() )
        {
          logger.debug("No script specified on action config " + config.getAttribute("name")
            + ". Expecting script to be in message.");
        }
        source = "Embedded script in message" ;
      }
      else
      {
        throw new ActionLifecycleException("'script' not configured on the action and message based scripting is not enabled ('supportMessageBasedScripting=false').");
      }
    }
    else
    {
      InputStream scriptStream = null;
      try
      {
        scriptStream = ClassUtil.getResourceAsStream(scriptPath, ScriptingAction.class);
        if (scriptStream != null)
        {
          scriptStream = new BufferedInputStream(scriptStream);
          script = new String( StreamUtils.readStream(scriptStream) );
        }
        else
        {
          throw new ActionLifecycleException("script '" + scriptPath + "' not found on classpath");
        }
      }
      catch (Throwable t)
      {
        throw new ActionLifecycleException(t);
      }
      finally
      {
        try { if (scriptStream != null) scriptStream.close(); } catch (Throwable t) {}
      }
      source = scriptPath ;
    }
    this.source = source ;
    // attempt to get the language
    language = getAttribute("language");
    if (language == null && script != null)
    {
      // the language attribute was not set but we found the script from the scriptPath,
      // so deduce the extension from the scriptPath
      int pos = scriptPath.lastIndexOf('.');
      if (pos > -1 && pos < scriptPath.length()-1)
        language = scriptPath.substring( pos+1, scriptPath.length() ).toLowerCase();
    }
    if (language != null)
    {
      if ( EXTN2LANG.containsKey(language) )
      {
        // either the user set the language property to the extension OR
        // the language property was not set and we deduced the extension...
        // either way, we now know two things:
        // 1) we need to swap out the extension for the language
        // 2) the language is already registered with BSF
        language = EXTN2LANG.get(language);
      }
      else
      {
        // here we still need to make sure the language is registered with BSF
        if ( !BSFManager.isLanguageRegistered(language) )
          throw new ActionLifecycleException("language '" + language + "' not registered");
      }
    }
    else
    {
      throw new ActionLifecycleException("language not specified");
    }
  }

  public Message process(Message message) throws ActionProcessingException
  {
    BSFManager bsf = new BSFManager();
    try
    {
      bsf.declareBean( "message", message, message.getClass() );
      bsf.declareBean( "config", config, config.getClass() );
      bsf.declareBean( "payloadProxy", payloadProxy, payloadProxy.getClass() );
      bsf.declareBean( "logger", logger, logger.getClass() );
      // NOTE: cannot use eval here since it does not work for all engines (jython in particular)
      bsf.exec( language, source, 0, 0, getScript(message) );
    }
    catch (BSFException bsfe)
    {
      final String error = "Exception caught while processing script: '" + source + "'" ;
      if (logger.isDebugEnabled())
      {
        logger.debug(error, bsfe) ;
      }
      throw new ActionProcessingException(error, bsfe);
    }
    finally
    {
      bsf.terminate();
    }
    return message;
  }

  private String getScript(Message message) throws ActionProcessingException
  {
    if (script != null)
      return script;
    else
    {
      Object messageScript;
      try
      {
        messageScript = payloadProxy.getPayload(message);
      }
      catch (MessageDeliverException mde)
      {
        throw new ActionProcessingException(mde);
      }
      if (messageScript instanceof String)
        return (String)messageScript;
      else if (messageScript instanceof byte[])
        return new String( (byte[])messageScript );
      else
      {
        throw new ActionProcessingException("script not specified in message");
      }
    }
  }

  private String getAttribute(String name)
  {
    String value = config.getAttribute(name);
    if (value != null)
    {
      value = value.trim();
      if (value.length() == 0)
        value = null;
    }
    return value;
  }

}
TOP

Related Classes of org.jboss.soa.esb.actions.scripting.ScriptingAction

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.