blob: 36fbc08bedf6a3887c9ed7375da766c6e93b7965 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.axis2.scripting;
import org.apache.axis2.AxisFault;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.context.ServiceContext;
import org.apache.axis2.description.AxisService;
import org.apache.axis2.description.Parameter;
import org.apache.axis2.receivers.AbstractInOutSyncMessageReceiver;
import org.apache.axis2.scripting.convertors.ConvertorFactory;
import org.apache.axis2.scripting.convertors.OMElementConvertor;
import org.apache.bsf.BSFEngine;
import org.apache.bsf.BSFException;
import org.apache.bsf.BSFManager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.util.ArrayList;
/**
* An Axis2 MessageReceiver for invoking script language functions.
*
* The scripting support uses the Apache Bean Scripting Framework (BSF)
* so the script may be written in any language supported by BSF.
*
* There are two ways of defining the script, either in a seperate file
* or embedded in-line within the services.xml file.
*
* This example shows a services.xml using a seperate script file:
* <code>
* <serviceGroup>
* <service ...>
* ...
* <parameter name="script">scripts/myScript.js</parameter>
* </service>
* </serviceGroup>
* </code>
*
* This example shows a JavaScript function embedded within a services.xml file:
* <code>
* <serviceGroup>
* <service ...>
* ...
* <parameter name="script.js"><![CDATA[
* function invoke(inMC, outMC) {
* ...
* }
* ]]></parameter>
* </service>
* </serviceGroup>
* </code>
*
* The script language is determined by the file name suffix when using scripts
* in seperate files or the script parameter name suffix when using inline scripts.
*/
public class ScriptReceiver extends AbstractInOutSyncMessageReceiver {
public static final String SCRIPT_ATTR = "script";
public static final String FUNCTION_ATTR = "function";
public static final String DEFAULT_FUNCTION = "invoke";
public static final String CONVERTOR_ATTR = "convertor";
protected static final String BSFENGINE_PROP = ScriptReceiver.class.getName() + "BSFEngine";
protected static final String CONVERTOR_PROP = ScriptReceiver.class.getName() + "OMElementConvertor";
public static final String SCRIPT_SRC_PROP = ScriptReceiver.class.getName() + "ScriptSrc";
private static final Log log = LogFactory.getLog(ScriptModule.class);
public ScriptReceiver() {
}
/**
* Invokes the service by calling the script function
*/
public void invokeBusinessLogic(MessageContext inMC, MessageContext outMC) throws AxisFault {
try {
log.debug("invoking script service");
outMC.setEnvelope(getSOAPFactory(inMC).getDefaultEnvelope());
BSFEngine engine = getBSFEngine(inMC);
OMElementConvertor convertor = (OMElementConvertor) inMC.getServiceContext().getProperty(CONVERTOR_PROP);
Parameter scriptFunctionParam = inMC.getAxisService().getParameter(FUNCTION_ATTR);
String scriptFunction = scriptFunctionParam == null ? DEFAULT_FUNCTION : (String) scriptFunctionParam.getValue();
ScriptMessageContext inScriptMC = new ScriptMessageContext(inMC, convertor);
ScriptMessageContext outScriptMC = new ScriptMessageContext(outMC, convertor);
Object[] args = new Object[] { inScriptMC, outScriptMC };
engine.call(null, scriptFunction, args);
} catch (BSFException e) {
throw AxisFault.makeFault(e);
}
}
/**
* Gets the BSFEngine for the script service.
*
* The first service invocation creates the BSFEngine and caches
* it in the Axis2 ServiceContext for reuse by subsequent requests.
*/
protected BSFEngine getBSFEngine(MessageContext mc) throws AxisFault {
BSFEngine bsfEngine;
ServiceContext serviceContext = mc.getServiceContext();
synchronized (serviceContext) {
bsfEngine = (BSFEngine) serviceContext.getProperty(BSFENGINE_PROP);
if (bsfEngine == null) {
bsfEngine = initScript(mc);
}
}
return bsfEngine;
}
/**
* Initializes the script service by finding the script source code,
* compiling it in a BSFEngine, and creating an OMElementConvertor
* for the script.
*/
protected BSFEngine initScript(MessageContext mc) throws AxisFault {
log.debug("initializing script service");
AxisService axisService = mc.getAxisService();
String scriptName = null;
String scriptSrc = null;
Parameter scriptFileParam = axisService.getParameter(SCRIPT_ATTR);
if (scriptFileParam != null) {
// the script is defined in a seperate file
scriptName = ((String) scriptFileParam.getValue()).trim();
Parameter scriptSrcParam = axisService.getParameter(SCRIPT_SRC_PROP);
if (scriptSrcParam != null) {
scriptSrc = (String) scriptSrcParam.getValue();
} else {
scriptSrc = readScript(axisService.getClassLoader(), scriptName);
}
} else {
// the script is defined inline within the services.xml
ArrayList parameters = axisService.getParameters();
for (int i=0; scriptFileParam == null && i<parameters.size(); i++) {
Parameter p = (Parameter) parameters.get(i);
if (p.getName().startsWith("script.")) {
scriptFileParam = p;
scriptName = p.getName();
scriptSrc = (String) p.getValue();
}
}
}
if (scriptName == null) {
throw new AxisFault("Missing script parameter");
}
try {
String scriptLanguage = BSFManager.getLangFromFilename(scriptName);
BSFManager bsfManager = new BSFManager();
bsfManager.setClassLoader(BSFManager.class.getClassLoader());
bsfManager.declareBean("_AxisService", axisService, AxisService.class);
BSFEngine bsfEngine = bsfManager.loadScriptingEngine(scriptLanguage);
bsfEngine.exec(scriptName, 0, 0, scriptSrc);
ServiceContext serviceContext = mc.getServiceContext();
serviceContext.setProperty(BSFENGINE_PROP, bsfEngine);
OMElementConvertor convertor = ConvertorFactory.createOMElementConvertor(axisService, scriptName);
serviceContext.setProperty(CONVERTOR_PROP, convertor);
return bsfEngine;
} catch (BSFException e) {
throw AxisFault.makeFault(e);
}
}
/**
* Reads the complete script source code into a String
*/
protected String readScript(ClassLoader cl, String scriptName) throws AxisFault {
URL url = cl.getResource(scriptName);
if (url == null) {
throw new AxisFault("Script not found: " + scriptName);
}
InputStream is;
try {
is = url.openStream();
} catch (IOException e) {
throw new AxisFault("IOException opening script: " + scriptName, e);
}
try {
Reader reader = new InputStreamReader(is, "UTF-8");
char[] buffer = new char[1024];
StringBuffer source = new StringBuffer();
int count;
while ((count = reader.read(buffer)) > 0) {
source.append(buffer, 0, count);
}
return source.toString();
} catch (IOException e) {
throw new AxisFault("IOException reading script: " + scriptName, e);
} finally {
try {
is.close();
} catch (IOException e) {
throw new AxisFault("IOException closing script: " + scriptName, e);
}
}
}
}