001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.servicemix.components.script;
018:
019: import java.io.IOException;
020: import java.io.InputStreamReader;
021: import java.util.HashMap;
022: import java.util.Map;
023: import java.util.logging.Logger;
024:
025: import javax.jbi.JBIException;
026: import javax.jbi.messaging.InOnly;
027: import javax.jbi.messaging.MessageExchange;
028: import javax.jbi.messaging.MessagingException;
029: import javax.jbi.messaging.NormalizedMessage;
030: import javax.script.Bindings;
031: import javax.script.Compilable;
032: import javax.script.CompiledScript;
033: import javax.script.ScriptEngine;
034: import javax.script.ScriptEngineManager;
035: import javax.script.ScriptException;
036: import javax.xml.namespace.QName;
037:
038: import org.apache.servicemix.components.util.TransformComponentSupport;
039: import org.apache.servicemix.jbi.messaging.NormalizedMessageImpl;
040: import org.springframework.core.io.Resource;
041:
042: /**
043: * A component which is capable of invoking a compiledScript using
044: * <a href="http://servicemix.org/JSR+223">JSR 223</a> to allow any scripting language to be integrated.
045: *
046: * @version $Revision: 556864 $
047: */
048: public class ScriptComponent extends TransformComponentSupport {
049:
050: public static final QName SERVICE = new QName(
051: "http://servicemix.org/example/", "receiver");
052: public static final String ENDPOINT = "receiver";
053:
054: private ScriptEngine engine;
055: private String scriptEngineName;
056: private CompiledScript compiledScript;
057: private String scriptText;
058: private Resource script;
059: private String logResourceBundle;
060:
061: private boolean disableOutput;
062: private Logger scriptLogger;
063: private Map bindings = new HashMap();
064:
065: public ScriptComponent() {
066: super (SERVICE, ENDPOINT);
067: }
068:
069: public ScriptComponent(QName service, String endpoint) {
070: super (service, endpoint);
071: }
072:
073: public void start() throws JBIException {
074:
075: if (engine == null) {
076: if (compiledScript != null) {
077: engine = compiledScript.getEngine();
078: } else {
079: if (scriptEngineName != null) {
080: engine = createScriptEngine();
081: }
082: if (engine == null) {
083: throw new JBIException(
084: "Must be configured with either the 'compiledScript' or 'engine' property");
085: }
086: }
087: }
088: if (compiledScript == null) {
089: checkScriptTextAvailable();
090: }
091: if (compiledScript == null) {
092: if (engine instanceof Compilable) {
093: Compilable compilable = (Compilable) engine;
094: compileScript(compilable);
095: }
096: }
097: }
098:
099: // Properties
100: //-------------------------------------------------------------------------
101: public ScriptEngine getEngine() {
102: return engine;
103: }
104:
105: public void setEngine(ScriptEngine engine) {
106: this .engine = engine;
107: }
108:
109: public CompiledScript getCompiledScript() {
110: return compiledScript;
111: }
112:
113: public void setCompiledScript(CompiledScript compiledScript) {
114: this .compiledScript = compiledScript;
115: }
116:
117: public String getScriptText() {
118: return scriptText;
119: }
120:
121: /**
122: * Sets the script as a String
123: *
124: * @param scriptText
125: */
126: public void setScriptText(String scriptText) {
127: this .scriptText = scriptText;
128: }
129:
130: /**
131: * Returns the script as a spring resource
132: *
133: * @return
134: */
135: public Resource getScript() {
136: return script;
137: }
138:
139: /**
140: * Sets the script as a Spring resource
141: *
142: * @param script
143: */
144: public void setScript(Resource script) {
145: this .script = script;
146: }
147:
148: public String getScriptEngineName() {
149: return scriptEngineName;
150: }
151:
152: public void setScriptEngineName(String scriptEngineName) {
153: this .scriptEngineName = scriptEngineName;
154: }
155:
156: public boolean isDisableOutput() {
157: return disableOutput;
158: }
159:
160: public void setDisableOutput(boolean disableOutput) {
161: this .disableOutput = disableOutput;
162: }
163:
164: public String getLogResourceBundle() {
165: return logResourceBundle;
166: }
167:
168: public Map getBindings() {
169: return bindings;
170: }
171:
172: /**
173: * Sets the component level bindings available to scripts as a variable called 'bindings'
174: *
175: * @param bindings
176: */
177: public void setBindings(Map bindings) {
178: this .bindings = bindings;
179: }
180:
181: /**
182: * Sets the resource bundle to use when creating a logger, if one is not
183: * explicitly configured.
184: *
185: * @param logResourceBundle
186: */
187: public void setLogResourceBundle(String logResourceBundle) {
188: this .logResourceBundle = logResourceBundle;
189: }
190:
191: public Logger getScriptLogger() throws MessagingException {
192: if (scriptLogger == null) {
193: scriptLogger = createScriptLogger();
194: }
195: return scriptLogger;
196: }
197:
198: /**
199: * Sets the logger to use if the script decides to log
200: *
201: * @param scriptLogger
202: */
203: public void setScriptLogger(Logger scriptLogger) {
204: this .scriptLogger = scriptLogger;
205: }
206:
207: // Implementation methods
208: //-------------------------------------------------------------------------
209: protected boolean transform(MessageExchange exchange,
210: NormalizedMessage in, NormalizedMessage out)
211: throws Exception {
212: Bindings bindings = engine.createBindings();
213:
214: populateBindings(bindings, exchange, in, out);
215: try {
216: runScript(bindings);
217: return !isDisableOutput();
218: } catch (ScriptException e) {
219: throw new MessagingException(
220: "Failed to run compiledScript. Reason: " + e, e);
221: }
222: }
223:
224: protected void populateBindings(Bindings bindings,
225: MessageExchange exchange, NormalizedMessage in,
226: NormalizedMessage out) throws MessagingException {
227: bindings.put("componentContext", getContext());
228: bindings.put("deliveryChannel", getDeliveryChannel());
229: bindings.put("exchange", exchange);
230: bindings.put("inMessage", in);
231: bindings.put("log", getScriptLogger());
232: bindings.put("componentNamespace", bindings);
233: bindings.put("bindings", this .bindings);
234:
235: InOnly outExchange = null;
236: if (isInAndOut(exchange)) {
237: bindings.put("outMessage", out);
238: } else if (!isDisableOutput()) {
239: outExchange = getExchangeFactory().createInOnlyExchange();
240: if (out instanceof NormalizedMessageImpl) {
241: bindings.put("outExchange",
242: ((NormalizedMessageImpl) out).getExchange());
243: }
244: bindings.put("outMessage", out);
245: }
246: }
247:
248: protected Logger createScriptLogger() throws MessagingException {
249: if (logResourceBundle != null) {
250: try {
251: return getContext().getLogger(getClass().getName(),
252: logResourceBundle);
253: } catch (JBIException e) {
254: throw new MessagingException(e);
255: }
256: } else {
257: return Logger.getLogger(getClass().getName());
258: }
259: }
260:
261: protected void runScript(Bindings bindings) throws ScriptException {
262: if (compiledScript != null) {
263: compiledScript.eval(bindings);
264: } else {
265: evaluteScript(bindings);
266: }
267: }
268:
269: protected void evaluteScript(Bindings bindings)
270: throws ScriptException {
271: engine.eval(scriptText, bindings);
272: }
273:
274: protected void compileScript(Compilable compilable)
275: throws JBIException {
276: try {
277: if (scriptText != null) {
278: compiledScript = compilable.compile(scriptText);
279: } else if (script != null) {
280: compiledScript = compilable
281: .compile(new InputStreamReader(script
282: .getInputStream()));
283:
284: }
285: } catch (ScriptException e) {
286: throw new JBIException(
287: "Failed to parse compiledScript. Reason: " + e, e);
288: } catch (IOException e) {
289: throw new JBIException(
290: "Failed to parse compiledScript. Reason: " + e, e);
291: }
292: }
293:
294: protected ScriptEngine createScriptEngine() {
295: ScriptEngineManager manager = new ScriptEngineManager();
296: return manager.getEngineByName(scriptEngineName);
297: }
298:
299: protected void checkScriptTextAvailable() throws JBIException {
300: if (scriptText == null && script == null) {
301: throw new JBIException(
302: "If no 'compiledScript' is specified you must specify the 'scriptText' or 'script'");
303: }
304: }
305: }
|