Initial import of tx bundle
This commit is contained in:
parent
3b6f092219
commit
846b848fd3
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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 {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<html>
|
||||
<body>
|
||||
|
||||
Support classes for DAO implementations,
|
||||
providing miscellaneous utility methods.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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">
|
||||
* <bean id="myTargetConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
|
||||
* <property name="jndiName" value="java:comp/env/cci/mycf"/>
|
||||
* </bean>
|
||||
*
|
||||
* <bean id="myConnectionFactory" class="org.springframework.jca.cci.connection.ConnectionSpecConnectionFactoryAdapter">
|
||||
* <property name="targetConnectionFactory" ref="myTargetConnectionFactory"/>
|
||||
* <property name="connectionSpec">
|
||||
* <bean class="your.resource.adapter.ConnectionSpecImpl">
|
||||
* <property name="username" value="myusername"/>
|
||||
* <property name="password" value="mypassword"/>
|
||||
* </bean>
|
||||
* </property>
|
||||
* </bean></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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<html>
|
||||
<body>
|
||||
|
||||
Provides the core JCA CCI support, based on CciTemplate
|
||||
and its associated callback interfaces.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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">
|
||||
* <?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></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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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">
|
||||
* <bean class="org.springframework.jca.endpoint.GenericMessageEndpointManager">
|
||||
* <property name="resourceAdapter" ref="resourceAdapter"/>
|
||||
* <property name="messageEndpointFactory">
|
||||
* <bean class="org.springframework.jca.endpoint.GenericMessageEndpointFactory">
|
||||
* <property name="messageListener" ref="messageListener"/>
|
||||
* </bean>
|
||||
* </property>
|
||||
* <property name="activationSpec">
|
||||
* <bean class="org.apache.activemq.ra.ActiveMQActivationSpec">
|
||||
* <property name="destination" value="myQueue"/>
|
||||
* <property name="destinationType" value="javax.jms.Queue"/>
|
||||
* </bean>
|
||||
* </property>
|
||||
* </bean></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">
|
||||
* <bean id="messageListener" class="com.myorg.messaging.myMessageListener">
|
||||
* ...
|
||||
* </bean></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">
|
||||
* <bean id="resourceAdapter" class="org.springframework.jca.support.ResourceAdapterFactoryBean">
|
||||
* <property name="resourceAdapter">
|
||||
* <bean class="org.apache.activemq.ra.ActiveMQResourceAdapter">
|
||||
* <property name="serverUrl" value="tcp://localhost:61616"/>
|
||||
* </bean>
|
||||
* </property>
|
||||
* <property name="workManager">
|
||||
* <bean class="org.springframework.jca.work.SimpleTaskWorkManager"/>
|
||||
* </property>
|
||||
* </bean></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">
|
||||
* <bean class="org.springframework.jca.endpoint.GenericMessageEndpointManager">
|
||||
* <property name="resourceAdapter" ref="resourceAdapter"/>
|
||||
* <property name="messageEndpointFactory">
|
||||
* <bean class="org.springframework.jca.endpoint.GenericMessageEndpointFactory">
|
||||
* <property name="messageListener" ref="messageListener"/>
|
||||
* <property name="transactionManager" ref="transactionManager"/>
|
||||
* </bean>
|
||||
* </property>
|
||||
* <property name="activationSpec">
|
||||
* <bean class="org.apache.activemq.ra.ActiveMQActivationSpec">
|
||||
* <property name="destination" value="myQueue"/>
|
||||
* <property name="destinationType" value="javax.jms.Queue"/>
|
||||
* </bean>
|
||||
* </property>
|
||||
* </bean>
|
||||
*
|
||||
* <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/></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">
|
||||
* <bean class="org.springframework.jca.endpoint.GenericMessageEndpointManager">
|
||||
* <property name="resourceAdapter" ref="resourceAdapter"/>
|
||||
* <property name="messageEndpointFactory">
|
||||
* <bean class="org.springframework.jca.endpoint.GenericMessageEndpointFactory">
|
||||
* <property name="messageListener" ref="messageListener"/>
|
||||
* </bean>
|
||||
* </property>
|
||||
* <property name="activationSpec">
|
||||
* <bean class="org.apache.activemq.ra.ActiveMQActivationSpec">
|
||||
* <property name="destination" value="myQueue"/>
|
||||
* <property name="destinationType" value="javax.jms.Queue"/>
|
||||
* <property name="useRAManagedTransaction" value="true"/>
|
||||
* </bean>
|
||||
* </property>
|
||||
* </bean></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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<html>
|
||||
<body>
|
||||
|
||||
This package provides a facility for generic JCA message endpoint management.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
@ -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() {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
@ -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
Loading…
Reference in New Issue