/*
* Copyright 2002-2015 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 org.junit.Test;
import org.springframework.aop.support.AopUtils;
import org.springframework.aop.target.dynamic.Refreshable;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent;
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;
import org.springframework.tests.sample.beans.TestBean;
import static org.junit.Assert.*;
import static org.mockito.BDDMockito.*;
/**
* @author Rob Harrop
* @author Rick Evans
* @author Juergen Hoeller
*/
public class BshScriptFactoryTests {
@Test
public void staticScript() 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));
}
@Test
public void staticScriptWithNullReturnValue() 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));
}
@Test
public void staticScriptWithTwoInterfacesSpecified() 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());
}
@Test
public void staticWithScriptReturningInstance() 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());
}
@Test
public void staticScriptImplementingInterface() 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());
}
@Test
public void staticPrototypeScript() 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());
}
@Test
public void nonStaticScript() 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());
}
@Test
public void nonStaticPrototypeScript() 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());
}
@Test
public void scriptCompilationException() 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));
}
}
@Test
public void scriptThatCompilesButIsJustPlainBad() throws Exception {
ScriptSource script = mock(ScriptSource.class);
final String badScript = "String getMessage() { throw new IllegalArgumentException(); }";
given(script.getScriptAsString()).willReturn(badScript);
given(script.isModified()).willReturn(true);
BshScriptFactory factory = new BshScriptFactory(
ScriptFactoryPostProcessor.INLINE_SCRIPT_PREFIX + badScript, Messenger.class);
try {
Messenger messenger = (Messenger) factory.getScriptedObject(script, Messenger.class);
messenger.getMessage();
fail("Must have thrown a BshScriptUtils.BshExecutionException.");
}
catch (BshScriptUtils.BshExecutionException expected) {
}
}
@Test
public void ctorWithNullScriptSourceLocator() throws Exception {
try {
new BshScriptFactory(null, Messenger.class);
fail("Must have thrown exception by this point.");
}
catch (IllegalArgumentException expected) {
}
}
@Test
public void ctorWithEmptyScriptSourceLocator() throws Exception {
try {
new BshScriptFactory("", new Class<?>[] {Messenger.class});
fail("Must have thrown exception by this point.");
}
catch (IllegalArgumentException expected) {
}
}
@Test
public void ctorWithWhitespacedScriptSourceLocator() throws Exception {
try {
new BshScriptFactory("\n ", new Class<?>[] {Messenger.class});
fail("Must have thrown exception by this point.");
}
catch (IllegalArgumentException expected) {
}
}
@Test
public void resourceScriptFromTag() throws Exception {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("bsh-with-xsd.xml", getClass());
TestBean testBean = (TestBean) ctx.getBean("testBean");
Collection<String> 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<Messenger> 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());
}
@Test
public void prototypeScriptFromTag() 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());
}
@Test
public void inlineScriptFromTag() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("bsh-with-xsd.xml", getClass());
Calculator calculator = (Calculator) ctx.getBean("calculator");
assertNotNull(calculator);
assertFalse(calculator instanceof Refreshable);
}
@Test
public void refreshableFromTag() 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);
}
@Test
public void applicationEventListener() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("bsh-with-xsd.xml", getClass());
Messenger eventListener = (Messenger) ctx.getBean("eventListener");
ctx.publishEvent(new MyEvent(ctx));
assertEquals("count=2", eventListener.getMessage());
}
@SuppressWarnings("serial")
private static class MyEvent extends ApplicationEvent {
public MyEvent(Object source) {
super(source);
}
}
}