diff --git a/spring-integration-groovy/src/main/java/org/springframework/integration/groovy/GroovyScriptExecutingMessageProcessor.java b/spring-integration-groovy/src/main/java/org/springframework/integration/groovy/GroovyScriptExecutingMessageProcessor.java index 72f33ace8e..125b847bea 100644 --- a/spring-integration-groovy/src/main/java/org/springframework/integration/groovy/GroovyScriptExecutingMessageProcessor.java +++ b/spring-integration-groovy/src/main/java/org/springframework/integration/groovy/GroovyScriptExecutingMessageProcessor.java @@ -16,12 +16,21 @@ package org.springframework.integration.groovy; +import groovy.lang.Binding; +import groovy.lang.GString; +import groovy.lang.GroovyClassLoader; +import groovy.lang.GroovyObject; +import groovy.lang.MetaClass; +import groovy.lang.MissingPropertyException; +import groovy.lang.Script; + import java.util.Map; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.integration.Message; import org.springframework.integration.scripting.AbstractScriptExecutingMessageProcessor; @@ -32,13 +41,6 @@ import org.springframework.scripting.groovy.GroovyObjectCustomizer; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; -import groovy.lang.Binding; -import groovy.lang.GString; -import groovy.lang.GroovyClassLoader; -import groovy.lang.GroovyObject; -import groovy.lang.MetaClass; -import groovy.lang.Script; - /** * The {@link org.springframework.integration.handler.MessageProcessor} implementation * to evaluate Groovy scripts. @@ -136,12 +138,9 @@ public class GroovyScriptExecutingMessageProcessor extends AbstractScriptExecuti try { GroovyObject goo = (GroovyObject) this.scriptClass.newInstance(); - GroovyObjectCustomizer groovyObjectCustomizer = this.customizerDecorator; - if (variables != null) { - // Override empty Script.Binding with new one with 'variables' - groovyObjectCustomizer = new BindingOverwriteGroovyObjectCustomizerDecorator(new Binding(variables)); - ((VariableBindingGroovyObjectCustomizerDecorator) groovyObjectCustomizer).setCustomizer(this.customizerDecorator); - } + VariableBindingGroovyObjectCustomizerDecorator groovyObjectCustomizer = + new BindingOverwriteGroovyObjectCustomizerDecorator(new BeanFactoryFallbackBinding(variables)); + groovyObjectCustomizer.setCustomizer(this.customizerDecorator); if (goo instanceof Script) { // Allow metaclass and other customization. @@ -164,4 +163,34 @@ public class GroovyScriptExecutingMessageProcessor extends AbstractScriptExecuti } } + private class BeanFactoryFallbackBinding extends Binding { + + private BeanFactoryFallbackBinding(Map variables) { + super(variables); + } + + @Override + public Object getVariable(String name) { + try { + return super.getVariable(name); + } + catch (MissingPropertyException e) { + // Original {@link Binding} doesn't have 'variable' for the given 'name'. + // Try to resolve it as 'bean' from the given beanFactory. + } + + if (GroovyScriptExecutingMessageProcessor.this.beanFactory == null) { + throw new MissingPropertyException(name, this.getClass()); + } + + try { + return GroovyScriptExecutingMessageProcessor.this.beanFactory.getBean(name); + } + catch (NoSuchBeanDefinitionException e) { + throw new MissingPropertyException(name, this.getClass(), e); + } + } + + } + } diff --git a/spring-integration-groovy/src/test/java/org/springframework/integration/groovy/config/GroovyServiceActivatorTests-context.xml b/spring-integration-groovy/src/test/java/org/springframework/integration/groovy/config/GroovyServiceActivatorTests-context.xml index 4641ef303a..da3348f1e5 100644 --- a/spring-integration-groovy/src/test/java/org/springframework/integration/groovy/config/GroovyServiceActivatorTests-context.xml +++ b/spring-integration-groovy/src/test/java/org/springframework/integration/groovy/config/GroovyServiceActivatorTests-context.xml @@ -10,30 +10,38 @@ http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> - - - + + - - - - - + + + + + + + diff --git a/spring-integration-groovy/src/test/java/org/springframework/integration/groovy/config/GroovyServiceActivatorTests-fail-context.xml b/spring-integration-groovy/src/test/java/org/springframework/integration/groovy/config/GroovyServiceActivatorTests-fail-context.xml deleted file mode 100644 index e105a28471..0000000000 --- a/spring-integration-groovy/src/test/java/org/springframework/integration/groovy/config/GroovyServiceActivatorTests-fail-context.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - diff --git a/spring-integration-groovy/src/test/java/org/springframework/integration/groovy/config/GroovyServiceActivatorTests.java b/spring-integration-groovy/src/test/java/org/springframework/integration/groovy/config/GroovyServiceActivatorTests.java index 86c3724da5..8615fcadbc 100644 --- a/spring-integration-groovy/src/test/java/org/springframework/integration/groovy/config/GroovyServiceActivatorTests.java +++ b/spring-integration-groovy/src/test/java/org/springframework/integration/groovy/config/GroovyServiceActivatorTests.java @@ -23,6 +23,8 @@ import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import java.text.DateFormat; +import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Map; @@ -38,6 +40,7 @@ import org.springframework.integration.Message; import org.springframework.integration.MessageChannel; import org.springframework.integration.MessageHandlingException; import org.springframework.integration.channel.QueueChannel; +import org.springframework.integration.core.PollableChannel; import org.springframework.integration.handler.ReplyRequiredException; import org.springframework.integration.message.ErrorMessage; import org.springframework.integration.message.GenericMessage; @@ -73,6 +76,9 @@ public class GroovyServiceActivatorTests { @Autowired private MessageChannel invalidInlineScript; + @Autowired + private MessageChannel scriptWithoutVariablesInput; + @Autowired private MyGroovyCustomizer groovyCustomizer; @@ -134,13 +140,38 @@ public class GroovyServiceActivatorTests { Message message = MessageBuilder.withPayload("test-" + i).setReplyChannel(replyChannel).build(); this.inlineScriptInput.send(message); } - assertEquals("inline-test-1", replyChannel.receive(0).getPayload()); - assertEquals("inline-test-2", replyChannel.receive(0).getPayload()); - assertEquals("inline-test-3", replyChannel.receive(0).getPayload()); + + DateFormat format = new SimpleDateFormat("dd.mm.yyyy"); + + String now = format.format(new Date()); + + assertEquals("inline-test-1 : " + now, replyChannel.receive(0).getPayload()); + assertEquals("inline-test-2 : " + now, replyChannel.receive(0).getPayload()); + assertEquals("inline-test-3 : " + now, replyChannel.receive(0).getPayload()); + assertNull(replyChannel.receive(0)); assertTrue(groovyCustomizer.executed); } + @Test + public void testScriptWithoutVariables() throws Exception{ + PollableChannel replyChannel = new QueueChannel(); + for (int i = 1; i <= 3; i++) { + Message message = MessageBuilder.withPayload("test-" + i).setReplyChannel(replyChannel).build(); + this.scriptWithoutVariablesInput.send(message); + } + + DateFormat format = new SimpleDateFormat("dd.mm.yyyy"); + + String now = format.format(new Date()); + + assertEquals("withoutVariables-test-1 : " + now, replyChannel.receive(0).getPayload()); + assertEquals("withoutVariables-test-2 : " + now, replyChannel.receive(0).getPayload()); + assertEquals("withoutVariables-test-3 : " + now, replyChannel.receive(0).getPayload()); + + assertNull(replyChannel.receive(0)); + } + //INT-2399 @Test(expected = MessageHandlingException.class) public void invalidInlineScript() throws Exception { @@ -158,11 +189,6 @@ public class GroovyServiceActivatorTests { } - @Test(expected=BeanDefinitionParsingException.class) - public void inlineScriptAndVariables() throws Exception{ - new ClassPathXmlApplicationContext("GroovyServiceActivatorTests-fail-context.xml", this.getClass()); - } - @Test(expected=BeanDefinitionParsingException.class) public void variablesAndScriptVariableGenerator() throws Exception{ new ClassPathXmlApplicationContext("GroovyServiceActivatorTests-fail-withgenerator-context.xml", this.getClass()); diff --git a/spring-integration-scripting/src/main/java/org/springframework/integration/scripting/config/AbstractScriptParser.java b/spring-integration-scripting/src/main/java/org/springframework/integration/scripting/config/AbstractScriptParser.java index 8e02a81da2..5d8c7f0aa6 100644 --- a/spring-integration-scripting/src/main/java/org/springframework/integration/scripting/config/AbstractScriptParser.java +++ b/spring-integration-scripting/src/main/java/org/springframework/integration/scripting/config/AbstractScriptParser.java @@ -16,14 +16,15 @@ import java.util.List; import org.w3c.dom.Element; +import org.springframework.beans.BeanMetadataElement; import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; import org.springframework.beans.factory.support.ManagedMap; import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.beans.factory.xml.XmlReaderContext; import org.springframework.integration.config.xml.IntegrationNamespaceUtils; +import org.springframework.integration.scripting.DefaultScriptVariableGenerator; import org.springframework.integration.scripting.RefreshableResourceScriptSource; import org.springframework.scripting.support.StaticScriptSource; import org.springframework.util.CollectionUtils; @@ -32,6 +33,7 @@ import org.springframework.util.xml.DomUtils; /** * @author David Turanski + * @author Artem Bilan * */ public abstract class AbstractScriptParser extends AbstractSingleBeanDefinitionParser { @@ -62,13 +64,6 @@ public abstract class AbstractScriptParser extends AbstractSingleBeanDefinitionP List variableElements = DomUtils.getChildElementsByTagName(element, "variable"); String scriptVariableGeneratorName = element.getAttribute("script-variable-generator"); - if (StringUtils.hasText(scriptText) - && (variableElements.size() > 0 || StringUtils.hasText(scriptVariableGeneratorName))) { - parserContext.getReaderContext().error( - "Variable bindings or custom ScriptVariableGenerator are not allowed when using an inline groovy script. " - + "Specify location of the script via 'location' attribute instead", element); - return; - } if (StringUtils.hasText(scriptVariableGeneratorName) && variableElements.size() > 0) { parserContext.getReaderContext().error( @@ -88,33 +83,23 @@ public abstract class AbstractScriptParser extends AbstractSingleBeanDefinitionP builder.addConstructorArgValue(new StaticScriptSource(scriptText)); } } + + BeanMetadataElement scriptVariableGeneratorDef = null; + if (!StringUtils.hasText(scriptVariableGeneratorName)) { BeanDefinitionBuilder scriptVariableGeneratorBuilder = BeanDefinitionBuilder - .genericBeanDefinition("org.springframework.integration.scripting.DefaultScriptVariableGenerator"); - ManagedMap variableMap = new ManagedMap(); - for (Element childElement : variableElements) { - String variableName = childElement.getAttribute("name"); - String variableValue = childElement.getAttribute("value"); - String variableRef = childElement.getAttribute("ref"); - if (!(StringUtils.hasText(variableValue) ^ StringUtils.hasText(variableRef))) { - parserContext.getReaderContext().error( - "Exactly one of the 'ref' attribute or 'value' attribute, " + " is required for element " - + IntegrationNamespaceUtils.createElementDescription(element) + ".", element); - } - if (StringUtils.hasText(variableValue)) { - variableMap.put(variableName, variableValue); - } - else { - variableMap.put(variableName, new RuntimeBeanReference(variableRef)); - } - } + .genericBeanDefinition(DefaultScriptVariableGenerator.class); + ManagedMap variableMap = buildVariablesMap(element, parserContext, variableElements); if (!CollectionUtils.isEmpty(variableMap)) { scriptVariableGeneratorBuilder.addConstructorArgValue(variableMap); } - scriptVariableGeneratorName = BeanDefinitionReaderUtils.registerWithGeneratedName( - scriptVariableGeneratorBuilder.getBeanDefinition(), parserContext.getRegistry()); + scriptVariableGeneratorDef = scriptVariableGeneratorBuilder.getBeanDefinition(); } - builder.addConstructorArgReference(scriptVariableGeneratorName); + else { + scriptVariableGeneratorDef = new RuntimeBeanReference(scriptVariableGeneratorName); + } + + builder.addConstructorArgValue(scriptVariableGeneratorDef); postProcess(builder, element, parserContext); } @@ -138,4 +123,61 @@ public abstract class AbstractScriptParser extends AbstractSingleBeanDefinitionP return resourceScriptSourceBuilder.getBeanDefinition(); } + private ManagedMap buildVariablesMap(final Element element, final ParserContext parserContext, + List variableElements) { + @SuppressWarnings("serial") + ManagedMap variableMap = new ManagedMap() { + + @Override + public Object put(String key, Object value) { + if (this.containsKey(key)) { + parserContext.getReaderContext().error("Duplicated variable: " + key, element); + } + return super.put(key, value); + } + + }; + + for (Element childElement : variableElements) { + String variableName = childElement.getAttribute("name"); + String variableValue = childElement.getAttribute("value"); + String variableRef = childElement.getAttribute("ref"); + if (!(StringUtils.hasText(variableValue) ^ StringUtils.hasText(variableRef))) { + parserContext.getReaderContext().error( + "Exactly one of the 'ref' attribute or 'value' attribute, " + " is required for element " + + IntegrationNamespaceUtils.createElementDescription(element) + ".", element); + } + if (StringUtils.hasText(variableValue)) { + variableMap.put(variableName, variableValue); + } + else { + variableMap.put(variableName, new RuntimeBeanReference(variableRef)); + } + } + + String variables = element.getAttribute("variables"); + if (StringUtils.hasText(variables)) { + String[] variablePairs = StringUtils.commaDelimitedListToStringArray(variables); + for (String variablePair : variablePairs) { + String[] variableValue = variablePair.split("="); + if (variableValue.length != 2) { + parserContext.getReaderContext().error( + "Variable declarations in the 'variable' attribute must have the " + + "form 'var=value'; found : '" + variablePair + "'", element); + } + String variable = variableValue[0].trim(); + String value = variableValue[1]; + if (variable.endsWith("-ref")) { + variable = variable.substring(0, variable.indexOf("-ref")); + variableMap.put(variable, new RuntimeBeanReference(value)); + } + else { + variableMap.put(variable, value); + } + } + } + + return variableMap; + } + } diff --git a/spring-integration-scripting/src/main/resources/org/springframework/integration/scripting/config/spring-integration-scripting-core-3.0.xsd b/spring-integration-scripting/src/main/resources/org/springframework/integration/scripting/config/spring-integration-scripting-core-3.0.xsd index b55e3bb317..f92337b667 100644 --- a/spring-integration-scripting/src/main/resources/org/springframework/integration/scripting/config/spring-integration-scripting-core-3.0.xsd +++ b/spring-integration-scripting/src/main/resources/org/springframework/integration/scripting/config/spring-integration-scripting-core-3.0.xsd @@ -61,7 +61,7 @@ Reference to the ScriptVariableGenerator bean. This attribute is mutually - exclusive with any 'variable' sub-elements. + exclusive with any 'variable' sub-elements and 'variables' attribute. + + + + Comma-delimited pairs of variables and their values. + the variable name can applies '-ref' suffix, which mean to determine + a variable value as a bean reference. + This attribute isn't mutually exclusive with 'variable' sub-elements + and all variables will be merged to one Map. + This attribute is mutually exclusive with 'script-variable-generator' attribute. + + + diff --git a/spring-integration-scripting/src/test/java/org/springframework/integration/scripting/config/jsr223/Jsr223ServiceActivatorTests-context.xml b/spring-integration-scripting/src/test/java/org/springframework/integration/scripting/config/jsr223/Jsr223ServiceActivatorTests-context.xml index 6949921b6a..69dab9f3cc 100644 --- a/spring-integration-scripting/src/test/java/org/springframework/integration/scripting/config/jsr223/Jsr223ServiceActivatorTests-context.xml +++ b/spring-integration-scripting/src/test/java/org/springframework/integration/scripting/config/jsr223/Jsr223ServiceActivatorTests-context.xml @@ -10,30 +10,31 @@ http://www.springframework.org/schema/integration/scripting http://www.springframework.org/schema/integration/scripting/spring-integration-scripting.xsd"> - + location="org/springframework/integration/scripting/config/jsr223/Jsr223ServiceActivatorTests.py" + variables="foo2=#{'foo2'}, date2-ref=date"> - - + + - - - - + + + + - + @@ -41,5 +42,5 @@ - + diff --git a/spring-integration-scripting/src/test/java/org/springframework/integration/scripting/config/jsr223/Jsr223ServiceActivatorTests-fail-context.xml b/spring-integration-scripting/src/test/java/org/springframework/integration/scripting/config/jsr223/Jsr223ServiceActivatorTests-fail-duplicated-variable-context.xml similarity index 80% rename from spring-integration-scripting/src/test/java/org/springframework/integration/scripting/config/jsr223/Jsr223ServiceActivatorTests-fail-context.xml rename to spring-integration-scripting/src/test/java/org/springframework/integration/scripting/config/jsr223/Jsr223ServiceActivatorTests-fail-duplicated-variable-context.xml index 6eb04afa62..e79f3e6b04 100644 --- a/spring-integration-scripting/src/test/java/org/springframework/integration/scripting/config/jsr223/Jsr223ServiceActivatorTests-fail-context.xml +++ b/spring-integration-scripting/src/test/java/org/springframework/integration/scripting/config/jsr223/Jsr223ServiceActivatorTests-fail-duplicated-variable-context.xml @@ -7,14 +7,13 @@ 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"> - - - + + - + - + diff --git a/spring-integration-scripting/src/test/java/org/springframework/integration/scripting/config/jsr223/Jsr223ServiceActivatorTests.java b/spring-integration-scripting/src/test/java/org/springframework/integration/scripting/config/jsr223/Jsr223ServiceActivatorTests.java index b46cca2ad2..87c0a07d00 100644 --- a/spring-integration-scripting/src/test/java/org/springframework/integration/scripting/config/jsr223/Jsr223ServiceActivatorTests.java +++ b/spring-integration-scripting/src/test/java/org/springframework/integration/scripting/config/jsr223/Jsr223ServiceActivatorTests.java @@ -17,19 +17,21 @@ package org.springframework.integration.scripting.config.jsr223; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.assertEquals; 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; import java.util.Map; +import org.hamcrest.Matchers; import org.junit.Test; import org.junit.runner.RunWith; +import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.parsing.BeanDefinitionParsingException; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.integration.Message; import org.springframework.integration.MessageChannel; @@ -72,14 +74,24 @@ public class Jsr223ServiceActivatorTests { String value1 = (String) replyChannel.receive(0).getPayload(); String value2 = (String) replyChannel.receive(0).getPayload(); String value3 = (String) replyChannel.receive(0).getPayload(); - assertTrue(value1.startsWith("python-test-1-foo - bar")); - assertTrue(value2.startsWith("python-test-2-foo - bar")); - assertTrue(value3.startsWith("python-test-3-foo - bar")); + assertTrue(value1.startsWith("python-test-1-foo (foo2) - bar")); + assertTrue(value2.startsWith("python-test-2-foo (foo2) - bar")); + assertTrue(value3.startsWith("python-test-3-foo (foo2) - bar")); // because we are using 'prototype bean the suffix date will be // different - assertFalse(value1.substring(26).equals(value2.substring(26))); - assertFalse(value2.substring(26).equals(value3.substring(26))); + assertFalse(value1.substring(value1.indexOf(":") + 1, value1.lastIndexOf(":")) + .equals(value2.substring(value1.indexOf(":") + 1, value1.lastIndexOf(":")))); + assertFalse(value1.substring(value1.indexOf(":") +1, value1.lastIndexOf(":")) + .equals(value1.substring(value1.lastIndexOf(":")))); + + assertFalse(value2.substring(value1.indexOf(":") + 1, value1.lastIndexOf(":")) + .equals(value3.substring(value1.indexOf(":") + 1, value1.lastIndexOf(":")))); + + assertFalse(value1.substring(value1.lastIndexOf(":") + 1) + .equals(value2.substring(value1.lastIndexOf(":") + 1))); + assertFalse(value2.substring(value1.lastIndexOf(":") + 1) + .equals(value3.substring(value1.lastIndexOf(":") + 1))); assertNull(replyChannel.receive(0)); } @@ -118,22 +130,41 @@ public class Jsr223ServiceActivatorTests { Message message = MessageBuilder.withPayload("test-" + i).setReplyChannel(replyChannel).build(); this.inlineScriptInput.send(message); } - assertEquals("inline-test-1", replyChannel.receive(0).getPayload()); - assertEquals("inline-test-2", replyChannel.receive(0).getPayload()); - assertEquals("inline-test-3", replyChannel.receive(0).getPayload()); + String payload = (String) replyChannel.receive(0).getPayload(); + + assertThat(payload, Matchers.startsWith("inline-test-1 - FOO")); + + payload = (String) replyChannel.receive(0).getPayload(); + assertThat(payload, Matchers.startsWith("inline-test-2 - FOO")); + + payload = (String) replyChannel.receive(0).getPayload(); + assertThat(payload, Matchers.startsWith("inline-test-3 - FOO")); + assertTrue(payload.substring(payload.indexOf(":") + 1).matches(".+\\d{2}:\\d{2}:\\d{2}.+")); + assertNull(replyChannel.receive(0)); } - @Test(expected = BeanDefinitionParsingException.class) - public void inlineScriptAndVariables() throws Exception { - new ClassPathXmlApplicationContext("Jsr223ServiceActivatorTests-fail-context.xml", this.getClass()); + @Test + public void variablesAndScriptVariableGenerator() throws Exception { + try { + new ClassPathXmlApplicationContext("Jsr223ServiceActivatorTests-fail-withgenerator-context.xml", this.getClass()); + fail("BeansException expected."); + } + catch (BeansException e) { + assertThat(e.getMessage(), Matchers.containsString("'script-variable-generator' and 'variable' sub-elements are mutually exclusive.")); + } } - @Test(expected = BeanDefinitionParsingException.class) - public void variablesAndScriptVariableGenerator() throws Exception { - new ClassPathXmlApplicationContext("Jsr223ServiceActivatorTests-fail-withgenerator-context.xml", - this.getClass()); + @Test + public void testDuplicateVariable() throws Exception { + try { + new ClassPathXmlApplicationContext("Jsr223ServiceActivatorTests-fail-duplicated-variable-context.xml", this.getClass()); + fail("BeansException expected."); + } + catch (BeansException e) { + assertThat(e.getMessage(), Matchers.containsString("Duplicated variable: foo")); + } } public static class SampleScriptVariSource implements ScriptVariableGenerator { diff --git a/spring-integration-scripting/src/test/java/org/springframework/integration/scripting/config/jsr223/Jsr223ServiceActivatorTests.py b/spring-integration-scripting/src/test/java/org/springframework/integration/scripting/config/jsr223/Jsr223ServiceActivatorTests.py index 41aced873d..4617c17a74 100644 --- a/spring-integration-scripting/src/test/java/org/springframework/integration/scripting/config/jsr223/Jsr223ServiceActivatorTests.py +++ b/spring-integration-scripting/src/test/java/org/springframework/integration/scripting/config/jsr223/Jsr223ServiceActivatorTests.py @@ -1 +1 @@ -"python-%s-%s - %s - %s" %(payload,foo,bar,date) \ No newline at end of file +"python-%s-%s (%s) - %s - :%s:%s" %(payload,foo,foo2,bar,date,date2) diff --git a/spring-integration-scripting/src/test/java/org/springframework/integration/scripting/jsr223/Jsr223ScriptExecutingMessageProcessorTests.java b/spring-integration-scripting/src/test/java/org/springframework/integration/scripting/jsr223/Jsr223ScriptExecutingMessageProcessorTests.java index 691fb30d60..64ea7d6538 100644 --- a/spring-integration-scripting/src/test/java/org/springframework/integration/scripting/jsr223/Jsr223ScriptExecutingMessageProcessorTests.java +++ b/spring-integration-scripting/src/test/java/org/springframework/integration/scripting/jsr223/Jsr223ScriptExecutingMessageProcessorTests.java @@ -1,11 +1,11 @@ /* * Copyright 2002-2011 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. @@ -19,6 +19,9 @@ import java.util.Map; import org.junit.Before; import org.junit.Test; +import org.mockito.Mockito; + +import org.springframework.beans.factory.BeanFactory; import org.springframework.core.io.ClassPathResource; import org.springframework.integration.Message; import org.springframework.integration.message.GenericMessage; @@ -31,42 +34,45 @@ import org.springframework.scripting.support.ResourceScriptSource; * */ public class Jsr223ScriptExecutingMessageProcessorTests { + ScriptExecutor executor; + @Before public void setUp() { executor = ScriptExecutorFactory.getScriptExecutor("jruby"); } @Test public void testExecuteWithVariables(){ - - Map vars = new HashMap(); vars.put("one",1); vars.put("two","two"); - vars.put("three", new Integer(3)); - + vars.put("three", 3); + ScriptSource scriptSource = new ResourceScriptSource(new ClassPathResource("/org/springframework/integration/scripting/jsr223/print_message.rb")); - - ScriptExecutingMessageProcessor messageProcessor = new ScriptExecutingMessageProcessor(scriptSource,executor,vars); - + + ScriptExecutingMessageProcessor messageProcessor = new ScriptExecutingMessageProcessor(scriptSource, executor, vars); + messageProcessor.setBeanFactory(Mockito.mock(BeanFactory.class)); + Message message = new GenericMessage("hello"); - + Object obj = messageProcessor.processMessage(message); - + assertEquals("hello modified",obj.toString().substring(0,"hello modified".length())); } - + @Test public void testWithNoVars(){ ScriptSource scriptSource = new ResourceScriptSource(new ClassPathResource("/org/springframework/integration/scripting/jsr223/print_message.rb")); - - ScriptExecutingMessageProcessor messageProcessor = new ScriptExecutingMessageProcessor(scriptSource,executor); - + + ScriptExecutingMessageProcessor messageProcessor = new ScriptExecutingMessageProcessor(scriptSource, executor); + messageProcessor.setBeanFactory(Mockito.mock(BeanFactory.class)); + Message message = new GenericMessage("hello"); - + Object obj = messageProcessor.processMessage(message); - + assertEquals("hello modified",obj.toString().substring(0,"hello modified".length())); } - + } + diff --git a/src/reference/docbook/groovy.xml b/src/reference/docbook/groovy.xml index 4845df307a..1011e016cc 100644 --- a/src/reference/docbook/groovy.xml +++ b/src/reference/docbook/groovy.xml @@ -57,9 +57,26 @@ Setting a custom GroovyObjectCustomizer is not mutually exclusive with <variable> sub-elements or the script-variable-generator attribute. It can also be provided when defining an inline script. - For more information regarding <variable> and script-variable-generator, see the - paragraph 'Script variable bindings' of . - + + + With Spring Integration 3.0, in addition to the variable sub-element, + the variables attribute has been introduced. Also, groovy scripts have the ability to resolve a + variable to a bean in the + BeanFactory, if a binding variable was not provided with + the name: + <int-groovy:script> + <![CDATA[ + entityManager.persist(payload) + payload + ]]> +</int-groovy:script> + where variable entityManager is an appropriate bean in the application context. + + + For more information regarding <variable>, variables, + and script-variable-generator, see the + paragraph 'Script variable bindings' of . +
diff --git a/src/reference/docbook/scripting.xml b/src/reference/docbook/scripting.xml index 559bd018ce..f79f807225 100644 --- a/src/reference/docbook/scripting.xml +++ b/src/reference/docbook/scripting.xml @@ -98,7 +98,32 @@ ]]> As shown in the above example, you can bind a script variable either to a scalar value or a Spring bean reference. Note that payload and headers will still be included as binding variables. - + + + With Spring Integration 3.0, in addition to the variable sub-element, + the variables attribute has been introduced. This attribute and variable sub-elements + aren't mutually exclusive and you can combine them within one script component. However variables must + be unique, regardless of where they are defined. Also, since Spring Integration 3.0, + variable bindings are allowed for inline scripts too: + <service-activator input-channel="input"> + <script:script lang="ruby" variables="foo=FOO, date-ref=dateBean"> + <script:variable name="bar" ref="barBean"/> + <script:variable name="baz" value="bar"/> + <![CDATA[ + payload.foo = foo + payload.date = date + payload.bar = bar + payload.baz = baz + payload + ]]> + </script:script> +</service-activator> + The example above shows a combination of an inline script, a variable sub-element and a variables attribute. + The variables attribute is a comma-separated value, where each segment contains an '=' separated pair + of the variable and its value. The variable name can be suffixed with -ref, as in the + date-ref variable above. That means that the binding variable + will have the name date, but the value will be a reference to the dateBean bean from the application context. + This may be useful when using Property Placeholder Configuration or command line arguments. If you need more control over how variables are generated, you can implement your own Java class @@ -115,7 +140,7 @@ provide an implementation of ScriptVariableGenerator and reference it with the script-variable-generator attribute: + script-variable-generator="variableGenerator"/> ]]> If a script-variable-generator is not provided, script components use @@ -124,7 +149,7 @@ variables from the Message in its generateScriptVariables(Message) method. You cannot provide both the script-variable-generator attribute and <variable> sub-element(s) - as they are mutually exclusive. Also, custom variable bindings cannot be used with an inline script. + as they are mutually exclusive.
diff --git a/src/reference/docbook/whats-new.xml b/src/reference/docbook/whats-new.xml index 3f32602196..174005f429 100644 --- a/src/reference/docbook/whats-new.xml +++ b/src/reference/docbook/whats-new.xml @@ -667,5 +667,13 @@ , , and for more information. +
+ Scripting Support: Variables Changes + + A new variables attribute has been introduced for scripting components. + In addition, variable bindings are now allowed for inline scripts. + See and for more information. + +