moving .scripting.* unit tests from .testsuite -> .context

This commit is contained in:
Chris Beams
2008-12-17 06:48:52 +00:00
parent 31f5961dce
commit 3e8c013df3
76 changed files with 145 additions and 12 deletions

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2002-2005 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.aop.framework;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
/**
* Simple before advice example that we can use for counting checks.
*
* @author Rod Johnson
*/
public class CountingBeforeAdvice extends MethodCounter implements MethodBeforeAdvice {
public void before(Method m, Object[] args, Object target) throws Throwable {
count(m);
}
}

View File

@@ -0,0 +1,68 @@
/*
* Copyright 2002-2007 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.aop.framework;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.HashMap;
/**
* Useful abstract superclass for counting advices etc.
*
* @author Rod Johnson
*/
public class MethodCounter implements Serializable {
/** Method name --> count, does not understand overloading */
private HashMap map = new HashMap();
private int allCount;
protected void count(Method m) {
count(m.getName());
}
protected void count(String methodName) {
Integer i = (Integer) map.get(methodName);
i = (i != null) ? new Integer(i.intValue() + 1) : new Integer(1);
map.put(methodName, i);
++allCount;
}
public int getCalls(String methodName) {
Integer i = (Integer) map.get(methodName);
return (i != null ? i.intValue() : 0);
}
public int getCalls() {
return allCount;
}
/**
* A bit simplistic: just wants the same class.
* Doesn't worry about counts.
* @see java.lang.Object#equals(java.lang.Object)
*/
public boolean equals(Object other) {
return (other != null && other.getClass() == this.getClass());
}
public int hashCode() {
return getClass().hashCode();
}
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright 2002-2006 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.scripting;
/**
* @author Rob Harrop
*/
public interface Calculator {
int add(int x, int y);
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright 2002-2007 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.scripting;
/**
* @author Juergen Hoeller
*/
public interface CallCounter {
void before();
int getCalls();
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright 2002-2006 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.scripting;
/**
* @author Juergen Hoeller
*/
public interface ConfigurableMessenger extends Messenger {
void setMessage(String message);
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright 2002-2007 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.scripting;
import org.springframework.beans.TestBean;
import org.springframework.context.ApplicationContext;
/**
* @author Juergen Hoeller
* @since 08.08.2006
*/
public interface ContextScriptBean extends ScriptBean {
TestBean getTestBean();
ApplicationContext getApplicationContext();
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright 2002-2006 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.scripting;
/**
* @author Rob Harrop
*/
public interface Messenger {
String getMessage();
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2002-2007 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.scripting;
import org.aspectj.lang.ProceedingJoinPoint;
/**
* Twee advice that 'scrambles' the return value
* of a {@link Messenger} invocation.
*
* @author Rick Evans
*/
public final class MessengerScrambler {
public String scramble(ProceedingJoinPoint pjp) throws Throwable {
String message = (String) pjp.proceed();
return new StringBuffer(message).reverse().toString();
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2002-2006 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.scripting;
/**
* Simple interface used in testing the scripted beans support.
*
* @author Rick Evans
*/
public interface ScriptBean {
String getName();
void setName(String name);
int getAge();
void setAge(int age);
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright 2002-2007 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.scripting;
import org.springframework.beans.TestBean;
/**
* @author Juergen Hoeller
*/
public interface TestBeanAwareMessenger extends ConfigurableMessenger {
TestBean getTestBean();
void setTestBean(TestBean testBean);
}

View File

@@ -0,0 +1 @@
one sure is the loneliest number... that i'll ever know

View File

@@ -0,0 +1,306 @@
/*
* Copyright 2002-2007 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.scripting.bsh;
import java.util.Arrays;
import java.util.Collection;
import junit.framework.TestCase;
import org.easymock.MockControl;
import org.springframework.aop.support.AopUtils;
import org.springframework.aop.target.dynamic.Refreshable;
import org.springframework.beans.TestBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.NestedRuntimeException;
import org.springframework.scripting.Calculator;
import org.springframework.scripting.ConfigurableMessenger;
import org.springframework.scripting.Messenger;
import org.springframework.scripting.ScriptCompilationException;
import org.springframework.scripting.ScriptSource;
import org.springframework.scripting.TestBeanAwareMessenger;
import org.springframework.scripting.support.ScriptFactoryPostProcessor;
/**
* @author Rob Harrop
* @author Rick Evans
* @author Juergen Hoeller
*/
public class BshScriptFactoryTests extends TestCase {
public void testStaticScript() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("bshContext.xml", getClass());
assertTrue(Arrays.asList(ctx.getBeanNamesForType(Calculator.class)).contains("calculator"));
assertTrue(Arrays.asList(ctx.getBeanNamesForType(Messenger.class)).contains("messenger"));
Calculator calc = (Calculator) ctx.getBean("calculator");
Messenger messenger = (Messenger) ctx.getBean("messenger");
assertFalse("Scripted object should not be instance of Refreshable", calc instanceof Refreshable);
assertFalse("Scripted object should not be instance of Refreshable", messenger instanceof Refreshable);
assertEquals(calc, calc);
assertEquals(messenger, messenger);
assertTrue(!messenger.equals(calc));
assertTrue(messenger.hashCode() != calc.hashCode());
assertTrue(!messenger.toString().equals(calc.toString()));
assertEquals(5, calc.add(2, 3));
String desiredMessage = "Hello World!";
assertEquals("Message is incorrect", desiredMessage, messenger.getMessage());
assertTrue(ctx.getBeansOfType(Calculator.class).values().contains(calc));
assertTrue(ctx.getBeansOfType(Messenger.class).values().contains(messenger));
}
public void testStaticScriptWithNullReturnValue() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("bshContext.xml", getClass());
assertTrue(Arrays.asList(ctx.getBeanNamesForType(Messenger.class)).contains("messengerWithConfig"));
ConfigurableMessenger messenger = (ConfigurableMessenger) ctx.getBean("messengerWithConfig");
messenger.setMessage(null);
assertNull(messenger.getMessage());
assertTrue(ctx.getBeansOfType(Messenger.class).values().contains(messenger));
}
public void testStaticScriptWithTwoInterfacesSpecified() throws Exception {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("bshContext.xml", getClass());
assertTrue(Arrays.asList(ctx.getBeanNamesForType(Messenger.class)).contains("messengerWithConfigExtra"));
ConfigurableMessenger messenger = (ConfigurableMessenger) ctx.getBean("messengerWithConfigExtra");
messenger.setMessage(null);
assertNull(messenger.getMessage());
assertTrue(ctx.getBeansOfType(Messenger.class).values().contains(messenger));
ctx.close();
assertNull(messenger.getMessage());
}
public void testStaticWithScriptReturningInstance() throws Exception {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("bshContext.xml", getClass());
assertTrue(Arrays.asList(ctx.getBeanNamesForType(Messenger.class)).contains("messengerInstance"));
Messenger messenger = (Messenger) ctx.getBean("messengerInstance");
String desiredMessage = "Hello World!";
assertEquals("Message is incorrect", desiredMessage, messenger.getMessage());
assertTrue(ctx.getBeansOfType(Messenger.class).values().contains(messenger));
ctx.close();
assertNull(messenger.getMessage());
}
public void testStaticScriptImplementingInterface() throws Exception {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("bshContext.xml", getClass());
assertTrue(Arrays.asList(ctx.getBeanNamesForType(Messenger.class)).contains("messengerImpl"));
Messenger messenger = (Messenger) ctx.getBean("messengerImpl");
String desiredMessage = "Hello World!";
assertEquals("Message is incorrect", desiredMessage, messenger.getMessage());
assertTrue(ctx.getBeansOfType(Messenger.class).values().contains(messenger));
ctx.close();
assertNull(messenger.getMessage());
}
public void testStaticPrototypeScript() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("bshContext.xml", getClass());
ConfigurableMessenger messenger = (ConfigurableMessenger) ctx.getBean("messengerPrototype");
ConfigurableMessenger messenger2 = (ConfigurableMessenger) ctx.getBean("messengerPrototype");
assertFalse("Shouldn't get proxy when refresh is disabled", AopUtils.isAopProxy(messenger));
assertFalse("Scripted object should not be instance of Refreshable", messenger instanceof Refreshable);
assertNotSame(messenger, messenger2);
assertSame(messenger.getClass(), messenger2.getClass());
assertEquals("Hello World!", messenger.getMessage());
assertEquals("Hello World!", messenger2.getMessage());
messenger.setMessage("Bye World!");
messenger2.setMessage("Byebye World!");
assertEquals("Bye World!", messenger.getMessage());
assertEquals("Byebye World!", messenger2.getMessage());
}
public void testNonStaticScript() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("bshRefreshableContext.xml", getClass());
Messenger messenger = (Messenger) ctx.getBean("messenger");
assertTrue("Should be a proxy for refreshable scripts", AopUtils.isAopProxy(messenger));
assertTrue("Should be an instance of Refreshable", messenger instanceof Refreshable);
String desiredMessage = "Hello World!";
assertEquals("Message is incorrect", desiredMessage, messenger.getMessage());
Refreshable refreshable = (Refreshable) messenger;
refreshable.refresh();
assertEquals("Message is incorrect after refresh", desiredMessage, messenger.getMessage());
assertEquals("Incorrect refresh count", 2, refreshable.getRefreshCount());
}
public void testNonStaticPrototypeScript() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("bshRefreshableContext.xml", getClass());
ConfigurableMessenger messenger = (ConfigurableMessenger) ctx.getBean("messengerPrototype");
ConfigurableMessenger messenger2 = (ConfigurableMessenger) ctx.getBean("messengerPrototype");
assertTrue("Should be a proxy for refreshable scripts", AopUtils.isAopProxy(messenger));
assertTrue("Should be an instance of Refreshable", messenger instanceof Refreshable);
assertEquals("Hello World!", messenger.getMessage());
assertEquals("Hello World!", messenger2.getMessage());
messenger.setMessage("Bye World!");
messenger2.setMessage("Byebye World!");
assertEquals("Bye World!", messenger.getMessage());
assertEquals("Byebye World!", messenger2.getMessage());
Refreshable refreshable = (Refreshable) messenger;
refreshable.refresh();
assertEquals("Hello World!", messenger.getMessage());
assertEquals("Byebye World!", messenger2.getMessage());
assertEquals("Incorrect refresh count", 2, refreshable.getRefreshCount());
}
public void testScriptCompilationException() throws Exception {
try {
new ClassPathXmlApplicationContext("org/springframework/scripting/bsh/bshBrokenContext.xml");
fail("Must throw exception for broken script file");
}
catch (NestedRuntimeException ex) {
assertTrue(ex.contains(ScriptCompilationException.class));
}
}
public void testScriptThatCompilesButIsJustPlainBad() throws Exception {
MockControl mock = MockControl.createControl(ScriptSource.class);
ScriptSource script = (ScriptSource) mock.getMock();
script.getScriptAsString();
final String badScript = "String getMessage() { throw new IllegalArgumentException(); }";
mock.setReturnValue(badScript);
script.isModified();
mock.setReturnValue(true);
mock.replay();
BshScriptFactory factory = new BshScriptFactory(
ScriptFactoryPostProcessor.INLINE_SCRIPT_PREFIX + badScript,
new Class[] {Messenger.class});
try {
Messenger messenger = (Messenger) factory.getScriptedObject(script, new Class[]{Messenger.class});
messenger.getMessage();
fail("Must have thrown a BshScriptUtils.BshExecutionException.");
}
catch (BshScriptUtils.BshExecutionException expected) {
}
mock.verify();
}
public void testCtorWithNullScriptSourceLocator() throws Exception {
try {
new BshScriptFactory(null, new Class[] {Messenger.class});
fail("Must have thrown exception by this point.");
}
catch (IllegalArgumentException expected) {
}
}
public void testCtorWithEmptyScriptSourceLocator() throws Exception {
try {
new BshScriptFactory("", new Class[] {Messenger.class});
fail("Must have thrown exception by this point.");
}
catch (IllegalArgumentException expected) {
}
}
public void testCtorWithWhitespacedScriptSourceLocator() throws Exception {
try {
new BshScriptFactory("\n ", new Class[] {Messenger.class});
fail("Must have thrown exception by this point.");
}
catch (IllegalArgumentException expected) {
}
}
public void testResourceScriptFromTag() throws Exception {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("bsh-with-xsd.xml", getClass());
TestBean testBean = (TestBean) ctx.getBean("testBean");
Collection beanNames = Arrays.asList(ctx.getBeanNamesForType(Messenger.class));
assertTrue(beanNames.contains("messenger"));
assertTrue(beanNames.contains("messengerImpl"));
assertTrue(beanNames.contains("messengerInstance"));
Messenger messenger = (Messenger) ctx.getBean("messenger");
assertEquals("Hello World!", messenger.getMessage());
assertFalse(messenger instanceof Refreshable);
Messenger messengerImpl = (Messenger) ctx.getBean("messengerImpl");
assertEquals("Hello World!", messengerImpl.getMessage());
Messenger messengerInstance = (Messenger) ctx.getBean("messengerInstance");
assertEquals("Hello World!", messengerInstance.getMessage());
TestBeanAwareMessenger messengerByType = (TestBeanAwareMessenger) ctx.getBean("messengerByType");
assertEquals(testBean, messengerByType.getTestBean());
TestBeanAwareMessenger messengerByName = (TestBeanAwareMessenger) ctx.getBean("messengerByName");
assertEquals(testBean, messengerByName.getTestBean());
Collection beans = ctx.getBeansOfType(Messenger.class).values();
assertTrue(beans.contains(messenger));
assertTrue(beans.contains(messengerImpl));
assertTrue(beans.contains(messengerInstance));
assertTrue(beans.contains(messengerByType));
assertTrue(beans.contains(messengerByName));
ctx.close();
assertNull(messenger.getMessage());
assertNull(messengerImpl.getMessage());
assertNull(messengerInstance.getMessage());
}
public void testPrototypeScriptFromTag() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("bsh-with-xsd.xml", getClass());
ConfigurableMessenger messenger = (ConfigurableMessenger) ctx.getBean("messengerPrototype");
ConfigurableMessenger messenger2 = (ConfigurableMessenger) ctx.getBean("messengerPrototype");
assertNotSame(messenger, messenger2);
assertSame(messenger.getClass(), messenger2.getClass());
assertEquals("Hello World!", messenger.getMessage());
assertEquals("Hello World!", messenger2.getMessage());
messenger.setMessage("Bye World!");
messenger2.setMessage("Byebye World!");
assertEquals("Bye World!", messenger.getMessage());
assertEquals("Byebye World!", messenger2.getMessage());
}
public void testInlineScriptFromTag() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("bsh-with-xsd.xml", getClass());
Calculator calculator = (Calculator) ctx.getBean("calculator");
assertNotNull(calculator);
assertFalse(calculator instanceof Refreshable);
}
public void testRefreshableFromTag() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("bsh-with-xsd.xml", getClass());
Messenger messenger = (Messenger) ctx.getBean("refreshableMessenger");
assertEquals("Hello World!", messenger.getMessage());
assertTrue("Messenger should be Refreshable", messenger instanceof Refreshable);
}
}

View File

@@ -0,0 +1,3 @@
int add(int x, int y) {
return x + y;
}

View File

@@ -0,0 +1,21 @@
String message;
boolean active;
void init() {
active = true;
}
String getMessage() {
if (!active && message != null) throw new java.lang.IllegalStateException();
return message;
}
void setMessage(String aMessage) {
message = aMessage;
}
void destroy() {
message = null;
active = false;
}

View File

@@ -0,0 +1,38 @@
import org.springframework.beans.TestBean;
import org.springframework.scripting.TestBeanAwareMessenger;
public class MyMessenger implements TestBeanAwareMessenger {
private String message;
private TestBean testBean;
private boolean active;
public void init() {
active = true;
}
public String getMessage() {
if (!active && message != null) throw new java.lang.IllegalStateException();
return message;
}
public void setMessage(String aMessage) {
message = aMessage;
}
public TestBean getTestBean() {
return testBean;
}
public void setTestBean(TestBean tb) {
testBean = tb;
}
public void destroy() {
message = null;
active = false;
}
}

View File

@@ -0,0 +1,28 @@
import org.springframework.scripting.Messenger;
public class MyMessenger implements Messenger {
private String message;
private boolean active;
public void init() {
active = true;
}
public String getMessage() {
if (!active && message != null) throw new java.lang.IllegalStateException();
return message;
}
public void setMessage(String aMessage) {
message = aMessage;
}
public void destroy() {
message = null;
active = false;
}
}
return new MyMessenger() ;

View File

@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:lang="http://www.springframework.org/schema/lang"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.5.xsd">
<lang:bsh id="messenger" script-source="classpath:org/springframework/scripting/bsh/Messenger.bsh"
script-interfaces="org.springframework.scripting.Messenger"
init-method="init" destroy-method="destroy">
<lang:property name="message" value="Hello World!"/>
</lang:bsh>
<lang:bsh id="messengerPrototype" script-source="classpath:org/springframework/scripting/bsh/Messenger.bsh"
script-interfaces="org.springframework.scripting.ConfigurableMessenger"
scope="prototype" init-method="init" destroy-method="destroy">
<lang:property name="message" value="Hello World!"/>
</lang:bsh>
<lang:bsh id="messengerImpl" script-source="classpath:org/springframework/scripting/bsh/MessengerImpl.bsh"
init-method="init" destroy-method="destroy">
<lang:property name="message" value="Hello World!"/>
</lang:bsh>
<lang:bsh id="messengerInstance" script-source="classpath:org/springframework/scripting/bsh/MessengerInstance.bsh"
init-method="init" destroy-method="destroy">
<lang:property name="message" value="Hello World!"/>
</lang:bsh>
<lang:bsh id="messengerByType" script-source="classpath:org/springframework/scripting/bsh/MessengerImpl.bsh"
autowire="byType" dependency-check="objects" init-method="init" destroy-method="destroy">
</lang:bsh>
<lang:bsh id="messengerByName" script-source="classpath:org/springframework/scripting/bsh/MessengerImpl.bsh"
autowire="byName" init-method="init" destroy-method="destroy">
</lang:bsh>
<bean id="testBean" class="org.springframework.beans.TestBean"/>
<lang:bsh id="calculator" script-interfaces="org.springframework.scripting.Calculator">
<lang:inline-script>
int add(int x, int y) {
return x + y;
}
</lang:inline-script>
</lang:bsh>
<lang:bsh id="refreshableMessenger" script-interfaces="org.springframework.scripting.Messenger"
script-source="classpath:org/springframework/scripting/bsh/Messenger.bsh" refresh-check-delay="5000"
init-method="init" destroy-method="destroy">
<lang:property name="message" value="Hello World!"/>
</lang:bsh>
</beans>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
"http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor"/>
<bean id="broken" class="org.springframework.scripting.bsh.BshScriptFactory">
<constructor-arg value="classpath:org/springframework/scripting/bsh/Broken.bsh"/>
<constructor-arg value="org.springframework.scripting.Messenger"/>
</bean>
</beans>

View File

@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans default-lazy-init="true">
<bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor"/>
<bean id="calculator" class="org.springframework.scripting.bsh.BshScriptFactory">
<constructor-arg>
<value>inline:
int add(int x, int y) {
return x + y;
}
</value>
</constructor-arg>
<constructor-arg value="org.springframework.scripting.Calculator"/>
</bean>
<bean id="messenger" class="org.springframework.scripting.bsh.BshScriptFactory"
init-method="init" destroy-method="destroy">
<constructor-arg value="classpath:org/springframework/scripting/bsh/Messenger.bsh"/>
<constructor-arg value="org.springframework.scripting.Messenger"/>
<property name="message" value="Hello World!"/>
</bean>
<bean id="messengerWithConfig" class="org.springframework.scripting.bsh.BshScriptFactory"
init-method="init" destroy-method="destroy">
<constructor-arg value="classpath:org/springframework/scripting/bsh/Messenger.bsh"/>
<constructor-arg value="org.springframework.scripting.ConfigurableMessenger"/>
<property name="message" value="Hello World!"/>
</bean>
<bean id="messengerWithConfigExtra" class="org.springframework.scripting.bsh.BshScriptFactory"
init-method="init" destroy-method="destroy">
<constructor-arg value="classpath:org/springframework/scripting/bsh/Messenger.bsh"/>
<constructor-arg value="org.springframework.scripting.Messenger,org.springframework.scripting.ConfigurableMessenger"/>
<property name="message" value="Hello World!"/>
</bean>
<bean id="messengerInstance" class="org.springframework.scripting.bsh.BshScriptFactory"
init-method="init" destroy-method="destroy">
<constructor-arg value="classpath:org/springframework/scripting/bsh/MessengerInstance.bsh"/>
<property name="message" value="Hello World!"/>
</bean>
<bean id="messengerInstanceWithExplicitInterface" class="org.springframework.scripting.bsh.BshScriptFactory">
<constructor-arg value="classpath:org/springframework/scripting/bsh/MessengerInstance.bsh"/>
<constructor-arg value="org.springframework.scripting.Messenger"/>
<property name="message" value="Hello World!"/>
</bean>
<bean id="messengerImpl" class="org.springframework.scripting.bsh.BshScriptFactory"
init-method="init" destroy-method="destroy">
<constructor-arg value="classpath:org/springframework/scripting/bsh/MessengerImpl.bsh"/>
<property name="message" value="Hello World!"/>
</bean>
<bean id="messengerImplWithExplicitInterface" class="org.springframework.scripting.bsh.BshScriptFactory"
init-method="init">
<constructor-arg value="classpath:org/springframework/scripting/bsh/MessengerImpl.bsh"/>
<constructor-arg value="org.springframework.scripting.Messenger"/>
<property name="message" value="Hello World!"/>
</bean>
<bean id="messengerPrototype" class="org.springframework.scripting.bsh.BshScriptFactory" scope="prototype"
init-method="init">
<constructor-arg value="classpath:org/springframework/scripting/bsh/MessengerImpl.bsh"/>
<property name="message" value="Hello World!"/>
</bean>
</beans>

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans default-lazy-init="true">
<bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor">
<property name="defaultRefreshCheckDelay" value="1"/>
</bean>
<bean id="calculator" class="org.springframework.scripting.bsh.BshScriptFactory">
<constructor-arg value="classpath:org/springframework/scripting/bsh/Calculator.bsh"/>
<constructor-arg value="org.springframework.scripting.Calculator"/>
</bean>
<bean id="messenger" class="org.springframework.scripting.bsh.BshScriptFactory" init-method="init">
<constructor-arg value="classpath:org/springframework/scripting/bsh/MessengerImpl.bsh"/>
<property name="message" value="Hello World!"/>
</bean>
<bean id="messengerPrototype" class="org.springframework.scripting.bsh.BshScriptFactory"
scope="prototype" init-method="init">
<constructor-arg value="classpath:org/springframework/scripting/bsh/MessengerImpl.bsh"/>
<property name="message" value="Hello World!"/>
</bean>
</beans>

View File

@@ -0,0 +1,30 @@
/*
* Copyright 2002-2007 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.scripting.config;
/**
* @author Mark Fisher
*/
public interface ITestBean {
boolean isInitialized();
boolean isDestroyed();
ITestBean getOtherBean();
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2002-2007 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.scripting.config;
/**
* @author Mark Fisher
*/
public class OtherTestBean implements ITestBean {
public ITestBean getOtherBean() {
return null;
}
public boolean isInitialized() {
return false;
}
public boolean isDestroyed() {
return false;
}
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright 2002-2007 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.scripting.config;
import java.lang.reflect.Field;
import junit.framework.TestCase;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.target.dynamic.AbstractRefreshableTargetSource;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author Mark Fisher
*/
public class ScriptingDefaultsTests extends TestCase {
private static final String CONFIG =
"org/springframework/scripting/config/scriptingDefaultsTests.xml";
public void testDefaultRefreshCheckDelay() throws Exception {
ApplicationContext context = new ClassPathXmlApplicationContext(CONFIG);
Advised advised = (Advised) context.getBean("testBean");
AbstractRefreshableTargetSource targetSource =
((AbstractRefreshableTargetSource) advised.getTargetSource());
Field field = AbstractRefreshableTargetSource.class.getDeclaredField("refreshCheckDelay");
field.setAccessible(true);
long delay = ((Long) field.get(targetSource)).longValue();
assertEquals(5000L, delay);
}
public void testDefaultInitMethod() {
ApplicationContext context = new ClassPathXmlApplicationContext(CONFIG);
ITestBean testBean = (ITestBean) context.getBean("testBean");
assertTrue(testBean.isInitialized());
}
public void testDefaultDestroyMethod() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(CONFIG);
ITestBean testBean = (ITestBean) context.getBean("nonRefreshableTestBean");
assertFalse(testBean.isDestroyed());
context.close();
assertTrue(testBean.isDestroyed());
}
public void testDefaultAutowire() {
ApplicationContext context = new ClassPathXmlApplicationContext(CONFIG);
ITestBean testBean = (ITestBean) context.getBean("testBean");
ITestBean otherBean = (ITestBean) context.getBean("otherBean");
assertEquals(otherBean, testBean.getOtherBean());
}
}

View File

@@ -0,0 +1,19 @@
package org.springframework.scripting.config
class TestBean implements ITestBean {
ITestBean otherBean
boolean initialized
boolean destroyed
void setOtherBean(ITestBean otherBean) {
this.otherBean = otherBean;
}
void startup() { this.initialized = true }
void shutdown() { this.destroyed = true }
}

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:lang="http://www.springframework.org/schema/lang"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/lang
http://www.springframework.org/schema/lang/spring-lang.xsd"
default-autowire="byName"
default-init-method="startup"
default-destroy-method="shutdown">
<lang:defaults refresh-check-delay="5000"/>
<lang:groovy id="testBean" script-source="classpath:org/springframework/scripting/config/TestBean.groovy"/>
<lang:groovy id="nonRefreshableTestBean" refresh-check-delay="-1"
script-source="classpath:org/springframework/scripting/config/TestBean.groovy"/>
<bean id="otherBean" class="org.springframework.scripting.config.OtherTestBean"/>
</beans>

View File

@@ -0,0 +1,14 @@
I have eaten
the plums
that were in
the icebox
and which
you were probably
saving
for breakfast
Forgive me
they were delicious
so sweet
and so cold

View File

@@ -0,0 +1,10 @@
package org.springframework.scripting.groovy;
import org.springframework.scripting.Calculator
class GroovyCalculator implements Calculator {
int add(int x, int y) {
return x + y;
}
}

View File

@@ -0,0 +1,24 @@
package org.springframework.scripting.groovy;
import org.springframework.scripting.CallCounter;
class GroovyCallCounter implements CallCounter {
int count = -100;
void init() {
count = 0;
}
void before() {
count++;
}
int getCalls() {
return count;
}
void destroy() {
count = -200;
}
}

View File

@@ -0,0 +1,19 @@
package org.springframework.scripting.groovy;
import org.springframework.scripting.Calculator
class DelegatingCalculator implements Calculator {
def Calculator delegate;
int add(int x, int y) {
//println "hello"
//println this.metaClass.getClass()
//println delegate.metaClass.getClass()
//delegate.metaClass.invokeMethod("add", [x,y])
delegate.callMissingMethod()
return delegate.add(x,y)
}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright 2002-2007 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.scripting.groovy;
import java.lang.reflect.Method;
import groovy.lang.GroovyClassLoader;
import junit.framework.TestCase;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.util.ReflectionUtils;
/**
* @author Mark Fisher
*/
public class GroovyClassLoadingTests extends TestCase {
public void testClassLoading() throws Exception {
StaticApplicationContext context = new StaticApplicationContext();
GroovyClassLoader gcl = new GroovyClassLoader();
Class class1 = gcl.parseClass("class TestBean { def myMethod() { \"foo\" } }");
Class class2 = gcl.parseClass("class TestBean { def myMethod() { \"bar\" } }");
context.registerBeanDefinition("testBean", new RootBeanDefinition(class1));
Object testBean1 = context.getBean("testBean");
Method method1 = class1.getDeclaredMethod("myMethod", new Class[0]);
Object result1 = ReflectionUtils.invokeMethod(method1, testBean1);
assertEquals("foo", (String) result1);
// ### uncommenting the next line causes the test to pass for Spring > 2.0.2 ###
//context.removeBeanDefinition("testBean");
context.registerBeanDefinition("testBean", new RootBeanDefinition(class2));
Object testBean2 = context.getBean("testBean");
Method method2 = class2.getDeclaredMethod("myMethod", new Class[0]);
Object result2 = ReflectionUtils.invokeMethod(method2, testBean2);
assertEquals("bar", (String) result2);
}
}

View File

@@ -0,0 +1,476 @@
/*
* Copyright 2002-2008 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.scripting.groovy;
import static org.junit.Assert.*;
import java.io.FileNotFoundException;
import java.util.Arrays;
import java.util.Map;
import groovy.lang.DelegatingMetaClass;
import groovy.lang.GroovyObject;
import junit.framework.TestCase;
import org.easymock.MockControl;
import org.junit.Test;
import org.springframework.aop.support.AopUtils;
import org.springframework.aop.target.dynamic.Refreshable;
import org.springframework.beans.TestBean;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.UnsatisfiedDependencyException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.NestedRuntimeException;
import org.springframework.scripting.Calculator;
import org.springframework.scripting.CallCounter;
import org.springframework.scripting.ConfigurableMessenger;
import org.springframework.scripting.ContextScriptBean;
import org.springframework.scripting.Messenger;
import org.springframework.scripting.ScriptCompilationException;
import org.springframework.scripting.ScriptSource;
import org.springframework.scripting.support.ScriptFactoryPostProcessor;
/**
* @author Rob Harrop
* @author Rick Evans
* @author Rod Johnson
* @author Juergen Hoeller
* @author Mark Fisher
* @author Chris Beams
*/
public class GroovyScriptFactoryTests {
@Test
public void testStaticScript() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("groovyContext.xml", getClass());
assertTrue(Arrays.asList(ctx.getBeanNamesForType(Calculator.class)).contains("calculator"));
assertTrue(Arrays.asList(ctx.getBeanNamesForType(Messenger.class)).contains("messenger"));
Calculator calc = (Calculator) ctx.getBean("calculator");
Messenger messenger = (Messenger) ctx.getBean("messenger");
assertFalse("Shouldn't get proxy when refresh is disabled", AopUtils.isAopProxy(calc));
assertFalse("Shouldn't get proxy when refresh is disabled", AopUtils.isAopProxy(messenger));
assertFalse("Scripted object should not be instance of Refreshable", calc instanceof Refreshable);
assertFalse("Scripted object should not be instance of Refreshable", messenger instanceof Refreshable);
assertEquals(calc, calc);
assertEquals(messenger, messenger);
assertTrue(!messenger.equals(calc));
assertTrue(messenger.hashCode() != calc.hashCode());
assertTrue(!messenger.toString().equals(calc.toString()));
String desiredMessage = "Hello World!";
assertEquals("Message is incorrect", desiredMessage, messenger.getMessage());
assertTrue(ctx.getBeansOfType(Calculator.class).values().contains(calc));
assertTrue(ctx.getBeansOfType(Messenger.class).values().contains(messenger));
}
@Test
public void testStaticPrototypeScript() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("groovyContext.xml", getClass());
ConfigurableMessenger messenger = (ConfigurableMessenger) ctx.getBean("messengerPrototype");
ConfigurableMessenger messenger2 = (ConfigurableMessenger) ctx.getBean("messengerPrototype");
assertFalse("Shouldn't get proxy when refresh is disabled", AopUtils.isAopProxy(messenger));
assertFalse("Scripted object should not be instance of Refreshable", messenger instanceof Refreshable);
assertNotSame(messenger, messenger2);
assertSame(messenger.getClass(), messenger2.getClass());
assertEquals("Hello World!", messenger.getMessage());
assertEquals("Hello World!", messenger2.getMessage());
messenger.setMessage("Bye World!");
messenger2.setMessage("Byebye World!");
assertEquals("Bye World!", messenger.getMessage());
assertEquals("Byebye World!", messenger2.getMessage());
}
@Test
public void testStaticScriptWithInstance() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("groovyContext.xml", getClass());
assertTrue(Arrays.asList(ctx.getBeanNamesForType(Messenger.class)).contains("messengerInstance"));
Messenger messenger = (Messenger) ctx.getBean("messengerInstance");
assertFalse("Shouldn't get proxy when refresh is disabled", AopUtils.isAopProxy(messenger));
assertFalse("Scripted object should not be instance of Refreshable", messenger instanceof Refreshable);
String desiredMessage = "Hello World!";
assertEquals("Message is incorrect", desiredMessage, messenger.getMessage());
assertTrue(ctx.getBeansOfType(Messenger.class).values().contains(messenger));
}
@Test
public void testStaticScriptWithInlineDefinedInstance() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("groovyContext.xml", getClass());
assertTrue(Arrays.asList(ctx.getBeanNamesForType(Messenger.class)).contains("messengerInstanceInline"));
Messenger messenger = (Messenger) ctx.getBean("messengerInstanceInline");
assertFalse("Shouldn't get proxy when refresh is disabled", AopUtils.isAopProxy(messenger));
assertFalse("Scripted object should not be instance of Refreshable", messenger instanceof Refreshable);
String desiredMessage = "Hello World!";
assertEquals("Message is incorrect", desiredMessage, messenger.getMessage());
assertTrue(ctx.getBeansOfType(Messenger.class).values().contains(messenger));
}
@Test
public void testNonStaticScript() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("groovyRefreshableContext.xml", getClass());
Messenger messenger = (Messenger) ctx.getBean("messenger");
assertTrue("Should be a proxy for refreshable scripts", AopUtils.isAopProxy(messenger));
assertTrue("Should be an instance of Refreshable", messenger instanceof Refreshable);
String desiredMessage = "Hello World!";
assertEquals("Message is incorrect", desiredMessage, messenger.getMessage());
Refreshable refreshable = (Refreshable) messenger;
refreshable.refresh();
assertEquals("Message is incorrect after refresh.", desiredMessage, messenger.getMessage());
assertEquals("Incorrect refresh count", 2, refreshable.getRefreshCount());
}
@Test
public void testNonStaticPrototypeScript() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("groovyRefreshableContext.xml", getClass());
ConfigurableMessenger messenger = (ConfigurableMessenger) ctx.getBean("messengerPrototype");
ConfigurableMessenger messenger2 = (ConfigurableMessenger) ctx.getBean("messengerPrototype");
assertTrue("Should be a proxy for refreshable scripts", AopUtils.isAopProxy(messenger));
assertTrue("Should be an instance of Refreshable", messenger instanceof Refreshable);
assertEquals("Hello World!", messenger.getMessage());
assertEquals("Hello World!", messenger2.getMessage());
messenger.setMessage("Bye World!");
messenger2.setMessage("Byebye World!");
assertEquals("Bye World!", messenger.getMessage());
assertEquals("Byebye World!", messenger2.getMessage());
Refreshable refreshable = (Refreshable) messenger;
refreshable.refresh();
assertEquals("Hello World!", messenger.getMessage());
assertEquals("Byebye World!", messenger2.getMessage());
assertEquals("Incorrect refresh count", 2, refreshable.getRefreshCount());
}
@Test
public void testScriptCompilationException() throws Exception {
try {
new ClassPathXmlApplicationContext("org/springframework/scripting/groovy/groovyBrokenContext.xml");
fail("Should throw exception for broken script file");
}
catch (NestedRuntimeException ex) {
assertTrue("Wrong root cause: " + ex, ex.contains(ScriptCompilationException.class));
}
}
@Test
public void testScriptedClassThatDoesNotHaveANoArgCtor() throws Exception {
MockControl mock = MockControl.createControl(ScriptSource.class);
ScriptSource script = (ScriptSource) mock.getMock();
script.getScriptAsString();
final String badScript = "class Foo { public Foo(String foo) {}}";
mock.setReturnValue(badScript);
script.suggestedClassName();
mock.setReturnValue("someName");
mock.replay();
GroovyScriptFactory factory = new GroovyScriptFactory(ScriptFactoryPostProcessor.INLINE_SCRIPT_PREFIX + badScript);
try {
factory.getScriptedObject(script, new Class[]{});
fail("Must have thrown a ScriptCompilationException (no public no-arg ctor in scripted class).");
}
catch (ScriptCompilationException expected) {
assertTrue(expected.contains(InstantiationException.class));
}
mock.verify();
}
@Test
public void testScriptedClassThatHasNoPublicNoArgCtor() throws Exception {
MockControl mock = MockControl.createControl(ScriptSource.class);
ScriptSource script = (ScriptSource) mock.getMock();
script.getScriptAsString();
final String badScript = "class Foo { protected Foo() {}}";
mock.setReturnValue(badScript);
script.suggestedClassName();
mock.setReturnValue("someName");
mock.replay();
GroovyScriptFactory factory = new GroovyScriptFactory(ScriptFactoryPostProcessor.INLINE_SCRIPT_PREFIX + badScript);
try {
factory.getScriptedObject(script, new Class[]{});
fail("Must have thrown a ScriptCompilationException (no oublic no-arg ctor in scripted class).");
}
catch (ScriptCompilationException expected) {
assertTrue(expected.contains(IllegalAccessException.class));
}
mock.verify();
}
@Test
public void testWithTwoClassesDefinedInTheOneGroovyFile_CorrectClassFirst() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("twoClassesCorrectOneFirst.xml", getClass());
Messenger messenger = (Messenger) ctx.getBean("messenger");
assertNotNull(messenger);
assertEquals("Hello World!", messenger.getMessage());
// Check can cast to GroovyObject
GroovyObject goo = (GroovyObject) messenger;
}
@Test
public void testWithTwoClassesDefinedInTheOneGroovyFile_WrongClassFirst() throws Exception {
try {
ApplicationContext ctx = new ClassPathXmlApplicationContext("twoClassesWrongOneFirst.xml", getClass());
ctx.getBean("messenger", Messenger.class);
fail("Must have failed: two classes defined in GroovyScriptFactory source, non-Messenger class defined first.");
}
// just testing for failure here, hence catching Exception...
catch (Exception expected) {
}
}
@Test
public void testCtorWithNullScriptSourceLocator() throws Exception {
try {
new GroovyScriptFactory(null);
fail("Must have thrown exception by this point.");
}
catch (IllegalArgumentException expected) {
}
}
@Test
public void testCtorWithEmptyScriptSourceLocator() throws Exception {
try {
new GroovyScriptFactory("");
fail("Must have thrown exception by this point.");
}
catch (IllegalArgumentException expected) {
}
}
@Test
public void testCtorWithWhitespacedScriptSourceLocator() throws Exception {
try {
new GroovyScriptFactory("\n ");
fail("Must have thrown exception by this point.");
}
catch (IllegalArgumentException expected) {
}
}
@Test
public void testWithInlineScriptWithLeadingWhitespace() throws Exception {
try {
new ClassPathXmlApplicationContext("lwspBadGroovyContext.xml", getClass());
fail("Must have thrown a BeanCreationException ('inline:' prefix was preceded by whitespace");
}
catch (BeanCreationException expected) {
assertTrue(expected.contains(FileNotFoundException.class));
}
}
@Test
public void testGetScriptedObjectDoesNotChokeOnNullInterfacesBeingPassedIn() throws Exception {
MockControl mock = MockControl.createControl(ScriptSource.class);
ScriptSource scriptSource = (ScriptSource) mock.getMock();
scriptSource.getScriptAsString();
mock.setReturnValue("class Bar {}");
scriptSource.suggestedClassName();
mock.setReturnValue("someName");
mock.replay();
GroovyScriptFactory factory = new GroovyScriptFactory("a script source locator (doesn't matter here)");
Object scriptedObject = factory.getScriptedObject(scriptSource, null);
assertNotNull(scriptedObject);
mock.verify();
}
@Test
public void testGetScriptedObjectDoesChokeOnNullScriptSourceBeingPassedIn() throws Exception {
GroovyScriptFactory factory = new GroovyScriptFactory("a script source locator (doesn't matter here)");
try {
factory.getScriptedObject(null, null);
fail("Must have thrown a NullPointerException as per contract ('null' ScriptSource supplied");
}
catch (NullPointerException expected) {
}
}
@Test
public void testResourceScriptFromTag() throws Exception {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("groovy-with-xsd.xml", getClass());
Messenger messenger = (Messenger) ctx.getBean("messenger");
CallCounter countingAspect = (CallCounter) ctx.getBean("getMessageAspect");
assertTrue(AopUtils.isAopProxy(messenger));
assertFalse(messenger instanceof Refreshable);
assertEquals(0, countingAspect.getCalls());
assertEquals("Hello World!", messenger.getMessage());
assertEquals(1, countingAspect.getCalls());
ctx.close();
assertEquals(-200, countingAspect.getCalls());
}
@Test
public void testPrototypeScriptFromTag() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("groovy-with-xsd.xml", getClass());
ConfigurableMessenger messenger = (ConfigurableMessenger) ctx.getBean("messengerPrototype");
ConfigurableMessenger messenger2 = (ConfigurableMessenger) ctx.getBean("messengerPrototype");
assertNotSame(messenger, messenger2);
assertSame(messenger.getClass(), messenger2.getClass());
assertEquals("Hello World!", messenger.getMessage());
assertEquals("Hello World!", messenger2.getMessage());
messenger.setMessage("Bye World!");
messenger2.setMessage("Byebye World!");
assertEquals("Bye World!", messenger.getMessage());
assertEquals("Byebye World!", messenger2.getMessage());
}
@Test
public void testInlineScriptFromTag() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("groovy-with-xsd.xml", getClass());
Calculator calculator = (Calculator) ctx.getBean("calculator");
assertNotNull(calculator);
assertFalse(calculator instanceof Refreshable);
}
@Test
public void testRefreshableFromTag() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("groovy-with-xsd.xml", getClass());
assertTrue(Arrays.asList(ctx.getBeanNamesForType(Messenger.class)).contains("refreshableMessenger"));
Messenger messenger = (Messenger) ctx.getBean("refreshableMessenger");
CallCounter countingAspect = (CallCounter) ctx.getBean("getMessageAspect");
assertTrue(AopUtils.isAopProxy(messenger));
assertTrue(messenger instanceof Refreshable);
assertEquals(0, countingAspect.getCalls());
assertEquals("Hello World!", messenger.getMessage());
assertEquals(1, countingAspect.getCalls());
assertTrue(ctx.getBeansOfType(Messenger.class).values().contains(messenger));
}
@Test
public void testAnonymousScriptDetected() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("groovy-with-xsd.xml", getClass());
Map beans = ctx.getBeansOfType(Messenger.class);
assertEquals(4, beans.size());
}
/**
* Tests the SPR-2098 bug whereby no more than 1 property element could be
* passed to a scripted bean :(
*/
@Test
public void testCanPassInMoreThanOneProperty() {
ApplicationContext ctx = new ClassPathXmlApplicationContext("groovy-multiple-properties.xml", getClass());
TestBean tb = (TestBean) ctx.getBean("testBean");
ContextScriptBean bean = (ContextScriptBean) ctx.getBean("bean");
assertEquals("The first property ain't bein' injected.", "Sophie Marceau", bean.getName());
assertEquals("The second property ain't bein' injected.", 31, bean.getAge());
assertEquals(tb, bean.getTestBean());
assertEquals(ctx, bean.getApplicationContext());
ContextScriptBean bean2 = (ContextScriptBean) ctx.getBean("bean2");
assertEquals(tb, bean2.getTestBean());
assertEquals(ctx, bean2.getApplicationContext());
try {
ctx.getBean("bean3");
fail("Should have thrown BeanCreationException");
}
catch (BeanCreationException ex) {
// expected
assertTrue(ex.contains(UnsatisfiedDependencyException.class));
}
}
@Test
public void testMetaClassWithBeans() {
testMetaClass("org/springframework/scripting/groovy/calculators.xml");
}
@Test
public void testMetaClassWithXsd() {
testMetaClass("org/springframework/scripting/groovy/calculators-with-xsd.xml");
}
private void testMetaClass(final String xmlFile) {
// expect the exception we threw in the custom metaclass to show it got invoked
try {
ApplicationContext ctx =
new ClassPathXmlApplicationContext(xmlFile);
Calculator calc = (Calculator) ctx.getBean("delegatingCalculator");
calc.add(1, 2);
fail("expected IllegalStateException");
} catch (IllegalStateException ex) {
assertEquals("Gotcha", ex.getMessage());
}
}
@Test
public void testFactoryBean() {
ApplicationContext context = new ClassPathXmlApplicationContext("groovyContext.xml", getClass());
Object factory = context.getBean("&factory");
assertTrue(factory instanceof FactoryBean);
Object result = context.getBean("factory");
assertTrue(result instanceof String);
assertEquals("test", result);
}
@Test
public void testRefreshableFactoryBean() {
ApplicationContext context = new ClassPathXmlApplicationContext("groovyContext.xml", getClass());
Object factory = context.getBean("&refreshableFactory");
assertTrue(factory instanceof FactoryBean);
Object result = context.getBean("refreshableFactory");
assertTrue(result instanceof String);
assertEquals("test", result);
}
public static class TestCustomizer implements GroovyObjectCustomizer {
public void customize(GroovyObject goo) {
DelegatingMetaClass dmc = new DelegatingMetaClass(goo.getMetaClass()) {
public Object invokeMethod(Object arg0, String mName, Object[] arg2) {
if (mName.indexOf("Missing") != -1) {
throw new IllegalStateException("Gotcha");
}
else {
return super.invokeMethod(arg0, mName, arg2);
}
}
};
dmc.initialize();
goo.setMetaClass(dmc);
}
}
}

View File

@@ -0,0 +1,8 @@
package org.springframework.scripting.groovy;
import org.springframework.scripting.ConfigurableMessenger
class GroovyMessenger implements ConfigurableMessenger {
def String message;
}

View File

@@ -0,0 +1,14 @@
package org.springframework.scripting.groovy;
import org.springframework.scripting.Messenger
class GroovyMessenger implements Messenger {
GroovyMessenger() {
println "GroovyMessenger"
}
def String message;
}
return new GroovyMessenger();

View File

@@ -0,0 +1,23 @@
import org.springframework.beans.TestBean
import org.springframework.context.ApplicationContext
import org.springframework.context.ApplicationContextAware
import org.springframework.scripting.ContextScriptBean
class GroovyScriptBean implements ContextScriptBean, ApplicationContextAware {
private int age
int getAge() {
return this.age
}
void setAge(int age) {
this.age = age
}
def String name
def TestBean testBean;
def ApplicationContext applicationContext
}

View File

@@ -0,0 +1,17 @@
import org.springframework.beans.factory.FactoryBean
class TestFactoryBean implements FactoryBean {
public boolean isSingleton() {
true
}
public Class getObjectType() {
String.class
}
public Object getObject() {
"test"
}
}

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:lang="http://www.springframework.org/schema/lang"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.0.xsd">
<lang:groovy id="calculator"
script-source="classpath:org/springframework/scripting/groovy/Calculator.groovy"
customizer-ref="testCustomizer" />
<bean id="testCustomizer" class="org.springframework.scripting.groovy.GroovyScriptFactoryTests$TestCustomizer"/>
<lang:groovy id="delegatingCalculator"
script-source="classpath:org/springframework/scripting/groovy/DelegatingCalculator.groovy">
<lang:property name="delegate" ref="calculator"/>
</lang:groovy>
</beans>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor"/>
<bean id="calculator" class="org.springframework.scripting.groovy.GroovyScriptFactory">
<constructor-arg value="classpath:org/springframework/scripting/groovy/Calculator.groovy"/>
<constructor-arg>
<bean class="org.springframework.scripting.groovy.GroovyScriptFactoryTests$TestCustomizer" />
</constructor-arg>
</bean>
<bean id="delegatingCalculator" class="org.springframework.scripting.groovy.GroovyScriptFactory">
<constructor-arg value="classpath:org/springframework/scripting/groovy/DelegatingCalculator.groovy"/>
<property name="delegate" ref="calculator"/>
</bean>
</beans>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:lang="http://www.springframework.org/schema/lang"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.5.xsd">
<lang:groovy id="bean" script-source="classpath:org/springframework/scripting/groovy/ScriptBean.groovy" autowire="byType" dependency-check="all">
<lang:property name="name" value="Sophie Marceau"/>
<lang:property name="age" value="31"/>
</lang:groovy>
<lang:groovy id="bean2" script-source="classpath:org/springframework/scripting/groovy/ScriptBean.groovy" autowire="byName">
<lang:property name="name" value="Sophie Marceau"/>
<lang:property name="age" value="31"/>
</lang:groovy>
<lang:groovy id="bean3" script-source="classpath:org/springframework/scripting/groovy/ScriptBean.groovy" dependency-check="objects" scope="prototype">
<lang:property name="name" value="Sophie Marceau"/>
<lang:property name="age" value="31"/>
</lang:groovy>
<bean id="testBean" class="org.springframework.beans.TestBean"/>
</beans>

View File

@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:lang="http://www.springframework.org/schema/lang"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.5.xsd">
<aop:config>
<aop:aspect ref="getMessageAspect">
<aop:before method="before" pointcut="execution(* org.springframework.scripting.Messenger.*(..))"/>
</aop:aspect>
</aop:config>
<lang:groovy id="getMessageAspect" script-source="classpath:org/springframework/scripting/groovy/CallCounter.groovy"
init-method="init" destroy-method="destroy"/>
<lang:groovy id="messenger" script-source="classpath:org/springframework/scripting/groovy/Messenger.groovy">
<lang:property name="message" value="Hello World!"/>
</lang:groovy>
<lang:groovy id="messengerPrototype" script-source="classpath:org/springframework/scripting/groovy/Messenger.groovy"
scope="prototype">
<lang:property name="message" value="Hello World!"/>
</lang:groovy>
<lang:groovy id="calculator" depends-on="messenger" customizer-ref="customizer">
<lang:inline-script>
package org.springframework.scripting.groovy;
import org.springframework.scripting.Calculator
class GroovyCalculator implements Calculator {
int add(int x, int y) {
return x + y;
}
}
</lang:inline-script>
</lang:groovy>
<lang:groovy id="customizer">
<lang:inline-script><![CDATA[
import org.springframework.scripting.groovy.GroovyObjectCustomizer;
public class TestCustomizer implements GroovyObjectCustomizer {
public void customize(GroovyObject o) {
println "customizing ${o}.."
}
}]]>
</lang:inline-script>
</lang:groovy>
<lang:groovy id="refreshableMessenger" refresh-check-delay="5000"
script-source="classpath:org/springframework/scripting/groovy/Messenger.groovy">
<lang:property name="message" value="Hello World!"/>
</lang:groovy>
<lang:groovy script-source="classpath:org/springframework/scripting/groovy/Messenger.groovy">
<lang:property name="message" value="Hello World!"/>
</lang:groovy>
</beans>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
"http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor"/>
<bean id="broken" class="org.springframework.scripting.groovy.GroovyScriptFactory">
<constructor-arg value="classpath:org/springframework/scripting/groovy/Broken.groovyb"/>
</bean>
</beans>

View File

@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:lang="http://www.springframework.org/schema/lang"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/lang
http://www.springframework.org/schema/lang/spring-lang.xsd"
default-lazy-init="true">
<bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor"/>
<bean id="calculator"
class="org.springframework.scripting.groovy.GroovyScriptFactory">
<constructor-arg>
<value>inline:
package org.springframework.scripting.groovy;
import org.springframework.scripting.Calculator
class GroovyCalculator implements Calculator {
int add(int x, int y) {
return x + y;
}
}
</value>
</constructor-arg>
</bean>
<bean id="messenger"
class="org.springframework.scripting.groovy.GroovyScriptFactory">
<constructor-arg value="classpath:org/springframework/scripting/groovy/Messenger.groovy"/>
<property name="message" value="Hello World!"/>
</bean>
<bean id="messengerPrototype"
class="org.springframework.scripting.groovy.GroovyScriptFactory"
scope="prototype">
<constructor-arg value="classpath:org/springframework/scripting/groovy/Messenger.groovy"/>
<property name="message" value="Hello World!"/>
</bean>
<bean id="messengerInstance"
class="org.springframework.scripting.groovy.GroovyScriptFactory">
<constructor-arg value="classpath:org/springframework/scripting/groovy/MessengerInstance.groovy"/>
<property name="message" ref="myMessage"/>
</bean>
<bean id="messengerInstanceInline"
class="org.springframework.scripting.groovy.GroovyScriptFactory">
<constructor-arg>
<value>inline:
package org.springframework.scripting.groovy;
import org.springframework.scripting.Messenger
class GroovyMessenger implements Messenger {
def String message;
}
return new GroovyMessenger();
</value>
</constructor-arg>
<property name="message" ref="myMessage"/>
</bean>
<bean id="myMessage" class="java.lang.String">
<constructor-arg value="Hello World!"/>
</bean>
<lang:groovy id="refreshableFactory" refresh-check-delay="5000"
script-source="org/springframework/scripting/groovy/TestFactoryBean.groovy"/>
<lang:groovy id="factory" script-source="classpath:org/springframework/scripting/groovy/TestFactoryBean.groovy"/>
</beans>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans default-lazy-init="true">
<bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor">
<property name="defaultRefreshCheckDelay" value="1"/>
</bean>
<bean id="calculator" class="org.springframework.scripting.groovy.GroovyScriptFactory">
<constructor-arg value="classpath:org/springframework/scripting/groovy/Calculator.groovy"/>
</bean>
<bean id="messenger" class="org.springframework.scripting.groovy.GroovyScriptFactory">
<constructor-arg value="classpath:org/springframework/scripting/groovy/Messenger.groovy"/>
<property name="message" value="Hello World!"/>
</bean>
<bean id="messengerPrototype" class="org.springframework.scripting.groovy.GroovyScriptFactory" scope="prototype">
<constructor-arg value="classpath:org/springframework/scripting/groovy/Messenger.groovy"/>
<property name="message" value="Hello World!"/>
</bean>
</beans>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor"/>
<bean id="messenger" class="org.springframework.scripting.groovy.GroovyScriptFactory">
<constructor-arg>
<!-- 'inline:' prefix is preceded by whitespace... -->
<value>
inline:
class Bingo {
@Property String message;
}
</value>
</constructor-arg>
<property name="message" value="Hello World!"/>
</bean>
</beans>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor"/>
<bean id="messenger" class="org.springframework.scripting.groovy.GroovyScriptFactory">
<constructor-arg>
<value>inline:
package org.springframework.scripting.groovy;
import org.springframework.scripting.Messenger;
class GroovyMessenger implements Messenger {
def String message;
}
class Bingo {
def String message;
}
</value>
</constructor-arg>
<property name="message" value="Hello World!"/>
</bean>
</beans>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor"/>
<bean id="messenger" class="org.springframework.scripting.groovy.GroovyScriptFactory">
<constructor-arg>
<value>inline:
package org.springframework.scripting.groovy;
import org.springframework.scripting.Messenger;
class Bingo {
@Property String message;
}
class GroovyMessenger implements Messenger {
@Property String message;
}
</value>
</constructor-arg>
<property name="message" value="Hello World!"/>
</bean>
</beans>

View File

@@ -0,0 +1,61 @@
/*
* Copyright 2002-2007 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.scripting.jruby;
import junit.framework.TestCase;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.CountingBeforeAdvice;
import org.springframework.aop.support.AopUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.scripting.Messenger;
/**
* @author Rob Harrop
*/
public class AdvisedJRubyScriptFactoryTests extends TestCase {
public void testAdviseWithProxyFactoryBean() throws Exception {
ApplicationContext context =
new ClassPathXmlApplicationContext("advisedByProxyFactoryBean.xml", getClass());
Messenger bean = (Messenger) context.getBean("messenger");
assertTrue("Bean is not a proxy", AopUtils.isAopProxy(bean));
assertTrue("Bean is not an Advised object", bean instanceof Advised);
CountingBeforeAdvice advice = (CountingBeforeAdvice) context.getBean("advice");
assertEquals(0, advice.getCalls());
bean.getMessage();
assertEquals(1, advice.getCalls());
}
public void testAdviseWithBeanNameAutoProxyCreator() throws Exception {
ApplicationContext context =
new ClassPathXmlApplicationContext("advisedByBeanNameAutoProxyCreator.xml", getClass());
Messenger bean = (Messenger) context.getBean("messenger");
assertTrue("Bean is not a proxy", AopUtils.isAopProxy(bean));
assertTrue("Bean is not an Advised object", bean instanceof Advised);
CountingBeforeAdvice advice = (CountingBeforeAdvice) context.getBean("advice");
assertEquals(0, advice.getCalls());
bean.getMessage();
assertEquals(1, advice.getCalls());
}
}

View File

@@ -0,0 +1,4 @@
In A Station Of The Metro
the apparition of these faces in the crowd
petals on a wet black bough

View File

@@ -0,0 +1,9 @@
require 'java'
class RubyCalculator
include org.springframework.scripting.Calculator
def add(x, y)
x + y
end
end

View File

@@ -0,0 +1,287 @@
/*
* Copyright 2002-2007 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.scripting.jruby;
import java.util.Map;
import junit.framework.TestCase;
import junit.framework.Assert;
import org.springframework.aop.support.AopUtils;
import org.springframework.aop.target.dynamic.Refreshable;
import org.springframework.beans.TestBean;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.scripting.Calculator;
import org.springframework.scripting.ConfigurableMessenger;
import org.springframework.scripting.Messenger;
import org.springframework.scripting.ScriptCompilationException;
import org.springframework.scripting.TestBeanAwareMessenger;
/**
* @author Rob Harrop
* @author Rick Evans
* @author Juergen Hoeller
*/
public class JRubyScriptFactoryTests extends TestCase {
private static final String RUBY_SCRIPT_SOURCE_LOCATOR =
"inline:require 'java'\n" +
"class RubyBar\n" +
"end\n" +
"RubyBar.new";
public void testStaticScript() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("jrubyContext.xml", getClass());
Calculator calc = (Calculator) ctx.getBean("calculator");
Messenger messenger = (Messenger) ctx.getBean("messenger");
assertFalse("Scripted object should not be instance of Refreshable", calc instanceof Refreshable);
assertFalse("Scripted object should not be instance of Refreshable", messenger instanceof Refreshable);
Assert.assertEquals(calc, calc);
Assert.assertEquals(messenger, messenger);
assertTrue(!messenger.equals(calc));
assertNotSame(messenger.hashCode(), calc.hashCode());
assertTrue(!messenger.toString().equals(calc.toString()));
String desiredMessage = "Hello World!";
Assert.assertEquals("Message is incorrect", desiredMessage, messenger.getMessage());
}
public void testNonStaticScript() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("jrubyRefreshableContext.xml", getClass());
Messenger messenger = (Messenger) ctx.getBean("messenger");
assertTrue("Should be a proxy for refreshable scripts", AopUtils.isAopProxy(messenger));
assertTrue("Should be an instance of Refreshable", messenger instanceof Refreshable);
String desiredMessage = "Hello World!";
Assert.assertEquals("Message is incorrect.", desiredMessage, messenger.getMessage());
Refreshable refreshable = (Refreshable) messenger;
refreshable.refresh();
Assert.assertEquals("Message is incorrect after refresh.", desiredMessage, messenger.getMessage());
assertEquals("Incorrect refresh count", 2, refreshable.getRefreshCount());
}
public void testScriptCompilationException() throws Exception {
try {
new ClassPathXmlApplicationContext("jrubyBrokenContext.xml", getClass());
fail("Should throw exception for broken script file");
}
catch (BeanCreationException ex) {
assertTrue(ex.contains(ScriptCompilationException.class));
}
}
public void testCtorWithNullScriptSourceLocator() throws Exception {
try {
new JRubyScriptFactory(null, new Class[]{Messenger.class});
fail("Must have thrown exception by this point.");
}
catch (IllegalArgumentException expected) {
}
}
public void testCtorWithEmptyScriptSourceLocator() throws Exception {
try {
new JRubyScriptFactory("", new Class[]{Messenger.class});
fail("Must have thrown exception by this point.");
}
catch (IllegalArgumentException expected) {
}
}
public void testCtorWithWhitespacedScriptSourceLocator() throws Exception {
try {
new JRubyScriptFactory("\n ", new Class[]{Messenger.class});
fail("Must have thrown exception by this point.");
}
catch (IllegalArgumentException expected) {
}
}
public void testCtorWithNullScriptInterfacesArray() throws Exception {
try {
new JRubyScriptFactory(RUBY_SCRIPT_SOURCE_LOCATOR, null);
fail("Must have thrown exception by this point.");
}
catch (IllegalArgumentException expected) {
}
}
public void testCtorWithEmptyScriptInterfacesArray() throws Exception {
try {
new JRubyScriptFactory(RUBY_SCRIPT_SOURCE_LOCATOR, new Class[]{});
fail("Must have thrown exception by this point.");
}
catch (IllegalArgumentException expected) {
}
}
public void testResourceScriptFromTag() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("jruby-with-xsd.xml", getClass());
TestBean testBean = (TestBean) ctx.getBean("testBean");
Messenger messenger = (Messenger) ctx.getBean("messenger");
Assert.assertEquals("Hello World!", messenger.getMessage());
assertFalse(messenger instanceof Refreshable);
TestBeanAwareMessenger messengerByType = (TestBeanAwareMessenger) ctx.getBean("messengerByType");
Assert.assertEquals(testBean, messengerByType.getTestBean());
TestBeanAwareMessenger messengerByName = (TestBeanAwareMessenger) ctx.getBean("messengerByName");
Assert.assertEquals(testBean, messengerByName.getTestBean());
}
public void testPrototypeScriptFromTag() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("jruby-with-xsd.xml", getClass());
ConfigurableMessenger messenger = (ConfigurableMessenger) ctx.getBean("messengerPrototype");
ConfigurableMessenger messenger2 = (ConfigurableMessenger) ctx.getBean("messengerPrototype");
assertNotSame(messenger, messenger2);
assertSame(messenger.getClass(), messenger2.getClass());
Assert.assertEquals("Hello World!", messenger.getMessage());
Assert.assertEquals("Hello World!", messenger2.getMessage());
messenger.setMessage("Bye World!");
messenger2.setMessage("Byebye World!");
Assert.assertEquals("Bye World!", messenger.getMessage());
Assert.assertEquals("Byebye World!", messenger2.getMessage());
}
public void testInlineScriptFromTag() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("jruby-with-xsd.xml", getClass());
Calculator calculator = (Calculator) ctx.getBean("calculator");
assertNotNull(calculator);
assertFalse(calculator instanceof Refreshable);
}
public void testRefreshableFromTag() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("jruby-with-xsd.xml", getClass());
Messenger messenger = (Messenger) ctx.getBean("refreshableMessenger");
Assert.assertEquals("Hello World!", messenger.getMessage());
assertTrue("Messenger should be Refreshable", messenger instanceof Refreshable);
}
public void testThatMultipleScriptInterfacesAreSupported() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("jruby-with-xsd.xml", getClass());
Messenger messenger = (Messenger) ctx.getBean("calculatingMessenger");
Assert.assertEquals("Hello World!", messenger.getMessage());
// cool, now check that the Calculator interface is also exposed
Calculator calc = (Calculator) messenger;
Assert.assertEquals(0, calc.add(2, -2));
}
public void testWithComplexArg() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("jrubyContext.xml", getClass());
Printer printer = (Printer) ctx.getBean("printer");
CountingPrintable printable = new CountingPrintable();
printer.print(printable);
assertEquals(1, printable.count);
}
public void testWithPrimitiveArgsInReturnTypeAndParameters() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("jrubyContextForPrimitives.xml", getClass());
PrimitiveAdder adder = (PrimitiveAdder) ctx.getBean("adder");
assertEquals(2, adder.addInts(1, 1));
assertEquals(4, adder.addShorts((short) 1, (short) 3));
assertEquals(5, adder.addLongs(2L, 3L));
assertEquals(5, new Float(adder.addFloats(2.0F, 3.1F)).intValue());
assertEquals(5, new Double(adder.addDoubles(2.0, 3.1)).intValue());
assertFalse(adder.resultIsPositive(-200, 1));
assertEquals("ri", adder.concatenate('r', 'i'));
assertEquals('c', adder.echo('c'));
}
public void testWithWrapperArgsInReturnTypeAndParameters() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("jrubyContextForWrappers.xml", getClass());
WrapperAdder adder = (WrapperAdder) ctx.getBean("adder");
assertEquals(new Integer(2), adder.addInts(new Integer(1), new Integer(1)));
assertEquals(Integer.class, adder.addInts(new Integer(1), new Integer(1)).getClass());
assertEquals(new Short((short) 4), adder.addShorts(new Short((short) 1), new Short((short) 3)));
assertEquals(Short.class, adder.addShorts(new Short((short) 1), new Short((short) 3)).getClass());
assertEquals(new Long(5L), adder.addLongs(new Long(2L), new Long(3L)));
assertEquals(Long.class, adder.addLongs(new Long(2L), new Long(3L)).getClass());
assertEquals(5, adder.addFloats(new Float(2.0F), new Float(3.1F)).intValue());
assertEquals(Float.class, adder.addFloats(new Float(2.0F), new Float(3.1F)).getClass());
assertEquals(5, new Double(adder.addDoubles(new Double(2.0), new Double(3.1)).intValue()).intValue());
assertEquals(Double.class, adder.addDoubles(new Double(2.0), new Double(3.1)).getClass());
assertFalse(adder.resultIsPositive(new Integer(-200), new Integer(1)).booleanValue());
assertEquals(Boolean.class, adder.resultIsPositive(new Integer(-200), new Integer(1)).getClass());
assertEquals("ri", adder.concatenate(new Character('r'), new Character('i')));
assertEquals(String.class, adder.concatenate(new Character('r'), new Character('i')).getClass());
assertEquals(new Character('c'), adder.echo(new Character('c')));
assertEquals(Character.class, adder.echo(new Character('c')).getClass());
Integer[] numbers = new Integer[]{new Integer(1), new Integer(2), new Integer(3), new Integer(4), new Integer(5)};
assertEquals("12345", adder.concatArrayOfIntegerWrappers(numbers));
assertEquals(String.class, adder.concatArrayOfIntegerWrappers(numbers).getClass());
Short[] shorts = adder.populate(new Short((short) 1), new Short((short) 2));
assertEquals(2, shorts.length);
assertNotNull(shorts[0]);
assertEquals(new Short((short) 1), shorts[0]);
assertNotNull(shorts[1]);
assertEquals(new Short((short) 2), shorts[1]);
String[][] lol = adder.createListOfLists("1", "2", "3");
assertNotNull(lol);
assertEquals(3, lol.length);
assertEquals("1", lol[0][0]);
assertEquals("2", lol[1][0]);
assertEquals("3", lol[2][0]);
Map singleValueMap = adder.toMap("key", "value");
assertNotNull(singleValueMap);
assertEquals(1, singleValueMap.size());
assertEquals("key", singleValueMap.keySet().iterator().next());
assertEquals("value", singleValueMap.values().iterator().next());
String[] expectedStrings = new String[]{"1", "2", "3"};
Map map = adder.toMap("key", expectedStrings);
assertNotNull(map);
assertEquals(1, map.size());
assertEquals("key", map.keySet().iterator().next());
String[] strings = (String[]) map.values().iterator().next();
for (int i = 0; i < expectedStrings.length; ++i) {
assertEquals(expectedStrings[i], strings[i]);
}
}
public void testAOP() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("jruby-aop.xml", getClass());
Messenger messenger = (Messenger) ctx.getBean("messenger");
Assert.assertEquals(new StringBuffer("Hello World!").reverse().toString(), messenger.getMessage());
}
private static final class CountingPrintable implements Printable {
public int count;
public String getContent() {
this.count++;
return "Hello World!";
}
}
}

View File

@@ -0,0 +1,21 @@
require 'java'
class RubyMessenger
include org.springframework.scripting.Messenger
def setMessage(message)
@@message = message
end
def getMessage
@@message
end
def setTestBean(testBean)
@@testBean = testBean
end
def getTestBean
@@testBean
end
end

View File

@@ -0,0 +1,25 @@
package org.springframework.scripting.jruby;
/**
* http://opensource.atlassian.com/projects/spring/browse/SPR-3026
*
* @author Rick Evans
*/
public interface PrimitiveAdder {
int addInts(int x, int y);
short addShorts(short x, short y);
long addLongs(long x, long y);
float addFloats(float x, float y);
double addDoubles(double x, double y);
boolean resultIsPositive(int x, int y);
String concatenate(char c, char d);
char echo(char c);
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright 2002-2006 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.scripting.jruby;
/**
* @author Rob Harrop
* @since 2.0.2
*/
public interface Printable {
String getContent();
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright 2002-2006 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.scripting.jruby;
/**
* @author Rob Harrop
* @since 2.0.2
*/
public interface Printer {
void print(Printable arg);
}

View File

@@ -0,0 +1,9 @@
require 'java'
class RubyPrinter
include org.springframework.scripting.jruby.Printer
def print(obj)
puts obj.getContent
end
end

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2002-2007 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.scripting.jruby;
import java.util.Map;
/**
* http://opensource.atlassian.com/projects/spring/browse/SPR-3038
*
* @author Rick Evans
*/
public interface WrapperAdder {
Integer addInts(Integer x, Integer y);
Short addShorts(Short x, Short y);
Long addLongs(Long x, Long y);
Float addFloats(Float x, Float y);
Double addDoubles(Double x, Double y);
Boolean resultIsPositive(Integer x, Integer y);
String concatenate(Character c, Character d);
Character echo(Character c);
String concatArrayOfIntegerWrappers(Integer[] numbers);
Short[] populate(Short one, Short two);
String[][] createListOfLists(String one, String second, String third);
Map toMap(String key, Object value);
}

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor"/>
<bean id="apc" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames" value="messenger"/>
<property name="interceptorNames" value="advice"/>
</bean>
<bean id="messenger" class="org.springframework.scripting.jruby.JRubyScriptFactory">
<constructor-arg value="classpath:org/springframework/scripting/jruby/Messenger.rb"/>
<constructor-arg value="org.springframework.scripting.Messenger"/>
<property name="message" value="Hello World!"/>
</bean>
<bean id="advice" class="org.springframework.aop.framework.CountingBeforeAdvice"/>
</beans>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor"/>
<bean id="messengerTarget" class="org.springframework.scripting.jruby.JRubyScriptFactory">
<constructor-arg value="classpath:org/springframework/scripting/jruby/Messenger.rb"/>
<constructor-arg value="org.springframework.scripting.Messenger"/>
<property name="message" value="Hello World!"/>
</bean>
<bean id="messenger" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="messengerTarget"/>
<property name="interceptorNames" value="advice"/>
</bean>
<bean id="advice" class="org.springframework.aop.framework.CountingBeforeAdvice"/>
</beans>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:lang="http://www.springframework.org/schema/lang"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<lang:jruby id="messenger"
script-interfaces="org.springframework.scripting.Messenger"
script-source="classpath:org/springframework/scripting/jruby/Messenger.rb">
<lang:property name="message" value="Hello World!"/>
</lang:jruby>
<aop:config>
<aop:pointcut id="messengerOps"
expression="execution(String org.springframework.scripting.Messenger.*())"/>
<aop:aspect id="scramblerAspect" ref="scrambler">
<aop:around pointcut-ref="messengerOps"
method="scramble"/>
</aop:aspect>
</aop:config>
<bean id="scrambler" class="org.springframework.scripting.MessengerScrambler"/>
</beans>

View File

@@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:lang="http://www.springframework.org/schema/lang"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.5.xsd">
<lang:jruby id="messenger"
script-source="classpath:org/springframework/scripting/jruby/Messenger.rb"
script-interfaces="org.springframework.scripting.Messenger">
<lang:property name="message" value="Hello World!"/>
</lang:jruby>
<lang:jruby id="messengerPrototype"
script-source="classpath:org/springframework/scripting/jruby/Messenger.rb"
script-interfaces="org.springframework.scripting.ConfigurableMessenger" scope="prototype">
<lang:property name="message" value="Hello World!"/>
</lang:jruby>
<lang:jruby id="messengerByType"
script-source="classpath:org/springframework/scripting/jruby/Messenger.rb"
script-interfaces="org.springframework.scripting.TestBeanAwareMessenger" scope="prototype"
autowire="byType" dependency-check="objects">
</lang:jruby>
<lang:jruby id="messengerByName"
script-source="classpath:org/springframework/scripting/jruby/Messenger.rb"
script-interfaces="org.springframework.scripting.TestBeanAwareMessenger" scope="prototype"
autowire="byName">
</lang:jruby>
<bean id="testBean" class="org.springframework.beans.TestBean"/>
<lang:jruby id="calculator"
script-interfaces="org.springframework.scripting.Calculator">
<lang:inline-script>
require 'java'
class RubyCalculator
include org.springframework.scripting.Calculator
def add(x, y)
x + y
end
end
</lang:inline-script>
</lang:jruby>
<lang:jruby id="refreshableMessenger"
script-source="classpath:org/springframework/scripting/jruby/Messenger.rb"
script-interfaces="org.springframework.scripting.Messenger"
refresh-check-delay="5000">
<lang:property name="message" value="Hello World!"/>
</lang:jruby>
<!-- just checking that multiple script interfaces are supported -->
<lang:jruby id="calculatingMessenger"
script-interfaces="org.springframework.scripting.Calculator, org.springframework.scripting.Messenger">
<lang:inline-script><![CDATA[require 'java'
class RubyCalculatingMessenger
def add(x, y)
x + y
end
def setMessage(message)
@@message = message
end
def getMessage
@@message
end
end
]]></lang:inline-script>
<lang:property name="message" value="Hello World!"/>
</lang:jruby>
</beans>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
"http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor"/>
<bean id="broken" class="org.springframework.scripting.jruby.JRubyScriptFactory">
<constructor-arg value="classpath:org/springframework/scripting/jruby/Broken.rb"/>
<constructor-arg value="org.springframework.scripting.Messenger"/>
</bean>
</beans>

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor"/>
<bean id="calculator" class="org.springframework.scripting.jruby.JRubyScriptFactory">
<constructor-arg>
<value>inline:
require 'java'
class RubyCalculator
include org.springframework.scripting.Calculator
def add(x, y)
x + y
end
end
</value>
</constructor-arg>
<constructor-arg value="org.springframework.scripting.Calculator"/>
</bean>
<bean id="messenger" class="org.springframework.scripting.jruby.JRubyScriptFactory">
<constructor-arg value="classpath:org/springframework/scripting/jruby/Messenger.rb"/>
<constructor-arg value="org.springframework.scripting.Messenger"/>
<property name="message" value="Hello World!"/>
</bean>
<bean id="printer" class="org.springframework.scripting.jruby.JRubyScriptFactory">
<constructor-arg value="classpath:org/springframework/scripting/jruby/Printer.rb"/>
<constructor-arg value="org.springframework.scripting.jruby.Printer"/>
</bean>
</beans>

View File

@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor"/>
<bean id="adder" class="org.springframework.scripting.jruby.JRubyScriptFactory">
<constructor-arg>
<value><![CDATA[inline:
require 'java'
class RubyPrimitiveAdder
include org.springframework.scripting.jruby.PrimitiveAdder
def addInts(x, y)
x + y
end
def addShorts(x, y)
x + y
end
def addLongs(x, y)
x + y
end
def addFloats(x, y)
x + y
end
def addDoubles(x, y)
x + y
end
def resultIsPositive(x, y)
(x + y) > 0
end
def concatenate(c, d)
return ("" << c) << d;
end
def echo(c)
c
end
end
]]></value>
</constructor-arg>
<constructor-arg value="org.springframework.scripting.jruby.PrimitiveAdder"/>
</bean>
</beans>

View File

@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor"/>
<bean id="adder" class="org.springframework.scripting.jruby.JRubyScriptFactory">
<constructor-arg>
<value><![CDATA[inline:
require 'java'
class RubyWrapperAdder
include org.springframework.scripting.jruby.WrapperAdder
def addInts(x, y)
x + y
end
def addShorts(x, y)
x + y
end
def addLongs(x, y)
x + y
end
def addFloats(x, y)
x + y
end
def addDoubles(x, y)
x + y
end
def resultIsPositive(x, y)
(x + y) > 0
end
def concatenate(c, d)
return ("" << c) << d;
end
def echo(c)
c
end
def concatArrayOfIntegerWrappers(numbers)
buffer = ""
numbers.each do |number|
buffer << number.to_s
end
return buffer
end
def populate(x, y)
[x, y]
end
def createListOfLists(x, y, z)
[[x], [y], [z]]
end
def toMap(key, value)
{key => value}
end
end
]]></value>
</constructor-arg>
<constructor-arg value="org.springframework.scripting.jruby.WrapperAdder"/>
</bean>
</beans>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor">
<property name="defaultRefreshCheckDelay" value="1"/>
</bean>
<bean id="calculator" class="org.springframework.scripting.jruby.JRubyScriptFactory">
<constructor-arg value="classpath:org/springframework/scripting/jruby/Calculator.rb"/>
<constructor-arg value="org.springframework.scripting.Calculator"/>
</bean>
<bean id="messenger" class="org.springframework.scripting.jruby.JRubyScriptFactory">
<constructor-arg value="classpath:org/springframework/scripting/jruby/Messenger.rb"/>
<constructor-arg value="org.springframework.scripting.Messenger"/>
<property name="message" value="Hello World!"/>
</bean>
</beans>

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2002-2008 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.scripting.support;
import junit.framework.TestCase;
import org.easymock.MockControl;
import org.springframework.beans.factory.BeanFactory;
/**
* @author Rick Evans
*/
public class RefreshableScriptTargetSourceTests extends TestCase {
public void testCreateWithNullScriptSource() throws Exception {
MockControl mockFactory = MockControl.createNiceControl(BeanFactory.class);
mockFactory.replay();
try {
new RefreshableScriptTargetSource((BeanFactory) mockFactory.getMock(), "a.bean", null, null, false);
fail("Must have failed when passed a null ScriptSource.");
}
catch (IllegalArgumentException expected) {
}
mockFactory.verify();
}
}

View File

@@ -0,0 +1,102 @@
/*
* Copyright 2002-2008 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.scripting.support;
import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import junit.framework.TestCase;
import org.easymock.MockControl;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
/**
* @author Rick Evans
* @author Juergen Hoeller
*/
public class ResourceScriptSourceTests extends TestCase {
public void testCtorWithNullResource() throws Exception {
try {
new ResourceScriptSource(null);
fail("Must have thrown exception by this point.");
}
catch (IllegalArgumentException expected) {
}
}
public void testDoesNotPropagateFatalExceptionOnResourceThatCannotBeResolvedToAFile() throws Exception {
MockControl mock = MockControl.createControl(Resource.class);
Resource resource = (Resource) mock.getMock();
resource.lastModified();
mock.setThrowable(new IOException());
mock.replay();
ResourceScriptSource scriptSource = new ResourceScriptSource(resource);
long lastModified = scriptSource.retrieveLastModifiedTime();
assertEquals(0, lastModified);
mock.verify();
}
public void testBeginsInModifiedState() throws Exception {
MockControl mock = MockControl.createControl(Resource.class);
Resource resource = (Resource) mock.getMock();
mock.replay();
ResourceScriptSource scriptSource = new ResourceScriptSource(resource);
assertTrue(scriptSource.isModified());
mock.verify();
}
public void testLastModifiedWorksWithResourceThatDoesNotSupportFileBasedReading() throws Exception {
MockControl mock = MockControl.createControl(Resource.class);
Resource resource = (Resource) mock.getMock();
// underlying File is asked for so that the last modified time can be checked...
resource.lastModified();
mock.setReturnValue(100, 2);
// does not support File-based reading; delegates to InputStream-style reading...
resource.getFile();
mock.setThrowable(new FileNotFoundException());
resource.getInputStream();
mock.setReturnValue(new ByteArrayInputStream(new byte[0]));
// And then mock the file changing; i.e. the File says it has been modified
resource.lastModified();
mock.setReturnValue(200);
mock.replay();
ResourceScriptSource scriptSource = new ResourceScriptSource(resource);
assertTrue("ResourceScriptSource must start off in the 'isModified' state (it obviously isn't).", scriptSource.isModified());
scriptSource.getScriptAsString();
assertFalse("ResourceScriptSource must not report back as being modified if the underlying File resource is not reporting a changed lastModified time.", scriptSource.isModified());
// Must now report back as having been modified
assertTrue("ResourceScriptSource must report back as being modified if the underlying File resource is reporting a changed lastModified time.", scriptSource.isModified());
mock.verify();
}
public void testLastModifiedWorksWithResourceThatDoesNotSupportFileBasedAccessAtAll() throws Exception {
Resource resource = new ByteArrayResource(new byte[0]);
ResourceScriptSource scriptSource = new ResourceScriptSource(resource);
assertTrue("ResourceScriptSource must start off in the 'isModified' state (it obviously isn't).", scriptSource.isModified());
scriptSource.getScriptAsString();
assertFalse("ResourceScriptSource must not report back as being modified if the underlying File resource is not reporting a changed lastModified time.", scriptSource.isModified());
// Must now continue to report back as not having been modified 'cos the Resource does not support access as a File (and so the lastModified date cannot be determined).
assertFalse("ResourceScriptSource must not report back as being modified if the underlying File resource is not reporting a changed lastModified time.", scriptSource.isModified());
}
}

View File

@@ -0,0 +1,277 @@
/*
* Copyright 2002-2008 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.scripting.support;
import junit.framework.TestCase;
import org.easymock.MockControl;
import org.springframework.beans.FatalBeanException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.scripting.Messenger;
import org.springframework.scripting.ScriptCompilationException;
import org.springframework.scripting.groovy.GroovyScriptFactory;
/**
* @author Rick Evans
* @author Juergen Hoeller
*/
public class ScriptFactoryPostProcessorTests extends TestCase {
private static final String MESSAGE_TEXT = "Bingo";
private static final String MESSENGER_BEAN_NAME = "messenger";
private static final String PROCESSOR_BEAN_NAME = "processor";
private static final String CHANGED_SCRIPT = "package org.springframework.scripting.groovy\n" +
"import org.springframework.scripting.Messenger\n" +
"class GroovyMessenger implements Messenger {\n" +
" private String message = \"Bingo\"\n" +
" public String getMessage() {\n" +
// quote the returned message (this is the change)...
" return \"'\" + this.message + \"'\"\n" +
" }\n" +
" public void setMessage(String message) {\n" +
" this.message = message\n" +
" }\n" +
"}";
private static final String EXPECTED_CHANGED_MESSAGE_TEXT = "'" + MESSAGE_TEXT + "'";
private static final int DEFAULT_SECONDS_TO_PAUSE = 1;
private static final String DELEGATING_SCRIPT = "inline:package org.springframework.scripting;\n" +
"class DelegatingMessenger implements Messenger {\n" +
" private Messenger wrappedMessenger;\n" +
" public String getMessage() {\n" +
" return this.wrappedMessenger.getMessage()\n" +
" }\n" +
" public void setMessenger(Messenger wrappedMessenger) {\n" +
" this.wrappedMessenger = wrappedMessenger\n" +
" }\n" +
"}";
public void testDoesNothingWhenPostProcessingNonScriptFactoryTypeBeforeInstantiation() throws Exception {
assertNull(new ScriptFactoryPostProcessor().postProcessBeforeInstantiation(getClass(), "a.bean"));
}
public void testThrowsExceptionIfGivenNonAbstractBeanFactoryImplementation() throws Exception {
MockControl mock = MockControl.createControl(BeanFactory.class);
mock.replay();
try {
new ScriptFactoryPostProcessor().setBeanFactory((BeanFactory) mock.getMock());
fail("Must have thrown exception by this point.");
}
catch (IllegalStateException expected) {
}
mock.verify();
}
public void testChangeScriptWithRefreshableBeanFunctionality() throws Exception {
BeanDefinition processorBeanDefinition = createScriptFactoryPostProcessor(true);
BeanDefinition scriptedBeanDefinition = createScriptedGroovyBean();
GenericApplicationContext ctx = new GenericApplicationContext();
ctx.registerBeanDefinition(PROCESSOR_BEAN_NAME, processorBeanDefinition);
ctx.registerBeanDefinition(MESSENGER_BEAN_NAME, scriptedBeanDefinition);
ctx.refresh();
Messenger messenger = (Messenger) ctx.getBean(MESSENGER_BEAN_NAME);
assertEquals(MESSAGE_TEXT, messenger.getMessage());
// cool; now let's change the script and check the refresh behaviour...
pauseToLetRefreshDelayKickIn(DEFAULT_SECONDS_TO_PAUSE);
StaticScriptSource source = getScriptSource(ctx);
source.setScript(CHANGED_SCRIPT);
Messenger refreshedMessenger = (Messenger) ctx.getBean(MESSENGER_BEAN_NAME);
// the updated script surrounds the message in quotes before returning...
assertEquals(EXPECTED_CHANGED_MESSAGE_TEXT, refreshedMessenger.getMessage());
}
public void testChangeScriptWithNoRefreshableBeanFunctionality() throws Exception {
BeanDefinition processorBeanDefinition = createScriptFactoryPostProcessor(false);
BeanDefinition scriptedBeanDefinition = createScriptedGroovyBean();
GenericApplicationContext ctx = new GenericApplicationContext();
ctx.registerBeanDefinition(PROCESSOR_BEAN_NAME, processorBeanDefinition);
ctx.registerBeanDefinition(MESSENGER_BEAN_NAME, scriptedBeanDefinition);
ctx.refresh();
Messenger messenger = (Messenger) ctx.getBean(MESSENGER_BEAN_NAME);
assertEquals(MESSAGE_TEXT, messenger.getMessage());
// cool; now let's change the script and check the refresh behaviour...
pauseToLetRefreshDelayKickIn(DEFAULT_SECONDS_TO_PAUSE);
StaticScriptSource source = getScriptSource(ctx);
source.setScript(CHANGED_SCRIPT);
Messenger refreshedMessenger = (Messenger) ctx.getBean(MESSENGER_BEAN_NAME);
assertEquals("Script seems to have been refreshed (must not be as no refreshCheckDelay set on ScriptFactoryPostProcessor)",
MESSAGE_TEXT, refreshedMessenger.getMessage());
}
public void testRefreshedScriptReferencePropagatesToCollaborators() throws Exception {
BeanDefinition processorBeanDefinition = createScriptFactoryPostProcessor(true);
BeanDefinition scriptedBeanDefinition = createScriptedGroovyBean();
BeanDefinitionBuilder collaboratorBuilder = BeanDefinitionBuilder.rootBeanDefinition(DefaultMessengerService.class);
collaboratorBuilder.addPropertyReference(MESSENGER_BEAN_NAME, MESSENGER_BEAN_NAME);
GenericApplicationContext ctx = new GenericApplicationContext();
ctx.registerBeanDefinition(PROCESSOR_BEAN_NAME, processorBeanDefinition);
ctx.registerBeanDefinition(MESSENGER_BEAN_NAME, scriptedBeanDefinition);
final String collaboratorBeanName = "collaborator";
ctx.registerBeanDefinition(collaboratorBeanName, collaboratorBuilder.getBeanDefinition());
ctx.refresh();
Messenger messenger = (Messenger) ctx.getBean(MESSENGER_BEAN_NAME);
assertEquals(MESSAGE_TEXT, messenger.getMessage());
// cool; now let's change the script and check the refresh behaviour...
pauseToLetRefreshDelayKickIn(DEFAULT_SECONDS_TO_PAUSE);
StaticScriptSource source = getScriptSource(ctx);
source.setScript(CHANGED_SCRIPT);
Messenger refreshedMessenger = (Messenger) ctx.getBean(MESSENGER_BEAN_NAME);
// the updated script surrounds the message in quotes before returning...
assertEquals(EXPECTED_CHANGED_MESSAGE_TEXT, refreshedMessenger.getMessage());
// ok, is this change reflected in the reference that the collaborator has?
DefaultMessengerService collaborator = (DefaultMessengerService) ctx.getBean(collaboratorBeanName);
assertEquals(EXPECTED_CHANGED_MESSAGE_TEXT, collaborator.getMessage());
}
public void testReferencesAcrossAContainerHierarchy() throws Exception {
GenericApplicationContext businessContext = new GenericApplicationContext();
businessContext.registerBeanDefinition("messenger", BeanDefinitionBuilder.rootBeanDefinition(StubMessenger.class).getBeanDefinition());
businessContext.refresh();
BeanDefinitionBuilder scriptedBeanBuilder = BeanDefinitionBuilder.rootBeanDefinition(GroovyScriptFactory.class);
scriptedBeanBuilder.addConstructorArgValue(DELEGATING_SCRIPT);
scriptedBeanBuilder.addPropertyReference("messenger", "messenger");
GenericApplicationContext presentationCtx = new GenericApplicationContext(businessContext);
presentationCtx.registerBeanDefinition("needsMessenger", scriptedBeanBuilder.getBeanDefinition());
presentationCtx.registerBeanDefinition("scriptProcessor", createScriptFactoryPostProcessor(true));
presentationCtx.refresh();
}
public void testScriptHavingAReferenceToAnotherBean() throws Exception {
// just tests that the (singleton) script-backed bean is able to be instantiated with references to its collaborators
new ClassPathXmlApplicationContext("org/springframework/scripting/support/groovyReferences.xml");
}
public void testForRefreshedScriptHavingErrorPickedUpOnFirstCall() throws Exception {
BeanDefinition processorBeanDefinition = createScriptFactoryPostProcessor(true);
BeanDefinition scriptedBeanDefinition = createScriptedGroovyBean();
BeanDefinitionBuilder collaboratorBuilder = BeanDefinitionBuilder.rootBeanDefinition(DefaultMessengerService.class);
collaboratorBuilder.addPropertyReference(MESSENGER_BEAN_NAME, MESSENGER_BEAN_NAME);
GenericApplicationContext ctx = new GenericApplicationContext();
ctx.registerBeanDefinition(PROCESSOR_BEAN_NAME, processorBeanDefinition);
ctx.registerBeanDefinition(MESSENGER_BEAN_NAME, scriptedBeanDefinition);
final String collaboratorBeanName = "collaborator";
ctx.registerBeanDefinition(collaboratorBeanName, collaboratorBuilder.getBeanDefinition());
ctx.refresh();
Messenger messenger = (Messenger) ctx.getBean(MESSENGER_BEAN_NAME);
assertEquals(MESSAGE_TEXT, messenger.getMessage());
// cool; now let's change the script and check the refresh behaviour...
pauseToLetRefreshDelayKickIn(DEFAULT_SECONDS_TO_PAUSE);
StaticScriptSource source = getScriptSource(ctx);
// needs The Sundays compiler; must NOT throw any exception here...
source.setScript("I keep hoping you are the same as me, and I'll send you letters and come to your house for tea");
Messenger refreshedMessenger = (Messenger) ctx.getBean(MESSENGER_BEAN_NAME);
try {
refreshedMessenger.getMessage();
fail("Must have thrown an Exception (invalid script)");
}
catch (FatalBeanException expected) {
assertTrue(expected.contains(ScriptCompilationException.class));
}
}
public void testPrototypeScriptedBean() throws Exception {
GenericApplicationContext ctx = new GenericApplicationContext();
ctx.registerBeanDefinition("messenger", BeanDefinitionBuilder.rootBeanDefinition(StubMessenger.class).getBeanDefinition());
BeanDefinitionBuilder scriptedBeanBuilder = BeanDefinitionBuilder.rootBeanDefinition(GroovyScriptFactory.class);
scriptedBeanBuilder.setSingleton(false);
scriptedBeanBuilder.addConstructorArgValue(DELEGATING_SCRIPT);
scriptedBeanBuilder.addPropertyReference("messenger", "messenger");
final String BEAN_WITH_DEPENDENCY_NAME = "needsMessenger";
ctx.registerBeanDefinition(BEAN_WITH_DEPENDENCY_NAME, scriptedBeanBuilder.getBeanDefinition());
ctx.registerBeanDefinition("scriptProcessor", createScriptFactoryPostProcessor(true));
ctx.refresh();
Messenger messenger1 = (Messenger) ctx.getBean(BEAN_WITH_DEPENDENCY_NAME);
Messenger messenger2 = (Messenger) ctx.getBean(BEAN_WITH_DEPENDENCY_NAME);
assertNotSame(messenger1, messenger2);
}
private static StaticScriptSource getScriptSource(GenericApplicationContext ctx) throws Exception {
ScriptFactoryPostProcessor processor = (ScriptFactoryPostProcessor) ctx.getBean(PROCESSOR_BEAN_NAME);
BeanDefinition bd = processor.scriptBeanFactory.getBeanDefinition("scriptedObject.messenger");
return (StaticScriptSource) bd.getConstructorArgumentValues().getIndexedArgumentValue(0, StaticScriptSource.class).getValue();
}
private static BeanDefinition createScriptFactoryPostProcessor(boolean isRefreshable) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(ScriptFactoryPostProcessor.class);
if (isRefreshable) {
builder.addPropertyValue("defaultRefreshCheckDelay", new Long(1));
}
return builder.getBeanDefinition();
}
private static BeanDefinition createScriptedGroovyBean() {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(GroovyScriptFactory.class);
builder.addConstructorArgValue("inline:package org.springframework.scripting;\n" +
"class GroovyMessenger implements Messenger {\n" +
" private String message = \"Bingo\"\n" +
" public String getMessage() {\n" +
" return this.message\n" +
" }\n" +
" public void setMessage(String message) {\n" +
" this.message = message\n" +
" }\n" +
"}");
builder.addPropertyValue("message", MESSAGE_TEXT);
return builder.getBeanDefinition();
}
private static void pauseToLetRefreshDelayKickIn(int secondsToPause) {
try {
Thread.sleep(secondsToPause * 1000);
}
catch (InterruptedException ignored) {
}
}
public static class DefaultMessengerService {
private Messenger messenger;
public void setMessenger(Messenger messenger) {
this.messenger = messenger;
}
public String getMessage() {
return this.messenger.getMessage();
}
}
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright 2002-2006 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.scripting.support;
import junit.framework.TestCase;
/**
* Unit tests for the StaticScriptSource class.
*
* @author Rick Evans
*/
public final class StaticScriptSourceTests extends TestCase {
private static final String SCRIPT_TEXT = "print($hello) if $true;";
public void testCreateWithNullScript() throws Exception {
try {
new StaticScriptSource(null);
fail("Must have failed when passed a null script string.");
}
catch (IllegalArgumentException expected) {
}
}
public void testCreateWithEmptyScript() throws Exception {
try {
new StaticScriptSource("");
fail("Must have failed when passed an empty script string.");
}
catch (IllegalArgumentException expected) {
}
}
public void testCreateWithWhitespaceOnlyScript() throws Exception {
try {
new StaticScriptSource(" \n\n\t \t\n");
fail("Must have failed when passed a whitespace-only script string.");
}
catch (IllegalArgumentException expected) {
}
}
public void testIsModifiedIsTrueByDefault() throws Exception {
StaticScriptSource source = new StaticScriptSource(SCRIPT_TEXT);
assertTrue("Script must be flagged as 'modified' when first created.", source.isModified());
}
public void testGettingScriptTogglesIsModified() throws Exception {
StaticScriptSource source = new StaticScriptSource(SCRIPT_TEXT);
source.getScriptAsString();
assertFalse("Script must be flagged as 'not modified' after script is read.", source.isModified());
}
public void testGettingScriptViaToStringDoesNotToggleIsModified() throws Exception {
StaticScriptSource source = new StaticScriptSource(SCRIPT_TEXT);
boolean isModifiedState = source.isModified();
source.toString();
assertEquals("Script's 'modified' flag must not change after script is read via toString().", isModifiedState, source.isModified());
}
public void testIsModifiedToggledWhenDifferentScriptIsSet() throws Exception {
StaticScriptSource source = new StaticScriptSource(SCRIPT_TEXT);
source.setScript("use warnings;");
assertTrue("Script must be flagged as 'modified' when different script is passed in.", source.isModified());
}
public void testIsModifiedNotToggledWhenSameScriptIsSet() throws Exception {
StaticScriptSource source = new StaticScriptSource(SCRIPT_TEXT);
source.setScript(SCRIPT_TEXT);
assertFalse("Script must not be flagged as 'modified' when same script is passed in.", source.isModified());
}
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2002-2006 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.scripting.support;
import org.springframework.scripting.ConfigurableMessenger;
/**
* @author Rick Evans
*/
public final class StubMessenger implements ConfigurableMessenger {
private String message = "I used to be smart... now I'm just stupid.";
public void setMessage(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor"/>
<bean id="messenger" class="org.springframework.scripting.groovy.GroovyScriptFactory">
<constructor-arg>
<value>inline:package org.springframework.scripting;
import org.springframework.scripting.Messenger
class DelegatingMessenger implements Messenger {
private Messenger wrappedMessenger;
public String getMessage() {
this.wrappedMessenger.getMessage();
}
public void setMessenger(Messenger wrappedMessenger) {
this.wrappedMessenger = wrappedMessenger;
}
}</value>
</constructor-arg>
<property name="messenger" ref="wrappedMessenger"/>
</bean>
<bean id="wrappedMessenger" class="org.springframework.scripting.support.StubMessenger"/>
</beans>