From e6d58735dd5ab8c4bc3a44b9861f307fb24c538d Mon Sep 17 00:00:00 2001 From: Oleg Zhurakousky Date: Wed, 26 Jan 2011 10:13:56 -0500 Subject: [PATCH] INT-1727 added initial support to allow customization of Groovy bindings --- .../BeanFactoryAwareScriptVariableSource.java | 32 +++++++++++++++++++ ...GroovyScriptExecutingMessageProcessor.java | 13 ++++++-- .../MessageContextBindingCustomizer.java | 17 ++++++++-- .../groovy/ScriptVariableSource.java | 28 ++++++++++++++++ ...yScriptExecutingMessageProcessorTests.java | 26 +++++++++++++++ 5 files changed, 111 insertions(+), 5 deletions(-) create mode 100644 spring-integration-groovy/src/main/java/org/springframework/integration/groovy/BeanFactoryAwareScriptVariableSource.java create mode 100644 spring-integration-groovy/src/main/java/org/springframework/integration/groovy/ScriptVariableSource.java diff --git a/spring-integration-groovy/src/main/java/org/springframework/integration/groovy/BeanFactoryAwareScriptVariableSource.java b/spring-integration-groovy/src/main/java/org/springframework/integration/groovy/BeanFactoryAwareScriptVariableSource.java new file mode 100644 index 0000000000..4dfc6258af --- /dev/null +++ b/spring-integration-groovy/src/main/java/org/springframework/integration/groovy/BeanFactoryAwareScriptVariableSource.java @@ -0,0 +1,32 @@ +/* + * 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. + */ +package org.springframework.integration.groovy; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; + +/** + * @author Oleg Zhurakousky + * + */ +public abstract class BeanFactoryAwareScriptVariableSource implements BeanFactoryAware, ScriptVariableSource { + protected volatile BeanFactory beanFactory; + + public void setBeanFactory(BeanFactory beanFactory) throws BeansException { + this.beanFactory = beanFactory; + } +} 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 80a24c5cea..b9b71f311b 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 @@ -36,14 +36,20 @@ public class GroovyScriptExecutingMessageProcessor extends AbstractScriptExecuti private final MessageContextBindingCustomizer customizer = new MessageContextBindingCustomizer(); private final ScriptSource scriptSource; - + + private final ScriptVariableSource scriptVariableSource; /** * Create a processor for the given {@link ScriptSource}. */ public GroovyScriptExecutingMessageProcessor(ScriptSource scriptSource) { + this(scriptSource, null); + } + + public GroovyScriptExecutingMessageProcessor(ScriptSource scriptSource, ScriptVariableSource scriptVariableSource) { Assert.notNull(scriptSource, "scriptSource must not be null"); this.scriptSource = scriptSource; + this.scriptVariableSource = scriptVariableSource; this.scriptFactory = new GroovyScriptFactory(this.getClass().getSimpleName(), this.customizer); } @@ -57,9 +63,12 @@ public class GroovyScriptExecutingMessageProcessor extends AbstractScriptExecuti protected Object executeScript(ScriptSource scriptSource, Message message) throws Exception { synchronized (this) { this.customizer.setMessage(message); + if (this.scriptVariableSource != null){ + this.customizer.setResolvedScriptVariables(this.scriptVariableSource.resolveScriptVariables()); + } Object result = this.scriptFactory.getScriptedObject(scriptSource, null); return (result instanceof GString) ? result.toString() : result; } - } + } } diff --git a/spring-integration-groovy/src/main/java/org/springframework/integration/groovy/MessageContextBindingCustomizer.java b/spring-integration-groovy/src/main/java/org/springframework/integration/groovy/MessageContextBindingCustomizer.java index b1df0b5962..79b8e4792d 100644 --- a/spring-integration-groovy/src/main/java/org/springframework/integration/groovy/MessageContextBindingCustomizer.java +++ b/spring-integration-groovy/src/main/java/org/springframework/integration/groovy/MessageContextBindingCustomizer.java @@ -36,6 +36,8 @@ class MessageContextBindingCustomizer implements GroovyObjectCustomizer { private volatile Message message; private final GroovyObjectCustomizer customizer; + + private volatile Map resolvedScriptVariables; public MessageContextBindingCustomizer() { @@ -51,20 +53,29 @@ class MessageContextBindingCustomizer implements GroovyObjectCustomizer { } + public void setResolvedScriptVariables(Map resolvedScriptVariables) { + this.resolvedScriptVariables = resolvedScriptVariables; + } + public void setMessage(Message message) { this.message = message; } public void customize(GroovyObject goo) { Assert.state(goo instanceof Script, "Expected a Script"); - if (this.customizer != null) { - this.customizer.customize(goo); + Binding binding = ((Script) goo).getBinding(); + if (resolvedScriptVariables != null){ + for (String key : resolvedScriptVariables.keySet()) { + binding.setVariable(key, this.resolvedScriptVariables.get(key)); + } } if (this.message != null) { - Binding binding = ((Script) goo).getBinding(); binding.setVariable("payload", this.message.getPayload()); binding.setVariable("headers", this.message.getHeaders()); } + if (this.customizer != null){ + this.customizer.customize(goo); + } } } diff --git a/spring-integration-groovy/src/main/java/org/springframework/integration/groovy/ScriptVariableSource.java b/spring-integration-groovy/src/main/java/org/springframework/integration/groovy/ScriptVariableSource.java new file mode 100644 index 0000000000..cbc327d393 --- /dev/null +++ b/spring-integration-groovy/src/main/java/org/springframework/integration/groovy/ScriptVariableSource.java @@ -0,0 +1,28 @@ +/* + * 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. + */ +package org.springframework.integration.groovy; + +import java.util.Map; + + +/** + * @author Oleg Zhurakousky + * + */ +public interface ScriptVariableSource { + + Map resolveScriptVariables(); +} diff --git a/spring-integration-groovy/src/test/java/org/springframework/integration/groovy/GroovyScriptExecutingMessageProcessorTests.java b/spring-integration-groovy/src/test/java/org/springframework/integration/groovy/GroovyScriptExecutingMessageProcessorTests.java index fcea598c38..8641d2e2f9 100644 --- a/spring-integration-groovy/src/test/java/org/springframework/integration/groovy/GroovyScriptExecutingMessageProcessorTests.java +++ b/spring-integration-groovy/src/test/java/org/springframework/integration/groovy/GroovyScriptExecutingMessageProcessorTests.java @@ -22,10 +22,13 @@ import static org.junit.Assert.assertFalse; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import org.junit.Rule; import org.junit.Test; + import org.springframework.core.io.AbstractResource; import org.springframework.integration.Message; import org.springframework.integration.groovy.config.RefreshableResourceScriptSource; @@ -60,6 +63,29 @@ public class GroovyScriptExecutingMessageProcessorTests { Object result = processor.processMessage(message); assertEquals("payload is foo, header is bar"+count, result.toString()); } + + @Test + public void testSimpleExecutionWithScriptVariableSource() throws Exception { + int count = countHolder.getAndIncrement(); + String script = "return \"payload is $payload, header is $headers.testHeader and date is $date\""; + Message message = MessageBuilder.withPayload("foo").setHeader("testHeader", "bar"+count).build(); + TestResource resource = new TestResource(script, "simpleTest"); + ScriptSource scriptSource = new ResourceScriptSource(resource); + Object result = null; + for (int i = 0; i < 5; i++) { + ScriptVariableSource scriptVariableSource = new ScriptVariableSource() { + public Map resolveScriptVariables() { + Map map = new HashMap(); + map.put("date", System.nanoTime()); + return map; + } + }; + MessageProcessor processor = new GroovyScriptExecutingMessageProcessor(scriptSource, scriptVariableSource); + Object newResult = processor.processMessage(message); + assertFalse(newResult.equals(result)); // make sure that we get different nanotime verifying that resolveScriptVariables() is invoked + result = newResult; + } + } @Test public void testLastModified() throws Exception {