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
This commit is contained in:
Chris Beams 2008-12-18 21:27:18 +00:00
parent 4049170b79
commit e1965dea0f
53 changed files with 5876 additions and 6 deletions

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- $Id: beans1.xml,v 1.3 2006/08/20 19:08:40 jhoeller Exp $ -->
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="beans1.bean1" class="org.springframework.beans.factory.access.TestBean">
<property name="name"><value>beans1.bean1</value></property>
</bean>
<bean id="beans1.bean2" class="org.springframework.beans.factory.access.TestBean">
<property name="name"><value>bean2</value></property>
<property name="objRef"><ref bean="beans1.bean2"/></property>
</bean>
</beans>

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- $Id: beans2.xml,v 1.3 2006/08/20 19:08:40 jhoeller Exp $ -->
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="beans2.bean1" class="org.springframework.beans.factory.access.TestBean">
<property name="name"><value>beans2.bean1</value></property>
</bean>
<bean id="beans2.bean2" class="org.springframework.beans.factory.access.TestBean">
<property name="name"><value>beans2.bean2</value></property>
<property name="objRef"><ref bean="beans1.bean1"/></property>
</bean>
</beans>

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<!-- We are only using one definition file for the purposes of this test, since we do not have multiple
classloaders available in the environment to allow combining multiple files of the same name, but
of course the contents within could be spread out across multiple files of the same name withing
different jars -->
<beans>
<!-- this definition could be inside one beanRefFactory.xml file -->
<bean id="a.qualified.name.of.some.sort"
class="org.springframework.beans.factory.xml.XmlBeanFactory">
<constructor-arg value="org/springframework/beans/factory/access/beans1.xml"/>
</bean>
<!-- while the following two could be inside another, also on the classpath,
perhaps coming from another component jar -->
<bean id="another.qualified.name"
class="org.springframework.beans.factory.xml.XmlBeanFactory">
<constructor-arg value="org/springframework/beans/factory/access/beans1.xml"/>
<constructor-arg ref="a.qualified.name.of.some.sort"/> <!-- parent bean factory -->
</bean>
<alias name="another.qualified.name" alias="a.qualified.name.which.is.an.alias"/>
</beans>

View File

@ -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<String, Object> jndiObjects = new ConcurrentHashMap<String, Object>();
/**
* Construct a new JndiTemplate that will always return given objects
* for given names. To be populated through <code>addObject</code> 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;
}
}

View File

@ -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.
*
* <p>This class is not intended for direct usage by applications, although it
* can be used for example to override JndiTemplate's <code>createInitialContext</code>
* 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<String, Object> boundObjects;
private final Hashtable<String, Object> environment = new Hashtable<String, Object>();
/**
* 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<String, Object>();
}
/**
* 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<String, Object> boundObjects, Hashtable<String, Object> env) {
this.root = root;
this.boundObjects = boundObjects;
if (env != null) {
this.environment.putAll(env);
}
}
// Actual implementations of Context methods follow
public NamingEnumeration<NameClassPair> list(String root) throws NamingException {
if (logger.isDebugEnabled()) {
logger.debug("Listing name/class pairs under [" + root + "]");
}
return new NameClassPairEnumeration(this, root);
}
public NamingEnumeration<Binding> 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.
* <p>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<String, Object> 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<NameClassPair> list(Name name) throws NamingException {
throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]");
}
public NamingEnumeration<Binding> 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<T> implements NamingEnumeration<T> {
private Iterator<T> iterator;
private AbstractNamingEnumeration(SimpleNamingContext context, String proot) throws NamingException {
if (!"".equals(proot) && !proot.endsWith("/")) {
proot = proot + "/";
}
String root = context.root + proot;
Map<String, T> contents = new HashMap<String, T>();
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<NameClassPair> {
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<Binding> {
private BindingEnumeration(SimpleNamingContext context, String root) throws NamingException {
super(context, root);
}
protected Binding createObject(String strippedName, Object obj) {
return new Binding(strippedName, obj);
}
}
}

View File

@ -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.
*
* <p>Mainly targeted at test environments, where each test case can
* configure JNDI appropriately, so that <code>new InitialContext()</code>
* 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.
*
* <p>There are various choices for DataSource implementations:
* <ul>
* <li>SingleConnectionDataSource (using the same Connection for all getConnection calls);
* <li>DriverManagerDataSource (creating a new Connection on each getConnection call);
* <li>Apache's Jakarta Commons DBCP offers BasicDataSource (a real pool).
* </ul>
*
* <p>Typical usage in bootstrap code:
*
* <pre class="code">
* SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder();
* DataSource ds = new DriverManagerDataSource(...);
* builder.bind("java:comp/env/jdbc/myds", ds);
* builder.activate();</pre>
*
* 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:
*
* <pre class="code">
* SimpleNamingContextBuilder builder = SimpleNamingContextBuilder.emptyActivatedContextBuilder();
* DataSource ds = new DriverManagerDataSource(...);
* builder.bind("java:comp/env/jdbc/myds", ds);</pre>
*
* Note that you <i>should not</i> call <code>activate()</code> on a builder from
* this factory method, as there will already be an activated one in any case.
*
* <p>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 <code>null</code> 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.
* <p>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, <code>new InitialContext()</code> will always
* return a context from this factory. Use the <code>emptyActivatedContextBuilder()</code>
* 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.
* <p>Call <code>activate()</code> 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);
}
};
}
}

View File

@ -0,0 +1,12 @@
<html>
<body>
The simplest implementation of the JNDI SPI that could possibly work.
<p>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.
</body>
</html>

View File

@ -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;
}
}

View File

@ -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++;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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 {
}

View File

@ -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";
}

View File

@ -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 {
}

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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> 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;
}
}

View File

@ -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;
}
}

View File

@ -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 {
}

View File

@ -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";
}
}

View File

@ -0,0 +1,36 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package 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;
}
}

View File

@ -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;
}
}

View File

@ -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";
}
}

View File

@ -16,8 +16,7 @@
package org.springframework.aop.framework; package org.springframework.aop.framework;
import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;

View File

@ -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.
*
* <p>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<String, String[]> parameters = new LinkedHashMap<String, String[]>(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 <code>null</code>)
* @param requestURI the request URI (may be <code>null</code>)
* @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 <code>null</code> 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 <code>null</code> to use a default MockServletContext)
* @param method the request method (may be <code>null</code>)
* @param requestURI the request URI (may be <code>null</code>)
* @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.
* <p>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.
* <p>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 <emphasis>replacing</emphasis> 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.
* <p>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.
* <p>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 <emphasis>without</emphasis> 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.
* <p>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.
* <p>Multiple values can only be stored as list of Strings,
* following the Servlet spec (see <code>getHeaders</code> accessor).
* As alternative to repeated <code>addHeader</code> 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();
}
}

View File

@ -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<String, Object> jndiObjects = new ConcurrentHashMap<String, Object>();
/**
* Construct a new JndiTemplate that will always return given objects
* for given names. To be populated through <code>addObject</code> 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;
}
}

View File

@ -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.
*
* <p>This class is not intended for direct usage by applications, although it
* can be used for example to override JndiTemplate's <code>createInitialContext</code>
* 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<String, Object> boundObjects;
private final Hashtable<String, Object> environment = new Hashtable<String, Object>();
/**
* 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<String, Object>();
}
/**
* 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<String, Object> boundObjects, Hashtable<String, Object> env) {
this.root = root;
this.boundObjects = boundObjects;
if (env != null) {
this.environment.putAll(env);
}
}
// Actual implementations of Context methods follow
public NamingEnumeration<NameClassPair> list(String root) throws NamingException {
if (logger.isDebugEnabled()) {
logger.debug("Listing name/class pairs under [" + root + "]");
}
return new NameClassPairEnumeration(this, root);
}
public NamingEnumeration<Binding> 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.
* <p>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<String, Object> 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<NameClassPair> list(Name name) throws NamingException {
throw new OperationNotSupportedException("SimpleNamingContext does not support [javax.naming.Name]");
}
public NamingEnumeration<Binding> 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<T> implements NamingEnumeration<T> {
private Iterator<T> iterator;
private AbstractNamingEnumeration(SimpleNamingContext context, String proot) throws NamingException {
if (!"".equals(proot) && !proot.endsWith("/")) {
proot = proot + "/";
}
String root = context.root + proot;
Map<String, T> contents = new HashMap<String, T>();
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<NameClassPair> {
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<Binding> {
private BindingEnumeration(SimpleNamingContext context, String root) throws NamingException {
super(context, root);
}
protected Binding createObject(String strippedName, Object obj) {
return new Binding(strippedName, obj);
}
}
}

View File

@ -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.
*
* <p>Mainly targeted at test environments, where each test case can
* configure JNDI appropriately, so that <code>new InitialContext()</code>
* 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.
*
* <p>There are various choices for DataSource implementations:
* <ul>
* <li>SingleConnectionDataSource (using the same Connection for all getConnection calls);
* <li>DriverManagerDataSource (creating a new Connection on each getConnection call);
* <li>Apache's Jakarta Commons DBCP offers BasicDataSource (a real pool).
* </ul>
*
* <p>Typical usage in bootstrap code:
*
* <pre class="code">
* SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder();
* DataSource ds = new DriverManagerDataSource(...);
* builder.bind("java:comp/env/jdbc/myds", ds);
* builder.activate();</pre>
*
* 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:
*
* <pre class="code">
* SimpleNamingContextBuilder builder = SimpleNamingContextBuilder.emptyActivatedContextBuilder();
* DataSource ds = new DriverManagerDataSource(...);
* builder.bind("java:comp/env/jdbc/myds", ds);</pre>
*
* Note that you <i>should not</i> call <code>activate()</code> on a builder from
* this factory method, as there will already be an activated one in any case.
*
* <p>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 <code>null</code> 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.
* <p>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, <code>new InitialContext()</code> will always
* return a context from this factory. Use the <code>emptyActivatedContextBuilder()</code>
* 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.
* <p>Call <code>activate()</code> 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);
}
};
}
}

View File

@ -20,12 +20,9 @@ import javax.transaction.RollbackException;
import javax.transaction.Status; import javax.transaction.Status;
import javax.transaction.UserTransaction; 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 junit.framework.TestCase;
import org.easymock.MockControl;
import org.easymock.MockControl;
import org.springframework.dao.OptimisticLockingFailureException; import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.mock.jndi.ExpectedLookupTemplate; import org.springframework.mock.jndi.ExpectedLookupTemplate;
import org.springframework.transaction.IllegalTransactionStateException; 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.TransactionCallback;
import org.springframework.transaction.support.TransactionSynchronizationManager; 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 * @author Juergen Hoeller
*/ */

View File

@ -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);
}
}

View File

@ -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<String, String[]> renderParameters = new LinkedHashMap<String, String[]>();
/**
* 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);
}
}

View File

@ -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.
*
* <p>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<String, MultipartFile> multipartFiles = new LinkedHashMap<String, MultipartFile>();
/**
* 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<String> getFileNames() {
return getFileMap().keySet().iterator();
}
public MultipartFile getFile(String name) {
return this.multipartFiles.get(name);
}
public Map<String, MultipartFile> getFileMap() {
return Collections.unmodifiableMap(this.multipartFiles);
}
}

View File

@ -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<String, String> properties = new HashMap<String, String>();
private final List<PortletMode> portletModes;
private final List<WindowState> 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<PortletMode>(3);
this.portletModes.add(PortletMode.VIEW);
this.portletModes.add(PortletMode.EDIT);
this.portletModes.add(PortletMode.HELP);
this.windowStates = new ArrayList<WindowState>(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<PortletMode> supportedPortletModes, List<WindowState> supportedWindowStates) {
this.portletModes = new ArrayList<PortletMode>(supportedPortletModes);
this.windowStates = new ArrayList<WindowState>(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<String> getPropertyNames() {
return Collections.enumeration(this.properties.keySet());
}
public Enumeration<PortletMode> getSupportedPortletModes() {
return Collections.enumeration(this.portletModes);
}
public Enumeration<WindowState> getSupportedWindowStates() {
return Collections.enumeration(this.windowStates);
}
}

View File

@ -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<Locale, ResourceBundle> resourceBundles = new HashMap<Locale, ResourceBundle>();
private final Map<String, String> initParameters = new LinkedHashMap<String, String>();
/**
* 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<String> getInitParameterNames() {
return Collections.enumeration(this.initParameters.keySet());
}
}

View File

@ -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<String, Object> attributes = new LinkedHashMap<String, Object>();
private final Map<String, String> initParameters = new LinkedHashMap<String, String>();
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<String> 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<String> resourcePaths = new HashSet<String>(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<String> 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<String> 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;
}
}

View File

@ -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<String, String[]> preferences = new LinkedHashMap<String, String[]>();
private final Set<String> readOnly = new HashSet<String>();
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<String> getNames() {
return Collections.enumeration(this.preferences.keySet());
}
public Map<String, String[]> 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);
}
}
}

View File

@ -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<String, List<String>> properties = new LinkedHashMap<String, List<String>>();
private final Map<String, Object> attributes = new LinkedHashMap<String, Object>();
private final Map<String, String[]> parameters = new LinkedHashMap<String, String[]>();
private String authType = null;
private String contextPath = "";
private String remoteUser = null;
private Principal userPrincipal = null;
private final Set<String> userRoles = new HashSet<String>();
private boolean secure = false;
private boolean requestedSessionIdValid = true;
private final List<String> responseContentTypes = new LinkedList<String>();
private final List<Locale> locales = new LinkedList<Locale>();
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.
* <p>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<String> list = new LinkedList<String>();
list.add(value);
this.properties.put(key, list);
}
/**
* Add a single value for the specified property.
* <p>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<String> oldList = this.properties.get(key);
if (oldList != null) {
oldList.add(value);
}
else {
List<String> list = new LinkedList<String>();
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<String> getProperties(String key) {
Assert.notNull(key, "property key must not be null");
return Collections.enumeration(this.properties.get(key));
}
public Enumeration<String> 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<String> getAttributeNames() {
checkActive();
return Collections.enumeration(this.attributes.keySet());
}
public void setParameters(Map<String, String[]> 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<String> 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<String> 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<Locale> 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;
}
}

View File

@ -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 + "]");
}
}
}

View File

@ -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<String, String[]> properties = new LinkedHashMap<String, String[]>();
/**
* 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;
}
}

View File

@ -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<String, Object> portletAttributes = new HashMap<String, Object>();
private final Map<String, Object> applicationAttributes = new HashMap<String, Object>();
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<String> getAttributeNames() {
return Collections.enumeration(this.portletAttributes.keySet());
}
public Enumeration<String> 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;
}
}

View File

@ -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<String, String[]> parameters = new LinkedHashMap<String, String[]>();
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<String> 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<String, String[]> 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<String, String[]> entry : this.parameters.entrySet()) {
sb.append(";").append(encodeParameter("param_" + entry.getKey(), entry.getValue()));
}
return (this.secure ? "https:" : "http:") +
"//localhost/mockportlet?" + sb.toString();
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,13 @@
<html>
<body>
A comprehensive set of Portlet API mock objects,
targeted at usage with Spring's web MVC framework.
Useful for testing web contexts and controllers.
<p>More convenient to use than dynamic mock objects
(<a href="http://www.easymock.org">EasyMock</a>) or
existing Portlet API mock objects.
</body>
</html>

View File

@ -0,0 +1,185 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Created using JasperAssistant (http://www.jasperassistant.com) -->
<!DOCTYPE jasperReport PUBLIC "-//JasperReports//DTD Report Design//EN" "http://jasperreports.sourceforge.net/dtds/jasperreport.dtd">
<jasperReport name="DataSourceReport" pageWidth="595" pageHeight="842" columnWidth="515" leftMargin="40" rightMargin="40" topMargin="50" bottomMargin="50">
<reportFont name="Arial_Normal" isDefault="true" fontName="Arial" size="12" isBold="false" isItalic="false" isUnderline="false" isStrikeThrough="false" pdfFontName="Helvetica" pdfEncoding="Cp1252" isPdfEmbedded="false"/>
<reportFont name="Arial_Bold" isDefault="false" fontName="Arial" size="12" isBold="true" isItalic="false" isUnderline="false" isStrikeThrough="false" pdfFontName="Helvetica-Bold" pdfEncoding="Cp1252" isPdfEmbedded="false"/>
<reportFont name="Arial_Italic" isDefault="false" fontName="Arial" size="12" isBold="false" isItalic="true" isUnderline="false" isStrikeThrough="false" pdfFontName="Helvetica-Oblique" pdfEncoding="Cp1252" isPdfEmbedded="false"/>
<parameter name="ReportTitle" class="java.lang.String">
</parameter>
<parameter name="DataFile" class="java.lang.String">
</parameter>
<field name="id" class="java.lang.Integer">
</field>
<field name="name" class="java.lang.String">
</field>
<field name="street" class="java.lang.String">
</field>
<field name="city" class="java.lang.String">
</field>
<variable name="CityNumber" class="java.lang.Integer" resetType="Group" resetGroup="CityGroup" calculation="System">
<initialValueExpression><![CDATA[($V{CityNumber} != null)?(new Integer($V{CityNumber}.intValue() + 1)):(new Integer(1))]]></initialValueExpression>
</variable>
<group name="CityGroup" minHeightToStartNewPage="60">
<groupExpression><![CDATA[$F{city}]]></groupExpression>
<groupHeader>
<band height="20">
<rectangle>
<reportElement x="0" y="4" width="515" height="15" forecolor="#c0c0c0" backcolor="#c0c0c0"/>
<graphicElement/>
</rectangle>
<textField>
<reportElement mode="Opaque" x="0" y="4" width="515" height="15" backcolor="#c0c0c0"/>
<textElement>
<font reportFont="Arial_Bold"/>
</textElement>
<textFieldExpression class="java.lang.String"><![CDATA[" " + String.valueOf($V{CityNumber}) + ". " + String.valueOf($F{city})]]></textFieldExpression>
</textField>
<line>
<reportElement x="0" y="19" width="515" height="1"/>
<graphicElement/>
</line>
</band>
</groupHeader>
<groupFooter>
<band height="20">
<line>
<reportElement x="0" y="-1" width="515" height="1"/>
<graphicElement/>
</line>
<staticText>
<reportElement x="400" y="1" width="60" height="15"/>
<textElement textAlignment="Right">
<font reportFont="Arial_Bold"/>
</textElement>
<text><![CDATA[Count :]]></text>
</staticText>
<textField>
<reportElement x="460" y="1" width="30" height="15"/>
<textElement textAlignment="Right">
<font reportFont="Arial_Bold"/>
</textElement>
<textFieldExpression class="java.lang.Integer"><![CDATA[$V{CityGroup_COUNT}]]></textFieldExpression>
</textField>
</band>
</groupFooter>
</group>
<title>
<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>
</title>
<pageHeader>
<band height="20">
<rectangle>
<reportElement x="0" y="5" width="515" height="15" forecolor="#333333" backcolor="#333333"/>
<graphicElement/>
</rectangle>
<staticText>
<reportElement mode="Opaque" x="0" y="5" width="55" height="15" forecolor="#ffffff" backcolor="#333333"/>
<textElement textAlignment="Center">
<font reportFont="Arial_Bold"/>
</textElement>
<text><![CDATA[ID]]></text>
</staticText>
<staticText>
<reportElement mode="Opaque" x="55" y="5" width="205" height="15" forecolor="#ffffff" backcolor="#333333"/>
<textElement>
<font reportFont="Arial_Bold"/>
</textElement>
<text><![CDATA[Name]]></text>
</staticText>
<staticText>
<reportElement mode="Opaque" x="260" y="5" width="255" height="15" forecolor="#ffffff" backcolor="#333333"/>
<textElement>
<font reportFont="Arial_Bold"/>
</textElement>
<text><![CDATA[Street]]></text>
</staticText>
</band>
</pageHeader>
<detail>
<band height="20">
<textField>
<reportElement x="0" y="4" width="50" height="15"/>
<textElement textAlignment="Right"/>
<textFieldExpression class="java.lang.Integer"><![CDATA[$F{id}]]></textFieldExpression>
</textField>
<textField isStretchWithOverflow="true">
<reportElement positionType="Float" x="55" y="4" width="200" height="15"/>
<textElement/>
<textFieldExpression class="java.lang.String"><![CDATA[$F{name}]]></textFieldExpression>
</textField>
<textField isStretchWithOverflow="true">
<reportElement positionType="Float" x="260" y="4" width="255" height="15"/>
<textElement/>
<textFieldExpression class="java.lang.String"><![CDATA[$F{street}]]></textFieldExpression>
</textField>
<line>
<reportElement positionType="Float" x="0" y="19" width="515" height="1" forecolor="#808080"/>
<graphicElement/>
</line>
</band>
</detail>
<pageFooter>
<band height="40">
<line>
<reportElement x="0" y="10" width="515" height="1"/>
<graphicElement/>
</line>
<textField>
<reportElement x="200" y="20" width="80" height="15"/>
<textElement textAlignment="Right"/>
<textFieldExpression class="java.lang.String"><![CDATA[$R{page} + " " + String.valueOf($V{PAGE_NUMBER}) + " of"]]></textFieldExpression>
</textField>
<textField evaluationTime="Report">
<reportElement x="280" y="20" width="75" height="15"/>
<textElement/>
<textFieldExpression class="java.lang.String"><![CDATA[" " + String.valueOf($V{PAGE_NUMBER})]]></textFieldExpression>
</textField>
</band>
</pageFooter>
<lastPageFooter>
<band height="60">
<textField>
<reportElement x="0" y="10" width="515" height="15"/>
<textElement textAlignment="Center"/>
<textFieldExpression class="java.lang.String"><![CDATA["There were " +
String.valueOf($V{REPORT_COUNT}) +
" address records on this report."]]></textFieldExpression>
</textField>
<line>
<reportElement x="0" y="30" width="515" height="1"/>
<graphicElement/>
</line>
<textField>
<reportElement x="200" y="40" width="80" height="15"/>
<textElement textAlignment="Right"/>
<textFieldExpression class="java.lang.String"><![CDATA[$R{page} + " " + String.valueOf($V{PAGE_NUMBER}) + " of"]]></textFieldExpression>
</textField>
<textField evaluationTime="Report">
<reportElement x="280" y="40" width="75" height="15"/>
<textElement/>
<textFieldExpression class="java.lang.String"><![CDATA[" " + String.valueOf($V{PAGE_NUMBER})]]></textFieldExpression>
</textField>
</band>
</lastPageFooter>
</jasperReport>

View File

@ -0,0 +1,227 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Created using JasperAssistant (http://www.jasperassistant.com) -->
<!DOCTYPE jasperReport PUBLIC "-//JasperReports//DTD Report Design//EN" "http://jasperreports.sourceforge.net/dtds/jasperreport.dtd">
<jasperReport name="ProductReport" columnCount="2" pageWidth="325" pageHeight="842" columnWidth="160" columnSpacing="5" leftMargin="0" rightMargin="0" topMargin="0" bottomMargin="0">
<reportFont name="Arial_Normal" isDefault="true" fontName="Arial" size="8" isBold="false" isItalic="false" isUnderline="false" isStrikeThrough="false" pdfFontName="Helvetica" pdfEncoding="Cp1252" isPdfEmbedded="false"/>
<reportFont name="Arial_Bold" isDefault="false" fontName="Arial" size="8" isBold="true" isItalic="false" isUnderline="false" isStrikeThrough="false" pdfFontName="Helvetica-Bold" pdfEncoding="Cp1252" isPdfEmbedded="false"/>
<reportFont name="Arial_Italic" isDefault="false" fontName="Arial" size="8" isBold="false" isItalic="true" isUnderline="false" isStrikeThrough="false" pdfFontName="Helvetica-Oblique" pdfEncoding="Cp1252" isPdfEmbedded="false"/>
<parameter name="City" class="java.lang.String"/>
<field name="id" class="java.lang.Integer">
</field>
<field name="name" class="java.lang.String">
</field>
<field name="quantity" class="java.lang.Float">
</field>
<field name="price" class="java.lang.Float">
</field>
<variable name="QuantityProductSum" class="java.lang.Float" resetType="Group" resetGroup="ProductGroup" calculation="Sum">
<variableExpression><![CDATA[$F{quantity}]]></variableExpression>
</variable>
<variable name="PriceProductSum" class="java.lang.Float" resetType="Group" resetGroup="ProductGroup" calculation="Sum">
<variableExpression><![CDATA[$F{price}]]></variableExpression>
</variable>
<variable name="QuantitySum" class="java.lang.Float" calculation="Sum">
<variableExpression><![CDATA[$F{quantity}]]></variableExpression>
</variable>
<variable name="PriceSum" class="java.lang.Float" calculation="Sum">
<variableExpression><![CDATA[$F{price}]]></variableExpression>
</variable>
<variable name="ProductCount" class="java.lang.Integer" resetType="Group" resetGroup="ProductGroup" calculation="System">
<initialValueExpression><![CDATA[($V{ProductCount} != null)?(new Integer($V{ProductCount}.intValue() + 1)):(new Integer(1))]]></initialValueExpression>
</variable>
<group name="ProductGroup">
<groupExpression><![CDATA[$F{id}]]></groupExpression>
<groupHeader>
<band height="14">
<textField>
<reportElement x="0" y="2" width="15" height="10"/>
<textElement textAlignment="Right"/>
<textFieldExpression class="java.lang.Integer"><![CDATA[$F{id}]]></textFieldExpression>
</textField>
<textField isStretchWithOverflow="true">
<reportElement positionType="Float" x="20" y="2" width="80" height="10"/>
<textElement/>
<textFieldExpression class="java.lang.String"><![CDATA[$F{name}]]></textFieldExpression>
</textField>
<textField isStretchWithOverflow="true" evaluationTime="Group" evaluationGroup="ProductGroup" pattern="#0">
<reportElement positionType="Float" x="105" y="2" width="20" height="10"/>
<textElement textAlignment="Right"/>
<textFieldExpression class="java.lang.Float"><![CDATA[$V{QuantityProductSum}]]></textFieldExpression>
</textField>
<textField isStretchWithOverflow="true" evaluationTime="Group" evaluationGroup="ProductGroup" pattern="#0.00">
<reportElement positionType="Float" x="130" y="2" width="30" height="10"/>
<textElement textAlignment="Right"/>
<textFieldExpression class="java.lang.Float"><![CDATA[$V{PriceProductSum}]]></textFieldExpression>
</textField>
</band>
</groupHeader>
<groupFooter>
<band>
</band>
</groupFooter>
</group>
<title>
<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>
</title>
<pageHeader>
<band height="14">
<rectangle>
<reportElement mode="Transparent" x="0" y="2" width="325" height="10" forecolor="#808000"/>
<graphicElement pen="Thin"/>
</rectangle>
<staticText>
<reportElement x="0" y="2" width="60" height="10" forecolor="#808000"/>
<textElement>
<font reportFont="Arial_Italic"/>
</textElement>
<text><![CDATA[Page Header]]></text>
</staticText>
</band>
</pageHeader>
<columnHeader>
<band height="14">
<rectangle>
<reportElement x="0" y="2" width="160" height="10" forecolor="#ffff99" backcolor="#ffff99"/>
<graphicElement/>
</rectangle>
<staticText>
<reportElement mode="Opaque" x="0" y="2" width="20" height="10" backcolor="#ffff99"/>
<textElement textAlignment="Center">
<font reportFont="Arial_Bold"/>
</textElement>
<text><![CDATA[ID]]></text>
</staticText>
<staticText>
<reportElement mode="Opaque" x="20" y="2" width="85" height="10" backcolor="#ffff99"/>
<textElement>
<font reportFont="Arial_Bold"/>
</textElement>
<text><![CDATA[Name]]></text>
</staticText>
<staticText>
<reportElement mode="Opaque" x="105" y="2" width="20" height="10" backcolor="#ffff99"/>
<textElement textAlignment="Right">
<font reportFont="Arial_Bold"/>
</textElement>
<text><![CDATA[Qty]]></text>
</staticText>
<staticText>
<reportElement mode="Opaque" x="125" y="2" width="35" height="10" backcolor="#ffff99"/>
<textElement textAlignment="Right">
<font reportFont="Arial_Bold"/>
</textElement>
<text><![CDATA[Price]]></text>
</staticText>
</band>
</columnHeader>
<columnFooter>
<band height="14">
<line>
<reportElement x="0" y="1" width="160" height="1"/>
<graphicElement pen="Thin"/>
</line>
<staticText>
<reportElement x="0" y="2" width="60" height="10"/>
<textElement>
<font reportFont="Arial_Italic"/>
</textElement>
<text><![CDATA[Column Footer]]></text>
</staticText>
<staticText>
<reportElement x="70" y="2" width="30" height="10"/>
<textElement textAlignment="Right">
<font reportFont="Arial_Bold"/>
</textElement>
<text><![CDATA[Total :]]></text>
</staticText>
<textField pattern="#0">
<reportElement x="105" y="2" width="20" height="10"/>
<textElement textAlignment="Right">
<font reportFont="Arial_Bold"/>
</textElement>
<textFieldExpression class="java.lang.Float"><![CDATA[$V{QuantitySum}]]></textFieldExpression>
</textField>
<textField pattern="#0.00">
<reportElement x="130" y="2" width="30" height="10"/>
<textElement textAlignment="Right">
<font reportFont="Arial_Bold"/>
</textElement>
<textFieldExpression class="java.lang.Float"><![CDATA[$V{PriceSum}]]></textFieldExpression>
</textField>
</band>
</columnFooter>
<pageFooter>
<band height="14">
<rectangle>
<reportElement mode="Transparent" x="0" y="2" width="325" height="10" forecolor="#808000"/>
<graphicElement pen="Thin"/>
</rectangle>
<staticText>
<reportElement x="0" y="2" width="60" height="10" forecolor="#808000"/>
<textElement>
<font reportFont="Arial_Italic"/>
</textElement>
<text><![CDATA[Page Footer]]></text>
</staticText>
<textField>
<reportElement x="150" y="2" width="100" height="10" forecolor="#808000"/>
<textElement textAlignment="Right">
<font reportFont="Arial_Italic"/>
</textElement>
<textFieldExpression class="java.lang.String"><![CDATA["Page " + String.valueOf($V{PAGE_NUMBER}) + " of "]]></textFieldExpression>
</textField>
<textField evaluationTime="Report">
<reportElement x="250" y="2" width="50" height="10" forecolor="#808000"/>
<textElement>
<font reportFont="Arial_Italic"/>
</textElement>
<textFieldExpression class="java.lang.Integer"><![CDATA[$V{PAGE_NUMBER}]]></textFieldExpression>
</textField>
</band>
</pageFooter>
<summary>
<band height="14">
<rectangle>
<reportElement x="0" y="2" width="325" height="10" forecolor="#808000" backcolor="#808000"/>
<graphicElement pen="Thin"/>
</rectangle>
<staticText>
<reportElement mode="Opaque" x="0" y="2" width="230" height="10" backcolor="#808000"/>
<textElement>
<font reportFont="Arial_Italic"/>
</textElement>
<text><![CDATA[Summary]]></text>
</staticText>
<staticText>
<reportElement mode="Opaque" x="230" y="2" width="55" height="10" backcolor="#808000"/>
<textElement textAlignment="Right">
<font reportFont="Arial_Bold"/>
</textElement>
<text><![CDATA[Count :]]></text>
</staticText>
<textField pattern="#0">
<reportElement mode="Opaque" x="285" y="2" width="40" height="10" backcolor="#808000"/>
<textElement textAlignment="Right">
<font reportFont="Arial_Bold"/>
</textElement>
<textFieldExpression class="java.lang.Integer"><![CDATA[$V{ProductCount}]]></textFieldExpression>
</textField>
</band>
</summary>
</jasperReport>

View File

@ -0,0 +1,103 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Created using JasperAssistant (http://www.jasperassistant.com) -->
<!DOCTYPE jasperReport PUBLIC "-//JasperReports//DTD Report Design//EN" "http://jasperreports.sourceforge.net/dtds/jasperreport.dtd">
<jasperReport name="MasterReport" pageWidth="595" pageHeight="842" columnWidth="515" leftMargin="40" rightMargin="40" topMargin="50" bottomMargin="50">
<reportFont name="Arial_Normal" isDefault="true" fontName="Arial" size="12" isBold="false" isItalic="false" isUnderline="false" isStrikeThrough="false" pdfFontName="Helvetica" pdfEncoding="Cp1252" isPdfEmbedded="false"/>
<reportFont name="Arial_Bold" isDefault="false" fontName="Arial" size="12" isBold="true" isItalic="false" isUnderline="false" isStrikeThrough="false" pdfFontName="Helvetica-Bold" pdfEncoding="Cp1252" isPdfEmbedded="false"/>
<reportFont name="Arial_Italic" isDefault="false" fontName="Arial" size="12" isBold="false" isItalic="true" isUnderline="false" isStrikeThrough="false" pdfFontName="Helvetica-Oblique" pdfEncoding="Cp1252" isPdfEmbedded="false"/>
<parameter name="ProductsSubReport" class="net.sf.jasperreports.engine.JasperReport"/>
<parameter name="SubReportData" class="net.sf.jasperreports.engine.JRDataSource"/>
<field name="city" class="java.lang.String">
</field>
<title>
<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>
</title>
<pageHeader>
<band height="21">
<rectangle>
<reportElement x="0" y="5" width="515" height="15" backcolor="#333333"/>
<graphicElement pen="None"/>
</rectangle>
<staticText>
<reportElement mode="Opaque" x="0" y="5" width="515" height="15" forecolor="#ffffff" backcolor="#333333"/>
<textElement>
<font reportFont="Arial_Bold"/>
</textElement>
<text><![CDATA[City List]]></text>
</staticText>
<line>
<reportElement x="0" y="20" width="515" height="1"/>
<graphicElement/>
</line>
</band>
</pageHeader>
<detail>
<band height="50">
<textField>
<reportElement x="5" y="5" width="100" height="15" isPrintWhenDetailOverflows="true"/>
<textElement>
<font reportFont="Arial_Bold"/>
</textElement>
<textFieldExpression class="java.lang.String"><![CDATA[$F{city}]]></textFieldExpression>
</textField>
<staticText>
<reportElement isPrintRepeatedValues="false" x="110" y="5" width="100" height="15" isPrintWhenDetailOverflows="true"/>
<textElement>
<font reportFont="Arial_Bold"/>
</textElement>
<text><![CDATA[(continued)]]></text>
</staticText>
<line>
<reportElement x="0" y="20" width="515" height="1" isPrintWhenDetailOverflows="true"/>
<graphicElement/>
</line>
<subreport>
<reportElement isPrintRepeatedValues="false" x="5" y="25" width="325" height="20" isRemoveLineWhenBlank="true" backcolor="#ffcc99"/>
<subreportParameter name="City">
<subreportParameterExpression><![CDATA[$F{city}]]></subreportParameterExpression>
</subreportParameter>
<dataSourceExpression><![CDATA[$P{SubReportData}]]></dataSourceExpression>
<subreportExpression class="net.sf.jasperreports.engine.JasperReport"><![CDATA[$P{ProductsSubReport}]]></subreportExpression>
</subreport>
<!--<subreport>
<reportElement positionType="Float" x="335" y="25" width="175" height="20" isRemoveLineWhenBlank="true" backcolor="#99ccff"/>
<subreportParameter name="City">
<subreportParameterExpression><![CDATA[$F{City}]]></subreportParameterExpression>
</subreportParameter>
<connectionExpression><![CDATA[$P{REPORT_CONNECTION}]]></connectionExpression>
<subreportExpression class="java.lang.String"><![CDATA["AddressReport.jasper"]]></subreportExpression>
</subreport> -->
</band>
</detail>
<pageFooter>
<band height="40">
<line>
<reportElement x="0" y="10" width="515" height="1"/>
<graphicElement/>
</line>
<textField>
<reportElement x="200" y="20" width="80" height="15"/>
<textElement textAlignment="Right"/>
<textFieldExpression class="java.lang.String"><![CDATA["Page " + String.valueOf($V{PAGE_NUMBER}) + " of"]]></textFieldExpression>
</textField>
<textField evaluationTime="Report">
<reportElement x="280" y="20" width="75" height="15"/>
<textElement/>
<textFieldExpression class="java.lang.String"><![CDATA[" " + String.valueOf($V{PAGE_NUMBER})]]></textFieldExpression>
</textField>
</band>
</pageFooter>
</jasperReport>