Initial import of tx bundle

This commit is contained in:
Arjen Poutsma 2008-10-23 14:09:34 +00:00
parent 3b6f092219
commit 846b848fd3
182 changed files with 19865 additions and 0 deletions

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="org.springframework.transaction">
<property file="${basedir}/../build.properties"/>
<import file="${basedir}/../build-spring-framework/package-bundle.xml"/>
<import file="${basedir}/../spring-build/standard/default.xml"/>
</project>

View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="http://ivyrep.jayasoft.org/ivy-doc.xsl"?>
<ivy-module
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://incubator.apache.org/ivy/schemas/ivy.xsd"
version="1.3">
<info organisation="org.springframework" module="${ant.project.name}">
<license name="Apache 2.0" url="http://www.apache.org/licenses/LICENSE-2.0"/>
</info>
<configurations>
<include file="${spring.build.dir}/common/default-ivy-configurations.xml"/>
</configurations>
<publications>
<artifact name="${ant.project.name}"/>
<artifact name="${ant.project.name}-sources" type="src" ext="jar"/>
</publications>
<dependencies>
<!-- compile dependencies -->
<dependency org="org.apache.commons" name="com.springsource.org.apache.commons.logging" rev="1.1.1" conf="compile->runtime" />
<dependency org="org.springframework" name="org.springframework.core" rev="latest.integration" conf="compile->compile" />
<dependency org="org.springframework" name="org.springframework.beans" rev="latest.integration" conf="compile->compile" />
<dependency org="org.springframework" name="org.springframework.aop" rev="latest.integration" conf="compile->compile" />
<!-- optional dependencies -->
<dependency org="org.springframework" name="org.springframework.context" rev="latest.integration" conf="optional->compile" />
<dependency org="javax.transaction" name="com.springsource.javax.transaction" rev="1.1.0" conf="optional->compile" />
<dependency org="com.ibm.websphere" name="com.springsource.com.ibm.websphere.uow" rev="6.0.2.17" conf="optional->compile" />
<dependency org="org.objectweb.jotm" name="com.springsource.org.objectweb.jotm" rev="2.0.10" conf="optional->compile" />
<dependency org="javax.ejb" name="com.springsource.javax.ejb" rev="3.0.0" conf="optional->compile" />
<dependency org="javax.resource" name="com.springsource.javax.resource" rev="1.5.0" conf="optional->compile" />
<!-- test dependencies -->
<dependency org="org.junit" name="com.springsource.org.junit" rev="4.4.0" conf="test->runtime" />
</dependencies>
</ivy-module>

View File

@ -0,0 +1,59 @@
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.core</artifactId>
<packaging>jar</packaging>
<name>Spring Core Abstractions and Utilities</name>
<version>3.0.0.M1</version>
<repositories>
<repository>
<id>com.springsource.repository.bundles.external</id>
<name>SpringSource Enterprise Bundle Repository - External Bundle Releases</name>
<url>http://repository.springsource.com/maven/bundles/external</url>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>com.springsource.org.apache.commons.logging</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.apache.log4j</groupId>
<artifactId>com.springsource.org.apache.log4j</artifactId>
<version>1.2.15</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>com.springsource.org.apache.commons.collections</artifactId>
<version>3.2.0</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>com.springsource.org.aspectj.weaver</artifactId>
<version>1.6.2.RELEASE</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.objectweb.asm</groupId>
<artifactId>com.springsource.org.objectweb.asm.commons</artifactId>
<version>2.2.3</version>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,44 @@
/*
* 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;
/**
* Exception thrown on failure to aquire a lock during an update,
* for example during a "select for update" statement.
*
* @author Rod Johnson
*/
public class CannotAcquireLockException extends PessimisticLockingFailureException {
/**
* Constructor for CannotAcquireLockException.
* @param msg the detail message
*/
public CannotAcquireLockException(String msg) {
super(msg);
}
/**
* Constructor for CannotAcquireLockException.
* @param msg the detail message
* @param cause the root cause from the data access API in use
*/
public CannotAcquireLockException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@ -0,0 +1,44 @@
/*
* 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;
/**
* Exception thrown on failure to complete a transaction in serialized mode
* due to update conflicts.
*
* @author Rod Johnson
*/
public class CannotSerializeTransactionException extends PessimisticLockingFailureException {
/**
* Constructor for CannotSerializeTransactionException.
* @param msg the detail message
*/
public CannotSerializeTransactionException(String msg) {
super(msg);
}
/**
* Constructor for CannotSerializeTransactionException.
* @param msg the detail message
* @param cause the root cause from the data access API in use
*/
public CannotSerializeTransactionException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@ -0,0 +1,44 @@
/*
* 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;
/**
* Exception thrown when we couldn't cleanup after a data access operation,
* but the actual operation went OK.
*
* <p>For example, this exception or a subclass might be thrown if a JDBC
* Connection couldn't be closed after it had been used successfully.
*
* <p>Note that data access code might perform resources cleanup in a
* finally block and therefore log cleanup failure rather than rethrow it,
* to keep the original data access exception, if any.
*
* @author Rod Johnson
*/
public class CleanupFailureDataAccessException extends NonTransientDataAccessException {
/**
* Constructor for CleanupFailureDataAccessException.
* @param msg the detail message
* @param cause the root cause from the underlying data access API,
* such as JDBC
*/
public CleanupFailureDataAccessException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@ -0,0 +1,51 @@
/*
* 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;
/**
* Exception thrown on concurrency failure.
*
* <p>This exception should be subclassed to indicate the type of failure:
* optimistic locking, failure to acquire lock, etc.
*
* @author Thomas Risberg
* @since 1.1
* @see OptimisticLockingFailureException
* @see PessimisticLockingFailureException
* @see CannotAcquireLockException
* @see DeadlockLoserDataAccessException
*/
public class ConcurrencyFailureException extends TransientDataAccessException {
/**
* Constructor for ConcurrencyFailureException.
* @param msg the detail message
*/
public ConcurrencyFailureException(String msg) {
super(msg);
}
/**
* Constructor for ConcurrencyFailureException.
* @param msg the detail message
* @param cause the root cause from the data access API in use
*/
public ConcurrencyFailureException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@ -0,0 +1,58 @@
/*
* 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;
import org.springframework.core.NestedRuntimeException;
/**
* Root of the hierarchy of data access exceptions discussed in
* <a href="http://www.amazon.com/exec/obidos/tg/detail/-/0764543857/">Expert One-On-One J2EE Design and Development</a>.
* Please see Chapter 9 of this book for detailed discussion of the
* motivation for this package.
*
* <p>This exception hierarchy aims to let user code find and handle the
* kind of error encountered without knowing the details of the particular
* data access API in use (e.g. JDBC). Thus it is possible to react to an
* optimistic locking failure without knowing that JDBC is being used.
*
* <p>As this class is a runtime exception, there is no need for user code
* to catch it or subclasses if any error is to be considered fatal
* (the usual case).
*
* @author Rod Johnson
*/
public abstract class DataAccessException extends NestedRuntimeException {
/**
* Constructor for DataAccessException.
* @param msg the detail message
*/
public DataAccessException(String msg) {
super(msg);
}
/**
* Constructor for DataAccessException.
* @param msg the detail message
* @param cause the root cause (usually from using a underlying
* data access API such as JDBC)
*/
public DataAccessException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@ -0,0 +1,45 @@
/*
* 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;
/**
* Data access exception thrown when a resource fails completely:
* for example, if we can't connect to a database using JDBC.
*
* @author Rod Johnson
* @author Thomas Risberg
*/
public class DataAccessResourceFailureException extends NonTransientDataAccessResourceException {
/**
* Constructor for DataAccessResourceFailureException.
* @param msg the detail message
*/
public DataAccessResourceFailureException(String msg) {
super(msg);
}
/**
* Constructor for DataAccessResourceFailureException.
* @param msg the detail message
* @param cause the root cause from the data access API in use
*/
public DataAccessResourceFailureException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@ -0,0 +1,46 @@
/*
* 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;
/**
* Exception thrown when an attempt to insert or update data
* results in violation of an integrity constraint. Note that this
* is not purely a relational concept; unique primary keys are
* required by most database types.
*
* @author Rod Johnson
*/
public class DataIntegrityViolationException extends NonTransientDataAccessException {
/**
* Constructor for DataIntegrityViolationException.
* @param msg the detail message
*/
public DataIntegrityViolationException(String msg) {
super(msg);
}
/**
* Constructor for DataIntegrityViolationException.
* @param msg the detail message
* @param cause the root cause from the data access API in use
*/
public DataIntegrityViolationException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@ -0,0 +1,46 @@
/*
* 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;
/**
* Exception thrown if certain expected data could not be retrieved, e.g.
* when looking up specific data via a known identifier. This exception
* will be thrown either by O/R mapping tools or by DAO implementations.
*
* @author Juergen Hoeller
* @since 13.10.2003
*/
public class DataRetrievalFailureException extends NonTransientDataAccessException {
/**
* Constructor for DataRetrievalFailureException.
* @param msg the detail message
*/
public DataRetrievalFailureException(String msg) {
super(msg);
}
/**
* Constructor for DataRetrievalFailureException.
* @param msg the detail message
* @param cause the root cause from the data access API in use
*/
public DataRetrievalFailureException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@ -0,0 +1,36 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.dao;
/**
* Generic exception thrown when the current process was
* a deadlock loser, and its transaction rolled back.
*
* @author Rod Johnson
*/
public class DeadlockLoserDataAccessException extends PessimisticLockingFailureException {
/**
* Constructor for DeadlockLoserDataAccessException.
* @param msg the detail message
* @param cause the root cause from the data access API in use
*/
public DeadlockLoserDataAccessException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@ -0,0 +1,46 @@
/*
* 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;
/**
* Data access exception thrown when a result was expected to have at least
* one row (or element) but zero rows (or elements) were actually returned.
*
* @author Juergen Hoeller
* @since 2.0
* @see IncorrectResultSizeDataAccessException
*/
public class EmptyResultDataAccessException extends IncorrectResultSizeDataAccessException {
/**
* Constructor for EmptyResultDataAccessException.
* @param expectedSize the expected result size
*/
public EmptyResultDataAccessException(int expectedSize) {
super(expectedSize, 0);
}
/**
* Constructor for EmptyResultDataAccessException.
* @param msg the detail message
* @param expectedSize the expected result size
*/
public EmptyResultDataAccessException(String msg, int expectedSize) {
super(msg, expectedSize, 0);
}
}

View File

@ -0,0 +1,93 @@
/*
* 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;
/**
* Data access exception thrown when a result was not of the expected size,
* for example when expecting a single row but getting 0 or more than 1 rows.
*
* @author Juergen Hoeller
* @since 1.0.2
* @see EmptyResultDataAccessException
*/
public class IncorrectResultSizeDataAccessException extends DataRetrievalFailureException {
private int expectedSize;
private int actualSize;
/**
* Constructor for IncorrectResultSizeDataAccessException.
* @param expectedSize the expected result size
*/
public IncorrectResultSizeDataAccessException(int expectedSize) {
super("Incorrect result size: expected " + expectedSize);
this.expectedSize = expectedSize;
this.actualSize = -1;
}
/**
* Constructor for IncorrectResultSizeDataAccessException.
* @param expectedSize the expected result size
* @param actualSize the actual result size (or -1 if unknown)
*/
public IncorrectResultSizeDataAccessException(int expectedSize, int actualSize) {
super("Incorrect result size: expected " + expectedSize + ", actual " + actualSize);
this.expectedSize = expectedSize;
this.actualSize = actualSize;
}
/**
* Constructor for IncorrectResultSizeDataAccessException.
* @param msg the detail message
* @param expectedSize the expected result size
*/
public IncorrectResultSizeDataAccessException(String msg, int expectedSize) {
super(msg);
this.expectedSize = expectedSize;
this.actualSize = -1;
}
/**
* Constructor for IncorrectResultSizeDataAccessException.
* @param msg the detail message
* @param expectedSize the expected result size
* @param actualSize the actual result size (or -1 if unknown)
*/
public IncorrectResultSizeDataAccessException(String msg, int expectedSize, int actualSize) {
super(msg);
this.expectedSize = expectedSize;
this.actualSize = actualSize;
}
/**
* Return the expected result size.
*/
public int getExpectedSize() {
return expectedSize;
}
/**
* Return the actual result size (or -1 if unknown).
*/
public int getActualSize() {
return actualSize;
}
}

View File

@ -0,0 +1,56 @@
/*
* 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;
/**
* Data access exception thrown when something unintended appears to have
* happened with an update, but the transaction hasn't already been rolled back.
* Thrown, for example, when we wanted to update 1 row in an RDBMS but actually
* updated 3.
*
* @author Rod Johnson
*/
public class IncorrectUpdateSemanticsDataAccessException extends InvalidDataAccessResourceUsageException {
/**
* Constructor for IncorrectUpdateSemanticsDataAccessException.
* @param msg the detail message
*/
public IncorrectUpdateSemanticsDataAccessException(String msg) {
super(msg);
}
/**
* Constructor for IncorrectUpdateSemanticsDataAccessException.
* @param msg the detail message
* @param cause the root cause from the underlying API, such as JDBC
*/
public IncorrectUpdateSemanticsDataAccessException(String msg, Throwable cause) {
super(msg, cause);
}
/**
* Return whether data was updated.
* If this method returns false, there's nothing to roll back.
* <p>The default implementation always returns true.
* This can be overridden in subclasses.
*/
public boolean wasDataUpdated() {
return true;
}
}

View File

@ -0,0 +1,47 @@
/*
* 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;
/**
* Exception thrown on incorrect usage of the API, such as failing to
* "compile" a query object that needed compilation before execution.
*
* <p>This represents a problem in our Java data access framework,
* not the underlying data access infrastructure.
*
* @author Rod Johnson
*/
public class InvalidDataAccessApiUsageException extends NonTransientDataAccessException {
/**
* Constructor for InvalidDataAccessApiUsageException.
* @param msg the detail message
*/
public InvalidDataAccessApiUsageException(String msg) {
super(msg);
}
/**
* Constructor for InvalidDataAccessApiUsageException.
* @param msg the detail message
* @param cause the root cause from the data access API in use
*/
public InvalidDataAccessApiUsageException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@ -0,0 +1,45 @@
/*
* 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;
/**
* Root for exceptions thrown when we use a data access resource incorrectly.
* Thrown for example on specifying bad SQL when using a RDBMS.
* Resource-specific subclasses are supplied by concrete data access packages.
*
* @author Rod Johnson
*/
public class InvalidDataAccessResourceUsageException extends NonTransientDataAccessException {
/**
* Constructor for InvalidDataAccessResourceUsageException.
* @param msg the detail message
*/
public InvalidDataAccessResourceUsageException(String msg) {
super(msg);
}
/**
* Constructor for InvalidDataAccessResourceUsageException.
* @param msg the detail message
* @param cause the root cause from the data access API in use
*/
public InvalidDataAccessResourceUsageException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@ -0,0 +1,48 @@
/*
* 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.dao;
/**
* Root of the hierarchy of data access exceptions that are considered non-transient -
* where a retry of the same operation would fail unless the cause of the Exception
* is corrected.
*
* @author Thomas Risberg
* @since 2.5
* @see java.sql.SQLNonTransientException
*/
public abstract class NonTransientDataAccessException extends DataAccessException {
/**
* Constructor for NonTransientDataAccessException.
* @param msg the detail message
*/
public NonTransientDataAccessException(String msg) {
super(msg);
}
/**
* Constructor for NonTransientDataAccessException.
* @param msg the detail message
* @param cause the root cause (usually from using a underlying
* data access API such as JDBC)
*/
public NonTransientDataAccessException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@ -0,0 +1,45 @@
/*
* 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.dao;
/**
* Data access exception thrown when a resource fails completely and the failure is permanent.
*
* @author Thomas Risberg
* @since 2.5
* @see java.sql.SQLNonTransientConnectionException
*/
public class NonTransientDataAccessResourceException extends NonTransientDataAccessException {
/**
* Constructor for NonTransientDataAccessResourceException.
* @param msg the detail message
*/
public NonTransientDataAccessResourceException(String msg) {
super(msg);
}
/**
* Constructor for NonTransientDataAccessResourceException.
* @param msg the detail message
* @param cause the root cause from the data access API in use
*/
public NonTransientDataAccessResourceException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@ -0,0 +1,48 @@
/*
* 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;
/**
* Exception thrown on an optimistic locking violation.
*
* <p>This exception will be thrown either by O/R mapping tools
* or by custom DAO implementations. Optimistic locking failure
* is typically <i>not</i> detected by the database itself.
*
* @author Rod Johnson
* @see PessimisticLockingFailureException
*/
public class OptimisticLockingFailureException extends ConcurrencyFailureException {
/**
* Constructor for OptimisticLockingFailureException.
* @param msg the detail message
*/
public OptimisticLockingFailureException(String msg) {
super(msg);
}
/**
* Constructor for OptimisticLockingFailureException.
* @param msg the detail message
* @param cause the root cause from the data access API in use
*/
public OptimisticLockingFailureException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@ -0,0 +1,38 @@
/*
* 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;
/**
* Exception thrown when the underlying resource denied a permission
* to access a specific element, such as a specific database table.
*
* @author Juergen Hoeller
* @since 2.0
*/
public class PermissionDeniedDataAccessException extends NonTransientDataAccessException {
/**
* Constructor for PermissionDeniedDataAccessException.
* @param msg the detail message
* @param cause the root cause from the underlying data access API,
* such as JDBC
*/
public PermissionDeniedDataAccessException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@ -0,0 +1,52 @@
/*
* 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;
/**
* Exception thrown on a pessimistic locking violation.
* Thrown by Spring's SQLException translation mechanism
* if a corresponding database error is encountered.
*
* <p>Serves as superclass for more specific exceptions, like
* CannotAcquireLockException and DeadlockLoserDataAccessException.
*
* @author Thomas Risberg
* @since 1.2
* @see CannotAcquireLockException
* @see DeadlockLoserDataAccessException
* @see OptimisticLockingFailureException
*/
public class PessimisticLockingFailureException extends ConcurrencyFailureException {
/**
* Constructor for PessimisticLockingFailureException.
* @param msg the detail message
*/
public PessimisticLockingFailureException(String msg) {
super(msg);
}
/**
* Constructor for PessimisticLockingFailureException.
* @param msg the detail message
* @param cause the root cause from the data access API in use
*/
public PessimisticLockingFailureException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@ -0,0 +1,50 @@
/*
* 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.dao;
/**
* Data access exception thrown when a previously failed operation might be able
* to succeed if the application performs some recovery steps and retries the entire
* transaction or in the case of a distributed transaction, the transaction branch.
* At a minimum, the recovery operation must include closing the current connection
* and getting a new connection.
*
* @author Thomas Risberg
* @since 2.5
* @see java.sql.SQLRecoverableException
*/
public class RecoverableDataAccessException extends DataAccessException {
/**
* Constructor for RecoverableDataAccessException.
* @param msg the detail message
*/
public RecoverableDataAccessException(String msg) {
super(msg);
}
/**
* Constructor for RecoverableDataAccessException.
* @param msg the detail message
* @param cause the root cause (usually from using a underlying
* data access API such as JDBC)
*/
public RecoverableDataAccessException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@ -0,0 +1,48 @@
/*
* 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.dao;
/**
* Root of the hierarchy of data access exceptions that are considered transient -
* where a previously failed operation might be able to succeed when the operation
* is retried without any intervention by application-level functionality.
*
* @author Thomas Risberg
* @since 2.5
* @see java.sql.SQLTransientException
*/
public abstract class TransientDataAccessException extends DataAccessException {
/**
* Constructor for TransientDataAccessException.
* @param msg the detail message
*/
public TransientDataAccessException(String msg) {
super(msg);
}
/**
* Constructor for TransientDataAccessException.
* @param msg the detail message
* @param cause the root cause (usually from using a underlying
* data access API such as JDBC)
*/
public TransientDataAccessException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@ -0,0 +1,46 @@
/*
* 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.dao;
/**
* Data access exception thrown when a resource fails temporarily
* and the operation can be retried.
*
* @author Thomas Risberg
* @since 2.5
* @see java.sql.SQLTransientConnectionException
*/
public class TransientDataAccessResourceException extends TransientDataAccessException {
/**
* Constructor for TransientDataAccessResourceException.
* @param msg the detail message
*/
public TransientDataAccessResourceException(String msg) {
super(msg);
}
/**
* Constructor for TransientDataAccessResourceException.
* @param msg the detail message
* @param cause the root cause from the data access API in use
*/
public TransientDataAccessResourceException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@ -0,0 +1,45 @@
/*
* 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;
/**
* Exception thrown on mismatch between Java type and database type:
* for example on an attempt to set an object of the wrong type
* in an RDBMS column.
*
* @author Rod Johnson
*/
public class TypeMismatchDataAccessException extends InvalidDataAccessResourceUsageException {
/**
* Constructor for TypeMismatchDataAccessException.
* @param msg the detail message
*/
public TypeMismatchDataAccessException(String msg) {
super(msg);
}
/**
* Constructor for TypeMismatchDataAccessException.
* @param msg the detail message
* @param cause the root cause from the data access API in use
*/
public TypeMismatchDataAccessException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@ -0,0 +1,37 @@
/*
* 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;
/**
* Normal superclass when we can't distinguish anything more specific
* than "something went wrong with the underlying resource": for example,
* a SQLException from JDBC we can't pinpoint more precisely.
*
* @author Rod Johnson
*/
public abstract class UncategorizedDataAccessException extends NonTransientDataAccessException {
/**
* Constructor for UncategorizedDataAccessException.
* @param msg the detail message
* @param cause the exception thrown by underlying data access API
*/
public UncategorizedDataAccessException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@ -0,0 +1,83 @@
/*
* 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 java.lang.annotation.Annotation;
import org.aopalliance.aop.Advice;
import org.springframework.aop.Pointcut;
import org.springframework.aop.support.AbstractPointcutAdvisor;
import org.springframework.aop.support.annotation.AnnotationMatchingPointcut;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.dao.support.PersistenceExceptionTranslationInterceptor;
import org.springframework.dao.support.PersistenceExceptionTranslator;
/**
* Spring AOP exception translation aspect for use at Repository or DAO layer level.
* Translates native persistence exceptions into Spring's DataAccessException hierarchy,
* based on a given PersistenceExceptionTranslator.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @since 2.0
* @see org.springframework.dao.DataAccessException
* @see org.springframework.dao.support.PersistenceExceptionTranslator
*/
public class PersistenceExceptionTranslationAdvisor extends AbstractPointcutAdvisor {
private final PersistenceExceptionTranslationInterceptor advice;
private final AnnotationMatchingPointcut pointcut;
/**
* Create a new PersistenceExceptionTranslationAdvisor.
* @param persistenceExceptionTranslator the PersistenceExceptionTranslator to use
* @param repositoryAnnotationType the annotation type to check for
*/
public PersistenceExceptionTranslationAdvisor(
PersistenceExceptionTranslator persistenceExceptionTranslator,
Class<? extends Annotation> repositoryAnnotationType) {
this.advice = new PersistenceExceptionTranslationInterceptor(persistenceExceptionTranslator);
this.pointcut = new AnnotationMatchingPointcut(repositoryAnnotationType, true);
}
/**
* Create a new PersistenceExceptionTranslationAdvisor.
* @param beanFactory the ListableBeanFactory to obtaining all
* PersistenceExceptionTranslators from
* @param repositoryAnnotationType the annotation type to check for
*/
PersistenceExceptionTranslationAdvisor(
ListableBeanFactory beanFactory, Class<? extends Annotation> repositoryAnnotationType) {
this.advice = new PersistenceExceptionTranslationInterceptor(beanFactory);
this.pointcut = new AnnotationMatchingPointcut(repositoryAnnotationType, true);
}
public Advice getAdvice() {
return this.advice;
}
public Pointcut getPointcut() {
return this.pointcut;
}
}

View File

@ -0,0 +1,139 @@
/*
* 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.dao.annotation;
import java.lang.annotation.Annotation;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.ProxyConfig;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Repository;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* Bean post-processor that automatically applies persistence exception
* translation to any bean that carries the
* {@link org.springframework.stereotype.Repository} annotation,
* adding a corresponding {@link PersistenceExceptionTranslationAdvisor}
* to the exposed proxy (either an existing AOP proxy or a newly generated
* proxy that implements all of the target's interfaces).
*
* <p>Translates native resource exceptions to Spring's
* {@link org.springframework.dao.DataAccessException} hierarchy.
* Autodetects beans that implement the
* {@link org.springframework.dao.support.PersistenceExceptionTranslator}
* interface, which are subsequently asked to translate candidate exceptions.
*
* <p>All of Spring's applicable resource factories implement the
* <code>PersistenceExceptionTranslator</code> interface out of the box.
* As a consequence, all that is usually needed to enable automatic exception
* translation is marking all affected beans (such as DAOs) with the
* <code>Repository</code> annotation, along with defining this post-processor
* as bean in the application context.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @since 2.0
* @see PersistenceExceptionTranslationAdvisor
* @see org.springframework.stereotype.Repository
* @see org.springframework.dao.DataAccessException
* @see org.springframework.dao.support.PersistenceExceptionTranslator
*/
public class PersistenceExceptionTranslationPostProcessor extends ProxyConfig
implements BeanPostProcessor, BeanClassLoaderAware, BeanFactoryAware, Ordered {
private Class<? extends Annotation> repositoryAnnotationType = Repository.class;
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
private PersistenceExceptionTranslationAdvisor persistenceExceptionTranslationAdvisor;
/**
* Set the 'repository' annotation type.
* The default required annotation type is the {@link Repository} annotation.
* <p>This setter property exists so that developers can provide their own
* (non-Spring-specific) annotation type to indicate that a class has a
* repository role.
* @param repositoryAnnotationType the desired annotation type
*/
public void setRepositoryAnnotationType(Class<? extends Annotation> repositoryAnnotationType) {
Assert.notNull(repositoryAnnotationType, "'requiredAnnotationType' must not be null");
this.repositoryAnnotationType = repositoryAnnotationType;
}
public void setBeanClassLoader(ClassLoader classLoader) {
this.beanClassLoader = classLoader;
}
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
if (!(beanFactory instanceof ListableBeanFactory)) {
throw new IllegalArgumentException(
"Cannot use PersistenceExceptionTranslator autodetection without ListableBeanFactory");
}
this.persistenceExceptionTranslationAdvisor = new PersistenceExceptionTranslationAdvisor(
(ListableBeanFactory) beanFactory, this.repositoryAnnotationType);
}
public int getOrder() {
// This should run after all other post-processors, so that it can just add
// an advisor to existing proxies rather than double-proxy.
return LOWEST_PRECEDENCE;
}
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
Class<?> targetClass =
(bean instanceof Advised ? ((Advised) bean).getTargetSource().getTargetClass() : bean.getClass());
if (targetClass == null) {
// Can't do much here
return bean;
}
if (AopUtils.canApply(this.persistenceExceptionTranslationAdvisor, targetClass)) {
if (bean instanceof Advised) {
((Advised) bean).addAdvisor(this.persistenceExceptionTranslationAdvisor);
return bean;
}
else {
ProxyFactory proxyFactory = new ProxyFactory(bean);
// Copy our properties (proxyTargetClass etc) inherited from ProxyConfig.
proxyFactory.copyFrom(this);
proxyFactory.addAdvisor(this.persistenceExceptionTranslationAdvisor);
return proxyFactory.getProxy(this.beanClassLoader);
}
}
else {
// This is not a repository.
return bean;
}
}
}

View File

@ -0,0 +1,8 @@
<html>
<body>
Annotation support for DAOs. Contains a bean post-processor for translating
persistence exceptions based on a repository stereotype annotation.
</html>
</body>

View File

@ -0,0 +1,19 @@
<html>
<body>
Exception hierarchy enabling sophisticated error handling independent
of the data access approach in use. For example, when DAOs and data
access frameworks use the exceptions in this package (and custom
subclasses), calling code can detect and handle common problems such
as deadlocks without being tied to a particular data access strategy,
such as JDBC.
<p>All these exceptions are unchecked, meaning that calling code can
leave them uncaught and treat all data access exceptions as fatal.
<p>The classes in this package are discussed in Chapter 9 of
<a href="http://www.amazon.com/exec/obidos/tg/detail/-/0764543857/">Expert One-On-One J2EE Design and Development</a>
by Rod Johnson (Wrox, 2002).
</body>
</html>

View File

@ -0,0 +1,67 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.dao.support;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.springframework.dao.DataAccessException;
import org.springframework.util.Assert;
/**
* Implementation of PersistenceExceptionTranslator that supports chaining,
* allowing the addition of PersistenceExceptionTranslator instances in order.
* Returns <code>non-null</code> on the first (if any) match.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @since 2.0
*/
public class ChainedPersistenceExceptionTranslator implements PersistenceExceptionTranslator {
/** List of PersistenceExceptionTranslators */
private final List delegates = new ArrayList(4);
/**
* Add a PersistenceExceptionTranslator to the chained delegate list.
*/
public final void addDelegate(PersistenceExceptionTranslator pet) {
Assert.notNull(pet, "PersistenceExceptionTranslator must not be null");
this.delegates.add(pet);
}
/**
* Return all registered PersistenceExceptionTranslator delegates (as array).
*/
public final PersistenceExceptionTranslator[] getDelegates() {
return (PersistenceExceptionTranslator[])
this.delegates.toArray(new PersistenceExceptionTranslator[this.delegates.size()]);
}
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
DataAccessException translatedDex = null;
for (Iterator it = this.delegates.iterator(); translatedDex == null && it.hasNext(); ) {
PersistenceExceptionTranslator pet = (PersistenceExceptionTranslator) it.next();
translatedDex = pet.translateExceptionIfPossible(ex);
}
return translatedDex;
}
}

View File

@ -0,0 +1,73 @@
/*
* 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 org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.InitializingBean;
/**
* Generic base class for DAOs, defining template methods for DAO initialization.
*
* <p>Extended by Spring's specific DAO support classes, such as:
* JdbcDaoSupport, JdoDaoSupport, etc.
*
* @author Juergen Hoeller
* @since 1.2.2
* @see org.springframework.jdbc.core.support.JdbcDaoSupport
* @see org.springframework.orm.jdo.support.JdoDaoSupport
*/
public abstract class DaoSupport implements InitializingBean {
/** Logger available to subclasses */
protected final Log logger = LogFactory.getLog(getClass());
public final void afterPropertiesSet() throws IllegalArgumentException, BeanInitializationException {
// Let abstract subclasses check their configuration.
checkDaoConfig();
// Let concrete implementations initialize themselves.
try {
initDao();
}
catch (Exception ex) {
throw new BeanInitializationException("Initialization of DAO failed", ex);
}
}
/**
* Abstract subclasses must override this to check their configuration.
* <p>Implementors should be marked as <code>final</code if concrete subclasses
* are not supposed to override this template method themselves.
* @throws IllegalArgumentException in case of illegal configuration
*/
protected abstract void checkDaoConfig() throws IllegalArgumentException;
/**
* Concrete subclasses can override this for custom initialization behavior.
* Gets called after population of this instance's bean properties.
* @throws Exception if DAO initialization fails
* (will be rethrown as a BeanInitializationException)
* @see org.springframework.beans.factory.BeanInitializationException
*/
protected void initDao() throws Exception {
}
}

View File

@ -0,0 +1,216 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.dao.support;
import java.util.Collection;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.dao.TypeMismatchDataAccessException;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.NumberUtils;
/**
* Miscellaneous utility methods for DAO implementations.
* Useful with any data access technology.
*
* @author Juergen Hoeller
* @since 1.0.2
*/
public abstract class DataAccessUtils {
/**
* Return a single result object from the given Collection.
* <p>Returns <code>null</code> if 0 result objects found;
* throws an exception if more than 1 element found.
* @param results the result Collection (can be <code>null</code>)
* @return the single result object, or <code>null</code> if none
* @throws IncorrectResultSizeDataAccessException if more than one
* element has been found in the given Collection
*/
public static Object singleResult(Collection results) throws IncorrectResultSizeDataAccessException {
int size = (results != null ? results.size() : 0);
if (size == 0) {
return null;
}
if (results.size() > 1) {
throw new IncorrectResultSizeDataAccessException(1, size);
}
return results.iterator().next();
}
/**
* Return a single result object from the given Collection.
* <p>Throws an exception if 0 or more than 1 element found.
* @param results the result Collection (can be <code>null</code>)
* @return the single result object
* @throws IncorrectResultSizeDataAccessException if more than one
* element has been found in the given Collection
* @throws EmptyResultDataAccessException if no element at all
* has been found in the given Collection
*/
public static Object requiredSingleResult(Collection results) throws IncorrectResultSizeDataAccessException {
int size = (results != null ? results.size() : 0);
if (size == 0) {
throw new EmptyResultDataAccessException(1);
}
if (results.size() > 1) {
throw new IncorrectResultSizeDataAccessException(1, size);
}
return results.iterator().next();
}
/**
* Return a unique result object from the given Collection.
* <p>Returns <code>null</code> if 0 result objects found;
* throws an exception if more than 1 instance found.
* @param results the result Collection (can be <code>null</code>)
* @return the unique result object, or <code>null</code> if none
* @throws IncorrectResultSizeDataAccessException if more than one
* result object has been found in the given Collection
* @see org.springframework.util.CollectionUtils#hasUniqueObject
*/
public static Object uniqueResult(Collection results) throws IncorrectResultSizeDataAccessException {
int size = (results != null ? results.size() : 0);
if (size == 0) {
return null;
}
if (!CollectionUtils.hasUniqueObject(results)) {
throw new IncorrectResultSizeDataAccessException(1, size);
}
return results.iterator().next();
}
/**
* Return a unique result object from the given Collection.
* <p>Throws an exception if 0 or more than 1 instance found.
* @param results the result Collection (can be <code>null</code>)
* @return the unique result object
* @throws IncorrectResultSizeDataAccessException if more than one
* result object has been found in the given Collection
* @throws EmptyResultDataAccessException if no result object at all
* has been found in the given Collection
* @see org.springframework.util.CollectionUtils#hasUniqueObject
*/
public static Object requiredUniqueResult(Collection results) throws IncorrectResultSizeDataAccessException {
int size = (results != null ? results.size() : 0);
if (size == 0) {
throw new EmptyResultDataAccessException(1);
}
if (!CollectionUtils.hasUniqueObject(results)) {
throw new IncorrectResultSizeDataAccessException(1, size);
}
return results.iterator().next();
}
/**
* Return a unique result object from the given Collection.
* Throws an exception if 0 or more than 1 result objects found,
* of if the unique result object is not convertable to the
* specified required type.
* @param results the result Collection (can be <code>null</code>)
* @return the unique result object
* @throws IncorrectResultSizeDataAccessException if more than one
* result object has been found in the given Collection
* @throws EmptyResultDataAccessException if no result object
* at all has been found in the given Collection
* @throws TypeMismatchDataAccessException if the unique object does
* not match the specified required type
*/
public static Object objectResult(Collection results, Class requiredType)
throws IncorrectResultSizeDataAccessException, TypeMismatchDataAccessException {
Object result = requiredUniqueResult(results);
if (requiredType != null && !requiredType.isInstance(result)) {
if (String.class.equals(requiredType)) {
result = result.toString();
}
else if (Number.class.isAssignableFrom(requiredType) && Number.class.isInstance(result)) {
try {
result = NumberUtils.convertNumberToTargetClass(((Number) result), requiredType);
}
catch (IllegalArgumentException ex) {
throw new TypeMismatchDataAccessException(ex.getMessage());
}
}
else {
throw new TypeMismatchDataAccessException(
"Result object is of type [" + result.getClass().getName() +
"] and could not be converted to required type [" + requiredType.getName() + "]");
}
}
return result;
}
/**
* Return a unique int result from the given Collection.
* Throws an exception if 0 or more than 1 result objects found,
* of if the unique result object is not convertable to an int.
* @param results the result Collection (can be <code>null</code>)
* @return the unique int result
* @throws IncorrectResultSizeDataAccessException if more than one
* result object has been found in the given Collection
* @throws EmptyResultDataAccessException if no result object
* at all has been found in the given Collection
* @throws TypeMismatchDataAccessException if the unique object
* in the collection is not convertable to an int
*/
public static int intResult(Collection results)
throws IncorrectResultSizeDataAccessException, TypeMismatchDataAccessException {
return ((Number) objectResult(results, Number.class)).intValue();
}
/**
* Return a unique long result from the given Collection.
* Throws an exception if 0 or more than 1 result objects found,
* of if the unique result object is not convertable to a long.
* @param results the result Collection (can be <code>null</code>)
* @return the unique long result
* @throws IncorrectResultSizeDataAccessException if more than one
* result object has been found in the given Collection
* @throws EmptyResultDataAccessException if no result object
* at all has been found in the given Collection
* @throws TypeMismatchDataAccessException if the unique object
* in the collection is not convertable to a long
*/
public static long longResult(Collection results)
throws IncorrectResultSizeDataAccessException, TypeMismatchDataAccessException {
return ((Number) objectResult(results, Number.class)).longValue();
}
/**
* Return a translated exception if this is appropriate,
* otherwise return the input exception.
* @param rawException exception we may wish to translate
* @param pet PersistenceExceptionTranslator to use to perform the translation
* @return a translated exception if translation is possible, or
* the raw exception if it is not
*/
public static RuntimeException translateIfNecessary(
RuntimeException rawException, PersistenceExceptionTranslator pet) {
Assert.notNull(pet, "PersistenceExceptionTranslator must not be null");
DataAccessException dex = pet.translateExceptionIfPossible(rawException);
return (dex != null ? dex : rawException);
}
}

View File

@ -0,0 +1,151 @@
/*
* 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.support;
import java.util.Iterator;
import java.util.Map;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
/**
* AOP Alliance MethodInterceptor that provides persistence exception translation
* based on a given PersistenceExceptionTranslator.
*
* <p>Delegates to the given {@link PersistenceExceptionTranslator} to translate
* a RuntimeException thrown into Spring's DataAccessException hierarchy
* (if appropriate). If the RuntimeException in question is declared on the
* target method, it is always propagated as-is (with no translation applied).
*
* @author Rod Johnson
* @author Juergen Hoeller
* @since 2.0
* @see PersistenceExceptionTranslator
*/
public class PersistenceExceptionTranslationInterceptor
implements MethodInterceptor, BeanFactoryAware, InitializingBean {
private PersistenceExceptionTranslator persistenceExceptionTranslator;
/**
* Create a new PersistenceExceptionTranslationInterceptor.
* Needs to be configured with a PersistenceExceptionTranslator afterwards.
* @see #setPersistenceExceptionTranslator
*/
public PersistenceExceptionTranslationInterceptor() {
}
/**
* Create a new PersistenceExceptionTranslationInterceptor
* for the given PersistenceExceptionTranslator.
* @param persistenceExceptionTranslator the PersistenceExceptionTranslator to use
*/
public PersistenceExceptionTranslationInterceptor(PersistenceExceptionTranslator persistenceExceptionTranslator) {
setPersistenceExceptionTranslator(persistenceExceptionTranslator);
}
/**
* Create a new PersistenceExceptionTranslationInterceptor, autodetecting
* PersistenceExceptionTranslators in the given BeanFactory.
* @param beanFactory the ListableBeanFactory to obtaining all
* PersistenceExceptionTranslators from
*/
public PersistenceExceptionTranslationInterceptor(ListableBeanFactory beanFactory) {
this.persistenceExceptionTranslator = detectPersistenceExceptionTranslators(beanFactory);
}
/**
* Specify the PersistenceExceptionTranslator to use.
* <p>Default is to autodetect all PersistenceExceptionTranslators
* in the containing BeanFactory, using them in a chain.
* @see #detectPersistenceExceptionTranslators
*/
public void setPersistenceExceptionTranslator(PersistenceExceptionTranslator pet) {
Assert.notNull(pet, "PersistenceExceptionTranslator must not be null");
this.persistenceExceptionTranslator = pet;
}
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
if (this.persistenceExceptionTranslator == null) {
// No explicit exception translator specified - perform autodetection.
if (!(beanFactory instanceof ListableBeanFactory)) {
throw new IllegalArgumentException(
"Cannot use PersistenceExceptionTranslator autodetection without ListableBeanFactory");
}
this.persistenceExceptionTranslator =
detectPersistenceExceptionTranslators((ListableBeanFactory) beanFactory);
}
}
public void afterPropertiesSet() {
if (this.persistenceExceptionTranslator == null) {
throw new IllegalArgumentException("Property 'persistenceExceptionTranslator' is required");
}
}
/**
* Detect all PersistenceExceptionTranslators in the given BeanFactory.
* @param beanFactory the ListableBeanFactory to obtaining all
* PersistenceExceptionTranslators from
* @return a chained PersistenceExceptionTranslator, combining all
* PersistenceExceptionTranslators found in the factory
* @see ChainedPersistenceExceptionTranslator
*/
protected PersistenceExceptionTranslator detectPersistenceExceptionTranslators(ListableBeanFactory beanFactory) {
// Find all translators, being careful not to activate FactoryBeans.
Map pets = BeanFactoryUtils.beansOfTypeIncludingAncestors(
beanFactory, PersistenceExceptionTranslator.class, false, false);
if (pets.isEmpty()) {
throw new IllegalStateException(
"No persistence exception translators found in bean factory. Cannot perform exception translation.");
}
ChainedPersistenceExceptionTranslator cpet = new ChainedPersistenceExceptionTranslator();
for (Iterator it = pets.values().iterator(); it.hasNext();) {
cpet.addDelegate((PersistenceExceptionTranslator) it.next());
}
return cpet;
}
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
catch (RuntimeException ex) {
// Let it throw raw if the type of the exception is on the throws clause of the method.
if (ReflectionUtils.declaresException(mi.getMethod(), ex.getClass())) {
throw ex;
}
else {
throw DataAccessUtils.translateIfNecessary(ex, this.persistenceExceptionTranslator);
}
}
}
}

View File

@ -0,0 +1,55 @@
/*
* 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 org.springframework.dao.DataAccessException;
/**
* Interface implemented by Spring integrations with data access technologies
* that throw runtime exceptions, such as JPA, TopLink, JDO and Hibernate.
*
* <p>This allows consistent usage of combined exception translation functionality,
* without forcing a single translator to understand every single possible type
* of exception.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @since 2.0
*/
public interface PersistenceExceptionTranslator {
/**
* Translate the given runtime exception thrown by a persistence framework to a
* corresponding exception from Spring's generic DataAccessException hierarchy,
* if possible.
* <p>Do not translate exceptions that are not understand by this translator:
* for example, if coming from another persistence framework, or resulting
* from user code and unrelated to persistence.
* <p>Of particular importance is the correct translation to
* DataIntegrityViolationException, for example on constraint violation.
* Implementations may use Spring JDBC's sophisticated exception translation
* to provide further information in the event of SQLException as a root cause.
* @param ex a RuntimeException thrown
* @return the corresponding DataAccessException (or <code>null</code> if the
* exception could not be translated, as in this case it may result from
* user code rather than an actual persistence problem)
* @see org.springframework.dao.DataIntegrityViolationException
* @see org.springframework.jdbc.support.SQLExceptionTranslator
*/
DataAccessException translateExceptionIfPossible(RuntimeException ex);
}

View File

@ -0,0 +1,8 @@
<html>
<body>
Support classes for DAO implementations,
providing miscellaneous utility methods.
</body>
</html>

View File

@ -0,0 +1,41 @@
/*
* 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 javax.resource.ResourceException;
import org.springframework.dao.DataAccessResourceFailureException;
/**
* Exception thrown when the creating of a CCI Record failed
* for connector-internal reasons.
*
* @author Juergen Hoeller
* @since 1.2
*/
public class CannotCreateRecordException extends DataAccessResourceFailureException {
/**
* Constructor for CannotCreateRecordException.
* @param msg message
* @param ex ResourceException root cause
*/
public CannotCreateRecordException(String msg, ResourceException ex) {
super(msg, ex);
}
}

View File

@ -0,0 +1,41 @@
/*
* 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 javax.resource.ResourceException;
import org.springframework.dao.DataAccessResourceFailureException;
/**
* Fatal exception thrown when we can't connect to an EIS using CCI.
*
* @author Thierry Templier
* @author Juergen Hoeller
* @since 1.2
*/
public class CannotGetCciConnectionException extends DataAccessResourceFailureException {
/**
* Constructor for CannotGetCciConnectionException.
* @param msg message
* @param ex ResourceException root cause
*/
public CannotGetCciConnectionException(String msg, ResourceException ex) {
super(msg, ex);
}
}

View File

@ -0,0 +1,40 @@
/*
* 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 javax.resource.ResourceException;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
/**
* Exception thrown when the connector doesn't support a specific CCI operation.
*
* @author Juergen Hoeller
* @since 1.2
*/
public class CciOperationNotSupportedException extends InvalidDataAccessResourceUsageException {
/**
* Constructor for CciOperationNotSupportedException.
* @param msg message
* @param ex ResourceException root cause
*/
public CciOperationNotSupportedException(String msg, ResourceException ex) {
super(msg, ex);
}
}

View File

@ -0,0 +1,45 @@
/*
* 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 java.sql.SQLException;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
/**
* Exception thrown when a ResultSet has been accessed in an invalid fashion.
* Such exceptions always have a <code>java.sql.SQLException</code> root cause.
*
* <p>This typically happens when an invalid ResultSet column index or name
* has been specified.
*
* @author Juergen Hoeller
* @since 1.2
* @see javax.resource.cci.ResultSet
*/
public class InvalidResultSetAccessException extends InvalidDataAccessResourceUsageException {
/**
* Constructor for InvalidResultSetAccessException.
* @param msg message
* @param ex the root cause
*/
public InvalidResultSetAccessException(String msg, SQLException ex) {
super(ex.getMessage(), ex);
}
}

View File

@ -0,0 +1,41 @@
/*
* 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 javax.resource.ResourceException;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
/**
* Exception thrown when the creating of a CCI Record failed because
* the connector doesn't support the desired CCI Record type.
*
* @author Juergen Hoeller
* @since 1.2
*/
public class RecordTypeNotSupportedException extends InvalidDataAccessResourceUsageException {
/**
* Constructor for RecordTypeNotSupportedException.
* @param msg message
* @param ex ResourceException root cause
*/
public RecordTypeNotSupportedException(String msg, ResourceException ex) {
super(msg, ex);
}
}

View File

@ -0,0 +1,264 @@
/*
* 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.jca.cci.connection;
import javax.resource.NotSupportedException;
import javax.resource.ResourceException;
import javax.resource.cci.Connection;
import javax.resource.cci.ConnectionFactory;
import javax.resource.spi.LocalTransactionException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.transaction.CannotCreateTransactionException;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.TransactionSystemException;
import org.springframework.transaction.support.AbstractPlatformTransactionManager;
import org.springframework.transaction.support.DefaultTransactionStatus;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.transaction.support.ResourceTransactionManager;
/**
* {@link org.springframework.transaction.PlatformTransactionManager} implementation
* that manages local transactions for a single CCI ConnectionFactory.
* Binds a CCI Connection from the specified ConnectionFactory to the thread,
* potentially allowing for one thread-bound Connection per ConnectionFactory.
*
* <p>Application code is required to retrieve the CCI Connection via
* {@link ConnectionFactoryUtils#getConnection(ConnectionFactory)} instead of a standard
* J2EE-style {@link ConnectionFactory#getConnection()} call. Spring classes such as
* {@link org.springframework.jca.cci.core.CciTemplate} use this strategy implicitly.
* If not used in combination with this transaction manager, the
* {@link ConnectionFactoryUtils} lookup strategy behaves exactly like the native
* DataSource lookup; it can thus be used in a portable fashion.
*
* <p>Alternatively, you can allow application code to work with the standard
* J2EE lookup pattern {@link ConnectionFactory#getConnection()}, for example
* for legacy code that is not aware of Spring at all. In that case, define a
* {@link TransactionAwareConnectionFactoryProxy} for your target ConnectionFactory,
* which will automatically participate in Spring-managed transactions.
*
* @author Thierry Templier
* @author Juergen Hoeller
* @since 1.2
* @see ConnectionFactoryUtils#getConnection(javax.resource.cci.ConnectionFactory)
* @see ConnectionFactoryUtils#releaseConnection
* @see TransactionAwareConnectionFactoryProxy
* @see org.springframework.jca.cci.core.CciTemplate
*/
public class CciLocalTransactionManager extends AbstractPlatformTransactionManager
implements ResourceTransactionManager, InitializingBean {
private ConnectionFactory connectionFactory;
/**
* Create a new CciLocalTransactionManager instance.
* A ConnectionFactory has to be set to be able to use it.
* @see #setConnectionFactory
*/
public CciLocalTransactionManager() {
}
/**
* Create a new CciLocalTransactionManager instance.
* @param connectionFactory CCI ConnectionFactory to manage local transactions for
*/
public CciLocalTransactionManager(ConnectionFactory connectionFactory) {
setConnectionFactory(connectionFactory);
afterPropertiesSet();
}
/**
* Set the CCI ConnectionFactory that this instance should manage local
* transactions for.
*/
public void setConnectionFactory(ConnectionFactory cf) {
if (cf instanceof TransactionAwareConnectionFactoryProxy) {
// If we got a TransactionAwareConnectionFactoryProxy, we need to perform transactions
// for its underlying target ConnectionFactory, else JMS access code won't see
// properly exposed transactions (i.e. transactions for the target ConnectionFactory).
this.connectionFactory = ((TransactionAwareConnectionFactoryProxy) cf).getTargetConnectionFactory();
}
else {
this.connectionFactory = cf;
}
}
/**
* Return the CCI ConnectionFactory that this instance manages local
* transactions for.
*/
public ConnectionFactory getConnectionFactory() {
return this.connectionFactory;
}
public void afterPropertiesSet() {
if (getConnectionFactory() == null) {
throw new IllegalArgumentException("Property 'connectionFactory' is required");
}
}
public Object getResourceFactory() {
return getConnectionFactory();
}
protected Object doGetTransaction() {
CciLocalTransactionObject txObject = new CciLocalTransactionObject();
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(getConnectionFactory());
txObject.setConnectionHolder(conHolder);
return txObject;
}
protected boolean isExistingTransaction(Object transaction) {
CciLocalTransactionObject txObject = (CciLocalTransactionObject) transaction;
// Consider a pre-bound connection as transaction.
return (txObject.getConnectionHolder() != null);
}
protected void doBegin(Object transaction, TransactionDefinition definition) {
CciLocalTransactionObject txObject = (CciLocalTransactionObject) transaction;
Connection con = null;
try {
con = getConnectionFactory().getConnection();
if (logger.isDebugEnabled()) {
logger.debug("Acquired Connection [" + con + "] for local CCI transaction");
}
txObject.setConnectionHolder(new ConnectionHolder(con));
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
con.getLocalTransaction().begin();
int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
}
TransactionSynchronizationManager.bindResource(getConnectionFactory(), txObject.getConnectionHolder());
}
catch (NotSupportedException ex) {
ConnectionFactoryUtils.releaseConnection(con, getConnectionFactory());
throw new CannotCreateTransactionException("CCI Connection does not support local transactions", ex);
}
catch (LocalTransactionException ex) {
ConnectionFactoryUtils.releaseConnection(con, getConnectionFactory());
throw new CannotCreateTransactionException("Could not begin local CCI transaction", ex);
}
catch (ResourceException ex) {
ConnectionFactoryUtils.releaseConnection(con, getConnectionFactory());
throw new TransactionSystemException("Unexpected failure on begin of CCI local transaction", ex);
}
}
protected Object doSuspend(Object transaction) {
CciLocalTransactionObject txObject = (CciLocalTransactionObject) transaction;
txObject.setConnectionHolder(null);
return TransactionSynchronizationManager.unbindResource(getConnectionFactory());
}
protected void doResume(Object transaction, Object suspendedResources) {
ConnectionHolder conHolder = (ConnectionHolder) suspendedResources;
TransactionSynchronizationManager.bindResource(getConnectionFactory(), conHolder);
}
protected boolean isRollbackOnly(Object transaction) throws TransactionException {
CciLocalTransactionObject txObject = (CciLocalTransactionObject) transaction;
return txObject.getConnectionHolder().isRollbackOnly();
}
protected void doCommit(DefaultTransactionStatus status) {
CciLocalTransactionObject txObject = (CciLocalTransactionObject) status.getTransaction();
Connection con = txObject.getConnectionHolder().getConnection();
if (status.isDebug()) {
logger.debug("Committing CCI local transaction on Connection [" + con + "]");
}
try {
con.getLocalTransaction().commit();
}
catch (LocalTransactionException ex) {
throw new TransactionSystemException("Could not commit CCI local transaction", ex);
}
catch (ResourceException ex) {
throw new TransactionSystemException("Unexpected failure on commit of CCI local transaction", ex);
}
}
protected void doRollback(DefaultTransactionStatus status) {
CciLocalTransactionObject txObject = (CciLocalTransactionObject) status.getTransaction();
Connection con = txObject.getConnectionHolder().getConnection();
if (status.isDebug()) {
logger.debug("Rolling back CCI local transaction on Connection [" + con + "]");
}
try {
con.getLocalTransaction().rollback();
}
catch (LocalTransactionException ex) {
throw new TransactionSystemException("Could not roll back CCI local transaction", ex);
}
catch (ResourceException ex) {
throw new TransactionSystemException("Unexpected failure on rollback of CCI local transaction", ex);
}
}
protected void doSetRollbackOnly(DefaultTransactionStatus status) {
CciLocalTransactionObject txObject = (CciLocalTransactionObject) status.getTransaction();
if (status.isDebug()) {
logger.debug("Setting CCI local transaction [" + txObject.getConnectionHolder().getConnection() +
"] rollback-only");
}
txObject.getConnectionHolder().setRollbackOnly();
}
protected void doCleanupAfterCompletion(Object transaction) {
CciLocalTransactionObject txObject = (CciLocalTransactionObject) transaction;
// Remove the connection holder from the thread.
TransactionSynchronizationManager.unbindResource(getConnectionFactory());
txObject.getConnectionHolder().clear();
Connection con = txObject.getConnectionHolder().getConnection();
if (logger.isDebugEnabled()) {
logger.debug("Releasing CCI Connection [" + con + "] after transaction");
}
ConnectionFactoryUtils.releaseConnection(con, getConnectionFactory());
}
/**
* CCI local transaction object, representing a ConnectionHolder.
* Used as transaction object by CciLocalTransactionManager.
* @see ConnectionHolder
*/
private static class CciLocalTransactionObject {
private ConnectionHolder connectionHolder;
public void setConnectionHolder(ConnectionHolder connectionHolder) {
this.connectionHolder = connectionHolder;
}
public ConnectionHolder getConnectionHolder() {
return connectionHolder;
}
}
}

View File

@ -0,0 +1,213 @@
/*
* 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.jca.cci.connection;
import javax.resource.ResourceException;
import javax.resource.cci.Connection;
import javax.resource.cci.ConnectionFactory;
import javax.resource.cci.ConnectionSpec;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.jca.cci.CannotGetCciConnectionException;
import org.springframework.transaction.support.ResourceHolder;
import org.springframework.transaction.support.ResourceHolderSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;
/**
* Helper class that provides static methods for obtaining CCI Connections
* from a {@link javax.resource.cci.ConnectionFactory}. Includes special
* support for Spring-managed transactional Connections, e.g. managed
* by {@link CciLocalTransactionManager} or
* {@link org.springframework.transaction.jta.JtaTransactionManager}.
*
* <p>Used internally by {@link org.springframework.jca.cci.core.CciTemplate},
* Spring's CCI operation objects and the {@link CciLocalTransactionManager}.
* Can also be used directly in application code.
*
* @author Thierry Templier
* @author Juergen Hoeller
* @since 1.2
* @see #getConnection
* @see #releaseConnection
* @see CciLocalTransactionManager
* @see org.springframework.transaction.jta.JtaTransactionManager
* @see org.springframework.transaction.support.TransactionSynchronizationManager
*/
public abstract class ConnectionFactoryUtils {
private static final Log logger = LogFactory.getLog(ConnectionFactoryUtils.class);
/**
* Obtain a Connection from the given ConnectionFactory. Translates ResourceExceptions
* into the Spring hierarchy of unchecked generic data access exceptions, simplifying
* calling code and making any exception that is thrown more meaningful.
* <p>Is aware of a corresponding Connection bound to the current thread, for example
* when using {@link CciLocalTransactionManager}. Will bind a Connection to the thread
* if transaction synchronization is active (e.g. if in a JTA transaction).
* @param cf the ConnectionFactory to obtain Connection from
* @return a CCI Connection from the given ConnectionFactory
* @throws org.springframework.jca.cci.CannotGetCciConnectionException
* if the attempt to get a Connection failed
* @see #releaseConnection
*/
public static Connection getConnection(ConnectionFactory cf) throws CannotGetCciConnectionException {
return getConnection(cf, null);
}
/**
* Obtain a Connection from the given ConnectionFactory. Translates ResourceExceptions
* into the Spring hierarchy of unchecked generic data access exceptions, simplifying
* calling code and making any exception that is thrown more meaningful.
* <p>Is aware of a corresponding Connection bound to the current thread, for example
* when using {@link CciLocalTransactionManager}. Will bind a Connection to the thread
* if transaction synchronization is active (e.g. if in a JTA transaction).
* @param cf the ConnectionFactory to obtain Connection from
* @param spec the ConnectionSpec for the desired Connection (may be <code>null</code>).
* Note: If this is specified, a new Connection will be obtained for every call,
* without participating in a shared transactional Connection.
* @return a CCI Connection from the given ConnectionFactory
* @throws org.springframework.jca.cci.CannotGetCciConnectionException
* if the attempt to get a Connection failed
* @see #releaseConnection
*/
public static Connection getConnection(ConnectionFactory cf, ConnectionSpec spec)
throws CannotGetCciConnectionException {
try {
if (spec != null) {
Assert.notNull(cf, "No ConnectionFactory specified");
return cf.getConnection(spec);
}
else {
return doGetConnection(cf);
}
}
catch (ResourceException ex) {
throw new CannotGetCciConnectionException("Could not get CCI Connection", ex);
}
}
/**
* Actually obtain a CCI Connection from the given ConnectionFactory.
* Same as {@link #getConnection}, but throwing the original ResourceException.
* <p>Is aware of a corresponding Connection bound to the current thread, for example
* when using {@link CciLocalTransactionManager}. Will bind a Connection to the thread
* if transaction synchronization is active (e.g. if in a JTA transaction).
* <p>Directly accessed by {@link TransactionAwareConnectionFactoryProxy}.
* @param cf the ConnectionFactory to obtain Connection from
* @return a CCI Connection from the given ConnectionFactory
* @throws ResourceException if thrown by CCI API methods
* @see #doReleaseConnection
*/
public static Connection doGetConnection(ConnectionFactory cf) throws ResourceException {
Assert.notNull(cf, "No ConnectionFactory specified");
ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(cf);
if (conHolder != null) {
return conHolder.getConnection();
}
logger.debug("Opening CCI Connection");
Connection con = cf.getConnection();
if (TransactionSynchronizationManager.isSynchronizationActive()) {
logger.debug("Registering transaction synchronization for CCI Connection");
conHolder = new ConnectionHolder(con);
conHolder.setSynchronizedWithTransaction(true);
TransactionSynchronizationManager.registerSynchronization(new ConnectionSynchronization(conHolder, cf));
TransactionSynchronizationManager.bindResource(cf, conHolder);
}
return con;
}
/**
* Determine whether the given JCA CCI Connection is transactional, that is,
* bound to the current thread by Spring's transaction facilities.
* @param con the Connection to check
* @param cf the ConnectionFactory that the Connection was obtained from
* (may be <code>null</code>)
* @return whether the Connection is transactional
*/
public static boolean isConnectionTransactional(Connection con, ConnectionFactory cf) {
if (cf == null) {
return false;
}
ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(cf);
return (conHolder != null && conHolder.getConnection() == con);
}
/**
* Close the given Connection, obtained from the given ConnectionFactory,
* if it is not managed externally (that is, not bound to the thread).
* @param con the Connection to close if necessary
* (if this is <code>null</code>, the call will be ignored)
* @param cf the ConnectionFactory that the Connection was obtained from
* (can be <code>null</code>)
* @see #getConnection
*/
public static void releaseConnection(Connection con, ConnectionFactory cf) {
try {
doReleaseConnection(con, cf);
}
catch (ResourceException ex) {
logger.debug("Could not close CCI Connection", ex);
}
catch (Throwable ex) {
// We don't trust the CCI driver: It might throw RuntimeException or Error.
logger.debug("Unexpected exception on closing CCI Connection", ex);
}
}
/**
* Actually close the given Connection, obtained from the given ConnectionFactory.
* Same as {@link #releaseConnection}, but throwing the original ResourceException.
* <p>Directly accessed by {@link TransactionAwareConnectionFactoryProxy}.
* @param con the Connection to close if necessary
* (if this is <code>null</code>, the call will be ignored)
* @param cf the ConnectionFactory that the Connection was obtained from
* (can be <code>null</code>)
* @throws ResourceException if thrown by JCA CCI methods
* @see #doGetConnection
*/
public static void doReleaseConnection(Connection con, ConnectionFactory cf) throws ResourceException {
if (con == null || isConnectionTransactional(con, cf)) {
return;
}
con.close();
}
/**
* Callback for resource cleanup at the end of a non-native CCI transaction
* (e.g. when participating in a JTA transaction).
*/
private static class ConnectionSynchronization extends ResourceHolderSynchronization {
public ConnectionSynchronization(ConnectionHolder connectionHolder, ConnectionFactory connectionFactory) {
super(connectionHolder, connectionFactory);
}
protected void releaseResource(ResourceHolder resourceHolder, Object resourceKey) {
releaseConnection(((ConnectionHolder) resourceHolder).getConnection(), (ConnectionFactory) resourceKey);
}
}
}

View File

@ -0,0 +1,49 @@
/*
* 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.connection;
import javax.resource.cci.Connection;
import org.springframework.transaction.support.ResourceHolderSupport;
/**
* Connection holder, wrapping a CCI Connection.
*
* <p>CciLocalTransactionManager binds instances of this class
* to the thread, for a given ConnectionFactory.
*
* <p>Note: This is an SPI class, not intended to be used by applications.
*
* @author Thierry Templier
* @author Juergen Hoeller
* @since 1.2
* @see CciLocalTransactionManager
* @see ConnectionFactoryUtils
*/
public class ConnectionHolder extends ResourceHolderSupport {
private final Connection connection;
public ConnectionHolder(Connection connection) {
this.connection = connection;
}
public Connection getConnection() {
return this.connection;
}
}

View File

@ -0,0 +1,140 @@
/*
* 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.jca.cci.connection;
import javax.resource.ResourceException;
import javax.resource.cci.Connection;
import javax.resource.cci.ConnectionSpec;
import org.springframework.core.NamedThreadLocal;
/**
* An adapter for a target CCI {@link javax.resource.cci.ConnectionFactory},
* applying the given ConnectionSpec to every standard <code>getConnection()</code>
* call, that is, implicitly invoking <code>getConnection(ConnectionSpec)</code>
* on the target. All other methods simply delegate to the corresponding methods
* of the target ConnectionFactory.
*
* <p>Can be used to proxy a target JNDI ConnectionFactory that does not have a
* ConnectionSpec configured. Client code can work with the ConnectionFactory
* without passing in a ConnectionSpec on every <code>getConnection()</code> call.
*
* <p>In the following example, client code can simply transparently work with
* the preconfigured "myConnectionFactory", implicitly accessing
* "myTargetConnectionFactory" with the specified user credentials.
*
* <pre class="code">
* &lt;bean id="myTargetConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean"&gt;
* &lt;property name="jndiName" value="java:comp/env/cci/mycf"/&gt;
* &lt;/bean>
*
* &lt;bean id="myConnectionFactory" class="org.springframework.jca.cci.connection.ConnectionSpecConnectionFactoryAdapter"&gt;
* &lt;property name="targetConnectionFactory" ref="myTargetConnectionFactory"/&gt;
* &lt;property name="connectionSpec"&gt;
* &lt;bean class="your.resource.adapter.ConnectionSpecImpl"&gt;
* &lt;property name="username" value="myusername"/&gt;
* &lt;property name="password" value="mypassword"/&gt;
* &lt;/bean&gt;
* &lt;/property&gt;
* &lt;/bean&gt;</pre>
*
* <p>If the "connectionSpec" is empty, this proxy will simply delegate to the
* standard <code>getConnection()</code> method of the target ConnectionFactory.
* This can be used to keep a UserCredentialsConnectionFactoryAdapter bean definition
* just for the <i>option</i> of implicitly passing in a ConnectionSpec if the
* particular target ConnectionFactory requires it.
*
* @author Juergen Hoeller
* @since 1.2
* @see #getConnection
*/
public class ConnectionSpecConnectionFactoryAdapter extends DelegatingConnectionFactory {
private ConnectionSpec connectionSpec;
private final ThreadLocal threadBoundSpec = new NamedThreadLocal("Current CCI ConnectionSpec");
/**
* Set the ConnectionSpec that this adapter should use for retrieving Connections.
* Default is none.
*/
public void setConnectionSpec(ConnectionSpec connectionSpec) {
this.connectionSpec = connectionSpec;
}
/**
* Set a ConnectionSpec for this proxy and the current thread.
* The given ConnectionSpec will be applied to all subsequent
* <code>getConnection()</code> calls on this ConnectionFactory proxy.
* <p>This will override any statically specified "connectionSpec" property.
* @param spec the ConnectionSpec to apply
* @see #removeConnectionSpecFromCurrentThread
*/
public void setConnectionSpecForCurrentThread(ConnectionSpec spec) {
this.threadBoundSpec.set(spec);
}
/**
* Remove any ConnectionSpec for this proxy from the current thread.
* A statically specified ConnectionSpec applies again afterwards.
* @see #setConnectionSpecForCurrentThread
*/
public void removeConnectionSpecFromCurrentThread() {
this.threadBoundSpec.set(null);
}
/**
* Determine whether there is currently a thread-bound ConnectionSpec,
* using it if available, falling back to the statically specified
* "connectionSpec" property else.
* @see #doGetConnection
*/
public final Connection getConnection() throws ResourceException {
ConnectionSpec threadSpec = (ConnectionSpec) this.threadBoundSpec.get();
if (threadSpec != null) {
return doGetConnection(threadSpec);
}
else {
return doGetConnection(this.connectionSpec);
}
}
/**
* This implementation delegates to the <code>getConnection(ConnectionSpec)</code>
* method of the target ConnectionFactory, passing in the specified user credentials.
* If the specified username is empty, it will simply delegate to the standard
* <code>getConnection()</code> method of the target ConnectionFactory.
* @param spec the ConnectionSpec to apply
* @return the Connection
* @see javax.resource.cci.ConnectionFactory#getConnection(javax.resource.cci.ConnectionSpec)
* @see javax.resource.cci.ConnectionFactory#getConnection()
*/
protected Connection doGetConnection(ConnectionSpec spec) throws ResourceException {
if (getTargetConnectionFactory() == null) {
throw new IllegalStateException("targetConnectionFactory is required");
}
if (spec != null) {
return getTargetConnectionFactory().getConnection(spec);
}
else {
return getTargetConnectionFactory().getConnection();
}
}
}

View File

@ -0,0 +1,93 @@
/*
* 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.jca.cci.connection;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.resource.ResourceException;
import javax.resource.cci.Connection;
import javax.resource.cci.ConnectionFactory;
import javax.resource.cci.ConnectionSpec;
import javax.resource.cci.RecordFactory;
import javax.resource.cci.ResourceAdapterMetaData;
import org.springframework.beans.factory.InitializingBean;
/**
* CCI {@link ConnectionFactory} implementation that delegates all calls
* to a given target {@link ConnectionFactory}.
*
* <p>This class is meant to be subclassed, with subclasses overriding only
* those methods (such as {@link #getConnection()}) that should not simply
* delegate to the target {@link ConnectionFactory}.
*
* @author Juergen Hoeller
* @since 1.2
* @see #getConnection
*/
public class DelegatingConnectionFactory implements ConnectionFactory, InitializingBean {
private ConnectionFactory targetConnectionFactory;
/**
* Set the target ConnectionFactory that this ConnectionFactory should delegate to.
*/
public void setTargetConnectionFactory(ConnectionFactory targetConnectionFactory) {
this.targetConnectionFactory = targetConnectionFactory;
}
/**
* Return the target ConnectionFactory that this ConnectionFactory should delegate to.
*/
public ConnectionFactory getTargetConnectionFactory() {
return this.targetConnectionFactory;
}
public void afterPropertiesSet() {
if (getTargetConnectionFactory() == null) {
throw new IllegalArgumentException("Property 'targetConnectionFactory' is required");
}
}
public Connection getConnection() throws ResourceException {
return getTargetConnectionFactory().getConnection();
}
public Connection getConnection(ConnectionSpec connectionSpec) throws ResourceException {
return getTargetConnectionFactory().getConnection(connectionSpec);
}
public RecordFactory getRecordFactory() throws ResourceException {
return getTargetConnectionFactory().getRecordFactory();
}
public ResourceAdapterMetaData getMetaData() throws ResourceException {
return getTargetConnectionFactory().getMetaData();
}
public Reference getReference() throws NamingException {
return getTargetConnectionFactory().getReference();
}
public void setReference(Reference reference) {
getTargetConnectionFactory().setReference(reference);
}
}

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.jca.cci.connection;
import javax.resource.NotSupportedException;
import javax.resource.ResourceException;
import javax.resource.cci.IndexedRecord;
import javax.resource.cci.MappedRecord;
import javax.resource.cci.RecordFactory;
/**
* Implementation of the CCI RecordFactory interface that always throws
* NotSupportedException.
*
* <p>Useful as a placeholder for a RecordFactory argument (for example as
* defined by the RecordCreator callback), in particular when the connector's
* <code>ConnectionFactory.getRecordFactory()</code> implementation happens to
* throw NotSupportedException early rather than throwing the exception from
* RecordFactory's methods.
*
* @author Juergen Hoeller
* @since 1.2.4
* @see org.springframework.jca.cci.core.RecordCreator#createRecord(javax.resource.cci.RecordFactory)
* @see org.springframework.jca.cci.core.CciTemplate#getRecordFactory(javax.resource.cci.ConnectionFactory)
* @see javax.resource.cci.ConnectionFactory#getRecordFactory()
* @see javax.resource.NotSupportedException
*/
public class NotSupportedRecordFactory implements RecordFactory {
public MappedRecord createMappedRecord(String name) throws ResourceException {
throw new NotSupportedException("The RecordFactory facility is not supported by the connector");
}
public IndexedRecord createIndexedRecord(String name) throws ResourceException {
throw new NotSupportedException("The RecordFactory facility is not supported by the connector");
}
}

View File

@ -0,0 +1,249 @@
/*
* 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.jca.cci.connection;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import javax.resource.NotSupportedException;
import javax.resource.ResourceException;
import javax.resource.cci.Connection;
import javax.resource.cci.ConnectionFactory;
import javax.resource.cci.ConnectionSpec;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.util.Assert;
/**
* A CCI ConnectionFactory adapter that returns the same Connection on all
* <code>getConnection</code> calls, and ignores calls to
* <code>Connection.close()</code>.
*
* <p>Useful for testing and standalone environments, to keep using the same
* Connection for multiple CciTemplate calls, without having a pooling
* ConnectionFactory, also spanning any number of transactions.
*
* <p>You can either pass in a CCI Connection directly, or let this
* factory lazily create a Connection via a given target ConnectionFactory.
*
* @author Juergen Hoeller
* @since 1.2
* @see #getConnection()
* @see javax.resource.cci.Connection#close()
* @see org.springframework.jca.cci.core.CciTemplate
*/
public class SingleConnectionFactory extends DelegatingConnectionFactory implements DisposableBean {
protected final Log logger = LogFactory.getLog(getClass());
/** Wrapped Connection */
private Connection target;
/** Proxy Connection */
private Connection connection;
/** Synchronization monitor for the shared Connection */
private final Object connectionMonitor = new Object();
/**
* Create a new SingleConnectionFactory for bean-style usage.
* @see #setTargetConnectionFactory
*/
public SingleConnectionFactory() {
}
/**
* Create a new SingleConnectionFactory that always returns the
* given Connection.
* @param target the single Connection
*/
public SingleConnectionFactory(Connection target) {
Assert.notNull(target, "Target Connection must not be null");
this.target = target;
this.connection = getCloseSuppressingConnectionProxy(target);
}
/**
* Create a new SingleConnectionFactory that always returns a single
* Connection which it will lazily create via the given target
* ConnectionFactory.
* @param targetConnectionFactory the target ConnectionFactory
*/
public SingleConnectionFactory(ConnectionFactory targetConnectionFactory) {
Assert.notNull(targetConnectionFactory, "Target ConnectionFactory must not be null");
setTargetConnectionFactory(targetConnectionFactory);
}
/**
* Make sure a Connection or ConnectionFactory has been set.
*/
public void afterPropertiesSet() {
if (this.connection == null && getTargetConnectionFactory() == null) {
throw new IllegalArgumentException("Connection or 'targetConnectionFactory' is required");
}
}
public Connection getConnection() throws ResourceException {
synchronized (this.connectionMonitor) {
if (this.connection == null) {
initConnection();
}
return this.connection;
}
}
public Connection getConnection(ConnectionSpec connectionSpec) throws ResourceException {
throw new NotSupportedException(
"SingleConnectionFactory does not support custom ConnectionSpec");
}
/**
* Close the underlying Connection.
* The provider of this ConnectionFactory needs to care for proper shutdown.
* <p>As this bean implements DisposableBean, a bean factory will
* automatically invoke this on destruction of its cached singletons.
*/
public void destroy() {
resetConnection();
}
/**
* Initialize the single underlying Connection.
* <p>Closes and reinitializes the Connection if an underlying
* Connection is present already.
* @throws javax.resource.ResourceException if thrown by CCI API methods
*/
public void initConnection() throws ResourceException {
if (getTargetConnectionFactory() == null) {
throw new IllegalStateException(
"'targetConnectionFactory' is required for lazily initializing a Connection");
}
synchronized (this.connectionMonitor) {
if (this.target != null) {
closeConnection(this.target);
}
this.target = doCreateConnection();
prepareConnection(this.target);
if (logger.isInfoEnabled()) {
logger.info("Established shared CCI Connection: " + this.target);
}
this.connection = getCloseSuppressingConnectionProxy(this.target);
}
}
/**
* Reset the underlying shared Connection, to be reinitialized on next access.
*/
public void resetConnection() {
synchronized (this.connectionMonitor) {
if (this.target != null) {
closeConnection(this.target);
}
this.target = null;
this.connection = null;
}
}
/**
* Create a CCI Connection via this template's ConnectionFactory.
* @return the new CCI Connection
* @throws javax.resource.ResourceException if thrown by CCI API methods
*/
protected Connection doCreateConnection() throws ResourceException {
return getTargetConnectionFactory().getConnection();
}
/**
* Prepare the given Connection before it is exposed.
* <p>The default implementation is empty. Can be overridden in subclasses.
* @param con the Connection to prepare
*/
protected void prepareConnection(Connection con) throws ResourceException {
}
/**
* Close the given Connection.
* @param con the Connection to close
*/
protected void closeConnection(Connection con) {
try {
con.close();
}
catch (Throwable ex) {
logger.warn("Could not close shared CCI Connection", ex);
}
}
/**
* Wrap the given Connection with a proxy that delegates every method call to it
* but suppresses close calls. This is useful for allowing application code to
* handle a special framework Connection just like an ordinary Connection from a
* CCI ConnectionFactory.
* @param target the original Connection to wrap
* @return the wrapped Connection
*/
protected Connection getCloseSuppressingConnectionProxy(Connection target) {
return (Connection) Proxy.newProxyInstance(
Connection.class.getClassLoader(),
new Class[] {Connection.class},
new CloseSuppressingInvocationHandler(target));
}
/**
* Invocation handler that suppresses close calls on CCI Connections.
*/
private static class CloseSuppressingInvocationHandler implements InvocationHandler {
private final Connection target;
private CloseSuppressingInvocationHandler(Connection target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("equals")) {
// Only consider equal when proxies are identical.
return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE);
}
else if (method.getName().equals("hashCode")) {
// Use hashCode of Connection proxy.
return new Integer(System.identityHashCode(proxy));
}
else if (method.getName().equals("close")) {
// Handle close method: don't pass the call on.
return null;
}
try {
return method.invoke(this.target, args);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
}

View File

@ -0,0 +1,162 @@
/*
* 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.jca.cci.connection;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import javax.resource.ResourceException;
import javax.resource.cci.Connection;
import javax.resource.cci.ConnectionFactory;
/**
* Proxy for a target CCI {@link javax.resource.cci.ConnectionFactory}, adding
* awareness of Spring-managed transactions. Similar to a transactional JNDI
* ConnectionFactory as provided by a J2EE server.
*
* <p>Data access code that should remain unaware of Spring's data access support
* can work with this proxy to seamlessly participate in Spring-managed transactions.
* Note that the transaction manager, for example the {@link CciLocalTransactionManager},
* still needs to work with underlying ConnectionFactory, <i>not</i> with this proxy.
*
* <p><b>Make sure that TransactionAwareConnectionFactoryProxy is the outermost
* ConnectionFactory of a chain of ConnectionFactory proxies/adapters.</b>
* TransactionAwareConnectionFactoryProxy can delegate either directly to the
* target connection pool or to some intermediate proxy/adapter like
* {@link ConnectionSpecConnectionFactoryAdapter}.
*
* <p>Delegates to {@link ConnectionFactoryUtils} for automatically participating in
* thread-bound transactions, for example managed by {@link CciLocalTransactionManager}.
* <code>getConnection</code> calls and <code>close</code> calls on returned Connections
* will behave properly within a transaction, i.e. always operate on the transactional
* Connection. If not within a transaction, normal ConnectionFactory behavior applies.
*
* <p>This proxy allows data access code to work with the plain JCA CCI API and still
* participate in Spring-managed transactions, similar to CCI code in a J2EE/JTA
* environment. However, if possible, use Spring's ConnectionFactoryUtils, CciTemplate or
* CCI operation objects to get transaction participation even without a proxy for
* the target ConnectionFactory, avoiding the need to define such a proxy in the first place.
*
* <p><b>NOTE:</b> This ConnectionFactory proxy needs to return wrapped Connections
* in order to handle close calls properly. Therefore, the returned Connections cannot
* be cast to a native CCI Connection type or to a connection pool implementation type.
*
* @author Juergen Hoeller
* @since 1.2
* @see javax.resource.cci.ConnectionFactory#getConnection
* @see javax.resource.cci.Connection#close
* @see org.springframework.jca.cci.connection.ConnectionFactoryUtils#doGetConnection
* @see org.springframework.jca.cci.connection.ConnectionFactoryUtils#doReleaseConnection
*/
public class TransactionAwareConnectionFactoryProxy extends DelegatingConnectionFactory {
/**
* Create a new TransactionAwareConnectionFactoryProxy.
* @see #setTargetConnectionFactory
*/
public TransactionAwareConnectionFactoryProxy() {
}
/**
* Create a new TransactionAwareConnectionFactoryProxy.
* @param targetConnectionFactory the target ConnectionFactory
*/
public TransactionAwareConnectionFactoryProxy(ConnectionFactory targetConnectionFactory) {
setTargetConnectionFactory(targetConnectionFactory);
afterPropertiesSet();
}
/**
* Delegate to ConnectionFactoryUtils for automatically participating in Spring-managed
* transactions. Throws the original ResourceException, if any.
* @return a transactional Connection if any, a new one else
* @see org.springframework.jca.cci.connection.ConnectionFactoryUtils#doGetConnection
*/
public Connection getConnection() throws ResourceException {
Connection con = ConnectionFactoryUtils.doGetConnection(getTargetConnectionFactory());
return getTransactionAwareConnectionProxy(con, getTargetConnectionFactory());
}
/**
* Wrap the given Connection with a proxy that delegates every method call to it
* but delegates <code>close</code> calls to ConnectionFactoryUtils.
* @param target the original Connection to wrap
* @param cf ConnectionFactory that the Connection came from
* @return the wrapped Connection
* @see javax.resource.cci.Connection#close()
* @see org.springframework.jca.cci.connection.ConnectionFactoryUtils#doReleaseConnection
*/
protected Connection getTransactionAwareConnectionProxy(Connection target, ConnectionFactory cf) {
return (Connection) Proxy.newProxyInstance(
Connection.class.getClassLoader(),
new Class[] {Connection.class},
new TransactionAwareInvocationHandler(target, cf));
}
/**
* Invocation handler that delegates close calls on CCI Connections
* to ConnectionFactoryUtils for being aware of thread-bound transactions.
*/
private static class TransactionAwareInvocationHandler implements InvocationHandler {
private final Connection target;
private final ConnectionFactory connectionFactory;
public TransactionAwareInvocationHandler(Connection target, ConnectionFactory cf) {
this.target = target;
this.connectionFactory = cf;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// Invocation on Connection interface coming in...
if (method.getName().equals("equals")) {
// Only consider equal when proxies are identical.
return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE);
}
else if (method.getName().equals("hashCode")) {
// Use hashCode of Connection proxy.
return new Integer(System.identityHashCode(proxy));
}
else if (method.getName().equals("getLocalTransaction")) {
if (ConnectionFactoryUtils.isConnectionTransactional(this.target, this.connectionFactory)) {
throw new javax.resource.spi.IllegalStateException(
"Local transaction handling not allowed within a managed transaction");
}
}
else if (method.getName().equals("close")) {
// Handle close method: only close if not within a transaction.
ConnectionFactoryUtils.doReleaseConnection(this.target, this.connectionFactory);
return null;
}
// Invoke method on target Connection.
try {
return method.invoke(this.target, args);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
}

View File

@ -0,0 +1,9 @@
<html>
<body>
Provides a utility class for easy ConnectionFactory access,
a PlatformTransactionManager for local CCI transactions,
and various simple ConnectionFactory proxies/adapters.
</body>
</html>

View File

@ -0,0 +1,121 @@
/*
* 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.core;
import javax.resource.cci.InteractionSpec;
import javax.resource.cci.Record;
import org.springframework.dao.DataAccessException;
/**
* Interface that specifies a basic set of CCI operations on an EIS.
* Implemented by CciTemplate. Not often used, but a useful option
* to enhance testability, as it can easily be mocked or stubbed.
*
* <p>Alternatively, the standard CCI infrastructure can be mocked.
* However, mocking this interface constitutes significantly less work.
*
* @author Juergen Hoeller
* @since 1.2
* @see CciTemplate
*/
public interface CciOperations {
/**
* Execute a request on an EIS with CCI, implemented as callback action
* working on a CCI Connection. This allows for implementing arbitrary
* data access operations, within Spring's managed CCI environment:
* that is, participating in Spring-managed transactions and converting
* JCA ResourceExceptions into Spring's DataAccessException hierarchy.
* <p>The callback action can return a result object, for example a
* domain object or a collection of domain objects.
* @param action the callback object that specifies the action
* @return the result object returned by the action, if any
* @throws DataAccessException if there is any problem
*/
Object execute(ConnectionCallback action) throws DataAccessException;
/**
* Execute a request on an EIS with CCI, implemented as callback action
* working on a CCI Interaction. This allows for implementing arbitrary
* data access operations on a single Interaction, within Spring's managed
* CCI environment: that is, participating in Spring-managed transactions
* and converting JCA ResourceExceptions into Spring's DataAccessException
* hierarchy.
* <p>The callback action can return a result object, for example a
* domain object or a collection of domain objects.
* @param action the callback object that specifies the action
* @return the result object returned by the action, if any
* @throws DataAccessException if there is any problem
*/
Object execute(InteractionCallback action) throws DataAccessException;
/**
* Execute the specified interaction on an EIS with CCI.
* @param spec the CCI InteractionSpec instance that defines
* the interaction (connector-specific)
* @param inputRecord the input record
* @return the output record
* @throws DataAccessException if there is any problem
*/
Record execute(InteractionSpec spec, Record inputRecord) throws DataAccessException;
/**
* Execute the specified interaction on an EIS with CCI.
* @param spec the CCI InteractionSpec instance that defines
* the interaction (connector-specific)
* @param inputRecord the input record
* @param outputRecord the output record
* @throws DataAccessException if there is any problem
*/
void execute(InteractionSpec spec, Record inputRecord, Record outputRecord) throws DataAccessException;
/**
* Execute the specified interaction on an EIS with CCI.
* @param spec the CCI InteractionSpec instance that defines
* the interaction (connector-specific)
* @param inputCreator object that creates the input record to use
* @return the output record
* @throws DataAccessException if there is any problem
*/
Record execute(InteractionSpec spec, RecordCreator inputCreator) throws DataAccessException;
/**
* Execute the specified interaction on an EIS with CCI.
* @param spec the CCI InteractionSpec instance that defines
* the interaction (connector-specific)
* @param inputRecord the input record
* @param outputExtractor object to convert the output record to a result object
* @return the output data extracted with the RecordExtractor object
* @throws DataAccessException if there is any problem
*/
Object execute(InteractionSpec spec, Record inputRecord, RecordExtractor outputExtractor)
throws DataAccessException;
/**
* Execute the specified interaction on an EIS with CCI.
* @param spec the CCI InteractionSpec instance that defines
* the interaction (connector-specific)
* @param inputCreator object that creates the input record to use
* @param outputExtractor object to convert the output record to a result object
* @return the output data extracted with the RecordExtractor object
* @throws DataAccessException if there is any problem
*/
Object execute(InteractionSpec spec, RecordCreator inputCreator, RecordExtractor outputExtractor)
throws DataAccessException;
}

View File

@ -0,0 +1,431 @@
/*
* 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.jca.cci.core;
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.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.jca.cci.CannotCreateRecordException;
import org.springframework.jca.cci.CciOperationNotSupportedException;
import org.springframework.jca.cci.InvalidResultSetAccessException;
import org.springframework.jca.cci.RecordTypeNotSupportedException;
import org.springframework.jca.cci.connection.ConnectionFactoryUtils;
import org.springframework.jca.cci.connection.NotSupportedRecordFactory;
import org.springframework.util.Assert;
/**
* <b>This is the central class in the CCI core package.</b>
* It simplifies the use of CCI and helps to avoid common errors.
* It executes core CCI workflow, leaving application code to provide parameters
* to CCI and extract results. This class executes EIS queries or updates,
* catching ResourceExceptions and translating them to the generic exception
* hierarchy defined in the <code>org.springframework.dao</code> package.
*
* <p>Code using this class can pass in and receive {@link javax.resource.cci.Record}
* instances, or alternatively implement callback interfaces for creating input
* Records and extracting result objects from output Records (or CCI ResultSets).
*
* <p>Can be used within a service implementation via direct instantiation
* with a ConnectionFactory reference, or get prepared in an application context
* and given to services as bean reference. Note: The ConnectionFactory should
* always be configured as a bean in the application context, in the first case
* given to the service directly, in the second case to the prepared template.
*
* @author Thierry Templier
* @author Juergen Hoeller
* @since 1.2
* @see RecordCreator
* @see RecordExtractor
*/
public class CciTemplate implements CciOperations {
private final Log logger = LogFactory.getLog(getClass());
private ConnectionFactory connectionFactory;
private ConnectionSpec connectionSpec;
private RecordCreator outputRecordCreator;
/**
* Construct a new CciTemplate for bean usage.
* <p>Note: The ConnectionFactory has to be set before using the instance.
* @see #setConnectionFactory
*/
public CciTemplate() {
}
/**
* Construct a new CciTemplate, given a ConnectionFactory to obtain Connections from.
* Note: This will trigger eager initialization of the exception translator.
* @param connectionFactory JCA ConnectionFactory to obtain Connections from
*/
public CciTemplate(ConnectionFactory connectionFactory) {
setConnectionFactory(connectionFactory);
afterPropertiesSet();
}
/**
* Construct a new CciTemplate, given a ConnectionFactory to obtain Connections from.
* Note: This will trigger eager initialization of the exception translator.
* @param connectionFactory JCA ConnectionFactory to obtain Connections from
* @param connectionSpec the CCI ConnectionSpec to obtain Connections for
* (may be <code>null</code>)
*/
public CciTemplate(ConnectionFactory connectionFactory, ConnectionSpec connectionSpec) {
setConnectionFactory(connectionFactory);
setConnectionSpec(connectionSpec);
afterPropertiesSet();
}
/**
* Set the CCI ConnectionFactory to obtain Connections from.
*/
public void setConnectionFactory(ConnectionFactory connectionFactory) {
this.connectionFactory = connectionFactory;
}
/**
* Return the CCI ConnectionFactory used by this template.
*/
public ConnectionFactory getConnectionFactory() {
return this.connectionFactory;
}
/**
* Set the CCI ConnectionSpec that this template instance is
* supposed to obtain Connections for.
*/
public void setConnectionSpec(ConnectionSpec connectionSpec) {
this.connectionSpec = connectionSpec;
}
/**
* Return the CCI ConnectionSpec used by this template, if any.
*/
public ConnectionSpec getConnectionSpec() {
return this.connectionSpec;
}
/**
* Set a RecordCreator that should be used for creating default output Records.
* <p>Default is none: When no explicit output Record gets passed into an
* <code>execute</code> method, CCI's <code>Interaction.execute</code> variant
* that returns an output Record will be called.
* <p>Specify a RecordCreator here if you always need to call CCI's
* <code>Interaction.execute</code> variant with a passed-in output Record.
* Unless there is an explicitly specified output Record, CciTemplate will
* then invoke this RecordCreator to create a default output Record instance.
* @see javax.resource.cci.Interaction#execute(javax.resource.cci.InteractionSpec, Record)
* @see javax.resource.cci.Interaction#execute(javax.resource.cci.InteractionSpec, Record, Record)
*/
public void setOutputRecordCreator(RecordCreator creator) {
this.outputRecordCreator = creator;
}
/**
* Return a RecordCreator that should be used for creating default output Records.
*/
public RecordCreator getOutputRecordCreator() {
return this.outputRecordCreator;
}
public void afterPropertiesSet() {
if (getConnectionFactory() == null) {
throw new IllegalArgumentException("Property 'connectionFactory' is required");
}
}
/**
* Create a template derived from this template instance,
* inheriting the ConnectionFactory and other settings but
* overriding the ConnectionSpec used for obtaining Connections.
* @param connectionSpec the CCI ConnectionSpec that the derived template
* instance is supposed to obtain Connections for
* @return the derived template instance
* @see #setConnectionSpec
*/
public CciTemplate getDerivedTemplate(ConnectionSpec connectionSpec) {
CciTemplate derived = new CciTemplate();
derived.setConnectionFactory(getConnectionFactory());
derived.setConnectionSpec(connectionSpec);
derived.setOutputRecordCreator(getOutputRecordCreator());
return derived;
}
public Object execute(ConnectionCallback action) throws DataAccessException {
Assert.notNull(action, "Callback object must not be null");
Connection con = ConnectionFactoryUtils.getConnection(getConnectionFactory(), getConnectionSpec());
try {
return action.doInConnection(con, getConnectionFactory());
}
catch (NotSupportedException ex) {
throw new CciOperationNotSupportedException("CCI operation not supported by connector", ex);
}
catch (ResourceException ex) {
throw new DataAccessResourceFailureException("CCI operation failed", ex);
}
catch (SQLException ex) {
throw new InvalidResultSetAccessException("Parsing of CCI ResultSet failed", ex);
}
finally {
ConnectionFactoryUtils.releaseConnection(con, getConnectionFactory());
}
}
public Object execute(final InteractionCallback action) throws DataAccessException {
Assert.notNull(action, "Callback object must not be null");
return execute(new ConnectionCallback() {
public Object doInConnection(Connection connection, ConnectionFactory connectionFactory)
throws ResourceException, SQLException, DataAccessException {
Interaction interaction = connection.createInteraction();
try {
return action.doInInteraction(interaction, connectionFactory);
}
finally {
closeInteraction(interaction);
}
}
});
}
public Record execute(InteractionSpec spec, Record inputRecord) throws DataAccessException {
return (Record) doExecute(spec, inputRecord, null, null);
}
public void execute(InteractionSpec spec, Record inputRecord, Record outputRecord) throws DataAccessException {
doExecute(spec, inputRecord, outputRecord, null);
}
public Record execute(InteractionSpec spec, RecordCreator inputCreator) throws DataAccessException {
return (Record) doExecute(spec, createRecord(inputCreator), null, null);
}
public Object execute(InteractionSpec spec, Record inputRecord, RecordExtractor outputExtractor)
throws DataAccessException {
return doExecute(spec, inputRecord, null, outputExtractor);
}
public Object execute(InteractionSpec spec, RecordCreator inputCreator, RecordExtractor outputExtractor)
throws DataAccessException {
return doExecute(spec, createRecord(inputCreator), null, outputExtractor);
}
/**
* Execute the specified interaction on an EIS with CCI.
* All other interaction execution methods go through this.
* @param spec the CCI InteractionSpec instance that defines
* the interaction (connector-specific)
* @param inputRecord the input record
* @param outputRecord output record (can be <code>null</code>)
* @param outputExtractor object to convert the output record to a result object
* @return the output data extracted with the RecordExtractor object
* @throws DataAccessException if there is any problem
*/
protected Object doExecute(
final InteractionSpec spec, final Record inputRecord, final Record outputRecord,
final RecordExtractor outputExtractor) throws DataAccessException {
return execute(new InteractionCallback() {
public Object doInInteraction(Interaction interaction, ConnectionFactory connectionFactory)
throws ResourceException, SQLException, DataAccessException {
Record outputRecordToUse = outputRecord;
try {
if (outputRecord != null || getOutputRecordCreator() != null) {
// Use the CCI execute method with output record as parameter.
if (outputRecord == null) {
RecordFactory recordFactory = getRecordFactory(connectionFactory);
outputRecordToUse = getOutputRecordCreator().createRecord(recordFactory);
}
interaction.execute(spec, inputRecord, outputRecordToUse);
}
else {
outputRecordToUse = interaction.execute(spec, inputRecord);
}
if (outputExtractor != null) {
return outputExtractor.extractData(outputRecordToUse);
}
else {
return outputRecordToUse;
}
}
finally {
if (outputRecordToUse instanceof ResultSet) {
closeResultSet((ResultSet) outputRecordToUse);
}
}
}
});
}
/**
* Create an indexed Record through the ConnectionFactory's RecordFactory.
* @param name the name of the record
* @return the Record
* @throws DataAccessException if creation of the Record failed
* @see #getRecordFactory(javax.resource.cci.ConnectionFactory)
* @see javax.resource.cci.RecordFactory#createIndexedRecord(String)
*/
public IndexedRecord createIndexedRecord(String name) throws DataAccessException {
try {
RecordFactory recordFactory = getRecordFactory(getConnectionFactory());
return recordFactory.createIndexedRecord(name);
}
catch (NotSupportedException ex) {
throw new RecordTypeNotSupportedException("Creation of indexed Record not supported by connector", ex);
}
catch (ResourceException ex) {
throw new CannotCreateRecordException("Creation of indexed Record failed", ex);
}
}
/**
* Create a mapped Record from the ConnectionFactory's RecordFactory.
* @param name record name
* @return the Record
* @throws DataAccessException if creation of the Record failed
* @see #getRecordFactory(javax.resource.cci.ConnectionFactory)
* @see javax.resource.cci.RecordFactory#createMappedRecord(String)
*/
public MappedRecord createMappedRecord(String name) throws DataAccessException {
try {
RecordFactory recordFactory = getRecordFactory(getConnectionFactory());
return recordFactory.createMappedRecord(name);
}
catch (NotSupportedException ex) {
throw new RecordTypeNotSupportedException("Creation of mapped Record not supported by connector", ex);
}
catch (ResourceException ex) {
throw new CannotCreateRecordException("Creation of mapped Record failed", ex);
}
}
/**
* Invoke the given RecordCreator, converting JCA ResourceExceptions
* to Spring's DataAccessException hierarchy.
* @param recordCreator the RecordCreator to invoke
* @return the created Record
* @throws DataAccessException if creation of the Record failed
* @see #getRecordFactory(javax.resource.cci.ConnectionFactory)
* @see RecordCreator#createRecord(javax.resource.cci.RecordFactory)
*/
protected Record createRecord(RecordCreator recordCreator) throws DataAccessException {
try {
RecordFactory recordFactory = getRecordFactory(getConnectionFactory());
return recordCreator.createRecord(recordFactory);
}
catch (NotSupportedException ex) {
throw new RecordTypeNotSupportedException(
"Creation of the desired Record type not supported by connector", ex);
}
catch (ResourceException ex) {
throw new CannotCreateRecordException("Creation of the desired Record failed", ex);
}
}
/**
* Return a RecordFactory for the given ConnectionFactory.
* <p>Default implementation returns the connector's RecordFactory if
* available, falling back to a NotSupportedRecordFactory placeholder.
* This allows to invoke a RecordCreator callback with a non-null
* RecordFactory reference in any case.
* @param connectionFactory the CCI ConnectionFactory
* @return the CCI RecordFactory for the ConnectionFactory
* @throws ResourceException if thrown by CCI methods
* @see org.springframework.jca.cci.connection.NotSupportedRecordFactory
*/
protected RecordFactory getRecordFactory(ConnectionFactory connectionFactory) throws ResourceException {
try {
return getConnectionFactory().getRecordFactory();
}
catch (NotSupportedException ex) {
return new NotSupportedRecordFactory();
}
}
/**
* Close the given CCI Interaction and ignore any thrown exception.
* This is useful for typical finally blocks in manual CCI code.
* @param interaction the CCI Interaction to close
* @see javax.resource.cci.Interaction#close()
*/
private void closeInteraction(Interaction interaction) {
if (interaction != null) {
try {
interaction.close();
}
catch (ResourceException ex) {
logger.trace("Could not close CCI Interaction", ex);
}
catch (Throwable ex) {
// We don't trust the CCI driver: It might throw RuntimeException or Error.
logger.trace("Unexpected exception on closing CCI Interaction", ex);
}
}
}
/**
* Close the given CCI ResultSet and ignore any thrown exception.
* This is useful for typical finally blocks in manual CCI code.
* @param resultSet the CCI ResultSet to close
* @see javax.resource.cci.ResultSet#close()
*/
private void closeResultSet(ResultSet resultSet) {
if (resultSet != null) {
try {
resultSet.close();
}
catch (SQLException ex) {
logger.trace("Could not close CCI ResultSet", ex);
}
catch (Throwable ex) {
// We don't trust the CCI driver: It might throw RuntimeException or Error.
logger.trace("Unexpected exception on closing CCI ResultSet", ex);
}
}
}
}

View File

@ -0,0 +1,79 @@
/*
* 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.core;
import java.sql.SQLException;
import javax.resource.ResourceException;
import javax.resource.cci.Connection;
import javax.resource.cci.ConnectionFactory;
import org.springframework.dao.DataAccessException;
/**
* Generic callback interface for code that operates on a CCI Connection.
* Allows to execute any number of operations on a single Connection,
* using any type and number of Interaction.
*
* <p>This is particularly useful for delegating to existing data access code
* that expects a Connection to work on and throws ResourceException. For newly
* written code, it is strongly recommended to use CciTemplate's more specific
* <code>execute</code> variants.
*
* @author Thierry Templier
* @author Juergen Hoeller
* @since 1.2
* @see CciTemplate#execute(ConnectionCallback)
* @see CciTemplate#execute(javax.resource.cci.InteractionSpec, javax.resource.cci.Record)
* @see CciTemplate#execute(javax.resource.cci.InteractionSpec, RecordCreator, RecordExtractor)
*/
public interface ConnectionCallback {
/**
* Gets called by <code>CciTemplate.execute</code> with an active CCI Connection.
* Does not need to care about activating or closing the Connection, or handling
* transactions.
*
* <p>If called without a thread-bound CCI transaction (initiated by
* CciLocalTransactionManager), the code will simply get executed on the CCI
* Connection with its transactional semantics. If CciTemplate is configured
* to use a JTA-aware ConnectionFactory, the CCI Connection and thus the callback
* code will be transactional if a JTA transaction is active.
*
* <p>Allows for returning a result object created within the callback, i.e.
* a domain object or a collection of domain objects. Note that there's special
* support for single step actions: see the <code>CciTemplate.execute</code>
* variants. A thrown RuntimeException is treated as application exception:
* it gets propagated to the caller of the template.
*
* @param connection active CCI Connection
* @param connectionFactory the CCI ConnectionFactory that the Connection was
* created with (gives access to RecordFactory and ResourceAdapterMetaData)
* @return a result object, or <code>null</code> if none
* @throws ResourceException if thrown by a CCI method, to be auto-converted
* to a DataAccessException
* @throws SQLException if thrown by a ResultSet method, to be auto-converted
* to a DataAccessException
* @throws DataAccessException in case of custom exceptions
* @see javax.resource.cci.ConnectionFactory#getRecordFactory()
* @see javax.resource.cci.ConnectionFactory#getMetaData()
* @see CciTemplate#execute(javax.resource.cci.InteractionSpec, RecordCreator, RecordExtractor)
*/
Object doInConnection(Connection connection, ConnectionFactory connectionFactory)
throws ResourceException, SQLException, DataAccessException;
}

View File

@ -0,0 +1,80 @@
/*
* 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.core;
import java.sql.SQLException;
import javax.resource.ResourceException;
import javax.resource.cci.ConnectionFactory;
import javax.resource.cci.Interaction;
import org.springframework.dao.DataAccessException;
/**
* Generic callback interface for code that operates on a CCI Interaction.
* Allows to execute any number of operations on a single Interaction, for
* example a single execute call or repeated execute calls with varying
* parameters.
*
* <p>This is particularly useful for delegating to existing data access code
* that expects an Interaction to work on and throws ResourceException. For newly
* written code, it is strongly recommended to use CciTemplate's more specific
* <code>execute</code> variants.
*
* @author Thierry Templier
* @author Juergen Hoeller
* @since 1.2
* @see CciTemplate#execute(InteractionCallback)
* @see CciTemplate#execute(javax.resource.cci.InteractionSpec, javax.resource.cci.Record)
* @see CciTemplate#execute(javax.resource.cci.InteractionSpec, RecordCreator, RecordExtractor)
*/
public interface InteractionCallback {
/**
* Gets called by <code>CciTemplate.execute</code> with an active CCI Interaction.
* Does not need to care about activating or closing the Interaction, or
* handling transactions.
*
* <p>If called without a thread-bound CCI transaction (initiated by
* CciLocalTransactionManager), the code will simply get executed on the CCI
* Interaction with its transactional semantics. If CciTemplate is configured
* to use a JTA-aware ConnectionFactory, the CCI Interaction and thus the callback
* code will be transactional if a JTA transaction is active.
*
* <p>Allows for returning a result object created within the callback, i.e.
* a domain object or a collection of domain objects. Note that there's special
* support for single step actions: see the <code>CciTemplate.execute</code>
* variants. A thrown RuntimeException is treated as application exception:
* it gets propagated to the caller of the template.
*
* @param interaction active CCI Interaction
* @param connectionFactory the CCI ConnectionFactory that the Connection was
* created with (gives access to RecordFactory and ResourceAdapterMetaData)
* @return a result object, or <code>null</code> if none
* @throws ResourceException if thrown by a CCI method, to be auto-converted
* to a DataAccessException
* @throws SQLException if thrown by a ResultSet method, to be auto-converted
* to a DataAccessException
* @throws DataAccessException in case of custom exceptions
* @see javax.resource.cci.ConnectionFactory#getRecordFactory()
* @see javax.resource.cci.ConnectionFactory#getMetaData()
* @see CciTemplate#execute(javax.resource.cci.InteractionSpec, RecordCreator, RecordExtractor)
*/
Object doInInteraction(Interaction interaction, ConnectionFactory connectionFactory)
throws ResourceException, SQLException, DataAccessException;
}

View File

@ -0,0 +1,64 @@
/*
* 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.core;
import javax.resource.ResourceException;
import javax.resource.cci.Record;
import javax.resource.cci.RecordFactory;
import org.springframework.dao.DataAccessException;
/**
* Callback interface for creating a CCI Record instance,
* usually based on the passed-in CCI RecordFactory.
*
* <p>Used for input Record creation in CciTemplate. Alternatively,
* Record instances can be passed into CciTemplate's corresponding
* <code>execute</code> methods directly, either instantiated manually
* or created through CciTemplate's Record factory methods.
*
* <P>Also used for creating default output Records in CciTemplate.
* This is useful when the JCA connector needs an explicit output Record
* instance, but no output Records should be passed into CciTemplate's
* <code>execute</code> methods.
*
* @author Thierry Templier
* @author Juergen Hoeller
* @since 1.2
* @see CciTemplate#execute(javax.resource.cci.InteractionSpec, RecordCreator)
* @see CciTemplate#execute(javax.resource.cci.InteractionSpec, RecordCreator, RecordExtractor)
* @see CciTemplate#createIndexedRecord(String)
* @see CciTemplate#createMappedRecord(String)
* @see CciTemplate#setOutputRecordCreator(RecordCreator)
*/
public interface RecordCreator {
/**
* Create a CCI Record instance, usually based on the passed-in CCI RecordFactory.
* <p>For use as <i>input</i> creator with CciTemplate's <code>execute</code> methods,
* this method should create a <i>populated</i> Record instance. For use as
* <i>output</i> Record creator, it should return an <i>empty</i> Record instance.
* @param recordFactory the CCI RecordFactory (never <code>null</code>, but not guaranteed to be
* supported by the connector: its create methods might throw NotSupportedException)
* @return the Record instance
* @throws ResourceException if thrown by a CCI method, to be auto-converted
* to a DataAccessException
* @throws DataAccessException in case of custom exceptions
*/
Record createRecord(RecordFactory recordFactory) throws ResourceException, DataAccessException;
}

View File

@ -0,0 +1,63 @@
/*
* 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.core;
import java.sql.SQLException;
import javax.resource.ResourceException;
import javax.resource.cci.Record;
import org.springframework.dao.DataAccessException;
/**
* Callback interface for extracting a result object from a CCI Record instance.
*
* <p>Used for output object creation in CciTemplate. Alternatively, output
* Records can also be returned to client code as-is. In case of a CCI ResultSet
* as execution result, you will almost always want to implement a RecordExtractor,
* to be able to read the ResultSet in a managed fashion, with the CCI Connection
* still open while reading the ResultSet.
*
* <p>Implementations of this interface perform the actual work of extracting
* results, but don't need to worry about exception handling. ResourceExceptions
* will be caught and handled correctly by the CciTemplate class.
*
* @author Thierry Templier
* @author Juergen Hoeller
* @since 1.2
* @see CciTemplate#execute(javax.resource.cci.InteractionSpec, Record, RecordExtractor)
* @see CciTemplate#execute(javax.resource.cci.InteractionSpec, RecordCreator, RecordExtractor)
* @see javax.resource.cci.ResultSet
*/
public interface RecordExtractor {
/**
* Process the data in the given Record, creating a corresponding result object.
* @param record the Record to extract data from
* (possibly a CCI ResultSet)
* @return an arbitrary result object, or <code>null</code> if none
* (the extractor will typically be stateful in the latter case)
* @throws ResourceException if thrown by a CCI method, to be auto-converted
* to a DataAccessException
* @throws SQLException if thrown by a ResultSet method, to be auto-converted
* to a DataAccessException
* @throws DataAccessException in case of custom exceptions
* @see javax.resource.cci.ResultSet
*/
Object extractData(Record record) throws ResourceException, SQLException, DataAccessException;
}

View File

@ -0,0 +1,8 @@
<html>
<body>
Provides the core JCA CCI support, based on CciTemplate
and its associated callback interfaces.
</body>
</html>

View File

@ -0,0 +1,137 @@
/*
* 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.jca.cci.core.support;
import javax.resource.cci.Connection;
import javax.resource.cci.ConnectionFactory;
import javax.resource.cci.ConnectionSpec;
import org.springframework.dao.support.DaoSupport;
import org.springframework.jca.cci.CannotGetCciConnectionException;
import org.springframework.jca.cci.connection.ConnectionFactoryUtils;
import org.springframework.jca.cci.core.CciTemplate;
/**
* Convenient super class for CCI-based data access objects.
*
* <p>Requires a {@link javax.resource.cci.ConnectionFactory} to be set,
* providing a {@link org.springframework.jca.cci.core.CciTemplate} based
* on it to subclasses through the {@link #getCciTemplate()} method.
*
* <p>This base class is mainly intended for CciTemplate usage but can
* also be used when working with a Connection directly or when using
* <code>org.springframework.jca.cci.object</code> classes.
*
* @author Thierry Templier
* @author Juergen Hoeller
* @since 1.2
* @see #setConnectionFactory
* @see #getCciTemplate
* @see org.springframework.jca.cci.core.CciTemplate
*/
public abstract class CciDaoSupport extends DaoSupport {
private CciTemplate cciTemplate;
/**
* Set the ConnectionFactory to be used by this DAO.
*/
public final void setConnectionFactory(ConnectionFactory connectionFactory) {
if (this.cciTemplate == null || connectionFactory != this.cciTemplate.getConnectionFactory()) {
this.cciTemplate = createCciTemplate(connectionFactory);
}
}
/**
* Create a CciTemplate for the given ConnectionFactory.
* Only invoked if populating the DAO with a ConnectionFactory reference!
* <p>Can be overridden in subclasses to provide a CciTemplate instance
* with different configuration, or a custom CciTemplate subclass.
* @param connectionFactory the CCI ConnectionFactory to create a CciTemplate for
* @return the new CciTemplate instance
* @see #setConnectionFactory(javax.resource.cci.ConnectionFactory)
*/
protected CciTemplate createCciTemplate(ConnectionFactory connectionFactory) {
return new CciTemplate(connectionFactory);
}
/**
* Return the ConnectionFactory used by this DAO.
*/
public final ConnectionFactory getConnectionFactory() {
return this.cciTemplate.getConnectionFactory();
}
/**
* Set the CciTemplate for this DAO explicitly,
* as an alternative to specifying a ConnectionFactory.
*/
public final void setCciTemplate(CciTemplate cciTemplate) {
this.cciTemplate = cciTemplate;
}
/**
* Return the CciTemplate for this DAO,
* pre-initialized with the ConnectionFactory or set explicitly.
*/
public final CciTemplate getCciTemplate() {
return this.cciTemplate;
}
protected final void checkDaoConfig() {
if (this.cciTemplate == null) {
throw new IllegalArgumentException("'connectionFactory' or 'cciTemplate' is required");
}
}
/**
* Obtain a CciTemplate derived from the main template instance,
* inheriting the ConnectionFactory and other settings but
* overriding the ConnectionSpec used for obtaining Connections.
* @param connectionSpec the CCI ConnectionSpec that the returned
* template instance is supposed to obtain Connections for
* @return the derived template instance
* @see org.springframework.jca.cci.core.CciTemplate#getDerivedTemplate(javax.resource.cci.ConnectionSpec)
*/
protected final CciTemplate getCciTemplate(ConnectionSpec connectionSpec) {
return getCciTemplate().getDerivedTemplate(connectionSpec);
}
/**
* Get a CCI Connection, either from the current transaction or a new one.
* @return the CCI Connection
* @throws org.springframework.jca.cci.CannotGetCciConnectionException
* if the attempt to get a Connection failed
* @see org.springframework.jca.cci.connection.ConnectionFactoryUtils#getConnection(javax.resource.cci.ConnectionFactory)
*/
protected final Connection getConnection() throws CannotGetCciConnectionException {
return ConnectionFactoryUtils.getConnection(getConnectionFactory());
}
/**
* Close the given CCI Connection, created via this bean's ConnectionFactory,
* if it isn't bound to the thread.
* @param con Connection to close
* @see org.springframework.jca.cci.connection.ConnectionFactoryUtils#releaseConnection
*/
protected final void releaseConnection(Connection con) {
ConnectionFactoryUtils.releaseConnection(con, getConnectionFactory());
}
}

View File

@ -0,0 +1,96 @@
/*
* 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.core.support;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.resource.cci.Record;
import javax.resource.cci.Streamable;
import org.springframework.util.FileCopyUtils;
/**
* CCI Record implementation for a COMMAREA, holding a byte array.
*
* @author Thierry Templier
* @author Juergen Hoeller
* @since 1.2
* @see org.springframework.jca.cci.object.MappingCommAreaOperation
*/
public class CommAreaRecord implements Record, Streamable {
private byte[] bytes;
private String recordName;
private String recordShortDescription;
/**
* Create a new CommAreaRecord.
* @see #read(java.io.InputStream)
*/
public CommAreaRecord() {
}
/**
* Create a new CommAreaRecord.
* @param bytes the bytes to fill the record with
*/
public CommAreaRecord(byte[] bytes) {
this.bytes = bytes;
}
public void setRecordName(String recordName) {
this.recordName=recordName;
}
public String getRecordName() {
return recordName;
}
public void setRecordShortDescription(String recordShortDescription) {
this.recordShortDescription=recordShortDescription;
}
public String getRecordShortDescription() {
return recordShortDescription;
}
public void read(InputStream in) throws IOException {
this.bytes = FileCopyUtils.copyToByteArray(in);
}
public void write(OutputStream out) throws IOException {
out.write(this.bytes);
out.flush();
}
public byte[] toByteArray() {
return this.bytes;
}
public Object clone() {
return new CommAreaRecord(this.bytes);
}
}

View File

@ -0,0 +1,8 @@
<html>
<body>
Classes supporting the <code>org.springframework.jca.cci.core</code> package.
Contains a DAO base class for CciTemplate usage.
</body>
</html>

View File

@ -0,0 +1,93 @@
/*
* 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.object;
import javax.resource.cci.ConnectionFactory;
import javax.resource.cci.InteractionSpec;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.jca.cci.core.CciTemplate;
/**
* Base class for EIS operation objects that work with the CCI API.
* Encapsulates a CCI ConnectionFactory and a CCI InteractionSpec.
*
* <p>Works with a CciTemplate instance underneath. EIS operation objects
* are an alternative to working with a CciTemplate directly.
*
* @author Juergen Hoeller
* @since 1.2
* @see #setConnectionFactory
* @see #setInteractionSpec
*/
public abstract class EisOperation implements InitializingBean {
private CciTemplate cciTemplate = new CciTemplate();
private InteractionSpec interactionSpec;
/**
* Set the CciTemplate to be used by this operation.
* Alternatively, specify a CCI ConnectionFactory.
* @see #setConnectionFactory
*/
public void setCciTemplate(CciTemplate cciTemplate) {
if (cciTemplate == null) {
throw new IllegalArgumentException("cciTemplate must not be null");
}
this.cciTemplate = cciTemplate;
}
/**
* Return the CciTemplate used by this operation.
*/
public CciTemplate getCciTemplate() {
return this.cciTemplate;
}
/**
* Set the CCI ConnectionFactory to be used by this operation.
*/
public void setConnectionFactory(ConnectionFactory connectionFactory) {
this.cciTemplate.setConnectionFactory(connectionFactory);
}
/**
* Set the CCI InteractionSpec for this operation.
*/
public void setInteractionSpec(InteractionSpec interactionSpec) {
this.interactionSpec = interactionSpec;
}
/**
* Return the CCI InteractionSpec for this operation.
*/
public InteractionSpec getInteractionSpec() {
return this.interactionSpec;
}
public void afterPropertiesSet() {
this.cciTemplate.afterPropertiesSet();
if (this.interactionSpec == null) {
throw new IllegalArgumentException("interactionSpec is required");
}
}
}

View File

@ -0,0 +1,95 @@
/*
* 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.object;
import java.io.IOException;
import javax.resource.cci.ConnectionFactory;
import javax.resource.cci.InteractionSpec;
import javax.resource.cci.Record;
import javax.resource.cci.RecordFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.jca.cci.core.support.CommAreaRecord;
/**
* EIS operation object for access to COMMAREA records.
* Subclass of the generic MappingRecordOperation class.
*
* @author Thierry Templier
* @since 1.2
*/
public abstract class MappingCommAreaOperation extends MappingRecordOperation {
/**
* Create a new MappingCommAreaQuery.
* @see #setConnectionFactory
* @see #setInteractionSpec
*/
public MappingCommAreaOperation() {
}
/**
* Create a new MappingCommAreaQuery.
* @param connectionFactory ConnectionFactory to use to obtain connections
* @param interactionSpec specification to configure the interaction
*/
public MappingCommAreaOperation(ConnectionFactory connectionFactory, InteractionSpec interactionSpec) {
super(connectionFactory, interactionSpec);
}
protected final Record createInputRecord(RecordFactory recordFactory, Object inObject) {
try {
return new CommAreaRecord(objectToBytes(inObject));
}
catch (IOException ex) {
throw new DataRetrievalFailureException("I/O exception during bytes conversion", ex);
}
}
protected final Object extractOutputData(Record record) throws DataAccessException {
CommAreaRecord commAreaRecord = (CommAreaRecord) record;
try {
return bytesToObject(commAreaRecord.toByteArray());
}
catch (IOException ex) {
throw new DataRetrievalFailureException("I/O exception during bytes conversion", ex);
}
}
/**
* Method used to convert an object into COMMAREA bytes.
* @param inObject the input data
* @return the COMMAREA's bytes
* @throws IOException if thrown by I/O methods
* @throws DataAccessException if conversion failed
*/
protected abstract byte[] objectToBytes(Object inObject) throws IOException, DataAccessException;
/**
* Method used to convert the COMMAREA's bytes to an object.
* @param bytes the COMMAREA's bytes
* @return the output data
* @throws IOException if thrown by I/O methods
* @throws DataAccessException if conversion failed
*/
protected abstract Object bytesToObject(byte[] bytes) throws IOException, DataAccessException;
}

View File

@ -0,0 +1,149 @@
/*
* 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.object;
import java.sql.SQLException;
import javax.resource.ResourceException;
import javax.resource.cci.ConnectionFactory;
import javax.resource.cci.InteractionSpec;
import javax.resource.cci.Record;
import javax.resource.cci.RecordFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.jca.cci.core.RecordCreator;
import org.springframework.jca.cci.core.RecordExtractor;
/**
* EIS operation object that expects mapped input and output objects,
* converting to and from CCI Records.
*
* <p>Concrete subclasses must implement the abstract
* <code>createInputRecord(RecordFactory, Object)</code> and
* <code>extractOutputData(Record)</code> methods, to create an input
* Record from an object and to convert an output Record into an object,
* respectively.
*
* @author Thierry Templier
* @author Juergen Hoeller
* @since 1.2
* @see #createInputRecord(javax.resource.cci.RecordFactory, Object)
* @see #extractOutputData(javax.resource.cci.Record)
*/
public abstract class MappingRecordOperation extends EisOperation {
/**
* Constructor that allows use as a JavaBean.
*/
public MappingRecordOperation() {
}
/**
* Convenient constructor with ConnectionFactory and specifications
* (connection and interaction).
* @param connectionFactory ConnectionFactory to use to obtain connections
*/
public MappingRecordOperation(ConnectionFactory connectionFactory, InteractionSpec interactionSpec) {
getCciTemplate().setConnectionFactory(connectionFactory);
setInteractionSpec(interactionSpec);
}
/**
* Set a RecordCreator that should be used for creating default output Records.
* <p>Default is none: CCI's <code>Interaction.execute</code> variant
* that returns an output Record will be called.
* <p>Specify a RecordCreator here if you always need to call CCI's
* <code>Interaction.execute</code> variant with a passed-in output Record.
* This RecordCreator will then be invoked to create a default output Record instance.
* @see javax.resource.cci.Interaction#execute(javax.resource.cci.InteractionSpec, Record)
* @see javax.resource.cci.Interaction#execute(javax.resource.cci.InteractionSpec, Record, Record)
* @see org.springframework.jca.cci.core.CciTemplate#setOutputRecordCreator
*/
public void setOutputRecordCreator(RecordCreator creator) {
getCciTemplate().setOutputRecordCreator(creator);
}
/**
* Execute the interaction encapsulated by this operation object.
* @param inputObject the input data, to be converted to a Record
* by the <code>createInputRecord</code> method
* @return the output data extracted with the <code>extractOutputData</code> method
* @throws DataAccessException if there is any problem
* @see #createInputRecord
* @see #extractOutputData
*/
public Object execute(Object inputObject) throws DataAccessException {
return getCciTemplate().execute(
getInteractionSpec(), new RecordCreatorImpl(inputObject), new RecordExtractorImpl());
}
/**
* Subclasses must implement this method to generate an input Record
* from an input object passed into the <code>execute</code> method.
* @param inputObject the passed-in input object
* @return the CCI input Record
* @throws ResourceException if thrown by a CCI method, to be auto-converted
* to a DataAccessException
* @see #execute(Object)
*/
protected abstract Record createInputRecord(RecordFactory recordFactory, Object inputObject)
throws ResourceException, DataAccessException;
/**
* Subclasses must implement this method to convert the Record returned
* by CCI execution into a result object for the <code>execute</code> method.
* @param outputRecord the Record returned by CCI execution
* @return the result object
* @throws ResourceException if thrown by a CCI method, to be auto-converted
* to a DataAccessException
* @see #execute(Object)
*/
protected abstract Object extractOutputData(Record outputRecord)
throws ResourceException, SQLException, DataAccessException;
/**
* Implementation of RecordCreator that calls the enclosing
* class's <code>createInputRecord</code> method.
*/
protected class RecordCreatorImpl implements RecordCreator {
private final Object inputObject;
public RecordCreatorImpl(Object inObject) {
this.inputObject = inObject;
}
public Record createRecord(RecordFactory recordFactory) throws ResourceException, DataAccessException {
return createInputRecord(recordFactory, this.inputObject);
}
}
/**
* Implementation of RecordExtractor that calls the enclosing
* class's <code>extractOutputData</code> method.
*/
protected class RecordExtractorImpl implements RecordExtractor {
public Object extractData(Record record) throws ResourceException, SQLException, DataAccessException {
return extractOutputData(record);
}
}
}

View File

@ -0,0 +1,76 @@
/*
* 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.object;
import javax.resource.cci.ConnectionFactory;
import javax.resource.cci.InteractionSpec;
import javax.resource.cci.Record;
import org.springframework.dao.DataAccessException;
/**
* EIS operation object that accepts a passed-in CCI input Record
* and returns a corresponding CCI output Record.
*
* @author Juergen Hoeller
* @since 1.2
*/
public class SimpleRecordOperation extends EisOperation {
/**
* Constructor that allows use as a JavaBean.
*/
public SimpleRecordOperation() {
}
/**
* Convenient constructor with ConnectionFactory and specifications
* (connection and interaction).
* @param connectionFactory ConnectionFactory to use to obtain connections
*/
public SimpleRecordOperation(ConnectionFactory connectionFactory, InteractionSpec interactionSpec) {
getCciTemplate().setConnectionFactory(connectionFactory);
setInteractionSpec(interactionSpec);
}
/**
* Execute the CCI interaction encapsulated by this operation object.
* <p>This method will call CCI's <code>Interaction.execute</code> variant
* that returns an output Record.
* @param inputRecord the input record
* @return the output record
* @throws DataAccessException if there is any problem
* @see javax.resource.cci.Interaction#execute(javax.resource.cci.InteractionSpec, Record)
*/
public Record execute(Record inputRecord) throws DataAccessException {
return getCciTemplate().execute(getInteractionSpec(), inputRecord);
}
/**
* Execute the CCI interaction encapsulated by this operation object.
* <p>This method will call CCI's <code>Interaction.execute</code> variant
* with a passed-in output Record.
* @param inputRecord the input record
* @param outputRecord the output record
* @throws DataAccessException if there is any problem
* @see javax.resource.cci.Interaction#execute(javax.resource.cci.InteractionSpec, Record, Record)
*/
public void execute(Record inputRecord, Record outputRecord) throws DataAccessException {
getCciTemplate().execute(getInteractionSpec(), inputRecord, outputRecord);
}
}

View File

@ -0,0 +1,11 @@
<html>
<body>
The classes in this package represent EIS operations as threadsafe,
reusable objects. This higher level of CCI abstraction depends on the
lower-level abstraction in the <code>org.springframework.jca.cci.core</code> package.
Exceptions thrown are as in the <code>org.springframework.dao</code> package,
meaning that code using this package does not need to worry about error handling.
</body>
</html>

View File

@ -0,0 +1,10 @@
<html>
<body>
This package contains Spring's support for the Common Client Interface (CCI),
as defined by the J2EE Connector Architecture. It is conceptually similar
to the <code>org.springframework.jdbc</code> package, providing the same
levels of data access abstraction.
</body>
</html>

View File

@ -0,0 +1,44 @@
/*
* 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.jca.context;
import javax.resource.spi.BootstrapContext;
/**
* Interface to be implemented by any object that wishes to be
* notified of the BootstrapContext (typically determined by the
* {@link ResourceAdapterApplicationContext}) that it runs in.
*
* @author Juergen Hoeller
* @since 2.5
* @see javax.resource.spi.BootstrapContext
*/
public interface BootstrapContextAware {
/**
* Set the BootstrapContext that this object runs in.
* <p>Invoked after population of normal bean properties but before an init
* callback like InitializingBean's <code>afterPropertiesSet</code> or a
* custom init-method. Invoked after ApplicationContextAware's
* <code>setApplicationContext</code>.
* @param bootstrapContext BootstrapContext object to be used by this object
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
* @see org.springframework.context.ApplicationContextAware#setApplicationContext
*/
void setBootstrapContext(BootstrapContext bootstrapContext);
}

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.jca.context;
import javax.resource.spi.BootstrapContext;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
* {@link org.springframework.beans.factory.config.BeanPostProcessor}
* implementation that passes the BootstrapContext to beans that implement
* the {@link BootstrapContextAware} interface.
*
* <p>{@link ResourceAdapterApplicationContext} automatically registers
* this processor with its underlying bean factory.
*
* @author Juergen Hoeller
* @since 2.5
* @see BootstrapContextAware
*/
class BootstrapContextAwareProcessor implements BeanPostProcessor {
private final BootstrapContext bootstrapContext;
/**
* Create a new BootstrapContextAwareProcessor for the given context.
*/
public BootstrapContextAwareProcessor(BootstrapContext bootstrapContext) {
this.bootstrapContext = bootstrapContext;
}
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (this.bootstrapContext != null && bean instanceof BootstrapContextAware) {
((BootstrapContextAware) bean).setBootstrapContext(this.bootstrapContext);
}
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}

View File

@ -0,0 +1,68 @@
/*
* 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.jca.context;
import javax.resource.spi.BootstrapContext;
import javax.resource.spi.work.WorkManager;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.util.Assert;
/**
* {@link org.springframework.context.ApplicationContext} implementation
* for a JCA ResourceAdapter. Needs to be initialized with the JCA
* {@link javax.resource.spi.BootstrapContext}, passing it on to
* Spring-managed beans that implement {@link BootstrapContextAware}.
*
* @author Juergen Hoeller
* @since 2.5
* @see SpringContextResourceAdapter
* @see BootstrapContextAware
*/
public class ResourceAdapterApplicationContext extends GenericApplicationContext {
private final BootstrapContext bootstrapContext;
/**
* Create a new ResourceAdapterApplicationContext for the given BootstrapContext.
* @param bootstrapContext the JCA BootstrapContext that the ResourceAdapter
* has been started with
*/
public ResourceAdapterApplicationContext(BootstrapContext bootstrapContext) {
Assert.notNull(bootstrapContext, "BootstrapContext must not be null");
this.bootstrapContext = bootstrapContext;
}
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
beanFactory.addBeanPostProcessor(new BootstrapContextAwareProcessor(this.bootstrapContext));
beanFactory.ignoreDependencyInterface(BootstrapContextAware.class);
beanFactory.registerResolvableDependency(BootstrapContext.class, this.bootstrapContext);
// JCA WorkManager resolved lazily - may not be available.
beanFactory.registerResolvableDependency(WorkManager.class, new ObjectFactory() {
public Object getObject() {
return bootstrapContext.getWorkManager();
}
});
}
}

View File

@ -0,0 +1,221 @@
/*
* 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.jca.context;
import javax.resource.NotSupportedException;
import javax.resource.ResourceException;
import javax.resource.spi.ActivationSpec;
import javax.resource.spi.BootstrapContext;
import javax.resource.spi.ResourceAdapter;
import javax.resource.spi.ResourceAdapterInternalException;
import javax.resource.spi.endpoint.MessageEndpointFactory;
import javax.transaction.xa.XAResource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.util.StringUtils;
/**
* JCA 1.5 {@link javax.resource.spi.ResourceAdapter} implementation
* that loads a Spring {@link org.springframework.context.ApplicationContext},
* starting and stopping Spring-managed beans as part of the ResourceAdapter's
* lifecycle.
*
* <p>Ideal for application contexts that do not need any HTTP entry points
* but rather just consist of message endpoints and scheduled jobs etc.
* Beans in such a context may use application server resources such as the
* JTA transaction manager and JNDI-bound JDBC DataSources and JMS
* ConnectionFactory instances, and may also register with the platform's
* JMX server - all through Spring's standard transaction management and
* JNDI and JMX support facilities.
*
* <p>If the need for scheduling asynchronous work arises, consider using
* Spring's {@link org.springframework.jca.work.WorkManagerTaskExecutor}
* as a standard bean definition, to be injected into application beans
* through dependency injection. This WorkManagerTaskExecutor will automatically
* use the JCA WorkManager from the BootstrapContext that has been provided
* to this ResourceAdapter.
*
* <p>The JCA {@link javax.resource.spi.BootstrapContext} may also be
* accessed directly, through application components that implement the
* {@link BootstrapContextAware} interface. When deployed using this
* ResourceAdapter, the BootstrapContext is guaranteed to be passed on
* to such components.
*
* <p>This ResourceAdapter is to be defined in a "META-INF/ra.xml" file
* within a J2EE ".rar" deployment unit like as follows:
*
* <pre class="code">
* &lt;?xml version="1.0" encoding="UTF-8"?&gt;
* &lt;connector xmlns="http://java.sun.com/xml/ns/j2ee"
* xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
* xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/connector_1_5.xsd"
* version="1.5"&gt;
* &lt;vendor-name&gt;Spring Framework&lt;/vendor-name&gt;
* &lt;eis-type&gt;Spring Connector&lt;/eis-type&gt;
* &lt;resourceadapter-version&gt;1.0&lt;/resourceadapter-version&gt;
* &lt;resourceadapter&gt;
* &lt;resourceadapter-class&gt;org.springframework.jca.context.SpringContextResourceAdapter&lt;/resourceadapter-class&gt;
* &lt;config-property&gt;
* &lt;config-property-name&gt;ContextConfigLocation&lt;/config-property-name&gt;
* &lt;config-property-type&gt;java.lang.String&lt;/config-property-type&gt;
* &lt;config-property-value&gt;META-INF/applicationContext.xml&lt;/config-property-value&gt;
* &lt;/config-property&gt;
* &lt;/resourceadapter&gt;
* &lt;/connector&gt;</pre>
*
* Note that "META-INF/applicationContext.xml" is the default context config
* location, so it doesn't have to specified unless you intend to specify
* different/additional config files. So in the default case, you may remove
* the entire <code>config-property</code> section above.
*
* <p><b>For simple deployment needs, all you need to do is the following:</b>
* Package all application classes into a RAR file (which is just a standard
* JAR file with a different file extension), add all required library jars
* into the root of the RAR archive, add a "META-INF/ra.xml" deployment
* descriptor as shown above as well as the corresponding Spring XML bean
* definition file(s) (typically "META-INF/applicationContext.xml"),
* and drop the resulting RAR file into your application server's
* deployment directory!
*
* @author Juergen Hoeller
* @since 2.5
* @see #setContextConfigLocation
* @see #loadBeanDefinitions
* @see ResourceAdapterApplicationContext
*/
public class SpringContextResourceAdapter implements ResourceAdapter {
/**
* Any number of these characters are considered delimiters between
* multiple context config paths in a single String value.
* @see #setContextConfigLocation
*/
public static final String CONFIG_LOCATION_DELIMITERS = ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS;
public static final String DEFAULT_CONTEXT_CONFIG_LOCATION = "META-INF/applicationContext.xml";
protected final Log logger = LogFactory.getLog(getClass());
private String contextConfigLocation = DEFAULT_CONTEXT_CONFIG_LOCATION;
private ConfigurableApplicationContext applicationContext;
/**
* Set the location of the context configuration files, within the
* resource adapter's deployment unit. This can be a delimited
* String that consists of multiple resource location, separated
* by commas, semicolons, whitespace, or line breaks.
* <p>This can be specified as "ContextConfigLocation" config
* property in the <code>ra.xml</code> deployment descriptor.
* <p>The default is "classpath:META-INF/applicationContext.xml".
*/
public void setContextConfigLocation(String contextConfigLocation) {
this.contextConfigLocation = contextConfigLocation;
}
/**
* Return the specified context configuration files.
*/
protected String getContextConfigLocation() {
return this.contextConfigLocation;
}
/**
* This implementation loads a Spring ApplicationContext through the
* {@link #createApplicationContext} template method.
*/
public void start(BootstrapContext bootstrapContext) throws ResourceAdapterInternalException {
if (logger.isInfoEnabled()) {
logger.info("Starting SpringContextResourceAdapter with BootstrapContext: " + bootstrapContext);
}
this.applicationContext = createApplicationContext(bootstrapContext);
}
/**
* Build a Spring ApplicationContext for the given JCA BootstrapContext.
* <p>The default implementation builds a {@link ResourceAdapterApplicationContext}
* and delegates to {@link #loadBeanDefinitions} for actually parsing the
* specified configuration files.
* @param bootstrapContext this ResourceAdapter's BootstrapContext
* @return the Spring ApplicationContext instance
*/
protected ConfigurableApplicationContext createApplicationContext(BootstrapContext bootstrapContext) {
ResourceAdapterApplicationContext applicationContext =
new ResourceAdapterApplicationContext(bootstrapContext);
// Set ResourceAdapter's ClassLoader as bean class loader.
applicationContext.setClassLoader(getClass().getClassLoader());
// Extract individual config locations.
String[] configLocations =
StringUtils.tokenizeToStringArray(getContextConfigLocation(), CONFIG_LOCATION_DELIMITERS);
if (configLocations != null) {
loadBeanDefinitions(applicationContext, configLocations);
}
applicationContext.refresh();
return applicationContext;
}
/**
* Load the bean definitions into the given registry,
* based on the specified configuration files.
* @param registry the registry to load into
* @param configLocations the parsed config locations
* @see #setContextConfigLocation
*/
protected void loadBeanDefinitions(BeanDefinitionRegistry registry, String[] configLocations) {
new XmlBeanDefinitionReader(registry).loadBeanDefinitions(configLocations);
}
/**
* This implementation closes the Spring ApplicationContext.
*/
public void stop() {
logger.info("Stopping SpringContextResourceAdapter");
this.applicationContext.close();
}
/**
* This implementation always throws a NotSupportedException.
*/
public void endpointActivation(MessageEndpointFactory messageEndpointFactory, ActivationSpec activationSpec)
throws ResourceException {
throw new NotSupportedException("SpringContextResourceAdapter does not support message endpoints");
}
/**
* This implementation does nothing.
*/
public void endpointDeactivation(MessageEndpointFactory messageEndpointFactory, ActivationSpec activationSpec) {
}
/**
* This implementation always returns <code>null</code>.
*/
public XAResource[] getXAResources(ActivationSpec[] activationSpecs) throws ResourceException {
return null;
}
}

View File

@ -0,0 +1,8 @@
<html>
<body>
Integration package that allows for deploying a Spring application context
as a JCA 1.5 compliant RAR file.
</body>
</html>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<connector xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/connector_1_5.xsd"
version="1.5">
<vendor-name>Spring Framework</vendor-name>
<eis-type>Spring Connector</eis-type>
<resourceadapter-version>1.0</resourceadapter-version>
<resourceadapter>
<resourceadapter-class>org.springframework.jca.context.SpringContextResourceAdapter</resourceadapter-class>
<config-property>
<config-property-name>ContextConfigLocation</config-property-name>
<config-property-type>java.lang.String</config-property-type>
<config-property-value>META-INF/applicationContext.xml</config-property-value>
</config-property>
</resourceadapter>
</connector>

View File

@ -0,0 +1,303 @@
/*
* 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.jca.endpoint;
import java.lang.reflect.Method;
import javax.resource.ResourceException;
import javax.resource.spi.ApplicationServerInternalException;
import javax.resource.spi.UnavailableException;
import javax.resource.spi.endpoint.MessageEndpoint;
import javax.resource.spi.endpoint.MessageEndpointFactory;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import javax.transaction.xa.XAResource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.transaction.jta.SimpleTransactionFactory;
import org.springframework.transaction.jta.TransactionFactory;
/**
* Abstract base implementation of the JCA 1.5
* {@link javax.resource.spi.endpoint.MessageEndpointFactory} interface,
* providing transaction management capabilities as well as ClassLoader
* exposure for endpoint invocations.
*
* @author Juergen Hoeller
* @since 2.5
* @see #setTransactionManager
*/
public abstract class AbstractMessageEndpointFactory implements MessageEndpointFactory {
/** Logger available to subclasses */
protected final Log logger = LogFactory.getLog(getClass());
private TransactionFactory transactionFactory;
private String transactionName;
private int transactionTimeout = -1;
/**
* Set the the XA transaction manager to use for wrapping endpoint
* invocations, enlisting the endpoint resource in each such transaction.
* <p>The passed-in object may be a transaction manager which implements
* Spring's {@link org.springframework.transaction.jta.TransactionFactory}
* interface, or a plain {@link javax.transaction.TransactionManager}.
* <p>If no transaction manager is specified, the endpoint invocation
* will simply not be wrapped in an XA transaction. Check out your
* resource provider's ActivationSpec documentation for local
* transaction options of your particular provider.
* @see #setTransactionName
* @see #setTransactionTimeout
*/
public void setTransactionManager(Object transactionManager) {
if (transactionManager instanceof TransactionFactory) {
this.transactionFactory = (TransactionFactory) transactionManager;
}
else if (transactionManager instanceof TransactionManager) {
this.transactionFactory = new SimpleTransactionFactory((TransactionManager) transactionManager);
}
else {
throw new IllegalArgumentException("Transaction manager [" + transactionManager +
"] is neither a [org.springframework.transaction.jta.TransactionFactory} nor a " +
"[javax.transaction.TransactionManager]");
}
}
/**
* Set the Spring TransactionFactory to use for wrapping endpoint
* invocations, enlisting the endpoint resource in each such transaction.
* <p>Alternatively, specify an appropriate transaction manager through
* the {@link #setTransactionManager "transactionManager"} property.
* <p>If no transaction factory is specified, the endpoint invocation
* will simply not be wrapped in an XA transaction. Check out your
* resource provider's ActivationSpec documentation for local
* transaction options of your particular provider.
* @see #setTransactionName
* @see #setTransactionTimeout
*/
public void setTransactionFactory(TransactionFactory transactionFactory) {
this.transactionFactory = transactionFactory;
}
/**
* Specify the name of the transaction, if any.
* <p>Default is none. A specified name will be passed on to the transaction
* manager, allowing to identify the transaction in a transaction monitor.
*/
public void setTransactionName(String transactionName) {
this.transactionName = transactionName;
}
/**
* Specify the transaction timeout, if any.
* <p>Default is -1: rely on the transaction manager's default timeout.
* Specify a concrete timeout to restrict the maximum duration of each
* endpoint invocation.
*/
public void setTransactionTimeout(int transactionTimeout) {
this.transactionTimeout = transactionTimeout;
}
/**
* This implementation returns <code>true</code> if a transaction manager
* has been specified; <code>false</code> otherwise.
* @see #setTransactionManager
* @see #setTransactionFactory
*/
public boolean isDeliveryTransacted(Method method) throws NoSuchMethodException {
return (this.transactionFactory != null);
}
/**
* This implementation delegates to {@link #createEndpointInternal()},
* initializing the endpoint's XAResource before the endpoint gets invoked.
*/
public MessageEndpoint createEndpoint(XAResource xaResource) throws UnavailableException {
AbstractMessageEndpoint endpoint = createEndpointInternal();
endpoint.initXAResource(xaResource);
return endpoint;
}
/**
* Create the actual endpoint instance, as a subclass of the
* {@link AbstractMessageEndpoint} inner class of this factory.
* @return the actual endpoint instance (never <code>null</code>)
* @throws UnavailableException if no endpoint is available at present
*/
protected abstract AbstractMessageEndpoint createEndpointInternal()
throws UnavailableException;
/**
* Inner class for actual endpoint implementations, based on template
* method to allow for any kind of concrete endpoint implementation.
*/
protected abstract class AbstractMessageEndpoint implements MessageEndpoint {
private TransactionDelegate transactionDelegate;
private boolean beforeDeliveryCalled = false;
private ClassLoader previousContextClassLoader;
/**
* Initialize this endpoint's TransactionDelegate.
* @param xaResource the XAResource for this endpoint
*/
void initXAResource(XAResource xaResource) {
this.transactionDelegate = new TransactionDelegate(xaResource);
}
/**
* This <code>beforeDelivery</code> implementation starts a transaction,
* if necessary, and exposes the endpoint ClassLoader as current
* thread context ClassLoader.
* <p>Note that the JCA 1.5 specification does not require a ResourceAdapter
* to call this method before invoking the concrete endpoint. If this method
* has not been called (check {@link #hasBeforeDeliveryBeenCalled()}), the
* concrete endpoint method should call <code>beforeDelivery</code> and its
* sibling {@link #afterDelivery()} explicitly, as part of its own processing.
*/
public void beforeDelivery(Method method) throws ResourceException {
this.beforeDeliveryCalled = true;
try {
this.transactionDelegate.beginTransaction();
}
catch (Throwable ex) {
throw new ApplicationServerInternalException("Failed to begin transaction", ex);
}
Thread currentThread = Thread.currentThread();
this.previousContextClassLoader = currentThread.getContextClassLoader();
currentThread.setContextClassLoader(getEndpointClassLoader());
}
/**
* Template method for exposing the endpoint's ClassLoader
* (typically the ClassLoader that the message listener class
* has been loaded with).
* @return the endpoint ClassLoader (never <code>null</code>)
*/
protected abstract ClassLoader getEndpointClassLoader();
/**
* Return whether the {@link #beforeDelivery} method of this endpoint
* has already been called.
*/
protected final boolean hasBeforeDeliveryBeenCalled() {
return this.beforeDeliveryCalled;
}
/**
* Callback method for notifying the endpoint base class
* that the concrete endpoint invocation led to an exception.
* <p>To be invoked by subclasses in case of the concrete
* endpoint throwing an exception.
* @param ex the exception thrown from the concrete endpoint
*/
protected final void onEndpointException(Throwable ex) {
this.transactionDelegate.setRollbackOnly();
}
/**
* This <code>afterDelivery</code> implementation resets the thread context
* ClassLoader and completes the transaction, if any.
* <p>Note that the JCA 1.5 specification does not require a ResourceAdapter
* to call this method after invoking the concrete endpoint. See the
* explanation in {@link #beforeDelivery}'s javadoc.
*/
public void afterDelivery() throws ResourceException {
this.beforeDeliveryCalled = false;
Thread.currentThread().setContextClassLoader(this.previousContextClassLoader);
this.previousContextClassLoader = null;
try {
this.transactionDelegate.endTransaction();
}
catch (Throwable ex) {
throw new ApplicationServerInternalException("Failed to complete transaction", ex);
}
}
public void release() {
try {
this.transactionDelegate.setRollbackOnly();
this.transactionDelegate.endTransaction();
}
catch (Throwable ex) {
logger.error("Could not complete unfinished transaction on endpoint release", ex);
}
}
}
/**
* Private inner class that performs the actual transaction handling,
* including enlistment of the endpoint's XAResource.
*/
private class TransactionDelegate {
private XAResource xaResource;
private Transaction transaction;
private boolean rollbackOnly;
public TransactionDelegate(XAResource xaResource) {
if (transactionFactory != null && xaResource == null) {
throw new IllegalStateException("ResourceAdapter-provided XAResource is required for " +
"transaction management. Check your ResourceAdapter's configuration.");
}
this.xaResource = xaResource;
}
public void beginTransaction() throws Exception {
if (transactionFactory != null) {
this.transaction = transactionFactory.createTransaction(transactionName, transactionTimeout);
this.transaction.enlistResource(this.xaResource);
}
}
public void setRollbackOnly() {
if (this.transaction != null) {
this.rollbackOnly = true;
}
}
public void endTransaction() throws Exception {
if (this.transaction != null) {
try {
if (this.rollbackOnly) {
this.transaction.rollback();
}
else {
this.transaction.commit();
}
}
finally {
this.transaction = null;
this.rollbackOnly = false;
}
}
}
}
}

View File

@ -0,0 +1,155 @@
/*
* 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.jca.endpoint;
import javax.resource.ResourceException;
import javax.resource.spi.UnavailableException;
import javax.resource.spi.endpoint.MessageEndpoint;
import javax.transaction.xa.XAResource;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DelegatingIntroductionInterceptor;
import org.springframework.util.ReflectionUtils;
/**
* Generic implementation of the JCA 1.5
* {@link javax.resource.spi.endpoint.MessageEndpointFactory} interface,
* providing transaction management capabilities for any kind of message
* listener object (e.g. {@link javax.jms.MessageListener} objects or
* {@link javax.resource.cci.MessageListener} objects.
*
* <p>Uses AOP proxies for concrete endpoint instances, simply wrapping
* the specified message listener object and exposing all of its implemented
* interfaces on the endpoint instance.
*
* <p>Typically used with Spring's {@link GenericMessageEndpointManager},
* but not tied to it. As a consequence, this endpoint factory could
* also be used with programmatic endpoint management on a native
* {@link javax.resource.spi.ResourceAdapter} instance.
*
* @author Juergen Hoeller
* @since 2.5
* @see #setMessageListener
* @see #setTransactionManager
* @see GenericMessageEndpointManager
*/
public class GenericMessageEndpointFactory extends AbstractMessageEndpointFactory {
private Object messageListener;
/**
* Specify the message listener object that the endpoint should expose
* (e.g. a {@link javax.jms.MessageListener} objects or
* {@link javax.resource.cci.MessageListener} implementation).
*/
public void setMessageListener(Object messageListener) {
this.messageListener = messageListener;
}
/**
* Wrap each concrete endpoint instance with an AOP proxy,
* exposing the message listener's interfaces as well as the
* endpoint SPI through an AOP introduction.
*/
public MessageEndpoint createEndpoint(XAResource xaResource) throws UnavailableException {
GenericMessageEndpoint endpoint = (GenericMessageEndpoint) super.createEndpoint(xaResource);
ProxyFactory proxyFactory = new ProxyFactory(this.messageListener);
DelegatingIntroductionInterceptor introduction = new DelegatingIntroductionInterceptor(endpoint);
introduction.suppressInterface(MethodInterceptor.class);
proxyFactory.addAdvice(introduction);
return (MessageEndpoint) proxyFactory.getProxy();
}
/**
* Creates a concrete generic message endpoint, internal to this factory.
*/
protected AbstractMessageEndpoint createEndpointInternal() throws UnavailableException {
return new GenericMessageEndpoint();
}
/**
* Private inner class that implements the concrete generic message endpoint,
* as an AOP Alliance MethodInterceptor that will be invoked by a proxy.
*/
private class GenericMessageEndpoint extends AbstractMessageEndpoint implements MethodInterceptor {
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
boolean applyDeliveryCalls = !hasBeforeDeliveryBeenCalled();
if (applyDeliveryCalls) {
try {
beforeDelivery(null);
}
catch (ResourceException ex) {
if (ReflectionUtils.declaresException(methodInvocation.getMethod(), ex.getClass())) {
throw ex;
}
else {
throw new InternalResourceException(ex);
}
}
}
try {
return methodInvocation.proceed();
}
catch (Throwable ex) {
onEndpointException(ex);
throw ex;
}
finally {
if (applyDeliveryCalls) {
try {
afterDelivery();
}
catch (ResourceException ex) {
if (ReflectionUtils.declaresException(methodInvocation.getMethod(), ex.getClass())) {
throw ex;
}
else {
throw new InternalResourceException(ex);
}
}
}
}
}
protected ClassLoader getEndpointClassLoader() {
return messageListener.getClass().getClassLoader();
}
}
/**
* Internal exception thrown when a ResourceExeption has been encountered
* during the endpoint invocation.
* <p>Will only be used if the ResourceAdapter does not invoke the
* endpoint's <code>beforeDelivery</code> and <code>afterDelivery</code>
* directly, leavng it up to the concrete endpoint to apply those -
* and to handle any ResourceExceptions thrown from them.
*/
public static class InternalResourceException extends RuntimeException {
protected InternalResourceException(ResourceException cause) {
super(cause);
}
}
}

View File

@ -0,0 +1,298 @@
/*
* 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.jca.endpoint;
import javax.resource.ResourceException;
import javax.resource.spi.ActivationSpec;
import javax.resource.spi.ResourceAdapter;
import javax.resource.spi.endpoint.MessageEndpointFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.Lifecycle;
/**
* Generic bean that manages JCA 1.5 message endpoints within a Spring
* application context, activating and deactivating the endpoint as part
* of the application context's lifecycle.
*
* <p>This class is completely generic in that it may work with any
* ResourceAdapter, any MessageEndpointFactory, and any ActivationSpec.
* It can be configured in standard bean style, for example through
* Spring's XML bean definition format, as follows:
*
* <pre class="code">
* &lt;bean class="org.springframework.jca.endpoint.GenericMessageEndpointManager"&gt;
* &lt;property name="resourceAdapter" ref="resourceAdapter"/&gt;
* &lt;property name="messageEndpointFactory"&gt;
* &lt;bean class="org.springframework.jca.endpoint.GenericMessageEndpointFactory"&gt;
* &lt;property name="messageListener" ref="messageListener"/&gt;
* &lt;/bean&gt;
* &lt;/property&gt;
* &lt;property name="activationSpec"&gt;
* &lt;bean class="org.apache.activemq.ra.ActiveMQActivationSpec"&gt;
* &lt;property name="destination" value="myQueue"/&gt;
* &lt;property name="destinationType" value="javax.jms.Queue"/&gt;
* &lt;/bean&gt;
* &lt;/property&gt;
* &lt;/bean&gt;</pre>
*
* In this example, Spring's own {@link GenericMessageEndpointFactory} is used
* to point to a standard message listener object that happens to be supported
* by the specified target ResourceAdapter: in this case, a JMS
* {@link javax.jms.MessageListener} object as supported by the ActiveMQ
* message broker, defined as a Spring bean:
*
* <pre class="code">
* &lt;bean id="messageListener" class="com.myorg.messaging.myMessageListener"&gt;
* ...
* &lt;/bean&gt;</pre>
*
* The target ResourceAdapter may be configured as a local Spring bean as well
* (the typical case) or obtained from JNDI (e.g. on WebLogic). For the
* example above, a local ResourceAdapter bean could be defined as follows
* (matching the "resourceAdapter" bean reference above):
*
* <pre class="code">
* &lt;bean id="resourceAdapter" class="org.springframework.jca.support.ResourceAdapterFactoryBean"&gt;
* &lt;property name="resourceAdapter"&gt;
* &lt;bean class="org.apache.activemq.ra.ActiveMQResourceAdapter"&gt;
* &lt;property name="serverUrl" value="tcp://localhost:61616"/&gt;
* &lt;/bean&gt;
* &lt;/property&gt;
* &lt;property name="workManager"&gt;
* &lt;bean class="org.springframework.jca.work.SimpleTaskWorkManager"/&gt;
* &lt;/property&gt;
* &lt;/bean&gt;</pre>
*
* For a different target resource, the configuration would simply point to a
* different ResourceAdapter and a different ActivationSpec object (which are
* both specific to the resource provider), and possibly a different message
* listener (e.g. a CCI {@link javax.resource.cci.MessageListener} for a
* resource adapter which is based on the JCA Common Client Interface).
*
* <p>The asynchronous execution strategy can be customized through the
* "workManager" property on the ResourceAdapterFactoryBean (as shown above).
* Check out {@link org.springframework.jca.work.SimpleTaskWorkManager}'s
* javadoc for its configuration options; alternatively, any other
* JCA-compliant WorkManager can be used (e.g. Geronimo's).
*
* <p>Transactional execution is a responsibility of the concrete message endpoint,
* as built by the specified MessageEndpointFactory. {@link GenericMessageEndpointFactory}
* supports XA transaction participation through its "transactionManager" property,
* typically with a Spring {@link org.springframework.transaction.jta.JtaTransactionManager}
* or a plain {@link javax.transaction.TransactionManager} implementation specified there.
*
* <pre class="code">
* &lt;bean class="org.springframework.jca.endpoint.GenericMessageEndpointManager"&gt;
* &lt;property name="resourceAdapter" ref="resourceAdapter"/&gt;
* &lt;property name="messageEndpointFactory"&gt;
* &lt;bean class="org.springframework.jca.endpoint.GenericMessageEndpointFactory"&gt;
* &lt;property name="messageListener" ref="messageListener"/&gt;
* &lt;property name="transactionManager" ref="transactionManager"/&gt;
* &lt;/bean&gt;
* &lt;/property&gt;
* &lt;property name="activationSpec"&gt;
* &lt;bean class="org.apache.activemq.ra.ActiveMQActivationSpec"&gt;
* &lt;property name="destination" value="myQueue"/&gt;
* &lt;property name="destinationType" value="javax.jms.Queue"/&gt;
* &lt;/bean&gt;
* &lt;/property&gt;
* &lt;/bean&gt;
*
* &lt;bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/&gt;</pre>
*
* Alternatively, check out your resource provider's ActivationSpec object,
* which should support local transactions through a provider-specific config flag,
* e.g. ActiveMQActivationSpec's "useRAManagedTransaction" bean property.
*
* <pre class="code">
* &lt;bean class="org.springframework.jca.endpoint.GenericMessageEndpointManager"&gt;
* &lt;property name="resourceAdapter" ref="resourceAdapter"/&gt;
* &lt;property name="messageEndpointFactory"&gt;
* &lt;bean class="org.springframework.jca.endpoint.GenericMessageEndpointFactory"&gt;
* &lt;property name="messageListener" ref="messageListener"/&gt;
* &lt;/bean&gt;
* &lt;/property&gt;
* &lt;property name="activationSpec"&gt;
* &lt;bean class="org.apache.activemq.ra.ActiveMQActivationSpec"&gt;
* &lt;property name="destination" value="myQueue"/&gt;
* &lt;property name="destinationType" value="javax.jms.Queue"/&gt;
* &lt;property name="useRAManagedTransaction" value="true"/&gt;
* &lt;/bean&gt;
* &lt;/property&gt;
* &lt;/bean&gt;</pre>
*
* @author Juergen Hoeller
* @since 2.5
* @see javax.resource.spi.ResourceAdapter#endpointActivation
* @see javax.resource.spi.ResourceAdapter#endpointDeactivation
* @see javax.resource.spi.endpoint.MessageEndpointFactory
* @see javax.resource.spi.ActivationSpec
*/
public class GenericMessageEndpointManager implements InitializingBean, Lifecycle, DisposableBean {
private ResourceAdapter resourceAdapter;
private MessageEndpointFactory messageEndpointFactory;
private ActivationSpec activationSpec;
private boolean autoStartup = true;
private boolean running = false;
private final Object lifecycleMonitor = new Object();
/**
* Set the JCA ResourceAdapter to manage endpoints for.
*/
public void setResourceAdapter(ResourceAdapter resourceAdapter) {
this.resourceAdapter = resourceAdapter;
}
/**
* Return the JCA ResourceAdapter to manage endpoints for.
*/
public ResourceAdapter getResourceAdapter() {
return this.resourceAdapter;
}
/**
* Set the JCA MessageEndpointFactory to activate, pointing to a
* MessageListener object that the endpoints will delegate to.
* <p>A MessageEndpointFactory instance may be shared across multiple
* endpoints (i.e. multiple GenericMessageEndpointManager instances),
* with different {@link #setActivationSpec ActivationSpec} objects applied.
* @see GenericMessageEndpointFactory#setMessageListener
*/
public void setMessageEndpointFactory(MessageEndpointFactory messageEndpointFactory) {
this.messageEndpointFactory = messageEndpointFactory;
}
/**
* Return the JCA MessageEndpointFactory to activate.
*/
public MessageEndpointFactory getMessageEndpointFactory() {
return this.messageEndpointFactory;
}
/**
* Set the JCA ActivationSpec to use for activating the endpoint.
* <p>Note that this ActivationSpec instance should not be shared
* across multiple ResourceAdapter instances.
*/
public void setActivationSpec(ActivationSpec activationSpec) {
this.activationSpec = activationSpec;
}
/**
* Return the JCA ActivationSpec to use for activating the endpoint.
*/
public ActivationSpec getActivationSpec() {
return this.activationSpec;
}
/**
* Set whether to auto-start the endpoint activation along with
* this endpoint manager's initialization.
* <p>Default is "true". Turn this flag off to defer the endpoint
* activation until an explicit {#start()} call.
*/
public void setAutoStartup(boolean autoStartup) {
this.autoStartup = autoStartup;
}
/**
* Prepares the message endpoint, and automatically activates it
* if the "autoStartup" flag is set to "true".
*/
public void afterPropertiesSet() throws ResourceException {
if (getResourceAdapter() == null) {
throw new IllegalArgumentException("Property 'resourceAdapter' is required");
}
if (getMessageEndpointFactory() == null) {
throw new IllegalArgumentException("Property 'messageEndpointFactory' is required");
}
ActivationSpec activationSpec = getActivationSpec();
if (activationSpec == null) {
throw new IllegalArgumentException("Property 'activationSpec' is required");
}
if (activationSpec.getResourceAdapter() == null) {
activationSpec.setResourceAdapter(getResourceAdapter());
}
else if (activationSpec.getResourceAdapter() != getResourceAdapter()) {
throw new IllegalArgumentException("ActivationSpec [" + activationSpec +
"] is associated with a different ResourceAdapter: " + activationSpec.getResourceAdapter());
}
if (this.autoStartup) {
start();
}
}
/**
* Activates the configured message endpoint.
*/
public void start() {
synchronized (this.lifecycleMonitor) {
if (!this.running) {
try {
getResourceAdapter().endpointActivation(getMessageEndpointFactory(), getActivationSpec());
}
catch (ResourceException ex) {
IllegalStateException wrapped = new IllegalStateException("Could not activate message endpoint");
wrapped.initCause(ex);
throw wrapped;
}
this.running = true;
}
}
}
/**
* Deactivates the configured message endpoint.
*/
public void stop() {
synchronized (this.lifecycleMonitor) {
if (this.running) {
getResourceAdapter().endpointDeactivation(getMessageEndpointFactory(), getActivationSpec());
this.running = false;
}
}
}
/**
* Return whether the configured message endpoint is currently active.
*/
public boolean isRunning() {
synchronized (this.lifecycleMonitor) {
return this.running;
}
}
/**
* Deactivates the message endpoint, preparing it for shutdown.
*/
public void destroy() {
stop();
}
}

View File

@ -0,0 +1,7 @@
<html>
<body>
This package provides a facility for generic JCA message endpoint management.
</body>
</html>

View File

@ -0,0 +1,137 @@
/*
* 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.jca.support;
import javax.resource.ResourceException;
import javax.resource.spi.ConnectionManager;
import javax.resource.spi.ManagedConnectionFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
/**
* {@link org.springframework.beans.factory.FactoryBean} that creates
* a local JCA connection factory in "non-managed" mode (as defined by the
* Java Connector Architecture specification). This is a direct alternative
* to a {@link org.springframework.jndi.JndiObjectFactoryBean} definition that
* obtains a connection factory handle from a J2EE server's naming environment.
*
* <p>The type of the connection factory is dependent on the actual connector:
* the connector can either expose its native API (such as a JDBC
* {@link javax.sql.DataSource} or a JMS {@link javax.jms.ConnectionFactory})
* or follow the standard Common Client Interface (CCI), as defined by the JCA spec.
* The exposed interface in the CCI case is {@link javax.resource.cci.ConnectionFactory}.
*
* <p>In order to use this FactoryBean, you must specify the connector's
* {@link #setManagedConnectionFactory "managedConnectionFactory"} (usually
* configured as separate JavaBean), which will be used to create the actual
* connection factory reference as exposed to the application. Optionally,
* you can also specify a {@link #setConnectionManager "connectionManager"},
* in order to use a custom ConnectionManager instead of the connector's default.
*
* <p><b>NOTE:</b> In non-managed mode, a connector is not deployed on an
* application server, or more specificially not interacting with an application
* server. Consequently, it cannot use a J2EE server's system contracts:
* connection management, transaction management, and security management.
* A custom ConnectionManager implementation has to be used for applying those
* services in conjunction with a standalone transaction coordinator etc.
*
* <p>The connector will use a local ConnectionManager (included in the connector)
* by default, which cannot participate in global transactions due to the lack
* of XA enlistment. You need to specify an XA-capable ConnectionManager in
* order to make the connector interact with an XA transaction coordinator.
* Alternatively, simply use the native local transaction facilities of the
* exposed API (e.g. CCI local transactions), or use a corresponding
* implementation of Spring's PlatformTransactionManager SPI
* (e.g. {@link org.springframework.jca.cci.connection.CciLocalTransactionManager})
* to drive local transactions.
*
* @author Juergen Hoeller
* @since 1.2
* @see #setManagedConnectionFactory
* @see #setConnectionManager
* @see javax.resource.cci.ConnectionFactory
* @see javax.resource.cci.Connection#getLocalTransaction
* @see org.springframework.jca.cci.connection.CciLocalTransactionManager
*/
public class LocalConnectionFactoryBean implements FactoryBean, InitializingBean {
private ManagedConnectionFactory managedConnectionFactory;
private ConnectionManager connectionManager;
private Object connectionFactory;
/**
* Set the JCA ManagerConnectionFactory that should be used to create
* the desired connection factory.
* <p>The ManagerConnectionFactory will usually be set up as separate bean
* (potentially as inner bean), populated with JavaBean properties:
* a ManagerConnectionFactory is encouraged to follow the JavaBean pattern
* by the JCA specification, analogous to a JDBC DataSource and a JDO
* PersistenceManagerFactory.
* <p>Note that the ManagerConnectionFactory implementation might expect
* a reference to its JCA 1.5 ResourceAdapter, expressed through the
* {@link javax.resource.spi.ResourceAdapterAssociation} interface.
* Simply inject the corresponding ResourceAdapter instance into its
* "resourceAdapter" bean property in this case, before passing the
* ManagerConnectionFactory into this LocalConnectionFactoryBean.
* @see javax.resource.spi.ManagedConnectionFactory#createConnectionFactory()
*/
public void setManagedConnectionFactory(ManagedConnectionFactory managedConnectionFactory) {
this.managedConnectionFactory = managedConnectionFactory;
}
/**
* Set the JCA ConnectionManager that should be used to create the
* desired connection factory.
* <p>A ConnectionManager implementation for local usage is often
* included with a JCA connector. Such an included ConnectionManager
* might be set as default, with no need to explicitly specify one.
* @see javax.resource.spi.ManagedConnectionFactory#createConnectionFactory(javax.resource.spi.ConnectionManager)
*/
public void setConnectionManager(ConnectionManager connectionManager) {
this.connectionManager = connectionManager;
}
public void afterPropertiesSet() throws ResourceException {
if (this.managedConnectionFactory == null) {
throw new IllegalArgumentException("Property 'managedConnectionFactory' is required");
}
if (this.connectionManager != null) {
this.connectionFactory = this.managedConnectionFactory.createConnectionFactory(this.connectionManager);
}
else {
this.connectionFactory = this.managedConnectionFactory.createConnectionFactory();
}
}
public Object getObject() {
return this.connectionFactory;
}
public Class getObjectType() {
return (this.connectionFactory != null ? this.connectionFactory.getClass() : null);
}
public boolean isSingleton() {
return true;
}
}

View File

@ -0,0 +1,148 @@
/*
* 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.jca.support;
import javax.resource.ResourceException;
import javax.resource.spi.BootstrapContext;
import javax.resource.spi.ResourceAdapter;
import javax.resource.spi.XATerminator;
import javax.resource.spi.work.WorkManager;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
/**
* {@link org.springframework.beans.factory.FactoryBean} that bootstraps
* the specified JCA 1.5 {@link javax.resource.spi.ResourceAdapter},
* starting it with a local {@link javax.resource.spi.BootstrapContext}
* and exposing it for bean references. It will also stop the ResourceAdapter
* on context shutdown. This corresponds to 'non-managed' bootstrap in a
* local environment, according to the JCA 1.5 specification.
*
* <p>This is essentially an adapter for bean-style bootstrapping of a
* JCA ResourceAdapter, allowing the BootstrapContext or its elements
* (such as the JCA WorkManager) to be specified through bean properties.
*
* @author Juergen Hoeller
* @since 2.0.3
* @see #setResourceAdapter
* @see #setBootstrapContext
* @see #setWorkManager
* @see javax.resource.spi.ResourceAdapter#start(javax.resource.spi.BootstrapContext)
* @see javax.resource.spi.ResourceAdapter#stop()
*/
public class ResourceAdapterFactoryBean implements FactoryBean, InitializingBean, DisposableBean {
private ResourceAdapter resourceAdapter;
private BootstrapContext bootstrapContext;
private WorkManager workManager;
private XATerminator xaTerminator;
/**
* Specify the target JCA ResourceAdapter as class, to be instantiated
* with its default configuration.
* <p>Alternatively, specify a pre-configured ResourceAdapter instance
* through the "resourceAdapter" property.
* @see #setResourceAdapter
*/
public void setResourceAdapterClass(Class resourceAdapterClass) {
Assert.isAssignable(ResourceAdapter.class, resourceAdapterClass);
this.resourceAdapter = (ResourceAdapter) BeanUtils.instantiateClass(resourceAdapterClass);
}
/**
* Specify the target JCA ResourceAdapter, passed in as configured instance
* which hasn't been started yet. This will typically happen as an
* inner bean definition, configuring the ResourceAdapter instance
* through its vendor-specific bean properties.
*/
public void setResourceAdapter(ResourceAdapter resourceAdapter) {
this.resourceAdapter = resourceAdapter;
}
/**
* Specify the JCA BootstrapContext to use for starting the ResourceAdapter.
* <p>Alternatively, you can specify the individual parts (such as the
* JCA WorkManager) as individual references.
* @see #setWorkManager
* @see #setXaTerminator
*/
public void setBootstrapContext(BootstrapContext bootstrapContext) {
this.bootstrapContext = bootstrapContext;
}
/**
* Specify the JCA WorkManager to use for bootstrapping the ResourceAdapter.
* @see #setBootstrapContext
*/
public void setWorkManager(WorkManager workManager) {
this.workManager = workManager;
}
/**
* Specify the JCA XATerminator to use for bootstrapping the ResourceAdapter.
* @see #setBootstrapContext
*/
public void setXaTerminator(XATerminator xaTerminator) {
this.xaTerminator = xaTerminator;
}
/**
* Builds the BootstrapContext and starts the ResourceAdapter with it.
* @see javax.resource.spi.ResourceAdapter#start(javax.resource.spi.BootstrapContext)
*/
public void afterPropertiesSet() throws ResourceException {
if (this.resourceAdapter == null) {
throw new IllegalArgumentException("'resourceAdapter' or 'resourceAdapterClass' is required");
}
if (this.bootstrapContext == null) {
this.bootstrapContext = new SimpleBootstrapContext(this.workManager, this.xaTerminator);
}
this.resourceAdapter.start(this.bootstrapContext);
}
public Object getObject() {
return this.resourceAdapter;
}
public Class getObjectType() {
return (this.resourceAdapter != null ? this.resourceAdapter.getClass() : ResourceAdapter.class);
}
public boolean isSingleton() {
return true;
}
/**
* Stops the ResourceAdapter.
* @see javax.resource.spi.ResourceAdapter#stop()
*/
public void destroy() {
this.resourceAdapter.stop();
}
}

View File

@ -0,0 +1,80 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jca.support;
import java.util.Timer;
import javax.resource.spi.BootstrapContext;
import javax.resource.spi.UnavailableException;
import javax.resource.spi.XATerminator;
import javax.resource.spi.work.WorkManager;
/**
* Simple implementation of the JCA 1.5 {@link javax.resource.spi.BootstrapContext}
* interface, used for bootstrapping a JCA ResourceAdapter in a local environment.
*
* <p>Delegates to the given WorkManager and XATerminator, if any. Creates simple
* local instances of <code>java.util.Timer</code>.
*
* @author Juergen Hoeller
* @since 2.0.3
* @see javax.resource.spi.ResourceAdapter#start(javax.resource.spi.BootstrapContext)
* @see ResourceAdapterFactoryBean
*/
public class SimpleBootstrapContext implements BootstrapContext {
private WorkManager workManager;
private XATerminator xaTerminator;
/**
* Create a new SimpleBootstrapContext for the given WorkManager,
* with no XATerminator available.
* @param workManager the JCA WorkManager to use (may be <code>null</code>)
*/
public SimpleBootstrapContext(WorkManager workManager) {
this.workManager = workManager;
}
/**
* Create a new SimpleBootstrapContext for the given WorkManager and XATerminator.
* @param workManager the JCA WorkManager to use (may be <code>null</code>)
* @param xaTerminator the JCA XATerminator to use (may be <code>null</code>)
*/
public SimpleBootstrapContext(WorkManager workManager, XATerminator xaTerminator) {
this.workManager = workManager;
this.xaTerminator = xaTerminator;
}
public WorkManager getWorkManager() {
if (this.workManager == null) {
throw new IllegalStateException("No WorkManager available");
}
return this.workManager;
}
public XATerminator getXATerminator() {
return this.xaTerminator;
}
public Timer createTimer() throws UnavailableException {
return new Timer();
}
}

View File

@ -0,0 +1,8 @@
<html>
<body>
Provides generic support classes for JCA usage within Spring,
mainly for local setup of a JCA ResourceAdapter and/or ConnectionFactory.
</body>
</html>

View File

@ -0,0 +1,67 @@
/*
* 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.jca.work;
import javax.resource.spi.work.Work;
import org.springframework.util.Assert;
/**
* Simple Work adapter that delegates to a given Runnable.
*
* @author Juergen Hoeller
* @since 2.0.3
* @see javax.resource.spi.work.Work
* @see Runnable
*/
public class DelegatingWork implements Work {
private final Runnable delegate;
/**
* Create a new DelegatingWork.
* @param delegate the Runnable implementation to delegate to
*/
public DelegatingWork(Runnable delegate) {
Assert.notNull(delegate, "Delegate must not be null");
this.delegate = delegate;
}
/**
* Return the wrapped Runnable implementation.
*/
public final Runnable getDelegate() {
return this.delegate;
}
/**
* Delegates execution to the underlying Runnable.
*/
public void run() {
this.delegate.run();
}
/**
* This implementation is empty, since we expect the Runnable
* to terminate based on some specific shutdown signal.
*/
public void release() {
}
}

View File

@ -0,0 +1,252 @@
/*
* 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.jca.work;
import javax.resource.spi.work.ExecutionContext;
import javax.resource.spi.work.Work;
import javax.resource.spi.work.WorkAdapter;
import javax.resource.spi.work.WorkCompletedException;
import javax.resource.spi.work.WorkEvent;
import javax.resource.spi.work.WorkException;
import javax.resource.spi.work.WorkListener;
import javax.resource.spi.work.WorkManager;
import javax.resource.spi.work.WorkRejectedException;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.core.task.SyncTaskExecutor;
import org.springframework.core.task.TaskExecutor;
import org.springframework.core.task.TaskRejectedException;
import org.springframework.core.task.TaskTimeoutException;
import org.springframework.util.Assert;
/**
* Simple JCA 1.5 {@link javax.resource.spi.work.WorkManager} implementation that
* delegates to a Spring {@link org.springframework.core.task.TaskExecutor}.
* Provides simple task execution including start timeouts, but without support
* for a JCA ExecutionContext (i.e. without support for imported transactions).
*
* <p>Uses a {@link org.springframework.core.task.SyncTaskExecutor} for {@link #doWork}
* calls and a {@link org.springframework.core.task.SimpleAsyncTaskExecutor}
* for {@link #startWork} and {@link #scheduleWork} calls, by default.
* These default task executors can be overridden through configuration.
*
* <p><b>NOTE: This WorkManager does not provide thread pooling by default!</b>
* Specify a {@link org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor}
* (or any other thread-pooling TaskExecutor) as "asyncTaskExecutor" in order to
* achieve actual thread pooling.
*
* <p>This WorkManager automatically detects a specified
* {@link org.springframework.core.task.AsyncTaskExecutor} implementation
* and uses its extended timeout functionality where appropriate.
* JCA WorkListeners are fully supported in any case.
*
* @author Juergen Hoeller
* @since 2.0.3
* @see #setSyncTaskExecutor
* @see #setAsyncTaskExecutor
*/
public class SimpleTaskWorkManager implements WorkManager {
private TaskExecutor syncTaskExecutor = new SyncTaskExecutor();
private TaskExecutor asyncTaskExecutor = new SimpleAsyncTaskExecutor();
/**
* Specify the TaskExecutor to use for <i>synchronous</i> work execution
* (i.e. {@link #doWork} calls).
* <p>Default is a {@link org.springframework.core.task.SyncTaskExecutor}.
*/
public void setSyncTaskExecutor(TaskExecutor syncTaskExecutor) {
this.syncTaskExecutor = syncTaskExecutor;
}
/**
* Specify the TaskExecutor to use for <i>asynchronous</i> work execution
* (i.e. {@link #startWork} and {@link #scheduleWork} calls).
* <p>This will typically (but not necessarily) be an
* {@link org.springframework.core.task.AsyncTaskExecutor} implementation.
* Default is a {@link org.springframework.core.task.SimpleAsyncTaskExecutor}.
*/
public void setAsyncTaskExecutor(TaskExecutor asyncTaskExecutor) {
this.asyncTaskExecutor = asyncTaskExecutor;
}
public void doWork(Work work) throws WorkException {
doWork(work, WorkManager.INDEFINITE, null, null);
}
public void doWork(Work work, long startTimeout, ExecutionContext executionContext, WorkListener workListener)
throws WorkException {
Assert.state(this.syncTaskExecutor != null, "No 'syncTaskExecutor' set");
executeWork(this.syncTaskExecutor, work, startTimeout, false, executionContext, workListener);
}
public long startWork(Work work) throws WorkException {
return startWork(work, WorkManager.INDEFINITE, null, null);
}
public long startWork(Work work, long startTimeout, ExecutionContext executionContext, WorkListener workListener)
throws WorkException {
Assert.state(this.asyncTaskExecutor != null, "No 'asyncTaskExecutor' set");
return executeWork(this.asyncTaskExecutor, work, startTimeout, true, executionContext, workListener);
}
public void scheduleWork(Work work) throws WorkException {
scheduleWork(work, WorkManager.INDEFINITE, null, null);
}
public void scheduleWork(Work work, long startTimeout, ExecutionContext executionContext, WorkListener workListener)
throws WorkException {
Assert.state(this.asyncTaskExecutor != null, "No 'asyncTaskExecutor' set");
executeWork(this.asyncTaskExecutor, work, startTimeout, false, executionContext, workListener);
}
/**
* Execute the given Work on the specified TaskExecutor.
* @param taskExecutor the TaskExecutor to use
* @param work the Work to execute
* @param startTimeout the time duration within which the Work is supposed to start
* @param blockUntilStarted whether to block until the Work has started
* @param executionContext the JCA ExecutionContext for the given Work
* @param workListener the WorkListener to clal for the given Work
* @return the time elapsed from Work acceptance until start of execution
* (or -1 if not applicable or not known)
* @throws WorkException if the TaskExecutor did not accept the Work
*/
protected long executeWork(TaskExecutor taskExecutor, Work work, long startTimeout,
boolean blockUntilStarted, ExecutionContext executionContext, WorkListener workListener)
throws WorkException {
if (executionContext != null && executionContext.getXid() != null) {
throw new WorkException("SimpleTaskWorkManager does not supported imported XIDs: " + executionContext.getXid());
}
WorkListener workListenerToUse = workListener;
if (workListenerToUse == null) {
workListenerToUse = new WorkAdapter();
}
boolean isAsync = (taskExecutor instanceof AsyncTaskExecutor);
DelegatingWorkAdapter workHandle = new DelegatingWorkAdapter(work, workListenerToUse, !isAsync);
try {
if (isAsync) {
((AsyncTaskExecutor) taskExecutor).execute(workHandle, startTimeout);
}
else {
taskExecutor.execute(workHandle);
}
}
catch (TaskTimeoutException ex) {
WorkException wex = new WorkRejectedException("TaskExecutor rejected Work because of timeout: " + work, ex);
wex.setErrorCode(WorkException.START_TIMED_OUT);
workListenerToUse.workRejected(new WorkEvent(this, WorkEvent.WORK_REJECTED, work, wex));
throw wex;
}
catch (TaskRejectedException ex) {
WorkException wex = new WorkRejectedException("TaskExecutor rejected Work: " + work, ex);
wex.setErrorCode(WorkException.INTERNAL);
workListenerToUse.workRejected(new WorkEvent(this, WorkEvent.WORK_REJECTED, work, wex));
throw wex;
}
catch (Throwable ex) {
WorkException wex = new WorkException("TaskExecutor failed to execute Work: " + work, ex);
wex.setErrorCode(WorkException.INTERNAL);
throw wex;
}
if (isAsync) {
workListenerToUse.workAccepted(new WorkEvent(this, WorkEvent.WORK_ACCEPTED, work, null));
}
if (blockUntilStarted) {
long acceptanceTime = System.currentTimeMillis();
synchronized (workHandle.monitor) {
try {
while (!workHandle.started) {
workHandle.monitor.wait();
}
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
return (System.currentTimeMillis() - acceptanceTime);
}
else {
return WorkManager.UNKNOWN;
}
}
/**
* Work adapter that supports start timeouts and WorkListener callbacks
* for a given Work that it delegates to.
*/
private static class DelegatingWorkAdapter implements Work {
private final Work work;
private final WorkListener workListener;
private final boolean acceptOnExecution;
public final Object monitor = new Object();
public boolean started = false;
public DelegatingWorkAdapter(Work work, WorkListener workListener, boolean acceptOnExecution) {
this.work = work;
this.workListener = workListener;
this.acceptOnExecution = acceptOnExecution;
}
public void run() {
if (this.acceptOnExecution) {
this.workListener.workAccepted(new WorkEvent(this, WorkEvent.WORK_ACCEPTED, work, null));
}
synchronized (this.monitor) {
this.started = true;
this.monitor.notify();
}
this.workListener.workStarted(new WorkEvent(this, WorkEvent.WORK_STARTED, this.work, null));
try {
this.work.run();
}
catch (RuntimeException ex) {
this.workListener.workCompleted(
new WorkEvent(this, WorkEvent.WORK_COMPLETED, this.work, new WorkCompletedException(ex)));
throw ex;
}
catch (Error err) {
this.workListener.workCompleted(
new WorkEvent(this, WorkEvent.WORK_COMPLETED, this.work, new WorkCompletedException(err)));
throw err;
}
this.workListener.workCompleted(new WorkEvent(this, WorkEvent.WORK_COMPLETED, this.work, null));
}
public void release() {
this.work.release();
}
}
}

View File

@ -0,0 +1,275 @@
/*
* 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.jca.work;
import javax.naming.NamingException;
import javax.resource.spi.BootstrapContext;
import javax.resource.spi.work.ExecutionContext;
import javax.resource.spi.work.Work;
import javax.resource.spi.work.WorkException;
import javax.resource.spi.work.WorkListener;
import javax.resource.spi.work.WorkManager;
import javax.resource.spi.work.WorkRejectedException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.core.task.TaskRejectedException;
import org.springframework.core.task.TaskTimeoutException;
import org.springframework.jca.context.BootstrapContextAware;
import org.springframework.jndi.JndiLocatorSupport;
import org.springframework.scheduling.SchedulingException;
import org.springframework.scheduling.SchedulingTaskExecutor;
import org.springframework.util.Assert;
/**
* {@link org.springframework.core.task.TaskExecutor} implementation
* that delegates to a JCA 1.5 WorkManager, implementing the
* {@link javax.resource.spi.work.WorkManager} interface.
*
* <p>This is mainly intended for use within a JCA ResourceAdapter implementation,
* but may also be used in a standalone environment, delegating to a locally
* embedded WorkManager implementation (such as Geronimo's).
*
* <p>Also implements the JCA 1.5 WorkManager interface itself, delegating all
* calls to the target WorkManager. Hence, a caller can choose whether it wants
* to talk to this executor through the Spring TaskExecutor interface or the
* JCA 1.5 WorkManager interface.
*
* <p>This adapter is also capable of obtaining a JCA WorkManager from JNDI.
* This is for example appropriate on the Geronimo application server, where
* WorkManager GBeans (e.g. Geronimo's default "DefaultWorkManager" GBean)
* can be linked into the J2EE environment through "gbean-ref" entries
* in the <code>geronimo-web.xml</code> deployment descriptor.
*
* <p><b>On JBoss and GlassFish, obtaining the default JCA WorkManager
* requires special lookup steps.</b> See the
* {@link org.springframework.jca.work.jboss.JBossWorkManagerTaskExecutor}
* {@link org.springframework.jca.work.glassfish.GlassFishWorkManagerTaskExecutor}
* classes which are the direct equivalent of this generic JCA adapter class.
*
* @author Juergen Hoeller
* @since 2.0.3
* @see #setWorkManager
* @see javax.resource.spi.work.WorkManager#scheduleWork
*/
public class WorkManagerTaskExecutor extends JndiLocatorSupport
implements SchedulingTaskExecutor, AsyncTaskExecutor, WorkManager, BootstrapContextAware, InitializingBean {
private WorkManager workManager;
private String workManagerName;
private boolean blockUntilStarted = false;
private boolean blockUntilCompleted = false;
private WorkListener workListener;
/**
* Create a new WorkManagerTaskExecutor, expecting bean-style configuration.
* @see #setWorkManager
*/
public WorkManagerTaskExecutor() {
}
/**
* Create a new WorkManagerTaskExecutor for the given WorkManager.
* @param workManager the JCA WorkManager to delegate to
*/
public WorkManagerTaskExecutor(WorkManager workManager) {
setWorkManager(workManager);
}
/**
* Specify the JCA WorkManager instance to delegate to.
*/
public void setWorkManager(WorkManager workManager) {
Assert.notNull(workManager, "WorkManager must not be null");
this.workManager = workManager;
}
/**
* Set the JNDI name of the JCA WorkManager.
* <p>This can either be a fully qualified JNDI name,
* or the JNDI name relative to the current environment
* naming context if "resourceRef" is set to "true".
* @see #setWorkManager
* @see #setResourceRef
*/
public void setWorkManagerName(String workManagerName) {
this.workManagerName = workManagerName;
}
/**
* Specify the JCA BootstrapContext that contains the
* WorkManager to delegate to.
*/
public void setBootstrapContext(BootstrapContext bootstrapContext) {
Assert.notNull(bootstrapContext, "BootstrapContext must not be null");
this.workManager = bootstrapContext.getWorkManager();
}
/**
* Set whether to let {@link #execute} block until the work
* has been actually started.
* <p>Uses the JCA <code>startWork</code> operation underneath,
* instead of the default <code>scheduleWork</code>.
* @see javax.resource.spi.work.WorkManager#startWork
* @see javax.resource.spi.work.WorkManager#scheduleWork
*/
public void setBlockUntilStarted(boolean blockUntilStarted) {
this.blockUntilStarted = blockUntilStarted;
}
/**
* Set whether to let {@link #execute} block until the work
* has been completed.
* <p>Uses the JCA <code>doWork</code> operation underneath,
* instead of the default <code>scheduleWork</code>.
* @see javax.resource.spi.work.WorkManager#doWork
* @see javax.resource.spi.work.WorkManager#scheduleWork
*/
public void setBlockUntilCompleted(boolean blockUntilCompleted) {
this.blockUntilCompleted = blockUntilCompleted;
}
/**
* Specify a JCA 1.5 WorkListener to apply, if any.
* <p>This shared WorkListener instance will be passed on to the
* WorkManager by all {@link #execute} calls on this TaskExecutor.
*/
public void setWorkListener(WorkListener workListener) {
this.workListener = workListener;
}
public void afterPropertiesSet() throws NamingException {
if (this.workManager == null) {
if (this.workManagerName != null) {
this.workManager = (WorkManager) lookup(this.workManagerName, WorkManager.class);
}
else {
this.workManager = getDefaultWorkManager();
}
}
}
/**
* Obtain a default WorkManager to delegate to.
* Called if no explicit WorkManager or WorkManager JNDI name has been specified.
* <p>The default implementation returns a {@link SimpleTaskWorkManager}.
* Can be overridden in subclasses.
*/
protected WorkManager getDefaultWorkManager() {
return new SimpleTaskWorkManager();
}
//-------------------------------------------------------------------------
// Implementation of the Spring SchedulingTaskExecutor interface
//-------------------------------------------------------------------------
public void execute(Runnable task) {
execute(task, TIMEOUT_INDEFINITE);
}
public void execute(Runnable task, long startTimeout) {
Assert.state(this.workManager != null, "No WorkManager specified");
Work work = new DelegatingWork(task);
try {
if (this.blockUntilCompleted) {
if (startTimeout != TIMEOUT_INDEFINITE || this.workListener != null) {
this.workManager.doWork(work, startTimeout, null, this.workListener);
}
else {
this.workManager.doWork(work);
}
}
else if (this.blockUntilStarted) {
if (startTimeout != TIMEOUT_INDEFINITE || this.workListener != null) {
this.workManager.startWork(work, startTimeout, null, this.workListener);
}
else {
this.workManager.startWork(work);
}
}
else {
if (startTimeout != TIMEOUT_INDEFINITE || this.workListener != null) {
this.workManager.scheduleWork(work, startTimeout, null, this.workListener);
}
else {
this.workManager.scheduleWork(work);
}
}
}
catch (WorkRejectedException ex) {
if (WorkException.START_TIMED_OUT.equals(ex.getErrorCode())) {
throw new TaskTimeoutException("JCA WorkManager rejected task because of timeout: " + task, ex);
}
else {
throw new TaskRejectedException("JCA WorkManager rejected task: " + task, ex);
}
}
catch (WorkException ex) {
throw new SchedulingException("Could not schedule task on JCA WorkManager", ex);
}
}
/**
* This task executor prefers short-lived work units.
*/
public boolean prefersShortLivedTasks() {
return true;
}
//-------------------------------------------------------------------------
// Implementation of the JCA WorkManager interface
//-------------------------------------------------------------------------
public void doWork(Work work) throws WorkException {
this.workManager.doWork(work);
}
public void doWork(Work work, long delay, ExecutionContext executionContext, WorkListener workListener)
throws WorkException {
this.workManager.doWork(work, delay, executionContext, workListener);
}
public long startWork(Work work) throws WorkException {
return this.workManager.startWork(work);
}
public long startWork(Work work, long delay, ExecutionContext executionContext, WorkListener workListener)
throws WorkException {
return this.workManager.startWork(work, delay, executionContext, workListener);
}
public void scheduleWork(Work work) throws WorkException {
this.workManager.scheduleWork(work);
}
public void scheduleWork(Work work, long delay, ExecutionContext executionContext, WorkListener workListener)
throws WorkException {
this.workManager.scheduleWork(work, delay, executionContext, workListener);
}
}

View File

@ -0,0 +1,80 @@
/*
* 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.jca.work.glassfish;
import java.lang.reflect.Method;
import javax.resource.spi.work.WorkManager;
import org.springframework.jca.work.WorkManagerTaskExecutor;
import org.springframework.util.ReflectionUtils;
/**
* Spring TaskExecutor adapter for the GlassFish JCA WorkManager.
* Can be defined in web applications to make a TaskExecutor reference
* available, talking to the GlassFish WorkManager (thread pool) underneath.
*
* <p>This is the GlassFish equivalent of the CommonJ
* {@link org.springframework.scheduling.commonj.WorkManagerTaskExecutor}
* adapter for WebLogic and WebSphere.
*
* @author Juergen Hoeller
* @since 2.5.2
* @see com.sun.enterprise.connectors.work.WorkManagerFactory
*/
public class GlassFishWorkManagerTaskExecutor extends WorkManagerTaskExecutor {
private static final String WORK_MANAGER_FACTORY_CLASS = "com.sun.enterprise.connectors.work.WorkManagerFactory";
private final Method getWorkManagerMethod;
public GlassFishWorkManagerTaskExecutor() {
try {
Class wmf = getClass().getClassLoader().loadClass(WORK_MANAGER_FACTORY_CLASS);
this.getWorkManagerMethod = wmf.getMethod("getWorkManager", new Class[] {String.class});
}
catch (Exception ex) {
throw new IllegalStateException(
"Could not initialize GlassFishWorkManagerTaskExecutor because GlassFish API is not available: " + ex);
}
}
/**
* Identify a specific GlassFish thread pool to talk to.
* <p>The thread pool name matches the resource adapter name
* in default RAR deployment scenarios.
*/
public void setThreadPoolName(String threadPoolName) {
WorkManager wm = (WorkManager)
ReflectionUtils.invokeMethod(this.getWorkManagerMethod, null, new Object[] {threadPoolName});
if (wm == null) {
throw new IllegalArgumentException("Specified thread pool name '" + threadPoolName +
"' does not correspond to an actual pool definition in GlassFish. Check your configuration!");
}
setWorkManager(wm);
}
/**
* Obtains GlassFish's default thread pool.
*/
protected WorkManager getDefaultWorkManager() {
return (WorkManager) ReflectionUtils.invokeMethod(this.getWorkManagerMethod, null, new Object[] {null});
}
}

View File

@ -0,0 +1,8 @@
<html>
<body>
Convenience package for obtaining a GlassFish JCA WorkManager for use in
web applications. Provides a Spring TaskExecutor adapter for GlassFish.
</body>
</html>

View File

@ -0,0 +1,47 @@
/*
* 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.jca.work.jboss;
import javax.resource.spi.work.WorkManager;
import org.springframework.jca.work.WorkManagerTaskExecutor;
/**
* Spring TaskExecutor adapter for the JBoss JCA WorkManager.
* Can be defined in web applications to make a TaskExecutor reference
* available, talking to the JBoss WorkManager (thread pool) underneath.
*
* <p>This is the JBoss equivalent of the CommonJ
* {@link org.springframework.scheduling.commonj.WorkManagerTaskExecutor}
* adapter for WebLogic and WebSphere.
*
* @author Juergen Hoeller
* @since 2.5.2
* @see org.jboss.resource.work.JBossWorkManagerMBean
*/
public class JBossWorkManagerTaskExecutor extends WorkManagerTaskExecutor {
/**
* Obtains the default JBoss JCA WorkManager through a JMX lookup
* for the JBossWorkManagerMBean.
* @see JBossWorkManagerUtils#getWorkManager()
*/
protected WorkManager getDefaultWorkManager() {
return JBossWorkManagerUtils.getWorkManager();
}
}

View File

@ -0,0 +1,64 @@
/*
* 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.jca.work.jboss;
import java.lang.reflect.Method;
import javax.management.MBeanServerConnection;
import javax.management.MBeanServerInvocationHandler;
import javax.management.ObjectName;
import javax.naming.InitialContext;
import javax.resource.spi.work.WorkManager;
/**
* Utility class for obtaining the JBoss JCA WorkManager,
* typically for use in web applications.
*
* @author Juergen Hoeller
* @since 2.5.2
*/
public abstract class JBossWorkManagerUtils {
private static final String JBOSS_WORK_MANAGER_MBEAN_CLASS_NAME = "org.jboss.resource.work.JBossWorkManagerMBean";
private static final String MBEAN_SERVER_CONNECTION_JNDI_NAME = "jmx/invoker/RMIAdaptor";
private static final String WORK_MANAGER_OBJECT_NAME = "jboss.jca:service=WorkManager";
/**
* Obtain the default JBoss JCA WorkManager through a JMX lookup
* for the JBossWorkManagerMBean.
* @see org.jboss.resource.work.JBossWorkManagerMBean
*/
public static WorkManager getWorkManager() {
try {
Class mbeanClass = JBossWorkManagerUtils.class.getClassLoader().loadClass(JBOSS_WORK_MANAGER_MBEAN_CLASS_NAME);
InitialContext jndiContext = new InitialContext();
MBeanServerConnection mconn = (MBeanServerConnection) jndiContext.lookup(MBEAN_SERVER_CONNECTION_JNDI_NAME);
ObjectName objectName = ObjectName.getInstance(WORK_MANAGER_OBJECT_NAME);
Object workManagerMBean = MBeanServerInvocationHandler.newProxyInstance(mconn, objectName, mbeanClass, false);
Method getInstanceMethod = workManagerMBean.getClass().getMethod("getInstance", new Class[0]);
return (WorkManager) getInstanceMethod.invoke(workManagerMBean, new Object[0]);
}
catch (Exception ex) {
throw new IllegalStateException(
"Could not initialize JBossWorkManagerTaskExecutor because JBoss API is not available: " + ex);
}
}
}

View File

@ -0,0 +1,8 @@
<html>
<body>
Convenience package for obtaining a JBoss JCA WorkManager for use in
web applications. Provides a Spring TaskExecutor adapter for JBoss.
</body>
</html>

View File

@ -0,0 +1,8 @@
<html>
<body>
Convenience classes for scheduling based on the JCA 1.5 WorkManager facility,
as supported within JCA 1.5 ResourceAdapters.
</body>
</html>

View File

@ -0,0 +1,45 @@
/*
* 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;
/**
* Exception thrown when a transaction can't be created using an
* underlying transaction API such as JTA.
*
* @author Rod Johnson
* @since 17.03.2003
*/
public class CannotCreateTransactionException extends TransactionException {
/**
* Constructor for CannotCreateTransactionException.
* @param msg the detail message
*/
public CannotCreateTransactionException(String msg) {
super(msg);
}
/**
* Constructor for CannotCreateTransactionException.
* @param msg the detail message
* @param cause the root cause from the transaction API in use
*/
public CannotCreateTransactionException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@ -0,0 +1,80 @@
/*
* 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;
/**
* Exception that represents a transaction failure caused by a heuristic
* decision on the side of the transaction coordinator.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @since 17.03.2003
*/
public class HeuristicCompletionException extends TransactionException {
/**
* Values for the outcome state of a heuristically completed transaction.
*/
public static final int STATE_UNKNOWN = 0;
public static final int STATE_COMMITTED = 1;
public static final int STATE_ROLLED_BACK = 2;
public static final int STATE_MIXED = 3;
public static String getStateString(int state) {
switch (state) {
case STATE_COMMITTED:
return "committed";
case STATE_ROLLED_BACK:
return "rolled back";
case STATE_MIXED:
return "mixed";
default:
return "unknown";
}
}
/**
* The outcome state of the transaction: have some or all resources been committed?
*/
private int outcomeState = STATE_UNKNOWN;
/**
* Constructor for HeuristicCompletionException.
* @param outcomeState the outcome state of the transaction
* @param cause the root cause from the transaction API in use
*/
public HeuristicCompletionException(int outcomeState, Throwable cause) {
super("Heuristic completion: outcome state is " + getStateString(outcomeState), cause);
this.outcomeState = outcomeState;
}
/**
* Return the outcome state of the transaction state,
* as one of the constants in this class.
* @see #STATE_UNKNOWN
* @see #STATE_COMMITTED
* @see #STATE_ROLLED_BACK
* @see #STATE_MIXED
*/
public int getOutcomeState() {
return outcomeState;
}
}

View File

@ -0,0 +1,46 @@
/*
* 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;
/**
* Exception thrown when the existence or non-existence of a transaction
* amounts to an illegal state according to the transaction propagation
* behavior that applies.
*
* @author Juergen Hoeller
* @since 21.01.2004
*/
public class IllegalTransactionStateException extends TransactionUsageException {
/**
* Constructor for IllegalTransactionStateException.
* @param msg the detail message
*/
public IllegalTransactionStateException(String msg) {
super(msg);
}
/**
* Constructor for IllegalTransactionStateException.
* @param msg the detail message
* @param cause the root cause from the transaction API in use
*/
public IllegalTransactionStateException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@ -0,0 +1,37 @@
/*
* 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;
/**
* Exception that gets thrown when an invalid isolation level is specified,
* i.e. an isolation level that the transaction manager implementation
* doesn't support.
*
* @author Juergen Hoeller
* @since 12.05.2003
*/
public class InvalidIsolationLevelException extends TransactionUsageException {
/**
* Constructor for InvalidIsolationLevelException.
* @param msg the detail message
*/
public InvalidIsolationLevelException(String msg) {
super(msg);
}
}

View File

@ -0,0 +1,49 @@
/*
* 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;
/**
* Exception that gets thrown when an invalid timeout is specified,
* that is, the specified timeout valid is out of range or the
* transaction manager implementation doesn't support timeouts.
*
* @author Juergen Hoeller
* @since 12.05.2003
*/
public class InvalidTimeoutException extends TransactionUsageException {
private int timeout;
/**
* Constructor for InvalidTimeoutException.
* @param msg the detail message
* @param timeout the invalid timeout value
*/
public InvalidTimeoutException(String msg, int timeout) {
super(msg);
this.timeout = timeout;
}
/**
* Return the invalid timeout value.
*/
public int getTimeout() {
return timeout;
}
}

View File

@ -0,0 +1,45 @@
/*
* 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;
/**
* Exception thrown when attempting to work with a nested transaction
* but nested transactions are not supported by the underlying backend.
*
* @author Juergen Hoeller
* @since 1.1
*/
public class NestedTransactionNotSupportedException extends CannotCreateTransactionException {
/**
* Constructor for NestedTransactionNotSupportedException.
* @param msg the detail message
*/
public NestedTransactionNotSupportedException(String msg) {
super(msg);
}
/**
* Constructor for NestedTransactionNotSupportedException.
* @param msg the detail message
* @param cause the root cause from the transaction API in use
*/
public NestedTransactionNotSupportedException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@ -0,0 +1,47 @@
/*
* 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;
/**
* Exception thrown when an operation is attempted that
* relies on an existing transaction (such as setting
* rollback status) and there is no existing transaction.
* This represents an illegal usage of the transaction API.
*
* @author Rod Johnson
* @since 17.03.2003
*/
public class NoTransactionException extends TransactionUsageException {
/**
* Constructor for NoTransactionException.
* @param msg the detail message
*/
public NoTransactionException(String msg) {
super(msg);
}
/**
* Constructor for NoTransactionException.
* @param msg the detail message
* @param cause the root cause from the transaction API in use
*/
public NoTransactionException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@ -0,0 +1,118 @@
/*
* 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;
/**
* This is the central interface in Spring's transaction infrastructure.
* Applications can use this directly, but it is not primarily meant as API:
* Typically, applications will work with either TransactionTemplate or
* declarative transaction demarcation through AOP.
*
* <p>For implementors, it is recommended to derive from the provided
* {@link org.springframework.transaction.support.AbstractPlatformTransactionManager}
* class, which pre-implements the defined propagation behavior and takes care
* of transaction synchronization handling. Subclasses have to implement
* template methods for specific states of the underlying transaction,
* for example: begin, suspend, resume, commit.
*
* <p>The default implementations of this strategy interface are
* {@link org.springframework.transaction.jta.JtaTransactionManager} and
* {@link org.springframework.jdbc.datasource.DataSourceTransactionManager},
* which can serve as an implementation guide for other transaction strategies.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @since 16.05.2003
* @see org.springframework.transaction.support.TransactionTemplate
* @see org.springframework.transaction.interceptor.TransactionInterceptor
* @see org.springframework.transaction.interceptor.TransactionProxyFactoryBean
*/
public interface PlatformTransactionManager {
/**
* Return a currently active transaction or create a new one, according to
* the specified propagation behavior.
* <p>Note that parameters like isolation level or timeout will only be applied
* to new transactions, and thus be ignored when participating in active ones.
* <p>Furthermore, not all transaction definition settings will be supported
* by every transaction manager: A proper transaction manager implementation
* should throw an exception when unsupported settings are encountered.
* <p>An exception to the above rule is the read-only flag, which should be
* ignored if no explicit read-only mode is supported. Essentially, the
* read-only flag is just a hint for potential optimization.
* @param definition TransactionDefinition instance (can be <code>null</code> for defaults),
* describing propagation behavior, isolation level, timeout etc.
* @return transaction status object representing the new or current transaction
* @throws TransactionException in case of lookup, creation, or system errors
* @throws IllegalTransactionStateException if the given transaction definition
* cannot be executed (for example, if a currently active transaction is in
* conflict with the specified propagation behavior)
* @see TransactionDefinition#getPropagationBehavior
* @see TransactionDefinition#getIsolationLevel
* @see TransactionDefinition#getTimeout
* @see TransactionDefinition#isReadOnly
*/
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
/**
* Commit the given transaction, with regard to its status. If the transaction
* has been marked rollback-only programmatically, perform a rollback.
* <p>If the transaction wasn't a new one, omit the commit for proper
* participation in the surrounding transaction. If a previous transaction
* has been suspended to be able to create a new one, resume the previous
* transaction after committing the new one.
* <p>Note that when the commit call completes, no matter if normally or
* throwing an exception, the transaction must be fully completed and
* cleaned up. No rollback call should be expected in such a case.
* <p>If this method throws an exception other than a TransactionException,
* then some before-commit error caused the commit attempt to fail. For
* example, an O/R Mapping tool might have tried to flush changes to the
* database right before commit, with the resulting DataAccessException
* causing the transaction to fail. The original exception will be
* propagated to the caller of this commit method in such a case.
* @param status object returned by the <code>getTransaction</code> method
* @throws UnexpectedRollbackException in case of an unexpected rollback
* that the transaction coordinator initiated
* @throws HeuristicCompletionException in case of a transaction failure
* caused by a heuristic decision on the side of the transaction coordinator
* @throws TransactionSystemException in case of commit or system errors
* (typically caused by fundamental resource failures)
* @throws IllegalTransactionStateException if the given transaction
* is already completed (that is, committed or rolled back)
* @see TransactionStatus#setRollbackOnly
*/
void commit(TransactionStatus status) throws TransactionException;
/**
* Perform a rollback of the given transaction.
* <p>If the transaction wasn't a new one, just set it rollback-only for proper
* participation in the surrounding transaction. If a previous transaction
* has been suspended to be able to create a new one, resume the previous
* transaction after rolling back the new one.
* <p><b>Do not call rollback on a transaction if commit threw an exception.</b>
* The transaction will already have been completed and cleaned up when commit
* returns, even in case of a commit exception. Consequently, a rollback call
* after commit failure will lead to an IllegalTransactionStateException.
* @param status object returned by the <code>getTransaction</code> method
* @throws TransactionSystemException in case of rollback or system errors
* (typically caused by fundamental resource failures)
* @throws IllegalTransactionStateException if the given transaction
* is already completed (that is, committed or rolled back)
*/
void rollback(TransactionStatus status) throws TransactionException;
}

View File

@ -0,0 +1,80 @@
/*
* 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;
/**
* Interface that specifies an API to programmatically manage transaction
* savepoints in a generic fashion. Extended by TransactionStatus to
* expose savepoint management functionality for a specific transaction.
*
* <p>Note that savepoints can only work within an active transaction.
* Just use this programmatic savepoint handling for advanced needs;
* else, a subtransaction with PROPAGATION_NESTED is preferable.
*
* <p>This interface is inspired by JDBC 3.0's Savepoint mechanism
* but is independent from any specific persistence technology.
*
* @author Juergen Hoeller
* @since 1.1
* @see TransactionStatus
* @see TransactionDefinition#PROPAGATION_NESTED
* @see java.sql.Savepoint
*/
public interface SavepointManager {
/**
* Create a new savepoint. You can roll back to a specific savepoint
* via <code>rollbackToSavepoint</code>, and explicitly release a
* savepoint that you don't need anymore via <code>releaseSavepoint</code>.
* <p>Note that most transaction managers will automatically release
* savepoints at transaction completion.
* @return a savepoint object, to be passed into rollbackToSavepoint
* or releaseSavepoint
* @throws NestedTransactionNotSupportedException if the underlying
* transaction does not support savepoints
* @throws TransactionException if the savepoint could not be created,
* for example because the transaction is not in an appropriate state
* @see java.sql.Connection#setSavepoint
*/
Object createSavepoint() throws TransactionException;
/**
* Roll back to the given savepoint. The savepoint will be
* automatically released afterwards.
* @param savepoint the savepoint to roll back to
* @throws NestedTransactionNotSupportedException if the underlying
* transaction does not support savepoints
* @throws TransactionException if the rollback failed
* @see java.sql.Connection#rollback(java.sql.Savepoint)
*/
void rollbackToSavepoint(Object savepoint) throws TransactionException;
/**
* Explicitly release the given savepoint.
* <p>Note that most transaction managers will automatically release
* savepoints at transaction completion.
* <p>Implementations should fail as silently as possible if
* proper resource cleanup will still happen at transaction completion.
* @param savepoint the savepoint to release
* @throws NestedTransactionNotSupportedException if the underlying
* transaction does not support savepoints
* @throws TransactionException if the release failed
* @see java.sql.Connection#releaseSavepoint
*/
void releaseSavepoint(Object savepoint) throws TransactionException;
}

View File

@ -0,0 +1,264 @@
/*
* 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;
import java.sql.Connection;
/**
* Interface that defines Spring-compliant transaction properties.
* Based on the propagation behavior definitions analogous to EJB CMT attributes.
*
* <p>Note that isolation level and timeout settings will not get applied unless
* an actual new transaction gets started. As only {@link #PROPAGATION_REQUIRED},
* {@link #PROPAGATION_REQUIRES_NEW} and {@link #PROPAGATION_NESTED} can cause
* that, it usually doesn't make sense to specify those settings in other cases.
* Furthermore, be aware that not all transaction managers will support those
* advanced features and thus might throw corresponding exceptions when given
* non-default values.
*
* <p>The {@link #isReadOnly() read-only flag} applies to any transaction context,
* whether backed by an actual resource transaction or operating non-transactionally
* at the resource level. In the latter case, the flag will only apply to managed
* resources within the application, such as a Hibernate <code>Session</code>.
*
* @author Juergen Hoeller
* @since 08.05.2003
* @see PlatformTransactionManager#getTransaction(TransactionDefinition)
* @see org.springframework.transaction.support.DefaultTransactionDefinition
* @see org.springframework.transaction.interceptor.TransactionAttribute
*/
public interface TransactionDefinition {
/**
* Support a current transaction; create a new one if none exists.
* Analogous to the EJB transaction attribute of the same name.
* <p>This is typically the default setting of a transaction definition,
* and typically defines a transaction synchronization scope.
*/
int PROPAGATION_REQUIRED = 0;
/**
* Support a current transaction; execute non-transactionally if none exists.
* Analogous to the EJB transaction attribute of the same name.
* <p><b>NOTE:</b> For transaction managers with transaction synchronization,
* <code>PROPAGATION_SUPPORTS</code> is slightly different from no transaction
* at all, as it defines a transaction scope that synchronization might apply to.
* As a consequence, the same resources (a JDBC <code>Connection</code>, a
* Hibernate <code>Session</code>, etc) will be shared for the entire specified
* scope. Note that the exact behavior depends on the actual synchronization
* configuration of the transaction manager!
* <p>In general, use <code>PROPAGATION_SUPPORTS</code> with care! In particular, do
* not rely on <code>PROPAGATION_REQUIRED</code> or <code>PROPAGATION_REQUIRES_NEW</code>
* <i>within</i> a <code>PROPAGATION_SUPPORTS</code> scope (which may lead to
* synchronization conflicts at runtime). If such nesting is unavoidable, make sure
* to configure your transaction manager appropriately (typically switching to
* "synchronization on actual transaction").
* @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setTransactionSynchronization
* @see org.springframework.transaction.support.AbstractPlatformTransactionManager#SYNCHRONIZATION_ON_ACTUAL_TRANSACTION
*/
int PROPAGATION_SUPPORTS = 1;
/**
* Support a current transaction; throw an exception if no current transaction
* exists. Analogous to the EJB transaction attribute of the same name.
* <p>Note that transaction synchronization within a <code>PROPAGATION_MANDATORY</code>
* scope will always be driven by the surrounding transaction.
*/
int PROPAGATION_MANDATORY = 2;
/**
* Create a new transaction, suspending the current transaction if one exists.
* Analogous to the EJB transaction attribute of the same name.
* <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
* on all transaction managers. This in particular applies to
* {@link org.springframework.transaction.jta.JtaTransactionManager},
* which requires the <code>javax.transaction.TransactionManager</code>
* to be made available it to it (which is server-specific in standard J2EE).
* <p>A <code>PROPAGATION_REQUIRES_NEW</code> scope always defines its own
* transaction synchronizations. Existing synchronizations will be suspended
* and resumed appropriately.
* @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
*/
int PROPAGATION_REQUIRES_NEW = 3;
/**
* Do not support a current transaction; rather always execute non-transactionally.
* Analogous to the EJB transaction attribute of the same name.
* <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
* on all transaction managers. This in particular applies to
* {@link org.springframework.transaction.jta.JtaTransactionManager},
* which requires the <code>javax.transaction.TransactionManager</code>
* to be made available it to it (which is server-specific in standard J2EE).
* <p>Note that transaction synchronization is <i>not</i> available within a
* <code>PROPAGATION_NOT_SUPPORTED</code> scope. Existing synchronizations
* will be suspended and resumed appropriately.
* @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
*/
int PROPAGATION_NOT_SUPPORTED = 4;
/**
* Do not support a current transaction; throw an exception if a current transaction
* exists. Analogous to the EJB transaction attribute of the same name.
* <p>Note that transaction synchronization is <i>not</i> available within a
* <code>PROPAGATION_NEVER</code> scope.
*/
int PROPAGATION_NEVER = 5;
/**
* Execute within a nested transaction if a current transaction exists,
* behave like {@link #PROPAGATION_REQUIRED} else. There is no analogous
* feature in EJB.
* <p><b>NOTE:</b> Actual creation of a nested transaction will only work on specific
* transaction managers. Out of the box, this only applies to the JDBC
* {@link org.springframework.jdbc.datasource.DataSourceTransactionManager}
* when working on a JDBC 3.0 driver. Some JTA providers might support
* nested transactions as well.
* @see org.springframework.jdbc.datasource.DataSourceTransactionManager
*/
int PROPAGATION_NESTED = 6;
/**
* Use the default isolation level of the underlying datastore.
* All other levels correspond to the JDBC isolation levels.
* @see java.sql.Connection
*/
int ISOLATION_DEFAULT = -1;
/**
* Indicates that dirty reads, non-repeatable reads and phantom reads
* can occur.
* <p>This level allows a row changed by one transaction to be read by
* another transaction before any changes in that row have been committed
* (a "dirty read"). If any of the changes are rolled back, the second
* transaction will have retrieved an invalid row.
* @see java.sql.Connection#TRANSACTION_READ_UNCOMMITTED
*/
int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;
/**
* Indicates that dirty reads are prevented; non-repeatable reads and
* phantom reads can occur.
* <p>This level only prohibits a transaction from reading a row
* with uncommitted changes in it.
* @see java.sql.Connection#TRANSACTION_READ_COMMITTED
*/
int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;
/**
* Indicates that dirty reads and non-repeatable reads are prevented;
* phantom reads can occur.
* <p>This level prohibits a transaction from reading a row with
* uncommitted changes in it, and it also prohibits the situation
* where one transaction reads a row, a second transaction alters
* the row, and the first transaction rereads the row, getting
* different values the second time (a "non-repeatable read").
* @see java.sql.Connection#TRANSACTION_REPEATABLE_READ
*/
int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;
/**
* Indicates that dirty reads, non-repeatable reads and phantom reads
* are prevented.
* <p>This level includes the prohibitions in
* {@link #ISOLATION_REPEATABLE_READ} and further prohibits the
* situation where one transaction reads all rows that satisfy a
* <code>WHERE</code> condition, a second transaction inserts a
* row that satisfies that <code>WHERE</code> condition, and the
* first transaction rereads for the same condition, retrieving
* the additional "phantom" row in the second read.
* @see java.sql.Connection#TRANSACTION_SERIALIZABLE
*/
int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;
/**
* Use the default timeout of the underlying transaction system,
* or none if timeouts are not supported.
*/
int TIMEOUT_DEFAULT = -1;
/**
* Return the propagation behavior.
* <p>Must return one of the <code>PROPAGATION_XXX</code> constants
* defined on {@link TransactionDefinition this interface}.
* @return the propagation behavior
* @see #PROPAGATION_REQUIRED
* @see org.springframework.transaction.support.TransactionSynchronizationManager#isActualTransactionActive()
*/
int getPropagationBehavior();
/**
* Return the isolation level.
* <p>Must return one of the <code>ISOLATION_XXX</code> constants
* defined on {@link TransactionDefinition this interface}.
* <p>Only makes sense in combination with {@link #PROPAGATION_REQUIRED}
* or {@link #PROPAGATION_REQUIRES_NEW}.
* <p>Note that a transaction manager that does not support custom
* isolation levels will throw an exception when given any other level
* than {@link #ISOLATION_DEFAULT}.
* @return the isolation level
*/
int getIsolationLevel();
/**
* Return the transaction timeout.
* <p>Must return a number of seconds, or {@link #TIMEOUT_DEFAULT}.
* <p>Only makes sense in combination with {@link #PROPAGATION_REQUIRED}
* or {@link #PROPAGATION_REQUIRES_NEW}.
* <p>Note that a transaction manager that does not support timeouts
* will throw an exception when given any other timeout than
* {@link #TIMEOUT_DEFAULT}.
* @return the transaction timeout
*/
int getTimeout();
/**
* Return whether to optimize as a read-only transaction.
* <p>The read-only flag applies to any transaction context, whether
* backed by an actual resource transaction
* ({@link #PROPAGATION_REQUIRED}/{@link #PROPAGATION_REQUIRES_NEW}) or
* operating non-transactionally at the resource level
* ({@link #PROPAGATION_SUPPORTS}). In the latter case, the flag will
* only apply to managed resources within the application, such as a
* Hibernate <code>Session</code>.
* <p>This just serves as a hint for the actual transaction subsystem;
* it will <i>not necessarily</i> cause failure of write access attempts.
* A transaction manager that cannot interpret the read-only hint will
* <i>not</i> throw an exception when asked for a read-only transaction.
* @return <code>true</code> if the transaction is to be optimized as read-only
* @see org.springframework.transaction.support.TransactionSynchronization#beforeCommit(boolean)
* @see org.springframework.transaction.support.TransactionSynchronizationManager#isCurrentTransactionReadOnly()
*/
boolean isReadOnly();
/**
* Return the name of this transaction. Can be <code>null</code>.
* <p>This will be used as the transaction name to be shown in a
* transaction monitor, if applicable (for example, WebLogic's).
* <p>In case of Spring's declarative transactions, the exposed name
* must (and will) be the
* <code>fully-qualified class name + "." + method name</code>
* (by default).
* @return the name of this transaction
* @see org.springframework.transaction.interceptor.TransactionAspectSupport
* @see org.springframework.transaction.support.TransactionSynchronizationManager#getCurrentTransactionName()
*/
String getName();
}

Some files were not shown because too many files have changed in this diff Show More