From e1965dea0f41bc3bbd3d20d5e66a3ba12396c340 Mon Sep 17 00:00:00 2001 From: Chris Beams Date: Thu, 18 Dec 2008 21:27:18 +0000 Subject: [PATCH] eliminated svn:externals in favor of localized copies of shared artifacts git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@472 50f2f4bb-b051-0410-bef5-90022cba6387 --- .../SingletonBeanFactoryLocatorTests.java | 182 ++++ .../beans/factory/access/TestBean.java | 75 ++ .../beans/factory/access/beans1.xml | 16 + .../beans/factory/access/beans2.xml | 16 + .../beans/factory/access/ref1.xml | 28 + .../mock/jndi/ExpectedLookupTemplate.java | 82 ++ .../mock/jndi/SimpleNamingContext.java | 345 +++++++ .../mock/jndi/SimpleNamingContextBuilder.java | 234 +++++ .../springframework/mock/jndi/package.html | 12 + .../java/example/aspects/PerTargetAspect.java | 35 + .../java/example/aspects/PerThisAspect.java | 37 + .../java/example/aspects/TwoAdviceAspect.java | 24 + .../AutowiredQualifierFooService.java | 51 ++ .../example/scannable/CustomComponent.java | 33 + .../example/scannable/CustomStereotype.java | 36 + .../scannable/DefaultNamedComponent.java | 26 + .../test/java/example/scannable/FooDao.java | 26 + .../java/example/scannable/FooService.java | 29 + .../example/scannable/FooServiceImpl.java | 80 ++ .../java/example/scannable/MessageBean.java | 39 + .../example/scannable/NamedComponent.java | 27 + .../java/example/scannable/NamedStubDao.java | 31 + .../scannable/ScopedProxyTestBean.java | 36 + .../scannable/ServiceInvocationCounter.java | 46 + .../java/example/scannable/StubFooDao.java | 33 + .../aop/framework/ProxyFactoryBeanTests.java | 3 +- .../mock/web/MockHttpServletRequest.java | 849 ++++++++++++++++++ .../mock/jndi/ExpectedLookupTemplate.java | 82 ++ .../mock/jndi/SimpleNamingContext.java | 345 +++++++ .../mock/jndi/SimpleNamingContextBuilder.java | 234 +++++ .../WebSphereUowTransactionManagerTests.java | 9 +- .../mock/web/portlet/MockActionRequest.java | 131 +++ .../mock/web/portlet/MockActionResponse.java | 163 ++++ .../portlet/MockMultipartActionRequest.java | 67 ++ .../mock/web/portlet/MockPortalContext.java | 101 +++ .../mock/web/portlet/MockPortletConfig.java | 116 +++ .../mock/web/portlet/MockPortletContext.java | 254 ++++++ .../web/portlet/MockPortletPreferences.java | 115 +++ .../mock/web/portlet/MockPortletRequest.java | 462 ++++++++++ .../portlet/MockPortletRequestDispatcher.java | 67 ++ .../mock/web/portlet/MockPortletResponse.java | 110 +++ .../mock/web/portlet/MockPortletSession.java | 190 ++++ .../mock/web/portlet/MockPortletURL.java | 190 ++++ .../mock/web/portlet/MockRenderRequest.java | 70 ++ .../mock/web/portlet/MockRenderResponse.java | 216 +++++ .../mock/web/portlet/package.html | 13 + .../ui/jasperreports/DataSourceReport.jasper | Bin 0 -> 18664 bytes .../ui/jasperreports/DataSourceReport.jrxml | 185 ++++ .../ui/jasperreports/messages_de.properties | 1 + .../ui/jasperreports/subReportChild.jasper | Bin 0 -> 18449 bytes .../ui/jasperreports/subReportChild.jrxml | 227 +++++ .../ui/jasperreports/subReportParent.jasper | Bin 0 -> 14261 bytes .../ui/jasperreports/subReportParent.jrxml | 103 +++ 53 files changed, 5876 insertions(+), 6 deletions(-) create mode 100644 org.springframework.context/src/test/java/org/springframework/beans/factory/access/SingletonBeanFactoryLocatorTests.java create mode 100644 org.springframework.context/src/test/java/org/springframework/beans/factory/access/TestBean.java create mode 100644 org.springframework.context/src/test/java/org/springframework/beans/factory/access/beans1.xml create mode 100644 org.springframework.context/src/test/java/org/springframework/beans/factory/access/beans2.xml create mode 100644 org.springframework.context/src/test/java/org/springframework/beans/factory/access/ref1.xml create mode 100644 org.springframework.context/src/test/java/org/springframework/mock/jndi/ExpectedLookupTemplate.java create mode 100644 org.springframework.context/src/test/java/org/springframework/mock/jndi/SimpleNamingContext.java create mode 100644 org.springframework.context/src/test/java/org/springframework/mock/jndi/SimpleNamingContextBuilder.java create mode 100644 org.springframework.context/src/test/java/org/springframework/mock/jndi/package.html create mode 100644 org.springframework.testsuite/src/test/java/example/aspects/PerTargetAspect.java create mode 100644 org.springframework.testsuite/src/test/java/example/aspects/PerThisAspect.java create mode 100644 org.springframework.testsuite/src/test/java/example/aspects/TwoAdviceAspect.java create mode 100644 org.springframework.testsuite/src/test/java/example/scannable/AutowiredQualifierFooService.java create mode 100644 org.springframework.testsuite/src/test/java/example/scannable/CustomComponent.java create mode 100644 org.springframework.testsuite/src/test/java/example/scannable/CustomStereotype.java create mode 100644 org.springframework.testsuite/src/test/java/example/scannable/DefaultNamedComponent.java create mode 100644 org.springframework.testsuite/src/test/java/example/scannable/FooDao.java create mode 100644 org.springframework.testsuite/src/test/java/example/scannable/FooService.java create mode 100644 org.springframework.testsuite/src/test/java/example/scannable/FooServiceImpl.java create mode 100644 org.springframework.testsuite/src/test/java/example/scannable/MessageBean.java create mode 100644 org.springframework.testsuite/src/test/java/example/scannable/NamedComponent.java create mode 100644 org.springframework.testsuite/src/test/java/example/scannable/NamedStubDao.java create mode 100644 org.springframework.testsuite/src/test/java/example/scannable/ScopedProxyTestBean.java create mode 100644 org.springframework.testsuite/src/test/java/example/scannable/ServiceInvocationCounter.java create mode 100644 org.springframework.testsuite/src/test/java/example/scannable/StubFooDao.java create mode 100644 org.springframework.testsuite/src/test/java/org/springframework/mock/web/MockHttpServletRequest.java create mode 100644 org.springframework.transaction/src/test/java/org/springframework/mock/jndi/ExpectedLookupTemplate.java create mode 100644 org.springframework.transaction/src/test/java/org/springframework/mock/jndi/SimpleNamingContext.java create mode 100644 org.springframework.transaction/src/test/java/org/springframework/mock/jndi/SimpleNamingContextBuilder.java create mode 100644 org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockActionRequest.java create mode 100644 org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockActionResponse.java create mode 100644 org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockMultipartActionRequest.java create mode 100644 org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortalContext.java create mode 100644 org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletConfig.java create mode 100644 org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletContext.java create mode 100644 org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletPreferences.java create mode 100644 org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletRequest.java create mode 100644 org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletRequestDispatcher.java create mode 100644 org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletResponse.java create mode 100644 org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletSession.java create mode 100644 org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletURL.java create mode 100644 org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockRenderRequest.java create mode 100644 org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockRenderResponse.java create mode 100644 org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/package.html create mode 100644 org.springframework.web.servlet/src/test/resources/org/springframework/ui/jasperreports/DataSourceReport.jasper create mode 100644 org.springframework.web.servlet/src/test/resources/org/springframework/ui/jasperreports/DataSourceReport.jrxml create mode 100644 org.springframework.web.servlet/src/test/resources/org/springframework/ui/jasperreports/messages_de.properties create mode 100644 org.springframework.web.servlet/src/test/resources/org/springframework/ui/jasperreports/subReportChild.jasper create mode 100644 org.springframework.web.servlet/src/test/resources/org/springframework/ui/jasperreports/subReportChild.jrxml create mode 100644 org.springframework.web.servlet/src/test/resources/org/springframework/ui/jasperreports/subReportParent.jasper create mode 100644 org.springframework.web.servlet/src/test/resources/org/springframework/ui/jasperreports/subReportParent.jrxml diff --git a/org.springframework.context/src/test/java/org/springframework/beans/factory/access/SingletonBeanFactoryLocatorTests.java b/org.springframework.context/src/test/java/org/springframework/beans/factory/access/SingletonBeanFactoryLocatorTests.java new file mode 100644 index 00000000000..9bdca2165cd --- /dev/null +++ b/org.springframework.context/src/test/java/org/springframework/beans/factory/access/SingletonBeanFactoryLocatorTests.java @@ -0,0 +1,182 @@ +/* + * 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.beans.factory.access; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.util.ClassUtils; + +/** + * @author Colin Sampaleanu + * @author Chris Beams + */ +public class SingletonBeanFactoryLocatorTests { + + @Test + public void testBasicFunctionality() { + SingletonBeanFactoryLocator facLoc = new SingletonBeanFactoryLocator( + "classpath*:" + ClassUtils.addResourcePathToPackagePath(getClass(), "ref1.xml")); + + basicFunctionalityTest(facLoc); + } + + /** + * Worker method so subclass can use it too. + */ + protected void basicFunctionalityTest(SingletonBeanFactoryLocator facLoc) { + BeanFactoryReference bfr = facLoc.useBeanFactory("a.qualified.name.of.some.sort"); + BeanFactory fac = bfr.getFactory(); + BeanFactoryReference bfr2 = facLoc.useBeanFactory("another.qualified.name"); + fac = bfr2.getFactory(); + // verify that the same instance is returned + TestBean tb = (TestBean) fac.getBean("beans1.bean1"); + assertTrue(tb.getName().equals("beans1.bean1")); + tb.setName("was beans1.bean1"); + BeanFactoryReference bfr3 = facLoc.useBeanFactory("another.qualified.name"); + fac = bfr3.getFactory(); + tb = (TestBean) fac.getBean("beans1.bean1"); + assertTrue(tb.getName().equals("was beans1.bean1")); + BeanFactoryReference bfr4 = facLoc.useBeanFactory("a.qualified.name.which.is.an.alias"); + fac = bfr4.getFactory(); + tb = (TestBean) fac.getBean("beans1.bean1"); + assertTrue(tb.getName().equals("was beans1.bean1")); + // Now verify that we can call release in any order. + // Unfortunately this doesn't validate complete release after the last one. + bfr2.release(); + bfr3.release(); + bfr.release(); + bfr4.release(); + } + + /** + * This test can run multiple times, but due to static keyed lookup of the locators, + * 2nd and subsequent calls will actuall get back same locator instance. This is not + * an issue really, since the contained beanfactories will still be loaded and released. + */ + @Test + public void testGetInstance() { + // Try with and without 'classpath*:' prefix, and with 'classpath:' prefix. + BeanFactoryLocator facLoc = SingletonBeanFactoryLocator.getInstance( + ClassUtils.addResourcePathToPackagePath(getClass(), "ref1.xml")); + getInstanceTest1(facLoc); + + facLoc = SingletonBeanFactoryLocator.getInstance( + "classpath*:/" + ClassUtils.addResourcePathToPackagePath(getClass(), "ref1.xml")); + getInstanceTest2(facLoc); + + // This will actually get another locator instance, as the key is the resource name. + facLoc = SingletonBeanFactoryLocator.getInstance( + "classpath:" + ClassUtils.addResourcePathToPackagePath(getClass(), "ref1.xml")); + getInstanceTest3(facLoc); + + } + + /** + * Worker method so subclass can use it too + */ + protected void getInstanceTest1(BeanFactoryLocator facLoc) { + BeanFactoryReference bfr = facLoc.useBeanFactory("a.qualified.name.of.some.sort"); + BeanFactory fac = bfr.getFactory(); + BeanFactoryReference bfr2 = facLoc.useBeanFactory("another.qualified.name"); + fac = bfr2.getFactory(); + // verify that the same instance is returned + TestBean tb = (TestBean) fac.getBean("beans1.bean1"); + assertTrue(tb.getName().equals("beans1.bean1")); + tb.setName("was beans1.bean1"); + BeanFactoryReference bfr3 = facLoc.useBeanFactory("another.qualified.name"); + fac = bfr3.getFactory(); + tb = (TestBean) fac.getBean("beans1.bean1"); + assertTrue(tb.getName().equals("was beans1.bean1")); + + BeanFactoryReference bfr4 = facLoc.useBeanFactory("a.qualified.name.which.is.an.alias"); + fac = bfr4.getFactory(); + tb = (TestBean) fac.getBean("beans1.bean1"); + assertTrue(tb.getName().equals("was beans1.bean1")); + + bfr.release(); + bfr3.release(); + bfr2.release(); + bfr4.release(); + } + + /** + * Worker method so subclass can use it too + */ + protected void getInstanceTest2(BeanFactoryLocator facLoc) { + BeanFactoryReference bfr; + BeanFactory fac; + BeanFactoryReference bfr2; + TestBean tb; + BeanFactoryReference bfr3; + BeanFactoryReference bfr4; + bfr = facLoc.useBeanFactory("a.qualified.name.of.some.sort"); + fac = bfr.getFactory(); + bfr2 = facLoc.useBeanFactory("another.qualified.name"); + fac = bfr2.getFactory(); + // verify that the same instance is returned + tb = (TestBean) fac.getBean("beans1.bean1"); + assertTrue(tb.getName().equals("beans1.bean1")); + tb.setName("was beans1.bean1"); + bfr3 = facLoc.useBeanFactory("another.qualified.name"); + fac = bfr3.getFactory(); + tb = (TestBean) fac.getBean("beans1.bean1"); + assertTrue(tb.getName().equals("was beans1.bean1")); + bfr4 = facLoc.useBeanFactory("a.qualified.name.which.is.an.alias"); + fac = bfr4.getFactory(); + tb = (TestBean) fac.getBean("beans1.bean1"); + assertTrue(tb.getName().equals("was beans1.bean1")); + bfr.release(); + bfr2.release(); + bfr4.release(); + bfr3.release(); + } + + /** + * Worker method so subclass can use it too + */ + protected void getInstanceTest3(BeanFactoryLocator facLoc) { + BeanFactoryReference bfr; + BeanFactory fac; + BeanFactoryReference bfr2; + TestBean tb; + BeanFactoryReference bfr3; + BeanFactoryReference bfr4; + bfr = facLoc.useBeanFactory("a.qualified.name.of.some.sort"); + fac = bfr.getFactory(); + bfr2 = facLoc.useBeanFactory("another.qualified.name"); + fac = bfr2.getFactory(); + // verify that the same instance is returned + tb = (TestBean) fac.getBean("beans1.bean1"); + assertTrue(tb.getName().equals("beans1.bean1")); + tb.setName("was beans1.bean1"); + bfr3 = facLoc.useBeanFactory("another.qualified.name"); + fac = bfr3.getFactory(); + tb = (TestBean) fac.getBean("beans1.bean1"); + assertTrue(tb.getName().equals("was beans1.bean1")); + bfr4 = facLoc.useBeanFactory("a.qualified.name.which.is.an.alias"); + fac = bfr4.getFactory(); + tb = (TestBean) fac.getBean("beans1.bean1"); + assertTrue(tb.getName().equals("was beans1.bean1")); + bfr4.release(); + bfr3.release(); + bfr2.release(); + bfr.release(); + } + +} diff --git a/org.springframework.context/src/test/java/org/springframework/beans/factory/access/TestBean.java b/org.springframework.context/src/test/java/org/springframework/beans/factory/access/TestBean.java new file mode 100644 index 00000000000..eaf1d5ec0b0 --- /dev/null +++ b/org.springframework.context/src/test/java/org/springframework/beans/factory/access/TestBean.java @@ -0,0 +1,75 @@ +/* + * 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.beans.factory.access; + +import java.util.List; + +/** + * Scrap bean for use in tests. + * + * @author Colin Sampaleanu + */ +public class TestBean { + + private String name; + + private List list; + + private Object objRef; + + /** + * @return Returns the name. + */ + public String getName() { + return name; + } + + /** + * @param name The name to set. + */ + public void setName(String name) { + this.name = name; + } + + /** + * @return Returns the list. + */ + public List getList() { + return list; + } + + /** + * @param list The list to set. + */ + public void setList(List list) { + this.list = list; + } + + /** + * @return Returns the object. + */ + public Object getObjRef() { + return objRef; + } + + /** + * @param object The object to set. + */ + public void setObjRef(Object object) { + this.objRef = object; + } +} diff --git a/org.springframework.context/src/test/java/org/springframework/beans/factory/access/beans1.xml b/org.springframework.context/src/test/java/org/springframework/beans/factory/access/beans1.xml new file mode 100644 index 00000000000..10581610497 --- /dev/null +++ b/org.springframework.context/src/test/java/org/springframework/beans/factory/access/beans1.xml @@ -0,0 +1,16 @@ + + + + + + + + beans1.bean1 + + + + bean2 + + + + diff --git a/org.springframework.context/src/test/java/org/springframework/beans/factory/access/beans2.xml b/org.springframework.context/src/test/java/org/springframework/beans/factory/access/beans2.xml new file mode 100644 index 00000000000..a5167f6bfe6 --- /dev/null +++ b/org.springframework.context/src/test/java/org/springframework/beans/factory/access/beans2.xml @@ -0,0 +1,16 @@ + + + + + + + + beans2.bean1 + + + + beans2.bean2 + + + + diff --git a/org.springframework.context/src/test/java/org/springframework/beans/factory/access/ref1.xml b/org.springframework.context/src/test/java/org/springframework/beans/factory/access/ref1.xml new file mode 100644 index 00000000000..2dde7a31b37 --- /dev/null +++ b/org.springframework.context/src/test/java/org/springframework/beans/factory/access/ref1.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.context/src/test/java/org/springframework/mock/jndi/ExpectedLookupTemplate.java b/org.springframework.context/src/test/java/org/springframework/mock/jndi/ExpectedLookupTemplate.java new file mode 100644 index 00000000000..28670fd4383 --- /dev/null +++ b/org.springframework.context/src/test/java/org/springframework/mock/jndi/ExpectedLookupTemplate.java @@ -0,0 +1,82 @@ +/* + * 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.mock.jndi; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import javax.naming.NamingException; + +import org.springframework.core.CollectionFactory; +import org.springframework.jndi.JndiTemplate; + +/** + * Simple extension of the JndiTemplate class that always returns + * a given object. Very useful for testing. Effectively a mock object. + * + * @author Rod Johnson + * @author Juergen Hoeller + */ +public class ExpectedLookupTemplate extends JndiTemplate { + + private final Map jndiObjects = new ConcurrentHashMap(); + + + /** + * Construct a new JndiTemplate that will always return given objects + * for given names. To be populated through addObject calls. + * @see #addObject(String, Object) + */ + public ExpectedLookupTemplate() { + } + + /** + * Construct a new JndiTemplate that will always return the + * given object, but honour only requests for the given name. + * @param name the name the client is expected to look up + * @param object the object that will be returned + */ + public ExpectedLookupTemplate(String name, Object object) { + addObject(name, object); + } + + + /** + * Add the given object to the list of JNDI objects that this + * template will expose. + * @param name the name the client is expected to look up + * @param object the object that will be returned + */ + public void addObject(String name, Object object) { + this.jndiObjects.put(name, object); + } + + + /** + * If the name is the expected name specified in the constructor, + * return the object provided in the constructor. If the name is + * unexpected, a respective NamingException gets thrown. + */ + public Object lookup(String name) throws NamingException { + Object object = this.jndiObjects.get(name); + if (object == null) { + throw new NamingException("Unexpected JNDI name '" + name + "': expecting " + this.jndiObjects.keySet()); + } + return object; + } + +} diff --git a/org.springframework.context/src/test/java/org/springframework/mock/jndi/SimpleNamingContext.java b/org.springframework.context/src/test/java/org/springframework/mock/jndi/SimpleNamingContext.java new file mode 100644 index 00000000000..b6489e42029 --- /dev/null +++ b/org.springframework.context/src/test/java/org/springframework/mock/jndi/SimpleNamingContext.java @@ -0,0 +1,345 @@ +/* + * 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.mock.jndi; + +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; +import javax.naming.Binding; +import javax.naming.Context; +import javax.naming.Name; +import javax.naming.NameClassPair; +import javax.naming.NameNotFoundException; +import javax.naming.NameParser; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.OperationNotSupportedException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.util.StringUtils; + +/** + * Simple implementation of a JNDI naming context. + * Only supports binding plain Objects to String names. + * Mainly for test environments, but also usable for standalone applications. + * + *

This class is not intended for direct usage by applications, although it + * can be used for example to override JndiTemplate's createInitialContext + * method in unit tests. Typically, SimpleNamingContextBuilder will be used to + * set up a JVM-level JNDI environment. + * + * @author Rod Johnson + * @author Juergen Hoeller + * @see org.springframework.mock.jndi.SimpleNamingContextBuilder + * @see org.springframework.jndi.JndiTemplate#createInitialContext + */ +public class SimpleNamingContext implements Context { + + private final Log logger = LogFactory.getLog(getClass()); + + private final String root; + + private final Hashtable boundObjects; + + private final Hashtable environment = new Hashtable(); + + + /** + * Create a new naming context. + */ + public SimpleNamingContext() { + this(""); + } + + /** + * Create a new naming context with the given naming root. + */ + public SimpleNamingContext(String root) { + this.root = root; + this.boundObjects = new Hashtable(); + } + + /** + * Create a new naming context with the given naming root, + * the given name/object map, and the JNDI environment entries. + */ + public SimpleNamingContext(String root, Hashtable boundObjects, Hashtable env) { + this.root = root; + this.boundObjects = boundObjects; + if (env != null) { + this.environment.putAll(env); + } + } + + + // Actual implementations of Context methods follow + + public NamingEnumeration list(String root) throws NamingException { + if (logger.isDebugEnabled()) { + logger.debug("Listing name/class pairs under [" + root + "]"); + } + return new NameClassPairEnumeration(this, root); + } + + public NamingEnumeration listBindings(String root) throws NamingException { + if (logger.isDebugEnabled()) { + logger.debug("Listing bindings under [" + root + "]"); + } + return new BindingEnumeration(this, root); + } + + /** + * Look up the object with the given name. + *

Note: Not intended for direct use by applications. + * Will be used by any standard InitialContext JNDI lookups. + * @throws javax.naming.NameNotFoundException if the object could not be found + */ + public Object lookup(String lookupName) throws NameNotFoundException { + String name = this.root + lookupName; + if (logger.isDebugEnabled()) { + logger.debug("Static JNDI lookup: [" + name + "]"); + } + if ("".equals(name)) { + return new SimpleNamingContext(this.root, this.boundObjects, this.environment); + } + Object found = this.boundObjects.get(name); + if (found == null) { + if (!name.endsWith("/")) { + name = name + "/"; + } + for (String boundName : this.boundObjects.keySet()) { + if (boundName.startsWith(name)) { + return new SimpleNamingContext(name, this.boundObjects, this.environment); + } + } + throw new NameNotFoundException( + "Name [" + this.root + lookupName + "] not bound; " + this.boundObjects.size() + " bindings: [" + + StringUtils.collectionToDelimitedString(this.boundObjects.keySet(), ",") + "]"); + } + return found; + } + + public Object lookupLink(String name) throws NameNotFoundException { + return lookup(name); + } + + /** + * Bind the given object to the given name. + * Note: Not intended for direct use by applications + * if setting up a JVM-level JNDI environment. + * Use SimpleNamingContextBuilder to set up JNDI bindings then. + * @see org.springframework.mock.jndi.SimpleNamingContextBuilder#bind + */ + public void bind(String name, Object obj) { + if (logger.isInfoEnabled()) { + logger.info("Static JNDI binding: [" + this.root + name + "] = [" + obj + "]"); + } + this.boundObjects.put(this.root + name, obj); + } + + public void unbind(String name) { + if (logger.isInfoEnabled()) { + logger.info("Static JNDI remove: [" + this.root + name + "]"); + } + this.boundObjects.remove(this.root + name); + } + + public void rebind(String name, Object obj) { + bind(name, obj); + } + + public void rename(String oldName, String newName) throws NameNotFoundException { + Object obj = lookup(oldName); + unbind(oldName); + bind(newName, obj); + } + + public Context createSubcontext(String name) { + String subcontextName = this.root + name; + if (!subcontextName.endsWith("/")) { + subcontextName += "/"; + } + Context subcontext = new SimpleNamingContext(subcontextName, this.boundObjects, this.environment); + bind(name, subcontext); + return subcontext; + } + + public void destroySubcontext(String name) { + unbind(name); + } + + public String composeName(String name, String prefix) { + return prefix + name; + } + + public Hashtable getEnvironment() { + return this.environment; + } + + public Object addToEnvironment(String propName, Object propVal) { + return this.environment.put(propName, propVal); + } + + public Object removeFromEnvironment(String propName) { + return this.environment.remove(propName); + } + + public void close() { + } + + + // Unsupported methods follow: no support for javax.naming.Name + + public NamingEnumeration list(Name name) throws NamingException { + throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); + } + + public NamingEnumeration listBindings(Name name) throws NamingException { + throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); + } + + public Object lookup(Name name) throws NamingException { + throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); + } + + public Object lookupLink(Name name) throws NamingException { + throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); + } + + public void bind(Name name, Object obj) throws NamingException { + throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); + } + + public void unbind(Name name) throws NamingException { + throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); + } + + public void rebind(Name name, Object obj) throws NamingException { + throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); + } + + public void rename(Name oldName, Name newName) throws NamingException { + throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); + } + + public Context createSubcontext(Name name) throws NamingException { + throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); + } + + public void destroySubcontext(Name name) throws NamingException { + throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); + } + + public String getNameInNamespace() throws NamingException { + throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); + } + + public NameParser getNameParser(Name name) throws NamingException { + throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); + } + + public NameParser getNameParser(String name) throws NamingException { + throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); + } + + public Name composeName(Name name, Name prefix) throws NamingException { + throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); + } + + + private static abstract class AbstractNamingEnumeration implements NamingEnumeration { + + private Iterator iterator; + + private AbstractNamingEnumeration(SimpleNamingContext context, String proot) throws NamingException { + if (!"".equals(proot) && !proot.endsWith("/")) { + proot = proot + "/"; + } + String root = context.root + proot; + Map contents = new HashMap(); + for (String boundName : context.boundObjects.keySet()) { + if (boundName.startsWith(root)) { + int startIndex = root.length(); + int endIndex = boundName.indexOf('/', startIndex); + String strippedName = + (endIndex != -1 ? boundName.substring(startIndex, endIndex) : boundName.substring(startIndex)); + if (!contents.containsKey(strippedName)) { + try { + contents.put(strippedName, createObject(strippedName, context.lookup(proot + strippedName))); + } + catch (NameNotFoundException ex) { + // cannot happen + } + } + } + } + if (contents.size() == 0) { + throw new NamingException("Invalid root: [" + context.root + proot + "]"); + } + this.iterator = contents.values().iterator(); + } + + protected abstract T createObject(String strippedName, Object obj); + + public boolean hasMore() { + return this.iterator.hasNext(); + } + + public T next() { + return this.iterator.next(); + } + + public boolean hasMoreElements() { + return this.iterator.hasNext(); + } + + public T nextElement() { + return this.iterator.next(); + } + + public void close() { + } + } + + + private static class NameClassPairEnumeration extends AbstractNamingEnumeration { + + private NameClassPairEnumeration(SimpleNamingContext context, String root) throws NamingException { + super(context, root); + } + + protected NameClassPair createObject(String strippedName, Object obj) { + return new NameClassPair(strippedName, obj.getClass().getName()); + } + } + + + private static class BindingEnumeration extends AbstractNamingEnumeration { + + private BindingEnumeration(SimpleNamingContext context, String root) throws NamingException { + super(context, root); + } + + protected Binding createObject(String strippedName, Object obj) { + return new Binding(strippedName, obj); + } + } + +} diff --git a/org.springframework.context/src/test/java/org/springframework/mock/jndi/SimpleNamingContextBuilder.java b/org.springframework.context/src/test/java/org/springframework/mock/jndi/SimpleNamingContextBuilder.java new file mode 100644 index 00000000000..130de79de5e --- /dev/null +++ b/org.springframework.context/src/test/java/org/springframework/mock/jndi/SimpleNamingContextBuilder.java @@ -0,0 +1,234 @@ +/* + * 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.mock.jndi; + +import java.util.Hashtable; + +import javax.naming.Context; +import javax.naming.NamingException; +import javax.naming.spi.InitialContextFactory; +import javax.naming.spi.InitialContextFactoryBuilder; +import javax.naming.spi.NamingManager; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.util.ClassUtils; + +/** + * Simple implementation of a JNDI naming context builder. + * + *

Mainly targeted at test environments, where each test case can + * configure JNDI appropriately, so that new InitialContext() + * will expose the required objects. Also usable for standalone applications, + * e.g. for binding a JDBC DataSource to a well-known JNDI location, to be + * able to use traditional J2EE data access code outside of a J2EE container. + * + *

There are various choices for DataSource implementations: + *

    + *
  • SingleConnectionDataSource (using the same Connection for all getConnection calls); + *
  • DriverManagerDataSource (creating a new Connection on each getConnection call); + *
  • Apache's Jakarta Commons DBCP offers BasicDataSource (a real pool). + *
+ * + *

Typical usage in bootstrap code: + * + *

+ * SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder();
+ * DataSource ds = new DriverManagerDataSource(...);
+ * builder.bind("java:comp/env/jdbc/myds", ds);
+ * builder.activate();
+ * + * Note that it's impossible to activate multiple builders within the same JVM, + * due to JNDI restrictions. Thus to configure a fresh builder repeatedly, use + * the following code to get a reference to either an already activated builder + * or a newly activated one: + * + *
+ * SimpleNamingContextBuilder builder = SimpleNamingContextBuilder.emptyActivatedContextBuilder();
+ * DataSource ds = new DriverManagerDataSource(...);
+ * builder.bind("java:comp/env/jdbc/myds", ds);
+ * + * Note that you should not call activate() on a builder from + * this factory method, as there will already be an activated one in any case. + * + *

An instance of this class is only necessary at setup time. + * An application does not need to keep a reference to it after activation. + * + * @author Juergen Hoeller + * @author Rod Johnson + * @see #emptyActivatedContextBuilder() + * @see #bind(String, Object) + * @see #activate() + * @see org.springframework.mock.jndi.SimpleNamingContext + * @see org.springframework.jdbc.datasource.SingleConnectionDataSource + * @see org.springframework.jdbc.datasource.DriverManagerDataSource + * @see org.apache.commons.dbcp.BasicDataSource + */ +public class SimpleNamingContextBuilder implements InitialContextFactoryBuilder { + + /** An instance of this class bound to JNDI */ + private static volatile SimpleNamingContextBuilder activated; + + private static boolean initialized = false; + + private static final Object initializationLock = new Object(); + + + /** + * Checks if a SimpleNamingContextBuilder is active. + * @return the current SimpleNamingContextBuilder instance, + * or null if none + */ + public static SimpleNamingContextBuilder getCurrentContextBuilder() { + return activated; + } + + /** + * If no SimpleNamingContextBuilder is already configuring JNDI, + * create and activate one. Otherwise take the existing activate + * SimpleNamingContextBuilder, clear it and return it. + *

This is mainly intended for test suites that want to + * reinitialize JNDI bindings from scratch repeatedly. + * @return an empty SimpleNamingContextBuilder that can be used + * to control JNDI bindings + */ + public static SimpleNamingContextBuilder emptyActivatedContextBuilder() throws NamingException { + if (activated != null) { + // Clear already activated context builder. + activated.clear(); + } + else { + // Create and activate new context builder. + SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder(); + // The activate() call will cause an assigment to the activated variable. + builder.activate(); + } + return activated; + } + + + private final Log logger = LogFactory.getLog(getClass()); + + private final Hashtable boundObjects = new Hashtable(); + + + /** + * Register the context builder by registering it with the JNDI NamingManager. + * Note that once this has been done, new InitialContext() will always + * return a context from this factory. Use the emptyActivatedContextBuilder() + * static method to get an empty context (for example, in test methods). + * @throws IllegalStateException if there's already a naming context builder + * registered with the JNDI NamingManager + */ + public void activate() throws IllegalStateException, NamingException { + logger.info("Activating simple JNDI environment"); + synchronized (initializationLock) { + if (!initialized) { + if (NamingManager.hasInitialContextFactoryBuilder()) { + throw new IllegalStateException( + "Cannot activate SimpleNamingContextBuilder: there is already a JNDI provider registered. " + + "Note that JNDI is a JVM-wide service, shared at the JVM system class loader level, " + + "with no reset option. As a consequence, a JNDI provider must only be registered once per JVM."); + } + NamingManager.setInitialContextFactoryBuilder(this); + initialized = true; + } + } + activated = this; + } + + /** + * Temporarily deactivate this context builder. It will remain registered with + * the JNDI NamingManager but will delegate to the standard JNDI InitialContextFactory + * (if configured) instead of exposing its own bound objects. + *

Call activate() again in order to expose this contexz builder's own + * bound objects again. Such activate/deactivate sequences can be applied any number + * of times (e.g. within a larger integration test suite running in the same VM). + * @see #activate() + */ + public void deactivate() { + logger.info("Deactivating simple JNDI environment"); + activated = null; + } + + /** + * Clear all bindings in this context builder, while keeping it active. + */ + public void clear() { + this.boundObjects.clear(); + } + + /** + * Bind the given object under the given name, for all naming contexts + * that this context builder will generate. + * @param name the JNDI name of the object (e.g. "java:comp/env/jdbc/myds") + * @param obj the object to bind (e.g. a DataSource implementation) + */ + public void bind(String name, Object obj) { + if (logger.isInfoEnabled()) { + logger.info("Static JNDI binding: [" + name + "] = [" + obj + "]"); + } + this.boundObjects.put(name, obj); + } + + + /** + * Simple InitialContextFactoryBuilder implementation, + * creating a new SimpleNamingContext instance. + * @see SimpleNamingContext + */ + public InitialContextFactory createInitialContextFactory(Hashtable environment) { + if (activated == null && environment != null) { + Object icf = environment.get(Context.INITIAL_CONTEXT_FACTORY); + if (icf != null) { + Class icfClass = null; + if (icf instanceof Class) { + icfClass = (Class) icf; + } + else if (icf instanceof String) { + icfClass = ClassUtils.resolveClassName((String) icf, getClass().getClassLoader()); + } + else { + throw new IllegalArgumentException("Invalid value type for environment key [" + + Context.INITIAL_CONTEXT_FACTORY + "]: " + icf.getClass().getName()); + } + if (!InitialContextFactory.class.isAssignableFrom(icfClass)) { + throw new IllegalArgumentException( + "Specified class does not implement [" + InitialContextFactory.class.getName() + "]: " + icf); + } + try { + return (InitialContextFactory) icfClass.newInstance(); + } + catch (Throwable ex) { + IllegalStateException ise = + new IllegalStateException("Cannot instantiate specified InitialContextFactory: " + icf); + ise.initCause(ex); + throw ise; + } + } + } + + // Default case... + return new InitialContextFactory() { + public Context getInitialContext(Hashtable environment) { + return new SimpleNamingContext("", boundObjects, environment); + } + }; + } + +} diff --git a/org.springframework.context/src/test/java/org/springframework/mock/jndi/package.html b/org.springframework.context/src/test/java/org/springframework/mock/jndi/package.html new file mode 100644 index 00000000000..141ee8db0fa --- /dev/null +++ b/org.springframework.context/src/test/java/org/springframework/mock/jndi/package.html @@ -0,0 +1,12 @@ + + + +The simplest implementation of the JNDI SPI that could possibly work. + +

Useful for setting up a simple JNDI environment for test suites +or standalone applications. If e.g. JDBC DataSources get bound to the +same JNDI names as within a J2EE container, both application code and +configuration can me reused without changes. + + + diff --git a/org.springframework.testsuite/src/test/java/example/aspects/PerTargetAspect.java b/org.springframework.testsuite/src/test/java/example/aspects/PerTargetAspect.java new file mode 100644 index 00000000000..4244c389493 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/example/aspects/PerTargetAspect.java @@ -0,0 +1,35 @@ +/** + * + */ +package example.aspects; + +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.springframework.core.Ordered; + +@Aspect("pertarget(execution(* *.getSpouse()))") +public class PerTargetAspect implements Ordered { + + public int count; + + private int order = Ordered.LOWEST_PRECEDENCE; + + @Around("execution(int *.getAge())") + public int returnCountAsAge() { + return count++; + } + + @Before("execution(void *.set*(int))") + public void countSetter() { + ++count; + } + + public int getOrder() { + return this.order; + } + + public void setOrder(int order) { + this.order = order; + } +} \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/example/aspects/PerThisAspect.java b/org.springframework.testsuite/src/test/java/example/aspects/PerThisAspect.java new file mode 100644 index 00000000000..9f95aaa018b --- /dev/null +++ b/org.springframework.testsuite/src/test/java/example/aspects/PerThisAspect.java @@ -0,0 +1,37 @@ +/* + * 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 example.aspects; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; + +@Aspect("perthis(execution(* getAge()))") +public class PerThisAspect { + + private int invocations = 0; + + public int getInvocations() { + return this.invocations; + } + + @Around("execution(* getAge())") + public int changeAge(ProceedingJoinPoint pjp) throws Throwable { + return invocations++; + } + +} diff --git a/org.springframework.testsuite/src/test/java/example/aspects/TwoAdviceAspect.java b/org.springframework.testsuite/src/test/java/example/aspects/TwoAdviceAspect.java new file mode 100644 index 00000000000..e69d7d99e57 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/example/aspects/TwoAdviceAspect.java @@ -0,0 +1,24 @@ +/** + * + */ +package example.aspects; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; + +@Aspect +public class TwoAdviceAspect { + private int totalCalls; + + @Around("execution(* getAge())") + public int returnCallCount(ProceedingJoinPoint pjp) throws Exception { + return totalCalls; + } + + @Before("execution(* setAge(int)) && args(newAge)") + public void countSet(int newAge) throws Exception { + ++totalCalls; + } +} \ No newline at end of file diff --git a/org.springframework.testsuite/src/test/java/example/scannable/AutowiredQualifierFooService.java b/org.springframework.testsuite/src/test/java/example/scannable/AutowiredQualifierFooService.java new file mode 100644 index 00000000000..6db0d795543 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/example/scannable/AutowiredQualifierFooService.java @@ -0,0 +1,51 @@ +/* + * 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 example.scannable; + +import javax.annotation.PostConstruct; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; + +/** + * @author Mark Fisher + */ +public class AutowiredQualifierFooService implements FooService { + + @Autowired + @Qualifier("testing") + private FooDao fooDao; + + private boolean initCalled = false; + + @PostConstruct + private void init() { + if (this.initCalled) { + throw new IllegalStateException("Init already called"); + } + this.initCalled = true; + } + + public String foo(int id) { + return this.fooDao.findFoo(id); + } + + public boolean isInitCalled() { + return this.initCalled; + } + +} diff --git a/org.springframework.testsuite/src/test/java/example/scannable/CustomComponent.java b/org.springframework.testsuite/src/test/java/example/scannable/CustomComponent.java new file mode 100644 index 00000000000..2f6ef7f42a9 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/example/scannable/CustomComponent.java @@ -0,0 +1,33 @@ +/* + * 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 example.scannable; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author Mark Fisher + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface CustomComponent { + +} diff --git a/org.springframework.testsuite/src/test/java/example/scannable/CustomStereotype.java b/org.springframework.testsuite/src/test/java/example/scannable/CustomStereotype.java new file mode 100644 index 00000000000..656ad49bd8f --- /dev/null +++ b/org.springframework.testsuite/src/test/java/example/scannable/CustomStereotype.java @@ -0,0 +1,36 @@ +/* + * 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 example.scannable; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.stereotype.Component; + +/** + * @author Juergen Hoeller + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Component +public @interface CustomStereotype { + + String value() default "thoreau"; + +} diff --git a/org.springframework.testsuite/src/test/java/example/scannable/DefaultNamedComponent.java b/org.springframework.testsuite/src/test/java/example/scannable/DefaultNamedComponent.java new file mode 100644 index 00000000000..8ce68ee3d41 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/example/scannable/DefaultNamedComponent.java @@ -0,0 +1,26 @@ +/* + * 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 example.scannable; + + +/** + * @author Juergen Hoeller + */ +@CustomStereotype +public class DefaultNamedComponent { + +} diff --git a/org.springframework.testsuite/src/test/java/example/scannable/FooDao.java b/org.springframework.testsuite/src/test/java/example/scannable/FooDao.java new file mode 100644 index 00000000000..92fe2622d3e --- /dev/null +++ b/org.springframework.testsuite/src/test/java/example/scannable/FooDao.java @@ -0,0 +1,26 @@ +/* + * 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 example.scannable; + +/** + * @author Mark Fisher + */ +public interface FooDao { + + String findFoo(int id); + +} diff --git a/org.springframework.testsuite/src/test/java/example/scannable/FooService.java b/org.springframework.testsuite/src/test/java/example/scannable/FooService.java new file mode 100644 index 00000000000..f5fc4e6bfb0 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/example/scannable/FooService.java @@ -0,0 +1,29 @@ +/* + * 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 example.scannable; + +/** + * @author Mark Fisher + * @author Juergen Hoeller + */ +public interface FooService { + + String foo(int id); + + boolean isInitCalled(); + +} diff --git a/org.springframework.testsuite/src/test/java/example/scannable/FooServiceImpl.java b/org.springframework.testsuite/src/test/java/example/scannable/FooServiceImpl.java new file mode 100644 index 00000000000..1b13d9644db --- /dev/null +++ b/org.springframework.testsuite/src/test/java/example/scannable/FooServiceImpl.java @@ -0,0 +1,80 @@ +/* + * 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 example.scannable; + +import java.util.List; + +import javax.annotation.PostConstruct; + +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.ListableBeanFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.MessageSource; +import org.springframework.context.support.AbstractApplicationContext; +import org.springframework.core.io.ResourceLoader; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.stereotype.Service; + +/** + * @author Mark Fisher + * @author Juergen Hoeller + */ +@Service +public class FooServiceImpl implements FooService { + + @Autowired private FooDao fooDao; + + @Autowired public BeanFactory beanFactory; + + @Autowired public List listableBeanFactory; + + @Autowired public ResourceLoader resourceLoader; + + @Autowired public ResourcePatternResolver resourcePatternResolver; + + @Autowired public ApplicationEventPublisher eventPublisher; + + @Autowired public MessageSource messageSource; + + @Autowired public ApplicationContext context; + + @Autowired public ConfigurableApplicationContext[] configurableContext; + + @Autowired public AbstractApplicationContext genericContext; + + private boolean initCalled = false; + + @PostConstruct + private void init() { + if (this.initCalled) { + throw new IllegalStateException("Init already called"); + } + this.initCalled = true; + } + + public String foo(int id) { + return this.fooDao.findFoo(id); + } + + public boolean isInitCalled() { + return this.initCalled; + } + +} diff --git a/org.springframework.testsuite/src/test/java/example/scannable/MessageBean.java b/org.springframework.testsuite/src/test/java/example/scannable/MessageBean.java new file mode 100644 index 00000000000..a1035f114fb --- /dev/null +++ b/org.springframework.testsuite/src/test/java/example/scannable/MessageBean.java @@ -0,0 +1,39 @@ +/* + * 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 example.scannable; + +/** + * @author Mark Fisher + */ +@CustomComponent +public class MessageBean { + + private String message; + + public MessageBean() { + this.message = "DEFAULT MESSAGE"; + } + + public MessageBean(String message) { + this.message = message; + } + + public String getMessage() { + return this.message; + } + +} diff --git a/org.springframework.testsuite/src/test/java/example/scannable/NamedComponent.java b/org.springframework.testsuite/src/test/java/example/scannable/NamedComponent.java new file mode 100644 index 00000000000..748eef7be8a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/example/scannable/NamedComponent.java @@ -0,0 +1,27 @@ +/* + * 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 example.scannable; + +import org.springframework.stereotype.Component; + +/** + * @author Mark Fisher + */ +@Component("myNamedComponent") +public class NamedComponent { + +} diff --git a/org.springframework.testsuite/src/test/java/example/scannable/NamedStubDao.java b/org.springframework.testsuite/src/test/java/example/scannable/NamedStubDao.java new file mode 100644 index 00000000000..a4eb66b88c6 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/example/scannable/NamedStubDao.java @@ -0,0 +1,31 @@ +/* + * 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 example.scannable; + +import org.springframework.stereotype.Repository; + +/** + * @author Juergen Hoeller + */ +@Repository("myNamedDao") +public class NamedStubDao { + + public String find(int id) { + return "bar"; + } + +} diff --git a/org.springframework.testsuite/src/test/java/example/scannable/ScopedProxyTestBean.java b/org.springframework.testsuite/src/test/java/example/scannable/ScopedProxyTestBean.java new file mode 100644 index 00000000000..5168b2b66ba --- /dev/null +++ b/org.springframework.testsuite/src/test/java/example/scannable/ScopedProxyTestBean.java @@ -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 example.scannable; + +import org.springframework.context.annotation.Scope; + +/** + * @author Mark Fisher + * @author Juergen Hoeller + */ +@Scope("myScope") +public class ScopedProxyTestBean implements FooService { + + public String foo(int id) { + return "bar"; + } + + public boolean isInitCalled() { + return false; + } + +} diff --git a/org.springframework.testsuite/src/test/java/example/scannable/ServiceInvocationCounter.java b/org.springframework.testsuite/src/test/java/example/scannable/ServiceInvocationCounter.java new file mode 100644 index 00000000000..a0aa9da7223 --- /dev/null +++ b/org.springframework.testsuite/src/test/java/example/scannable/ServiceInvocationCounter.java @@ -0,0 +1,46 @@ +/* + * 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 example.scannable; + +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.annotation.Pointcut; + +import org.springframework.stereotype.Component; + +/** + * @author Mark Fisher + */ +@Component +@Aspect +public class ServiceInvocationCounter { + + private int useCount; + + @Pointcut("execution(* example.scannable.FooService+.*(..))") + public void serviceExecution() {} + + @Before("serviceExecution()") + public void countUse() { + this.useCount++; + } + + public int getCount() { + return this.useCount; + } + +} diff --git a/org.springframework.testsuite/src/test/java/example/scannable/StubFooDao.java b/org.springframework.testsuite/src/test/java/example/scannable/StubFooDao.java new file mode 100644 index 00000000000..b4ea5b65d5d --- /dev/null +++ b/org.springframework.testsuite/src/test/java/example/scannable/StubFooDao.java @@ -0,0 +1,33 @@ +/* + * 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 example.scannable; + +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Repository; + +/** + * @author Mark Fisher + */ +@Repository +@Qualifier("testing") +public class StubFooDao implements FooDao { + + public String findFoo(int id) { + return "bar"; + } + +} diff --git a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/ProxyFactoryBeanTests.java b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/ProxyFactoryBeanTests.java index 721565b3233..1ba52a95874 100644 --- a/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/ProxyFactoryBeanTests.java +++ b/org.springframework.testsuite/src/test/java/org/springframework/aop/framework/ProxyFactoryBeanTests.java @@ -16,8 +16,7 @@ package org.springframework.aop.framework; -import static org.hamcrest.CoreMatchers.instanceOf; -import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; import java.io.FileNotFoundException; diff --git a/org.springframework.testsuite/src/test/java/org/springframework/mock/web/MockHttpServletRequest.java b/org.springframework.testsuite/src/test/java/org/springframework/mock/web/MockHttpServletRequest.java new file mode 100644 index 00000000000..527f05c150a --- /dev/null +++ b/org.springframework.testsuite/src/test/java/org/springframework/mock/web/MockHttpServletRequest.java @@ -0,0 +1,849 @@ +/* + * 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.mock.web; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.UnsupportedEncodingException; +import java.security.Principal; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.Vector; + +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletContext; +import javax.servlet.ServletInputStream; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; + +import org.springframework.util.Assert; + +/** + * Mock implementation of the {@link javax.servlet.http.HttpServletRequest} + * interface. Supports the Servlet 2.4 API level. + * + *

Used for testing the web framework; also useful for testing + * application controllers. + * + * @author Juergen Hoeller + * @author Rod Johnson + * @author Rick Evans + * @author Mark Fisher + * @since 1.0.2 + */ +public class MockHttpServletRequest implements HttpServletRequest { + + /** + * The default protocol: 'http'. + */ + public static final String DEFAULT_PROTOCOL = "http"; + + /** + * The default server address: '127.0.0.1'. + */ + public static final String DEFAULT_SERVER_ADDR = "127.0.0.1"; + + /** + * The default server name: 'localhost'. + */ + public static final String DEFAULT_SERVER_NAME = "localhost"; + + /** + * The default server port: '80'. + */ + public static final int DEFAULT_SERVER_PORT = 80; + + /** + * The default remote address: '127.0.0.1'. + */ + public static final String DEFAULT_REMOTE_ADDR = "127.0.0.1"; + + /** + * The default remote host: 'localhost'. + */ + public static final String DEFAULT_REMOTE_HOST = "localhost"; + + + private boolean active = true; + + + //--------------------------------------------------------------------- + // ServletRequest properties + //--------------------------------------------------------------------- + + private final Hashtable attributes = new Hashtable(); + + private String characterEncoding; + + private byte[] content; + + private String contentType; + + private final Map parameters = new LinkedHashMap(16); + + private String protocol = DEFAULT_PROTOCOL; + + private String scheme = DEFAULT_PROTOCOL; + + private String serverName = DEFAULT_SERVER_NAME; + + private int serverPort = DEFAULT_SERVER_PORT; + + private String remoteAddr = DEFAULT_REMOTE_ADDR; + + private String remoteHost = DEFAULT_REMOTE_HOST; + + /** List of locales in descending order */ + private final Vector locales = new Vector(); + + private boolean secure = false; + + private final ServletContext servletContext; + + private int remotePort = DEFAULT_SERVER_PORT; + + private String localName = DEFAULT_SERVER_NAME; + + private String localAddr = DEFAULT_SERVER_ADDR; + + private int localPort = DEFAULT_SERVER_PORT; + + + //--------------------------------------------------------------------- + // HttpServletRequest properties + //--------------------------------------------------------------------- + + private String authType; + + private Cookie[] cookies; + + /** + * The key is the lowercase header name; the value is a {@link HeaderValueHolder} object. + */ + private final Hashtable headers = new Hashtable(); + + private String method; + + private String pathInfo; + + private String contextPath = ""; + + private String queryString; + + private String remoteUser; + + private final Set userRoles = new HashSet(); + + private Principal userPrincipal; + + private String requestURI; + + private String servletPath = ""; + + private HttpSession session; + + private boolean requestedSessionIdValid = true; + + private boolean requestedSessionIdFromCookie = true; + + private boolean requestedSessionIdFromURL = false; + + + //--------------------------------------------------------------------- + // Constructors + //--------------------------------------------------------------------- + + /** + * Create a new MockHttpServletRequest with a default + * {@link MockServletContext}. + * @see MockServletContext + */ + public MockHttpServletRequest() { + this(null, "", ""); + } + + /** + * Create a new MockHttpServletRequest with a default + * {@link MockServletContext}. + * @param method the request method (may be null) + * @param requestURI the request URI (may be null) + * @see #setMethod + * @see #setRequestURI + * @see MockServletContext + */ + public MockHttpServletRequest(String method, String requestURI) { + this(null, method, requestURI); + } + + /** + * Create a new MockHttpServletRequest. + * @param servletContext the ServletContext that the request runs in + * (may be null to use a default MockServletContext) + * @see MockServletContext + */ + public MockHttpServletRequest(ServletContext servletContext) { + this(servletContext, "", ""); + } + + /** + * Create a new MockHttpServletRequest. + * @param servletContext the ServletContext that the request runs in + * (may be null to use a default MockServletContext) + * @param method the request method (may be null) + * @param requestURI the request URI (may be null) + * @see #setMethod + * @see #setRequestURI + * @see MockServletContext + */ + public MockHttpServletRequest(ServletContext servletContext, String method, String requestURI) { + this.servletContext = (servletContext != null ? servletContext : new MockServletContext()); + this.method = method; + this.requestURI = requestURI; + this.locales.add(Locale.ENGLISH); + } + + + //--------------------------------------------------------------------- + // Lifecycle methods + //--------------------------------------------------------------------- + + /** + * Return the ServletContext that this request is associated with. + * (Not available in the standard HttpServletRequest interface for some reason.) + */ + public ServletContext getServletContext() { + return this.servletContext; + } + + /** + * Return whether this request is still active (that is, not completed yet). + */ + public boolean isActive() { + return this.active; + } + + /** + * Mark this request as completed, keeping its state. + */ + public void close() { + this.active = false; + } + + /** + * Invalidate this request, clearing its state. + */ + public void invalidate() { + close(); + clearAttributes(); + } + + /** + * Check whether this request is still active (that is, not completed yet), + * throwing an IllegalStateException if not active anymore. + */ + protected void checkActive() throws IllegalStateException { + if (!this.active) { + throw new IllegalStateException("Request is not active anymore"); + } + } + + + //--------------------------------------------------------------------- + // ServletRequest interface + //--------------------------------------------------------------------- + + public Object getAttribute(String name) { + checkActive(); + return this.attributes.get(name); + } + + public Enumeration getAttributeNames() { + checkActive(); + return this.attributes.keys(); + } + + public String getCharacterEncoding() { + return this.characterEncoding; + } + + public void setCharacterEncoding(String characterEncoding) { + this.characterEncoding = characterEncoding; + } + + public void setContent(byte[] content) { + this.content = content; + } + + public int getContentLength() { + return (this.content != null ? this.content.length : -1); + } + + public void setContentType(String contentType) { + this.contentType = contentType; + } + + public String getContentType() { + return this.contentType; + } + + public ServletInputStream getInputStream() { + if (this.content != null) { + return new DelegatingServletInputStream(new ByteArrayInputStream(this.content)); + } + else { + return null; + } + } + + /** + * Set a single value for the specified HTTP parameter. + *

If there are already one or more values registered for the given + * parameter name, they will be replaced. + */ + public void setParameter(String name, String value) { + setParameter(name, new String[] {value}); + } + + /** + * Set an array of values for the specified HTTP parameter. + *

If there are already one or more values registered for the given + * parameter name, they will be replaced. + */ + public void setParameter(String name, String[] values) { + Assert.notNull(name, "Parameter name must not be null"); + this.parameters.put(name, values); + } + + /** + * Sets all provided parameters replacing any + * existing values for the provided parameter names. To add without + * replacing existing values, use {@link #addParameters(java.util.Map)}. + */ + public void setParameters(Map params) { + Assert.notNull(params, "Parameter map must not be null"); + for (Object key : params.keySet()) { + Assert.isInstanceOf(String.class, key, + "Parameter map key must be of type [" + String.class.getName() + "]"); + Object value = params.get(key); + if (value instanceof String) { + this.setParameter((String) key, (String) value); + } + else if (value instanceof String[]) { + this.setParameter((String) key, (String[]) value); + } + else { + throw new IllegalArgumentException( + "Parameter map value must be single value " + " or array of type [" + String.class.getName() + + "]"); + } + } + } + + /** + * Add a single value for the specified HTTP parameter. + *

If there are already one or more values registered for the given + * parameter name, the given value will be added to the end of the list. + */ + public void addParameter(String name, String value) { + addParameter(name, new String[] {value}); + } + + /** + * Add an array of values for the specified HTTP parameter. + *

If there are already one or more values registered for the given + * parameter name, the given values will be added to the end of the list. + */ + public void addParameter(String name, String[] values) { + Assert.notNull(name, "Parameter name must not be null"); + String[] oldArr = this.parameters.get(name); + if (oldArr != null) { + String[] newArr = new String[oldArr.length + values.length]; + System.arraycopy(oldArr, 0, newArr, 0, oldArr.length); + System.arraycopy(values, 0, newArr, oldArr.length, values.length); + this.parameters.put(name, newArr); + } + else { + this.parameters.put(name, values); + } + } + + /** + * Adds all provided parameters without replacing + * any existing values. To replace existing values, use + * {@link #setParameters(java.util.Map)}. + */ + public void addParameters(Map params) { + Assert.notNull(params, "Parameter map must not be null"); + for (Object key : params.keySet()) { + Assert.isInstanceOf(String.class, key, + "Parameter map key must be of type [" + String.class.getName() + "]"); + Object value = params.get(key); + if (value instanceof String) { + this.addParameter((String) key, (String) value); + } + else if (value instanceof String[]) { + this.addParameter((String) key, (String[]) value); + } + else { + throw new IllegalArgumentException("Parameter map value must be single value " + + " or array of type [" + String.class.getName() + "]"); + } + } + } + + /** + * Remove already registered values for the specified HTTP parameter, if any. + */ + public void removeParameter(String name) { + Assert.notNull(name, "Parameter name must not be null"); + this.parameters.remove(name); + } + + /** + * Removes all existing parameters. + */ + public void removeAllParameters() { + this.parameters.clear(); + } + + public String getParameter(String name) { + Assert.notNull(name, "Parameter name must not be null"); + String[] arr = this.parameters.get(name); + return (arr != null && arr.length > 0 ? arr[0] : null); + } + + public Enumeration getParameterNames() { + return Collections.enumeration(this.parameters.keySet()); + } + + public String[] getParameterValues(String name) { + Assert.notNull(name, "Parameter name must not be null"); + return this.parameters.get(name); + } + + public Map getParameterMap() { + return Collections.unmodifiableMap(this.parameters); + } + + public void setProtocol(String protocol) { + this.protocol = protocol; + } + + public String getProtocol() { + return this.protocol; + } + + public void setScheme(String scheme) { + this.scheme = scheme; + } + + public String getScheme() { + return this.scheme; + } + + public void setServerName(String serverName) { + this.serverName = serverName; + } + + public String getServerName() { + return this.serverName; + } + + public void setServerPort(int serverPort) { + this.serverPort = serverPort; + } + + public int getServerPort() { + return this.serverPort; + } + + public BufferedReader getReader() throws UnsupportedEncodingException { + if (this.content != null) { + InputStream sourceStream = new ByteArrayInputStream(this.content); + Reader sourceReader = (this.characterEncoding != null) ? + new InputStreamReader(sourceStream, this.characterEncoding) : new InputStreamReader(sourceStream); + return new BufferedReader(sourceReader); + } + else { + return null; + } + } + + public void setRemoteAddr(String remoteAddr) { + this.remoteAddr = remoteAddr; + } + + public String getRemoteAddr() { + return this.remoteAddr; + } + + public void setRemoteHost(String remoteHost) { + this.remoteHost = remoteHost; + } + + public String getRemoteHost() { + return this.remoteHost; + } + + public void setAttribute(String name, Object value) { + checkActive(); + Assert.notNull(name, "Attribute name must not be null"); + if (value != null) { + this.attributes.put(name, value); + } + else { + this.attributes.remove(name); + } + } + + public void removeAttribute(String name) { + checkActive(); + Assert.notNull(name, "Attribute name must not be null"); + this.attributes.remove(name); + } + + /** + * Clear all of this request's attributes. + */ + public void clearAttributes() { + this.attributes.clear(); + } + + /** + * Add a new preferred locale, before any existing locales. + */ + public void addPreferredLocale(Locale locale) { + Assert.notNull(locale, "Locale must not be null"); + this.locales.add(0, locale); + } + + public Locale getLocale() { + return (Locale) this.locales.get(0); + } + + public Enumeration getLocales() { + return this.locales.elements(); + } + + public void setSecure(boolean secure) { + this.secure = secure; + } + + public boolean isSecure() { + return this.secure; + } + + public RequestDispatcher getRequestDispatcher(String path) { + return new MockRequestDispatcher(path); + } + + public String getRealPath(String path) { + return this.servletContext.getRealPath(path); + } + + public void setRemotePort(int remotePort) { + this.remotePort = remotePort; + } + + public int getRemotePort() { + return this.remotePort; + } + + public void setLocalName(String localName) { + this.localName = localName; + } + + public String getLocalName() { + return this.localName; + } + + public void setLocalAddr(String localAddr) { + this.localAddr = localAddr; + } + + public String getLocalAddr() { + return this.localAddr; + } + + public void setLocalPort(int localPort) { + this.localPort = localPort; + } + + public int getLocalPort() { + return this.localPort; + } + + + //--------------------------------------------------------------------- + // HttpServletRequest interface + //--------------------------------------------------------------------- + + public void setAuthType(String authType) { + this.authType = authType; + } + + public String getAuthType() { + return this.authType; + } + + public void setCookies(Cookie[] cookies) { + this.cookies = cookies; + } + + public Cookie[] getCookies() { + return this.cookies; + } + + /** + * Add a header entry for the given name. + *

If there was no entry for that header name before, + * the value will be used as-is. In case of an existing entry, + * a String array will be created, adding the given value (more + * specifically, its toString representation) as further element. + *

Multiple values can only be stored as list of Strings, + * following the Servlet spec (see getHeaders accessor). + * As alternative to repeated addHeader calls for + * individual elements, you can use a single call with an entire + * array or Collection of values as parameter. + * @see #getHeaderNames + * @see #getHeader + * @see #getHeaders + * @see #getDateHeader + * @see #getIntHeader + */ + public void addHeader(String name, Object value) { + HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name); + Assert.notNull(value, "Header value must not be null"); + if (header == null) { + header = new HeaderValueHolder(); + this.headers.put(name, header); + } + if (value instanceof Collection) { + header.addValues((Collection) value); + } + else if (value.getClass().isArray()) { + header.addValueArray(value); + } + else { + header.addValue(value); + } + } + + public long getDateHeader(String name) { + HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name); + Object value = (header != null ? header.getValue() : null); + if (value instanceof Date) { + return ((Date) value).getTime(); + } + else if (value instanceof Number) { + return ((Number) value).longValue(); + } + else if (value != null) { + throw new IllegalArgumentException( + "Value for header '" + name + "' is neither a Date nor a Number: " + value); + } + else { + return -1L; + } + } + + public String getHeader(String name) { + HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name); + return (header != null ? header.getValue().toString() : null); + } + + public Enumeration getHeaders(String name) { + HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name); + return Collections.enumeration(header != null ? header.getValues() : Collections.EMPTY_LIST); + } + + public Enumeration getHeaderNames() { + return this.headers.keys(); + } + + public int getIntHeader(String name) { + HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name); + Object value = (header != null ? header.getValue() : null); + if (value instanceof Number) { + return ((Number) value).intValue(); + } + else if (value instanceof String) { + return Integer.parseInt((String) value); + } + else if (value != null) { + throw new NumberFormatException("Value for header '" + name + "' is not a Number: " + value); + } + else { + return -1; + } + } + + public void setMethod(String method) { + this.method = method; + } + + public String getMethod() { + return this.method; + } + + public void setPathInfo(String pathInfo) { + this.pathInfo = pathInfo; + } + + public String getPathInfo() { + return this.pathInfo; + } + + public String getPathTranslated() { + return (this.pathInfo != null ? getRealPath(this.pathInfo) : null); + } + + public void setContextPath(String contextPath) { + this.contextPath = contextPath; + } + + public String getContextPath() { + return this.contextPath; + } + + public void setQueryString(String queryString) { + this.queryString = queryString; + } + + public String getQueryString() { + return this.queryString; + } + + public void setRemoteUser(String remoteUser) { + this.remoteUser = remoteUser; + } + + public String getRemoteUser() { + return this.remoteUser; + } + + public void addUserRole(String role) { + this.userRoles.add(role); + } + + public boolean isUserInRole(String role) { + return this.userRoles.contains(role); + } + + public void setUserPrincipal(Principal userPrincipal) { + this.userPrincipal = userPrincipal; + } + + public Principal getUserPrincipal() { + return this.userPrincipal; + } + + public String getRequestedSessionId() { + HttpSession session = getSession(); + return (session != null ? session.getId() : null); + } + + public void setRequestURI(String requestURI) { + this.requestURI = requestURI; + } + + public String getRequestURI() { + return this.requestURI; + } + + public StringBuffer getRequestURL() { + StringBuffer url = new StringBuffer(this.scheme); + url.append("://").append(this.serverName).append(':').append(this.serverPort); + url.append(getRequestURI()); + return url; + } + + public void setServletPath(String servletPath) { + this.servletPath = servletPath; + } + + public String getServletPath() { + return this.servletPath; + } + + public void setSession(HttpSession session) { + this.session = session; + if (session instanceof MockHttpSession) { + MockHttpSession mockSession = ((MockHttpSession) session); + mockSession.access(); + } + } + + public HttpSession getSession(boolean create) { + checkActive(); + // Reset session if invalidated. + if (this.session instanceof MockHttpSession && ((MockHttpSession) this.session).isInvalid()) { + this.session = null; + } + // Create new session if necessary. + if (this.session == null && create) { + this.session = new MockHttpSession(this.servletContext); + } + return this.session; + } + + public HttpSession getSession() { + return getSession(true); + } + + public void setRequestedSessionIdValid(boolean requestedSessionIdValid) { + this.requestedSessionIdValid = requestedSessionIdValid; + } + + public boolean isRequestedSessionIdValid() { + return this.requestedSessionIdValid; + } + + public void setRequestedSessionIdFromCookie(boolean requestedSessionIdFromCookie) { + this.requestedSessionIdFromCookie = requestedSessionIdFromCookie; + } + + public boolean isRequestedSessionIdFromCookie() { + return this.requestedSessionIdFromCookie; + } + + public void setRequestedSessionIdFromURL(boolean requestedSessionIdFromURL) { + this.requestedSessionIdFromURL = requestedSessionIdFromURL; + } + + public boolean isRequestedSessionIdFromURL() { + return this.requestedSessionIdFromURL; + } + + public boolean isRequestedSessionIdFromUrl() { + return isRequestedSessionIdFromURL(); + } + +} diff --git a/org.springframework.transaction/src/test/java/org/springframework/mock/jndi/ExpectedLookupTemplate.java b/org.springframework.transaction/src/test/java/org/springframework/mock/jndi/ExpectedLookupTemplate.java new file mode 100644 index 00000000000..28670fd4383 --- /dev/null +++ b/org.springframework.transaction/src/test/java/org/springframework/mock/jndi/ExpectedLookupTemplate.java @@ -0,0 +1,82 @@ +/* + * 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.mock.jndi; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import javax.naming.NamingException; + +import org.springframework.core.CollectionFactory; +import org.springframework.jndi.JndiTemplate; + +/** + * Simple extension of the JndiTemplate class that always returns + * a given object. Very useful for testing. Effectively a mock object. + * + * @author Rod Johnson + * @author Juergen Hoeller + */ +public class ExpectedLookupTemplate extends JndiTemplate { + + private final Map jndiObjects = new ConcurrentHashMap(); + + + /** + * Construct a new JndiTemplate that will always return given objects + * for given names. To be populated through addObject calls. + * @see #addObject(String, Object) + */ + public ExpectedLookupTemplate() { + } + + /** + * Construct a new JndiTemplate that will always return the + * given object, but honour only requests for the given name. + * @param name the name the client is expected to look up + * @param object the object that will be returned + */ + public ExpectedLookupTemplate(String name, Object object) { + addObject(name, object); + } + + + /** + * Add the given object to the list of JNDI objects that this + * template will expose. + * @param name the name the client is expected to look up + * @param object the object that will be returned + */ + public void addObject(String name, Object object) { + this.jndiObjects.put(name, object); + } + + + /** + * If the name is the expected name specified in the constructor, + * return the object provided in the constructor. If the name is + * unexpected, a respective NamingException gets thrown. + */ + public Object lookup(String name) throws NamingException { + Object object = this.jndiObjects.get(name); + if (object == null) { + throw new NamingException("Unexpected JNDI name '" + name + "': expecting " + this.jndiObjects.keySet()); + } + return object; + } + +} diff --git a/org.springframework.transaction/src/test/java/org/springframework/mock/jndi/SimpleNamingContext.java b/org.springframework.transaction/src/test/java/org/springframework/mock/jndi/SimpleNamingContext.java new file mode 100644 index 00000000000..b6489e42029 --- /dev/null +++ b/org.springframework.transaction/src/test/java/org/springframework/mock/jndi/SimpleNamingContext.java @@ -0,0 +1,345 @@ +/* + * 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.mock.jndi; + +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; +import javax.naming.Binding; +import javax.naming.Context; +import javax.naming.Name; +import javax.naming.NameClassPair; +import javax.naming.NameNotFoundException; +import javax.naming.NameParser; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.OperationNotSupportedException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.util.StringUtils; + +/** + * Simple implementation of a JNDI naming context. + * Only supports binding plain Objects to String names. + * Mainly for test environments, but also usable for standalone applications. + * + *

This class is not intended for direct usage by applications, although it + * can be used for example to override JndiTemplate's createInitialContext + * method in unit tests. Typically, SimpleNamingContextBuilder will be used to + * set up a JVM-level JNDI environment. + * + * @author Rod Johnson + * @author Juergen Hoeller + * @see org.springframework.mock.jndi.SimpleNamingContextBuilder + * @see org.springframework.jndi.JndiTemplate#createInitialContext + */ +public class SimpleNamingContext implements Context { + + private final Log logger = LogFactory.getLog(getClass()); + + private final String root; + + private final Hashtable boundObjects; + + private final Hashtable environment = new Hashtable(); + + + /** + * Create a new naming context. + */ + public SimpleNamingContext() { + this(""); + } + + /** + * Create a new naming context with the given naming root. + */ + public SimpleNamingContext(String root) { + this.root = root; + this.boundObjects = new Hashtable(); + } + + /** + * Create a new naming context with the given naming root, + * the given name/object map, and the JNDI environment entries. + */ + public SimpleNamingContext(String root, Hashtable boundObjects, Hashtable env) { + this.root = root; + this.boundObjects = boundObjects; + if (env != null) { + this.environment.putAll(env); + } + } + + + // Actual implementations of Context methods follow + + public NamingEnumeration list(String root) throws NamingException { + if (logger.isDebugEnabled()) { + logger.debug("Listing name/class pairs under [" + root + "]"); + } + return new NameClassPairEnumeration(this, root); + } + + public NamingEnumeration listBindings(String root) throws NamingException { + if (logger.isDebugEnabled()) { + logger.debug("Listing bindings under [" + root + "]"); + } + return new BindingEnumeration(this, root); + } + + /** + * Look up the object with the given name. + *

Note: Not intended for direct use by applications. + * Will be used by any standard InitialContext JNDI lookups. + * @throws javax.naming.NameNotFoundException if the object could not be found + */ + public Object lookup(String lookupName) throws NameNotFoundException { + String name = this.root + lookupName; + if (logger.isDebugEnabled()) { + logger.debug("Static JNDI lookup: [" + name + "]"); + } + if ("".equals(name)) { + return new SimpleNamingContext(this.root, this.boundObjects, this.environment); + } + Object found = this.boundObjects.get(name); + if (found == null) { + if (!name.endsWith("/")) { + name = name + "/"; + } + for (String boundName : this.boundObjects.keySet()) { + if (boundName.startsWith(name)) { + return new SimpleNamingContext(name, this.boundObjects, this.environment); + } + } + throw new NameNotFoundException( + "Name [" + this.root + lookupName + "] not bound; " + this.boundObjects.size() + " bindings: [" + + StringUtils.collectionToDelimitedString(this.boundObjects.keySet(), ",") + "]"); + } + return found; + } + + public Object lookupLink(String name) throws NameNotFoundException { + return lookup(name); + } + + /** + * Bind the given object to the given name. + * Note: Not intended for direct use by applications + * if setting up a JVM-level JNDI environment. + * Use SimpleNamingContextBuilder to set up JNDI bindings then. + * @see org.springframework.mock.jndi.SimpleNamingContextBuilder#bind + */ + public void bind(String name, Object obj) { + if (logger.isInfoEnabled()) { + logger.info("Static JNDI binding: [" + this.root + name + "] = [" + obj + "]"); + } + this.boundObjects.put(this.root + name, obj); + } + + public void unbind(String name) { + if (logger.isInfoEnabled()) { + logger.info("Static JNDI remove: [" + this.root + name + "]"); + } + this.boundObjects.remove(this.root + name); + } + + public void rebind(String name, Object obj) { + bind(name, obj); + } + + public void rename(String oldName, String newName) throws NameNotFoundException { + Object obj = lookup(oldName); + unbind(oldName); + bind(newName, obj); + } + + public Context createSubcontext(String name) { + String subcontextName = this.root + name; + if (!subcontextName.endsWith("/")) { + subcontextName += "/"; + } + Context subcontext = new SimpleNamingContext(subcontextName, this.boundObjects, this.environment); + bind(name, subcontext); + return subcontext; + } + + public void destroySubcontext(String name) { + unbind(name); + } + + public String composeName(String name, String prefix) { + return prefix + name; + } + + public Hashtable getEnvironment() { + return this.environment; + } + + public Object addToEnvironment(String propName, Object propVal) { + return this.environment.put(propName, propVal); + } + + public Object removeFromEnvironment(String propName) { + return this.environment.remove(propName); + } + + public void close() { + } + + + // Unsupported methods follow: no support for javax.naming.Name + + public NamingEnumeration list(Name name) throws NamingException { + throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); + } + + public NamingEnumeration listBindings(Name name) throws NamingException { + throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); + } + + public Object lookup(Name name) throws NamingException { + throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); + } + + public Object lookupLink(Name name) throws NamingException { + throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); + } + + public void bind(Name name, Object obj) throws NamingException { + throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); + } + + public void unbind(Name name) throws NamingException { + throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); + } + + public void rebind(Name name, Object obj) throws NamingException { + throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); + } + + public void rename(Name oldName, Name newName) throws NamingException { + throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); + } + + public Context createSubcontext(Name name) throws NamingException { + throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); + } + + public void destroySubcontext(Name name) throws NamingException { + throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); + } + + public String getNameInNamespace() throws NamingException { + throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); + } + + public NameParser getNameParser(Name name) throws NamingException { + throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); + } + + public NameParser getNameParser(String name) throws NamingException { + throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); + } + + public Name composeName(Name name, Name prefix) throws NamingException { + throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]"); + } + + + private static abstract class AbstractNamingEnumeration implements NamingEnumeration { + + private Iterator iterator; + + private AbstractNamingEnumeration(SimpleNamingContext context, String proot) throws NamingException { + if (!"".equals(proot) && !proot.endsWith("/")) { + proot = proot + "/"; + } + String root = context.root + proot; + Map contents = new HashMap(); + for (String boundName : context.boundObjects.keySet()) { + if (boundName.startsWith(root)) { + int startIndex = root.length(); + int endIndex = boundName.indexOf('/', startIndex); + String strippedName = + (endIndex != -1 ? boundName.substring(startIndex, endIndex) : boundName.substring(startIndex)); + if (!contents.containsKey(strippedName)) { + try { + contents.put(strippedName, createObject(strippedName, context.lookup(proot + strippedName))); + } + catch (NameNotFoundException ex) { + // cannot happen + } + } + } + } + if (contents.size() == 0) { + throw new NamingException("Invalid root: [" + context.root + proot + "]"); + } + this.iterator = contents.values().iterator(); + } + + protected abstract T createObject(String strippedName, Object obj); + + public boolean hasMore() { + return this.iterator.hasNext(); + } + + public T next() { + return this.iterator.next(); + } + + public boolean hasMoreElements() { + return this.iterator.hasNext(); + } + + public T nextElement() { + return this.iterator.next(); + } + + public void close() { + } + } + + + private static class NameClassPairEnumeration extends AbstractNamingEnumeration { + + private NameClassPairEnumeration(SimpleNamingContext context, String root) throws NamingException { + super(context, root); + } + + protected NameClassPair createObject(String strippedName, Object obj) { + return new NameClassPair(strippedName, obj.getClass().getName()); + } + } + + + private static class BindingEnumeration extends AbstractNamingEnumeration { + + private BindingEnumeration(SimpleNamingContext context, String root) throws NamingException { + super(context, root); + } + + protected Binding createObject(String strippedName, Object obj) { + return new Binding(strippedName, obj); + } + } + +} diff --git a/org.springframework.transaction/src/test/java/org/springframework/mock/jndi/SimpleNamingContextBuilder.java b/org.springframework.transaction/src/test/java/org/springframework/mock/jndi/SimpleNamingContextBuilder.java new file mode 100644 index 00000000000..130de79de5e --- /dev/null +++ b/org.springframework.transaction/src/test/java/org/springframework/mock/jndi/SimpleNamingContextBuilder.java @@ -0,0 +1,234 @@ +/* + * 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.mock.jndi; + +import java.util.Hashtable; + +import javax.naming.Context; +import javax.naming.NamingException; +import javax.naming.spi.InitialContextFactory; +import javax.naming.spi.InitialContextFactoryBuilder; +import javax.naming.spi.NamingManager; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.util.ClassUtils; + +/** + * Simple implementation of a JNDI naming context builder. + * + *

Mainly targeted at test environments, where each test case can + * configure JNDI appropriately, so that new InitialContext() + * will expose the required objects. Also usable for standalone applications, + * e.g. for binding a JDBC DataSource to a well-known JNDI location, to be + * able to use traditional J2EE data access code outside of a J2EE container. + * + *

There are various choices for DataSource implementations: + *

    + *
  • SingleConnectionDataSource (using the same Connection for all getConnection calls); + *
  • DriverManagerDataSource (creating a new Connection on each getConnection call); + *
  • Apache's Jakarta Commons DBCP offers BasicDataSource (a real pool). + *
+ * + *

Typical usage in bootstrap code: + * + *

+ * SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder();
+ * DataSource ds = new DriverManagerDataSource(...);
+ * builder.bind("java:comp/env/jdbc/myds", ds);
+ * builder.activate();
+ * + * Note that it's impossible to activate multiple builders within the same JVM, + * due to JNDI restrictions. Thus to configure a fresh builder repeatedly, use + * the following code to get a reference to either an already activated builder + * or a newly activated one: + * + *
+ * SimpleNamingContextBuilder builder = SimpleNamingContextBuilder.emptyActivatedContextBuilder();
+ * DataSource ds = new DriverManagerDataSource(...);
+ * builder.bind("java:comp/env/jdbc/myds", ds);
+ * + * Note that you should not call activate() on a builder from + * this factory method, as there will already be an activated one in any case. + * + *

An instance of this class is only necessary at setup time. + * An application does not need to keep a reference to it after activation. + * + * @author Juergen Hoeller + * @author Rod Johnson + * @see #emptyActivatedContextBuilder() + * @see #bind(String, Object) + * @see #activate() + * @see org.springframework.mock.jndi.SimpleNamingContext + * @see org.springframework.jdbc.datasource.SingleConnectionDataSource + * @see org.springframework.jdbc.datasource.DriverManagerDataSource + * @see org.apache.commons.dbcp.BasicDataSource + */ +public class SimpleNamingContextBuilder implements InitialContextFactoryBuilder { + + /** An instance of this class bound to JNDI */ + private static volatile SimpleNamingContextBuilder activated; + + private static boolean initialized = false; + + private static final Object initializationLock = new Object(); + + + /** + * Checks if a SimpleNamingContextBuilder is active. + * @return the current SimpleNamingContextBuilder instance, + * or null if none + */ + public static SimpleNamingContextBuilder getCurrentContextBuilder() { + return activated; + } + + /** + * If no SimpleNamingContextBuilder is already configuring JNDI, + * create and activate one. Otherwise take the existing activate + * SimpleNamingContextBuilder, clear it and return it. + *

This is mainly intended for test suites that want to + * reinitialize JNDI bindings from scratch repeatedly. + * @return an empty SimpleNamingContextBuilder that can be used + * to control JNDI bindings + */ + public static SimpleNamingContextBuilder emptyActivatedContextBuilder() throws NamingException { + if (activated != null) { + // Clear already activated context builder. + activated.clear(); + } + else { + // Create and activate new context builder. + SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder(); + // The activate() call will cause an assigment to the activated variable. + builder.activate(); + } + return activated; + } + + + private final Log logger = LogFactory.getLog(getClass()); + + private final Hashtable boundObjects = new Hashtable(); + + + /** + * Register the context builder by registering it with the JNDI NamingManager. + * Note that once this has been done, new InitialContext() will always + * return a context from this factory. Use the emptyActivatedContextBuilder() + * static method to get an empty context (for example, in test methods). + * @throws IllegalStateException if there's already a naming context builder + * registered with the JNDI NamingManager + */ + public void activate() throws IllegalStateException, NamingException { + logger.info("Activating simple JNDI environment"); + synchronized (initializationLock) { + if (!initialized) { + if (NamingManager.hasInitialContextFactoryBuilder()) { + throw new IllegalStateException( + "Cannot activate SimpleNamingContextBuilder: there is already a JNDI provider registered. " + + "Note that JNDI is a JVM-wide service, shared at the JVM system class loader level, " + + "with no reset option. As a consequence, a JNDI provider must only be registered once per JVM."); + } + NamingManager.setInitialContextFactoryBuilder(this); + initialized = true; + } + } + activated = this; + } + + /** + * Temporarily deactivate this context builder. It will remain registered with + * the JNDI NamingManager but will delegate to the standard JNDI InitialContextFactory + * (if configured) instead of exposing its own bound objects. + *

Call activate() again in order to expose this contexz builder's own + * bound objects again. Such activate/deactivate sequences can be applied any number + * of times (e.g. within a larger integration test suite running in the same VM). + * @see #activate() + */ + public void deactivate() { + logger.info("Deactivating simple JNDI environment"); + activated = null; + } + + /** + * Clear all bindings in this context builder, while keeping it active. + */ + public void clear() { + this.boundObjects.clear(); + } + + /** + * Bind the given object under the given name, for all naming contexts + * that this context builder will generate. + * @param name the JNDI name of the object (e.g. "java:comp/env/jdbc/myds") + * @param obj the object to bind (e.g. a DataSource implementation) + */ + public void bind(String name, Object obj) { + if (logger.isInfoEnabled()) { + logger.info("Static JNDI binding: [" + name + "] = [" + obj + "]"); + } + this.boundObjects.put(name, obj); + } + + + /** + * Simple InitialContextFactoryBuilder implementation, + * creating a new SimpleNamingContext instance. + * @see SimpleNamingContext + */ + public InitialContextFactory createInitialContextFactory(Hashtable environment) { + if (activated == null && environment != null) { + Object icf = environment.get(Context.INITIAL_CONTEXT_FACTORY); + if (icf != null) { + Class icfClass = null; + if (icf instanceof Class) { + icfClass = (Class) icf; + } + else if (icf instanceof String) { + icfClass = ClassUtils.resolveClassName((String) icf, getClass().getClassLoader()); + } + else { + throw new IllegalArgumentException("Invalid value type for environment key [" + + Context.INITIAL_CONTEXT_FACTORY + "]: " + icf.getClass().getName()); + } + if (!InitialContextFactory.class.isAssignableFrom(icfClass)) { + throw new IllegalArgumentException( + "Specified class does not implement [" + InitialContextFactory.class.getName() + "]: " + icf); + } + try { + return (InitialContextFactory) icfClass.newInstance(); + } + catch (Throwable ex) { + IllegalStateException ise = + new IllegalStateException("Cannot instantiate specified InitialContextFactory: " + icf); + ise.initCause(ex); + throw ise; + } + } + } + + // Default case... + return new InitialContextFactory() { + public Context getInitialContext(Hashtable environment) { + return new SimpleNamingContext("", boundObjects, environment); + } + }; + } + +} diff --git a/org.springframework.transaction/src/test/java/org/springframework/transaction/jta/WebSphereUowTransactionManagerTests.java b/org.springframework.transaction/src/test/java/org/springframework/transaction/jta/WebSphereUowTransactionManagerTests.java index 8c80f0f0131..91adf3f4cde 100644 --- a/org.springframework.transaction/src/test/java/org/springframework/transaction/jta/WebSphereUowTransactionManagerTests.java +++ b/org.springframework.transaction/src/test/java/org/springframework/transaction/jta/WebSphereUowTransactionManagerTests.java @@ -20,12 +20,9 @@ import javax.transaction.RollbackException; import javax.transaction.Status; import javax.transaction.UserTransaction; -import com.ibm.wsspi.uow.UOWAction; -import com.ibm.wsspi.uow.UOWException; -import com.ibm.wsspi.uow.UOWManager; import junit.framework.TestCase; -import org.easymock.MockControl; +import org.easymock.MockControl; import org.springframework.dao.OptimisticLockingFailureException; import org.springframework.mock.jndi.ExpectedLookupTemplate; import org.springframework.transaction.IllegalTransactionStateException; @@ -37,6 +34,10 @@ import org.springframework.transaction.support.DefaultTransactionDefinition; import org.springframework.transaction.support.TransactionCallback; import org.springframework.transaction.support.TransactionSynchronizationManager; +import com.ibm.wsspi.uow.UOWAction; +import com.ibm.wsspi.uow.UOWException; +import com.ibm.wsspi.uow.UOWManager; + /** * @author Juergen Hoeller */ diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockActionRequest.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockActionRequest.java new file mode 100644 index 00000000000..e85da537d15 --- /dev/null +++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockActionRequest.java @@ -0,0 +1,131 @@ +/* + * 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.mock.web.portlet; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.UnsupportedEncodingException; + +import javax.portlet.ActionRequest; +import javax.portlet.PortalContext; +import javax.portlet.PortletContext; +import javax.portlet.PortletMode; + +/** + * Mock implementation of the {@link javax.portlet.ActionRequest} interface. + * + * @author John A. Lewis + * @author Juergen Hoeller + * @since 2.0 + */ +public class MockActionRequest extends MockPortletRequest implements ActionRequest { + + private String characterEncoding; + + private byte[] content; + + private String contentType; + + + /** + * Create a new MockActionRequest with a default {@link MockPortalContext} + * and a default {@link MockPortletContext}. + * @see MockPortalContext + * @see MockPortletContext + */ + public MockActionRequest() { + super(); + } + + /** + * Create a new MockActionRequest with a default {@link MockPortalContext} + * and a default {@link MockPortletContext}. + * @param portletMode the mode that the portlet runs in + */ + public MockActionRequest(PortletMode portletMode) { + super(); + setPortletMode(portletMode); + } + + /** + * Create a new MockActionRequest with a default {@link MockPortalContext}. + * @param portletContext the PortletContext that the request runs in + */ + public MockActionRequest(PortletContext portletContext) { + super(portletContext); + } + + /** + * Create a new MockActionRequest. + * @param portalContext the PortalContext that the request runs in + * @param portletContext the PortletContext that the request runs in + */ + public MockActionRequest(PortalContext portalContext, PortletContext portletContext) { + super(portalContext, portletContext); + } + + + public void setContent(byte[] content) { + this.content = content; + } + + public InputStream getPortletInputStream() throws IOException { + if (this.content != null) { + return new ByteArrayInputStream(this.content); + } + else { + return null; + } + } + + public void setCharacterEncoding(String characterEncoding) { + this.characterEncoding = characterEncoding; + } + + public BufferedReader getReader() throws UnsupportedEncodingException { + if (this.content != null) { + InputStream sourceStream = new ByteArrayInputStream(this.content); + Reader sourceReader = (this.characterEncoding != null) ? + new InputStreamReader(sourceStream, this.characterEncoding) : new InputStreamReader(sourceStream); + return new BufferedReader(sourceReader); + } + else { + return null; + } + } + + public String getCharacterEncoding() { + return characterEncoding; + } + + public void setContentType(String contentType) { + this.contentType = contentType; + } + + public String getContentType() { + return contentType; + } + + public int getContentLength() { + return (this.content != null ? content.length : -1); + } + +} diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockActionResponse.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockActionResponse.java new file mode 100644 index 00000000000..e608e81c49f --- /dev/null +++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockActionResponse.java @@ -0,0 +1,163 @@ +/* + * 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.mock.web.portlet; + +import java.io.IOException; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import javax.portlet.ActionResponse; +import javax.portlet.PortalContext; +import javax.portlet.PortletMode; +import javax.portlet.PortletModeException; +import javax.portlet.WindowState; +import javax.portlet.WindowStateException; + +import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; + +/** + * Mock implementation of the {@link javax.portlet.ActionResponse} interface. + * + * @author John A. Lewis + * @author Juergen Hoeller + * @since 2.0 + */ +public class MockActionResponse extends MockPortletResponse implements ActionResponse { + + private WindowState windowState; + + private PortletMode portletMode; + + private String redirectedUrl; + + private final Map renderParameters = new LinkedHashMap(); + + + /** + * Create a new MockActionResponse with a default {@link MockPortalContext}. + * @see MockPortalContext + */ + public MockActionResponse() { + super(); + } + + /** + * Create a new MockActionResponse. + * @param portalContext the PortalContext defining the supported + * PortletModes and WindowStates + */ + public MockActionResponse(PortalContext portalContext) { + super(portalContext); + } + + + public void setWindowState(WindowState windowState) throws WindowStateException { + if (this.redirectedUrl != null) { + throw new IllegalStateException("Cannot set WindowState after sendRedirect has been called"); + } + if (!CollectionUtils.contains(getPortalContext().getSupportedWindowStates(), windowState)) { + throw new WindowStateException("WindowState not supported", windowState); + } + this.windowState = windowState; + } + + public WindowState getWindowState() { + return windowState; + } + + public void setPortletMode(PortletMode portletMode) throws PortletModeException { + if (this.redirectedUrl != null) { + throw new IllegalStateException("Cannot set PortletMode after sendRedirect has been called"); + } + if (!CollectionUtils.contains(getPortalContext().getSupportedPortletModes(), portletMode)) { + throw new PortletModeException("PortletMode not supported", portletMode); + } + this.portletMode = portletMode; + } + + public PortletMode getPortletMode() { + return portletMode; + } + + public void sendRedirect(String url) throws IOException { + if (this.windowState != null || this.portletMode != null || !this.renderParameters.isEmpty()) { + throw new IllegalStateException( + "Cannot call sendRedirect after windowState, portletMode, or renderParameters have been set"); + } + Assert.notNull(url, "Redirect URL must not be null"); + this.redirectedUrl = url; + } + + public String getRedirectedUrl() { + return redirectedUrl; + } + + public void setRenderParameters(Map parameters) { + if (this.redirectedUrl != null) { + throw new IllegalStateException("Cannot set render parameters after sendRedirect has been called"); + } + Assert.notNull(parameters, "Parameters Map must not be null"); + this.renderParameters.clear(); + for (Iterator it = parameters.entrySet().iterator(); it.hasNext();) { + Map.Entry entry = (Map.Entry) it.next(); + Assert.isTrue(entry.getKey() instanceof String, "Key must be of type String"); + Assert.isTrue(entry.getValue() instanceof String[], "Value must be of type String[]"); + this.renderParameters.put((String) entry.getKey(), (String[]) entry.getValue()); + } + } + + public void setRenderParameter(String key, String value) { + if (this.redirectedUrl != null) { + throw new IllegalStateException("Cannot set render parameters after sendRedirect has been called"); + } + Assert.notNull(key, "Parameter key must not be null"); + Assert.notNull(value, "Parameter value must not be null"); + this.renderParameters.put(key, new String[] {value}); + } + + public String getRenderParameter(String key) { + Assert.notNull(key, "Parameter key must not be null"); + String[] arr = this.renderParameters.get(key); + return (arr != null && arr.length > 0 ? arr[0] : null); + } + + public void setRenderParameter(String key, String[] values) { + if (this.redirectedUrl != null) { + throw new IllegalStateException("Cannot set render parameters after sendRedirect has been called"); + } + Assert.notNull(key, "Parameter key must not be null"); + Assert.notNull(values, "Parameter values must not be null"); + this.renderParameters.put(key, values); + } + + public String[] getRenderParameterValues(String key) { + Assert.notNull(key, "Parameter key must not be null"); + return this.renderParameters.get(key); + } + + public Iterator getRenderParameterNames() { + return this.renderParameters.keySet().iterator(); + } + + public Map getRenderParameterMap() { + return Collections.unmodifiableMap(this.renderParameters); + } + + +} diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockMultipartActionRequest.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockMultipartActionRequest.java new file mode 100644 index 00000000000..cc2b2277cff --- /dev/null +++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockMultipartActionRequest.java @@ -0,0 +1,67 @@ +/* + * 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.mock.web.portlet; + +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.springframework.util.Assert; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.portlet.multipart.MultipartActionRequest; + +/** + * Mock implementation of the + * {@link org.springframework.web.portlet.multipart.MultipartActionRequest} interface. + * + *

Useful for testing application controllers that access multipart uploads. + * The {@link org.springframework.mock.web.MockMultipartFile} can be used to + * populate these mock requests with files. + * + * @author Juergen Hoeller + * @since 2.0 + * @see org.springframework.mock.web.MockMultipartFile + */ +public class MockMultipartActionRequest extends MockActionRequest implements MultipartActionRequest { + + private final Map multipartFiles = new LinkedHashMap(); + + + /** + * Add a file to this request. The parameter name from the multipart + * form is taken from the {@link org.springframework.web.multipart.MultipartFile#getName()}. + * @param file multipart file to be added + */ + public void addFile(MultipartFile file) { + Assert.notNull(file, "MultipartFile must not be null"); + this.multipartFiles.put(file.getName(), file); + } + + public Iterator getFileNames() { + return getFileMap().keySet().iterator(); + } + + public MultipartFile getFile(String name) { + return this.multipartFiles.get(name); + } + + public Map getFileMap() { + return Collections.unmodifiableMap(this.multipartFiles); + } + +} diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortalContext.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortalContext.java new file mode 100644 index 00000000000..1a81847f978 --- /dev/null +++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortalContext.java @@ -0,0 +1,101 @@ +/* + * 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.mock.web.portlet; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.portlet.PortalContext; +import javax.portlet.PortletMode; +import javax.portlet.WindowState; + +/** + * Mock implementation of the {@link javax.portlet.PortalContext} interface. + * + * @author John A. Lewis + * @author Juergen Hoeller + * @since 2.0 + */ +public class MockPortalContext implements PortalContext { + + private final Map properties = new HashMap(); + + private final List portletModes; + + private final List windowStates; + + + /** + * Create a new MockPortalContext + * with default PortletModes (VIEW, EDIT, HELP) + * and default WindowStates (NORMAL, MAXIMIZED, MINIMIZED). + * @see javax.portlet.PortletMode + * @see javax.portlet.WindowState + */ + public MockPortalContext() { + this.portletModes = new ArrayList(3); + this.portletModes.add(PortletMode.VIEW); + this.portletModes.add(PortletMode.EDIT); + this.portletModes.add(PortletMode.HELP); + + this.windowStates = new ArrayList(3); + this.windowStates.add(WindowState.NORMAL); + this.windowStates.add(WindowState.MAXIMIZED); + this.windowStates.add(WindowState.MINIMIZED); + } + + /** + * Create a new MockPortalContext with the given PortletModes and WindowStates. + * @param supportedPortletModes the List of supported PortletMode instances + * @param supportedWindowStates the List of supported WindowState instances + * @see javax.portlet.PortletMode + * @see javax.portlet.WindowState + */ + public MockPortalContext(List supportedPortletModes, List supportedWindowStates) { + this.portletModes = new ArrayList(supportedPortletModes); + this.windowStates = new ArrayList(supportedWindowStates); + } + + + public String getPortalInfo() { + return "MockPortal/1.0"; + } + + public void setProperty(String name, String value) { + this.properties.put(name, value); + } + + public String getProperty(String name) { + return this.properties.get(name); + } + + public Enumeration getPropertyNames() { + return Collections.enumeration(this.properties.keySet()); + } + + public Enumeration getSupportedPortletModes() { + return Collections.enumeration(this.portletModes); + } + + public Enumeration getSupportedWindowStates() { + return Collections.enumeration(this.windowStates); + } + +} diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletConfig.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletConfig.java new file mode 100644 index 00000000000..249429e1a13 --- /dev/null +++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletConfig.java @@ -0,0 +1,116 @@ +/* + * 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.mock.web.portlet; + +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Properties; +import java.util.ResourceBundle; +import java.util.LinkedHashMap; +import java.util.Collections; +import javax.portlet.PortletConfig; +import javax.portlet.PortletContext; + +import org.springframework.util.Assert; + +/** + * Mock implementation of the {@link javax.portlet.PortletConfig} interface. + * + * @author John A. Lewis + * @author Juergen Hoeller + * @since 2.0 + */ +public class MockPortletConfig implements PortletConfig { + + private final PortletContext portletContext; + + private final String portletName; + + private final Map resourceBundles = new HashMap(); + + private final Map initParameters = new LinkedHashMap(); + + + /** + * Create a new MockPortletConfig with a default {@link MockPortletContext}. + */ + public MockPortletConfig() { + this(null, ""); + } + + /** + * Create a new MockPortletConfig with a default {@link MockPortletContext}. + * @param portletName the name of the portlet + */ + public MockPortletConfig(String portletName) { + this(null, portletName); + } + + /** + * Create a new MockPortletConfig. + * @param portletContext the PortletContext that the portlet runs in + */ + public MockPortletConfig(PortletContext portletContext) { + this(portletContext, ""); + } + + /** + * Create a new MockPortletConfig. + * @param portletContext the PortletContext that the portlet runs in + * @param portletName the name of the portlet + */ + public MockPortletConfig(PortletContext portletContext, String portletName) { + this.portletContext = (portletContext != null ? portletContext : new MockPortletContext()); + this.portletName = portletName; + } + + + public String getPortletName() { + return this.portletName; + } + + public PortletContext getPortletContext() { + return this.portletContext; + } + + public void setResourceBundle(Locale locale, ResourceBundle resourceBundle) { + Assert.notNull(locale, "Locale must not be null"); + this.resourceBundles.put(locale, resourceBundle); + } + + public ResourceBundle getResourceBundle(Locale locale) { + Assert.notNull(locale, "Locale must not be null"); + return this.resourceBundles.get(locale); + } + + public void addInitParameter(String name, String value) { + Assert.notNull(name, "Parameter name must not be null"); + this.initParameters.put(name, value); + } + + public String getInitParameter(String name) { + Assert.notNull(name, "Parameter name must not be null"); + return this.initParameters.get(name); + } + + public Enumeration getInitParameterNames() { + return Collections.enumeration(this.initParameters.keySet()); + } + +} diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletContext.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletContext.java new file mode 100644 index 00000000000..336b21e95b4 --- /dev/null +++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletContext.java @@ -0,0 +1,254 @@ +/* + * 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.mock.web.portlet; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; +import javax.portlet.PortletContext; +import javax.portlet.PortletRequestDispatcher; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.core.io.DefaultResourceLoader; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; +import org.springframework.util.Assert; +import org.springframework.web.util.WebUtils; + +/** + * Mock implementation of the {@link javax.portlet.PortletContext} interface. + * + * @author John A. Lewis + * @author Juergen Hoeller + * @since 2.0 + */ +public class MockPortletContext implements PortletContext { + + private static final String TEMP_DIR_SYSTEM_PROPERTY = "java.io.tmpdir"; + + + private final Log logger = LogFactory.getLog(getClass()); + + private final String resourceBasePath; + + private final ResourceLoader resourceLoader; + + private final Map attributes = new LinkedHashMap(); + + private final Map initParameters = new LinkedHashMap(); + + private String portletContextName = "MockPortletContext"; + + + /** + * Create a new MockPortletContext with no base path and a + * DefaultResourceLoader (i.e. the classpath root as WAR root). + * @see org.springframework.core.io.DefaultResourceLoader + */ + public MockPortletContext() { + this("", null); + } + + /** + * Create a new MockPortletContext using a DefaultResourceLoader. + * @param resourceBasePath the WAR root directory (should not end with a slash) + * @see org.springframework.core.io.DefaultResourceLoader + */ + public MockPortletContext(String resourceBasePath) { + this(resourceBasePath, null); + } + + /** + * Create a new MockPortletContext, using the specified ResourceLoader + * and no base path. + * @param resourceLoader the ResourceLoader to use (or null for the default) + */ + public MockPortletContext(ResourceLoader resourceLoader) { + this("", resourceLoader); + } + + /** + * Create a new MockPortletContext. + * @param resourceBasePath the WAR root directory (should not end with a slash) + * @param resourceLoader the ResourceLoader to use (or null for the default) + */ + public MockPortletContext(String resourceBasePath, ResourceLoader resourceLoader) { + this.resourceBasePath = (resourceBasePath != null ? resourceBasePath : ""); + this.resourceLoader = (resourceLoader != null ? resourceLoader : new DefaultResourceLoader()); + + // Use JVM temp dir as PortletContext temp dir. + String tempDir = System.getProperty(TEMP_DIR_SYSTEM_PROPERTY); + if (tempDir != null) { + this.attributes.put(WebUtils.TEMP_DIR_CONTEXT_ATTRIBUTE, new File(tempDir)); + } + } + + /** + * Build a full resource location for the given path, + * prepending the resource base path of this MockPortletContext. + * @param path the path as specified + * @return the full resource path + */ + protected String getResourceLocation(String path) { + if (!path.startsWith("/")) { + path = "/" + path; + } + return this.resourceBasePath + path; + } + + + public String getServerInfo() { + return "MockPortal/1.0"; + } + + public PortletRequestDispatcher getRequestDispatcher(String path) { + if (!path.startsWith("/")) { + throw new IllegalArgumentException( + "PortletRequestDispatcher path at PortletContext level must start with '/'"); + } + return new MockPortletRequestDispatcher(path); + } + + public PortletRequestDispatcher getNamedDispatcher(String path) { + return null; + } + + public InputStream getResourceAsStream(String path) { + Resource resource = this.resourceLoader.getResource(getResourceLocation(path)); + try { + return resource.getInputStream(); + } + catch (IOException ex) { + logger.info("Couldn't open InputStream for " + resource, ex); + return null; + } + } + + public int getMajorVersion() { + return 1; + } + + public int getMinorVersion() { + return 0; + } + + public String getMimeType(String filePath) { + return null; + } + + public String getRealPath(String path) { + Resource resource = this.resourceLoader.getResource(getResourceLocation(path)); + try { + return resource.getFile().getAbsolutePath(); + } + catch (IOException ex) { + logger.info("Couldn't determine real path of resource " + resource, ex); + return null; + } + } + + public Set getResourcePaths(String path) { + Resource resource = this.resourceLoader.getResource(getResourceLocation(path)); + try { + File file = resource.getFile(); + String[] fileList = file.list(); + String prefix = (path.endsWith("/") ? path : path + "/"); + Set resourcePaths = new HashSet(fileList.length); + for (String fileEntry : fileList) { + resourcePaths.add(prefix + fileEntry); + } + return resourcePaths; + } + catch (IOException ex) { + logger.info("Couldn't get resource paths for " + resource, ex); + return null; + } + } + + public URL getResource(String path) throws MalformedURLException { + Resource resource = this.resourceLoader.getResource(getResourceLocation(path)); + try { + return resource.getURL(); + } + catch (IOException ex) { + logger.info("Couldn't get URL for " + resource, ex); + return null; + } + } + + public Object getAttribute(String name) { + return this.attributes.get(name); + } + + public Enumeration getAttributeNames() { + return Collections.enumeration(this.attributes.keySet()); + } + + public void setAttribute(String name, Object value) { + if (value != null) { + this.attributes.put(name, value); + } + else { + this.attributes.remove(name); + } + } + + public void removeAttribute(String name) { + this.attributes.remove(name); + } + + public void addInitParameter(String name, String value) { + Assert.notNull(name, "Parameter name must not be null"); + this.initParameters.put(name, value); + } + + public String getInitParameter(String name) { + Assert.notNull(name, "Parameter name must not be null"); + return this.initParameters.get(name); + } + + public Enumeration getInitParameterNames() { + return Collections.enumeration(this.initParameters.keySet()); + } + + public void log(String message) { + logger.info(message); + } + + public void log(String message, Throwable t) { + logger.info(message, t); + } + + public void setPortletContextName(String portletContextName) { + this.portletContextName = portletContextName; + } + + public String getPortletContextName() { + return portletContextName; + } + +} diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletPreferences.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletPreferences.java new file mode 100644 index 00000000000..122ead007e6 --- /dev/null +++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletPreferences.java @@ -0,0 +1,115 @@ +/* + * 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.mock.web.portlet; + +import java.io.IOException; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +import javax.portlet.PortletPreferences; +import javax.portlet.PreferencesValidator; +import javax.portlet.ReadOnlyException; +import javax.portlet.ValidatorException; + +import org.springframework.util.Assert; + +/** + * Mock implementation of the {@link javax.portlet.PortletPreferences} interface. + * + * @author John A. Lewis + * @author Juergen Hoeller + * @since 2.0 + */ +public class MockPortletPreferences implements PortletPreferences { + + private PreferencesValidator preferencesValidator; + + private final Map preferences = new LinkedHashMap(); + + private final Set readOnly = new HashSet(); + + + public void setReadOnly(String key, boolean readOnly) { + Assert.notNull(key, "Key must not be null"); + if (readOnly) { + this.readOnly.add(key); + } + else { + this.readOnly.remove(key); + } + } + + public boolean isReadOnly(String key) { + Assert.notNull(key, "Key must not be null"); + return this.readOnly.contains(key); + } + + public String getValue(String key, String def) { + Assert.notNull(key, "Key must not be null"); + String[] values = this.preferences.get(key); + return (values != null && values.length > 0 ? values[0] : def); + } + + public String[] getValues(String key, String[] def) { + Assert.notNull(key, "Key must not be null"); + String[] values = this.preferences.get(key); + return (values != null && values.length > 0 ? values : def); + } + + public void setValue(String key, String value) throws ReadOnlyException { + setValues(key, new String[] {value}); + } + + public void setValues(String key, String[] values) throws ReadOnlyException { + Assert.notNull(key, "Key must not be null"); + if (isReadOnly(key)) { + throw new ReadOnlyException("Preference '" + key + "' is read-only"); + } + this.preferences.put(key, values); + } + + public Enumeration getNames() { + return Collections.enumeration(this.preferences.keySet()); + } + + public Map getMap() { + return Collections.unmodifiableMap(this.preferences); + } + + public void reset(String key) throws ReadOnlyException { + Assert.notNull(key, "Key must not be null"); + if (isReadOnly(key)) { + throw new ReadOnlyException("Preference '" + key + "' is read-only"); + } + this.preferences.remove(key); + } + + public void setPreferencesValidator(PreferencesValidator preferencesValidator) { + this.preferencesValidator = preferencesValidator; + } + + public void store() throws IOException, ValidatorException { + if (this.preferencesValidator != null) { + this.preferencesValidator.validate(this); + } + } + +} diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletRequest.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletRequest.java new file mode 100644 index 00000000000..84c8af733f3 --- /dev/null +++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletRequest.java @@ -0,0 +1,462 @@ +/* + * 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.mock.web.portlet; + +import java.security.Principal; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import javax.portlet.PortalContext; +import javax.portlet.PortletContext; +import javax.portlet.PortletMode; +import javax.portlet.PortletPreferences; +import javax.portlet.PortletRequest; +import javax.portlet.PortletSession; +import javax.portlet.WindowState; + +import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; + +/** + * Mock implementation of the {@link javax.portlet.PortletRequest} interface. + * + * @author John A. Lewis + * @author Juergen Hoeller + * @since 2.0 + */ +public class MockPortletRequest implements PortletRequest { + + private boolean active = true; + + private final PortalContext portalContext; + + private final PortletContext portletContext; + + private PortletSession session; + + private WindowState windowState = WindowState.NORMAL; + + private PortletMode portletMode = PortletMode.VIEW; + + private PortletPreferences portletPreferences = new MockPortletPreferences(); + + private final Map> properties = new LinkedHashMap>(); + + private final Map attributes = new LinkedHashMap(); + + private final Map parameters = new LinkedHashMap(); + + private String authType = null; + + private String contextPath = ""; + + private String remoteUser = null; + + private Principal userPrincipal = null; + + private final Set userRoles = new HashSet(); + + private boolean secure = false; + + private boolean requestedSessionIdValid = true; + + private final List responseContentTypes = new LinkedList(); + + private final List locales = new LinkedList(); + + private String scheme = "http"; + + private String serverName = "localhost"; + + private int serverPort = 80; + + + /** + * Create a new MockPortletRequest with a default {@link MockPortalContext} + * and a default {@link MockPortletContext}. + * @see MockPortalContext + * @see MockPortletContext + */ + public MockPortletRequest() { + this(null, null); + } + + /** + * Create a new MockPortletRequest with a default {@link MockPortalContext}. + * @param portletContext the PortletContext that the request runs in + * @see MockPortalContext + */ + public MockPortletRequest(PortletContext portletContext) { + this(null, portletContext); + } + + /** + * Create a new MockPortletRequest. + * @param portalContext the PortalContext that the request runs in + * @param portletContext the PortletContext that the request runs in + */ + public MockPortletRequest(PortalContext portalContext, PortletContext portletContext) { + this.portalContext = (portalContext != null ? portalContext : new MockPortalContext()); + this.portletContext = (portletContext != null ? portletContext : new MockPortletContext()); + this.responseContentTypes.add("text/html"); + this.locales.add(Locale.ENGLISH); + } + + + //--------------------------------------------------------------------- + // Lifecycle methods + //--------------------------------------------------------------------- + + /** + * Return whether this request is still active (that is, not completed yet). + */ + public boolean isActive() { + return this.active; + } + + /** + * Mark this request as completed. + */ + public void close() { + this.active = false; + } + + /** + * Check whether this request is still active (that is, not completed yet), + * throwing an IllegalStateException if not active anymore. + */ + protected void checkActive() throws IllegalStateException { + if (!this.active) { + throw new IllegalStateException("Request is not active anymore"); + } + } + + + //--------------------------------------------------------------------- + // PortletRequest methods + //--------------------------------------------------------------------- + + public boolean isWindowStateAllowed(WindowState windowState) { + return CollectionUtils.contains(this.portalContext.getSupportedWindowStates(), windowState); + } + + public boolean isPortletModeAllowed(PortletMode portletMode) { + return CollectionUtils.contains(this.portalContext.getSupportedPortletModes(), portletMode); + } + + public void setPortletMode(PortletMode portletMode) { + Assert.notNull(portletMode, "PortletMode must not be null"); + this.portletMode = portletMode; + } + + public PortletMode getPortletMode() { + return this.portletMode; + } + + public void setWindowState(WindowState windowState) { + Assert.notNull(windowState, "WindowState must not be null"); + this.windowState = windowState; + } + + public WindowState getWindowState() { + return this.windowState; + } + + public void setPreferences(PortletPreferences preferences) { + Assert.notNull(preferences, "PortletPreferences must not be null"); + this.portletPreferences = preferences; + } + + public PortletPreferences getPreferences() { + return this.portletPreferences; + } + + public void setSession(PortletSession session) { + this.session = session; + if (session instanceof MockPortletSession) { + MockPortletSession mockSession = ((MockPortletSession) session); + mockSession.access(); + } + } + + public PortletSession getPortletSession() { + return getPortletSession(true); + } + + public PortletSession getPortletSession(boolean create) { + checkActive(); + // Reset session if invalidated. + if (this.session instanceof MockPortletSession && ((MockPortletSession) this.session).isInvalid()) { + this.session = null; + } + // Create new session if necessary. + if (this.session == null && create) { + this.session = new MockPortletSession(this.portletContext); + } + return this.session; + } + + /** + * Set a single value for the specified property. + *

If there are already one or more values registered for the given + * property key, they will be replaced. + */ + public void setProperty(String key, String value) { + Assert.notNull(key, "Property key must not be null"); + List list = new LinkedList(); + list.add(value); + this.properties.put(key, list); + } + + /** + * Add a single value for the specified property. + *

If there are already one or more values registered for the given + * property key, the given value will be added to the end of the list. + */ + public void addProperty(String key, String value) { + Assert.notNull(key, "Property key must not be null"); + List oldList = this.properties.get(key); + if (oldList != null) { + oldList.add(value); + } + else { + List list = new LinkedList(); + list.add(value); + this.properties.put(key, list); + } + } + + public String getProperty(String key) { + Assert.notNull(key, "Property key must not be null"); + List list = this.properties.get(key); + return (list != null && list.size() > 0 ? (String) list.get(0) : null); + } + + public Enumeration getProperties(String key) { + Assert.notNull(key, "property key must not be null"); + return Collections.enumeration(this.properties.get(key)); + } + + public Enumeration getPropertyNames() { + return Collections.enumeration(this.properties.keySet()); + } + + public PortalContext getPortalContext() { + return this.portalContext; + } + + public void setAuthType(String authType) { + this.authType = authType; + } + + public String getAuthType() { + return this.authType; + } + + public void setContextPath(String contextPath) { + this.contextPath = contextPath; + } + + public String getContextPath() { + return this.contextPath; + } + + public void setRemoteUser(String remoteUser) { + this.remoteUser = remoteUser; + } + + public String getRemoteUser() { + return this.remoteUser; + } + + public void setUserPrincipal(Principal userPrincipal) { + this.userPrincipal = userPrincipal; + } + + public Principal getUserPrincipal() { + return this.userPrincipal; + } + + public void addUserRole(String role) { + this.userRoles.add(role); + } + + public boolean isUserInRole(String role) { + return this.userRoles.contains(role); + } + + public Object getAttribute(String name) { + checkActive(); + return this.attributes.get(name); + } + + public Enumeration getAttributeNames() { + checkActive(); + return Collections.enumeration(this.attributes.keySet()); + } + + public void setParameters(Map parameters) { + Assert.notNull(parameters, "Parameters Map must not be null"); + this.parameters.clear(); + this.parameters.putAll(parameters); + } + + public void setParameter(String key, String value) { + Assert.notNull(key, "Parameter key must be null"); + Assert.notNull(value, "Parameter value must not be null"); + this.parameters.put(key, new String[] {value}); + } + + public void setParameter(String key, String[] values) { + Assert.notNull(key, "Parameter key must be null"); + Assert.notNull(values, "Parameter values must not be null"); + this.parameters.put(key, values); + } + + public void addParameter(String name, String value) { + addParameter(name, new String[] {value}); + } + + public void addParameter(String name, String[] values) { + String[] oldArr = this.parameters.get(name); + if (oldArr != null) { + String[] newArr = new String[oldArr.length + values.length]; + System.arraycopy(oldArr, 0, newArr, 0, oldArr.length); + System.arraycopy(values, 0, newArr, oldArr.length, values.length); + this.parameters.put(name, newArr); + } + else { + this.parameters.put(name, values); + } + } + + public String getParameter(String name) { + String[] arr = this.parameters.get(name); + return (arr != null && arr.length > 0 ? arr[0] : null); + } + + public Enumeration getParameterNames() { + return Collections.enumeration(this.parameters.keySet()); + } + + public String[] getParameterValues(String name) { + return this.parameters.get(name); + } + + public Map getParameterMap() { + return Collections.unmodifiableMap(this.parameters); + } + + public void setSecure(boolean secure) { + this.secure = secure; + } + + public boolean isSecure() { + return this.secure; + } + + public void setAttribute(String name, Object value) { + checkActive(); + if (value != null) { + this.attributes.put(name, value); + } + else { + this.attributes.remove(name); + } + } + + public void removeAttribute(String name) { + checkActive(); + this.attributes.remove(name); + } + + public String getRequestedSessionId() { + PortletSession session = this.getPortletSession(); + return (session != null ? session.getId() : null); + } + + public void setRequestedSessionIdValid(boolean requestedSessionIdValid) { + this.requestedSessionIdValid = requestedSessionIdValid; + } + + public boolean isRequestedSessionIdValid() { + return this.requestedSessionIdValid; + } + + public void addResponseContentType(String responseContentType) { + this.responseContentTypes.add(responseContentType); + } + + public void addPreferredResponseContentType(String responseContentType) { + this.responseContentTypes.add(0, responseContentType); + } + + public String getResponseContentType() { + return this.responseContentTypes.get(0); + } + + public Enumeration getResponseContentTypes() { + return Collections.enumeration(this.responseContentTypes); + } + + public void addLocale(Locale locale) { + this.locales.add(locale); + } + + public void addPreferredLocale(Locale locale) { + this.locales.add(0, locale); + } + + public Locale getLocale() { + return this.locales.get(0); + } + + public Enumeration getLocales() { + return Collections.enumeration(this.locales); + } + + public void setScheme(String scheme) { + this.scheme = scheme; + } + + public String getScheme() { + return this.scheme; + } + + public void setServerName(String serverName) { + this.serverName = serverName; + } + + public String getServerName() { + return this.serverName; + } + + public void setServerPort(int serverPort) { + this.serverPort = serverPort; + } + + public int getServerPort() { + return this.serverPort; + } + +} diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletRequestDispatcher.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletRequestDispatcher.java new file mode 100644 index 00000000000..2703c1920c2 --- /dev/null +++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletRequestDispatcher.java @@ -0,0 +1,67 @@ +/* + * 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.mock.web.portlet; + +import java.io.IOException; + +import javax.portlet.PortletException; +import javax.portlet.PortletRequestDispatcher; +import javax.portlet.RenderRequest; +import javax.portlet.RenderResponse; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.util.Assert; + +/** + * Mock implementation of the {@link javax.portlet.PortletRequestDispatcher} interface. + * + * @author John A. Lewis + * @author Juergen Hoeller + * @since 2.0 + */ +public class MockPortletRequestDispatcher implements PortletRequestDispatcher { + + private final Log logger = LogFactory.getLog(getClass()); + + private final String url; + + + /** + * Create a new MockPortletRequestDispatcher for the given URL. + * @param url the URL to dispatch to. + */ + public MockPortletRequestDispatcher(String url) { + Assert.notNull(url, "URL must not be null"); + this.url = url; + } + + + public void include(RenderRequest request, RenderResponse response) throws PortletException, IOException { + Assert.notNull(request, "Request must not be null"); + Assert.notNull(response, "Response must not be null"); + if (!(response instanceof MockRenderResponse)) { + throw new IllegalArgumentException("MockPortletRequestDispatcher requires MockRenderResponse"); + } + ((MockRenderResponse) response).setIncludedUrl(this.url); + if (logger.isDebugEnabled()) { + logger.debug("MockPortletRequestDispatcher: including URL [" + this.url + "]"); + } + } + +} diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletResponse.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletResponse.java new file mode 100644 index 00000000000..2c94ddda4a5 --- /dev/null +++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletResponse.java @@ -0,0 +1,110 @@ +/* + * 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.mock.web.portlet; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +import javax.portlet.PortalContext; +import javax.portlet.PortletResponse; + +import org.springframework.util.Assert; + +/** + * Mock implementation of the {@link javax.portlet.PortletResponse} interface. + * + * @author John A. Lewis + * @author Juergen Hoeller + * @since 2.0 + */ +public class MockPortletResponse implements PortletResponse { + + private final PortalContext portalContext; + + private final Map properties = new LinkedHashMap(); + + + /** + * Create a new MockPortletResponse with a default {@link MockPortalContext}. + * @see MockPortalContext + */ + public MockPortletResponse() { + this(null); + } + + /** + * Create a new MockPortletResponse. + * @param portalContext the PortalContext defining the supported + * PortletModes and WindowStates + */ + public MockPortletResponse(PortalContext portalContext) { + this.portalContext = (portalContext != null ? portalContext : new MockPortalContext()); + } + + /** + * Return the PortalContext that this MockPortletResponse runs in, + * defining the supported PortletModes and WindowStates. + */ + public PortalContext getPortalContext() { + return this.portalContext; + } + + + //--------------------------------------------------------------------- + // PortletResponse methods + //--------------------------------------------------------------------- + + public void addProperty(String key, String value) { + Assert.notNull(key, "Property key must not be null"); + String[] oldArr = this.properties.get(key); + if (oldArr != null) { + String[] newArr = new String[oldArr.length + 1]; + System.arraycopy(oldArr, 0, newArr, 0, oldArr.length); + newArr[oldArr.length] = value; + this.properties.put(key, newArr); + } + else { + this.properties.put(key, new String[] {value}); + } + } + + public void setProperty(String key, String value) { + Assert.notNull(key, "Property key must not be null"); + this.properties.put(key, new String[] {value}); + } + + public Set getPropertyNames() { + return this.properties.keySet(); + } + + public String getProperty(String key) { + Assert.notNull(key, "Property key must not be null"); + String[] arr = this.properties.get(key); + return (arr != null && arr.length > 0 ? arr[0] : null); + } + + public String[] getProperties(String key) { + Assert.notNull(key, "Property key must not be null"); + return this.properties.get(key); + } + + public String encodeURL(String path) { + return path; + } + +} diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletSession.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletSession.java new file mode 100644 index 00000000000..ab27defe000 --- /dev/null +++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletSession.java @@ -0,0 +1,190 @@ +/* + * 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.mock.web.portlet; + +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import javax.portlet.PortletContext; +import javax.portlet.PortletSession; + +/** + * Mock implementation of the {@link javax.portlet.PortletSession} interface. + * + * @author John A. Lewis + * @author Juergen Hoeller + * @since 2.0 + */ +public class MockPortletSession implements PortletSession { + + private static int nextId = 1; + + + private final String id = Integer.toString(nextId++); + + private final long creationTime = System.currentTimeMillis(); + + private int maxInactiveInterval; + + private long lastAccessedTime = System.currentTimeMillis(); + + private final PortletContext portletContext; + + private final Map portletAttributes = new HashMap(); + + private final Map applicationAttributes = new HashMap(); + + private boolean invalid = false; + + private boolean isNew = true; + + + /** + * Create a new MockPortletSession with a default {@link MockPortletContext}. + * @see MockPortletContext + */ + public MockPortletSession() { + this(null); + } + + /** + * Create a new MockPortletSession. + * @param portletContext the PortletContext that the session runs in + */ + public MockPortletSession(PortletContext portletContext) { + this.portletContext = (portletContext != null ? portletContext : new MockPortletContext()); + } + + + public Object getAttribute(String name) { + return this.portletAttributes.get(name); + } + + public Object getAttribute(String name, int scope) { + if (scope == PortletSession.PORTLET_SCOPE) { + return this.portletAttributes.get(name); + } + else if (scope == PortletSession.APPLICATION_SCOPE) { + return this.applicationAttributes.get(name); + } + return null; + } + + public Enumeration getAttributeNames() { + return Collections.enumeration(this.portletAttributes.keySet()); + } + + public Enumeration getAttributeNames(int scope) { + if (scope == PortletSession.PORTLET_SCOPE) { + return Collections.enumeration(this.portletAttributes.keySet()); + } + else if (scope == PortletSession.APPLICATION_SCOPE) { + return Collections.enumeration(this.applicationAttributes.keySet()); + } + return null; + } + + public long getCreationTime() { + return this.creationTime; + } + + public String getId() { + return this.id; + } + + public void access() { + this.lastAccessedTime = System.currentTimeMillis(); + setNew(false); + } + + public long getLastAccessedTime() { + return this.lastAccessedTime; + } + + public int getMaxInactiveInterval() { + return this.maxInactiveInterval; + } + + public void invalidate() { + this.invalid = true; + this.portletAttributes.clear(); + this.applicationAttributes.clear(); + } + + public boolean isInvalid() { + return invalid; + } + + public void setNew(boolean value) { + this.isNew = value; + } + + public boolean isNew() { + return this.isNew; + } + + public void removeAttribute(String name) { + this.portletAttributes.remove(name); + } + + public void removeAttribute(String name, int scope) { + if (scope == PortletSession.PORTLET_SCOPE) { + this.portletAttributes.remove(name); + } + else if (scope == PortletSession.APPLICATION_SCOPE) { + this.applicationAttributes.remove(name); + } + } + + public void setAttribute(String name, Object value) { + if (value != null) { + this.portletAttributes.put(name, value); + } + else { + this.portletAttributes.remove(name); + } + } + + public void setAttribute(String name, Object value, int scope) { + if (scope == PortletSession.PORTLET_SCOPE) { + if (value != null) { + this.portletAttributes.put(name, value); + } + else { + this.portletAttributes.remove(name); + } + } + else if (scope == PortletSession.APPLICATION_SCOPE) { + if (value != null) { + this.applicationAttributes.put(name, value); + } + else { + this.applicationAttributes.remove(name); + } + } + } + + public void setMaxInactiveInterval(int interval) { + this.maxInactiveInterval = interval; + } + + public PortletContext getPortletContext() { + return portletContext; + } + +} diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletURL.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletURL.java new file mode 100644 index 00000000000..edf889cf93e --- /dev/null +++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletURL.java @@ -0,0 +1,190 @@ +/* + * 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.mock.web.portlet; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +import javax.portlet.PortalContext; +import javax.portlet.PortletMode; +import javax.portlet.PortletModeException; +import javax.portlet.PortletSecurityException; +import javax.portlet.PortletURL; +import javax.portlet.WindowState; +import javax.portlet.WindowStateException; + +import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; + +/** + * Mock implementation of the {@link javax.portlet.PortletURL} interface. + * + * @author John A. Lewis + * @author Juergen Hoeller + * @since 2.0 + */ +public class MockPortletURL implements PortletURL { + + public static final String URL_TYPE_RENDER = "render"; + + public static final String URL_TYPE_ACTION = "action"; + + private static final String ENCODING = "UTF-8"; + + + private final PortalContext portalContext; + + private final String urlType; + + private WindowState windowState; + + private PortletMode portletMode; + + private final Map parameters = new LinkedHashMap(); + + private boolean secure = false; + + + /** + * Create a new MockPortletURL for the given URL type. + * @param portalContext the PortalContext defining the supported + * PortletModes and WindowStates + * @param urlType the URL type, for example "render" or "action" + * @see #URL_TYPE_RENDER + * @see #URL_TYPE_ACTION + */ + public MockPortletURL(PortalContext portalContext, String urlType) { + Assert.notNull(portalContext, "PortalContext is required"); + this.portalContext = portalContext; + this.urlType = urlType; + } + + + //--------------------------------------------------------------------- + // PortletURL methods + //--------------------------------------------------------------------- + + public void setWindowState(WindowState windowState) throws WindowStateException { + if (!CollectionUtils.contains(this.portalContext.getSupportedWindowStates(), windowState)) { + throw new WindowStateException("WindowState not supported", windowState); + } + this.windowState = windowState; + } + + public void setPortletMode(PortletMode portletMode) throws PortletModeException { + if (!CollectionUtils.contains(this.portalContext.getSupportedPortletModes(), portletMode)) { + throw new PortletModeException("PortletMode not supported", portletMode); + } + this.portletMode = portletMode; + } + + public void setParameter(String key, String value) { + Assert.notNull(key, "Parameter key must be null"); + Assert.notNull(value, "Parameter value must not be null"); + this.parameters.put(key, new String[] {value}); + } + + public void setParameter(String key, String[] values) { + Assert.notNull(key, "Parameter key must be null"); + Assert.notNull(values, "Parameter values must not be null"); + this.parameters.put(key, values); + } + + public void setParameters(Map parameters) { + Assert.notNull(parameters, "Parameters Map must not be null"); + this.parameters.clear(); + for (Iterator it = parameters.entrySet().iterator(); it.hasNext();) { + Map.Entry entry = (Map.Entry) it.next(); + Assert.isTrue(entry.getKey() instanceof String, "Key must be of type String"); + Assert.isTrue(entry.getValue() instanceof String[], "Value must be of type String[]"); + this.parameters.put((String) entry.getKey(), (String[]) entry.getValue()); + } + } + + public Set getParameterNames() { + return this.parameters.keySet(); + } + + public String getParameter(String name) { + String[] arr = this.parameters.get(name); + return (arr != null && arr.length > 0 ? arr[0] : null); + } + + public String[] getParameterValues(String name) { + return this.parameters.get(name); + } + + public Map getParameterMap() { + return Collections.unmodifiableMap(this.parameters); + } + + public void setSecure(boolean secure) throws PortletSecurityException { + this.secure = secure; + } + + public boolean isSecure() { + return this.secure; + } + + + private String encodeParameter(String name, String value) { + try { + return URLEncoder.encode(name, ENCODING) + "=" + URLEncoder.encode(value, ENCODING); + } + catch (UnsupportedEncodingException ex) { + return null; + } + } + + private String encodeParameter(String name, String[] values) { + try { + StringBuilder sb = new StringBuilder(); + for (int i = 0, n = values.length; i < n; i++) { + sb.append((i > 0 ? ";" : "") + + URLEncoder.encode(name, ENCODING) + "=" + + URLEncoder.encode(values[i], ENCODING)); + } + return sb.toString(); + } + catch (UnsupportedEncodingException ex) { + return null; + } + } + + + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(encodeParameter("urlType", this.urlType)); + if (this.windowState != null) { + sb.append(";").append(encodeParameter("windowState", this.windowState.toString())); + } + if (this.portletMode != null) { + sb.append(";").append(encodeParameter("portletMode", this.portletMode.toString())); + } + for (Map.Entry entry : this.parameters.entrySet()) { + sb.append(";").append(encodeParameter("param_" + entry.getKey(), entry.getValue())); + } + return (this.secure ? "https:" : "http:") + + "//localhost/mockportlet?" + sb.toString(); + } + +} diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockRenderRequest.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockRenderRequest.java new file mode 100644 index 00000000000..5bb8c54e42d --- /dev/null +++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockRenderRequest.java @@ -0,0 +1,70 @@ +/* + * 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.mock.web.portlet; + +import javax.portlet.PortalContext; +import javax.portlet.PortletContext; +import javax.portlet.PortletMode; +import javax.portlet.RenderRequest; + +/** + * Mock implementation of the {@link javax.portlet.RenderRequest} interface. + * + * @author John A. Lewis + * @author Juergen Hoeller + * @since 2.0 + */ +public class MockRenderRequest extends MockPortletRequest implements RenderRequest { + + /** + * Create a new MockRenderRequest with a default {@link MockPortalContext} + * and a default {@link MockPortletContext}. + * @see MockPortalContext + * @see MockPortletContext + */ + public MockRenderRequest() { + super(); + } + + /** + * Create a new MockRenderRequest with a default {@link MockPortalContext} + * and a default {@link MockPortletContext}. + * @param portletMode the mode that the portlet runs in + */ + public MockRenderRequest(PortletMode portletMode) { + super(); + setPortletMode(portletMode); + } + + /** + * Create a new MockRenderRequest with a default {@link MockPortalContext}. + * @param portletContext the PortletContext that the request runs in + */ + public MockRenderRequest(PortletContext portletContext) { + super(portletContext); + } + + /** + * Create a new MockRenderRequest. + * @param portalContext the PortletContext that the request runs in + * @param portletContext the PortletContext that the request runs in + */ + public MockRenderRequest(PortalContext portalContext, PortletContext portletContext) { + super(portalContext, portletContext); + } + +} diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockRenderResponse.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockRenderResponse.java new file mode 100644 index 00000000000..c63e9a44599 --- /dev/null +++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockRenderResponse.java @@ -0,0 +1,216 @@ +/* + * 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.mock.web.portlet; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.io.Writer; +import java.util.Locale; + +import javax.portlet.PortalContext; +import javax.portlet.PortletURL; +import javax.portlet.RenderResponse; + +import org.springframework.web.util.WebUtils; + +/** + * Mock implementation of the {@link javax.portlet.RenderResponse} interface. + * + * @author John A. Lewis + * @author Juergen Hoeller + * @since 2.0 + */ +public class MockRenderResponse extends MockPortletResponse implements RenderResponse { + + private String contentType; + + private String namespace = "MockPortlet"; + + private String title; + + private String characterEncoding = WebUtils.DEFAULT_CHARACTER_ENCODING; + + private PrintWriter writer; + + private Locale locale = Locale.getDefault(); + + private int bufferSize = 4096; + + private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + + private boolean committed; + + private String includedUrl; + + + /** + * Create a new MockRenderResponse with a default {@link MockPortalContext}. + * @see MockPortalContext + */ + public MockRenderResponse() { + super(); + } + + /** + * Create a new MockRenderResponse. + * @param portalContext the PortalContext defining the supported + * PortletModes and WindowStates + */ + public MockRenderResponse(PortalContext portalContext) { + super(portalContext); + } + + + //--------------------------------------------------------------------- + // RenderResponse methods + //--------------------------------------------------------------------- + + public String getContentType() { + return this.contentType; + } + + public PortletURL createRenderURL() { + PortletURL url = new MockPortletURL(getPortalContext(), MockPortletURL.URL_TYPE_RENDER); + return url; + } + + public PortletURL createActionURL() { + PortletURL url = new MockPortletURL(getPortalContext(), MockPortletURL.URL_TYPE_ACTION); + return url; + } + + public String getNamespace() { + return this.namespace; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getTitle() { + return title; + } + + public void setContentType(String contentType) { + this.contentType = contentType; + } + + public void setCharacterEncoding(String characterEncoding) { + this.characterEncoding = characterEncoding; + } + + public String getCharacterEncoding() { + return this.characterEncoding; + } + + public PrintWriter getWriter() throws UnsupportedEncodingException { + if (this.writer == null) { + Writer targetWriter = (this.characterEncoding != null + ? new OutputStreamWriter(this.outputStream, this.characterEncoding) + : new OutputStreamWriter(this.outputStream)); + this.writer = new PrintWriter(targetWriter); + } + return this.writer; + } + + public byte[] getContentAsByteArray() { + flushBuffer(); + return this.outputStream.toByteArray(); + } + + public String getContentAsString() throws UnsupportedEncodingException { + flushBuffer(); + return (this.characterEncoding != null) + ? this.outputStream.toString(this.characterEncoding) + : this.outputStream.toString(); + } + + public void setLocale(Locale locale) { + this.locale = locale; + } + + public Locale getLocale() { + return this.locale; + } + + public void setBufferSize(int bufferSize) { + this.bufferSize = bufferSize; + } + + public int getBufferSize() { + return this.bufferSize; + } + + public void flushBuffer() { + if (this.writer != null) { + this.writer.flush(); + } + if (this.outputStream != null) { + try { + this.outputStream.flush(); + } + catch (IOException ex) { + throw new IllegalStateException("Could not flush OutputStream: " + ex.getMessage()); + } + } + this.committed = true; + } + + public void resetBuffer() { + if (this.committed) { + throw new IllegalStateException("Cannot reset buffer - response is already committed"); + } + this.outputStream.reset(); + } + + public void setCommitted(boolean committed) { + this.committed = committed; + } + + public boolean isCommitted() { + return this.committed; + } + + public void reset() { + resetBuffer(); + this.characterEncoding = null; + this.contentType = null; + this.locale = null; + } + + public OutputStream getPortletOutputStream() throws IOException { + return this.outputStream; + } + + + //--------------------------------------------------------------------- + // Methods for MockPortletRequestDispatcher + //--------------------------------------------------------------------- + + public void setIncludedUrl(String includedUrl) { + this.includedUrl = includedUrl; + } + + public String getIncludedUrl() { + return includedUrl; + } + +} diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/package.html b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/package.html new file mode 100644 index 00000000000..3fa19b640c7 --- /dev/null +++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/package.html @@ -0,0 +1,13 @@ + + + +A comprehensive set of Portlet API mock objects, +targeted at usage with Spring's web MVC framework. +Useful for testing web contexts and controllers. + +

More convenient to use than dynamic mock objects +(EasyMock) or +existing Portlet API mock objects. + + + diff --git a/org.springframework.web.servlet/src/test/resources/org/springframework/ui/jasperreports/DataSourceReport.jasper b/org.springframework.web.servlet/src/test/resources/org/springframework/ui/jasperreports/DataSourceReport.jasper new file mode 100644 index 0000000000000000000000000000000000000000..8414447e09db656cb73537e527808a0856f81a0d GIT binary patch literal 18664 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 Q?_GQCMcO9rTuxd41FwE+c>n+a literal 0 HcmV?d00001 diff --git a/org.springframework.web.servlet/src/test/resources/org/springframework/ui/jasperreports/DataSourceReport.jrxml b/org.springframework.web.servlet/src/test/resources/org/springframework/ui/jasperreports/DataSourceReport.jrxml new file mode 100644 index 00000000000..2df89cfb9e7 --- /dev/null +++ b/org.springframework.web.servlet/src/test/resources/org/springframework/ui/jasperreports/DataSourceReport.jrxml @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <band height="70"> + <line> + <reportElement x="0" y="0" width="515" height="1"/> + <graphicElement/> + </line> + <textField isBlankWhenNull="true"> + <reportElement x="0" y="10" width="515" height="30"/> + <textElement textAlignment="Center"> + <font reportFont="Arial_Normal" size="22"/> + </textElement> + <textFieldExpression class="java.lang.String"><![CDATA[$P{ReportTitle}]]></textFieldExpression> + </textField> + <textField isBlankWhenNull="true"> + <reportElement x="0" y="40" width="515" height="20"/> + <textElement textAlignment="Center"> + <font reportFont="Arial_Normal" size="14"/> + </textElement> + <textFieldExpression class="java.lang.String"><![CDATA[$P{DataFile}]]></textFieldExpression> + </textField> + </band> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.web.servlet/src/test/resources/org/springframework/ui/jasperreports/messages_de.properties b/org.springframework.web.servlet/src/test/resources/org/springframework/ui/jasperreports/messages_de.properties new file mode 100644 index 00000000000..4dd7d2be865 --- /dev/null +++ b/org.springframework.web.servlet/src/test/resources/org/springframework/ui/jasperreports/messages_de.properties @@ -0,0 +1 @@ +page=MeineSeite diff --git a/org.springframework.web.servlet/src/test/resources/org/springframework/ui/jasperreports/subReportChild.jasper b/org.springframework.web.servlet/src/test/resources/org/springframework/ui/jasperreports/subReportChild.jasper new file mode 100644 index 0000000000000000000000000000000000000000..cd8ad2052ff4771741b37d5adb79530cb41fa103 GIT binary patch literal 18449 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 a!be+qk0tEc|F^n(xU&m&hNwP*vHlmupxvAR literal 0 HcmV?d00001 diff --git a/org.springframework.web.servlet/src/test/resources/org/springframework/ui/jasperreports/subReportChild.jrxml b/org.springframework.web.servlet/src/test/resources/org/springframework/ui/jasperreports/subReportChild.jrxml new file mode 100644 index 00000000000..ede2a092214 --- /dev/null +++ b/org.springframework.web.servlet/src/test/resources/org/springframework/ui/jasperreports/subReportChild.jrxml @@ -0,0 +1,227 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <band height="14"> + <staticText> + <reportElement x="0" y="2" width="60" height="10"/> + <textElement> + <font reportFont="Arial_Italic"/> + </textElement> + <text><![CDATA[Title]]></text> + </staticText> + <textField> + <reportElement x="0" y="2" width="325" height="10"/> + <textElement textAlignment="Center"> + <font reportFont="Arial_Bold"/> + </textElement> + <textFieldExpression class="java.lang.String"><![CDATA["Products ordered by people in " + $P{City}]]></textFieldExpression> + </textField> + </band> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.web.servlet/src/test/resources/org/springframework/ui/jasperreports/subReportParent.jasper b/org.springframework.web.servlet/src/test/resources/org/springframework/ui/jasperreports/subReportParent.jasper new file mode 100644 index 0000000000000000000000000000000000000000..aba7bb207d4184ee67894cbc179354983bd7bb0c GIT binary patch literal 14261 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 literal 0 HcmV?d00001 diff --git a/org.springframework.web.servlet/src/test/resources/org/springframework/ui/jasperreports/subReportParent.jrxml b/org.springframework.web.servlet/src/test/resources/org/springframework/ui/jasperreports/subReportParent.jrxml new file mode 100644 index 00000000000..f2f9c08d3f9 --- /dev/null +++ b/org.springframework.web.servlet/src/test/resources/org/springframework/ui/jasperreports/subReportParent.jrxml @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + <band height="50"> + <line> + <reportElement x="0" y="0" width="515" height="1"/> + <graphicElement/> + </line> + <staticText> + <reportElement x="0" y="10" width="515" height="30"/> + <textElement textAlignment="Center"> + <font reportFont="Arial_Normal" size="22"/> + </textElement> + <text><![CDATA[Master Report]]></text> + </staticText> + </band> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +