Rename modules {org.springframework.*=>spring-*}

This renaming more intuitively expresses the relationship between
subprojects and the JAR artifacts they produce.

Tracking history across these renames is possible, but it requires
use of the --follow flag to `git log`, for example

    $ git log spring-aop/src/main/java/org/springframework/aop/Advisor.java

will show history up until the renaming event, where

    $ git log --follow spring-aop/src/main/java/org/springframework/aop/Advisor.java

will show history for all changes to the file, before and after the
renaming.

See http://chrisbeams.com/git-diff-across-renamed-directories
This commit is contained in:
Chris Beams
2012-01-20 22:51:02 +01:00
parent b6cb514d38
commit 02a4473c62
5671 changed files with 20 additions and 32 deletions

View File

@@ -0,0 +1,35 @@
/*
* 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;
import org.springframework.core.enums.ShortCodedLabeledEnum;
/**
* @author Rob Harrop
*/
public class Colour extends ShortCodedLabeledEnum {
public static final Colour RED = new Colour(0, "RED");
public static final Colour BLUE = new Colour(1, "BLUE");
public static final Colour GREEN = new Colour(2, "GREEN");
public static final Colour PURPLE = new Colour(3, "PURPLE");
private Colour(int code, String label) {
super(code, label);
}
}

View File

@@ -0,0 +1,85 @@
/*
* 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;
import java.io.Serializable;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
/**
* @author Juergen Hoeller
* @since 21.08.2003
*/
public class DerivedTestBean extends TestBean implements Serializable, BeanNameAware, DisposableBean {
private String beanName;
private boolean initialized;
private boolean destroyed;
public DerivedTestBean() {
}
public DerivedTestBean(String[] names) {
if (names == null || names.length < 2) {
throw new IllegalArgumentException("Invalid names array");
}
setName(names[0]);
setBeanName(names[1]);
}
public static DerivedTestBean create(String[] names) {
return new DerivedTestBean(names);
}
public void setBeanName(String beanName) {
if (this.beanName == null || beanName == null) {
this.beanName = beanName;
}
}
public String getBeanName() {
return beanName;
}
public void setSpouseRef(String name) {
setSpouse(new TestBean(name));
}
public void initialize() {
this.initialized = true;
}
public boolean wasInitialized() {
return initialized;
}
public void destroy() {
this.destroyed = true;
}
public boolean wasDestroyed() {
return destroyed;
}
}

View File

@@ -0,0 +1,23 @@
/*
* 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;
public interface INestedTestBean {
public String getCompany();
}

View File

@@ -0,0 +1,24 @@
/*
* 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;
public interface IOther {
void absquatulate();
}

View File

@@ -0,0 +1,71 @@
/*
* 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;
import java.io.IOException;
/**
* Interface used for {@link org.springframework.beans.TestBean}.
*
* <p>Two methods are the same as on Person, but if this
* extends person it breaks quite a few tests..
*
* @author Rod Johnson
* @author Juergen Hoeller
*/
public interface ITestBean {
int getAge();
void setAge(int age);
String getName();
void setName(String name);
ITestBean getSpouse();
void setSpouse(ITestBean spouse);
ITestBean[] getSpouses();
String[] getStringArray();
void setStringArray(String[] stringArray);
/**
* Throws a given (non-null) exception.
*/
void exceptional(Throwable t) throws Throwable;
Object returnsThis();
INestedTestBean getDoctor();
INestedTestBean getLawyer();
IndexedTestBean getNestedIndexedBean();
/**
* Increment the age by one.
* @return the previous age
*/
int haveBirthday();
void unreliableFileOperation() throws IOException;
}

View File

@@ -0,0 +1,145 @@
/*
* 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.beans;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeSet;
/**
* @author Juergen Hoeller
* @since 11.11.2003
*/
public class IndexedTestBean {
private TestBean[] array;
private Collection collection;
private List list;
private Set set;
private SortedSet sortedSet;
private Map map;
private SortedMap sortedMap;
public IndexedTestBean() {
this(true);
}
public IndexedTestBean(boolean populate) {
if (populate) {
populate();
}
}
public void populate() {
TestBean tb0 = new TestBean("name0", 0);
TestBean tb1 = new TestBean("name1", 0);
TestBean tb2 = new TestBean("name2", 0);
TestBean tb3 = new TestBean("name3", 0);
TestBean tb4 = new TestBean("name4", 0);
TestBean tb5 = new TestBean("name5", 0);
TestBean tb6 = new TestBean("name6", 0);
TestBean tb7 = new TestBean("name7", 0);
TestBean tbX = new TestBean("nameX", 0);
TestBean tbY = new TestBean("nameY", 0);
this.array = new TestBean[] {tb0, tb1};
this.list = new ArrayList();
this.list.add(tb2);
this.list.add(tb3);
this.set = new TreeSet();
this.set.add(tb6);
this.set.add(tb7);
this.map = new HashMap();
this.map.put("key1", tb4);
this.map.put("key2", tb5);
this.map.put("key.3", tb5);
List list = new ArrayList();
list.add(tbX);
list.add(tbY);
this.map.put("key4", list);
}
public TestBean[] getArray() {
return array;
}
public void setArray(TestBean[] array) {
this.array = array;
}
public Collection getCollection() {
return collection;
}
public void setCollection(Collection collection) {
this.collection = collection;
}
public List getList() {
return list;
}
public void setList(List list) {
this.list = list;
}
public Set getSet() {
return set;
}
public void setSet(Set set) {
this.set = set;
}
public SortedSet getSortedSet() {
return sortedSet;
}
public void setSortedSet(SortedSet sortedSet) {
this.sortedSet = sortedSet;
}
public Map getMap() {
return map;
}
public void setMap(Map map) {
this.map = map;
}
public SortedMap getSortedMap() {
return sortedMap;
}
public void setSortedMap(SortedMap sortedMap) {
this.sortedMap = sortedMap;
}
}

View File

@@ -0,0 +1,60 @@
/*
* 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;
/**
* Simple nested test bean used for testing bean factories, AOP framework etc.
*
* @author Trevor D. Cook
* @since 30.09.2003
*/
public class NestedTestBean implements INestedTestBean {
private String company = "";
public NestedTestBean() {
}
public NestedTestBean(String company) {
setCompany(company);
}
public void setCompany(String company) {
this.company = (company != null ? company : "");
}
public String getCompany() {
return company;
}
public boolean equals(Object obj) {
if (!(obj instanceof NestedTestBean)) {
return false;
}
NestedTestBean ntb = (NestedTestBean) obj;
return this.company.equals(ntb.company);
}
public int hashCode() {
return this.company.hashCode();
}
public String toString() {
return "NestedTestBean: " + this.company;
}
}

View File

@@ -0,0 +1,437 @@
/*
* 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.beans;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.util.ObjectUtils;
/**
* Simple test bean used for testing bean factories, the AOP framework etc.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @since 15 April 2001
*/
public class TestBean implements BeanNameAware, BeanFactoryAware, ITestBean, IOther, Comparable {
private String beanName;
private String country;
private BeanFactory beanFactory;
private boolean postProcessed;
private String name;
private String sex;
private int age;
private boolean jedi;
private ITestBean[] spouses;
private String touchy;
private String[] stringArray;
private Integer[] someIntegerArray;
private Date date = new Date();
private Float myFloat = new Float(0.0);
private Collection friends = new LinkedList();
private Set someSet = new HashSet();
private Map someMap = new HashMap();
private List someList = new ArrayList();
private Properties someProperties = new Properties();
private INestedTestBean doctor = new NestedTestBean();
private INestedTestBean lawyer = new NestedTestBean();
private IndexedTestBean nestedIndexedBean;
private boolean destroyed;
private Number someNumber;
private Colour favouriteColour;
private Boolean someBoolean;
private List otherColours;
private List pets;
public TestBean() {
}
public TestBean(String name) {
this.name = name;
}
public TestBean(ITestBean spouse) {
this.spouses = new ITestBean[] {spouse};
}
public TestBean(String name, int age) {
this.name = name;
this.age = age;
}
public TestBean(ITestBean spouse, Properties someProperties) {
this.spouses = new ITestBean[] {spouse};
this.someProperties = someProperties;
}
public TestBean(List someList) {
this.someList = someList;
}
public TestBean(Set someSet) {
this.someSet = someSet;
}
public TestBean(Map someMap) {
this.someMap = someMap;
}
public TestBean(Properties someProperties) {
this.someProperties = someProperties;
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
public String getBeanName() {
return beanName;
}
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
public BeanFactory getBeanFactory() {
return beanFactory;
}
public void setPostProcessed(boolean postProcessed) {
this.postProcessed = postProcessed;
}
public boolean isPostProcessed() {
return postProcessed;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
if (this.name == null) {
this.name = sex;
}
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public boolean isJedi() {
return jedi;
}
public void setJedi(boolean jedi) {
this.jedi = jedi;
}
public ITestBean getSpouse() {
return (spouses != null ? spouses[0] : null);
}
public void setSpouse(ITestBean spouse) {
this.spouses = new ITestBean[] {spouse};
}
public ITestBean[] getSpouses() {
return spouses;
}
public String getTouchy() {
return touchy;
}
public void setTouchy(String touchy) throws Exception {
if (touchy.indexOf('.') != -1) {
throw new Exception("Can't contain a .");
}
if (touchy.indexOf(',') != -1) {
throw new NumberFormatException("Number format exception: contains a ,");
}
this.touchy = touchy;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String[] getStringArray() {
return stringArray;
}
public void setStringArray(String[] stringArray) {
this.stringArray = stringArray;
}
public Integer[] getSomeIntegerArray() {
return someIntegerArray;
}
public void setSomeIntegerArray(Integer[] someIntegerArray) {
this.someIntegerArray = someIntegerArray;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public Float getMyFloat() {
return myFloat;
}
public void setMyFloat(Float myFloat) {
this.myFloat = myFloat;
}
public Collection getFriends() {
return friends;
}
public void setFriends(Collection friends) {
this.friends = friends;
}
public Set getSomeSet() {
return someSet;
}
public void setSomeSet(Set someSet) {
this.someSet = someSet;
}
public Map getSomeMap() {
return someMap;
}
public void setSomeMap(Map someMap) {
this.someMap = someMap;
}
public List getSomeList() {
return someList;
}
public void setSomeList(List someList) {
this.someList = someList;
}
public Properties getSomeProperties() {
return someProperties;
}
public void setSomeProperties(Properties someProperties) {
this.someProperties = someProperties;
}
public INestedTestBean getDoctor() {
return doctor;
}
public void setDoctor(INestedTestBean doctor) {
this.doctor = doctor;
}
public INestedTestBean getLawyer() {
return lawyer;
}
public void setLawyer(INestedTestBean lawyer) {
this.lawyer = lawyer;
}
public Number getSomeNumber() {
return someNumber;
}
public void setSomeNumber(Number someNumber) {
this.someNumber = someNumber;
}
public Colour getFavouriteColour() {
return favouriteColour;
}
public void setFavouriteColour(Colour favouriteColour) {
this.favouriteColour = favouriteColour;
}
public Boolean getSomeBoolean() {
return someBoolean;
}
public void setSomeBoolean(Boolean someBoolean) {
this.someBoolean = someBoolean;
}
public IndexedTestBean getNestedIndexedBean() {
return nestedIndexedBean;
}
public void setNestedIndexedBean(IndexedTestBean nestedIndexedBean) {
this.nestedIndexedBean = nestedIndexedBean;
}
public List getOtherColours() {
return otherColours;
}
public void setOtherColours(List otherColours) {
this.otherColours = otherColours;
}
public List getPets() {
return pets;
}
public void setPets(List pets) {
this.pets = pets;
}
/**
* @see org.springframework.beans.ITestBean#exceptional(Throwable)
*/
public void exceptional(Throwable t) throws Throwable {
if (t != null) {
throw t;
}
}
public void unreliableFileOperation() throws IOException {
throw new IOException();
}
/**
* @see org.springframework.beans.ITestBean#returnsThis()
*/
public Object returnsThis() {
return this;
}
/**
* @see org.springframework.beans.IOther#absquatulate()
*/
public void absquatulate() {
}
public int haveBirthday() {
return age++;
}
public void destroy() {
this.destroyed = true;
}
public boolean wasDestroyed() {
return destroyed;
}
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (other == null || !(other instanceof TestBean)) {
return false;
}
TestBean tb2 = (TestBean) other;
return (ObjectUtils.nullSafeEquals(this.name, tb2.name) && this.age == tb2.age);
}
public int hashCode() {
return this.age;
}
public int compareTo(Object other) {
if (this.name != null && other instanceof TestBean) {
return this.name.compareTo(((TestBean) other).getName());
}
else {
return 1;
}
}
public String toString() {
return this.name;
}
}

View File

@@ -0,0 +1,86 @@
/*
* 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.parsing;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.springframework.core.CollectionFactory;
/**
* @author Rob Harrop
* @author Juergen Hoeller
*/
public class CollectingReaderEventListener implements ReaderEventListener {
private final List defaults = new LinkedList();
private final Map componentDefinitions = CollectionFactory.createLinkedMapIfPossible(8);
private final Map aliasMap = CollectionFactory.createLinkedMapIfPossible(8);
private final List imports = new LinkedList();
public void defaultsRegistered(DefaultsDefinition defaultsDefinition) {
this.defaults.add(defaultsDefinition);
}
public List getDefaults() {
return Collections.unmodifiableList(this.defaults);
}
public void componentRegistered(ComponentDefinition componentDefinition) {
this.componentDefinitions.put(componentDefinition.getName(), componentDefinition);
}
public ComponentDefinition getComponentDefinition(String name) {
return (ComponentDefinition) this.componentDefinitions.get(name);
}
public ComponentDefinition[] getComponentDefinitions() {
Collection collection = this.componentDefinitions.values();
return (ComponentDefinition[]) collection.toArray(new ComponentDefinition[collection.size()]);
}
public void aliasRegistered(AliasDefinition aliasDefinition) {
List aliases = (List) this.aliasMap.get(aliasDefinition.getBeanName());
if(aliases == null) {
aliases = new ArrayList();
this.aliasMap.put(aliasDefinition.getBeanName(), aliases);
}
aliases.add(aliasDefinition);
}
public List getAliases(String beanName) {
List aliases = (List) this.aliasMap.get(beanName);
return aliases == null ? null : Collections.unmodifiableList(aliases);
}
public void importProcessed(ImportDefinition importDefinition) {
this.imports.add(importDefinition);
}
public List getImports() {
return Collections.unmodifiableList(this.imports);
}
}

View File

@@ -0,0 +1,231 @@
/*
* Copyright 2002-2009 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.dao.annotation;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.persistence.PersistenceException;
import junit.framework.TestCase;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.dao.support.DataAccessUtilsTests.MapPersistenceExceptionTranslator;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.stereotype.Repository;
/**
* Tests for PersistenceExceptionTranslationAdvisor's exception translation, as applied by
* PersistenceExceptionTranslationPostProcessor.
*
* @author Rod Johnson
* @author Juergen Hoeller
*/
public class PersistenceExceptionTranslationAdvisorTests extends TestCase {
private RuntimeException doNotTranslate = new RuntimeException();
private PersistenceException persistenceException1 = new PersistenceException();
protected RepositoryInterface createProxy(RepositoryInterfaceImpl target) {
MapPersistenceExceptionTranslator mpet = new MapPersistenceExceptionTranslator();
mpet.addTranslation(persistenceException1, new InvalidDataAccessApiUsageException("", persistenceException1));
ProxyFactory pf = new ProxyFactory(target);
pf.addInterface(RepositoryInterface.class);
addPersistenceExceptionTranslation(pf, mpet);
return (RepositoryInterface) pf.getProxy();
}
protected void addPersistenceExceptionTranslation(ProxyFactory pf, PersistenceExceptionTranslator pet) {
pf.addAdvisor(new PersistenceExceptionTranslationAdvisor(pet, Repository.class));
}
public void testNoTranslationNeeded() {
RepositoryInterfaceImpl target = new RepositoryInterfaceImpl();
RepositoryInterface ri = createProxy(target);
ri.noThrowsClause();
ri.throwsPersistenceException();
target.setBehavior(persistenceException1);
try {
ri.noThrowsClause();
fail();
}
catch (RuntimeException ex) {
assertSame(persistenceException1, ex);
}
try {
ri.throwsPersistenceException();
fail();
}
catch (RuntimeException ex) {
assertSame(persistenceException1, ex);
}
}
public void testTranslationNotNeededForTheseExceptions() {
RepositoryInterfaceImpl target = new StereotypedRepositoryInterfaceImpl();
RepositoryInterface ri = createProxy(target);
ri.noThrowsClause();
ri.throwsPersistenceException();
target.setBehavior(doNotTranslate);
try {
ri.noThrowsClause();
fail();
}
catch (RuntimeException ex) {
assertSame(doNotTranslate, ex);
}
try {
ri.throwsPersistenceException();
fail();
}
catch (RuntimeException ex) {
assertSame(doNotTranslate, ex);
}
}
public void testTranslationNeededForTheseExceptions() {
doTestTranslationNeededForTheseExceptions(new StereotypedRepositoryInterfaceImpl());
}
public void testTranslationNeededForTheseExceptionsOnSuperclass() {
doTestTranslationNeededForTheseExceptions(new MyStereotypedRepositoryInterfaceImpl());
}
public void testTranslationNeededForTheseExceptionsWithCustomStereotype() {
doTestTranslationNeededForTheseExceptions(new CustomStereotypedRepositoryInterfaceImpl());
}
public void testTranslationNeededForTheseExceptionsOnInterface() {
doTestTranslationNeededForTheseExceptions(new MyInterfaceStereotypedRepositoryInterfaceImpl());
}
public void testTranslationNeededForTheseExceptionsOnInheritedInterface() {
doTestTranslationNeededForTheseExceptions(new MyInterfaceInheritedStereotypedRepositoryInterfaceImpl());
}
private void doTestTranslationNeededForTheseExceptions(RepositoryInterfaceImpl target) {
RepositoryInterface ri = createProxy(target);
target.setBehavior(persistenceException1);
try {
ri.noThrowsClause();
fail();
}
catch (DataAccessException ex) {
// Expected
assertSame(persistenceException1, ex.getCause());
}
catch (PersistenceException ex) {
fail("Should have been translated");
}
try {
ri.throwsPersistenceException();
fail();
}
catch (PersistenceException ex) {
assertSame(persistenceException1, ex);
}
}
public interface RepositoryInterface {
void noThrowsClause();
void throwsPersistenceException() throws PersistenceException;
}
public static class RepositoryInterfaceImpl implements RepositoryInterface {
private RuntimeException runtimeException;
public void setBehavior(RuntimeException rex) {
this.runtimeException = rex;
}
public void noThrowsClause() {
if (runtimeException != null) {
throw runtimeException;
}
}
public void throwsPersistenceException() throws PersistenceException {
if (runtimeException != null) {
throw runtimeException;
}
}
}
@Repository
public static class StereotypedRepositoryInterfaceImpl extends RepositoryInterfaceImpl {
// Extends above class just to add repository annotation
}
public static class MyStereotypedRepositoryInterfaceImpl extends StereotypedRepositoryInterfaceImpl {
}
@MyRepository
public static class CustomStereotypedRepositoryInterfaceImpl extends RepositoryInterfaceImpl {
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Repository
public @interface MyRepository {
}
@Repository
public interface StereotypedInterface {
}
public static class MyInterfaceStereotypedRepositoryInterfaceImpl extends RepositoryInterfaceImpl
implements StereotypedInterface {
}
public interface StereotypedInheritingInterface extends StereotypedInterface {
}
public static class MyInterfaceInheritedStereotypedRepositoryInterfaceImpl extends RepositoryInterfaceImpl
implements StereotypedInheritingInterface {
}
}

View File

@@ -0,0 +1,45 @@
/*
* 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.dao.annotation;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.dao.support.PersistenceExceptionTranslationInterceptor;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.stereotype.Repository;
/**
* Tests for standalone usage of a PersistenceExceptionTranslationInterceptor, as explicit advice bean in a BeanFactory
* rather than applied as part of a PersistenceExceptionTranslationAdvisor.
*
* @author Juergen Hoeller
*/
public class PersistenceExceptionTranslationInterceptorTests extends PersistenceExceptionTranslationAdvisorTests {
@Override
protected void addPersistenceExceptionTranslation(ProxyFactory pf, PersistenceExceptionTranslator pet) {
if (AnnotationUtils.findAnnotation(pf.getTargetClass(), Repository.class) != null) {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.registerBeanDefinition("peti", new RootBeanDefinition(PersistenceExceptionTranslationInterceptor.class));
bf.registerSingleton("pet", pet);
pf.addAdvice((PersistenceExceptionTranslationInterceptor) bf.getBean("peti"));
}
}
}

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.dao.annotation;
import junit.framework.TestCase;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.dao.annotation.PersistenceExceptionTranslationAdvisorTests.RepositoryInterface;
import org.springframework.dao.annotation.PersistenceExceptionTranslationAdvisorTests.RepositoryInterfaceImpl;
import org.springframework.dao.annotation.PersistenceExceptionTranslationAdvisorTests.StereotypedRepositoryInterfaceImpl;
import org.springframework.dao.support.ChainedPersistenceExceptionTranslator;
import org.springframework.stereotype.Repository;
/**
* Unit tests for PersistenceExceptionTranslationPostProcessor. Does not test translation; there are separate unit tests
* for the Spring AOP Advisor. Just checks whether proxying occurs correctly, as a unit test should.
*
* @author Rod Johnson
*/
public class PersistenceExceptionTranslationPostProcessorTests extends TestCase {
public void testFailsWithNoPersistenceExceptionTranslators() {
GenericApplicationContext gac = new GenericApplicationContext();
gac.registerBeanDefinition("translator",
new RootBeanDefinition(PersistenceExceptionTranslationPostProcessor.class));
gac.registerBeanDefinition("proxied", new RootBeanDefinition(StereotypedRepositoryInterfaceImpl.class));
try {
gac.refresh();
fail("Should fail with no translators");
}
catch (BeansException ex) {
// Ok
}
}
public void testProxiesCorrectly() {
GenericApplicationContext gac = new GenericApplicationContext();
gac.registerBeanDefinition("translator",
new RootBeanDefinition(PersistenceExceptionTranslationPostProcessor.class));
gac.registerBeanDefinition("notProxied", new RootBeanDefinition(RepositoryInterfaceImpl.class));
gac.registerBeanDefinition("proxied", new RootBeanDefinition(StereotypedRepositoryInterfaceImpl.class));
gac.registerBeanDefinition("classProxied", new RootBeanDefinition(RepositoryWithoutInterface.class));
gac.registerBeanDefinition("classProxiedAndAdvised",
new RootBeanDefinition(RepositoryWithoutInterfaceAndOtherwiseAdvised.class));
gac.registerBeanDefinition("chainedTranslator",
new RootBeanDefinition(ChainedPersistenceExceptionTranslator.class));
gac.registerBeanDefinition("proxyCreator",
BeanDefinitionBuilder.rootBeanDefinition(AnnotationAwareAspectJAutoProxyCreator.class).
addPropertyValue("order", 50).getBeanDefinition());
gac.registerBeanDefinition("logger", new RootBeanDefinition(LogAllAspect.class));
gac.refresh();
RepositoryInterface shouldNotBeProxied = (RepositoryInterface) gac.getBean("notProxied");
assertFalse(AopUtils.isAopProxy(shouldNotBeProxied));
RepositoryInterface shouldBeProxied = (RepositoryInterface) gac.getBean("proxied");
assertTrue(AopUtils.isAopProxy(shouldBeProxied));
RepositoryWithoutInterface rwi = (RepositoryWithoutInterface) gac.getBean("classProxied");
assertTrue(AopUtils.isAopProxy(rwi));
checkWillTranslateExceptions(rwi);
Additional rwi2 = (Additional) gac.getBean("classProxiedAndAdvised");
assertTrue(AopUtils.isAopProxy(rwi2));
rwi2.additionalMethod();
checkWillTranslateExceptions(rwi2);
}
protected void checkWillTranslateExceptions(Object o) {
assertTrue(o instanceof Advised);
Advised a = (Advised) o;
for (Advisor advisor : a.getAdvisors()) {
if (advisor instanceof PersistenceExceptionTranslationAdvisor) {
return;
}
}
fail("No translation");
}
@Repository
public static class RepositoryWithoutInterface {
public void nameDoesntMatter() {
}
}
public interface Additional {
void additionalMethod();
}
public static class RepositoryWithoutInterfaceAndOtherwiseAdvised extends StereotypedRepositoryInterfaceImpl
implements Additional {
public void additionalMethod() {
}
}
@Aspect
public static class LogAllAspect {
//@Before("execution(* *())")
@Before("execution(void *.additionalMethod())")
public void log(JoinPoint jp) {
System.out.println("Before " + jp.getSignature().getName());
}
}
}

View File

@@ -0,0 +1,72 @@
/*
* 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.dao.support;
import junit.framework.TestCase;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.dao.support.DataAccessUtilsTests.MapPersistenceExceptionTranslator;
/**
* @author Rod Johnson
* @since 2.0
*/
public class ChainedPersistenceExceptionTranslatorTests extends TestCase {
public void testEmpty() {
ChainedPersistenceExceptionTranslator pet = new ChainedPersistenceExceptionTranslator();
//MapPersistenceExceptionTranslator mpet = new MapPersistenceExceptionTranslator();
RuntimeException in = new RuntimeException("in");
assertSame(in, DataAccessUtils.translateIfNecessary(in, pet));
}
public void testExceptionTranslationWithTranslation() {
MapPersistenceExceptionTranslator mpet1 = new MapPersistenceExceptionTranslator();
RuntimeException in1 = new RuntimeException("in");
InvalidDataAccessApiUsageException out1 = new InvalidDataAccessApiUsageException("out");
InvalidDataAccessApiUsageException out2 = new InvalidDataAccessApiUsageException("out");
mpet1.addTranslation(in1, out1);
ChainedPersistenceExceptionTranslator chainedPet1 = new ChainedPersistenceExceptionTranslator();
assertSame("Should not translate yet", in1, DataAccessUtils.translateIfNecessary(in1, chainedPet1));
chainedPet1.addDelegate(mpet1);
assertSame("Should now translate", out1, DataAccessUtils.translateIfNecessary(in1, chainedPet1));
// Now add a new translator and verify it wins
MapPersistenceExceptionTranslator mpet2 = new MapPersistenceExceptionTranslator();
mpet2.addTranslation(in1, out2);
chainedPet1.addDelegate(mpet2);
assertSame("Should still translate the same due to ordering",
out1, DataAccessUtils.translateIfNecessary(in1, chainedPet1));
ChainedPersistenceExceptionTranslator chainedPet2 = new ChainedPersistenceExceptionTranslator();
chainedPet2.addDelegate(mpet2);
chainedPet2.addDelegate(mpet1);
assertSame("Should translate differently due to ordering",
out2, DataAccessUtils.translateIfNecessary(in1, chainedPet2));
RuntimeException in2 = new RuntimeException("in2");
OptimisticLockingFailureException out3 = new OptimisticLockingFailureException("out2");
assertNull(chainedPet2.translateExceptionIfPossible(in2));
MapPersistenceExceptionTranslator mpet3 = new MapPersistenceExceptionTranslator();
mpet3.addTranslation(in2, out3);
chainedPet2.addDelegate(mpet3);
assertSame(out3, chainedPet2.translateExceptionIfPossible(in2));
}
}

View File

@@ -0,0 +1,278 @@
/*
* 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.dao.support;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import junit.framework.TestCase;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.dao.TypeMismatchDataAccessException;
/**
* @author Juergen Hoeller
* @since 20.10.2004
*/
public class DataAccessUtilsTests extends TestCase {
public void testWithEmptyCollection() {
Collection col = new HashSet();
assertNull(DataAccessUtils.uniqueResult(col));
try {
DataAccessUtils.requiredUniqueResult(col);
fail("Should have thrown IncorrectResultSizeDataAccessException");
}
catch (IncorrectResultSizeDataAccessException ex) {
// expected
assertEquals(1, ex.getExpectedSize());
assertEquals(0, ex.getActualSize());
}
try {
DataAccessUtils.objectResult(col, String.class);
fail("Should have thrown IncorrectResultSizeDataAccessException");
}
catch (IncorrectResultSizeDataAccessException ex) {
// expected
assertEquals(1, ex.getExpectedSize());
assertEquals(0, ex.getActualSize());
}
try {
DataAccessUtils.intResult(col);
fail("Should have thrown IncorrectResultSizeDataAccessException");
}
catch (IncorrectResultSizeDataAccessException ex) {
// expected
assertEquals(1, ex.getExpectedSize());
assertEquals(0, ex.getActualSize());
}
try {
DataAccessUtils.longResult(col);
fail("Should have thrown IncorrectResultSizeDataAccessException");
}
catch (IncorrectResultSizeDataAccessException ex) {
// expected
assertEquals(1, ex.getExpectedSize());
assertEquals(0, ex.getActualSize());
}
}
public void testWithTooLargeCollection() {
Collection col = new HashSet();
col.add("test1");
col.add("test2");
try {
DataAccessUtils.uniqueResult(col);
fail("Should have thrown IncorrectResultSizeDataAccessException");
}
catch (IncorrectResultSizeDataAccessException ex) {
// expected
assertEquals(1, ex.getExpectedSize());
assertEquals(2, ex.getActualSize());
}
try {
DataAccessUtils.requiredUniqueResult(col);
fail("Should have thrown IncorrectResultSizeDataAccessException");
}
catch (IncorrectResultSizeDataAccessException ex) {
// expected
assertEquals(1, ex.getExpectedSize());
assertEquals(2, ex.getActualSize());
}
try {
DataAccessUtils.objectResult(col, String.class);
fail("Should have thrown IncorrectResultSizeDataAccessException");
}
catch (IncorrectResultSizeDataAccessException ex) {
// expected
assertEquals(1, ex.getExpectedSize());
assertEquals(2, ex.getActualSize());
}
try {
DataAccessUtils.intResult(col);
fail("Should have thrown IncorrectResultSizeDataAccessException");
}
catch (IncorrectResultSizeDataAccessException ex) {
// expected
assertEquals(1, ex.getExpectedSize());
assertEquals(2, ex.getActualSize());
}
try {
DataAccessUtils.longResult(col);
fail("Should have thrown IncorrectResultSizeDataAccessException");
}
catch (IncorrectResultSizeDataAccessException ex) {
// expected
assertEquals(1, ex.getExpectedSize());
assertEquals(2, ex.getActualSize());
}
}
public void testWithInteger() {
Collection col = new HashSet();
col.add(new Integer(5));
assertEquals(new Integer(5), DataAccessUtils.uniqueResult(col));
assertEquals(new Integer(5), DataAccessUtils.requiredUniqueResult(col));
assertEquals(new Integer(5), DataAccessUtils.objectResult(col, Integer.class));
assertEquals("5", DataAccessUtils.objectResult(col, String.class));
assertEquals(5, DataAccessUtils.intResult(col));
assertEquals(5, DataAccessUtils.longResult(col));
}
public void testWithSameIntegerInstanceTwice() {
Integer i = new Integer(5);
Collection col = new ArrayList();
col.add(i);
col.add(i);
assertEquals(new Integer(5), DataAccessUtils.uniqueResult(col));
assertEquals(new Integer(5), DataAccessUtils.requiredUniqueResult(col));
assertEquals(new Integer(5), DataAccessUtils.objectResult(col, Integer.class));
assertEquals("5", DataAccessUtils.objectResult(col, String.class));
assertEquals(5, DataAccessUtils.intResult(col));
assertEquals(5, DataAccessUtils.longResult(col));
}
public void testWithEquivalentIntegerInstanceTwice() {
Collection col = new ArrayList();
col.add(new Integer(5));
col.add(new Integer(5));
try {
DataAccessUtils.uniqueResult(col);
fail("Should have thrown IncorrectResultSizeDataAccessException");
}
catch (IncorrectResultSizeDataAccessException ex) {
// expected
assertEquals(1, ex.getExpectedSize());
assertEquals(2, ex.getActualSize());
}
}
public void testWithLong() {
Collection col = new HashSet();
col.add(new Long(5));
assertEquals(new Long(5), DataAccessUtils.uniqueResult(col));
assertEquals(new Long(5), DataAccessUtils.requiredUniqueResult(col));
assertEquals(new Long(5), DataAccessUtils.objectResult(col, Long.class));
assertEquals("5", DataAccessUtils.objectResult(col, String.class));
assertEquals(5, DataAccessUtils.intResult(col));
assertEquals(5, DataAccessUtils.longResult(col));
}
public void testWithString() {
Collection col = new HashSet();
col.add("test1");
assertEquals("test1", DataAccessUtils.uniqueResult(col));
assertEquals("test1", DataAccessUtils.requiredUniqueResult(col));
assertEquals("test1", DataAccessUtils.objectResult(col, String.class));
try {
DataAccessUtils.intResult(col);
fail("Should have thrown TypeMismatchDataAccessException");
}
catch (TypeMismatchDataAccessException ex) {
// expected
}
try {
DataAccessUtils.longResult(col);
fail("Should have thrown TypeMismatchDataAccessException");
}
catch (TypeMismatchDataAccessException ex) {
// expected
}
}
public void testWithDate() {
Date date = new Date();
Collection col = new HashSet();
col.add(date);
assertEquals(date, DataAccessUtils.uniqueResult(col));
assertEquals(date, DataAccessUtils.requiredUniqueResult(col));
assertEquals(date, DataAccessUtils.objectResult(col, Date.class));
assertEquals(date.toString(), DataAccessUtils.objectResult(col, String.class));
try {
DataAccessUtils.intResult(col);
fail("Should have thrown TypeMismatchDataAccessException");
}
catch (TypeMismatchDataAccessException ex) {
// expected
}
try {
DataAccessUtils.longResult(col);
fail("Should have thrown TypeMismatchDataAccessException");
}
catch (TypeMismatchDataAccessException ex) {
// expected
}
}
public void testExceptionTranslationWithNoTranslation() {
MapPersistenceExceptionTranslator mpet = new MapPersistenceExceptionTranslator();
RuntimeException in = new RuntimeException();
assertSame(in, DataAccessUtils.translateIfNecessary(in, mpet));
}
public void testExceptionTranslationWithTranslation() {
MapPersistenceExceptionTranslator mpet = new MapPersistenceExceptionTranslator();
RuntimeException in = new RuntimeException("in");
InvalidDataAccessApiUsageException out = new InvalidDataAccessApiUsageException("out");
mpet.addTranslation(in, out);
assertSame(out, DataAccessUtils.translateIfNecessary(in, mpet));
}
public static class MapPersistenceExceptionTranslator implements PersistenceExceptionTranslator {
/**
* Map<RuntimeException,RuntimeException>: in to out
*/
private Map translations = new HashMap();
public void addTranslation(RuntimeException in, RuntimeException out) {
this.translations.put(in, out);
}
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
return (DataAccessException) translations.get(ex);
}
}
}

View File

@@ -0,0 +1,147 @@
/*
* 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.jca.cci;
import static org.easymock.EasyMock.*;
import static org.junit.Assert.assertTrue;
import javax.resource.ResourceException;
import javax.resource.cci.Connection;
import javax.resource.cci.ConnectionFactory;
import javax.resource.cci.Interaction;
import javax.resource.cci.InteractionSpec;
import javax.resource.cci.LocalTransaction;
import javax.resource.cci.Record;
import org.junit.Test;
import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.jca.cci.core.CciTemplate;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.transaction.support.TransactionTemplate;
/**
* @author Thierry Templier
* @author Chris Beams
*/
public class CciLocalTransactionTests {
/**
* Test if a transaction ( begin / commit ) is executed on the
* LocalTransaction when CciLocalTransactionManager is specified as
* transaction manager.
*/
@Test
public void testLocalTransactionCommit() throws ResourceException {
final ConnectionFactory connectionFactory = createMock(ConnectionFactory.class);
Connection connection = createMock(Connection.class);
Interaction interaction = createMock(Interaction.class);
LocalTransaction localTransaction = createMock(LocalTransaction.class);
final Record record = createMock(Record.class);
final InteractionSpec interactionSpec = createMock(InteractionSpec.class);
expect(connectionFactory.getConnection()).andReturn(connection);
expect(connection.getLocalTransaction()).andReturn(localTransaction);
localTransaction.begin();
expect(connection.createInteraction()).andReturn(interaction);
expect(interaction.execute(interactionSpec, record, record)).andReturn(true);
interaction.close();
expect(connection.getLocalTransaction()).andReturn(localTransaction);
localTransaction.commit();
connection.close();
replay(connectionFactory, connection, localTransaction, interaction, record);
org.springframework.jca.cci.connection.CciLocalTransactionManager tm = new org.springframework.jca.cci.connection.CciLocalTransactionManager();
tm.setConnectionFactory(connectionFactory);
TransactionTemplate tt = new TransactionTemplate(tm);
tt.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(connectionFactory));
CciTemplate ct = new CciTemplate(connectionFactory);
ct.execute(interactionSpec, record, record);
}
});
verify(connectionFactory, connection, localTransaction, interaction, record);
}
/**
* Test if a transaction ( begin / rollback ) is executed on the
* LocalTransaction when CciLocalTransactionManager is specified as
* transaction manager and a non-checked exception is thrown.
*/
@Test
public void testLocalTransactionRollback() throws ResourceException {
final ConnectionFactory connectionFactory = createMock(ConnectionFactory.class);
Connection connection = createMock(Connection.class);
Interaction interaction = createMock(Interaction.class);
LocalTransaction localTransaction = createMock(LocalTransaction.class);
final Record record = createMock(Record.class);
final InteractionSpec interactionSpec = createMock(InteractionSpec.class);
expect(connectionFactory.getConnection()).andReturn(connection);
expect(connection.getLocalTransaction()).andReturn(localTransaction);
localTransaction.begin();
expect(connection.createInteraction()).andReturn(interaction);
expect(interaction.execute(interactionSpec, record, record)).andReturn(true);
interaction.close();
expect(connection.getLocalTransaction()).andReturn(localTransaction);
localTransaction.rollback();
connection.close();
replay(connectionFactory, connection, localTransaction, interaction, record);
org.springframework.jca.cci.connection.CciLocalTransactionManager tm = new org.springframework.jca.cci.connection.CciLocalTransactionManager();
tm.setConnectionFactory(connectionFactory);
TransactionTemplate tt = new TransactionTemplate(tm);
try {
tt.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(connectionFactory));
CciTemplate ct = new CciTemplate(connectionFactory);
ct.execute(interactionSpec, record, record);
throw new DataRetrievalFailureException("error");
}
});
}
catch (Exception ex) {
}
verify(connectionFactory, connection, localTransaction, interaction, record);
}
}

View File

@@ -0,0 +1,709 @@
/*
* 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.jca.cci;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.sql.SQLException;
import javax.resource.NotSupportedException;
import javax.resource.ResourceException;
import javax.resource.cci.Connection;
import javax.resource.cci.ConnectionFactory;
import javax.resource.cci.ConnectionSpec;
import javax.resource.cci.IndexedRecord;
import javax.resource.cci.Interaction;
import javax.resource.cci.InteractionSpec;
import javax.resource.cci.MappedRecord;
import javax.resource.cci.Record;
import javax.resource.cci.RecordFactory;
import javax.resource.cci.ResultSet;
import org.junit.Test;
import org.springframework.jca.cci.connection.ConnectionSpecConnectionFactoryAdapter;
import org.springframework.jca.cci.connection.NotSupportedRecordFactory;
import org.springframework.jca.cci.core.CciTemplate;
import org.springframework.jca.cci.core.ConnectionCallback;
import org.springframework.jca.cci.core.InteractionCallback;
import org.springframework.jca.cci.core.RecordCreator;
import org.springframework.jca.cci.core.RecordExtractor;
/**
* @author Thierry Templier
* @author Juergen Hoeller
* @author Chris Beams
*/
public class CciTemplateTests {
@Test
public void testCreateIndexedRecord() throws ResourceException {
ConnectionFactory connectionFactory = createMock(ConnectionFactory.class);
RecordFactory recordFactory = createMock(RecordFactory.class);
IndexedRecord indexedRecord = createMock(IndexedRecord.class);
expect(connectionFactory.getRecordFactory()).andReturn(recordFactory);
expect(recordFactory.createIndexedRecord("name")).andReturn(
indexedRecord);
replay(connectionFactory, recordFactory);
CciTemplate ct = new CciTemplate(connectionFactory);
ct.createIndexedRecord("name");
verify(connectionFactory, recordFactory);
}
@Test
public void testCreateMappedRecord() throws ResourceException {
ConnectionFactory connectionFactory = createMock(ConnectionFactory.class);
RecordFactory recordFactory = createMock(RecordFactory.class);
MappedRecord mappedRecord = createMock(MappedRecord.class);
expect(connectionFactory.getRecordFactory()).andReturn(recordFactory);
expect(recordFactory.createMappedRecord("name"))
.andReturn(mappedRecord);
replay(connectionFactory, recordFactory);
CciTemplate ct = new CciTemplate(connectionFactory);
ct.createMappedRecord("name");
verify(connectionFactory, recordFactory);
}
@Test
public void testTemplateExecuteInputOutput() throws ResourceException {
ConnectionFactory connectionFactory = createMock(ConnectionFactory.class);
Connection connection = createMock(Connection.class);
Interaction interaction = createMock(Interaction.class);
Record inputRecord = createMock(Record.class);
Record outputRecord = createMock(Record.class);
InteractionSpec interactionSpec = createMock(InteractionSpec.class);
expect(connectionFactory.getConnection()).andReturn(connection);
expect(connection.createInteraction()).andReturn(interaction);
expect(interaction.execute(interactionSpec, inputRecord, outputRecord))
.andReturn(true);
interaction.close();
connection.close();
replay(connectionFactory, connection, interaction);
CciTemplate ct = new CciTemplate(connectionFactory);
ct.execute(interactionSpec, inputRecord, outputRecord);
verify(connectionFactory, connection, interaction);
}
@Test
public void testTemplateExecuteWithCreatorAndRecordFactoryNotSupported()
throws ResourceException {
ConnectionFactory connectionFactory = createMock(ConnectionFactory.class);
Connection connection = createMock(Connection.class);
Interaction interaction = createMock(Interaction.class);
Record inputRecord = createMock(Record.class);
final Record outputRecord = createMock(Record.class);
InteractionSpec interactionSpec = createMock(InteractionSpec.class);
expect(connectionFactory.getConnection()).andReturn(connection);
expect(connectionFactory.getRecordFactory()).andThrow(
new NotSupportedException("not supported"));
expect(connection.createInteraction()).andReturn(interaction);
expect(interaction.execute(interactionSpec, inputRecord, outputRecord))
.andReturn(true);
interaction.close();
connection.close();
replay(connectionFactory, connection, interaction);
CciTemplate ct = new CciTemplate(connectionFactory);
ct.setOutputRecordCreator(new RecordCreator() {
public Record createRecord(RecordFactory recordFactory) {
assertTrue(recordFactory instanceof NotSupportedRecordFactory);
return outputRecord;
}
});
ct.execute(interactionSpec, inputRecord);
verify(connectionFactory, connection, interaction);
}
@Test
public void testTemplateExecuteInputTrueWithCreator2()
throws ResourceException {
ConnectionFactory connectionFactory = createMock(ConnectionFactory.class);
RecordFactory recordFactory = createMock(RecordFactory.class);
Connection connection = createMock(Connection.class);
Interaction interaction = createMock(Interaction.class);
RecordCreator creator = createMock(RecordCreator.class);
Record inputRecord = createMock(Record.class);
final Record outputRecord = createMock(Record.class);
InteractionSpec interactionSpec = createMock(InteractionSpec.class);
expect(connectionFactory.getConnection()).andReturn(connection);
expect(connectionFactory.getRecordFactory()).andReturn(recordFactory);
expect(connection.createInteraction()).andReturn(interaction);
expect(creator.createRecord(recordFactory)).andReturn(outputRecord);
expect(interaction.execute(interactionSpec, inputRecord, outputRecord))
.andReturn(true);
interaction.close();
connection.close();
replay(connectionFactory, connection, interaction, creator);
CciTemplate ct = new CciTemplate(connectionFactory);
ct.setOutputRecordCreator(creator);
ct.execute(interactionSpec, inputRecord);
verify(connectionFactory, connection, interaction, creator);
}
@Test
public void testTemplateExecuteInputFalse() throws ResourceException {
ConnectionFactory connectionFactory = createMock(ConnectionFactory.class);
Connection connection = createMock(Connection.class);
Interaction interaction = createMock(Interaction.class);
Record inputRecord = createMock(Record.class);
Record outputRecord = createMock(Record.class);
InteractionSpec interactionSpec = createMock(InteractionSpec.class);
expect(connectionFactory.getConnection()).andReturn(connection);
expect(connection.createInteraction()).andReturn(interaction);
expect(interaction.execute(interactionSpec, inputRecord)).andReturn(
outputRecord);
interaction.close();
connection.close();
replay(connectionFactory, connection, interaction);
CciTemplate ct = new CciTemplate(connectionFactory);
ct.execute(interactionSpec, inputRecord);
verify(connectionFactory, connection, interaction);
}
@SuppressWarnings("unchecked")
@Test
public void testTemplateExecuteInputExtractorTrueWithCreator()
throws ResourceException, SQLException {
ConnectionFactory connectionFactory = createMock(ConnectionFactory.class);
RecordFactory recordFactory = createMock(RecordFactory.class);
Connection connection = createMock(Connection.class);
Interaction interaction = createMock(Interaction.class);
RecordExtractor<Object> extractor = createMock(RecordExtractor.class);
RecordCreator creator = createMock(RecordCreator.class);
Record inputRecord = createMock(Record.class);
Record outputRecord = createMock(Record.class);
InteractionSpec interactionSpec = createMock(InteractionSpec.class);
expect(connectionFactory.getConnection()).andReturn(connection);
expect(connection.createInteraction()).andReturn(interaction);
expect(connectionFactory.getRecordFactory()).andReturn(recordFactory);
expect(creator.createRecord(recordFactory)).andReturn(outputRecord);
expect(interaction.execute(interactionSpec, inputRecord, outputRecord))
.andReturn(true);
expect(extractor.extractData(outputRecord)).andStubReturn(new Object());
interaction.close();
connection.close();
replay(connectionFactory, connection, interaction, extractor, creator);
CciTemplate ct = new CciTemplate(connectionFactory);
ct.setOutputRecordCreator(creator);
ct.execute(interactionSpec, inputRecord, extractor);
verify(connectionFactory, connection, interaction, extractor, creator);
}
@SuppressWarnings("unchecked")
@Test
public void testTemplateExecuteInputExtractorFalse()
throws ResourceException, SQLException {
ConnectionFactory connectionFactory = createMock(ConnectionFactory.class);
Connection connection = createMock(Connection.class);
Interaction interaction = createMock(Interaction.class);
RecordExtractor<Object> extractor = createMock(RecordExtractor.class);
Record inputRecord = createMock(Record.class);
Record outputRecord = createMock(Record.class);
InteractionSpec interactionSpec = createMock(InteractionSpec.class);
expect(connectionFactory.getConnection()).andReturn(connection);
expect(connection.createInteraction()).andReturn(interaction);
expect(interaction.execute(interactionSpec, inputRecord)).andReturn(
outputRecord);
expect(extractor.extractData(outputRecord)).andStubReturn(new Object());
interaction.close();
connection.close();
replay(connectionFactory, connection, interaction, extractor);
CciTemplate ct = new CciTemplate(connectionFactory);
ct.execute(interactionSpec, inputRecord, extractor);
verify(connectionFactory, connection, interaction, extractor);
}
@Test
public void testTemplateExecuteInputGeneratorTrueWithCreator()
throws ResourceException {
ConnectionFactory connectionFactory = createMock(ConnectionFactory.class);
RecordFactory recordFactory = createMock(RecordFactory.class);
Connection connection = createMock(Connection.class);
Interaction interaction = createMock(Interaction.class);
RecordCreator generator = createMock(RecordCreator.class);
RecordCreator creator = createMock(RecordCreator.class);
Record inputRecord = createMock(Record.class);
Record outputRecord = createMock(Record.class);
InteractionSpec interactionSpec = createMock(InteractionSpec.class);
expect(connectionFactory.getRecordFactory()).andReturn(recordFactory);
expect(generator.createRecord(recordFactory)).andReturn(inputRecord);
expect(connectionFactory.getConnection()).andReturn(connection);
expect(connection.createInteraction()).andReturn(interaction);
expect(creator.createRecord(recordFactory)).andReturn(outputRecord);
expect(connectionFactory.getRecordFactory()).andReturn(recordFactory);
expect(interaction.execute(interactionSpec, inputRecord, outputRecord))
.andReturn(true);
interaction.close();
connection.close();
replay(connectionFactory, connection, interaction, generator, creator);
CciTemplate ct = new CciTemplate(connectionFactory);
ct.setOutputRecordCreator(creator);
ct.execute(interactionSpec, generator);
verify(connectionFactory, connection, interaction, generator, creator);
}
@Test
public void testTemplateExecuteInputGeneratorFalse()
throws ResourceException {
ConnectionFactory connectionFactory = createMock(ConnectionFactory.class);
RecordFactory recordFactory = createMock(RecordFactory.class);
Connection connection = createMock(Connection.class);
Interaction interaction = createMock(Interaction.class);
RecordCreator generator = createMock(RecordCreator.class);
Record inputRecord = createMock(Record.class);
Record outputRecord = createMock(Record.class);
InteractionSpec interactionSpec = createMock(InteractionSpec.class);
expect(connectionFactory.getRecordFactory()).andReturn(recordFactory);
expect(connectionFactory.getConnection()).andReturn(connection);
expect(connection.createInteraction()).andReturn(interaction);
expect(generator.createRecord(recordFactory)).andReturn(inputRecord);
expect(interaction.execute(interactionSpec, inputRecord)).andReturn(
outputRecord);
interaction.close();
connection.close();
replay(connectionFactory, connection, interaction, generator);
CciTemplate ct = new CciTemplate(connectionFactory);
ct.execute(interactionSpec, generator);
verify(connectionFactory, connection, interaction, generator);
}
@SuppressWarnings("unchecked")
@Test
public void testTemplateExecuteInputGeneratorExtractorTrueWithCreator()
throws ResourceException, SQLException {
ConnectionFactory connectionFactory = createMock(ConnectionFactory.class);
RecordFactory recordFactory = createMock(RecordFactory.class);
Connection connection = createMock(Connection.class);
Interaction interaction = createMock(Interaction.class);
RecordCreator generator = createMock(RecordCreator.class);
RecordExtractor<Object> extractor = createMock(RecordExtractor.class);
RecordCreator creator = createMock(RecordCreator.class);
Record inputRecord = createMock(Record.class);
Record outputRecord = createMock(Record.class);
Object obj = new Object();
InteractionSpec interactionSpec = createMock(InteractionSpec.class);
expect(connectionFactory.getRecordFactory()).andReturn(recordFactory);
expect(connectionFactory.getConnection()).andReturn(connection);
expect(connection.createInteraction()).andReturn(interaction);
expect(creator.createRecord(recordFactory)).andReturn(outputRecord);
expect(connectionFactory.getRecordFactory()).andReturn(recordFactory);
expect(generator.createRecord(recordFactory)).andReturn(inputRecord);
expect(interaction.execute(interactionSpec, inputRecord, outputRecord))
.andReturn(true);
expect(extractor.extractData(outputRecord)).andStubReturn(obj);
interaction.close();
connection.close();
replay(connectionFactory, connection, interaction, generator, creator,
extractor);
CciTemplate ct = new CciTemplate(connectionFactory);
ct.setOutputRecordCreator(creator);
assertEquals(obj, ct.execute(interactionSpec, generator, extractor));
verify(connectionFactory, connection, interaction, generator, creator,
extractor);
}
@SuppressWarnings("unchecked")
@Test
public void testTemplateExecuteInputGeneratorExtractorFalse()
throws ResourceException, SQLException {
ConnectionFactory connectionFactory = createMock(ConnectionFactory.class);
RecordFactory recordFactory = createMock(RecordFactory.class);
Connection connection = createMock(Connection.class);
Interaction interaction = createMock(Interaction.class);
RecordCreator generator = createMock(RecordCreator.class);
RecordExtractor<Object> extractor = createMock(RecordExtractor.class);
Record inputRecord = createMock(Record.class);
Record outputRecord = createMock(Record.class);
InteractionSpec interactionSpec = createMock(InteractionSpec.class);
expect(connectionFactory.getRecordFactory()).andReturn(recordFactory);
expect(connectionFactory.getConnection()).andReturn(connection);
expect(connection.createInteraction()).andReturn(interaction);
expect(generator.createRecord(recordFactory)).andReturn(inputRecord);
expect(interaction.execute(interactionSpec, inputRecord)).andReturn(
outputRecord);
expect(extractor.extractData(outputRecord)).andStubReturn(new Object());
interaction.close();
connection.close();
replay(connectionFactory, connection, interaction, generator, extractor);
CciTemplate ct = new CciTemplate(connectionFactory);
ct.execute(interactionSpec, generator, extractor);
verify(connectionFactory, connection, interaction, generator, extractor);
}
@Test
public void testTemplateExecuteInputOutputConnectionSpec()
throws ResourceException {
ConnectionFactory connectionFactory = createMock(ConnectionFactory.class);
ConnectionSpec connectionSpec = createMock(ConnectionSpec.class);
Connection connection = createMock(Connection.class);
Interaction interaction = createMock(Interaction.class);
Record inputRecord = createMock(Record.class);
Record outputRecord = createMock(Record.class);
InteractionSpec interactionSpec = createMock(InteractionSpec.class);
expect(connectionFactory.getConnection(connectionSpec)).andReturn(
connection);
expect(connection.createInteraction()).andReturn(interaction);
expect(interaction.execute(interactionSpec, inputRecord, outputRecord))
.andReturn(true);
interaction.close();
connection.close();
replay(connectionFactory, connection, interaction);
ConnectionSpecConnectionFactoryAdapter adapter = new ConnectionSpecConnectionFactoryAdapter();
adapter.setTargetConnectionFactory(connectionFactory);
adapter.setConnectionSpec(connectionSpec);
CciTemplate ct = new CciTemplate(adapter);
ct.execute(interactionSpec, inputRecord, outputRecord);
verify(connectionFactory, connection, interaction);
}
@SuppressWarnings("unchecked")
@Test
public void testTemplateExecuteInputOutputResultsSetFalse()
throws ResourceException, SQLException {
ConnectionFactory connectionFactory = createMock(ConnectionFactory.class);
RecordFactory recordFactory = createMock(RecordFactory.class);
Connection connection = createMock(Connection.class);
Interaction interaction = createMock(Interaction.class);
Record record = createMock(Record.class);
ResultSet resultset = createMock(ResultSet.class);
RecordCreator generator = createMock(RecordCreator.class);
RecordExtractor<Object> extractor = createMock(RecordExtractor.class);
InteractionSpec interactionSpec = createMock(InteractionSpec.class);
expect(connectionFactory.getRecordFactory()).andReturn(recordFactory);
expect(connectionFactory.getConnection()).andReturn(connection);
expect(connection.createInteraction()).andReturn(interaction);
expect(generator.createRecord(recordFactory)).andReturn(record);
expect(interaction.execute(interactionSpec, record)).andReturn(
resultset);
expect(extractor.extractData(resultset)).andStubReturn(new Object());
resultset.close();
interaction.close();
connection.close();
replay(connectionFactory, connection, interaction, generator,
extractor, resultset);
CciTemplate ct = new CciTemplate(connectionFactory);
ct.execute(interactionSpec, generator, extractor);
verify(connectionFactory, connection, interaction, generator,
extractor, resultset);
}
@SuppressWarnings("unchecked")
@Test
public void testTemplateExecuteConnectionCallback()
throws ResourceException, SQLException {
ConnectionFactory connectionFactory = createMock(ConnectionFactory.class);
Connection connection = createMock(Connection.class);
ConnectionCallback<Object> connectionCallback = createMock(ConnectionCallback.class);
expect(connectionFactory.getConnection()).andReturn(connection);
expect(connectionCallback.doInConnection(connection, connectionFactory))
.andStubReturn(new Object());
connection.close();
replay(connectionFactory, connection, connectionCallback);
CciTemplate ct = new CciTemplate(connectionFactory);
ct.execute(connectionCallback);
verify(connectionFactory, connection, connectionCallback);
}
@SuppressWarnings("unchecked")
@Test
public void testTemplateExecuteInteractionCallback()
throws ResourceException, SQLException {
ConnectionFactory connectionFactory = createMock(ConnectionFactory.class);
Connection connection = createMock(Connection.class);
Interaction interaction = createMock(Interaction.class);
InteractionCallback<Object> interactionCallback = createMock(InteractionCallback.class);
expect(connectionFactory.getConnection()).andReturn(connection);
expect(connection.createInteraction()).andReturn(interaction);
expect(
interactionCallback.doInInteraction(interaction,
connectionFactory)).andStubReturn(new Object());
interaction.close();
connection.close();
replay(connectionFactory, connection, interaction, interactionCallback);
CciTemplate ct = new CciTemplate(connectionFactory);
ct.execute(interactionCallback);
verify(connectionFactory, connection, interaction, interactionCallback);
}
@Test
public void testTemplateExecuteInputTrueTrueWithCreator()
throws ResourceException {
ConnectionFactory connectionFactory = createMock(ConnectionFactory.class);
Connection connection = createMock(Connection.class);
Interaction interaction = createMock(Interaction.class);
RecordCreator creator = createMock(RecordCreator.class);
Record inputOutputRecord = createMock(Record.class);
InteractionSpec interactionSpec = createMock(InteractionSpec.class);
expect(connectionFactory.getConnection()).andReturn(connection);
expect(connection.createInteraction()).andReturn(interaction);
expect(
interaction.execute(interactionSpec, inputOutputRecord,
inputOutputRecord)).andReturn(true);
interaction.close();
connection.close();
replay(connectionFactory, connection, interaction, creator);
CciTemplate ct = new CciTemplate(connectionFactory);
ct.setOutputRecordCreator(creator);
ct.execute(interactionSpec, inputOutputRecord, inputOutputRecord);
verify(connectionFactory, connection, interaction, creator);
}
@Test
public void testTemplateExecuteInputTrueTrue() throws ResourceException {
ConnectionFactory connectionFactory = createMock(ConnectionFactory.class);
Connection connection = createMock(Connection.class);
Interaction interaction = createMock(Interaction.class);
Record inputOutputRecord = createMock(Record.class);
InteractionSpec interactionSpec = createMock(InteractionSpec.class);
expect(connectionFactory.getConnection()).andReturn(connection);
expect(connection.createInteraction()).andReturn(interaction);
expect(
interaction.execute(interactionSpec, inputOutputRecord,
inputOutputRecord)).andReturn(true);
interaction.close();
connection.close();
replay(connectionFactory, connection, interaction);
CciTemplate ct = new CciTemplate(connectionFactory);
ct.execute(interactionSpec, inputOutputRecord, inputOutputRecord);
verify(connectionFactory, connection, interaction);
}
@Test
public void testTemplateExecuteInputFalseTrue() throws ResourceException {
ConnectionFactory connectionFactory = createMock(ConnectionFactory.class);
Connection connection = createMock(Connection.class);
Interaction interaction = createMock(Interaction.class);
Record inputOutputRecord = createMock(Record.class);
InteractionSpec interactionSpec = createMock(InteractionSpec.class);
expect(connectionFactory.getConnection()).andReturn(connection);
expect(connection.createInteraction()).andReturn(interaction);
expect(interaction.execute(interactionSpec, inputOutputRecord))
.andReturn(null);
interaction.close();
connection.close();
replay(connectionFactory, connection, interaction);
CciTemplate ct = new CciTemplate(connectionFactory);
Record tmpOutputRecord = (Record) ct.execute(interactionSpec,
inputOutputRecord);
assertNull(tmpOutputRecord);
verify(connectionFactory, connection, interaction);
}
}

View File

@@ -0,0 +1,253 @@
/*
* 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.jca.cci;
import static org.easymock.EasyMock.*;
import static org.junit.Assert.assertSame;
import javax.resource.ResourceException;
import javax.resource.cci.Connection;
import javax.resource.cci.ConnectionFactory;
import javax.resource.cci.Interaction;
import javax.resource.cci.InteractionSpec;
import javax.resource.cci.Record;
import javax.resource.cci.RecordFactory;
import org.junit.Test;
import org.springframework.jca.cci.core.RecordCreator;
import org.springframework.jca.cci.object.MappingRecordOperation;
import org.springframework.jca.cci.object.SimpleRecordOperation;
/**
* @author Thierry Templier
* @author Chris Beams
*/
public class EisOperationTests {
@Test
public void testSimpleRecordOperation() throws ResourceException {
ConnectionFactory connectionFactory = createMock(ConnectionFactory.class);
Connection connection = createMock(Connection.class);
Interaction interaction = createMock(Interaction.class);
Record inputRecord = createMock(Record.class);
Record outputRecord = createMock(Record.class);
InteractionSpec interactionSpec = createMock(InteractionSpec.class);
SimpleRecordOperation query = new SimpleRecordOperation(connectionFactory, interactionSpec);
expect(connectionFactory.getConnection()).andReturn(connection);
expect(connection.createInteraction()).andReturn(interaction);
expect(interaction.execute(interactionSpec, inputRecord)).andReturn(outputRecord);
interaction.close();
connection.close();
replay(connectionFactory, connection, interaction);
query.execute(inputRecord);
verify(connectionFactory, connection, interaction);
}
@Test
public void testSimpleRecordOperationWithExplicitOutputRecord() throws ResourceException {
ConnectionFactory connectionFactory = createMock(ConnectionFactory.class);
Connection connection = createMock(Connection.class);
Interaction interaction = createMock(Interaction.class);
Record inputRecord = createMock(Record.class);
Record outputRecord = createMock(Record.class);
InteractionSpec interactionSpec = createMock(InteractionSpec.class);
SimpleRecordOperation operation = new SimpleRecordOperation(connectionFactory, interactionSpec);
expect(connectionFactory.getConnection()).andReturn(connection);
expect(connection.createInteraction()).andReturn(interaction);
expect(interaction.execute(interactionSpec, inputRecord, outputRecord)).andReturn(true);
interaction.close();
connection.close();
replay(connectionFactory, connection, interaction);
operation.execute(inputRecord, outputRecord);
verify(connectionFactory, connection, interaction);
}
@Test
public void testSimpleRecordOperationWithInputOutputRecord() throws ResourceException {
ConnectionFactory connectionFactory = createMock(ConnectionFactory.class);
Connection connection = createMock(Connection.class);
Interaction interaction = createMock(Interaction.class);
Record inputOutputRecord = createMock(Record.class);
InteractionSpec interactionSpec = createMock(InteractionSpec.class);
SimpleRecordOperation query = new SimpleRecordOperation(connectionFactory, interactionSpec);
expect(connectionFactory.getConnection()).andReturn(connection);
expect(connection.createInteraction()).andReturn(interaction);
expect(interaction.execute(interactionSpec, inputOutputRecord, inputOutputRecord)).andReturn(true);
interaction.close();
connection.close();
replay(connectionFactory, connection, interaction);
query.execute(inputOutputRecord, inputOutputRecord);
verify(connectionFactory, connection, interaction);
}
@Test
public void testMappingRecordOperation() throws ResourceException {
ConnectionFactory connectionFactory = createMock(ConnectionFactory.class);
Connection connection = createMock(Connection.class);
Interaction interaction = createMock(Interaction.class);
RecordFactory recordFactory = createMock(RecordFactory.class);
Record inputRecord = createMock(Record.class);
Record outputRecord = createMock(Record.class);
InteractionSpec interactionSpec = createMock(InteractionSpec.class);
QueryCallDetector callDetector = createMock(QueryCallDetector.class);
MappingRecordOperationImpl query = new MappingRecordOperationImpl(connectionFactory, interactionSpec);
query.setCallDetector(callDetector);
Object inObj = new Object();
Object outObj = new Object();
expect(connectionFactory.getRecordFactory()).andReturn(recordFactory);
expect(callDetector.callCreateInputRecord(recordFactory, inObj)).andReturn(inputRecord);
expect(connectionFactory.getConnection()).andReturn(connection);
expect(connection.createInteraction()).andReturn(interaction);
expect(interaction.execute(interactionSpec, inputRecord)).andReturn(outputRecord);
expect(callDetector.callExtractOutputData(outputRecord)).andReturn(outObj);
interaction.close();
connection.close();
replay(connectionFactory, connection, interaction, callDetector);
assertSame(outObj, query.execute(inObj));
verify(connectionFactory, connection, interaction, callDetector);
}
@Test
public void testMappingRecordOperationWithOutputRecordCreator() throws ResourceException {
ConnectionFactory connectionFactory = createMock(ConnectionFactory.class);
Connection connection = createMock(Connection.class);
Interaction interaction = createMock(Interaction.class);
RecordFactory recordFactory = createMock(RecordFactory.class);
Record inputRecord = createMock(Record.class);
Record outputRecord = createMock(Record.class);
RecordCreator outputCreator = createMock(RecordCreator.class);
InteractionSpec interactionSpec = createMock(InteractionSpec.class);
QueryCallDetector callDetector = createMock(QueryCallDetector.class);
MappingRecordOperationImpl query = new MappingRecordOperationImpl(connectionFactory, interactionSpec);
query.setOutputRecordCreator(outputCreator);
query.setCallDetector(callDetector);
Object inObj = new Object();
Object outObj = new Object();
expect(connectionFactory.getRecordFactory()).andReturn(recordFactory);
expect(callDetector.callCreateInputRecord(recordFactory, inObj)).andReturn(inputRecord);
expect(connectionFactory.getConnection()).andReturn(connection);
expect(connection.createInteraction()).andReturn(interaction);
expect(connectionFactory.getRecordFactory()).andReturn(recordFactory);
expect(outputCreator.createRecord(recordFactory)).andReturn(outputRecord);
expect(interaction.execute(interactionSpec, inputRecord, outputRecord)).andReturn(true);
expect(callDetector.callExtractOutputData(outputRecord)).andReturn(outObj);
interaction.close();
connection.close();
replay(connectionFactory, connection, interaction, outputCreator, callDetector);
assertSame(outObj, query.execute(inObj));
verify(connectionFactory, connection, interaction, outputCreator, callDetector);
}
private class MappingRecordOperationImpl extends MappingRecordOperation {
private QueryCallDetector callDetector;
public MappingRecordOperationImpl(ConnectionFactory connectionFactory, InteractionSpec interactionSpec) {
super(connectionFactory, interactionSpec);
}
public void setCallDetector(QueryCallDetector callDetector) {
this.callDetector = callDetector;
}
protected Record createInputRecord(RecordFactory recordFactory, Object inputObject) {
return this.callDetector.callCreateInputRecord(recordFactory, inputObject);
}
protected Object extractOutputData(Record outputRecord) throws ResourceException {
return this.callDetector.callExtractOutputData(outputRecord);
}
}
private interface QueryCallDetector {
Record callCreateInputRecord(RecordFactory recordFactory, Object inputObject);
Object callExtractOutputData(Record outputRecord);
}
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jca.support;
import static org.easymock.EasyMock.*;
import static org.junit.Assert.*;
import javax.resource.spi.ConnectionManager;
import javax.resource.spi.ManagedConnectionFactory;
import org.junit.Test;
/**
* Unit tests for the {@link LocalConnectionFactoryBean} class.
*
* @author Rick Evans
* @author Chris Beams
*/
public final class LocalConnectionFactoryBeanTests {
@Test(expected=IllegalArgumentException.class)
public void testManagedConnectionFactoryIsRequired() throws Exception {
new LocalConnectionFactoryBean().afterPropertiesSet();
}
@Test
public void testIsSingleton() throws Exception {
LocalConnectionFactoryBean factory = new LocalConnectionFactoryBean();
assertTrue(factory.isSingleton());
}
@Test
public void testGetObjectTypeIsNullIfConnectionFactoryHasNotBeenConfigured() throws Exception {
LocalConnectionFactoryBean factory = new LocalConnectionFactoryBean();
assertNull(factory.getObjectType());
}
@Test
public void testCreatesVanillaConnectionFactoryIfNoConnectionManagerHasBeenConfigured() throws Exception {
final Object CONNECTION_FACTORY = new Object();
ManagedConnectionFactory managedConnectionFactory = createMock(ManagedConnectionFactory.class);
expect(managedConnectionFactory.createConnectionFactory()).andReturn(CONNECTION_FACTORY);
replay(managedConnectionFactory);
LocalConnectionFactoryBean factory = new LocalConnectionFactoryBean();
factory.setManagedConnectionFactory(managedConnectionFactory);
factory.afterPropertiesSet();
assertEquals(CONNECTION_FACTORY, factory.getObject());
verify(managedConnectionFactory);
}
@Test
public void testCreatesManagedConnectionFactoryIfAConnectionManagerHasBeenConfigured() throws Exception {
ManagedConnectionFactory managedConnectionFactory = createMock(ManagedConnectionFactory.class);
ConnectionManager connectionManager = createMock(ConnectionManager.class);
expect(managedConnectionFactory.createConnectionFactory(connectionManager)).andReturn(null);
replay(connectionManager, managedConnectionFactory);
LocalConnectionFactoryBean factory = new LocalConnectionFactoryBean();
factory.setManagedConnectionFactory(managedConnectionFactory);
factory.setConnectionManager(connectionManager);
factory.afterPropertiesSet();
verify(connectionManager, managedConnectionFactory);
}
}

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,235 @@
/*
* Copyright 2002-2009 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 assignment to the activated variable.
builder.activate();
}
return activated;
}
private final Log logger = LogFactory.getLog(getClass());
private final Hashtable<String,Object> boundObjects = new Hashtable<String,Object>();
/**
* 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 context 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() {
@SuppressWarnings("unchecked")
public Context getInitialContext(Hashtable<?,?> environment) {
return new SimpleNamingContext("", boundObjects, (Hashtable<String, Object>) environment);
}
};
}
}

View File

@@ -0,0 +1,58 @@
/*
* 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.transaction;
import org.springframework.transaction.support.AbstractPlatformTransactionManager;
import org.springframework.transaction.support.DefaultTransactionStatus;
/**
* @author Rod Johnson
* @author Juergen Hoeller
*/
public class CallCountingTransactionManager extends AbstractPlatformTransactionManager {
public TransactionDefinition lastDefinition;
public int begun;
public int commits;
public int rollbacks;
public int inflight;
protected Object doGetTransaction() {
return new Object();
}
protected void doBegin(Object transaction, TransactionDefinition definition) {
this.lastDefinition = definition;
++begun;
++inflight;
}
protected void doCommit(DefaultTransactionStatus status) {
++commits;
--inflight;
}
protected void doRollback(DefaultTransactionStatus status) {
++rollbacks;
--inflight;
}
public void clear() {
begun = commits = rollbacks = inflight = 0;
}
}

View File

@@ -0,0 +1,243 @@
/*
* 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.transaction;
import javax.transaction.Status;
import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;
import junit.framework.TestCase;
import org.easymock.MockControl;
import org.springframework.mock.jndi.ExpectedLookupTemplate;
import org.springframework.transaction.jta.JtaTransactionManager;
import org.springframework.transaction.jta.UserTransactionAdapter;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.transaction.support.TransactionTemplate;
/**
* @author Juergen Hoeller
* @since 05.08.2005
*/
public class JndiJtaTransactionManagerTests extends TestCase {
public void testJtaTransactionManagerWithDefaultJndiLookups1() throws Exception {
doTestJtaTransactionManagerWithDefaultJndiLookups("java:comp/TransactionManager", true, true);
}
public void testJtaTransactionManagerWithDefaultJndiLookups2() throws Exception {
doTestJtaTransactionManagerWithDefaultJndiLookups("java:/TransactionManager", true, true);
}
public void testJtaTransactionManagerWithDefaultJndiLookupsAndNoTmFound() throws Exception {
doTestJtaTransactionManagerWithDefaultJndiLookups("java:/tm", false, true);
}
public void testJtaTransactionManagerWithDefaultJndiLookupsAndNoUtFound() throws Exception {
doTestJtaTransactionManagerWithDefaultJndiLookups("java:/TransactionManager", true, false);
}
private void doTestJtaTransactionManagerWithDefaultJndiLookups(String tmName, boolean tmFound, boolean defaultUt)
throws Exception {
MockControl utControl = MockControl.createControl(UserTransaction.class);
UserTransaction ut = (UserTransaction) utControl.getMock();
if (defaultUt) {
ut.getStatus();
utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1);
ut.getStatus();
utControl.setReturnValue(Status.STATUS_ACTIVE, 2);
ut.begin();
utControl.setVoidCallable(1);
ut.commit();
utControl.setVoidCallable(1);
}
utControl.replay();
MockControl tmControl = MockControl.createControl(TransactionManager.class);
TransactionManager tm = (TransactionManager) tmControl.getMock();
if (!defaultUt) {
tm.getStatus();
tmControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1);
tm.getStatus();
tmControl.setReturnValue(Status.STATUS_ACTIVE, 2);
tm.begin();
tmControl.setVoidCallable(1);
tm.commit();
tmControl.setVoidCallable(1);
}
tmControl.replay();
JtaTransactionManager ptm = new JtaTransactionManager();
ExpectedLookupTemplate jndiTemplate = new ExpectedLookupTemplate();
if (defaultUt) {
jndiTemplate.addObject("java:comp/UserTransaction", ut);
}
jndiTemplate.addObject(tmName, tm);
ptm.setJndiTemplate(jndiTemplate);
ptm.afterPropertiesSet();
if (tmFound) {
assertEquals(tm, ptm.getTransactionManager());
}
else {
assertNull(ptm.getTransactionManager());
}
if (defaultUt) {
assertEquals(ut, ptm.getUserTransaction());
}
else {
assertTrue(ptm.getUserTransaction() instanceof UserTransactionAdapter);
UserTransactionAdapter uta = (UserTransactionAdapter) ptm.getUserTransaction();
assertEquals(tm, uta.getTransactionManager());
}
TransactionTemplate tt = new TransactionTemplate(ptm);
assertTrue(!TransactionSynchronizationManager.isSynchronizationActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
tt.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
// something transactional
assertTrue(TransactionSynchronizationManager.isSynchronizationActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
}
});
assertTrue(!TransactionSynchronizationManager.isSynchronizationActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
utControl.verify();
tmControl.verify();
}
public void testJtaTransactionManagerWithCustomJndiLookups() throws Exception {
MockControl utControl = MockControl.createControl(UserTransaction.class);
UserTransaction ut = (UserTransaction) utControl.getMock();
ut.getStatus();
utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1);
ut.getStatus();
utControl.setReturnValue(Status.STATUS_ACTIVE, 2);
ut.begin();
utControl.setVoidCallable(1);
ut.commit();
utControl.setVoidCallable(1);
utControl.replay();
MockControl tmControl = MockControl.createControl(TransactionManager.class);
TransactionManager tm = (TransactionManager) tmControl.getMock();
JtaTransactionManager ptm = new JtaTransactionManager();
ptm.setUserTransactionName("jndi-ut");
ptm.setTransactionManagerName("jndi-tm");
ExpectedLookupTemplate jndiTemplate = new ExpectedLookupTemplate();
jndiTemplate.addObject("jndi-ut", ut);
jndiTemplate.addObject("jndi-tm", tm);
ptm.setJndiTemplate(jndiTemplate);
ptm.afterPropertiesSet();
assertEquals(ut, ptm.getUserTransaction());
assertEquals(tm, ptm.getTransactionManager());
TransactionTemplate tt = new TransactionTemplate(ptm);
assertTrue(!TransactionSynchronizationManager.isSynchronizationActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
tt.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
// something transactional
assertTrue(TransactionSynchronizationManager.isSynchronizationActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
}
});
assertTrue(!TransactionSynchronizationManager.isSynchronizationActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
utControl.verify();
}
public void testJtaTransactionManagerWithNotCacheUserTransaction() throws Exception {
MockControl utControl = MockControl.createControl(UserTransaction.class);
UserTransaction ut = (UserTransaction) utControl.getMock();
ut.getStatus();
utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1);
ut.getStatus();
utControl.setReturnValue(Status.STATUS_ACTIVE, 2);
ut.begin();
utControl.setVoidCallable(1);
ut.commit();
utControl.setVoidCallable(1);
utControl.replay();
MockControl ut2Control = MockControl.createControl(UserTransaction.class);
UserTransaction ut2 = (UserTransaction) ut2Control.getMock();
ut2.getStatus();
ut2Control.setReturnValue(Status.STATUS_NO_TRANSACTION, 1);
ut2.getStatus();
ut2Control.setReturnValue(Status.STATUS_ACTIVE, 2);
ut2.begin();
ut2Control.setVoidCallable(1);
ut2.commit();
ut2Control.setVoidCallable(1);
ut2Control.replay();
JtaTransactionManager ptm = new JtaTransactionManager();
ptm.setJndiTemplate(new ExpectedLookupTemplate("java:comp/UserTransaction", ut));
ptm.setCacheUserTransaction(false);
ptm.afterPropertiesSet();
assertEquals(ut, ptm.getUserTransaction());
TransactionTemplate tt = new TransactionTemplate(ptm);
assertEquals(JtaTransactionManager.SYNCHRONIZATION_ALWAYS, ptm.getTransactionSynchronization());
assertTrue(!TransactionSynchronizationManager.isSynchronizationActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
tt.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
// something transactional
assertTrue(TransactionSynchronizationManager.isSynchronizationActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
}
});
ptm.setJndiTemplate(new ExpectedLookupTemplate("java:comp/UserTransaction", ut2));
tt.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
// something transactional
assertTrue(TransactionSynchronizationManager.isSynchronizationActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
}
});
assertTrue(!TransactionSynchronizationManager.isSynchronizationActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
utControl.verify();
ut2Control.verify();
}
/**
* Prevent any side-effects due to this test modifying ThreadLocals that might
* affect subsequent tests when all tests are run in the same JVM, as with Eclipse.
*/
protected void tearDown() {
assertTrue(TransactionSynchronizationManager.getResourceMap().isEmpty());
assertFalse(TransactionSynchronizationManager.isSynchronizationActive());
assertNull(TransactionSynchronizationManager.getCurrentTransactionName());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
}
}

View File

@@ -0,0 +1,60 @@
/*
* 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.transaction;
import org.springframework.transaction.support.CallbackPreferringPlatformTransactionManager;
import org.springframework.transaction.support.SimpleTransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
/**
* @author Juergen Hoeller
*/
public class MockCallbackPreferringTransactionManager implements CallbackPreferringPlatformTransactionManager {
private TransactionDefinition definition;
private TransactionStatus status;
public Object execute(TransactionDefinition definition, TransactionCallback callback) throws TransactionException {
this.definition = definition;
this.status = new SimpleTransactionStatus();
return callback.doInTransaction(this.status);
}
public TransactionDefinition getDefinition() {
return this.definition;
}
public TransactionStatus getStatus() {
return this.status;
}
public TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
throw new UnsupportedOperationException();
}
public void commit(TransactionStatus status) throws TransactionException {
throw new UnsupportedOperationException();
}
public void rollback(TransactionStatus status) throws TransactionException {
throw new UnsupportedOperationException();
}
}

View File

@@ -0,0 +1,60 @@
/*
* 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.transaction;
import javax.transaction.Status;
import javax.transaction.Synchronization;
import javax.transaction.xa.XAResource;
/**
* @author Juergen Hoeller
* @since 31.08.2004
*/
public class MockJtaTransaction implements javax.transaction.Transaction {
private Synchronization synchronization;
public int getStatus() {
return Status.STATUS_ACTIVE;
}
public void registerSynchronization(Synchronization synchronization) {
this.synchronization = synchronization;
}
public Synchronization getSynchronization() {
return synchronization;
}
public boolean enlistResource(XAResource xaResource) {
return false;
}
public boolean delistResource(XAResource xaResource, int i) {
return false;
}
public void commit() {
}
public void rollback() {
}
public void setRollbackOnly() {
}
}

View File

@@ -0,0 +1,87 @@
/*
* 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.transaction;
import org.springframework.transaction.support.AbstractPlatformTransactionManager;
import org.springframework.transaction.support.DefaultTransactionStatus;
/**
* @author Juergen Hoeller
* @since 29.04.2003
*/
class TestTransactionManager extends AbstractPlatformTransactionManager {
private static final Object TRANSACTION = "transaction";
private final boolean existingTransaction;
private final boolean canCreateTransaction;
protected boolean begin = false;
protected boolean commit = false;
protected boolean rollback = false;
protected boolean rollbackOnly = false;
protected TestTransactionManager(boolean existingTransaction, boolean canCreateTransaction) {
this.existingTransaction = existingTransaction;
this.canCreateTransaction = canCreateTransaction;
setTransactionSynchronization(SYNCHRONIZATION_NEVER);
}
protected Object doGetTransaction() {
return TRANSACTION;
}
protected boolean isExistingTransaction(Object transaction) {
return existingTransaction;
}
protected void doBegin(Object transaction, TransactionDefinition definition) {
if (!TRANSACTION.equals(transaction)) {
throw new IllegalArgumentException("Not the same transaction object");
}
if (!this.canCreateTransaction) {
throw new CannotCreateTransactionException("Cannot create transaction");
}
this.begin = true;
}
protected void doCommit(DefaultTransactionStatus status) {
if (!TRANSACTION.equals(status.getTransaction())) {
throw new IllegalArgumentException("Not the same transaction object");
}
this.commit = true;
}
protected void doRollback(DefaultTransactionStatus status) {
if (!TRANSACTION.equals(status.getTransaction())) {
throw new IllegalArgumentException("Not the same transaction object");
}
this.rollback = true;
}
protected void doSetRollbackOnly(DefaultTransactionStatus status) {
if (!TRANSACTION.equals(status.getTransaction())) {
throw new IllegalArgumentException("Not the same transaction object");
}
this.rollbackOnly = true;
}
}

View File

@@ -0,0 +1,284 @@
/*
* 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.transaction;
import junit.framework.TestCase;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.transaction.support.DefaultTransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.transaction.support.TransactionTemplate;
/**
* @author Juergen Hoeller
* @since 29.04.2003
*/
public class TransactionSupportTests extends TestCase {
public void testNoExistingTransaction() {
PlatformTransactionManager tm = new TestTransactionManager(false, true);
DefaultTransactionStatus status1 = (DefaultTransactionStatus)
tm.getTransaction(new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_SUPPORTS));
assertTrue("Must not have transaction", status1.getTransaction() == null);
DefaultTransactionStatus status2 = (DefaultTransactionStatus)
tm.getTransaction(new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRED));
assertTrue("Must have transaction", status2.getTransaction() != null);
assertTrue("Must be new transaction", status2.isNewTransaction());
try {
tm.getTransaction(new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_MANDATORY));
fail("Should not have thrown NoTransactionException");
}
catch (IllegalTransactionStateException ex) {
// expected
}
}
public void testExistingTransaction() {
PlatformTransactionManager tm = new TestTransactionManager(true, true);
DefaultTransactionStatus status1 = (DefaultTransactionStatus)
tm.getTransaction(new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_SUPPORTS));
assertTrue("Must have transaction", status1.getTransaction() != null);
assertTrue("Must not be new transaction", !status1.isNewTransaction());
DefaultTransactionStatus status2 = (DefaultTransactionStatus)
tm.getTransaction(new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRED));
assertTrue("Must have transaction", status2.getTransaction() != null);
assertTrue("Must not be new transaction", !status2.isNewTransaction());
try {
DefaultTransactionStatus status3 = (DefaultTransactionStatus)
tm.getTransaction(new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_MANDATORY));
assertTrue("Must have transaction", status3.getTransaction() != null);
assertTrue("Must not be new transaction", !status3.isNewTransaction());
}
catch (NoTransactionException ex) {
fail("Should not have thrown NoTransactionException");
}
}
public void testCommitWithoutExistingTransaction() {
TestTransactionManager tm = new TestTransactionManager(false, true);
TransactionStatus status = tm.getTransaction(null);
tm.commit(status);
assertTrue("triggered begin", tm.begin);
assertTrue("triggered commit", tm.commit);
assertTrue("no rollback", !tm.rollback);
assertTrue("no rollbackOnly", !tm.rollbackOnly);
}
public void testRollbackWithoutExistingTransaction() {
TestTransactionManager tm = new TestTransactionManager(false, true);
TransactionStatus status = tm.getTransaction(null);
tm.rollback(status);
assertTrue("triggered begin", tm.begin);
assertTrue("no commit", !tm.commit);
assertTrue("triggered rollback", tm.rollback);
assertTrue("no rollbackOnly", !tm.rollbackOnly);
}
public void testRollbackOnlyWithoutExistingTransaction() {
TestTransactionManager tm = new TestTransactionManager(false, true);
TransactionStatus status = tm.getTransaction(null);
status.setRollbackOnly();
tm.commit(status);
assertTrue("triggered begin", tm.begin);
assertTrue("no commit", !tm.commit);
assertTrue("triggered rollback", tm.rollback);
assertTrue("no rollbackOnly", !tm.rollbackOnly);
}
public void testCommitWithExistingTransaction() {
TestTransactionManager tm = new TestTransactionManager(true, true);
TransactionStatus status = tm.getTransaction(null);
tm.commit(status);
assertTrue("no begin", !tm.begin);
assertTrue("no commit", !tm.commit);
assertTrue("no rollback", !tm.rollback);
assertTrue("no rollbackOnly", !tm.rollbackOnly);
}
public void testRollbackWithExistingTransaction() {
TestTransactionManager tm = new TestTransactionManager(true, true);
TransactionStatus status = tm.getTransaction(null);
tm.rollback(status);
assertTrue("no begin", !tm.begin);
assertTrue("no commit", !tm.commit);
assertTrue("no rollback", !tm.rollback);
assertTrue("triggered rollbackOnly", tm.rollbackOnly);
}
public void testRollbackOnlyWithExistingTransaction() {
TestTransactionManager tm = new TestTransactionManager(true, true);
TransactionStatus status = tm.getTransaction(null);
status.setRollbackOnly();
tm.commit(status);
assertTrue("no begin", !tm.begin);
assertTrue("no commit", !tm.commit);
assertTrue("no rollback", !tm.rollback);
assertTrue("triggered rollbackOnly", tm.rollbackOnly);
}
public void testTransactionTemplate() {
TestTransactionManager tm = new TestTransactionManager(false, true);
TransactionTemplate template = new TransactionTemplate(tm);
template.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
}
});
assertTrue("triggered begin", tm.begin);
assertTrue("triggered commit", tm.commit);
assertTrue("no rollback", !tm.rollback);
assertTrue("no rollbackOnly", !tm.rollbackOnly);
}
public void testTransactionTemplateWithCallbackPreference() {
MockCallbackPreferringTransactionManager ptm = new MockCallbackPreferringTransactionManager();
TransactionTemplate template = new TransactionTemplate(ptm);
template.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
}
});
assertSame(template, ptm.getDefinition());
assertFalse(ptm.getStatus().isRollbackOnly());
}
public void testTransactionTemplateWithException() {
TestTransactionManager tm = new TestTransactionManager(false, true);
TransactionTemplate template = new TransactionTemplate(tm);
final RuntimeException ex = new RuntimeException("Some application exception");
try {
template.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
throw ex;
}
});
fail("Should have propagated RuntimeException");
}
catch (RuntimeException caught) {
// expected
assertTrue("Correct exception", caught == ex);
assertTrue("triggered begin", tm.begin);
assertTrue("no commit", !tm.commit);
assertTrue("triggered rollback", tm.rollback);
assertTrue("no rollbackOnly", !tm.rollbackOnly);
}
}
public void testTransactionTemplateWithRollbackException() {
final TransactionSystemException tex = new TransactionSystemException("system exception");
TestTransactionManager tm = new TestTransactionManager(false, true) {
protected void doRollback(DefaultTransactionStatus status) {
super.doRollback(status);
throw tex;
}
};
TransactionTemplate template = new TransactionTemplate(tm);
final RuntimeException ex = new RuntimeException("Some application exception");
try {
template.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
throw ex;
}
});
fail("Should have propagated RuntimeException");
}
catch (RuntimeException caught) {
// expected
assertTrue("Correct exception", caught == tex);
assertTrue("triggered begin", tm.begin);
assertTrue("no commit", !tm.commit);
assertTrue("triggered rollback", tm.rollback);
assertTrue("no rollbackOnly", !tm.rollbackOnly);
}
}
public void testTransactionTemplateWithError() {
TestTransactionManager tm = new TestTransactionManager(false, true);
TransactionTemplate template = new TransactionTemplate(tm);
try {
template.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
throw new Error("Some application error");
}
});
fail("Should have propagated Error");
}
catch (Error err) {
// expected
assertTrue("triggered begin", tm.begin);
assertTrue("no commit", !tm.commit);
assertTrue("triggered rollback", tm.rollback);
assertTrue("no rollbackOnly", !tm.rollbackOnly);
}
}
public void testTransactionTemplateInitialization() {
TestTransactionManager tm = new TestTransactionManager(false, true);
TransactionTemplate template = new TransactionTemplate();
template.setTransactionManager(tm);
assertTrue("correct transaction manager set", template.getTransactionManager() == tm);
try {
template.setPropagationBehaviorName("TIMEOUT_DEFAULT");
fail("Should have thrown IllegalArgumentException");
}
catch (IllegalArgumentException ex) {
// expected
}
template.setPropagationBehaviorName("PROPAGATION_SUPPORTS");
assertTrue("Correct propagation behavior set", template.getPropagationBehavior() == TransactionDefinition.PROPAGATION_SUPPORTS);
try {
template.setPropagationBehavior(999);
fail("Should have thrown IllegalArgumentException");
}
catch (IllegalArgumentException ex) {
// expected
}
template.setPropagationBehavior(TransactionDefinition.PROPAGATION_MANDATORY);
assertTrue("Correct propagation behavior set", template.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY);
try {
template.setIsolationLevelName("TIMEOUT_DEFAULT");
fail("Should have thrown IllegalArgumentException");
}
catch (IllegalArgumentException ex) {
// expected
}
template.setIsolationLevelName("ISOLATION_SERIALIZABLE");
assertTrue("Correct isolation level set", template.getIsolationLevel() == TransactionDefinition.ISOLATION_SERIALIZABLE);
try {
template.setIsolationLevel(999);
fail("Should have thrown IllegalArgumentException");
}
catch (IllegalArgumentException ex) {
// expected
}
template.setIsolationLevel(TransactionDefinition.ISOLATION_REPEATABLE_READ);
assertTrue("Correct isolation level set", template.getIsolationLevel() == TransactionDefinition.ISOLATION_REPEATABLE_READ);
}
protected void tearDown() {
assertTrue(TransactionSynchronizationManager.getResourceMap().isEmpty());
assertFalse(TransactionSynchronizationManager.isSynchronizationActive());
}
}

View File

@@ -0,0 +1,50 @@
/*
* 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.transaction;
import junit.framework.TestCase;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.parsing.CollectingReaderEventListener;
import org.springframework.beans.factory.parsing.ComponentDefinition;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.ClassPathResource;
/**
* @author Torsten Juergeleit
* @author Juergen Hoeller
*/
public class TxNamespaceHandlerEventTests extends TestCase {
private DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
private CollectingReaderEventListener eventListener = new CollectingReaderEventListener();
public void setUp() throws Exception {
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this.beanFactory);
reader.setEventListener(this.eventListener);
reader.loadBeanDefinitions(new ClassPathResource("txNamespaceHandlerTests.xml", getClass()));
}
public void testComponentEventReceived() {
ComponentDefinition component = this.eventListener.getComponentDefinition("txAdvice");
assertTrue(component instanceof BeanComponentDefinition);
}
}

View File

@@ -0,0 +1,94 @@
/*
* 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.transaction;
import java.lang.reflect.Method;
import junit.framework.TestCase;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.ITestBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.transaction.interceptor.TransactionAttribute;
import org.springframework.transaction.interceptor.TransactionAttributeSource;
import org.springframework.transaction.interceptor.TransactionInterceptor;
/**
* @author Rob Harrop
* @author Adrian Colyer
*/
public class TxNamespaceHandlerTests extends TestCase {
private ApplicationContext context;
private Method getAgeMethod;
private Method setAgeMethod;
public void setUp() throws Exception {
this.context = new ClassPathXmlApplicationContext("txNamespaceHandlerTests.xml", getClass());
this.getAgeMethod = ITestBean.class.getMethod("getAge", new Class[0]);
this.setAgeMethod = ITestBean.class.getMethod("setAge", new Class[] {int.class});
}
public void testIsProxy() throws Exception {
ITestBean bean = getTestBean();
assertTrue("testBean is not a proxy", AopUtils.isAopProxy(bean));
}
public void testInvokeTransactional() throws Exception {
ITestBean testBean = getTestBean();
CallCountingTransactionManager ptm = (CallCountingTransactionManager) context.getBean("transactionManager");
// try with transactional
assertEquals("Should not have any started transactions", 0, ptm.begun);
testBean.getName();
assertTrue(ptm.lastDefinition.isReadOnly());
assertEquals("Should have 1 started transaction", 1, ptm.begun);
assertEquals("Should have 1 committed transaction", 1, ptm.commits);
// try with non-transaction
testBean.haveBirthday();
assertEquals("Should not have started another transaction", 1, ptm.begun);
// try with exceptional
try {
testBean.exceptional(new IllegalArgumentException("foo"));
fail("Should NEVER get here");
}
catch (Throwable throwable) {
assertEquals("Should have another started transaction", 2, ptm.begun);
assertEquals("Should have 1 rolled back transaction", 1, ptm.rollbacks);
}
}
public void testRollbackRules() {
TransactionInterceptor txInterceptor = (TransactionInterceptor) context.getBean("txRollbackAdvice");
TransactionAttributeSource txAttrSource = txInterceptor.getTransactionAttributeSource();
TransactionAttribute txAttr = txAttrSource.getTransactionAttribute(getAgeMethod,ITestBean.class);
assertTrue("should be configured to rollback on Exception",txAttr.rollbackOn(new Exception()));
txAttr = txAttrSource.getTransactionAttribute(setAgeMethod, ITestBean.class);
assertFalse("should not rollback on RuntimeException",txAttr.rollbackOn(new RuntimeException()));
}
private ITestBean getTestBean() {
return (ITestBean)context.getBean("testBean");
}
}

View File

@@ -0,0 +1,593 @@
/*
* Copyright 2002-2010 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.transaction.annotation;
import java.io.IOException;
import java.io.Serializable;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import javax.ejb.TransactionAttributeType;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.transaction.CallCountingTransactionManager;
import org.springframework.transaction.interceptor.NoRollbackRuleAttribute;
import org.springframework.transaction.interceptor.RollbackRuleAttribute;
import org.springframework.transaction.interceptor.RuleBasedTransactionAttribute;
import org.springframework.transaction.interceptor.TransactionAttribute;
import org.springframework.transaction.interceptor.TransactionInterceptor;
import org.springframework.util.SerializationTestUtils;
/**
* @author Colin Sampaleanu
* @author Juergen Hoeller
*/
public class AnnotationTransactionAttributeSourceTests {
@Test
public void testSerializable() throws Exception {
TestBean1 tb = new TestBean1();
CallCountingTransactionManager ptm = new CallCountingTransactionManager();
AnnotationTransactionAttributeSource tas = new AnnotationTransactionAttributeSource();
TransactionInterceptor ti = new TransactionInterceptor(ptm, tas);
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setInterfaces(new Class[] {ITestBean.class});
proxyFactory.addAdvice(ti);
proxyFactory.setTarget(tb);
ITestBean proxy = (ITestBean) proxyFactory.getProxy();
proxy.getAge();
assertEquals(1, ptm.commits);
ITestBean serializedProxy = (ITestBean) SerializationTestUtils.serializeAndDeserialize(proxy);
serializedProxy.getAge();
Advised advised = (Advised) serializedProxy;
TransactionInterceptor serializedTi = (TransactionInterceptor) advised.getAdvisors()[0].getAdvice();
CallCountingTransactionManager serializedPtm =
(CallCountingTransactionManager) serializedTi.getTransactionManager();
assertEquals(2, serializedPtm.commits);
}
@Test
public void testNullOrEmpty() throws Exception {
Method method = Empty.class.getMethod("getAge", (Class[]) null);
AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource();
assertNull(atas.getTransactionAttribute(method, null));
// Try again in case of caching
assertNull(atas.getTransactionAttribute(method, null));
}
/**
* Test the important case where the invocation is on a proxied interface method
* but the attribute is defined on the target class.
*/
@Test
public void testTransactionAttributeDeclaredOnClassMethod() throws Exception {
Method classMethod = ITestBean.class.getMethod("getAge", (Class[]) null);
AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource();
TransactionAttribute actual = atas.getTransactionAttribute(classMethod, TestBean1.class);
RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class));
assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules());
}
/**
* Test the important case where the invocation is on a proxied interface method
* but the attribute is defined on the target class.
*/
@Test
public void testTransactionAttributeDeclaredOnCglibClassMethod() throws Exception {
Method classMethod = ITestBean.class.getMethod("getAge", (Class[]) null);
TestBean1 tb = new TestBean1();
ProxyFactory pf = new ProxyFactory(tb);
pf.setProxyTargetClass(true);
Object proxy = pf.getProxy();
AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource();
TransactionAttribute actual = atas.getTransactionAttribute(classMethod, proxy.getClass());
RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class));
assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules());
}
/**
* Test case where attribute is on the interface method.
*/
@Test
public void testTransactionAttributeDeclaredOnInterfaceMethodOnly() throws Exception {
Method interfaceMethod = ITestBean2.class.getMethod("getAge", (Class[]) null);
AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource();
TransactionAttribute actual = atas.getTransactionAttribute(interfaceMethod, TestBean2.class);
RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules());
}
/**
* Test that when an attribute exists on both class and interface, class takes precedence.
*/
@Test
public void testTransactionAttributeOnTargetClassMethodOverridesAttributeOnInterfaceMethod() throws Exception {
Method interfaceMethod = ITestBean3.class.getMethod("getAge", (Class[]) null);
Method interfaceMethod2 = ITestBean3.class.getMethod("getName", (Class[]) null);
AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource();
TransactionAttribute actual = atas.getTransactionAttribute(interfaceMethod, TestBean3.class);
assertEquals(TransactionAttribute.PROPAGATION_REQUIRES_NEW, actual.getPropagationBehavior());
assertEquals(TransactionAttribute.ISOLATION_REPEATABLE_READ, actual.getIsolationLevel());
assertEquals(5, actual.getTimeout());
assertTrue(actual.isReadOnly());
RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class));
rbta.getRollbackRules().add(new NoRollbackRuleAttribute(IOException.class));
assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules());
TransactionAttribute actual2 = atas.getTransactionAttribute(interfaceMethod2, TestBean3.class);
assertEquals(TransactionAttribute.PROPAGATION_REQUIRED, actual2.getPropagationBehavior());
}
@Test
public void testRollbackRulesAreApplied() throws Exception {
Method method = TestBean3.class.getMethod("getAge", (Class[]) null);
AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource();
TransactionAttribute actual = atas.getTransactionAttribute(method, TestBean3.class);
RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
rbta.getRollbackRules().add(new RollbackRuleAttribute("java.lang.Exception"));
rbta.getRollbackRules().add(new NoRollbackRuleAttribute(IOException.class));
assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules());
assertTrue(actual.rollbackOn(new Exception()));
assertFalse(actual.rollbackOn(new IOException()));
actual = atas.getTransactionAttribute(method, method.getDeclaringClass());
rbta = new RuleBasedTransactionAttribute();
rbta.getRollbackRules().add(new RollbackRuleAttribute("java.lang.Exception"));
rbta.getRollbackRules().add(new NoRollbackRuleAttribute(IOException.class));
assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules());
assertTrue(actual.rollbackOn(new Exception()));
assertFalse(actual.rollbackOn(new IOException()));
}
/**
* Test that transaction attribute is inherited from class
* if not specified on method.
*/
@Test
public void testDefaultsToClassTransactionAttribute() throws Exception {
Method method = TestBean4.class.getMethod("getAge", (Class[]) null);
AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource();
TransactionAttribute actual = atas.getTransactionAttribute(method, TestBean4.class);
RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class));
rbta.getRollbackRules().add(new NoRollbackRuleAttribute(IOException.class));
assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules());
}
@Test
public void testCustomClassAttributeDetected() throws Exception {
Method method = TestBean5.class.getMethod("getAge", (Class[]) null);
AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource();
TransactionAttribute actual = atas.getTransactionAttribute(method, TestBean5.class);
RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class));
rbta.getRollbackRules().add(new NoRollbackRuleAttribute(IOException.class));
assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules());
}
@Test
public void testCustomMethodAttributeDetected() throws Exception {
Method method = TestBean6.class.getMethod("getAge", (Class[]) null);
AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource();
TransactionAttribute actual = atas.getTransactionAttribute(method, TestBean5.class);
RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class));
rbta.getRollbackRules().add(new NoRollbackRuleAttribute(IOException.class));
assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules());
}
@Test
public void testTransactionAttributeDeclaredOnClassMethodWithEjb3() throws Exception {
Method getAgeMethod = ITestBean.class.getMethod("getAge", (Class[]) null);
Method getNameMethod = ITestBean.class.getMethod("getName", (Class[]) null);
AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource();
TransactionAttribute getAgeAttr = atas.getTransactionAttribute(getAgeMethod, Ejb3AnnotatedBean1.class);
assertEquals(TransactionAttribute.PROPAGATION_REQUIRED, getAgeAttr.getPropagationBehavior());
TransactionAttribute getNameAttr = atas.getTransactionAttribute(getNameMethod, Ejb3AnnotatedBean1.class);
assertEquals(TransactionAttribute.PROPAGATION_SUPPORTS, getNameAttr.getPropagationBehavior());
}
@Test
public void testTransactionAttributeDeclaredOnClassWithEjb3() throws Exception {
Method getAgeMethod = ITestBean.class.getMethod("getAge", (Class[]) null);
Method getNameMethod = ITestBean.class.getMethod("getName", (Class[]) null);
AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource();
TransactionAttribute getAgeAttr = atas.getTransactionAttribute(getAgeMethod, Ejb3AnnotatedBean2.class);
assertEquals(TransactionAttribute.PROPAGATION_REQUIRED, getAgeAttr.getPropagationBehavior());
TransactionAttribute getNameAttr = atas.getTransactionAttribute(getNameMethod, Ejb3AnnotatedBean2.class);
assertEquals(TransactionAttribute.PROPAGATION_SUPPORTS, getNameAttr.getPropagationBehavior());
}
@Test
public void testTransactionAttributeDeclaredOnInterfaceWithEjb3() throws Exception {
Method getAgeMethod = ITestEjb.class.getMethod("getAge", (Class[]) null);
Method getNameMethod = ITestEjb.class.getMethod("getName", (Class[]) null);
AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource();
TransactionAttribute getAgeAttr = atas.getTransactionAttribute(getAgeMethod, Ejb3AnnotatedBean3.class);
assertEquals(TransactionAttribute.PROPAGATION_REQUIRED, getAgeAttr.getPropagationBehavior());
TransactionAttribute getNameAttr = atas.getTransactionAttribute(getNameMethod, Ejb3AnnotatedBean3.class);
assertEquals(TransactionAttribute.PROPAGATION_SUPPORTS, getNameAttr.getPropagationBehavior());
}
public interface ITestBean {
int getAge();
void setAge(int age);
String getName();
void setName(String name);
}
public interface ITestBean2 {
@Transactional
int getAge();
void setAge(int age);
String getName();
void setName(String name);
}
@Transactional
public interface ITestBean3 {
int getAge();
void setAge(int age);
String getName();
void setName(String name);
}
public static class Empty implements ITestBean {
private String name;
private int age;
public Empty() {
}
public Empty(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public static class TestBean1 implements ITestBean, Serializable {
private String name;
private int age;
public TestBean1() {
}
public TestBean1(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Transactional(rollbackFor=Exception.class)
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public static class TestBean2 implements ITestBean2 {
private String name;
private int age;
public TestBean2() {
}
public TestBean2(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public static class TestBean3 implements ITestBean3 {
private String name;
private int age;
public TestBean3() {
}
public TestBean3(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Transactional(propagation=Propagation.REQUIRES_NEW, isolation=Isolation.REPEATABLE_READ, timeout=5,
readOnly=true, rollbackFor=Exception.class, noRollbackFor={IOException.class})
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
@Transactional(rollbackFor=Exception.class, noRollbackFor={IOException.class})
public static class TestBean4 implements ITestBean3 {
private String name;
private int age;
public TestBean4() {
}
public TestBean4(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Transactional(rollbackFor=Exception.class, noRollbackFor={IOException.class})
public @interface Tx {
}
@Tx
public static class TestBean5 {
public int getAge() {
return 10;
}
}
public static class TestBean6 {
@Tx
public int getAge() {
return 10;
}
}
public static interface Foo<T> {
void doSomething(T theArgument);
}
public static class MyFoo implements Foo<String> {
@Transactional
public void doSomething(String theArgument) {
System.out.println(theArgument);
}
}
public static class Ejb3AnnotatedBean1 implements ITestBean {
private String name;
private int age;
@javax.ejb.TransactionAttribute(TransactionAttributeType.SUPPORTS)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@javax.ejb.TransactionAttribute
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
@javax.ejb.TransactionAttribute(TransactionAttributeType.SUPPORTS)
public static class Ejb3AnnotatedBean2 implements ITestBean {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@javax.ejb.TransactionAttribute
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
@javax.ejb.TransactionAttribute(TransactionAttributeType.SUPPORTS)
public interface ITestEjb {
@javax.ejb.TransactionAttribute
int getAge();
void setAge(int age);
String getName();
void setName(String name);
}
public static class Ejb3AnnotatedBean3 implements ITestEjb {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
}

View File

@@ -0,0 +1,374 @@
/*
* 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.transaction.annotation;
import junit.framework.TestCase;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.transaction.CallCountingTransactionManager;
import org.springframework.transaction.interceptor.TransactionInterceptor;
import org.springframework.transaction.support.TransactionSynchronizationManager;
/**
* @author Rob Harrop
* @author Juergen Hoeller
*/
public class AnnotationTransactionInterceptorTests extends TestCase {
private CallCountingTransactionManager ptm;
private AnnotationTransactionAttributeSource source;
private TransactionInterceptor ti;
public void setUp() {
this.ptm = new CallCountingTransactionManager();
this.source = new AnnotationTransactionAttributeSource();
this.ti = new TransactionInterceptor(this.ptm, this.source);
}
public void testClassLevelOnly() {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new TestClassLevelOnly());
proxyFactory.addAdvice(this.ti);
TestClassLevelOnly proxy = (TestClassLevelOnly) proxyFactory.getProxy();
proxy.doSomething();
assertGetTransactionAndCommitCount(1);
proxy.doSomethingElse();
assertGetTransactionAndCommitCount(2);
proxy.doSomething();
assertGetTransactionAndCommitCount(3);
proxy.doSomethingElse();
assertGetTransactionAndCommitCount(4);
}
public void testWithSingleMethodOverride() {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new TestWithSingleMethodOverride());
proxyFactory.addAdvice(this.ti);
TestWithSingleMethodOverride proxy = (TestWithSingleMethodOverride) proxyFactory.getProxy();
proxy.doSomething();
assertGetTransactionAndCommitCount(1);
proxy.doSomethingElse();
assertGetTransactionAndCommitCount(2);
proxy.doSomethingCompletelyElse();
assertGetTransactionAndCommitCount(3);
proxy.doSomething();
assertGetTransactionAndCommitCount(4);
}
public void testWithSingleMethodOverrideInverted() {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new TestWithSingleMethodOverrideInverted());
proxyFactory.addAdvice(this.ti);
TestWithSingleMethodOverrideInverted proxy = (TestWithSingleMethodOverrideInverted) proxyFactory.getProxy();
proxy.doSomething();
assertGetTransactionAndCommitCount(1);
proxy.doSomethingElse();
assertGetTransactionAndCommitCount(2);
proxy.doSomethingCompletelyElse();
assertGetTransactionAndCommitCount(3);
proxy.doSomething();
assertGetTransactionAndCommitCount(4);
}
public void testWithMultiMethodOverride() {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new TestWithMultiMethodOverride());
proxyFactory.addAdvice(this.ti);
TestWithMultiMethodOverride proxy = (TestWithMultiMethodOverride) proxyFactory.getProxy();
proxy.doSomething();
assertGetTransactionAndCommitCount(1);
proxy.doSomethingElse();
assertGetTransactionAndCommitCount(2);
proxy.doSomethingCompletelyElse();
assertGetTransactionAndCommitCount(3);
proxy.doSomething();
assertGetTransactionAndCommitCount(4);
}
public void testWithRollback() {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new TestWithRollback());
proxyFactory.addAdvice(this.ti);
TestWithRollback proxy = (TestWithRollback) proxyFactory.getProxy();
try {
proxy.doSomethingErroneous();
fail("Should throw IllegalStateException");
}
catch (IllegalStateException ex) {
assertGetTransactionAndRollbackCount(1);
}
try {
proxy.doSomethingElseErroneous();
fail("Should throw IllegalArgumentException");
}
catch (IllegalArgumentException ex) {
assertGetTransactionAndRollbackCount(2);
}
}
public void testWithInterface() {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new TestWithInterfaceImpl());
proxyFactory.addInterface(TestWithInterface.class);
proxyFactory.addAdvice(this.ti);
TestWithInterface proxy = (TestWithInterface) proxyFactory.getProxy();
proxy.doSomething();
assertGetTransactionAndCommitCount(1);
proxy.doSomethingElse();
assertGetTransactionAndCommitCount(2);
proxy.doSomethingElse();
assertGetTransactionAndCommitCount(3);
proxy.doSomething();
assertGetTransactionAndCommitCount(4);
}
public void testCrossClassInterfaceMethodLevelOnJdkProxy() throws Exception {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new SomeServiceImpl());
proxyFactory.addInterface(SomeService.class);
proxyFactory.addAdvice(this.ti);
SomeService someService = (SomeService) proxyFactory.getProxy();
someService.bar();
assertGetTransactionAndCommitCount(1);
someService.foo();
assertGetTransactionAndCommitCount(2);
someService.fooBar();
assertGetTransactionAndCommitCount(3);
}
public void testCrossClassInterfaceOnJdkProxy() throws Exception {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new OtherServiceImpl());
proxyFactory.addInterface(OtherService.class);
proxyFactory.addAdvice(this.ti);
OtherService otherService = (OtherService) proxyFactory.getProxy();
otherService.foo();
assertGetTransactionAndCommitCount(1);
}
private void assertGetTransactionAndCommitCount(int expectedCount) {
assertEquals(expectedCount, this.ptm.begun);
assertEquals(expectedCount, this.ptm.commits);
}
private void assertGetTransactionAndRollbackCount(int expectedCount) {
assertEquals(expectedCount, this.ptm.begun);
assertEquals(expectedCount, this.ptm.rollbacks);
}
@Transactional
public static class TestClassLevelOnly {
public void doSomething() {
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
}
public void doSomethingElse() {
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
}
}
@Transactional
public static class TestWithSingleMethodOverride {
public void doSomething() {
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
}
@Transactional(readOnly = true)
public void doSomethingElse() {
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertTrue(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
}
public void doSomethingCompletelyElse() {
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
}
}
@Transactional(readOnly = true)
public static class TestWithSingleMethodOverrideInverted {
@Transactional
public void doSomething() {
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
}
public void doSomethingElse() {
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertTrue(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
}
public void doSomethingCompletelyElse() {
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertTrue(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
}
}
@Transactional
public static class TestWithMultiMethodOverride {
@Transactional(readOnly = true)
public void doSomething() {
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertTrue(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
}
@Transactional(readOnly = true)
public void doSomethingElse() {
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertTrue(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
}
public void doSomethingCompletelyElse() {
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
}
}
@Transactional(rollbackFor = IllegalStateException.class)
public static class TestWithRollback {
public void doSomethingErroneous() {
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
throw new IllegalStateException();
}
@Transactional(rollbackFor = IllegalArgumentException.class)
public void doSomethingElseErroneous() {
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
throw new IllegalArgumentException();
}
}
@Transactional
public static interface TestWithInterface {
public void doSomething();
@Transactional(readOnly = true)
public void doSomethingElse();
}
public static class TestWithInterfaceImpl implements TestWithInterface {
public void doSomething() {
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
}
public void doSomethingElse() {
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertTrue(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
}
}
public static interface SomeService {
void foo();
@Transactional
void bar();
@Transactional(readOnly = true)
void fooBar();
}
public static class SomeServiceImpl implements SomeService {
public void bar() {
}
@Transactional
public void foo() {
}
@Transactional(readOnly = false)
public void fooBar() {
}
}
public static interface OtherService {
void foo();
}
@Transactional
public static class OtherServiceImpl implements OtherService {
public void foo() {
}
}
}

View File

@@ -0,0 +1,134 @@
/*
* 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.transaction.annotation;
import java.lang.management.ManagementFactory;
import java.util.Collection;
import java.util.Map;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import junit.framework.TestCase;
import org.springframework.aop.support.AopUtils;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.CallCountingTransactionManager;
/**
* @author Rob Harrop
* @author Juergen Hoeller
*/
public class AnnotationTransactionNamespaceHandlerTests extends TestCase {
private ConfigurableApplicationContext context;
public void setUp() {
this.context = new ClassPathXmlApplicationContext(
"org/springframework/transaction/annotation/annotationTransactionNamespaceHandlerTests.xml");
}
protected void tearDown() {
this.context.close();
}
public void testIsProxy() throws Exception {
TransactionalTestBean bean = getTestBean();
assertTrue("testBean is not a proxy", AopUtils.isAopProxy(bean));
Map services = this.context.getBeansWithAnnotation(Service.class);
assertTrue("Stereotype annotation not visible", services.containsKey("testBean"));
}
public void testInvokeTransactional() throws Exception {
TransactionalTestBean testBean = getTestBean();
CallCountingTransactionManager ptm = (CallCountingTransactionManager) context.getBean("transactionManager");
// try with transactional
assertEquals("Should not have any started transactions", 0, ptm.begun);
testBean.findAllFoos();
assertEquals("Should have 1 started transaction", 1, ptm.begun);
assertEquals("Should have 1 committed transaction", 1, ptm.commits);
// try with non-transaction
testBean.doSomething();
assertEquals("Should not have started another transaction", 1, ptm.begun);
// try with exceptional
try {
testBean.exceptional(new IllegalArgumentException("foo"));
fail("Should NEVER get here");
}
catch (Throwable throwable) {
assertEquals("Should have another started transaction", 2, ptm.begun);
assertEquals("Should have 1 rolled back transaction", 1, ptm.rollbacks);
}
}
public void testNonPublicMethodsNotAdvised() {
TransactionalTestBean testBean = getTestBean();
CallCountingTransactionManager ptm = (CallCountingTransactionManager) context.getBean("transactionManager");
assertEquals("Should not have any started transactions", 0, ptm.begun);
testBean.annotationsOnProtectedAreIgnored();
assertEquals("Should not have any started transactions", 0, ptm.begun);
}
public void testMBeanExportAlsoWorks() throws Exception {
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
assertEquals("done",
server.invoke(ObjectName.getInstance("test:type=TestBean"), "doSomething", new Object[0], new String[0]));
}
private TransactionalTestBean getTestBean() {
return (TransactionalTestBean) context.getBean("testBean");
}
@Service
@ManagedResource("test:type=TestBean")
public static class TransactionalTestBean {
@Transactional(readOnly = true)
public Collection findAllFoos() {
return null;
}
@Transactional
public void saveFoo() {
}
@Transactional
public void exceptional(Throwable t) throws Throwable {
throw t;
}
@ManagedOperation
public String doSomething() {
return "done";
}
@Transactional
protected void annotationsOnProtectedAreIgnored() {
}
}
}

View File

@@ -0,0 +1,134 @@
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.transaction.annotation;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import java.util.Map;
import org.junit.Test;
import org.springframework.aop.support.AopUtils;
import org.springframework.context.annotation.AdviceMode;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Service;
import org.springframework.transaction.CallCountingTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.AnnotationTransactionNamespaceHandlerTests.TransactionalTestBean;
/**
* Tests demonstrating use of @EnableTransactionManagement @Configuration classes.
*
* @author Chris Beams
* @since 3.1
*/
public class EnableTransactionManagementTests {
@Test
public void transactionProxyIsCreated() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(EnableTxConfig.class, TxManagerConfig.class);
ctx.refresh();
TransactionalTestBean bean = ctx.getBean(TransactionalTestBean.class);
assertThat("testBean is not a proxy", AopUtils.isAopProxy(bean), is(true));
Map<?,?> services = ctx.getBeansWithAnnotation(Service.class);
assertThat("Stereotype annotation not visible", services.containsKey("testBean"), is(true));
}
@Test
public void txManagerIsResolvedOnInvocationOfTransactionalMethod() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(EnableTxConfig.class, TxManagerConfig.class);
ctx.refresh();
TransactionalTestBean bean = ctx.getBean(TransactionalTestBean.class);
// invoke a transactional method, causing the PlatformTransactionManager bean to be resolved.
bean.findAllFoos();
}
@Test
public void txManagerIsResolvedCorrectlyWhenMultipleManagersArePresent() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(EnableTxConfig.class, MultiTxManagerConfig.class);
ctx.refresh();
TransactionalTestBean bean = ctx.getBean(TransactionalTestBean.class);
// invoke a transactional method, causing the PlatformTransactionManager bean to be resolved.
bean.findAllFoos();
}
/**
* A cheap test just to prove that in ASPECTJ mode, the AnnotationTransactionAspect does indeed
* get loaded -- or in this case, attempted to be loaded at which point the test fails.
*/
@Test
public void proxyTypeAspectJCausesRegistrationOfAnnotationTransactionAspect() {
try {
new AnnotationConfigApplicationContext(EnableAspectJTxConfig.class, TxManagerConfig.class);
fail("should have thrown CNFE when trying to load AnnotationTransactionAspect. " +
"Do you actually have org.springframework.aspects on the classpath?");
} catch (Exception ex) {
System.out.println(ex);
assertThat(ex.getMessage().endsWith("AspectJTransactionManagementConfiguration.class] cannot be opened because it does not exist"), is(true));
}
}
@Configuration
@EnableTransactionManagement
static class EnableTxConfig {
}
@Configuration
@EnableTransactionManagement(mode=AdviceMode.ASPECTJ)
static class EnableAspectJTxConfig {
}
@Configuration
static class TxManagerConfig {
@Bean
public TransactionalTestBean testBean() {
return new TransactionalTestBean();
}
@Bean
public PlatformTransactionManager txManager() {
return new CallCountingTransactionManager();
}
}
@Configuration
static class MultiTxManagerConfig extends TxManagerConfig implements TransactionManagementConfigurer {
@Bean
public PlatformTransactionManager txManager2() {
return new CallCountingTransactionManager();
}
public PlatformTransactionManager annotationDrivenTransactionManager() {
return txManager2();
}
}
}

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<tx:annotation-driven/>
<bean id="transactionManager" class="org.springframework.transaction.CallCountingTransactionManager"/>
<bean id="testBean"
class="org.springframework.transaction.annotation.AnnotationTransactionNamespaceHandlerTests$TransactionalTestBean"/>
<context:mbean-export/>
</beans>

View File

@@ -0,0 +1,102 @@
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.transaction.config;
import java.io.Serializable;
import junit.framework.TestCase;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.support.AopUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.transaction.CallCountingTransactionManager;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.SerializationTestUtils;
/**
* @author Rob Harrop
* @author Juergen Hoeller
*/
public class AnnotationDrivenTests extends TestCase {
public void testWithProxyTargetClass() throws Exception {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("annotationDrivenProxyTargetClassTests.xml", getClass());
doTestWithMultipleTransactionManagers(context);
}
public void testWithConfigurationClass() throws Exception {
AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext();
parent.register(TransactionManagerConfiguration.class);
parent.refresh();
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"annotationDrivenConfigurationClassTests.xml"}, getClass(), parent);
doTestWithMultipleTransactionManagers(context);
}
private void doTestWithMultipleTransactionManagers(ApplicationContext context) {
CallCountingTransactionManager tm1 = context.getBean("transactionManager1", CallCountingTransactionManager.class);
CallCountingTransactionManager tm2 = context.getBean("transactionManager2", CallCountingTransactionManager.class);
TransactionalService service = context.getBean("service", TransactionalService.class);
assertTrue(AopUtils.isCglibProxy(service));
service.setSomething("someName");
assertEquals(1, tm1.commits);
assertEquals(0, tm2.commits);
service.doSomething();
assertEquals(1, tm1.commits);
assertEquals(1, tm2.commits);
service.setSomething("someName");
assertEquals(2, tm1.commits);
assertEquals(1, tm2.commits);
service.doSomething();
assertEquals(2, tm1.commits);
assertEquals(2, tm2.commits);
}
public void testSerializableWithPreviousUsage() throws Exception {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("annotationDrivenProxyTargetClassTests.xml", getClass());
TransactionalService service = context.getBean("service", TransactionalService.class);
service.setSomething("someName");
service = (TransactionalService) SerializationTestUtils.serializeAndDeserialize(service);
service.setSomething("someName");
}
public void testSerializableWithoutPreviousUsage() throws Exception {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("annotationDrivenProxyTargetClassTests.xml", getClass());
TransactionalService service = context.getBean("service", TransactionalService.class);
service = (TransactionalService) SerializationTestUtils.serializeAndDeserialize(service);
service.setSomething("someName");
}
public static class TransactionCheckingInterceptor implements MethodInterceptor, Serializable {
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
if (methodInvocation.getMethod().getName().equals("setSomething")) {
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertTrue(TransactionSynchronizationManager.isSynchronizationActive());
}
else {
assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isSynchronizationActive());
}
return methodInvocation.proceed();
}
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2002-2010 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.transaction.config;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.CallCountingTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
/**
* @author Juergen Hoeller
*/
@Configuration
public class TransactionManagerConfiguration {
@Bean
@Qualifier("synch")
public PlatformTransactionManager transactionManager1() {
return new CallCountingTransactionManager();
}
@Bean
@Qualifier("noSynch")
public PlatformTransactionManager transactionManager2() {
CallCountingTransactionManager tm = new CallCountingTransactionManager();
tm.setTransactionSynchronization(CallCountingTransactionManager.SYNCHRONIZATION_NEVER);
return tm;
}
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2002-2010 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.transaction.config;
import java.io.Serializable;
import org.springframework.transaction.annotation.Transactional;
/**
* @author Rob Harrop
* @author Juergen Hoeller
*/
public class TransactionalService implements Serializable {
@Transactional("synch")
public void setSomething(String name) {
}
@Transactional("noSynch")
public void doSomething() {
}
}

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<context:annotation-config/>
<tx:annotation-driven proxy-target-class="true" order="0"/>
<aop:config>
<aop:advisor advice-ref="txCheckingInterceptor" pointcut="execution(* *..TransactionalService.*(..))" order="1"/>
</aop:config>
<bean id="txCheckingInterceptor" class="org.springframework.transaction.config.AnnotationDrivenTests$TransactionCheckingInterceptor"/>
<bean id="service" class="org.springframework.transaction.config.TransactionalService"/>
</beans>

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<tx:annotation-driven proxy-target-class="true" order="0"/>
<aop:config>
<aop:advisor advice-ref="txCheckingInterceptor" pointcut="execution(* *..TransactionalService.*(..))" order="1"/>
</aop:config>
<bean id="txCheckingInterceptor" class="org.springframework.transaction.config.AnnotationDrivenTests$TransactionCheckingInterceptor"/>
<bean id="transactionManager1" class="org.springframework.transaction.CallCountingTransactionManager">
<qualifier value="synch"/>
</bean>
<bean id="transactionManager2" class="org.springframework.transaction.CallCountingTransactionManager">
<property name="transactionSynchronizationName" value="SYNCHRONIZATION_NEVER"/>
<qualifier value="noSynch"/>
</bean>
<bean id="service" class="org.springframework.transaction.config.TransactionalService"/>
</beans>

View File

@@ -0,0 +1,599 @@
/*
* 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.transaction.interceptor;
import java.lang.reflect.Method;
import junit.framework.TestCase;
import org.easymock.MockControl;
import org.springframework.beans.ITestBean;
import org.springframework.beans.TestBean;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.transaction.CannotCreateTransactionException;
import org.springframework.transaction.MockCallbackPreferringTransactionManager;
import org.springframework.transaction.NoTransactionException;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.TransactionSystemException;
import org.springframework.transaction.UnexpectedRollbackException;
import org.springframework.transaction.interceptor.TransactionAspectSupport.TransactionInfo;
/**
* Mock object based tests for transaction aspects.
* True unit test in that it tests how the transaction aspect uses
* the PlatformTransactionManager helper, rather than indirectly
* testing the helper implementation.
*
* This is a superclass to allow testing both the AOP Alliance MethodInterceptor
* and the AspectJ aspect.
*
* @author Rod Johnson
* @since 16.03.2003
*/
public abstract class AbstractTransactionAspectTests extends TestCase {
protected Method exceptionalMethod;
protected Method getNameMethod;
protected Method setNameMethod;
public AbstractTransactionAspectTests() {
try {
// Cache the methods we'll be testing
exceptionalMethod = ITestBean.class.getMethod("exceptional", new Class[] { Throwable.class });
getNameMethod = ITestBean.class.getMethod("getName", (Class[]) null);
setNameMethod = ITestBean.class.getMethod("setName", new Class[] { String.class} );
}
catch (NoSuchMethodException ex) {
throw new RuntimeException("Shouldn't happen", ex);
}
}
public void testNoTransaction() throws Exception {
MockControl ptmControl = MockControl.createControl(PlatformTransactionManager.class);
PlatformTransactionManager ptm = (PlatformTransactionManager) ptmControl.getMock();
// expect no calls
ptmControl.replay();
TestBean tb = new TestBean();
TransactionAttributeSource tas = new MapTransactionAttributeSource();
// All the methods in this class use the advised() template method
// to obtain a transaction object, configured with the given PlatformTransactionManager
// and transaction attribute source
ITestBean itb = (ITestBean) advised(tb, ptm, tas);
checkTransactionStatus(false);
itb.getName();
checkTransactionStatus(false);
ptmControl.verify();
}
/**
* Check that a transaction is created and committed.
*/
public void testTransactionShouldSucceed() throws Exception {
TransactionAttribute txatt = new DefaultTransactionAttribute();
MapTransactionAttributeSource tas = new MapTransactionAttributeSource();
tas.register(getNameMethod, txatt);
TransactionStatus status = transactionStatusForNewTransaction();
MockControl ptmControl = MockControl.createControl(PlatformTransactionManager.class);
PlatformTransactionManager ptm = (PlatformTransactionManager) ptmControl.getMock();
// expect a transaction
ptm.getTransaction(txatt);
ptmControl.setReturnValue(status, 1);
ptm.commit(status);
ptmControl.setVoidCallable(1);
ptmControl.replay();
TestBean tb = new TestBean();
ITestBean itb = (ITestBean) advised(tb, ptm, tas);
checkTransactionStatus(false);
itb.getName();
checkTransactionStatus(false);
ptmControl.verify();
}
/**
* Check that a transaction is created and committed using
* CallbackPreferringPlatformTransactionManager.
*/
public void testTransactionShouldSucceedWithCallbackPreference() throws Exception {
TransactionAttribute txatt = new DefaultTransactionAttribute();
MapTransactionAttributeSource tas = new MapTransactionAttributeSource();
tas.register(getNameMethod, txatt);
MockCallbackPreferringTransactionManager ptm = new MockCallbackPreferringTransactionManager();
TestBean tb = new TestBean();
ITestBean itb = (ITestBean) advised(tb, ptm, tas);
checkTransactionStatus(false);
itb.getName();
checkTransactionStatus(false);
assertSame(txatt, ptm.getDefinition());
assertFalse(ptm.getStatus().isRollbackOnly());
}
public void testTransactionExceptionPropagatedWithCallbackPreference() throws Throwable {
TransactionAttribute txatt = new DefaultTransactionAttribute();
MapTransactionAttributeSource tas = new MapTransactionAttributeSource();
tas.register(exceptionalMethod, txatt);
MockCallbackPreferringTransactionManager ptm = new MockCallbackPreferringTransactionManager();
TestBean tb = new TestBean();
ITestBean itb = (ITestBean) advised(tb, ptm, tas);
checkTransactionStatus(false);
try {
itb.exceptional(new OptimisticLockingFailureException(""));
fail("Should have thrown OptimisticLockingFailureException");
}
catch (OptimisticLockingFailureException ex) {
// expected
}
checkTransactionStatus(false);
assertSame(txatt, ptm.getDefinition());
assertFalse(ptm.getStatus().isRollbackOnly());
}
/**
* Check that two transactions are created and committed.
*/
public void testTwoTransactionsShouldSucceed() throws Exception {
TransactionAttribute txatt = new DefaultTransactionAttribute();
MapTransactionAttributeSource tas1 = new MapTransactionAttributeSource();
tas1.register(getNameMethod, txatt);
MapTransactionAttributeSource tas2 = new MapTransactionAttributeSource();
tas2.register(setNameMethod, txatt);
TransactionStatus status = transactionStatusForNewTransaction();
MockControl ptmControl = MockControl.createControl(PlatformTransactionManager.class);
PlatformTransactionManager ptm = (PlatformTransactionManager) ptmControl.getMock();
// expect a transaction
ptm.getTransaction(txatt);
ptmControl.setReturnValue(status, 2);
ptm.commit(status);
ptmControl.setVoidCallable(2);
ptmControl.replay();
TestBean tb = new TestBean();
ITestBean itb = (ITestBean) advised(tb, ptm, new TransactionAttributeSource[] {tas1, tas2});
checkTransactionStatus(false);
itb.getName();
checkTransactionStatus(false);
itb.setName("myName");
checkTransactionStatus(false);
ptmControl.verify();
}
/**
* Check that a transaction is created and committed.
*/
public void testTransactionShouldSucceedWithNotNew() throws Exception {
TransactionAttribute txatt = new DefaultTransactionAttribute();
MapTransactionAttributeSource tas = new MapTransactionAttributeSource();
tas.register(getNameMethod, txatt);
MockControl statusControl = MockControl.createControl(TransactionStatus.class);
TransactionStatus status = (TransactionStatus) statusControl.getMock();
MockControl ptmControl = MockControl.createControl(PlatformTransactionManager.class);
PlatformTransactionManager ptm = (PlatformTransactionManager) ptmControl.getMock();
// expect a transaction
ptm.getTransaction(txatt);
ptmControl.setReturnValue(status, 1);
ptm.commit(status);
ptmControl.setVoidCallable(1);
ptmControl.replay();
TestBean tb = new TestBean();
ITestBean itb = (ITestBean) advised(tb, ptm, tas);
checkTransactionStatus(false);
// verification!?
itb.getName();
checkTransactionStatus(false);
ptmControl.verify();
}
public void testEnclosingTransactionWithNonTransactionMethodOnAdvisedInside() throws Throwable {
TransactionAttribute txatt = new DefaultTransactionAttribute();
MapTransactionAttributeSource tas = new MapTransactionAttributeSource();
tas.register(exceptionalMethod, txatt);
TransactionStatus status = transactionStatusForNewTransaction();
MockControl ptmControl = MockControl.createControl(PlatformTransactionManager.class);
PlatformTransactionManager ptm = (PlatformTransactionManager) ptmControl.getMock();
// Expect a transaction
ptm.getTransaction(txatt);
ptmControl.setReturnValue(status, 1);
ptm.commit(status);
ptmControl.setVoidCallable(1);
ptmControl.replay();
final String spouseName = "innerName";
TestBean outer = new TestBean() {
public void exceptional(Throwable t) throws Throwable {
TransactionInfo ti = TransactionAspectSupport.currentTransactionInfo();
assertTrue(ti.hasTransaction());
assertEquals(spouseName, getSpouse().getName());
}
};
TestBean inner = new TestBean() {
public String getName() {
// Assert that we're in the inner proxy
TransactionInfo ti = TransactionAspectSupport.currentTransactionInfo();
assertFalse(ti.hasTransaction());
return spouseName;
}
};
ITestBean outerProxy = (ITestBean) advised(outer, ptm, tas);
ITestBean innerProxy = (ITestBean) advised(inner, ptm, tas);
outer.setSpouse(innerProxy);
checkTransactionStatus(false);
// Will invoke inner.getName, which is non-transactional
outerProxy.exceptional(null);
checkTransactionStatus(false);
ptmControl.verify();
}
public void testEnclosingTransactionWithNestedTransactionOnAdvisedInside() throws Throwable {
final TransactionAttribute outerTxatt = new DefaultTransactionAttribute();
final TransactionAttribute innerTxatt = new DefaultTransactionAttribute(TransactionDefinition.PROPAGATION_NESTED);
Method outerMethod = exceptionalMethod;
Method innerMethod = getNameMethod;
MapTransactionAttributeSource tas = new MapTransactionAttributeSource();
tas.register(outerMethod, outerTxatt);
tas.register(innerMethod, innerTxatt);
TransactionStatus outerStatus = transactionStatusForNewTransaction();
TransactionStatus innerStatus = transactionStatusForNewTransaction();
MockControl ptmControl = MockControl.createControl(PlatformTransactionManager.class);
PlatformTransactionManager ptm = (PlatformTransactionManager) ptmControl.getMock();
// Expect a transaction
ptm.getTransaction(outerTxatt);
ptmControl.setReturnValue(outerStatus, 1);
ptm.getTransaction(innerTxatt);
ptmControl.setReturnValue(innerStatus, 1);
ptm.commit(innerStatus);
ptmControl.setVoidCallable(1);
ptm.commit(outerStatus);
ptmControl.setVoidCallable(1);
ptmControl.replay();
final String spouseName = "innerName";
TestBean outer = new TestBean() {
public void exceptional(Throwable t) throws Throwable {
TransactionInfo ti = TransactionAspectSupport.currentTransactionInfo();
assertTrue(ti.hasTransaction());
assertEquals(outerTxatt, ti.getTransactionAttribute());
assertEquals(spouseName, getSpouse().getName());
}
};
TestBean inner = new TestBean() {
public String getName() {
// Assert that we're in the inner proxy
TransactionInfo ti = TransactionAspectSupport.currentTransactionInfo();
// Has nested transaction
assertTrue(ti.hasTransaction());
assertEquals(innerTxatt, ti.getTransactionAttribute());
return spouseName;
}
};
ITestBean outerProxy = (ITestBean) advised(outer, ptm, tas);
ITestBean innerProxy = (ITestBean) advised(inner, ptm, tas);
outer.setSpouse(innerProxy);
checkTransactionStatus(false);
// Will invoke inner.getName, which is non-transactional
outerProxy.exceptional(null);
checkTransactionStatus(false);
ptmControl.verify();
}
public void testRollbackOnCheckedException() throws Throwable {
doTestRollbackOnException(new Exception(), true, false);
}
public void testNoRollbackOnCheckedException() throws Throwable {
doTestRollbackOnException(new Exception(), false, false);
}
public void testRollbackOnUncheckedException() throws Throwable {
doTestRollbackOnException(new RuntimeException(), true, false);
}
public void testNoRollbackOnUncheckedException() throws Throwable {
doTestRollbackOnException(new RuntimeException(), false, false);
}
public void testRollbackOnCheckedExceptionWithRollbackException() throws Throwable {
doTestRollbackOnException(new Exception(), true, true);
}
public void testNoRollbackOnCheckedExceptionWithRollbackException() throws Throwable {
doTestRollbackOnException(new Exception(), false, true);
}
public void testRollbackOnUncheckedExceptionWithRollbackException() throws Throwable {
doTestRollbackOnException(new RuntimeException(), true, true);
}
public void testNoRollbackOnUncheckedExceptionWithRollbackException() throws Throwable {
doTestRollbackOnException(new RuntimeException(), false, true);
}
/**
* Check that the given exception thrown by the target can produce the
* desired behavior with the appropriate transaction attribute.
* @param ex exception to be thrown by the target
* @param shouldRollback whether this should cause a transaction rollback
*/
protected void doTestRollbackOnException(
final Exception ex, final boolean shouldRollback, boolean rollbackException) throws Exception {
TransactionAttribute txatt = new DefaultTransactionAttribute() {
public boolean rollbackOn(Throwable t) {
assertTrue(t == ex);
return shouldRollback;
}
};
Method m = exceptionalMethod;
MapTransactionAttributeSource tas = new MapTransactionAttributeSource();
tas.register(m, txatt);
MockControl statusControl = MockControl.createControl(TransactionStatus.class);
TransactionStatus status = (TransactionStatus) statusControl.getMock();
MockControl ptmControl = MockControl.createControl(PlatformTransactionManager.class);
PlatformTransactionManager ptm = (PlatformTransactionManager) ptmControl.getMock();
// Gets additional call(s) from TransactionControl
ptm.getTransaction(txatt);
ptmControl.setReturnValue(status, 1);
if (shouldRollback) {
ptm.rollback(status);
}
else {
ptm.commit(status);
}
TransactionSystemException tex = new TransactionSystemException("system exception");
if (rollbackException) {
ptmControl.setThrowable(tex, 1);
}
else {
ptmControl.setVoidCallable(1);
}
ptmControl.replay();
TestBean tb = new TestBean();
ITestBean itb = (ITestBean) advised(tb, ptm, tas);
try {
itb.exceptional(ex);
fail("Should have thrown exception");
}
catch (Throwable t) {
if (rollbackException) {
assertEquals("Caught wrong exception", tex, t );
}
else {
assertEquals("Caught wrong exception", ex, t);
}
}
ptmControl.verify();
}
/**
* Test that TransactionStatus.setRollbackOnly works.
*/
public void testProgrammaticRollback() throws Exception {
TransactionAttribute txatt = new DefaultTransactionAttribute();
Method m = getNameMethod;
MapTransactionAttributeSource tas = new MapTransactionAttributeSource();
tas.register(m, txatt);
TransactionStatus status = transactionStatusForNewTransaction();
MockControl ptmControl = MockControl.createControl(PlatformTransactionManager.class);
PlatformTransactionManager ptm = (PlatformTransactionManager) ptmControl.getMock();
ptm.getTransaction(txatt);
ptmControl.setReturnValue(status, 1);
ptm.commit(status);
ptmControl.setVoidCallable(1);
ptmControl.replay();
final String name = "jenny";
TestBean tb = new TestBean() {
public String getName() {
TransactionStatus txStatus = TransactionInterceptor.currentTransactionStatus();
txStatus.setRollbackOnly();
return name;
}
};
ITestBean itb = (ITestBean) advised(tb, ptm, tas);
// verification!?
assertTrue(name.equals(itb.getName()));
ptmControl.verify();
}
/**
* @return a TransactionStatus object configured for a new transaction
*/
private TransactionStatus transactionStatusForNewTransaction() {
MockControl statusControl = MockControl.createControl(TransactionStatus.class);
return (TransactionStatus) statusControl.getMock();
}
/**
* Simulate a transaction infrastructure failure.
* Shouldn't invoke target method.
*/
public void testCannotCreateTransaction() throws Exception {
TransactionAttribute txatt = new DefaultTransactionAttribute();
Method m = getNameMethod;
MapTransactionAttributeSource tas = new MapTransactionAttributeSource();
tas.register(m, txatt);
MockControl ptmControl = MockControl.createControl(PlatformTransactionManager.class);
PlatformTransactionManager ptm = (PlatformTransactionManager) ptmControl.getMock();
// Expect a transaction
ptm.getTransaction(txatt);
CannotCreateTransactionException ex = new CannotCreateTransactionException("foobar", null);
ptmControl.setThrowable(ex);
ptmControl.replay();
TestBean tb = new TestBean() {
public String getName() {
throw new UnsupportedOperationException(
"Shouldn't have invoked target method when couldn't create transaction for transactional method");
}
};
ITestBean itb = (ITestBean) advised(tb, ptm, tas);
try {
itb.getName();
fail("Shouldn't have invoked method");
}
catch (CannotCreateTransactionException thrown) {
assertTrue(thrown == ex);
}
ptmControl.verify();
}
/**
* Simulate failure of the underlying transaction infrastructure to commit.
* Check that the target method was invoked, but that the transaction
* infrastructure exception was thrown to the client
*/
public void testCannotCommitTransaction() throws Exception {
TransactionAttribute txatt = new DefaultTransactionAttribute();
Method m = setNameMethod;
MapTransactionAttributeSource tas = new MapTransactionAttributeSource();
tas.register(m, txatt);
Method m2 = getNameMethod;
// No attributes for m2
MockControl ptmControl = MockControl.createControl(PlatformTransactionManager.class);
PlatformTransactionManager ptm = (PlatformTransactionManager) ptmControl.getMock();
TransactionStatus status = transactionStatusForNewTransaction();
ptm.getTransaction(txatt);
ptmControl.setReturnValue(status);
UnexpectedRollbackException ex = new UnexpectedRollbackException("foobar", null);
ptm.commit(status);
ptmControl.setThrowable(ex);
ptmControl.replay();
TestBean tb = new TestBean();
ITestBean itb = (ITestBean) advised(tb, ptm, tas);
String name = "new name";
try {
itb.setName(name);
fail("Shouldn't have succeeded");
}
catch (UnexpectedRollbackException thrown) {
assertTrue(thrown == ex);
}
// Should have invoked target and changed name
assertTrue(itb.getName() == name);
ptmControl.verify();
}
protected void checkTransactionStatus(boolean expected) {
try {
TransactionInterceptor.currentTransactionStatus();
if (!expected) {
fail("Should have thrown NoTransactionException");
}
}
catch (NoTransactionException ex) {
if (expected) {
fail("Should have current TransactionStatus");
}
}
}
protected Object advised(
Object target, PlatformTransactionManager ptm, TransactionAttributeSource[] tas) throws Exception {
return advised(target, ptm, new CompositeTransactionAttributeSource(tas));
}
/**
* Subclasses must implement this to create an advised object based on the
* given target. In the case of AspectJ, the advised object will already
* have been created, as there's no distinction between target and proxy.
* In the case of Spring's own AOP framework, a proxy must be created
* using a suitably configured transaction interceptor
* @param target target if there's a distinct target. If not (AspectJ),
* return target.
* @return transactional advised object
*/
protected abstract Object advised(
Object target, PlatformTransactionManager ptm, TransactionAttributeSource tas) throws Exception;
}

View File

@@ -0,0 +1,226 @@
/*
* Copyright 2002-2010 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.transaction.interceptor;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;
import junit.framework.TestCase;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.easymock.MockControl;
import org.springframework.aop.support.AopUtils;
import org.springframework.aop.support.StaticMethodMatcherPointcut;
import org.springframework.aop.target.HotSwappableTargetSource;
import org.springframework.beans.DerivedTestBean;
import org.springframework.beans.FatalBeanException;
import org.springframework.beans.ITestBean;
import org.springframework.beans.TestBean;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.transaction.CallCountingTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.TransactionStatus;
/**
* Test cases for AOP transaction management.
*
* @author Rod Johnson
* @since 23.04.2003
*/
public class BeanFactoryTransactionTests extends TestCase {
private XmlBeanFactory factory;
public void setUp() {
this.factory = new XmlBeanFactory(new ClassPathResource("transactionalBeanFactory.xml", getClass()));
}
public void testGetsAreNotTransactionalWithProxyFactory1() throws NoSuchMethodException {
ITestBean testBean = (ITestBean) factory.getBean("proxyFactory1");
assertTrue("testBean is a dynamic proxy", Proxy.isProxyClass(testBean.getClass()));
doTestGetsAreNotTransactional(testBean);
}
public void testGetsAreNotTransactionalWithProxyFactory2DynamicProxy() throws NoSuchMethodException {
this.factory.preInstantiateSingletons();
ITestBean testBean = (ITestBean) factory.getBean("proxyFactory2DynamicProxy");
assertTrue("testBean is a dynamic proxy", Proxy.isProxyClass(testBean.getClass()));
doTestGetsAreNotTransactional(testBean);
}
public void testGetsAreNotTransactionalWithProxyFactory2Cglib() throws NoSuchMethodException {
ITestBean testBean = (ITestBean) factory.getBean("proxyFactory2Cglib");
assertTrue("testBean is CGLIB advised", AopUtils.isCglibProxy(testBean));
doTestGetsAreNotTransactional(testBean);
}
public void testProxyFactory2Lazy() throws NoSuchMethodException {
ITestBean testBean = (ITestBean) factory.getBean("proxyFactory2Lazy");
assertFalse(factory.containsSingleton("target"));
assertEquals(666, testBean.getAge());
assertTrue(factory.containsSingleton("target"));
}
public void testCglibTransactionProxyImplementsNoInterfaces() throws NoSuchMethodException {
ImplementsNoInterfaces ini = (ImplementsNoInterfaces) factory.getBean("cglibNoInterfaces");
assertTrue("testBean is CGLIB advised", AopUtils.isCglibProxy(ini));
String newName = "Gordon";
// Install facade
CallCountingTransactionManager ptm = new CallCountingTransactionManager();
PlatformTransactionManagerFacade.delegate = ptm;
ini.setName(newName);
assertEquals(newName, ini.getName());
assertEquals(2, ptm.commits);
}
public void testGetsAreNotTransactionalWithProxyFactory3() throws NoSuchMethodException {
ITestBean testBean = (ITestBean) factory.getBean("proxyFactory3");
assertTrue("testBean is a full proxy", testBean instanceof DerivedTestBean);
InvocationCounterPointcut txnCounter = (InvocationCounterPointcut) factory.getBean("txnInvocationCounterPointcut");
InvocationCounterInterceptor preCounter = (InvocationCounterInterceptor) factory.getBean("preInvocationCounterInterceptor");
InvocationCounterInterceptor postCounter = (InvocationCounterInterceptor) factory.getBean("postInvocationCounterInterceptor");
txnCounter.counter = 0;
preCounter.counter = 0;
postCounter.counter = 0;
doTestGetsAreNotTransactional(testBean);
// Can't assert it's equal to 4 as the pointcut may be optimized and only invoked once
assertTrue(0 < txnCounter.counter && txnCounter.counter <= 4);
assertEquals(4, preCounter.counter);
assertEquals(4, postCounter.counter);
}
private void doTestGetsAreNotTransactional(final ITestBean testBean) {
// Install facade
MockControl ptmControl = MockControl.createControl(PlatformTransactionManager.class);
PlatformTransactionManager ptm = (PlatformTransactionManager) ptmControl.getMock();
// Expect no methods
ptmControl.replay();
PlatformTransactionManagerFacade.delegate = ptm;
assertTrue("Age should not be " + testBean.getAge(), testBean.getAge() == 666);
// Check no calls
ptmControl.verify();
// Install facade expecting a call
MockControl statusControl = MockControl.createControl(TransactionStatus.class);
final TransactionStatus ts = (TransactionStatus) statusControl.getMock();
ptm = new PlatformTransactionManager() {
private boolean invoked;
public TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
if (invoked) {
throw new IllegalStateException("getTransaction should not get invoked more than once");
}
invoked = true;
System.out.println(definition.getName());
if (!((definition.getName().indexOf(TestBean.class.getName()) != -1) &&
(definition.getName().indexOf("setAge") != -1))) {
throw new IllegalStateException(
"transaction name should contain class and method name: " + definition.getName());
}
return ts;
}
public void commit(TransactionStatus status) throws TransactionException {
assertTrue(status == ts);
}
public void rollback(TransactionStatus status) throws TransactionException {
throw new IllegalStateException("rollback should not get invoked");
}
};
PlatformTransactionManagerFacade.delegate = ptm;
// TODO same as old age to avoid ordering effect for now
int age = 666;
testBean.setAge(age);
assertTrue(testBean.getAge() == age);
ptmControl.verify();
}
public void testGetBeansOfTypeWithAbstract() {
Map beansOfType = factory.getBeansOfType(ITestBean.class, true, true);
}
/**
* Check that we fail gracefully if the user doesn't set any transaction attributes.
*/
public void testNoTransactionAttributeSource() {
try {
XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("noTransactionAttributeSource.xml", getClass()));
ITestBean testBean = (ITestBean) bf.getBean("noTransactionAttributeSource");
fail("Should require TransactionAttributeSource to be set");
}
catch (FatalBeanException ex) {
// Ok
}
}
/**
* Test that we can set the target to a dynamic TargetSource.
*/
public void testDynamicTargetSource() throws NoSuchMethodException {
// Install facade
CallCountingTransactionManager txMan = new CallCountingTransactionManager();
PlatformTransactionManagerFacade.delegate = txMan;
TestBean tb = (TestBean) factory.getBean("hotSwapped");
assertEquals(666, tb.getAge());
int newAge = 557;
tb.setAge(newAge);
assertEquals(newAge, tb.getAge());
TestBean target2 = new TestBean();
target2.setAge(65);
HotSwappableTargetSource ts = (HotSwappableTargetSource) factory.getBean("swapper");
ts.swap(target2);
assertEquals(target2.getAge(), tb.getAge());
tb.setAge(newAge);
assertEquals(newAge, target2.getAge());
assertEquals(0, txMan.inflight);
assertEquals(2, txMan.commits);
assertEquals(0, txMan.rollbacks);
}
public static class InvocationCounterPointcut extends StaticMethodMatcherPointcut {
int counter = 0;
public boolean matches(Method method, Class clazz) {
counter++;
return true;
}
}
public static class InvocationCounterInterceptor implements MethodInterceptor {
int counter = 0;
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
counter++;
return methodInvocation.proceed();
}
}
}

View File

@@ -0,0 +1,43 @@
/*
* 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.transaction.interceptor;
import org.springframework.beans.TestBean;
/**
* Test for CGLIB proxying that implements no interfaces
* and has one dependency.
*
* @author Rod Johnson
*/
public class ImplementsNoInterfaces {
private TestBean testBean;
public void setDependency(TestBean testBean) {
this.testBean = testBean;
}
public String getName() {
return testBean.getName();
}
public void setName(String name) {
testBean.setName(name);
}
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright 2002-2010 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.transaction.interceptor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
/**
* Inherits fallback behavior from AbstractFallbackTransactionAttributeSource.
*
* @author Rod Johnson
* @author Juergen Hoeller
*/
public class MapTransactionAttributeSource extends AbstractFallbackTransactionAttributeSource {
private final Map<Object, TransactionAttribute> attributeMap = new HashMap<Object, TransactionAttribute>();
public void register(Method method, TransactionAttribute txAtt) {
this.attributeMap.put(method, txAtt);
}
public void register(Class clazz, TransactionAttribute txAtt) {
this.attributeMap.put(clazz, txAtt);
}
protected TransactionAttribute findTransactionAttribute(Method method) {
return this.attributeMap.get(method);
}
protected TransactionAttribute findTransactionAttribute(Class clazz) {
return this.attributeMap.get(clazz);
}
}

View File

@@ -0,0 +1,31 @@
/*
* 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.transaction.interceptor;
import org.springframework.core.NestedRuntimeException;
/**
* An example {@link RuntimeException} for use in testing rollback rules.
*
* @author Chris Beams
*/
@SuppressWarnings("serial")
class MyRuntimeException extends NestedRuntimeException {
public MyRuntimeException(String msg) {
super(msg);
}
}

View File

@@ -0,0 +1,52 @@
/*
* 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.transaction.interceptor;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
/**
* Used for testing only (for example, when we must replace the
* behavior of a PlatformTransactionManager bean we don't have access to).
*
* <p>Allows behavior of an entire class to change with static delegate change.
* Not multi-threaded.
*
* @author Rod Johnson
* @since 26.04.2003
*/
public class PlatformTransactionManagerFacade implements PlatformTransactionManager {
/**
* This member can be changed to change behavior class-wide.
*/
public static PlatformTransactionManager delegate;
public TransactionStatus getTransaction(TransactionDefinition definition) {
return delegate.getTransaction(definition);
}
public void commit(TransactionStatus status) {
delegate.commit(status);
}
public void rollback(TransactionStatus status) {
delegate.rollback(status);
}
}

View File

@@ -0,0 +1,94 @@
/*
* 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.transaction.interceptor;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertThat;
import java.io.IOException;
import junit.framework.TestCase;
import org.springframework.beans.FatalBeanException;
/**
* Unit tests for the {@link RollbackRuleAttribute} class.
*
* @author Rod Johnson
* @author Rick Evans
* @author Chris Beams
* @since 09.04.2003
*/
public class RollbackRuleTests extends TestCase {
public void testFoundImmediatelyWithString() {
RollbackRuleAttribute rr = new RollbackRuleAttribute(java.lang.Exception.class.getName());
assertTrue(rr.getDepth(new Exception()) == 0);
}
public void testFoundImmediatelyWithClass() {
RollbackRuleAttribute rr = new RollbackRuleAttribute(Exception.class);
assertTrue(rr.getDepth(new Exception()) == 0);
}
public void testNotFound() {
RollbackRuleAttribute rr = new RollbackRuleAttribute(java.io.IOException.class.getName());
assertTrue(rr.getDepth(new MyRuntimeException("")) == -1);
}
public void testAncestry() {
RollbackRuleAttribute rr = new RollbackRuleAttribute(java.lang.Exception.class.getName());
// Exception -> Runtime -> NestedRuntime -> MyRuntimeException
assertThat(rr.getDepth(new MyRuntimeException("")), equalTo(3));
}
public void testAlwaysTrueForThrowable() {
RollbackRuleAttribute rr = new RollbackRuleAttribute(java.lang.Throwable.class.getName());
assertTrue(rr.getDepth(new MyRuntimeException("")) > 0);
assertTrue(rr.getDepth(new IOException()) > 0);
assertTrue(rr.getDepth(new FatalBeanException(null,null)) > 0);
assertTrue(rr.getDepth(new RuntimeException()) > 0);
}
public void testCtorArgMustBeAThrowableClassWithNonThrowableType() {
try {
new RollbackRuleAttribute(StringBuffer.class);
fail("Cannot construct a RollbackRuleAttribute with a non-Throwable type");
}
catch (IllegalArgumentException expected) {
}
}
public void testCtorArgMustBeAThrowableClassWithNullThrowableType() {
try {
new RollbackRuleAttribute((Class) null);
fail("Cannot construct a RollbackRuleAttribute with a null-Throwable type");
}
catch (IllegalArgumentException expected) {
}
}
public void testCtorArgExceptionStringNameVersionWithNull() {
try {
new RollbackRuleAttribute((String) null);
fail("Cannot construct a RollbackRuleAttribute with a null-Throwable type");
}
catch (IllegalArgumentException expected) {
}
}
}

View File

@@ -0,0 +1,173 @@
/*
* 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.transaction.interceptor;
import static org.junit.Assert.*;
import java.io.IOException;
import java.rmi.RemoteException;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import org.junit.Test;
import org.springframework.transaction.TransactionDefinition;
/**
* @author Rod Johnson
* @author Juergen Hoeller
* @author Rick Evans
* @author Chris Beams
* @since 09.04.2003
*/
public class RuleBasedTransactionAttributeTests {
@Test
public void testDefaultRule() {
RuleBasedTransactionAttribute rta = new RuleBasedTransactionAttribute();
assertTrue(rta.rollbackOn(new RuntimeException()));
assertTrue(rta.rollbackOn(new MyRuntimeException("")));
assertFalse(rta.rollbackOn(new Exception()));
assertFalse(rta.rollbackOn(new IOException()));
}
/**
* Test one checked exception that should roll back.
*/
@Test
public void testRuleForRollbackOnChecked() {
List<RollbackRuleAttribute> list = new LinkedList<RollbackRuleAttribute>();
list.add(new RollbackRuleAttribute(IOException.class.getName()));
RuleBasedTransactionAttribute rta = new RuleBasedTransactionAttribute(TransactionDefinition.PROPAGATION_REQUIRED, list);
assertTrue(rta.rollbackOn(new RuntimeException()));
assertTrue(rta.rollbackOn(new MyRuntimeException("")));
assertFalse(rta.rollbackOn(new Exception()));
// Check that default behaviour is overridden
assertTrue(rta.rollbackOn(new IOException()));
}
@Test
public void testRuleForCommitOnUnchecked() {
List<RollbackRuleAttribute> list = new LinkedList<RollbackRuleAttribute>();
list.add(new NoRollbackRuleAttribute(MyRuntimeException.class.getName()));
list.add(new RollbackRuleAttribute(IOException.class.getName()));
RuleBasedTransactionAttribute rta = new RuleBasedTransactionAttribute(TransactionDefinition.PROPAGATION_REQUIRED, list);
assertTrue(rta.rollbackOn(new RuntimeException()));
// Check default behaviour is overridden
assertFalse(rta.rollbackOn(new MyRuntimeException("")));
assertFalse(rta.rollbackOn(new Exception()));
// Check that default behaviour is overridden
assertTrue(rta.rollbackOn(new IOException()));
}
@Test
public void testRuleForSelectiveRollbackOnCheckedWithString() {
List<RollbackRuleAttribute> l = new LinkedList<RollbackRuleAttribute>();
l.add(new RollbackRuleAttribute(java.rmi.RemoteException.class.getName()));
RuleBasedTransactionAttribute rta = new RuleBasedTransactionAttribute(TransactionDefinition.PROPAGATION_REQUIRED, l);
doTestRuleForSelectiveRollbackOnChecked(rta);
}
@Test
public void testRuleForSelectiveRollbackOnCheckedWithClass() {
List<RollbackRuleAttribute> l = Collections.singletonList(new RollbackRuleAttribute(RemoteException.class));
RuleBasedTransactionAttribute rta = new RuleBasedTransactionAttribute(TransactionDefinition.PROPAGATION_REQUIRED, l);
doTestRuleForSelectiveRollbackOnChecked(rta);
}
private void doTestRuleForSelectiveRollbackOnChecked(RuleBasedTransactionAttribute rta) {
assertTrue(rta.rollbackOn(new RuntimeException()));
// Check default behaviour is overridden
assertFalse(rta.rollbackOn(new Exception()));
// Check that default behaviour is overridden
assertTrue(rta.rollbackOn(new RemoteException()));
}
/**
* Check that a rule can cause commit on a IOException
* when Exception prompts a rollback.
*/
@Test
public void testRuleForCommitOnSubclassOfChecked() {
List<RollbackRuleAttribute> list = new LinkedList<RollbackRuleAttribute>();
// Note that it's important to ensure that we have this as
// a FQN: otherwise it will match everything!
list.add(new RollbackRuleAttribute("java.lang.Exception"));
list.add(new NoRollbackRuleAttribute("IOException"));
RuleBasedTransactionAttribute rta = new RuleBasedTransactionAttribute(TransactionDefinition.PROPAGATION_REQUIRED, list);
assertTrue(rta.rollbackOn(new RuntimeException()));
assertTrue(rta.rollbackOn(new Exception()));
// Check that default behaviour is overridden
assertFalse(rta.rollbackOn(new IOException()));
}
@Test
public void testRollbackNever() {
List<RollbackRuleAttribute> list = new LinkedList<RollbackRuleAttribute>();
list.add(new NoRollbackRuleAttribute("Throwable"));
RuleBasedTransactionAttribute rta = new RuleBasedTransactionAttribute(TransactionDefinition.PROPAGATION_REQUIRED, list);
assertFalse(rta.rollbackOn(new Throwable()));
assertFalse(rta.rollbackOn(new RuntimeException()));
assertFalse(rta.rollbackOn(new MyRuntimeException("")));
assertFalse(rta.rollbackOn(new Exception()));
assertFalse(rta.rollbackOn(new IOException()));
}
@Test
public void testToStringMatchesEditor() {
List<RollbackRuleAttribute> list = new LinkedList<RollbackRuleAttribute>();
list.add(new NoRollbackRuleAttribute("Throwable"));
RuleBasedTransactionAttribute rta = new RuleBasedTransactionAttribute(TransactionDefinition.PROPAGATION_REQUIRED, list);
TransactionAttributeEditor tae = new TransactionAttributeEditor();
tae.setAsText(rta.toString());
rta = (RuleBasedTransactionAttribute) tae.getValue();
assertFalse(rta.rollbackOn(new Throwable()));
assertFalse(rta.rollbackOn(new RuntimeException()));
assertFalse(rta.rollbackOn(new MyRuntimeException("")));
assertFalse(rta.rollbackOn(new Exception()));
assertFalse(rta.rollbackOn(new IOException()));
}
/**
* See <a href="http://forum.springframework.org/showthread.php?t=41350">this forum post</a>.
*/
@Test
public void testConflictingRulesToDetermineExactContract() {
List<RollbackRuleAttribute> list = new LinkedList<RollbackRuleAttribute>();
list.add(new NoRollbackRuleAttribute(MyBusinessWarningException.class));
list.add(new RollbackRuleAttribute(MyBusinessException.class));
RuleBasedTransactionAttribute rta = new RuleBasedTransactionAttribute(TransactionDefinition.PROPAGATION_REQUIRED, list);
assertTrue(rta.rollbackOn(new MyBusinessException()));
assertFalse(rta.rollbackOn(new MyBusinessWarningException()));
}
@SuppressWarnings("serial")
private static class MyBusinessException extends Exception {}
@SuppressWarnings("serial")
private static final class MyBusinessWarningException extends MyBusinessException {}
}

View File

@@ -0,0 +1,175 @@
/*
* 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.transaction.interceptor;
import static org.junit.Assert.*;
import java.io.IOException;
import org.junit.Test;
import org.springframework.transaction.TransactionDefinition;
/**
* Tests to check conversion from String to TransactionAttribute.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @author Chris Beams
* @since 26.04.2003
*/
public class TransactionAttributeEditorTests {
@Test
public void testNull() {
TransactionAttributeEditor pe = new TransactionAttributeEditor();
pe.setAsText(null);
TransactionAttribute ta = (TransactionAttribute) pe.getValue();
assertTrue(ta == null);
}
@Test
public void testEmptyString() {
TransactionAttributeEditor pe = new TransactionAttributeEditor();
pe.setAsText("");
TransactionAttribute ta = (TransactionAttribute) pe.getValue();
assertTrue(ta == null);
}
@Test
public void testValidPropagationCodeOnly() {
TransactionAttributeEditor pe = new TransactionAttributeEditor();
pe.setAsText("PROPAGATION_REQUIRED");
TransactionAttribute ta = (TransactionAttribute) pe.getValue();
assertTrue(ta != null);
assertTrue(ta.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED);
assertTrue(ta.getIsolationLevel() == TransactionDefinition.ISOLATION_DEFAULT);
assertTrue(!ta.isReadOnly());
}
@Test(expected=IllegalArgumentException.class)
public void testInvalidPropagationCodeOnly() {
TransactionAttributeEditor pe = new TransactionAttributeEditor();
// should have failed with bogus propagation code
pe.setAsText("XXPROPAGATION_REQUIRED");
}
@Test
public void testValidPropagationCodeAndIsolationCode() {
TransactionAttributeEditor pe = new TransactionAttributeEditor();
pe.setAsText("PROPAGATION_REQUIRED, ISOLATION_READ_UNCOMMITTED");
TransactionAttribute ta = (TransactionAttribute) pe.getValue();
assertTrue(ta != null);
assertTrue(ta.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED);
assertTrue(ta.getIsolationLevel() == TransactionDefinition.ISOLATION_READ_UNCOMMITTED);
}
@Test(expected=IllegalArgumentException.class)
public void testValidPropagationAndIsolationCodesAndInvalidRollbackRule() {
TransactionAttributeEditor pe = new TransactionAttributeEditor();
// should fail with bogus rollback rule
pe.setAsText("PROPAGATION_REQUIRED,ISOLATION_READ_UNCOMMITTED,XXX");
}
@Test
public void testValidPropagationCodeAndIsolationCodeAndRollbackRules1() {
TransactionAttributeEditor pe = new TransactionAttributeEditor();
pe.setAsText("PROPAGATION_MANDATORY,ISOLATION_REPEATABLE_READ,timeout_10,-IOException,+MyRuntimeException");
TransactionAttribute ta = (TransactionAttribute) pe.getValue();
assertNotNull(ta);
assertEquals(ta.getPropagationBehavior(), TransactionDefinition.PROPAGATION_MANDATORY);
assertEquals(ta.getIsolationLevel(), TransactionDefinition.ISOLATION_REPEATABLE_READ);
assertEquals(ta.getTimeout(), 10);
assertFalse(ta.isReadOnly());
assertTrue(ta.rollbackOn(new RuntimeException()));
assertFalse(ta.rollbackOn(new Exception()));
// Check for our bizarre customized rollback rules
assertTrue(ta.rollbackOn(new IOException()));
assertTrue(!ta.rollbackOn(new MyRuntimeException("")));
}
@Test
public void testValidPropagationCodeAndIsolationCodeAndRollbackRules2() {
TransactionAttributeEditor pe = new TransactionAttributeEditor();
pe.setAsText("+IOException,readOnly,ISOLATION_READ_COMMITTED,-MyRuntimeException,PROPAGATION_SUPPORTS");
TransactionAttribute ta = (TransactionAttribute) pe.getValue();
assertNotNull(ta);
assertEquals(ta.getPropagationBehavior(), TransactionDefinition.PROPAGATION_SUPPORTS);
assertEquals(ta.getIsolationLevel(), TransactionDefinition.ISOLATION_READ_COMMITTED);
assertEquals(ta.getTimeout(), TransactionDefinition.TIMEOUT_DEFAULT);
assertTrue(ta.isReadOnly());
assertTrue(ta.rollbackOn(new RuntimeException()));
assertFalse(ta.rollbackOn(new Exception()));
// Check for our bizarre customized rollback rules
assertFalse(ta.rollbackOn(new IOException()));
assertTrue(ta.rollbackOn(new MyRuntimeException("")));
}
@Test
public void testDefaultTransactionAttributeToString() {
DefaultTransactionAttribute source = new DefaultTransactionAttribute();
source.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS);
source.setIsolationLevel(TransactionDefinition.ISOLATION_REPEATABLE_READ);
source.setTimeout(10);
source.setReadOnly(true);
TransactionAttributeEditor pe = new TransactionAttributeEditor();
pe.setAsText(source.toString());
TransactionAttribute ta = (TransactionAttribute) pe.getValue();
assertEquals(ta, source);
assertEquals(ta.getPropagationBehavior(), TransactionDefinition.PROPAGATION_SUPPORTS);
assertEquals(ta.getIsolationLevel(), TransactionDefinition.ISOLATION_REPEATABLE_READ);
assertEquals(ta.getTimeout(), 10);
assertTrue(ta.isReadOnly());
assertTrue(ta.rollbackOn(new RuntimeException()));
assertFalse(ta.rollbackOn(new Exception()));
source.setTimeout(9);
assertNotSame(ta, source);
source.setTimeout(10);
assertEquals(ta, source);
}
@Test
public void testRuleBasedTransactionAttributeToString() {
RuleBasedTransactionAttribute source = new RuleBasedTransactionAttribute();
source.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS);
source.setIsolationLevel(TransactionDefinition.ISOLATION_REPEATABLE_READ);
source.setTimeout(10);
source.setReadOnly(true);
source.getRollbackRules().add(new RollbackRuleAttribute("IllegalArgumentException"));
source.getRollbackRules().add(new NoRollbackRuleAttribute("IllegalStateException"));
TransactionAttributeEditor pe = new TransactionAttributeEditor();
pe.setAsText(source.toString());
TransactionAttribute ta = (TransactionAttribute) pe.getValue();
assertEquals(ta, source);
assertEquals(ta.getPropagationBehavior(), TransactionDefinition.PROPAGATION_SUPPORTS);
assertEquals(ta.getIsolationLevel(), TransactionDefinition.ISOLATION_REPEATABLE_READ);
assertEquals(ta.getTimeout(), 10);
assertTrue(ta.isReadOnly());
assertTrue(ta.rollbackOn(new IllegalArgumentException()));
assertFalse(ta.rollbackOn(new IllegalStateException()));
source.getRollbackRules().clear();
assertNotSame(ta, source);
source.getRollbackRules().add(new RollbackRuleAttribute("IllegalArgumentException"));
source.getRollbackRules().add(new NoRollbackRuleAttribute("IllegalStateException"));
assertEquals(ta, source);
}
}

View File

@@ -0,0 +1,42 @@
/*
* 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.transaction.interceptor;
import java.util.Properties;
import org.springframework.util.SerializationTestUtils;
import junit.framework.TestCase;
/**
*
* @author Rod Johnson
*/
public class TransactionAttributeSourceAdvisorTests extends TestCase {
public TransactionAttributeSourceAdvisorTests(String s) {
super(s);
}
public void testSerializability() throws Exception {
TransactionInterceptor ti = new TransactionInterceptor();
ti.setTransactionAttributes(new Properties());
TransactionAttributeSourceAdvisor tas = new TransactionAttributeSourceAdvisor(ti);
SerializationTestUtils.serializeAndDeserialize(tas);
}
}

View File

@@ -0,0 +1,117 @@
/*
* 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.transaction.interceptor;
import java.lang.reflect.Method;
import junit.framework.TestCase;
import org.springframework.transaction.TransactionDefinition;
/**
* Format is
* <code>FQN.Method=tx attribute representation</code>
*
* @author Rod Johnson
* @since 26.04.2003
*/
public class TransactionAttributeSourceEditorTests extends TestCase {
public void testNull() throws Exception {
TransactionAttributeSourceEditor pe = new TransactionAttributeSourceEditor();
pe.setAsText(null);
TransactionAttributeSource tas = (TransactionAttributeSource) pe.getValue();
Method m = Object.class.getMethod("hashCode", (Class[]) null);
assertTrue(tas.getTransactionAttribute(m, null) == null);
}
public void testInvalid() throws Exception {
TransactionAttributeSourceEditor pe = new TransactionAttributeSourceEditor();
try {
pe.setAsText("foo=bar");
fail();
}
catch (IllegalArgumentException ex) {
// Ok
}
}
public void testMatchesSpecific() throws Exception {
TransactionAttributeSourceEditor pe = new TransactionAttributeSourceEditor();
// TODO need FQN?
pe.setAsText(
"java.lang.Object.hashCode=PROPAGATION_REQUIRED\n" +
"java.lang.Object.equals=PROPAGATION_MANDATORY\n" +
"java.lang.Object.*it=PROPAGATION_SUPPORTS\n" +
"java.lang.Object.notify=PROPAGATION_SUPPORTS\n" +
"java.lang.Object.not*=PROPAGATION_REQUIRED");
TransactionAttributeSource tas = (TransactionAttributeSource) pe.getValue();
checkTransactionProperties(tas, Object.class.getMethod("hashCode", (Class[]) null),
TransactionDefinition.PROPAGATION_REQUIRED);
checkTransactionProperties(tas, Object.class.getMethod("equals", new Class[] { Object.class }),
TransactionDefinition.PROPAGATION_MANDATORY);
checkTransactionProperties(tas, Object.class.getMethod("wait", (Class[]) null),
TransactionDefinition.PROPAGATION_SUPPORTS);
checkTransactionProperties(tas, Object.class.getMethod("wait", new Class[] { long.class }),
TransactionDefinition.PROPAGATION_SUPPORTS);
checkTransactionProperties(tas, Object.class.getMethod("wait", new Class[] { long.class, int.class }),
TransactionDefinition.PROPAGATION_SUPPORTS);
checkTransactionProperties(tas, Object.class.getMethod("notify", (Class[]) null),
TransactionDefinition.PROPAGATION_SUPPORTS);
checkTransactionProperties(tas, Object.class.getMethod("notifyAll", (Class[]) null),
TransactionDefinition.PROPAGATION_REQUIRED);
checkTransactionProperties(tas, Object.class.getMethod("toString", (Class[]) null), -1);
}
public void testMatchesAll() throws Exception {
TransactionAttributeSourceEditor pe = new TransactionAttributeSourceEditor();
pe.setAsText("java.lang.Object.*=PROPAGATION_REQUIRED");
TransactionAttributeSource tas = (TransactionAttributeSource) pe.getValue();
checkTransactionProperties(tas, Object.class.getMethod("hashCode", (Class[]) null),
TransactionDefinition.PROPAGATION_REQUIRED);
checkTransactionProperties(tas, Object.class.getMethod("equals", new Class[] { Object.class }),
TransactionDefinition.PROPAGATION_REQUIRED);
checkTransactionProperties(tas, Object.class.getMethod("wait", (Class[]) null),
TransactionDefinition.PROPAGATION_REQUIRED);
checkTransactionProperties(tas, Object.class.getMethod("wait", new Class[] { long.class }),
TransactionDefinition.PROPAGATION_REQUIRED);
checkTransactionProperties(tas, Object.class.getMethod("wait", new Class[] { long.class, int.class }),
TransactionDefinition.PROPAGATION_REQUIRED);
checkTransactionProperties(tas, Object.class.getMethod("notify", (Class[]) null),
TransactionDefinition.PROPAGATION_REQUIRED);
checkTransactionProperties(tas, Object.class.getMethod("notifyAll", (Class[]) null),
TransactionDefinition.PROPAGATION_REQUIRED);
checkTransactionProperties(tas, Object.class.getMethod("toString", (Class[]) null),
TransactionDefinition.PROPAGATION_REQUIRED);
}
private void checkTransactionProperties(TransactionAttributeSource tas, Method method, int propagationBehavior) {
TransactionAttribute ta = tas.getTransactionAttribute(method, null);
if (propagationBehavior >= 0) {
assertTrue(ta != null);
assertTrue(ta.getIsolationLevel() == TransactionDefinition.ISOLATION_DEFAULT);
assertTrue(ta.getPropagationBehavior() == propagationBehavior);
}
else {
assertTrue(ta == null);
}
}
}

View File

@@ -0,0 +1,162 @@
/*
* 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.transaction.interceptor;
import static org.junit.Assert.*;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.transaction.TransactionDefinition;
/**
* Unit tests for the various {@link TransactionAttributeSource} implementations.
*
* @author Colin Sampaleanu
* @author Juergen Hoeller
* @author Rick Evans
* @author Chris Beams
* @since 15.10.2003
* @see org.springframework.transaction.interceptor.TransactionProxyFactoryBean
*/
public final class TransactionAttributeSourceTests {
@Test
public void testMatchAlwaysTransactionAttributeSource() throws Exception {
MatchAlwaysTransactionAttributeSource tas = new MatchAlwaysTransactionAttributeSource();
TransactionAttribute ta = tas.getTransactionAttribute(
Object.class.getMethod("hashCode", (Class[]) null), null);
assertNotNull(ta);
assertTrue(TransactionDefinition.PROPAGATION_REQUIRED == ta.getPropagationBehavior());
tas.setTransactionAttribute(new DefaultTransactionAttribute(TransactionDefinition.PROPAGATION_SUPPORTS));
ta = tas.getTransactionAttribute(
IOException.class.getMethod("getMessage", (Class[]) null), IOException.class);
assertNotNull(ta);
assertTrue(TransactionDefinition.PROPAGATION_SUPPORTS == ta.getPropagationBehavior());
}
@SuppressWarnings("unchecked")
@Ignore // no longer works now that setMethodMap has been parameterized
@Test
public void testMethodMapTransactionAttributeSource() throws NoSuchMethodException {
MethodMapTransactionAttributeSource tas = new MethodMapTransactionAttributeSource();
Map methodMap = new HashMap();
methodMap.put(Object.class.getName() + ".hashCode", TransactionDefinition.PROPAGATION_REQUIRED);
methodMap.put(Object.class.getName() + ".toString",
new DefaultTransactionAttribute(TransactionDefinition.PROPAGATION_SUPPORTS));
tas.setMethodMap(methodMap);
tas.afterPropertiesSet();
TransactionAttribute ta = tas.getTransactionAttribute(
Object.class.getMethod("hashCode", (Class[]) null), null);
assertNotNull(ta);
assertEquals(TransactionDefinition.PROPAGATION_REQUIRED, ta.getPropagationBehavior());
ta = tas.getTransactionAttribute(Object.class.getMethod("toString", (Class[]) null), null);
assertNotNull(ta);
assertEquals(TransactionDefinition.PROPAGATION_SUPPORTS, ta.getPropagationBehavior());
}
@SuppressWarnings("unchecked")
@Ignore // no longer works now that setMethodMap has been parameterized
@Test
public void testMethodMapTransactionAttributeSourceWithLazyInit() throws NoSuchMethodException {
MethodMapTransactionAttributeSource tas = new MethodMapTransactionAttributeSource();
Map methodMap = new HashMap();
methodMap.put(Object.class.getName() + ".hashCode", "PROPAGATION_REQUIRED");
methodMap.put(Object.class.getName() + ".toString",
new DefaultTransactionAttribute(TransactionDefinition.PROPAGATION_SUPPORTS));
tas.setMethodMap(methodMap);
TransactionAttribute ta = tas.getTransactionAttribute(
Object.class.getMethod("hashCode", (Class[]) null), null);
assertNotNull(ta);
assertEquals(TransactionDefinition.PROPAGATION_REQUIRED, ta.getPropagationBehavior());
ta = tas.getTransactionAttribute(Object.class.getMethod("toString", (Class[]) null), null);
assertNotNull(ta);
assertEquals(TransactionDefinition.PROPAGATION_SUPPORTS, ta.getPropagationBehavior());
}
@SuppressWarnings("unchecked")
@Ignore // no longer works now that setMethodMap has been parameterized
@Test
public void testNameMatchTransactionAttributeSource() throws NoSuchMethodException {
NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource();
Map methodMap = new HashMap();
methodMap.put("hashCode", "PROPAGATION_REQUIRED");
methodMap.put("toString", new DefaultTransactionAttribute(TransactionDefinition.PROPAGATION_SUPPORTS));
tas.setNameMap(methodMap);
TransactionAttribute ta = tas.getTransactionAttribute(
Object.class.getMethod("hashCode", (Class[]) null), null);
assertNotNull(ta);
assertEquals(TransactionDefinition.PROPAGATION_REQUIRED, ta.getPropagationBehavior());
ta = tas.getTransactionAttribute(Object.class.getMethod("toString", (Class[]) null), null);
assertNotNull(ta);
assertEquals(TransactionDefinition.PROPAGATION_SUPPORTS, ta.getPropagationBehavior());
}
@Test
public void testNameMatchTransactionAttributeSourceWithStarAtStartOfMethodName() throws NoSuchMethodException {
NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource();
Properties attributes = new Properties();
attributes.put("*ashCode", "PROPAGATION_REQUIRED");
tas.setProperties(attributes);
TransactionAttribute ta = tas.getTransactionAttribute(
Object.class.getMethod("hashCode", (Class[]) null), null);
assertNotNull(ta);
assertEquals(TransactionDefinition.PROPAGATION_REQUIRED, ta.getPropagationBehavior());
}
@Test
public void testNameMatchTransactionAttributeSourceWithStarAtEndOfMethodName() throws NoSuchMethodException {
NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource();
Properties attributes = new Properties();
attributes.put("hashCod*", "PROPAGATION_REQUIRED");
tas.setProperties(attributes);
TransactionAttribute ta = tas.getTransactionAttribute(
Object.class.getMethod("hashCode", (Class[]) null), null);
assertNotNull(ta);
assertEquals(TransactionDefinition.PROPAGATION_REQUIRED, ta.getPropagationBehavior());
}
@Test
public void testNameMatchTransactionAttributeSourceMostSpecificMethodNameIsDefinitelyMatched() throws NoSuchMethodException {
NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource();
Properties attributes = new Properties();
attributes.put("*", "PROPAGATION_REQUIRED");
attributes.put("hashCode", "PROPAGATION_MANDATORY");
tas.setProperties(attributes);
TransactionAttribute ta = tas.getTransactionAttribute(
Object.class.getMethod("hashCode", (Class[]) null), null);
assertNotNull(ta);
assertEquals(TransactionDefinition.PROPAGATION_MANDATORY, ta.getPropagationBehavior());
}
@Test
public void testNameMatchTransactionAttributeSourceWithEmptyMethodName() throws NoSuchMethodException {
NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource();
Properties attributes = new Properties();
attributes.put("", "PROPAGATION_MANDATORY");
tas.setProperties(attributes);
TransactionAttribute ta = tas.getTransactionAttribute(
Object.class.getMethod("hashCode", (Class[]) null), null);
assertNull(ta);
}
}

View File

@@ -0,0 +1,126 @@
/*
* 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.transaction.interceptor;
import java.io.Serializable;
import java.util.Properties;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.TransactionStatus;
import org.springframework.util.SerializationTestUtils;
/**
* Mock object based tests for TransactionInterceptor.
*
* @author Rod Johnson
* @since 16.03.2003
*/
public class TransactionInterceptorTests extends AbstractTransactionAspectTests {
protected Object advised(Object target, PlatformTransactionManager ptm, TransactionAttributeSource[] tas) throws Exception {
TransactionInterceptor ti = new TransactionInterceptor();
ti.setTransactionManager(ptm);
ti.setTransactionAttributeSources(tas);
ProxyFactory pf = new ProxyFactory(target);
pf.addAdvice(0, ti);
return pf.getProxy();
}
/**
* Template method to create an advised object given the
* target object and transaction setup.
* Creates a TransactionInterceptor and applies it.
*/
protected Object advised(Object target, PlatformTransactionManager ptm, TransactionAttributeSource tas) {
TransactionInterceptor ti = new TransactionInterceptor();
ti.setTransactionManager(ptm);
assertEquals(ptm, ti.getTransactionManager());
ti.setTransactionAttributeSource(tas);
assertEquals(tas, ti.getTransactionAttributeSource());
ProxyFactory pf = new ProxyFactory(target);
pf.addAdvice(0, ti);
return pf.getProxy();
}
/**
* A TransactionInterceptor should be serializable if its
* PlatformTransactionManager is.
*/
public void testSerializableWithAttributeProperties() throws Exception {
TransactionInterceptor ti = new TransactionInterceptor();
Properties props = new Properties();
props.setProperty("methodName", "PROPAGATION_REQUIRED");
ti.setTransactionAttributes(props);
PlatformTransactionManager ptm = new SerializableTransactionManager();
ti.setTransactionManager(ptm);
ti = (TransactionInterceptor) SerializationTestUtils.serializeAndDeserialize(ti);
// Check that logger survived deserialization
assertNotNull(ti.logger);
assertTrue(ti.getTransactionManager() instanceof SerializableTransactionManager);
assertNotNull(ti.getTransactionAttributeSource());
}
public void testSerializableWithCompositeSource() throws Exception {
NameMatchTransactionAttributeSource tas1 = new NameMatchTransactionAttributeSource();
Properties props = new Properties();
props.setProperty("methodName", "PROPAGATION_REQUIRED");
tas1.setProperties(props);
NameMatchTransactionAttributeSource tas2 = new NameMatchTransactionAttributeSource();
props = new Properties();
props.setProperty("otherMethodName", "PROPAGATION_REQUIRES_NEW");
tas2.setProperties(props);
TransactionInterceptor ti = new TransactionInterceptor();
ti.setTransactionAttributeSources(new TransactionAttributeSource[] {tas1, tas2});
PlatformTransactionManager ptm = new SerializableTransactionManager();
ti.setTransactionManager(ptm);
ti = (TransactionInterceptor) SerializationTestUtils.serializeAndDeserialize(ti);
assertTrue(ti.getTransactionManager() instanceof SerializableTransactionManager);
assertTrue(ti.getTransactionAttributeSource() instanceof CompositeTransactionAttributeSource);
CompositeTransactionAttributeSource ctas = (CompositeTransactionAttributeSource) ti.getTransactionAttributeSource();
assertTrue(ctas.getTransactionAttributeSources()[0] instanceof NameMatchTransactionAttributeSource);
assertTrue(ctas.getTransactionAttributeSources()[1] instanceof NameMatchTransactionAttributeSource);
}
/**
* We won't use this: we just want to know it's serializable.
*/
public static class SerializableTransactionManager implements PlatformTransactionManager, Serializable {
public TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
throw new UnsupportedOperationException();
}
public void commit(TransactionStatus status) throws TransactionException {
throw new UnsupportedOperationException();
}
public void rollback(TransactionStatus status) throws TransactionException {
throw new UnsupportedOperationException();
}
}
}

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<!-- Simple target -->
<bean id="target" class="org.springframework.beans.DerivedTestBean">
<property name="name"><value>custom</value></property>
<property name="age"><value>666</value></property>
</bean>
<bean id="mockMan" class="org.springframework.transaction.interceptor.PlatformTransactionManagerFacade"/>
<!--
Invalid: we need a transaction attribute source
-->
<bean id="noTransactionAttributeSource" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager"><ref local="mockMan"/></property>
<property name="target"><ref local="target"/></property>
</bean>
</beans>

View File

@@ -0,0 +1,137 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="targetDependency" class="org.springframework.beans.TestBean">
<property name="name"><value>dependency</value></property>
</bean>
<!-- Simple target -->
<bean id="target" class="org.springframework.beans.DerivedTestBean" lazy-init="true">
<property name="name"><value>custom</value></property>
<property name="age"><value>666</value></property>
<property name="spouse"><ref local="targetDependency"/></property>
</bean>
<bean id="debugInterceptor" class="org.springframework.aop.interceptor.DebugInterceptor"/>
<bean id="mockMan" class="org.springframework.transaction.interceptor.PlatformTransactionManagerFacade"/>
<bean id="txInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager"><ref local="mockMan"/></property>
<property name="transactionAttributeSource">
<value>
org.springframework.beans.ITestBean.s*=PROPAGATION_MANDATORY
org.springframework.beans.ITestBean.setAg*=PROPAGATION_REQUIRED
org.springframework.beans.ITestBean.set*= PROPAGATION_SUPPORTS , readOnly
</value>
</property>
</bean>
<bean id="proxyFactory1" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>org.springframework.beans.ITestBean</value>
</property>
<property name="interceptorNames">
<list>
<value>txInterceptor</value>
<value>target</value>
</list>
</property>
</bean>
<bean id="baseProxyFactory" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
abstract="true">
<property name="transactionManager"><ref local="mockMan"/></property>
<property name="transactionAttributes">
<props>
<prop key="s*">PROPAGATION_MANDATORY</prop>
<prop key="setAg*"> PROPAGATION_REQUIRED , readOnly </prop>
<prop key="set*">PROPAGATION_SUPPORTS</prop>
</props>
</property>
</bean>
<bean id="proxyFactory2DynamicProxy" parent="baseProxyFactory">
<property name="target"><ref local="target"/></property>
</bean>
<!--
Same as proxyFactory2DynamicProxy but forces the use of CGLIB.
-->
<bean id="proxyFactory2Cglib" parent="baseProxyFactory">
<property name="proxyTargetClass"><value>true</value></property>
<property name="target"><ref local="target"/></property>
</bean>
<bean id="proxyFactory2Lazy" parent="baseProxyFactory">
<property name="target">
<bean class="org.springframework.aop.target.LazyInitTargetSource">
<property name="targetBeanName"><idref local="target"/></property>
</bean>
</property>
</bean>
<bean id="proxyFactory3" parent="baseProxyFactory">
<property name="target"><ref local="target"/></property>
<property name="proxyTargetClass"><value>true</value></property>
<property name="pointcut">
<ref local="txnInvocationCounterPointcut"/>
</property>
<property name="preInterceptors">
<list>
<ref local="preInvocationCounterInterceptor"/>
</list>
</property>
<property name="postInterceptors">
<list>
<ref local="postInvocationCounterInterceptor"/>
</list>
</property>
</bean>
<bean name="cglibNoInterfaces" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager"><ref local="mockMan"/></property>
<property name="target">
<bean class="org.springframework.transaction.interceptor.ImplementsNoInterfaces">
<property name="dependency"><ref local="targetDependency"/></property>
</bean>
</property>
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<!--
The HotSwappableTargetSource is a Type 3 component.
-->
<bean id="swapper" class="org.springframework.aop.target.HotSwappableTargetSource">
<constructor-arg><ref local="target"/></constructor-arg>
</bean>
<bean id="hotSwapped" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager"><ref local="mockMan"/></property>
<!-- Should automatically pick up the target source, rather than simple target -->
<property name="target"><ref local="swapper"/></property>
<property name="transactionAttributes">
<props>
<prop key="s*">PROPAGATION_MANDATORY</prop>
<prop key="setAg*">PROPAGATION_REQUIRED</prop>
<prop key="set*">PROPAGATION_SUPPORTS</prop>
</props>
</property>
<property name="proxyTargetClass"><value>true</value></property>
<property name="optimize"><value>false</value></property>
</bean>
<bean id="txnInvocationCounterPointcut"
class="org.springframework.transaction.interceptor.BeanFactoryTransactionTests$InvocationCounterPointcut"/>
<bean id="preInvocationCounterInterceptor" class="org.springframework.transaction.interceptor.BeanFactoryTransactionTests$InvocationCounterInterceptor"/>
<bean id="postInvocationCounterInterceptor" class="org.springframework.transaction.interceptor.BeanFactoryTransactionTests$InvocationCounterInterceptor"/>
</beans>

View File

@@ -0,0 +1,125 @@
/*
* 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.transaction.jta;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.transaction.Synchronization;
import com.ibm.wsspi.uow.UOWAction;
import com.ibm.wsspi.uow.UOWActionException;
import com.ibm.wsspi.uow.UOWException;
import com.ibm.wsspi.uow.UOWManager;
/**
* @author Juergen Hoeller
*/
public class MockUOWManager implements UOWManager {
private int type = UOW_TYPE_GLOBAL_TRANSACTION;
private boolean joined;
private int timeout;
private boolean rollbackOnly;
private int status = UOW_STATUS_NONE;
private final Map resources = new HashMap();
private final List synchronizations = new LinkedList();
public void runUnderUOW(int type, boolean join, UOWAction action) throws UOWActionException, UOWException {
this.type = type;
this.joined = join;
try {
this.status = UOW_STATUS_ACTIVE;
action.run();
this.status = (this.rollbackOnly ? UOW_STATUS_ROLLEDBACK : UOW_STATUS_COMMITTED);
}
catch (Error err) {
this.status = UOW_STATUS_ROLLEDBACK;
throw err;
}
catch (RuntimeException ex) {
this.status = UOW_STATUS_ROLLEDBACK;
throw ex;
}
catch (Exception ex) {
this.status = UOW_STATUS_ROLLEDBACK;
throw new UOWActionException(ex);
}
}
public int getUOWType() {
return this.type;
}
public boolean getJoined() {
return this.joined;
}
public long getLocalUOWId() {
return 0;
}
public void setUOWTimeout(int uowType, int timeout) {
this.timeout = timeout;
}
public int getUOWTimeout() {
return this.timeout;
}
public void setRollbackOnly() {
this.rollbackOnly = true;
}
public boolean getRollbackOnly() {
return this.rollbackOnly;
}
public void setUOWStatus(int status) {
this.status = status;
}
public int getUOWStatus() {
return this.status;
}
public void putResource(Object key, Object value) {
this.resources.put(key, value);
}
public Object getResource(Object key) throws NullPointerException {
return this.resources.get(key);
}
public void registerInterposedSynchronization(Synchronization sync) {
this.synchronizations.add(sync);
}
public List getSynchronizations() {
return this.synchronizations;
}
}

View File

@@ -0,0 +1,629 @@
/*
* Copyright 2002-2010 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.transaction.jta;
import javax.transaction.RollbackException;
import javax.transaction.Status;
import javax.transaction.UserTransaction;
import com.ibm.wsspi.uow.UOWAction;
import com.ibm.wsspi.uow.UOWException;
import com.ibm.wsspi.uow.UOWManager;
import junit.framework.TestCase;
import org.easymock.MockControl;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.mock.jndi.ExpectedLookupTemplate;
import org.springframework.transaction.IllegalTransactionStateException;
import org.springframework.transaction.NestedTransactionNotSupportedException;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.TransactionSystemException;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionSynchronizationManager;
/**
* @author Juergen Hoeller
*/
public class WebSphereUowTransactionManagerTests extends TestCase {
public void testUowManagerFoundInJndi() {
MockUOWManager manager = new MockUOWManager();
ExpectedLookupTemplate jndiTemplate =
new ExpectedLookupTemplate(WebSphereUowTransactionManager.DEFAULT_UOW_MANAGER_NAME, manager);
WebSphereUowTransactionManager ptm = new WebSphereUowTransactionManager();
ptm.setJndiTemplate(jndiTemplate);
ptm.afterPropertiesSet();
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
assertEquals("result", ptm.execute(definition, new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
return "result";
}
}));
assertEquals(UOWManager.UOW_TYPE_GLOBAL_TRANSACTION, manager.getUOWType());
assertFalse(manager.getJoined());
assertFalse(manager.getRollbackOnly());
}
public void testUowManagerAndUserTransactionFoundInJndi() throws Exception {
MockControl utControl = MockControl.createControl(UserTransaction.class);
UserTransaction ut = (UserTransaction) utControl.getMock();
ut.getStatus();
utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1);
ut.getStatus();
utControl.setReturnValue(Status.STATUS_ACTIVE, 2);
ut.begin();
utControl.setVoidCallable(1);
ut.commit();
utControl.setVoidCallable(1);
utControl.replay();
MockUOWManager manager = new MockUOWManager();
ExpectedLookupTemplate jndiTemplate = new ExpectedLookupTemplate();
jndiTemplate.addObject(WebSphereUowTransactionManager.DEFAULT_USER_TRANSACTION_NAME, ut);
jndiTemplate.addObject(WebSphereUowTransactionManager.DEFAULT_UOW_MANAGER_NAME, manager);
WebSphereUowTransactionManager ptm = new WebSphereUowTransactionManager();
ptm.setJndiTemplate(jndiTemplate);
ptm.afterPropertiesSet();
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
TransactionStatus ts = ptm.getTransaction(definition);
ptm.commit(ts);
assertEquals("result", ptm.execute(definition, new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
return "result";
}
}));
assertEquals(UOWManager.UOW_TYPE_GLOBAL_TRANSACTION, manager.getUOWType());
assertFalse(manager.getJoined());
assertFalse(manager.getRollbackOnly());
}
public void testPropagationMandatoryFailsInCaseOfNoExistingTransaction() {
MockUOWManager manager = new MockUOWManager();
WebSphereUowTransactionManager ptm = new WebSphereUowTransactionManager(manager);
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_MANDATORY);
try {
ptm.execute(definition, new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
return "result";
}
});
fail("Should have thrown IllegalTransactionStateException");
}
catch (IllegalTransactionStateException ex) {
// expected
}
}
public void testNewTransactionSynchronizationUsingPropagationSupports() {
doTestNewTransactionSynchronization(
TransactionDefinition.PROPAGATION_SUPPORTS, WebSphereUowTransactionManager.SYNCHRONIZATION_ALWAYS);
}
public void testNewTransactionSynchronizationUsingPropagationNotSupported() {
doTestNewTransactionSynchronization(
TransactionDefinition.PROPAGATION_NOT_SUPPORTED, WebSphereUowTransactionManager.SYNCHRONIZATION_ALWAYS);
}
public void testNewTransactionSynchronizationUsingPropagationNever() {
doTestNewTransactionSynchronization(
TransactionDefinition.PROPAGATION_NEVER, WebSphereUowTransactionManager.SYNCHRONIZATION_ALWAYS);
}
public void testNewTransactionSynchronizationUsingPropagationSupportsAndSynchOnActual() {
doTestNewTransactionSynchronization(
TransactionDefinition.PROPAGATION_SUPPORTS, WebSphereUowTransactionManager.SYNCHRONIZATION_ON_ACTUAL_TRANSACTION);
}
public void testNewTransactionSynchronizationUsingPropagationNotSupportedAndSynchOnActual() {
doTestNewTransactionSynchronization(
TransactionDefinition.PROPAGATION_NOT_SUPPORTED, WebSphereUowTransactionManager.SYNCHRONIZATION_ON_ACTUAL_TRANSACTION);
}
public void testNewTransactionSynchronizationUsingPropagationNeverAndSynchOnActual() {
doTestNewTransactionSynchronization(
TransactionDefinition.PROPAGATION_NEVER, WebSphereUowTransactionManager.SYNCHRONIZATION_ON_ACTUAL_TRANSACTION);
}
public void testNewTransactionSynchronizationUsingPropagationSupportsAndSynchNever() {
doTestNewTransactionSynchronization(
TransactionDefinition.PROPAGATION_SUPPORTS, WebSphereUowTransactionManager.SYNCHRONIZATION_NEVER);
}
public void testNewTransactionSynchronizationUsingPropagationNotSupportedAndSynchNever() {
doTestNewTransactionSynchronization(
TransactionDefinition.PROPAGATION_NOT_SUPPORTED, WebSphereUowTransactionManager.SYNCHRONIZATION_NEVER);
}
public void testNewTransactionSynchronizationUsingPropagationNeverAndSynchNever() {
doTestNewTransactionSynchronization(
TransactionDefinition.PROPAGATION_NEVER, WebSphereUowTransactionManager.SYNCHRONIZATION_NEVER);
}
private void doTestNewTransactionSynchronization(int propagationBehavior, final int synchMode) {
MockUOWManager manager = new MockUOWManager();
WebSphereUowTransactionManager ptm = new WebSphereUowTransactionManager(manager);
ptm.setTransactionSynchronization(synchMode);
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
definition.setPropagationBehavior(propagationBehavior);
definition.setReadOnly(true);
assertFalse(TransactionSynchronizationManager.isSynchronizationActive());
assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
assertEquals("result", ptm.execute(definition, new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
if (synchMode == WebSphereUowTransactionManager.SYNCHRONIZATION_ALWAYS) {
assertTrue(TransactionSynchronizationManager.isSynchronizationActive());
assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
assertTrue(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
}
else {
assertFalse(TransactionSynchronizationManager.isSynchronizationActive());
assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
}
return "result";
}
}));
assertFalse(TransactionSynchronizationManager.isSynchronizationActive());
assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
assertEquals(0, manager.getUOWTimeout());
assertEquals(UOWManager.UOW_TYPE_LOCAL_TRANSACTION, manager.getUOWType());
assertFalse(manager.getJoined());
assertFalse(manager.getRollbackOnly());
}
public void testNewTransactionWithCommitUsingPropagationRequired() {
doTestNewTransactionWithCommit(
TransactionDefinition.PROPAGATION_REQUIRED, WebSphereUowTransactionManager.SYNCHRONIZATION_ALWAYS);
}
public void testNewTransactionWithCommitUsingPropagationRequiresNew() {
doTestNewTransactionWithCommit(
TransactionDefinition.PROPAGATION_REQUIRES_NEW, WebSphereUowTransactionManager.SYNCHRONIZATION_ALWAYS);
}
public void testNewTransactionWithCommitUsingPropagationNested() {
doTestNewTransactionWithCommit(
TransactionDefinition.PROPAGATION_NESTED, WebSphereUowTransactionManager.SYNCHRONIZATION_ALWAYS);
}
public void testNewTransactionWithCommitUsingPropagationRequiredAndSynchOnActual() {
doTestNewTransactionWithCommit(
TransactionDefinition.PROPAGATION_REQUIRED, WebSphereUowTransactionManager.SYNCHRONIZATION_ON_ACTUAL_TRANSACTION);
}
public void testNewTransactionWithCommitUsingPropagationRequiresNewAndSynchOnActual() {
doTestNewTransactionWithCommit(
TransactionDefinition.PROPAGATION_REQUIRES_NEW, WebSphereUowTransactionManager.SYNCHRONIZATION_ON_ACTUAL_TRANSACTION);
}
public void testNewTransactionWithCommitUsingPropagationNestedAndSynchOnActual() {
doTestNewTransactionWithCommit(
TransactionDefinition.PROPAGATION_NESTED, WebSphereUowTransactionManager.SYNCHRONIZATION_ON_ACTUAL_TRANSACTION);
}
public void testNewTransactionWithCommitUsingPropagationRequiredAndSynchNever() {
doTestNewTransactionWithCommit(
TransactionDefinition.PROPAGATION_REQUIRED, WebSphereUowTransactionManager.SYNCHRONIZATION_NEVER);
}
public void testNewTransactionWithCommitUsingPropagationRequiresNewAndSynchNever() {
doTestNewTransactionWithCommit(
TransactionDefinition.PROPAGATION_REQUIRES_NEW, WebSphereUowTransactionManager.SYNCHRONIZATION_NEVER);
}
public void testNewTransactionWithCommitUsingPropagationNestedAndSynchNever() {
doTestNewTransactionWithCommit(
TransactionDefinition.PROPAGATION_NESTED, WebSphereUowTransactionManager.SYNCHRONIZATION_NEVER);
}
private void doTestNewTransactionWithCommit(int propagationBehavior, final int synchMode) {
MockUOWManager manager = new MockUOWManager();
WebSphereUowTransactionManager ptm = new WebSphereUowTransactionManager(manager);
ptm.setTransactionSynchronization(synchMode);
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
definition.setPropagationBehavior(propagationBehavior);
definition.setReadOnly(true);
assertFalse(TransactionSynchronizationManager.isSynchronizationActive());
assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
assertEquals("result", ptm.execute(definition, new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
if (synchMode != WebSphereUowTransactionManager.SYNCHRONIZATION_NEVER) {
assertTrue(TransactionSynchronizationManager.isSynchronizationActive());
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertTrue(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
}
else {
assertFalse(TransactionSynchronizationManager.isSynchronizationActive());
assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
}
return "result";
}
}));
assertFalse(TransactionSynchronizationManager.isSynchronizationActive());
assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
assertEquals(0, manager.getUOWTimeout());
assertEquals(UOWManager.UOW_TYPE_GLOBAL_TRANSACTION, manager.getUOWType());
assertFalse(manager.getJoined());
assertFalse(manager.getRollbackOnly());
}
public void testNewTransactionWithCommitAndTimeout() {
MockUOWManager manager = new MockUOWManager();
WebSphereUowTransactionManager ptm = new WebSphereUowTransactionManager(manager);
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
definition.setTimeout(10);
definition.setReadOnly(true);
assertFalse(TransactionSynchronizationManager.isSynchronizationActive());
assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
assertEquals("result", ptm.execute(definition, new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
assertTrue(TransactionSynchronizationManager.isSynchronizationActive());
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertTrue(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
return "result";
}
}));
assertFalse(TransactionSynchronizationManager.isSynchronizationActive());
assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
assertEquals(10, manager.getUOWTimeout());
assertEquals(UOWManager.UOW_TYPE_GLOBAL_TRANSACTION, manager.getUOWType());
assertFalse(manager.getJoined());
assertFalse(manager.getRollbackOnly());
}
public void testNewTransactionWithCommitException() {
final RollbackException rex = new RollbackException();
MockUOWManager manager = new MockUOWManager() {
public void runUnderUOW(int type, boolean join, UOWAction action) throws UOWException {
throw new UOWException(rex);
}
};
WebSphereUowTransactionManager ptm = new WebSphereUowTransactionManager(manager);
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
assertFalse(TransactionSynchronizationManager.isSynchronizationActive());
assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
try {
ptm.execute(definition, new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
assertTrue(TransactionSynchronizationManager.isSynchronizationActive());
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
return "result";
}
});
fail("Should have thrown TransactionSystemException");
}
catch (TransactionSystemException ex) {
// expected
assertTrue(ex.getCause() instanceof UOWException);
assertSame(rex, ex.getRootCause());
assertSame(rex, ex.getMostSpecificCause());
}
assertFalse(TransactionSynchronizationManager.isSynchronizationActive());
assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
assertEquals(0, manager.getUOWTimeout());
}
public void testNewTransactionWithRollback() {
MockUOWManager manager = new MockUOWManager();
WebSphereUowTransactionManager ptm = new WebSphereUowTransactionManager(manager);
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
assertFalse(TransactionSynchronizationManager.isSynchronizationActive());
assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
try {
ptm.execute(definition, new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
assertTrue(TransactionSynchronizationManager.isSynchronizationActive());
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
throw new OptimisticLockingFailureException("");
}
});
fail("Should have thrown OptimisticLockingFailureException");
}
catch (OptimisticLockingFailureException ex) {
// expected
}
assertFalse(TransactionSynchronizationManager.isSynchronizationActive());
assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
assertEquals(0, manager.getUOWTimeout());
assertEquals(UOWManager.UOW_TYPE_GLOBAL_TRANSACTION, manager.getUOWType());
assertFalse(manager.getJoined());
assertTrue(manager.getRollbackOnly());
}
public void testNewTransactionWithRollbackOnly() {
MockUOWManager manager = new MockUOWManager();
WebSphereUowTransactionManager ptm = new WebSphereUowTransactionManager(manager);
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
assertFalse(TransactionSynchronizationManager.isSynchronizationActive());
assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
assertEquals("result", ptm.execute(definition, new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
assertTrue(TransactionSynchronizationManager.isSynchronizationActive());
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
status.setRollbackOnly();
return "result";
}
}));
assertFalse(TransactionSynchronizationManager.isSynchronizationActive());
assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
assertEquals(0, manager.getUOWTimeout());
assertEquals(UOWManager.UOW_TYPE_GLOBAL_TRANSACTION, manager.getUOWType());
assertFalse(manager.getJoined());
assertTrue(manager.getRollbackOnly());
}
public void testExistingNonSpringTransaction() {
MockUOWManager manager = new MockUOWManager();
manager.setUOWStatus(UOWManager.UOW_STATUS_ACTIVE);
WebSphereUowTransactionManager ptm = new WebSphereUowTransactionManager(manager);
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
assertFalse(TransactionSynchronizationManager.isSynchronizationActive());
assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
assertEquals("result", ptm.execute(definition, new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
assertTrue(TransactionSynchronizationManager.isSynchronizationActive());
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
return "result";
}
}));
assertFalse(TransactionSynchronizationManager.isSynchronizationActive());
assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
assertEquals(0, manager.getUOWTimeout());
assertEquals(UOWManager.UOW_TYPE_GLOBAL_TRANSACTION, manager.getUOWType());
assertTrue(manager.getJoined());
assertFalse(manager.getRollbackOnly());
}
public void testPropagationNeverFailsInCaseOfExistingTransaction() {
MockUOWManager manager = new MockUOWManager();
manager.setUOWStatus(UOWManager.UOW_STATUS_ACTIVE);
WebSphereUowTransactionManager ptm = new WebSphereUowTransactionManager(manager);
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_NEVER);
try {
ptm.execute(definition, new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
return "result";
}
});
fail("Should have thrown IllegalTransactionStateException");
}
catch (IllegalTransactionStateException ex) {
// expected
}
}
public void testPropagationNestedFailsInCaseOfExistingTransaction() {
MockUOWManager manager = new MockUOWManager();
manager.setUOWStatus(UOWManager.UOW_STATUS_ACTIVE);
WebSphereUowTransactionManager ptm = new WebSphereUowTransactionManager(manager);
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_NESTED);
try {
ptm.execute(definition, new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
return "result";
}
});
fail("Should have thrown NestedTransactionNotSupportedException");
}
catch (NestedTransactionNotSupportedException ex) {
// expected
}
}
public void testExistingTransactionWithParticipationUsingPropagationRequired() {
doTestExistingTransactionWithParticipation(TransactionDefinition.PROPAGATION_REQUIRED);
}
public void testExistingTransactionWithParticipationUsingPropagationSupports() {
doTestExistingTransactionWithParticipation(TransactionDefinition.PROPAGATION_SUPPORTS);
}
public void testExistingTransactionWithParticipationUsingPropagationMandatory() {
doTestExistingTransactionWithParticipation(TransactionDefinition.PROPAGATION_MANDATORY);
}
private void doTestExistingTransactionWithParticipation(int propagationBehavior) {
MockUOWManager manager = new MockUOWManager();
final WebSphereUowTransactionManager ptm = new WebSphereUowTransactionManager(manager);
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
final DefaultTransactionDefinition definition2 = new DefaultTransactionDefinition();
definition2.setPropagationBehavior(propagationBehavior);
definition2.setReadOnly(true);
assertFalse(TransactionSynchronizationManager.isSynchronizationActive());
assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
assertEquals("result", ptm.execute(definition, new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
assertTrue(TransactionSynchronizationManager.isSynchronizationActive());
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
assertEquals("result2", ptm.execute(definition2, new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
assertTrue(TransactionSynchronizationManager.isSynchronizationActive());
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
return "result2";
}
}));
return "result";
}
}));
assertFalse(TransactionSynchronizationManager.isSynchronizationActive());
assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
assertEquals(0, manager.getUOWTimeout());
assertEquals(UOWManager.UOW_TYPE_GLOBAL_TRANSACTION, manager.getUOWType());
assertTrue(manager.getJoined());
assertFalse(manager.getRollbackOnly());
}
public void testExistingTransactionWithSuspensionUsingPropagationRequiresNew() {
doTestExistingTransactionWithSuspension(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
}
public void testExistingTransactionWithSuspensionUsingPropagationNotSupported() {
doTestExistingTransactionWithSuspension(TransactionDefinition.PROPAGATION_NOT_SUPPORTED);
}
private void doTestExistingTransactionWithSuspension(final int propagationBehavior) {
MockUOWManager manager = new MockUOWManager();
final WebSphereUowTransactionManager ptm = new WebSphereUowTransactionManager(manager);
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
final DefaultTransactionDefinition definition2 = new DefaultTransactionDefinition();
definition2.setPropagationBehavior(propagationBehavior);
definition2.setReadOnly(true);
assertFalse(TransactionSynchronizationManager.isSynchronizationActive());
assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
assertEquals("result", ptm.execute(definition, new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
assertTrue(TransactionSynchronizationManager.isSynchronizationActive());
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
assertEquals("result2", ptm.execute(definition2, new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
assertTrue(TransactionSynchronizationManager.isSynchronizationActive());
assertEquals(propagationBehavior == TransactionDefinition.PROPAGATION_REQUIRES_NEW,
TransactionSynchronizationManager.isActualTransactionActive());
assertTrue(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
return "result2";
}
}));
return "result";
}
}));
assertFalse(TransactionSynchronizationManager.isSynchronizationActive());
assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
assertEquals(0, manager.getUOWTimeout());
if (propagationBehavior == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
assertEquals(UOWManager.UOW_TYPE_GLOBAL_TRANSACTION, manager.getUOWType());
}
else {
assertEquals(UOWManager.UOW_TYPE_LOCAL_TRANSACTION, manager.getUOWType());
}
assertFalse(manager.getJoined());
assertFalse(manager.getRollbackOnly());
}
public void testExistingTransactionUsingPropagationNotSupported() {
MockUOWManager manager = new MockUOWManager();
final WebSphereUowTransactionManager ptm = new WebSphereUowTransactionManager(manager);
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
final DefaultTransactionDefinition definition2 = new DefaultTransactionDefinition();
definition2.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED);
definition2.setReadOnly(true);
assertFalse(TransactionSynchronizationManager.isSynchronizationActive());
assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
assertEquals("result", ptm.execute(definition, new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
assertTrue(TransactionSynchronizationManager.isSynchronizationActive());
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
assertEquals("result2", ptm.execute(definition2, new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
assertTrue(TransactionSynchronizationManager.isSynchronizationActive());
assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
assertTrue(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
return "result2";
}
}));
return "result";
}
}));
assertFalse(TransactionSynchronizationManager.isSynchronizationActive());
assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
assertEquals(0, manager.getUOWTimeout());
assertEquals(UOWManager.UOW_TYPE_LOCAL_TRANSACTION, manager.getUOWType());
assertFalse(manager.getJoined());
assertFalse(manager.getRollbackOnly());
}
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright 2002-2009 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.transaction.support;
import static org.easymock.EasyMock.createMock;
import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;
import junit.framework.TestCase;
import org.springframework.mock.jndi.SimpleNamingContextBuilder;
import org.springframework.transaction.jta.JtaTransactionManager;
import org.springframework.util.SerializationTestUtils;
/**
* @author Rod Johnson
*/
public class JtaTransactionManagerSerializationTests extends TestCase {
public void testSerializable() throws Exception {
UserTransaction ut1 = createMock(UserTransaction.class);
UserTransaction ut2 = createMock(UserTransaction.class);
TransactionManager tm = createMock(TransactionManager.class);
JtaTransactionManager jtam = new JtaTransactionManager();
jtam.setUserTransaction(ut1);
jtam.setTransactionManager(tm);
jtam.setRollbackOnCommitFailure(true);
jtam.afterPropertiesSet();
SimpleNamingContextBuilder jndiEnv = SimpleNamingContextBuilder
.emptyActivatedContextBuilder();
jndiEnv.bind(JtaTransactionManager.DEFAULT_USER_TRANSACTION_NAME, ut2);
JtaTransactionManager serializedJtatm = (JtaTransactionManager) SerializationTestUtils
.serializeAndDeserialize(jtam);
// should do client-side lookup
assertNotNull("Logger must survive serialization",
serializedJtatm.logger);
assertTrue("UserTransaction looked up on client", serializedJtatm
.getUserTransaction() == ut2);
assertNull("TransactionManager didn't survive", serializedJtatm
.getTransactionManager());
assertEquals(true, serializedJtatm.isRollbackOnCommitFailure());
}
}

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<aop:config>
<aop:advisor pointcut="execution(* *..ITestBean.*(..))" advice-ref="txAdvice"/>
</aop:config>
<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="set*"/>
<tx:method name="exceptional"/>
</tx:attributes>
</tx:advice>
<tx:advice id="txRollbackAdvice">
<tx:attributes>
<tx:method name="get*" rollback-for="java.lang.Exception"/>
<tx:method name="set*" no-rollback-for="java.lang.RuntimeException"/>
</tx:attributes>
</tx:advice>
<bean id="transactionManager" class="org.springframework.transaction.CallCountingTransactionManager"/>
<bean id="testBean" class="org.springframework.beans.TestBean"/>
</beans>

View File

@@ -0,0 +1,97 @@
/*
* The Spring Framework is published under the terms
* of the Apache Software License.
*/
package org.springframework.util;
import java.awt.Point;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.NotSerializableException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import junit.framework.TestCase;
import org.springframework.beans.TestBean;
/**
* Utilities for testing serializability of objects.
* Exposes static methods for use in other test cases.
* Extends TestCase only to test itself.
*
* @author Rod Johnson
*/
public class SerializationTestUtils extends TestCase {
public static void testSerialization(Object o) throws IOException {
OutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(o);
}
public static boolean isSerializable(Object o) throws IOException {
try {
testSerialization(o);
return true;
}
catch (NotSerializableException ex) {
return false;
}
}
public static Object serializeAndDeserialize(Object o) throws IOException, ClassNotFoundException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(o);
oos.flush();
baos.flush();
byte[] bytes = baos.toByteArray();
ByteArrayInputStream is = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(is);
Object o2 = ois.readObject();
return o2;
}
public SerializationTestUtils(String s) {
super(s);
}
public void testWithNonSerializableObject() throws IOException {
TestBean o = new TestBean();
assertFalse(o instanceof Serializable);
assertFalse(isSerializable(o));
try {
testSerialization(o);
fail();
}
catch (NotSerializableException ex) {
// Ok
}
}
public void testWithSerializableObject() throws Exception {
int x = 5;
int y = 10;
Point p = new Point(x, y);
assertTrue(p instanceof Serializable);
testSerialization(p);
assertTrue(isSerializable(p));
Point p2 = (Point) serializeAndDeserialize(p);
assertNotSame(p, p2);
assertEquals(x, (int) p2.getX());
assertEquals(y, (int) p2.getY());
}
}