Merge remote-tracking branch 'upstream/master' into 4.0.0-WIP

Conflicts:
	spring-integration-core/src/main/java/org/springframework/integration/handler/ExpressionEvaluatingMessageHandler.java
	spring-integration-groovy/src/test/java/org/springframework/integration/groovy/config/GroovyServiceActivatorTests.java

Resolve.
This commit is contained in:
Gary Russell
2013-10-11 18:20:27 -04:00
13 changed files with 278 additions and 76 deletions

View File

@@ -62,7 +62,7 @@ public class GroovyRefreshTests {
super.setValue(new CycleResource());
}
}
private static class CycleResource extends AbstractResource {
private int count = -1;
@@ -71,12 +71,12 @@ public class GroovyRefreshTests {
public String getDescription() {
return "CycleResource";
}
@Override
public String getFilename() throws IllegalStateException {
return "CycleResource";
}
@Override
public long lastModified() throws IOException {
return -1;
@@ -88,6 +88,6 @@ public class GroovyRefreshTests {
}
return new ByteArrayInputStream(scripts[count].getBytes());
}
}
}

View File

@@ -16,9 +16,12 @@
package org.springframework.integration.groovy.config;
import static org.junit.Assert.*;
import groovy.lang.GroovyObject;
import groovy.lang.MissingPropertyException;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.Date;
import java.util.HashMap;
@@ -44,6 +47,9 @@ import org.springframework.scripting.groovy.GroovyObjectCustomizer;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import groovy.lang.GroovyObject;
import groovy.lang.MissingPropertyException;
/**
* @author Mark Fisher
* @author Oleg Zhurakousky

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,6 +24,10 @@ import org.springframework.messaging.Message;
import org.springframework.util.CollectionUtils;
/**
* A default {@link ScriptVariableGenerator} implementation; used by script processors.
* The result of {@link #generateScriptVariables(Message)} is a {@link Map} of any provided {@code variables}
* plus {@code payload} and {@code headers} from the {@code Message} argument.
*
* @author Oleg Zhurakousky
* @author Mark Fisher
* @since 2.0.2
@@ -53,7 +57,7 @@ public class DefaultScriptVariableGenerator implements ScriptVariableGenerator {
if (!CollectionUtils.isEmpty(this.variableMap)) {
for (Map.Entry<String, Object> entry : this.variableMap.entrySet()) {
scriptVariables.put(entry.getKey(), entry.getValue());
}
}
}
return scriptVariables;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,6 +26,7 @@ import org.springframework.scripting.support.ResourceScriptSource;
/**
* @author Dave Syer
* @author Oleg Zhurakousky
* @author Artem Bilan
* @since 2.0
*/
public class RefreshableResourceScriptSource implements ScriptSource {
@@ -51,7 +52,10 @@ public class RefreshableResourceScriptSource implements ScriptSource {
}
public String getScriptAsString() throws IOException {
this.script = source.getScriptAsString();
if (this.script == null || this.isModified()) {
this.lastModifiedChecked.set(System.currentTimeMillis());
this.script = source.getScriptAsString();
}
return this.script;
}
@@ -60,15 +64,14 @@ public class RefreshableResourceScriptSource implements ScriptSource {
}
public boolean isModified() {
if (this.refreshDelay < 0) {
return false;
}
long time = System.currentTimeMillis();
if (this.refreshDelay == 0 || (time - this.lastModifiedChecked.get()) > this.refreshDelay) {
this.lastModifiedChecked.set(time);
return this.source.isModified();
}
return false;
return this.refreshDelay >= 0 &&
(System.currentTimeMillis() - this.lastModifiedChecked.get()) > this.refreshDelay &&
this.source.isModified();
}
@Override
public String toString() {
return this.source.toString();
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,6 +21,9 @@ import java.util.Map;
import org.springframework.messaging.Message;
/**
* Strategy interface to provide a {@link Map} of variables to the script execution context.
* Variables may be extracted from the {@link Message} argument.
*
* @author Oleg Zhurakousky
* @since 2.0.2
*/

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2002-2011 the original author or authors.
*
* Copyright 2002-2013 the original author or authors.
*
* Licensed 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.
@@ -14,13 +14,14 @@ package org.springframework.integration.scripting.jsr223;
import java.util.Date;
import java.util.Map;
import java.util.Map.Entry;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.SimpleBindings;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.integration.scripting.ScriptExecutor;
import org.springframework.integration.scripting.ScriptingException;
import org.springframework.scripting.ScriptSource;
@@ -28,9 +29,10 @@ import org.springframework.util.Assert;
/**
* Base Class for {@link ScriptExecutor}
*
*
* @author David Turanski
* @author Mark Fisher
* @author Artem Bilan
* @since 2.1
*/
abstract class AbstractScriptExecutor implements ScriptExecutor {
@@ -44,9 +46,9 @@ abstract class AbstractScriptExecutor implements ScriptExecutor {
public AbstractScriptExecutor(String language) {
Assert.hasText(language, "language must not be empty");
this.language = language;
scriptEngine = new ScriptEngineManager().getEngineByName(this.language);
if (logger.isDebugEnabled()) {
if (scriptEngine == null) {
@@ -66,18 +68,18 @@ abstract class AbstractScriptExecutor implements ScriptExecutor {
Object result = null;
try {
if (variables != null) {
for (Entry<String, Object> entry : variables.entrySet()) {
scriptEngine.put(entry.getKey(), entry.getValue());
}
}
String script = scriptSource.getScriptAsString();
Date start = new Date();
if (logger.isDebugEnabled()) {
logger.debug("executing script: " + script);
}
result = scriptEngine.eval(script);
if (variables != null) {
result = scriptEngine.eval(script, new SimpleBindings(variables));
}
else {
result = scriptEngine.eval(script);
}
result = postProcess(result, scriptEngine, script);

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/integration"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:script="http://www.springframework.org/schema/integration/scripting"
xsi:schemaLocation="http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration/scripting http://www.springframework.org/schema/integration/scripting/spring-integration-scripting.xsd">
<transformer input-channel="referencedScriptInput" output-channel="outputChannel">
<script:script refresh-check-delay="0"
location="file:#{T(System).getProperty('java.io.tmpdir')}/Int3164Jsr223RefreshTests/int3164.groovy"/>
</transformer>
<channel id="outputChannel">
<queue/>
</channel>
</beans:beans>

View File

@@ -0,0 +1,89 @@
/*
* Copyright 2013 the original author or authors.
*
* Licensed 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.springframework.integration.scripting.config.jsr223;
import static org.junit.Assert.assertEquals;
import java.io.File;
import java.io.IOException;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.core.PollableChannel;
import org.springframework.integration.message.GenericMessage;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.util.FileCopyUtils;
/**
* @author Artem Bilan
* @since 3.0
*/
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class Int3164Jsr223RefreshTests {
private static File workDir;
private static File scriptFile;
@Autowired
private MessageChannel referencedScriptInput;
@Autowired
private PollableChannel outputChannel;
@BeforeClass
public static void start() throws IOException {
String basePath = System.getProperty("java.io.tmpdir") + File.separator + "Int3164Jsr223RefreshTests";
workDir = new File(basePath);
shutdown();
workDir.mkdir();
workDir.deleteOnExit();
scriptFile = new File(workDir, "int3164.groovy");
scriptFile.createNewFile();
FileCopyUtils.copy("1".getBytes(), scriptFile);
}
@AfterClass
public static void shutdown() {
if (workDir != null && workDir.exists()) {
for (File file : workDir.listFiles()) {
file.delete();
}
workDir.delete();
}
}
@Test
public void testRefreshingScript() throws Exception {
this.referencedScriptInput.send(new GenericMessage<Object>("test"));
assertEquals(1, this.outputChannel.receive(100).getPayload());
FileCopyUtils.copy("2".getBytes(), scriptFile);
scriptFile.setLastModified(System.currentTimeMillis() + 10000); // force refresh
this.referencedScriptInput.send(new GenericMessage<Object>("test"));
assertEquals(2, this.outputChannel.receive(100).getPayload());
}
}

View File

@@ -1,15 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/integration"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:script="http://www.springframework.org/schema/integration/scripting"
xsi:schemaLocation="http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:script="http://www.springframework.org/schema/integration/scripting"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration/scripting http://www.springframework.org/schema/integration/scripting/spring-integration-scripting.xsd">
http://www.springframework.org/schema/integration/scripting http://www.springframework.org/schema/integration/scripting/spring-integration-scripting.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd">
<transformer input-channel="referencedScriptInput">
<script:script
lang="ruby"
lang="ruby"
location="org/springframework/integration/scripting/config/jsr223/Jsr223TransformerTests.rb"/>
</transformer>
@@ -19,4 +21,23 @@
]]></script:script>
</transformer>
<task:executor id="executor" pool-size="100"/>
<channel id="int3162InputChannel">
<dispatcher task-executor="executor"/>
</channel>
<channel id="int3162OutputChannel">
<queue/>
</channel>
<transformer input-channel="int3162InputChannel" output-channel="int3162OutputChannel">
<script:script lang="javascript"><![CDATA[
(function(){
return payload;
})();
]]></script:script>
</transformer>
</beans:beans>

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,6 +19,9 @@ package org.springframework.integration.scripting.config.jsr223;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import java.util.HashSet;
import java.util.Set;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -26,12 +29,15 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.core.PollableChannel;
import org.springframework.integration.message.GenericMessage;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Mark Fisher
* @author Artem Bilan
* @since 2.0
*/
@ContextConfiguration
@@ -44,6 +50,12 @@ public class Jsr223TransformerTests {
@Autowired
private MessageChannel inlineScriptInput;
@Autowired
private MessageChannel int3162InputChannel;
@Autowired
private PollableChannel int3162OutputChannel;
@Test
public void referencedScript() {
@@ -73,4 +85,22 @@ public class Jsr223TransformerTests {
assertNull(replyChannel.receive(0));
}
@Test
public void testInt3162ScriptExecutorThreadSafety() {
for (int i = 0; i < 100; i++) {
this.int3162InputChannel.send(new GenericMessage<Object>(i));
}
Set<Object> result = new HashSet<Object>();
for (int i = 0; i < 100; i++) {
Message<?> message = this.int3162OutputChannel.receive(1000);
result.add(message.getPayload());
}
assertEquals(100, result.size());
}
}

View File

@@ -47,11 +47,11 @@
</tip>
</section>
<section>
<section id="amqp-inbound-channel-adapter">
<title>Inbound Channel Adapter</title>
<para>A configuration sample for an AMQP Inbound Channel Adapter is shown
below with all available parameters.</para>
below.</para>
<programlisting language="xml"><![CDATA[<int-amqp:inbound-channel-adapter id="inboundAmqp"]]><co id="amqp-inbound-channel-adapter-xml-01-co" linkends="amqp-inbound-channel-adapter-xml-01" /><![CDATA[
channel="inboundChannel"]]><co id="amqp-inbound-channel-adapter-xml-02-co" linkends="amqp-inbound-channel-adapter-xml-02" /><![CDATA[
queue-names="si.test.queue"]]><co id="amqp-inbound-channel-adapter-xml-03-co" linkends="amqp-inbound-channel-adapter-xml-03" /><![CDATA[
@@ -165,7 +165,20 @@ this list can also be simple patterns to be matched against the header names (e.
core responsibility of this Channel Adapter implementation,
the referenced listener container must NOT already have its
own MessageListener configured.
<emphasis>Optional</emphasis>.</para>
<emphasis>Optional</emphasis>.
<note>
Note that when configuring an external container, you cannot use the <emphasis role="bold">Spring AMQP</emphasis>
namespace to define the container. This is because the namespace requires at least one <code>&lt;listener/&gt;</code>
element. In this environment, the listener is internal to the adapter. For this reason, you must define
the container using a normal Spring <code>&lt;bean/&gt;</code> definition, such as:
<programlisting language="xml"><![CDATA[
<bean id="container"
class="org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory" />
<property name="queueNames" value="foo.queue" />
<property name="defaultRequeueRejected" value="false"/>
</bean>]]></programlisting>
</note></para>
</callout>
<callout arearefs="amqp-inbound-channel-adapter-xml-15-co" id="amqp-inbound-channel-adapter-xml-15">
<para>The MessageConverter to use when receiving AMQP Messages.
@@ -273,7 +286,7 @@ this list can also be simple patterns to be matched against the header names (e.
<title>Outbound Channel Adapter</title>
<para>A configuration sample for an AMQP Outbound Channel Adapter is shown
below with all available parameters.</para>
below.</para>
<programlisting language="xml"><![CDATA[<int-amqp:outbound-channel-adapter id="outboundAmqp"]]><co id="amqp-outbound-channel-adapter-xml-1-co" linkends="amqp-outbound-channel-adapter-xml-1" /><![CDATA[
channel="outboundChannel"]]><co id="amqp-outbound-channel-adapter-xml-2-co" linkends="amqp-outbound-channel-adapter-xml-2" /><![CDATA[
amqp-template="myAmqpTemplate"]]><co id="amqp-outbound-channel-adapter-xml-3-co" linkends="amqp-outbound-channel-adapter-xml-3" /><![CDATA[
@@ -368,7 +381,7 @@ this list can also be simple patterns to be matched against the header names (e.
<section>
<title>Inbound Gateway</title>
<para>A configuration sample for an AMQP Inbound Gateway is shown
below with all available parameters.</para>
below.</para>
<programlisting language="xml"><![CDATA[<int-amqp:inbound-gateway id="inboundGateway"]]><co id="amqp-inbound-gateway-adapter-xml-1-co" linkends="amqp-inbound-gateway-adapter-xml-1" /><![CDATA[
request-channel="myRequestChannel"]]><co id="amqp-inbound-gateway-adapter-xml-2-co" linkends="amqp-inbound-gateway-adapter-xml-2" /><![CDATA[
queue-names="si.test.queue"]]><co id="amqp-inbound-gateway-adapter-xml-3-co" linkends="amqp-inbound-gateway-adapter-xml-3" /><![CDATA[
@@ -415,12 +428,16 @@ this list can also be simple patterns to be matched against the header names (e.
</callout>
</calloutlist>
</para>
<para>
See the note in <xref linkend="amqp-inbound-channel-adapter"/> about configuring the <code>listener-container</code>
attribute.
</para>
</section>
<section>
<title>Outbound Gateway</title>
<para>A configuration sample for an AMQP Outbound Gateway is shown
below with all available parameters.</para>
below.</para>
<programlisting language="xml"><![CDATA[<int-amqp:outbound-gateway id="inboundGateway"]]><co id="amqp-outbound-gateway-adapter-xml-1-co" linkends="amqp-outbound-gateway-adapter-xml-1" /><![CDATA[
request-channel="myRequestChannel"]]><co id="amqp-outbound-gateway-adapter-xml-2-co" linkends="amqp-outbound-gateway-adapter-xml-2" /><![CDATA[
amqp-template=""]]><co id="amqp-outbound-gateway-adapter-xml-3-co" linkends="amqp-outbound-gateway-adapter-xml-3" /><![CDATA[

View File

@@ -57,6 +57,8 @@
Setting a custom GroovyObjectCustomizer is not mutually exclusive with <code>&lt;variable&gt;</code> sub-elements or
the <code>script-variable-generator</code> attribute. It can also be provided when defining an inline script.
For more information regarding <code>&lt;variable&gt;</code> and <code>script-variable-generator</code>, see the
paragraph '<emphasis>Script variable bindings</emphasis>' of <xref linkend="scripting-config"/>.
</para>
</section>

View File

@@ -8,26 +8,26 @@
<title>Scripting support</title>
<para>With Spring Integration 2.1 we've added support for the <ulink url="http://jcp.org/aboutJava/communityprocess/pr/jsr223/">
JSR223 Scripting for Java specification</ulink>,
introduced in Java version 6. This allows you to use scripts written in any supported language including
Ruby/JRuby, Javascript and Groovy to provide the logic for various integration components similar to the way
the Spring Expression Language (SpEL) is used in Spring Integration. For more information about JSR223 please refer to the
JSR223 Scripting for Java specification</ulink>,
introduced in Java version 6. This allows you to use scripts written in any supported language including
Ruby/JRuby, Javascript and Groovy to provide the logic for various integration components similar to the way
the Spring Expression Language (SpEL) is used in Spring Integration. For more information about JSR223 please refer to the
<ulink url="http://java.sun.com/developer/technicalArticles/J2SE/Desktop/scripting/">documentation</ulink>
<important>
Note that this feature requires Java 6 or higher. Sun developed a JSR223 reference implementation which works with
Note that this feature requires Java 6 or higher. Sun developed a JSR223 reference implementation which works with
Java 5 but it is not officially supported and we have not tested it with Spring Integration.
</important>
</para>
<para>
In order to use a JVM scripting language, a JSR223 implementation for that language must be included in your class path. Java 6 natively
supports Javascript. The <ulink url="http://groovy.codehaus.org">Groovy</ulink> and
supports Javascript. The <ulink url="http://groovy.codehaus.org">Groovy</ulink> and
<ulink url="http://jruby.org/">JRuby</ulink> projects provide JSR233 support in their standard distribution.
Other language implementations may be available or under development. Please refer to the appropriate project website for more information.
<important>
Various JSR223 language implementations have been developed by third parties. A particular implementation's compatibility
with Spring Integration depends on how well it conforms to the specification and/or the implementer's interpretation of the specification.
</important>
<tip>If you plan to use Groovy as your scripting language, we recommended you use <xref linkend="groovy">Spring-Integration's Groovy Support</xref>
Various JSR223 language implementations have been developed by third parties. A particular implementation's compatibility
with Spring Integration depends on how well it conforms to the specification and/or the implementer's interpretation of the specification.
</important>
<tip>If you plan to use Groovy as your scripting language, we recommended you use <xref linkend="groovy">Spring-Integration's Groovy Support</xref>
as it offers additional features specific to Groovy. <emphasis>However you will find this section relevant as well</emphasis>.
</tip>
</para>
@@ -50,28 +50,30 @@
&lt;/int:filter&gt;
&lt;int:filter input-channel="inlineScriptInput"&gt;
&lt;int-script:script lang="groovy"&gt;&lt;![CDATA[
&lt;int-script:script lang="groovy"&gt;
&lt;![CDATA[
return payload == 'good'
]]&gt;&lt;/int-script:script&gt;
]]&gt;
&lt;/int-script:script&gt;
&lt;/int:filter&gt;</programlisting>
Here, you see that the script can be included inline
or can reference a resource location via the <code>location</code> attribute. Additionally the <code>lang</code> attribute
or can reference a resource location via the <code>location</code> attribute. Additionally the <code>lang</code> attribute
corresponds to the language name (or JSR223 alias)</para>
<para>Other Spring Integration endpoint elements which support scripting include <emphasis>router</emphasis>, <emphasis>service-activator</emphasis>,
<emphasis>transformer</emphasis>, and <emphasis>splitter</emphasis>. The scripting configuration in each case would be identical to the above
<emphasis>transformer</emphasis>, and <emphasis>splitter</emphasis>. The scripting configuration in each case would be identical to the above
(besides the endpoint element).
</para>
<para>Another useful feature of Scripting support is the ability to update (reload) scripts without
having to restart the Application Context. To accomplish this, specify the <code>refresh-check-delay</code>
<para>Another useful feature of Scripting support is the ability to update (reload) scripts without
having to restart the Application Context. To accomplish this, specify the <code>refresh-check-delay</code>
attribute on the <emphasis>script</emphasis> element:
<programlisting language="xml">&lt;int-script:script location="..." refresh-check-delay="5000"/&gt;</programlisting>
In the above example, the script location will be checked for updates every 5 seconds. If the script is updated,
any invocation that occurs later than 5 seconds since the update will result in execution of the new script.
any invocation that occurs later than 5 seconds since the update will result in execution of the new script.
<programlisting language="xml">&lt;int-script:script location="..." refresh-check-delay="0"/&gt;</programlisting>
@@ -82,12 +84,12 @@
This is the default behavior. <important>Inline scripts can not be reloaded.</important></para>
<programlisting language="xml">&lt;int-script:script location="..." refresh-check-delay="-1"/&gt;</programlisting>
<para><emphasis>Script variable bindings</emphasis> </para>
<para>
Variable bindings are required to enable the script to reference variables externally provided to the script's execution context.
As we have seen, <code>payload</code> and <code>headers</code> are used as binding variables by default. You can bind additional variables
Variable bindings are required to enable the script to reference variables externally provided to the script's execution context.
As we have seen, <code>payload</code> and <code>headers</code> are used as binding variables by default. You can bind additional variables
to a script via <code>&lt;variable&gt;</code> sub-elements:
<programlisting language="xml"><![CDATA[<script:script lang="js" location="foo/bar/MyScript.js">
<script:variable name="foo" value="foo"/>
@@ -96,29 +98,32 @@
</script:script>]]></programlisting>
As shown in the above example, you can bind a script variable either to a scalar value or a Spring bean reference. Note that
<code>payload</code> and <code>headers</code> will still be included as binding variables.
</para>
<para>
If you need more control over how variables are generated, you can implement your own Java class
If you need more control over how variables are generated, you can implement your own Java class
using the <classname>ScriptVariableGenerator</classname> strategy:
<programlisting language="java"><![CDATA[public interface ScriptVariableGenerator {
Map<String, Object> generateScriptVariables(Message<?> message);
}]]></programlisting>
This interface requires you to implement the method <code>generateScriptVariables(Message)</code>. The Message
argument allows you to access any data available in the Message payload and headers and the return value is
the Map of bound variables. This method will be called every time the script is executed for a Message. All you need to do is
the Map of bound variables. This method will be called every time the script is executed for a Message. All you need to do is
provide an implementation of <classname>ScriptVariableGenerator</classname> and reference it with the <code>script-variable-generator</code>
attribute:
<programlisting language="xml"><![CDATA[<int-script:script location="foo/bar/MyScript.groovy"
script-variable-generator="variableGenerator"/>
<bean id="variableGenerator" class="foo.bar.MyScriptVariableGenerator"/>]]></programlisting>
If a <code>script-variable-generator</code> is not provided, script components use
<classname>org.springframework.integration.scripting.DefaultScriptVariableGenerator</classname>, which merges
any provided <code>&lt;variable&gt;</code>s with <emphasis>payload</emphasis> and <emphasis>headers</emphasis>
variables from the <code>Message</code> in its <code>generateScriptVariables(Message)</code> method.
<important>
You cannot provide both the <code>script-variable-generator</code> attribute and <code>&lt;variable&gt;</code> sub-element(s)
You cannot provide both the <code>script-variable-generator</code> attribute and <code>&lt;variable&gt;</code> sub-element(s)
as they are mutually exclusive. Also, custom variable bindings cannot be used with an inline script.
</important>
</para>