001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019: package org.apache.axis2.scripting;
020:
021: import java.io.IOException;
022: import java.io.InputStream;
023: import java.io.InputStreamReader;
024: import java.io.Reader;
025: import java.net.URL;
026: import java.util.ArrayList;
027:
028: import org.apache.axis2.AxisFault;
029: import org.apache.axis2.context.MessageContext;
030: import org.apache.axis2.context.ServiceContext;
031: import org.apache.axis2.description.AxisService;
032: import org.apache.axis2.description.Parameter;
033: import org.apache.axis2.receivers.AbstractInOutSyncMessageReceiver;
034: import org.apache.axis2.scripting.convertors.ConvertorFactory;
035: import org.apache.axis2.scripting.convertors.OMElementConvertor;
036: import org.apache.bsf.BSFEngine;
037: import org.apache.bsf.BSFException;
038: import org.apache.bsf.BSFManager;
039: import org.apache.commons.logging.Log;
040: import org.apache.commons.logging.LogFactory;
041:
042: /**
043: * An Axis2 MessageReceiver for invoking script language functions.
044: *
045: * The scripting support uses the Apache Bean Scripting Framework (BSF)
046: * so the script may be written in any language supported by BSF.
047: *
048: * There are two ways of defining the script, either in a seperate file
049: * or embedded in-line within the services.xml file.
050: *
051: * This example shows a services.xml using a seperate script file:
052: * <code>
053: * <serviceGroup>
054: * <service ...>
055: * ...
056: * <parameter name="script">scripts/myScript.js</parameter>
057: * </service>
058: * </serviceGroup>
059: * </code>
060: *
061: * This example shows a JavaScript function embedded within a services.xml file:
062: * <code>
063: * <serviceGroup>
064: * <service ...>
065: * ...
066: * <parameter name="script.js"><![CDATA[
067: * function invoke(inMC, outMC) {
068: * ...
069: * }
070: * ]]></parameter>
071: * </service>
072: * </serviceGroup>
073: * </code>
074: *
075: * The script language is determined by the file name suffix when using scripts
076: * in seperate files or the script parameter name suffix when using inline scripts.
077: */
078: public class ScriptReceiver extends AbstractInOutSyncMessageReceiver {
079:
080: public static final String SCRIPT_ATTR = "script";
081: public static final String FUNCTION_ATTR = "function";
082: public static final String DEFAULT_FUNCTION = "invoke";
083: public static final String CONVERTOR_ATTR = "convertor";
084:
085: protected static final String BSFENGINE_PROP = ScriptReceiver.class
086: .getName()
087: + "BSFEngine";
088: protected static final String CONVERTOR_PROP = ScriptReceiver.class
089: .getName()
090: + "OMElementConvertor";
091: public static final String SCRIPT_SRC_PROP = ScriptReceiver.class
092: .getName()
093: + "ScriptSrc";
094:
095: private static final Log log = LogFactory
096: .getLog(ScriptModule.class);
097:
098: public ScriptReceiver() {
099: }
100:
101: /**
102: * Invokes the service by calling the script function
103: */
104: public void invokeBusinessLogic(MessageContext inMC,
105: MessageContext outMC) throws AxisFault {
106: try {
107:
108: log.debug("invoking script service");
109:
110: outMC
111: .setEnvelope(getSOAPFactory(inMC)
112: .getDefaultEnvelope());
113:
114: BSFEngine engine = getBSFEngine(inMC);
115: OMElementConvertor convertor = (OMElementConvertor) inMC
116: .getServiceContext().getProperty(CONVERTOR_PROP);
117:
118: Parameter scriptFunctionParam = inMC.getAxisService()
119: .getParameter(FUNCTION_ATTR);
120: String scriptFunction = scriptFunctionParam == null ? DEFAULT_FUNCTION
121: : (String) scriptFunctionParam.getValue();
122:
123: ScriptMessageContext inScriptMC = new ScriptMessageContext(
124: inMC, convertor);
125: ScriptMessageContext outScriptMC = new ScriptMessageContext(
126: outMC, convertor);
127: Object[] args = new Object[] { inScriptMC, outScriptMC };
128:
129: engine.call(null, scriptFunction, args);
130:
131: } catch (BSFException e) {
132: throw AxisFault.makeFault(e);
133: }
134: }
135:
136: /**
137: * Gets the BSFEngine for the script service.
138: *
139: * The first service invocation creates the BSFEngine and caches
140: * it in the Axis2 ServiceContext for reuse by subsequent requests.
141: */
142: protected BSFEngine getBSFEngine(MessageContext mc)
143: throws AxisFault {
144: BSFEngine bsfEngine;
145: ServiceContext serviceContext = mc.getServiceContext();
146: synchronized (serviceContext) {
147: bsfEngine = (BSFEngine) serviceContext
148: .getProperty(BSFENGINE_PROP);
149: if (bsfEngine == null) {
150: bsfEngine = initScript(mc);
151: }
152: }
153: return bsfEngine;
154: }
155:
156: /**
157: * Initializes the script service by finding the script source code,
158: * compiling it in a BSFEngine, and creating an OMElementConvertor
159: * for the script.
160: */
161: protected BSFEngine initScript(MessageContext mc) throws AxisFault {
162: log.debug("initializing script service");
163:
164: AxisService axisService = mc.getAxisService();
165:
166: String scriptName = null;
167: String scriptSrc = null;
168: Parameter scriptFileParam = axisService
169: .getParameter(SCRIPT_ATTR);
170: if (scriptFileParam != null) {
171: // the script is defined in a seperate file
172: scriptName = ((String) scriptFileParam.getValue()).trim();
173: Parameter scriptSrcParam = axisService
174: .getParameter(SCRIPT_SRC_PROP);
175: if (scriptSrcParam != null) {
176: scriptSrc = (String) scriptSrcParam.getValue();
177: } else {
178: scriptSrc = readScript(axisService.getClassLoader(),
179: scriptName);
180: }
181: } else {
182: // the script is defined inline within the services.xml
183: ArrayList parameters = axisService.getParameters();
184: for (int i = 0; scriptFileParam == null
185: && i < parameters.size(); i++) {
186: Parameter p = (Parameter) parameters.get(i);
187: if (p.getName().startsWith("script.")) {
188: scriptFileParam = p;
189: scriptName = p.getName();
190: scriptSrc = (String) p.getValue();
191: }
192: }
193: }
194: if (scriptName == null) {
195: throw new AxisFault("Missing script parameter");
196: }
197:
198: try {
199:
200: String scriptLanguage = BSFManager
201: .getLangFromFilename(scriptName);
202: BSFManager bsfManager = new BSFManager();
203: bsfManager
204: .setClassLoader(BSFManager.class.getClassLoader());
205: bsfManager.declareBean("_AxisService", axisService,
206: AxisService.class);
207:
208: BSFEngine bsfEngine = bsfManager
209: .loadScriptingEngine(scriptLanguage);
210: bsfEngine.exec(scriptName, 0, 0, scriptSrc);
211:
212: ServiceContext serviceContext = mc.getServiceContext();
213: serviceContext.setProperty(BSFENGINE_PROP, bsfEngine);
214:
215: OMElementConvertor convertor = ConvertorFactory
216: .createOMElementConvertor(axisService, scriptName);
217: serviceContext.setProperty(CONVERTOR_PROP, convertor);
218:
219: return bsfEngine;
220:
221: } catch (BSFException e) {
222: throw AxisFault.makeFault(e);
223: }
224: }
225:
226: /**
227: * Reads the complete script source code into a String
228: */
229: protected String readScript(ClassLoader cl, String scriptName)
230: throws AxisFault {
231: URL url = cl.getResource(scriptName);
232: if (url == null) {
233: throw new AxisFault("Script not found: " + scriptName);
234: }
235: InputStream is;
236: try {
237: is = url.openStream();
238: } catch (IOException e) {
239: throw new AxisFault("IOException opening script: "
240: + scriptName, e);
241: }
242: try {
243: Reader reader = new InputStreamReader(is, "UTF-8");
244: char[] buffer = new char[1024];
245: StringBuffer source = new StringBuffer();
246: int count;
247: while ((count = reader.read(buffer)) > 0) {
248: source.append(buffer, 0, count);
249: }
250: return source.toString();
251: } catch (IOException e) {
252: throw new AxisFault("IOException reading script: "
253: + scriptName, e);
254: } finally {
255: try {
256: is.close();
257: } catch (IOException e) {
258: throw new AxisFault("IOException closing script: "
259: + scriptName, e);
260: }
261: }
262: }
263: }
|