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

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

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

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

will show history up until the renaming event, where

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

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

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

View File

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

View File

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

View File

@@ -0,0 +1,44 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.dao;
/**
* Exception thrown when we couldn't cleanup after a data access operation,
* but the actual operation went OK.
*
* <p>For example, this exception or a subclass might be thrown if a JDBC
* Connection couldn't be closed after it had been used successfully.
*
* <p>Note that data access code might perform resources cleanup in a
* finally block and therefore log cleanup failure rather than rethrow it,
* to keep the original data access exception, if any.
*
* @author Rod Johnson
*/
public class CleanupFailureDataAccessException extends NonTransientDataAccessException {
/**
* Constructor for CleanupFailureDataAccessException.
* @param msg the detail message
* @param cause the root cause from the underlying data access API,
* such as JDBC
*/
public CleanupFailureDataAccessException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.dao;
/**
* Exception thrown on concurrency failure.
*
* <p>This exception should be subclassed to indicate the type of failure:
* optimistic locking, failure to acquire lock, etc.
*
* @author Thomas Risberg
* @since 1.1
* @see OptimisticLockingFailureException
* @see PessimisticLockingFailureException
* @see CannotAcquireLockException
* @see DeadlockLoserDataAccessException
*/
public class ConcurrencyFailureException extends TransientDataAccessException {
/**
* Constructor for ConcurrencyFailureException.
* @param msg the detail message
*/
public ConcurrencyFailureException(String msg) {
super(msg);
}
/**
* Constructor for ConcurrencyFailureException.
* @param msg the detail message
* @param cause the root cause from the data access API in use
*/
public ConcurrencyFailureException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.dao;
import org.springframework.core.NestedRuntimeException;
/**
* Root of the hierarchy of data access exceptions discussed in
* <a href="http://www.amazon.com/exec/obidos/tg/detail/-/0764543857/">Expert One-On-One J2EE Design and Development</a>.
* Please see Chapter 9 of this book for detailed discussion of the
* motivation for this package.
*
* <p>This exception hierarchy aims to let user code find and handle the
* kind of error encountered without knowing the details of the particular
* data access API in use (e.g. JDBC). Thus it is possible to react to an
* optimistic locking failure without knowing that JDBC is being used.
*
* <p>As this class is a runtime exception, there is no need for user code
* to catch it or subclasses if any error is to be considered fatal
* (the usual case).
*
* @author Rod Johnson
*/
public abstract class DataAccessException extends NestedRuntimeException {
/**
* Constructor for DataAccessException.
* @param msg the detail message
*/
public DataAccessException(String msg) {
super(msg);
}
/**
* Constructor for DataAccessException.
* @param msg the detail message
* @param cause the root cause (usually from using a underlying
* data access API such as JDBC)
*/
public DataAccessException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.dao;
/**
* Data access exception thrown when a resource fails completely:
* for example, if we can't connect to a database using JDBC.
*
* @author Rod Johnson
* @author Thomas Risberg
*/
public class DataAccessResourceFailureException extends NonTransientDataAccessResourceException {
/**
* Constructor for DataAccessResourceFailureException.
* @param msg the detail message
*/
public DataAccessResourceFailureException(String msg) {
super(msg);
}
/**
* Constructor for DataAccessResourceFailureException.
* @param msg the detail message
* @param cause the root cause from the data access API in use
*/
public DataAccessResourceFailureException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.dao;
/**
* Exception thrown when an attempt to insert or update data
* results in violation of an integrity constraint. Note that this
* is not purely a relational concept; unique primary keys are
* required by most database types.
*
* @author Rod Johnson
*/
public class DataIntegrityViolationException extends NonTransientDataAccessException {
/**
* Constructor for DataIntegrityViolationException.
* @param msg the detail message
*/
public DataIntegrityViolationException(String msg) {
super(msg);
}
/**
* Constructor for DataIntegrityViolationException.
* @param msg the detail message
* @param cause the root cause from the data access API in use
*/
public DataIntegrityViolationException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.dao;
/**
* Exception thrown if certain expected data could not be retrieved, e.g.
* when looking up specific data via a known identifier. This exception
* will be thrown either by O/R mapping tools or by DAO implementations.
*
* @author Juergen Hoeller
* @since 13.10.2003
*/
public class DataRetrievalFailureException extends NonTransientDataAccessException {
/**
* Constructor for DataRetrievalFailureException.
* @param msg the detail message
*/
public DataRetrievalFailureException(String msg) {
super(msg);
}
/**
* Constructor for DataRetrievalFailureException.
* @param msg the detail message
* @param cause the root cause from the data access API in use
*/
public DataRetrievalFailureException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

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

View File

@@ -0,0 +1,46 @@
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.dao;
/**
* Exception thrown when an attempt to insert or update data
* results in violation of an primary key or unique constraint.
* Note that this is not necessarily a purely relational concept;
* unique primary keys are required by most database types.
*
* @author Thomas Risberg
*/
public class DuplicateKeyException extends DataIntegrityViolationException {
/**
* Constructor for DuplicateKeyException.
* @param msg the detail message
*/
public DuplicateKeyException(String msg) {
super(msg);
}
/**
* Constructor for DuplicateKeyException.
* @param msg the detail message
* @param cause the root cause from the data access API in use
*/
public DuplicateKeyException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.dao;
/**
* Data access exception thrown when a result was expected to have at least
* one row (or element) but zero rows (or elements) were actually returned.
*
* @author Juergen Hoeller
* @since 2.0
* @see IncorrectResultSizeDataAccessException
*/
public class EmptyResultDataAccessException extends IncorrectResultSizeDataAccessException {
/**
* Constructor for EmptyResultDataAccessException.
* @param expectedSize the expected result size
*/
public EmptyResultDataAccessException(int expectedSize) {
super(expectedSize, 0);
}
/**
* Constructor for EmptyResultDataAccessException.
* @param msg the detail message
* @param expectedSize the expected result size
*/
public EmptyResultDataAccessException(String msg, int expectedSize) {
super(msg, expectedSize, 0);
}
}

View File

@@ -0,0 +1,107 @@
/*
* 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
* @author Chris Beams
* @since 1.0.2
* @see EmptyResultDataAccessException
*/
@SuppressWarnings("serial")
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 ex the wrapped exception
* @param expectedSize the expected result size
*/
public IncorrectResultSizeDataAccessException(String msg, int expectedSize, Throwable ex) {
super(msg, ex);
this.expectedSize = expectedSize;
this.actualSize = -1;
}
/**
* Constructor for IncorrectResultSizeDataAccessException.
* @param msg the detail message
* @param expectedSize the expected result size
* @param actualSize the actual result size (or -1 if unknown)
*/
public IncorrectResultSizeDataAccessException(String msg, int expectedSize, int actualSize) {
super(msg);
this.expectedSize = expectedSize;
this.actualSize = actualSize;
}
/**
* Return the expected result size.
*/
public int getExpectedSize() {
return expectedSize;
}
/**
* Return the actual result size (or -1 if unknown).
*/
public int getActualSize() {
return actualSize;
}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.dao;
/**
* Data access exception thrown when something unintended appears to have
* happened with an update, but the transaction hasn't already been rolled back.
* Thrown, for example, when we wanted to update 1 row in an RDBMS but actually
* updated 3.
*
* @author Rod Johnson
*/
public class IncorrectUpdateSemanticsDataAccessException extends InvalidDataAccessResourceUsageException {
/**
* Constructor for IncorrectUpdateSemanticsDataAccessException.
* @param msg the detail message
*/
public IncorrectUpdateSemanticsDataAccessException(String msg) {
super(msg);
}
/**
* Constructor for IncorrectUpdateSemanticsDataAccessException.
* @param msg the detail message
* @param cause the root cause from the underlying API, such as JDBC
*/
public IncorrectUpdateSemanticsDataAccessException(String msg, Throwable cause) {
super(msg, cause);
}
/**
* Return whether data was updated.
* If this method returns false, there's nothing to roll back.
* <p>The default implementation always returns true.
* This can be overridden in subclasses.
*/
public boolean wasDataUpdated() {
return true;
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.dao;
/**
* Exception thrown on incorrect usage of the API, such as failing to
* "compile" a query object that needed compilation before execution.
*
* <p>This represents a problem in our Java data access framework,
* not the underlying data access infrastructure.
*
* @author Rod Johnson
*/
public class InvalidDataAccessApiUsageException extends NonTransientDataAccessException {
/**
* Constructor for InvalidDataAccessApiUsageException.
* @param msg the detail message
*/
public InvalidDataAccessApiUsageException(String msg) {
super(msg);
}
/**
* Constructor for InvalidDataAccessApiUsageException.
* @param msg the detail message
* @param cause the root cause from the data access API in use
*/
public InvalidDataAccessApiUsageException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.dao;
/**
* Root for exceptions thrown when we use a data access resource incorrectly.
* Thrown for example on specifying bad SQL when using a RDBMS.
* Resource-specific subclasses are supplied by concrete data access packages.
*
* @author Rod Johnson
*/
public class InvalidDataAccessResourceUsageException extends NonTransientDataAccessException {
/**
* Constructor for InvalidDataAccessResourceUsageException.
* @param msg the detail message
*/
public InvalidDataAccessResourceUsageException(String msg) {
super(msg);
}
/**
* Constructor for InvalidDataAccessResourceUsageException.
* @param msg the detail message
* @param cause the root cause from the data access API in use
*/
public InvalidDataAccessResourceUsageException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.dao;
/**
* Root of the hierarchy of data access exceptions that are considered non-transient -
* where a retry of the same operation would fail unless the cause of the Exception
* is corrected.
*
* @author Thomas Risberg
* @since 2.5
* @see java.sql.SQLNonTransientException
*/
public abstract class NonTransientDataAccessException extends DataAccessException {
/**
* Constructor for NonTransientDataAccessException.
* @param msg the detail message
*/
public NonTransientDataAccessException(String msg) {
super(msg);
}
/**
* Constructor for NonTransientDataAccessException.
* @param msg the detail message
* @param cause the root cause (usually from using a underlying
* data access API such as JDBC)
*/
public NonTransientDataAccessException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.dao;
/**
* Data access exception thrown when a resource fails completely and the failure is permanent.
*
* @author Thomas Risberg
* @since 2.5
* @see java.sql.SQLNonTransientConnectionException
*/
public class NonTransientDataAccessResourceException extends NonTransientDataAccessException {
/**
* Constructor for NonTransientDataAccessResourceException.
* @param msg the detail message
*/
public NonTransientDataAccessResourceException(String msg) {
super(msg);
}
/**
* Constructor for NonTransientDataAccessResourceException.
* @param msg the detail message
* @param cause the root cause from the data access API in use
*/
public NonTransientDataAccessResourceException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.dao;
/**
* Exception thrown on an optimistic locking violation.
*
* <p>This exception will be thrown either by O/R mapping tools
* or by custom DAO implementations. Optimistic locking failure
* is typically <i>not</i> detected by the database itself.
*
* @author Rod Johnson
* @see PessimisticLockingFailureException
*/
public class OptimisticLockingFailureException extends ConcurrencyFailureException {
/**
* Constructor for OptimisticLockingFailureException.
* @param msg the detail message
*/
public OptimisticLockingFailureException(String msg) {
super(msg);
}
/**
* Constructor for OptimisticLockingFailureException.
* @param msg the detail message
* @param cause the root cause from the data access API in use
*/
public OptimisticLockingFailureException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.dao;
/**
* Exception thrown when the underlying resource denied a permission
* to access a specific element, such as a specific database table.
*
* @author Juergen Hoeller
* @since 2.0
*/
public class PermissionDeniedDataAccessException extends NonTransientDataAccessException {
/**
* Constructor for PermissionDeniedDataAccessException.
* @param msg the detail message
* @param cause the root cause from the underlying data access API,
* such as JDBC
*/
public PermissionDeniedDataAccessException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.dao;
/**
* Exception thrown on a pessimistic locking violation.
* Thrown by Spring's SQLException translation mechanism
* if a corresponding database error is encountered.
*
* <p>Serves as superclass for more specific exceptions, like
* CannotAcquireLockException and DeadlockLoserDataAccessException.
*
* @author Thomas Risberg
* @since 1.2
* @see CannotAcquireLockException
* @see DeadlockLoserDataAccessException
* @see OptimisticLockingFailureException
*/
public class PessimisticLockingFailureException extends ConcurrencyFailureException {
/**
* Constructor for PessimisticLockingFailureException.
* @param msg the detail message
*/
public PessimisticLockingFailureException(String msg) {
super(msg);
}
/**
* Constructor for PessimisticLockingFailureException.
* @param msg the detail message
* @param cause the root cause from the data access API in use
*/
public PessimisticLockingFailureException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.dao;
/**
* Data access exception thrown when a previously failed operation might be able
* to succeed if the application performs some recovery steps and retries the entire
* transaction or in the case of a distributed transaction, the transaction branch.
* At a minimum, the recovery operation must include closing the current connection
* and getting a new connection.
*
* @author Thomas Risberg
* @since 2.5
* @see java.sql.SQLRecoverableException
*/
public class RecoverableDataAccessException extends DataAccessException {
/**
* Constructor for RecoverableDataAccessException.
* @param msg the detail message
*/
public RecoverableDataAccessException(String msg) {
super(msg);
}
/**
* Constructor for RecoverableDataAccessException.
* @param msg the detail message
* @param cause the root cause (usually from using a underlying
* data access API such as JDBC)
*/
public RecoverableDataAccessException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.dao;
/**
* Root of the hierarchy of data access exceptions that are considered transient -
* where a previously failed operation might be able to succeed when the operation
* is retried without any intervention by application-level functionality.
*
* @author Thomas Risberg
* @since 2.5
* @see java.sql.SQLTransientException
*/
public abstract class TransientDataAccessException extends DataAccessException {
/**
* Constructor for TransientDataAccessException.
* @param msg the detail message
*/
public TransientDataAccessException(String msg) {
super(msg);
}
/**
* Constructor for TransientDataAccessException.
* @param msg the detail message
* @param cause the root cause (usually from using a underlying
* data access API such as JDBC)
*/
public TransientDataAccessException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.dao;
/**
* Data access exception thrown when a resource fails temporarily
* and the operation can be retried.
*
* @author Thomas Risberg
* @since 2.5
* @see java.sql.SQLTransientConnectionException
*/
public class TransientDataAccessResourceException extends TransientDataAccessException {
/**
* Constructor for TransientDataAccessResourceException.
* @param msg the detail message
*/
public TransientDataAccessResourceException(String msg) {
super(msg);
}
/**
* Constructor for TransientDataAccessResourceException.
* @param msg the detail message
* @param cause the root cause from the data access API in use
*/
public TransientDataAccessResourceException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.dao;
/**
* Exception thrown on mismatch between Java type and database type:
* for example on an attempt to set an object of the wrong type
* in an RDBMS column.
*
* @author Rod Johnson
*/
public class TypeMismatchDataAccessException extends InvalidDataAccessResourceUsageException {
/**
* Constructor for TypeMismatchDataAccessException.
* @param msg the detail message
*/
public TypeMismatchDataAccessException(String msg) {
super(msg);
}
/**
* Constructor for TypeMismatchDataAccessException.
* @param msg the detail message
* @param cause the root cause from the data access API in use
*/
public TypeMismatchDataAccessException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.dao;
/**
* Normal superclass when we can't distinguish anything more specific
* than "something went wrong with the underlying resource": for example,
* a SQLException from JDBC we can't pinpoint more precisely.
*
* @author Rod Johnson
*/
public abstract class UncategorizedDataAccessException extends NonTransientDataAccessException {
/**
* Constructor for UncategorizedDataAccessException.
* @param msg the detail message
* @param cause the exception thrown by underlying data access API
*/
public UncategorizedDataAccessException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@@ -0,0 +1,83 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.dao.annotation;
import java.lang.annotation.Annotation;
import org.aopalliance.aop.Advice;
import org.springframework.aop.Pointcut;
import org.springframework.aop.support.AbstractPointcutAdvisor;
import org.springframework.aop.support.annotation.AnnotationMatchingPointcut;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.dao.support.PersistenceExceptionTranslationInterceptor;
import org.springframework.dao.support.PersistenceExceptionTranslator;
/**
* Spring AOP exception translation aspect for use at Repository or DAO layer level.
* Translates native persistence exceptions into Spring's DataAccessException hierarchy,
* based on a given PersistenceExceptionTranslator.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @since 2.0
* @see org.springframework.dao.DataAccessException
* @see org.springframework.dao.support.PersistenceExceptionTranslator
*/
public class PersistenceExceptionTranslationAdvisor extends AbstractPointcutAdvisor {
private final PersistenceExceptionTranslationInterceptor advice;
private final AnnotationMatchingPointcut pointcut;
/**
* Create a new PersistenceExceptionTranslationAdvisor.
* @param persistenceExceptionTranslator the PersistenceExceptionTranslator to use
* @param repositoryAnnotationType the annotation type to check for
*/
public PersistenceExceptionTranslationAdvisor(
PersistenceExceptionTranslator persistenceExceptionTranslator,
Class<? extends Annotation> repositoryAnnotationType) {
this.advice = new PersistenceExceptionTranslationInterceptor(persistenceExceptionTranslator);
this.pointcut = new AnnotationMatchingPointcut(repositoryAnnotationType, true);
}
/**
* Create a new PersistenceExceptionTranslationAdvisor.
* @param beanFactory the ListableBeanFactory to obtaining all
* PersistenceExceptionTranslators from
* @param repositoryAnnotationType the annotation type to check for
*/
PersistenceExceptionTranslationAdvisor(
ListableBeanFactory beanFactory, Class<? extends Annotation> repositoryAnnotationType) {
this.advice = new PersistenceExceptionTranslationInterceptor(beanFactory);
this.pointcut = new AnnotationMatchingPointcut(repositoryAnnotationType, true);
}
public Advice getAdvice() {
return this.advice;
}
public Pointcut getPointcut() {
return this.pointcut;
}
}

View File

@@ -0,0 +1,142 @@
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.dao.annotation;
import java.lang.annotation.Annotation;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.AopInfrastructureBean;
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 marked with Spring's @{@link org.springframework.stereotype.Repository 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 DataAccessException} hierarchy.
* Autodetects beans that implement the
* {@link org.springframework.dao.support.PersistenceExceptionTranslator
* PersistenceExceptionTranslator} interface, which are subsequently asked to translate
* candidate exceptions.
*
* <p>All of Spring's applicable resource factories (e.g. {@link
* org.springframework.orm.hibernate3.LocalSessionFactoryBean LocalSessionFactoryBean},
* {@link org.springframework.orm.jpa.LocalEntityManagerFactoryBean
* LocalEntityManagerFactoryBean}) implement the {@code PersistenceExceptionTranslator}
* 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 Repositories or
* DAOs) with the {@code @Repository} annotation, along with defining this post-processor
* as a 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
*/
@SuppressWarnings("serial")
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 repository 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, "'repositoryAnnotationType' 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) {
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof AopInfrastructureBean) {
// Ignore AOP infrastructure such as scoped proxies.
return bean;
}
Class<?> targetClass = AopUtils.getTargetClass(bean);
if (AopUtils.canApply(this.persistenceExceptionTranslationAdvisor, targetClass)) {
if (bean instanceof Advised) {
((Advised) bean).addAdvisor(this.persistenceExceptionTranslationAdvisor);
return bean;
}
else {
ProxyFactory proxyFactory = new ProxyFactory(bean);
// Copy our properties (proxyTargetClass etc) inherited from ProxyConfig.
proxyFactory.copyFrom(this);
proxyFactory.addAdvisor(this.persistenceExceptionTranslationAdvisor);
return proxyFactory.getProxy(this.beanClassLoader);
}
}
else {
// This is not a repository.
return bean;
}
}
}

View File

@@ -0,0 +1,9 @@
/**
*
* Annotation support for DAOs. Contains a bean post-processor for translating
* persistence exceptions based on a repository stereotype annotation.
*
*/
package org.springframework.dao.annotation;

View File

@@ -0,0 +1,20 @@
/**
*
* 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).
*
*/
package org.springframework.dao;

View File

@@ -0,0 +1,66 @@
/*
* 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.support;
import java.util.ArrayList;
import java.util.List;
import org.springframework.dao.DataAccessException;
import org.springframework.util.Assert;
/**
* Implementation of {@link 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<PersistenceExceptionTranslator> delegates = new ArrayList<PersistenceExceptionTranslator>(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 this.delegates.toArray(new PersistenceExceptionTranslator[this.delegates.size()]);
}
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
for (PersistenceExceptionTranslator pet : this.delegates) {
DataAccessException translatedDex = pet.translateExceptionIfPossible(ex);
if (translatedDex != null) {
return translatedDex;
}
}
return null;
}
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.dao.support;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.InitializingBean;
/**
* Generic base class for DAOs, defining template methods for DAO initialization.
*
* <p>Extended by Spring's specific DAO support classes, such as:
* JdbcDaoSupport, JdoDaoSupport, etc.
*
* @author Juergen Hoeller
* @since 1.2.2
* @see org.springframework.jdbc.core.support.JdbcDaoSupport
* @see org.springframework.orm.jdo.support.JdoDaoSupport
*/
public abstract class DaoSupport implements InitializingBean {
/** Logger available to subclasses */
protected final Log logger = LogFactory.getLog(getClass());
public final void afterPropertiesSet() throws IllegalArgumentException, BeanInitializationException {
// Let abstract subclasses check their configuration.
checkDaoConfig();
// Let concrete implementations initialize themselves.
try {
initDao();
}
catch (Exception ex) {
throw new BeanInitializationException("Initialization of DAO failed", ex);
}
}
/**
* Abstract subclasses must override this to check their configuration.
* <p>Implementors should be marked as <code>final</code if concrete subclasses
* are not supposed to override this template method themselves.
* @throws IllegalArgumentException in case of illegal configuration
*/
protected abstract void checkDaoConfig() throws IllegalArgumentException;
/**
* Concrete subclasses can override this for custom initialization behavior.
* Gets called after population of this instance's bean properties.
* @throws Exception if DAO initialization fails
* (will be rethrown as a BeanInitializationException)
* @see org.springframework.beans.factory.BeanInitializationException
*/
protected void initDao() throws Exception {
}
}

View File

@@ -0,0 +1,217 @@
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.dao.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 <T> T singleResult(Collection<T> 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 <T> T requiredSingleResult(Collection<T> 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 <T> T uniqueResult(Collection<T> 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 <T> T requiredUniqueResult(Collection<T> 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
*/
@SuppressWarnings("unchecked")
public static <T> T objectResult(Collection<?> results, Class<T> 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), (Class<? extends Number>) 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 (T) 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 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 objectResult(results, Number.class).longValue();
}
/**
* Return a translated exception if this is appropriate,
* otherwise return the input exception.
* @param rawException exception we may wish to translate
* @param pet PersistenceExceptionTranslator to use to perform the translation
* @return a translated exception if translation is possible, or
* the raw exception if it is not
*/
public static RuntimeException translateIfNecessary(
RuntimeException rawException, PersistenceExceptionTranslator pet) {
Assert.notNull(pet, "PersistenceExceptionTranslator must not be null");
DataAccessException dex = pet.translateExceptionIfPossible(rawException);
return (dex != null ? dex : rawException);
}
}

View File

@@ -0,0 +1,168 @@
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.dao.support;
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;
private boolean alwaysTranslate = false;
/**
* 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;
}
/**
* Specify whether to always translate the exception ("true"), or whether throw the
* raw exception when declared, i.e. when the originating method signature's exception
* declarations allow for the raw exception to be thrown ("false").
* <p>Default is "false". Switch this flag to "true" in order to always translate
* applicable exceptions, independent from the originating method signature.
* <p>Note that the originating method does not have to declare the specific exception.
* Any base class will do as well, even <code>throws Exception</code>: As long as the
* originating method does explicitly declare compatible exceptions, the raw exception
* will be rethrown. If you would like to avoid throwing raw exceptions in any case,
* switch this flag to "true".
*/
public void setAlwaysTranslate(boolean alwaysTranslate) {
this.alwaysTranslate = alwaysTranslate;
}
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<String, PersistenceExceptionTranslator> 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 (PersistenceExceptionTranslator pet : pets.values()) {
cpet.addDelegate(pet);
}
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 (!this.alwaysTranslate && ReflectionUtils.declaresException(mi.getMethod(), ex.getClass())) {
throw ex;
}
else {
throw DataAccessUtils.translateIfNecessary(ex, this.persistenceExceptionTranslator);
}
}
}
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.dao.support;
import org.springframework.dao.DataAccessException;
/**
* Interface implemented by Spring integrations with data access technologies
* that throw runtime exceptions, such as JPA, TopLink, JDO and Hibernate.
*
* <p>This allows consistent usage of combined exception translation functionality,
* without forcing a single translator to understand every single possible type
* of exception.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @since 2.0
*/
public interface PersistenceExceptionTranslator {
/**
* Translate the given runtime exception thrown by a persistence framework to a
* corresponding exception from Spring's generic DataAccessException hierarchy,
* if possible.
* <p>Do not translate exceptions that are not understand by this translator:
* for example, if coming from another persistence framework, or resulting
* from user code and unrelated to persistence.
* <p>Of particular importance is the correct translation to
* DataIntegrityViolationException, for example on constraint violation.
* Implementations may use Spring JDBC's sophisticated exception translation
* to provide further information in the event of SQLException as a root cause.
* @param ex a RuntimeException thrown
* @return the corresponding DataAccessException (or <code>null</code> if the
* exception could not be translated, as in this case it may result from
* user code rather than an actual persistence problem)
* @see org.springframework.dao.DataIntegrityViolationException
* @see org.springframework.jdbc.support.SQLExceptionTranslator
*/
DataAccessException translateExceptionIfPossible(RuntimeException ex);
}

View File

@@ -0,0 +1,9 @@
/**
*
* Support classes for DAO implementations,
* providing miscellaneous utility methods.
*
*/
package org.springframework.dao.support;

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2002-2005 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jca.cci;
import javax.resource.ResourceException;
import org.springframework.dao.DataAccessResourceFailureException;
/**
* Exception thrown when the creating of a CCI Record failed
* for connector-internal reasons.
*
* @author Juergen Hoeller
* @since 1.2
*/
public class CannotCreateRecordException extends DataAccessResourceFailureException {
/**
* Constructor for CannotCreateRecordException.
* @param msg message
* @param ex ResourceException root cause
*/
public CannotCreateRecordException(String msg, ResourceException ex) {
super(msg, ex);
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2002-2005 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jca.cci;
import javax.resource.ResourceException;
import org.springframework.dao.DataAccessResourceFailureException;
/**
* Fatal exception thrown when we can't connect to an EIS using CCI.
*
* @author Thierry Templier
* @author Juergen Hoeller
* @since 1.2
*/
public class CannotGetCciConnectionException extends DataAccessResourceFailureException {
/**
* Constructor for CannotGetCciConnectionException.
* @param msg message
* @param ex ResourceException root cause
*/
public CannotGetCciConnectionException(String msg, ResourceException ex) {
super(msg, ex);
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2002-2005 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jca.cci;
import javax.resource.ResourceException;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
/**
* Exception thrown when the connector doesn't support a specific CCI operation.
*
* @author Juergen Hoeller
* @since 1.2
*/
public class CciOperationNotSupportedException extends InvalidDataAccessResourceUsageException {
/**
* Constructor for CciOperationNotSupportedException.
* @param msg message
* @param ex ResourceException root cause
*/
public CciOperationNotSupportedException(String msg, ResourceException ex) {
super(msg, ex);
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2002-2005 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jca.cci;
import java.sql.SQLException;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
/**
* Exception thrown when a ResultSet has been accessed in an invalid fashion.
* Such exceptions always have a <code>java.sql.SQLException</code> root cause.
*
* <p>This typically happens when an invalid ResultSet column index or name
* has been specified.
*
* @author Juergen Hoeller
* @since 1.2
* @see javax.resource.cci.ResultSet
*/
public class InvalidResultSetAccessException extends InvalidDataAccessResourceUsageException {
/**
* Constructor for InvalidResultSetAccessException.
* @param msg message
* @param ex the root cause
*/
public InvalidResultSetAccessException(String msg, SQLException ex) {
super(ex.getMessage(), ex);
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2002-2005 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jca.cci;
import javax.resource.ResourceException;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
/**
* Exception thrown when the creating of a CCI Record failed because
* the connector doesn't support the desired CCI Record type.
*
* @author Juergen Hoeller
* @since 1.2
*/
public class RecordTypeNotSupportedException extends InvalidDataAccessResourceUsageException {
/**
* Constructor for RecordTypeNotSupportedException.
* @param msg message
* @param ex ResourceException root cause
*/
public RecordTypeNotSupportedException(String msg, ResourceException ex) {
super(msg, ex);
}
}

View File

@@ -0,0 +1,273 @@
/*
* 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();
}
@Override
protected Object doGetTransaction() {
CciLocalTransactionObject txObject = new CciLocalTransactionObject();
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(getConnectionFactory());
txObject.setConnectionHolder(conHolder);
return txObject;
}
@Override
protected boolean isExistingTransaction(Object transaction) {
CciLocalTransactionObject txObject = (CciLocalTransactionObject) transaction;
// Consider a pre-bound connection as transaction.
return (txObject.getConnectionHolder() != null);
}
@Override
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);
}
}
@Override
protected Object doSuspend(Object transaction) {
CciLocalTransactionObject txObject = (CciLocalTransactionObject) transaction;
txObject.setConnectionHolder(null);
return TransactionSynchronizationManager.unbindResource(getConnectionFactory());
}
@Override
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();
}
@Override
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);
}
}
@Override
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);
}
}
@Override
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();
}
@Override
protected void doCleanupAfterCompletion(Object transaction) {
CciLocalTransactionObject txObject = (CciLocalTransactionObject) transaction;
// Remove the connection holder from the thread.
TransactionSynchronizationManager.unbindResource(getConnectionFactory());
txObject.getConnectionHolder().clear();
Connection con = txObject.getConnectionHolder().getConnection();
if (logger.isDebugEnabled()) {
logger.debug("Releasing CCI Connection [" + con + "] after transaction");
}
ConnectionFactoryUtils.releaseConnection(con, getConnectionFactory());
}
/**
* CCI local transaction object, representing a ConnectionHolder.
* Used as transaction object by CciLocalTransactionManager.
* @see ConnectionHolder
*/
private static class CciLocalTransactionObject {
private ConnectionHolder connectionHolder;
public void setConnectionHolder(ConnectionHolder connectionHolder) {
this.connectionHolder = connectionHolder;
}
public ConnectionHolder getConnectionHolder() {
return connectionHolder;
}
}
}

View File

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

View File

@@ -0,0 +1,49 @@
/*
* Copyright 2002-2005 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jca.cci.connection;
import javax.resource.cci.Connection;
import org.springframework.transaction.support.ResourceHolderSupport;
/**
* Connection holder, wrapping a CCI Connection.
*
* <p>CciLocalTransactionManager binds instances of this class
* to the thread, for a given ConnectionFactory.
*
* <p>Note: This is an SPI class, not intended to be used by applications.
*
* @author Thierry Templier
* @author Juergen Hoeller
* @since 1.2
* @see CciLocalTransactionManager
* @see ConnectionFactoryUtils
*/
public class ConnectionHolder extends ResourceHolderSupport {
private final Connection connection;
public ConnectionHolder(Connection connection) {
this.connection = connection;
}
public Connection getConnection() {
return this.connection;
}
}

View File

@@ -0,0 +1,142 @@
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jca.cci.connection;
import javax.resource.ResourceException;
import javax.resource.cci.Connection;
import javax.resource.cci.ConnectionSpec;
import org.springframework.core.NamedThreadLocal;
/**
* An adapter for a target CCI {@link javax.resource.cci.ConnectionFactory},
* applying the given ConnectionSpec to every standard <code>getConnection()</code>
* call, that is, implicitly invoking <code>getConnection(ConnectionSpec)</code>
* on the target. All other methods simply delegate to the corresponding methods
* of the target ConnectionFactory.
*
* <p>Can be used to proxy a target JNDI ConnectionFactory that does not have a
* ConnectionSpec configured. Client code can work with the ConnectionFactory
* without passing in a ConnectionSpec on every <code>getConnection()</code> call.
*
* <p>In the following example, client code can simply transparently work with
* the preconfigured "myConnectionFactory", implicitly accessing
* "myTargetConnectionFactory" with the specified user credentials.
*
* <pre class="code">
* &lt;bean id="myTargetConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean"&gt;
* &lt;property name="jndiName" value="java:comp/env/cci/mycf"/&gt;
* &lt;/bean>
*
* &lt;bean id="myConnectionFactory" class="org.springframework.jca.cci.connection.ConnectionSpecConnectionFactoryAdapter"&gt;
* &lt;property name="targetConnectionFactory" ref="myTargetConnectionFactory"/&gt;
* &lt;property name="connectionSpec"&gt;
* &lt;bean class="your.resource.adapter.ConnectionSpecImpl"&gt;
* &lt;property name="username" value="myusername"/&gt;
* &lt;property name="password" value="mypassword"/&gt;
* &lt;/bean&gt;
* &lt;/property&gt;
* &lt;/bean&gt;</pre>
*
* <p>If the "connectionSpec" is empty, this proxy will simply delegate to the
* standard <code>getConnection()</code> method of the target ConnectionFactory.
* This can be used to keep a UserCredentialsConnectionFactoryAdapter bean definition
* just for the <i>option</i> of implicitly passing in a ConnectionSpec if the
* particular target ConnectionFactory requires it.
*
* @author Juergen Hoeller
* @since 1.2
* @see #getConnection
*/
public class ConnectionSpecConnectionFactoryAdapter extends DelegatingConnectionFactory {
private ConnectionSpec connectionSpec;
private final ThreadLocal<ConnectionSpec> threadBoundSpec =
new NamedThreadLocal<ConnectionSpec>("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.remove();
}
/**
* Determine whether there is currently a thread-bound ConnectionSpec,
* using it if available, falling back to the statically specified
* "connectionSpec" property else.
* @see #doGetConnection
*/
@Override
public final Connection getConnection() throws ResourceException {
ConnectionSpec threadSpec = this.threadBoundSpec.get();
if (threadSpec != null) {
return doGetConnection(threadSpec);
}
else {
return doGetConnection(this.connectionSpec);
}
}
/**
* This implementation delegates to the <code>getConnection(ConnectionSpec)</code>
* method of the target ConnectionFactory, passing in the specified user credentials.
* If the specified username is empty, it will simply delegate to the standard
* <code>getConnection()</code> method of the target ConnectionFactory.
* @param spec the ConnectionSpec to apply
* @return the Connection
* @see javax.resource.cci.ConnectionFactory#getConnection(javax.resource.cci.ConnectionSpec)
* @see javax.resource.cci.ConnectionFactory#getConnection()
*/
protected Connection doGetConnection(ConnectionSpec spec) throws ResourceException {
if (getTargetConnectionFactory() == null) {
throw new IllegalStateException("targetConnectionFactory is required");
}
if (spec != null) {
return getTargetConnectionFactory().getConnection(spec);
}
else {
return getTargetConnectionFactory().getConnection();
}
}
}

View File

@@ -0,0 +1,93 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jca.cci.connection;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.resource.ResourceException;
import javax.resource.cci.Connection;
import javax.resource.cci.ConnectionFactory;
import javax.resource.cci.ConnectionSpec;
import javax.resource.cci.RecordFactory;
import javax.resource.cci.ResourceAdapterMetaData;
import org.springframework.beans.factory.InitializingBean;
/**
* CCI {@link ConnectionFactory} implementation that delegates all calls
* to a given target {@link ConnectionFactory}.
*
* <p>This class is meant to be subclassed, with subclasses overriding only
* those methods (such as {@link #getConnection()}) that should not simply
* delegate to the target {@link ConnectionFactory}.
*
* @author Juergen Hoeller
* @since 1.2
* @see #getConnection
*/
public class DelegatingConnectionFactory implements ConnectionFactory, InitializingBean {
private ConnectionFactory targetConnectionFactory;
/**
* Set the target ConnectionFactory that this ConnectionFactory should delegate to.
*/
public void setTargetConnectionFactory(ConnectionFactory targetConnectionFactory) {
this.targetConnectionFactory = targetConnectionFactory;
}
/**
* Return the target ConnectionFactory that this ConnectionFactory should delegate to.
*/
public ConnectionFactory getTargetConnectionFactory() {
return this.targetConnectionFactory;
}
public void afterPropertiesSet() {
if (getTargetConnectionFactory() == null) {
throw new IllegalArgumentException("Property 'targetConnectionFactory' is required");
}
}
public Connection getConnection() throws ResourceException {
return getTargetConnectionFactory().getConnection();
}
public Connection getConnection(ConnectionSpec connectionSpec) throws ResourceException {
return getTargetConnectionFactory().getConnection(connectionSpec);
}
public RecordFactory getRecordFactory() throws ResourceException {
return getTargetConnectionFactory().getRecordFactory();
}
public ResourceAdapterMetaData getMetaData() throws ResourceException {
return getTargetConnectionFactory().getMetaData();
}
public Reference getReference() throws NamingException {
return getTargetConnectionFactory().getReference();
}
public void setReference(Reference reference) {
getTargetConnectionFactory().setReference(reference);
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2002-2005 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jca.cci.connection;
import javax.resource.NotSupportedException;
import javax.resource.ResourceException;
import javax.resource.cci.IndexedRecord;
import javax.resource.cci.MappedRecord;
import javax.resource.cci.RecordFactory;
/**
* Implementation of the CCI RecordFactory interface that always throws
* NotSupportedException.
*
* <p>Useful as a placeholder for a RecordFactory argument (for example as
* defined by the RecordCreator callback), in particular when the connector's
* <code>ConnectionFactory.getRecordFactory()</code> implementation happens to
* throw NotSupportedException early rather than throwing the exception from
* RecordFactory's methods.
*
* @author Juergen Hoeller
* @since 1.2.4
* @see org.springframework.jca.cci.core.RecordCreator#createRecord(javax.resource.cci.RecordFactory)
* @see org.springframework.jca.cci.core.CciTemplate#getRecordFactory(javax.resource.cci.ConnectionFactory)
* @see javax.resource.cci.ConnectionFactory#getRecordFactory()
* @see javax.resource.NotSupportedException
*/
public class NotSupportedRecordFactory implements RecordFactory {
public MappedRecord createMappedRecord(String name) throws ResourceException {
throw new NotSupportedException("The RecordFactory facility is not supported by the connector");
}
public IndexedRecord createIndexedRecord(String name) throws ResourceException {
throw new NotSupportedException("The RecordFactory facility is not supported by the connector");
}
}

View File

@@ -0,0 +1,252 @@
/*
* 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.
*/
@Override
public void afterPropertiesSet() {
if (this.connection == null && getTargetConnectionFactory() == null) {
throw new IllegalArgumentException("Connection or 'targetConnectionFactory' is required");
}
}
@Override
public Connection getConnection() throws ResourceException {
synchronized (this.connectionMonitor) {
if (this.connection == null) {
initConnection();
}
return this.connection;
}
}
@Override
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]);
}
else if (method.getName().equals("hashCode")) {
// Use hashCode of Connection proxy.
return System.identityHashCode(proxy);
}
else if (method.getName().equals("close")) {
// Handle close method: don't pass the call on.
return null;
}
try {
return method.invoke(this.target, args);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
}

View File

@@ -0,0 +1,163 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.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
*/
@Override
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]);
}
else if (method.getName().equals("hashCode")) {
// Use hashCode of Connection proxy.
return System.identityHashCode(proxy);
}
else if (method.getName().equals("getLocalTransaction")) {
if (ConnectionFactoryUtils.isConnectionTransactional(this.target, this.connectionFactory)) {
throw new javax.resource.spi.IllegalStateException(
"Local transaction handling not allowed within a managed transaction");
}
}
else if (method.getName().equals("close")) {
// Handle close method: only close if not within a transaction.
ConnectionFactoryUtils.doReleaseConnection(this.target, this.connectionFactory);
return null;
}
// Invoke method on target Connection.
try {
return method.invoke(this.target, args);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
}

View File

@@ -0,0 +1,10 @@
/**
*
* Provides a utility class for easy ConnectionFactory access,
* a PlatformTransactionManager for local CCI transactions,
* and various simple ConnectionFactory proxies/adapters.
*
*/
package org.springframework.jca.cci.connection;

View File

@@ -0,0 +1,121 @@
/*
* 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 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
*/
<T> T execute(ConnectionCallback<T> 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
*/
<T> T execute(InteractionCallback<T> 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
*/
<T> T execute(InteractionSpec spec, Record inputRecord, RecordExtractor<T> 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
*/
<T> T execute(InteractionSpec spec, RecordCreator inputCreator, RecordExtractor<T> outputExtractor)
throws DataAccessException;
}

View File

@@ -0,0 +1,429 @@
/*
* 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 <T> T execute(ConnectionCallback<T> 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 <T> T execute(final InteractionCallback<T> action) throws DataAccessException {
Assert.notNull(action, "Callback object must not be null");
return execute(new ConnectionCallback<T>() {
public T 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 doExecute(spec, inputRecord, null, new SimpleRecordExtractor());
}
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 doExecute(spec, createRecord(inputCreator), null, new SimpleRecordExtractor());
}
public <T> T execute(InteractionSpec spec, Record inputRecord, RecordExtractor<T> outputExtractor)
throws DataAccessException {
return doExecute(spec, inputRecord, null, outputExtractor);
}
public <T> T execute(InteractionSpec spec, RecordCreator inputCreator, RecordExtractor<T> 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 <T> T doExecute(
final InteractionSpec spec, final Record inputRecord, final Record outputRecord,
final RecordExtractor<T> outputExtractor) throws DataAccessException {
return execute(new InteractionCallback<T>() {
public T 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);
}
return (outputExtractor != null ? outputExtractor.extractData(outputRecordToUse) : null);
}
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 connectionFactory.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);
}
}
}
private static class SimpleRecordExtractor implements RecordExtractor<Record> {
public Record extractData(Record record) {
return record;
}
}
}

View File

@@ -0,0 +1,79 @@
/*
* 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.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<T> {
/**
* 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)
*/
T doInConnection(Connection connection, ConnectionFactory connectionFactory)
throws ResourceException, SQLException, DataAccessException;
}

View File

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

View File

@@ -0,0 +1,64 @@
/*
* Copyright 2002-2005 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jca.cci.core;
import javax.resource.ResourceException;
import javax.resource.cci.Record;
import javax.resource.cci.RecordFactory;
import org.springframework.dao.DataAccessException;
/**
* Callback interface for creating a CCI Record instance,
* usually based on the passed-in CCI RecordFactory.
*
* <p>Used for input Record creation in CciTemplate. Alternatively,
* Record instances can be passed into CciTemplate's corresponding
* <code>execute</code> methods directly, either instantiated manually
* or created through CciTemplate's Record factory methods.
*
* <P>Also used for creating default output Records in CciTemplate.
* This is useful when the JCA connector needs an explicit output Record
* instance, but no output Records should be passed into CciTemplate's
* <code>execute</code> methods.
*
* @author Thierry Templier
* @author Juergen Hoeller
* @since 1.2
* @see CciTemplate#execute(javax.resource.cci.InteractionSpec, RecordCreator)
* @see CciTemplate#execute(javax.resource.cci.InteractionSpec, RecordCreator, RecordExtractor)
* @see CciTemplate#createIndexedRecord(String)
* @see CciTemplate#createMappedRecord(String)
* @see CciTemplate#setOutputRecordCreator(RecordCreator)
*/
public interface RecordCreator {
/**
* Create a CCI Record instance, usually based on the passed-in CCI RecordFactory.
* <p>For use as <i>input</i> creator with CciTemplate's <code>execute</code> methods,
* this method should create a <i>populated</i> Record instance. For use as
* <i>output</i> Record creator, it should return an <i>empty</i> Record instance.
* @param recordFactory the CCI RecordFactory (never <code>null</code>, but not guaranteed to be
* supported by the connector: its create methods might throw NotSupportedException)
* @return the Record instance
* @throws ResourceException if thrown by a CCI method, to be auto-converted
* to a DataAccessException
* @throws DataAccessException in case of custom exceptions
*/
Record createRecord(RecordFactory recordFactory) throws ResourceException, DataAccessException;
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright 2002-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.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<T> {
/**
* 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
*/
T extractData(Record record) throws ResourceException, SQLException, DataAccessException;
}

View File

@@ -0,0 +1,9 @@
/**
*
* Provides the core JCA CCI support, based on CciTemplate
* and its associated callback interfaces.
*
*/
package org.springframework.jca.cci.core;

View File

@@ -0,0 +1,138 @@
/*
* 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;
}
@Override
protected final void checkDaoConfig() {
if (this.cciTemplate == null) {
throw new IllegalArgumentException("'connectionFactory' or 'cciTemplate' is required");
}
}
/**
* Obtain a CciTemplate derived from the main template instance,
* inheriting the ConnectionFactory and other settings but
* overriding the ConnectionSpec used for obtaining Connections.
* @param connectionSpec the CCI ConnectionSpec that the returned
* template instance is supposed to obtain Connections for
* @return the derived template instance
* @see org.springframework.jca.cci.core.CciTemplate#getDerivedTemplate(javax.resource.cci.ConnectionSpec)
*/
protected final CciTemplate getCciTemplate(ConnectionSpec connectionSpec) {
return getCciTemplate().getDerivedTemplate(connectionSpec);
}
/**
* Get a CCI Connection, either from the current transaction or a new one.
* @return the CCI Connection
* @throws org.springframework.jca.cci.CannotGetCciConnectionException
* if the attempt to get a Connection failed
* @see org.springframework.jca.cci.connection.ConnectionFactoryUtils#getConnection(javax.resource.cci.ConnectionFactory)
*/
protected final Connection getConnection() throws CannotGetCciConnectionException {
return ConnectionFactoryUtils.getConnection(getConnectionFactory());
}
/**
* Close the given CCI Connection, created via this bean's ConnectionFactory,
* if it isn't bound to the thread.
* @param con Connection to close
* @see org.springframework.jca.cci.connection.ConnectionFactoryUtils#releaseConnection
*/
protected final void releaseConnection(Connection con) {
ConnectionFactoryUtils.releaseConnection(con, getConnectionFactory());
}
}

View File

@@ -0,0 +1,97 @@
/*
* 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;
}
@Override
public Object clone() {
return new CommAreaRecord(this.bytes);
}
}

View File

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

View File

@@ -0,0 +1,93 @@
/*
* Copyright 2002-2005 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jca.cci.object;
import javax.resource.cci.ConnectionFactory;
import javax.resource.cci.InteractionSpec;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.jca.cci.core.CciTemplate;
/**
* Base class for EIS operation objects that work with the CCI API.
* Encapsulates a CCI ConnectionFactory and a CCI InteractionSpec.
*
* <p>Works with a CciTemplate instance underneath. EIS operation objects
* are an alternative to working with a CciTemplate directly.
*
* @author Juergen Hoeller
* @since 1.2
* @see #setConnectionFactory
* @see #setInteractionSpec
*/
public abstract class EisOperation implements InitializingBean {
private CciTemplate cciTemplate = new CciTemplate();
private InteractionSpec interactionSpec;
/**
* Set the CciTemplate to be used by this operation.
* Alternatively, specify a CCI ConnectionFactory.
* @see #setConnectionFactory
*/
public void setCciTemplate(CciTemplate cciTemplate) {
if (cciTemplate == null) {
throw new IllegalArgumentException("cciTemplate must not be null");
}
this.cciTemplate = cciTemplate;
}
/**
* Return the CciTemplate used by this operation.
*/
public CciTemplate getCciTemplate() {
return this.cciTemplate;
}
/**
* Set the CCI ConnectionFactory to be used by this operation.
*/
public void setConnectionFactory(ConnectionFactory connectionFactory) {
this.cciTemplate.setConnectionFactory(connectionFactory);
}
/**
* Set the CCI InteractionSpec for this operation.
*/
public void setInteractionSpec(InteractionSpec interactionSpec) {
this.interactionSpec = interactionSpec;
}
/**
* Return the CCI InteractionSpec for this operation.
*/
public InteractionSpec getInteractionSpec() {
return this.interactionSpec;
}
public void afterPropertiesSet() {
this.cciTemplate.afterPropertiesSet();
if (this.interactionSpec == null) {
throw new IllegalArgumentException("interactionSpec is required");
}
}
}

View File

@@ -0,0 +1,97 @@
/*
* 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);
}
@Override
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);
}
}
@Override
protected final Object extractOutputData(Record record) throws DataAccessException {
CommAreaRecord commAreaRecord = (CommAreaRecord) record;
try {
return bytesToObject(commAreaRecord.toByteArray());
}
catch (IOException ex) {
throw new DataRetrievalFailureException("I/O exception during bytes conversion", ex);
}
}
/**
* Method used to convert an object into COMMAREA bytes.
* @param inObject the input data
* @return the COMMAREA's bytes
* @throws IOException if thrown by I/O methods
* @throws DataAccessException if conversion failed
*/
protected abstract byte[] objectToBytes(Object inObject) throws IOException, DataAccessException;
/**
* Method used to convert the COMMAREA's bytes to an object.
* @param bytes the COMMAREA's bytes
* @return the output data
* @throws IOException if thrown by I/O methods
* @throws DataAccessException if conversion failed
*/
protected abstract Object bytesToObject(byte[] bytes) throws IOException, DataAccessException;
}

View File

@@ -0,0 +1,149 @@
/*
* Copyright 2002-2005 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jca.cci.object;
import java.sql.SQLException;
import javax.resource.ResourceException;
import javax.resource.cci.ConnectionFactory;
import javax.resource.cci.InteractionSpec;
import javax.resource.cci.Record;
import javax.resource.cci.RecordFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.jca.cci.core.RecordCreator;
import org.springframework.jca.cci.core.RecordExtractor;
/**
* EIS operation object that expects mapped input and output objects,
* converting to and from CCI Records.
*
* <p>Concrete subclasses must implement the abstract
* <code>createInputRecord(RecordFactory, Object)</code> and
* <code>extractOutputData(Record)</code> methods, to create an input
* Record from an object and to convert an output Record into an object,
* respectively.
*
* @author Thierry Templier
* @author Juergen Hoeller
* @since 1.2
* @see #createInputRecord(javax.resource.cci.RecordFactory, Object)
* @see #extractOutputData(javax.resource.cci.Record)
*/
public abstract class MappingRecordOperation extends EisOperation {
/**
* Constructor that allows use as a JavaBean.
*/
public MappingRecordOperation() {
}
/**
* Convenient constructor with ConnectionFactory and specifications
* (connection and interaction).
* @param connectionFactory ConnectionFactory to use to obtain connections
*/
public MappingRecordOperation(ConnectionFactory connectionFactory, InteractionSpec interactionSpec) {
getCciTemplate().setConnectionFactory(connectionFactory);
setInteractionSpec(interactionSpec);
}
/**
* Set a RecordCreator that should be used for creating default output Records.
* <p>Default is none: CCI's <code>Interaction.execute</code> variant
* that returns an output Record will be called.
* <p>Specify a RecordCreator here if you always need to call CCI's
* <code>Interaction.execute</code> variant with a passed-in output Record.
* This RecordCreator will then be invoked to create a default output Record instance.
* @see javax.resource.cci.Interaction#execute(javax.resource.cci.InteractionSpec, Record)
* @see javax.resource.cci.Interaction#execute(javax.resource.cci.InteractionSpec, Record, Record)
* @see org.springframework.jca.cci.core.CciTemplate#setOutputRecordCreator
*/
public void setOutputRecordCreator(RecordCreator creator) {
getCciTemplate().setOutputRecordCreator(creator);
}
/**
* Execute the interaction encapsulated by this operation object.
* @param inputObject the input data, to be converted to a Record
* by the <code>createInputRecord</code> method
* @return the output data extracted with the <code>extractOutputData</code> method
* @throws DataAccessException if there is any problem
* @see #createInputRecord
* @see #extractOutputData
*/
public Object execute(Object inputObject) throws DataAccessException {
return getCciTemplate().execute(
getInteractionSpec(), new RecordCreatorImpl(inputObject), new RecordExtractorImpl());
}
/**
* Subclasses must implement this method to generate an input Record
* from an input object passed into the <code>execute</code> method.
* @param inputObject the passed-in input object
* @return the CCI input Record
* @throws ResourceException if thrown by a CCI method, to be auto-converted
* to a DataAccessException
* @see #execute(Object)
*/
protected abstract Record createInputRecord(RecordFactory recordFactory, Object inputObject)
throws ResourceException, DataAccessException;
/**
* Subclasses must implement this method to convert the Record returned
* by CCI execution into a result object for the <code>execute</code> method.
* @param outputRecord the Record returned by CCI execution
* @return the result object
* @throws ResourceException if thrown by a CCI method, to be auto-converted
* to a DataAccessException
* @see #execute(Object)
*/
protected abstract Object extractOutputData(Record outputRecord)
throws ResourceException, SQLException, DataAccessException;
/**
* Implementation of RecordCreator that calls the enclosing
* class's <code>createInputRecord</code> method.
*/
protected class RecordCreatorImpl implements RecordCreator {
private final Object inputObject;
public RecordCreatorImpl(Object inObject) {
this.inputObject = inObject;
}
public Record createRecord(RecordFactory recordFactory) throws ResourceException, DataAccessException {
return createInputRecord(recordFactory, this.inputObject);
}
}
/**
* Implementation of RecordExtractor that calls the enclosing
* class's <code>extractOutputData</code> method.
*/
protected class RecordExtractorImpl implements RecordExtractor {
public Object extractData(Record record) throws ResourceException, SQLException, DataAccessException {
return extractOutputData(record);
}
}
}

View File

@@ -0,0 +1,76 @@
/*
* Copyright 2002-2005 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jca.cci.object;
import javax.resource.cci.ConnectionFactory;
import javax.resource.cci.InteractionSpec;
import javax.resource.cci.Record;
import org.springframework.dao.DataAccessException;
/**
* EIS operation object that accepts a passed-in CCI input Record
* and returns a corresponding CCI output Record.
*
* @author Juergen Hoeller
* @since 1.2
*/
public class SimpleRecordOperation extends EisOperation {
/**
* Constructor that allows use as a JavaBean.
*/
public SimpleRecordOperation() {
}
/**
* Convenient constructor with ConnectionFactory and specifications
* (connection and interaction).
* @param connectionFactory ConnectionFactory to use to obtain connections
*/
public SimpleRecordOperation(ConnectionFactory connectionFactory, InteractionSpec interactionSpec) {
getCciTemplate().setConnectionFactory(connectionFactory);
setInteractionSpec(interactionSpec);
}
/**
* Execute the CCI interaction encapsulated by this operation object.
* <p>This method will call CCI's <code>Interaction.execute</code> variant
* that returns an output Record.
* @param inputRecord the input record
* @return the output record
* @throws DataAccessException if there is any problem
* @see javax.resource.cci.Interaction#execute(javax.resource.cci.InteractionSpec, Record)
*/
public Record execute(Record inputRecord) throws DataAccessException {
return getCciTemplate().execute(getInteractionSpec(), inputRecord);
}
/**
* Execute the CCI interaction encapsulated by this operation object.
* <p>This method will call CCI's <code>Interaction.execute</code> variant
* with a passed-in output Record.
* @param inputRecord the input record
* @param outputRecord the output record
* @throws DataAccessException if there is any problem
* @see javax.resource.cci.Interaction#execute(javax.resource.cci.InteractionSpec, Record, Record)
*/
public void execute(Record inputRecord, Record outputRecord) throws DataAccessException {
getCciTemplate().execute(getInteractionSpec(), inputRecord, outputRecord);
}
}

View File

@@ -0,0 +1,12 @@
/**
*
* 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.
*
*/
package org.springframework.jca.cci.object;

View File

@@ -0,0 +1,11 @@
/**
*
* 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.
*
*/
package org.springframework.jca.cci;

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jca.context;
import javax.resource.spi.BootstrapContext;
import org.springframework.beans.factory.Aware;
/**
* 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
* @author Chris Beams
* @since 2.5
* @see javax.resource.spi.BootstrapContext
*/
public interface BootstrapContextAware extends Aware {
/**
* Set the BootstrapContext that this object runs in.
* <p>Invoked after population of normal bean properties but before an init
* callback like InitializingBean's <code>afterPropertiesSet</code> or a
* custom init-method. Invoked after ApplicationContextAware's
* <code>setApplicationContext</code>.
* @param bootstrapContext BootstrapContext object to be used by this object
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
* @see org.springframework.context.ApplicationContextAware#setApplicationContext
*/
void setBootstrapContext(BootstrapContext bootstrapContext);
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jca.context;
import javax.resource.spi.BootstrapContext;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
* {@link org.springframework.beans.factory.config.BeanPostProcessor}
* implementation that passes the BootstrapContext to beans that implement
* the {@link BootstrapContextAware} interface.
*
* <p>{@link ResourceAdapterApplicationContext} automatically registers
* this processor with its underlying bean factory.
*
* @author Juergen Hoeller
* @since 2.5
* @see BootstrapContextAware
*/
class BootstrapContextAwareProcessor implements BeanPostProcessor {
private final BootstrapContext bootstrapContext;
/**
* Create a new BootstrapContextAwareProcessor for the given context.
*/
public BootstrapContextAwareProcessor(BootstrapContext bootstrapContext) {
this.bootstrapContext = bootstrapContext;
}
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (this.bootstrapContext != null && bean instanceof BootstrapContextAware) {
((BootstrapContextAware) bean).setBootstrapContext(this.bootstrapContext);
}
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}

View File

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

View File

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

View File

@@ -0,0 +1,9 @@
/**
*
* Integration package that allows for deploying a Spring application context
* as a JCA 1.5 compliant RAR file.
*
*/
package org.springframework.jca.context;

View File

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

View File

@@ -0,0 +1,316 @@
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.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/1.6
* {@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);
}
/**
* The standard JCA 1.5 version of <code>createEndpoint</code>.
* <p>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;
}
/**
* The alternative JCA 1.6 version of <code>createEndpoint</code>.
* <p>This implementation delegates to {@link #createEndpointInternal()},
* ignoring the specified timeout. It is only here for JCA 1.6 compliance.
*/
public MessageEndpoint createEndpoint(XAResource xaResource, long timeout) 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 final XAResource xaResource;
private Transaction transaction;
private boolean rollbackOnly;
public TransactionDelegate(XAResource xaResource) {
if (xaResource == null) {
if (transactionFactory != null && !transactionFactory.supportsResourceAdapterManagedTransactions()) {
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.xaResource != null) {
this.transaction = transactionFactory.createTransaction(transactionName, transactionTimeout);
this.transaction.enlistResource(this.xaResource);
}
}
public void setRollbackOnly() {
if (this.transaction != null) {
this.rollbackOnly = true;
}
}
public void endTransaction() throws Exception {
if (this.transaction != null) {
try {
if (this.rollbackOnly) {
this.transaction.rollback();
}
else {
this.transaction.commit();
}
}
finally {
this.transaction = null;
this.rollbackOnly = false;
}
}
}
}
}

View File

@@ -0,0 +1,158 @@
/*
* 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.
*/
@Override
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.
*/
@Override
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);
}
}
}
}
}
@Override
protected ClassLoader getEndpointClassLoader() {
return messageListener.getClass().getClassLoader();
}
}
/**
* Internal exception thrown when a ResourceExeption has been encountered
* during the endpoint invocation.
* <p>Will only be used if the ResourceAdapter does not invoke the
* endpoint's <code>beforeDelivery</code> and <code>afterDelivery</code>
* directly, leavng it up to the concrete endpoint to apply those -
* and to handle any ResourceExceptions thrown from them.
*/
public static class InternalResourceException extends RuntimeException {
protected InternalResourceException(ResourceException cause) {
super(cause);
}
}
}

View File

@@ -0,0 +1,326 @@
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.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.SmartLifecycle;
/**
* Generic bean that manages JCA 1.5 message endpoints within a Spring
* application context, activating and deactivating the endpoint as part
* of the application context's lifecycle.
*
* <p>This class is completely generic in that it may work with any
* ResourceAdapter, any MessageEndpointFactory, and any ActivationSpec.
* It can be configured in standard bean style, for example through
* Spring's XML bean definition format, as follows:
*
* <pre class="code">
* &lt;bean class="org.springframework.jca.endpoint.GenericMessageEndpointManager"&gt;
* &lt;property name="resourceAdapter" ref="resourceAdapter"/&gt;
* &lt;property name="messageEndpointFactory"&gt;
* &lt;bean class="org.springframework.jca.endpoint.GenericMessageEndpointFactory"&gt;
* &lt;property name="messageListener" ref="messageListener"/&gt;
* &lt;/bean&gt;
* &lt;/property&gt;
* &lt;property name="activationSpec"&gt;
* &lt;bean class="org.apache.activemq.ra.ActiveMQActivationSpec"&gt;
* &lt;property name="destination" value="myQueue"/&gt;
* &lt;property name="destinationType" value="javax.jms.Queue"/&gt;
* &lt;/bean&gt;
* &lt;/property&gt;
* &lt;/bean&gt;</pre>
*
* In this example, Spring's own {@link GenericMessageEndpointFactory} is used
* to point to a standard message listener object that happens to be supported
* by the specified target ResourceAdapter: in this case, a JMS
* {@link javax.jms.MessageListener} object as supported by the ActiveMQ
* message broker, defined as a Spring bean:
*
* <pre class="code">
* &lt;bean id="messageListener" class="com.myorg.messaging.myMessageListener"&gt;
* ...
* &lt;/bean&gt;</pre>
*
* The target ResourceAdapter may be configured as a local Spring bean as well
* (the typical case) or obtained from JNDI (e.g. on WebLogic). For the
* example above, a local ResourceAdapter bean could be defined as follows
* (matching the "resourceAdapter" bean reference above):
*
* <pre class="code">
* &lt;bean id="resourceAdapter" class="org.springframework.jca.support.ResourceAdapterFactoryBean"&gt;
* &lt;property name="resourceAdapter"&gt;
* &lt;bean class="org.apache.activemq.ra.ActiveMQResourceAdapter"&gt;
* &lt;property name="serverUrl" value="tcp://localhost:61616"/&gt;
* &lt;/bean&gt;
* &lt;/property&gt;
* &lt;property name="workManager"&gt;
* &lt;bean class="org.springframework.jca.work.SimpleTaskWorkManager"/&gt;
* &lt;/property&gt;
* &lt;/bean&gt;</pre>
*
* For a different target resource, the configuration would simply point to a
* different ResourceAdapter and a different ActivationSpec object (which are
* both specific to the resource provider), and possibly a different message
* listener (e.g. a CCI {@link javax.resource.cci.MessageListener} for a
* resource adapter which is based on the JCA Common Client Interface).
*
* <p>The asynchronous execution strategy can be customized through the
* "workManager" property on the ResourceAdapterFactoryBean (as shown above).
* Check out {@link org.springframework.jca.work.SimpleTaskWorkManager}'s
* javadoc for its configuration options; alternatively, any other
* JCA-compliant WorkManager can be used (e.g. Geronimo's).
*
* <p>Transactional execution is a responsibility of the concrete message endpoint,
* as built by the specified MessageEndpointFactory. {@link GenericMessageEndpointFactory}
* supports XA transaction participation through its "transactionManager" property,
* typically with a Spring {@link org.springframework.transaction.jta.JtaTransactionManager}
* or a plain {@link javax.transaction.TransactionManager} implementation specified there.
*
* <pre class="code">
* &lt;bean class="org.springframework.jca.endpoint.GenericMessageEndpointManager"&gt;
* &lt;property name="resourceAdapter" ref="resourceAdapter"/&gt;
* &lt;property name="messageEndpointFactory"&gt;
* &lt;bean class="org.springframework.jca.endpoint.GenericMessageEndpointFactory"&gt;
* &lt;property name="messageListener" ref="messageListener"/&gt;
* &lt;property name="transactionManager" ref="transactionManager"/&gt;
* &lt;/bean&gt;
* &lt;/property&gt;
* &lt;property name="activationSpec"&gt;
* &lt;bean class="org.apache.activemq.ra.ActiveMQActivationSpec"&gt;
* &lt;property name="destination" value="myQueue"/&gt;
* &lt;property name="destinationType" value="javax.jms.Queue"/&gt;
* &lt;/bean&gt;
* &lt;/property&gt;
* &lt;/bean&gt;
*
* &lt;bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/&gt;</pre>
*
* Alternatively, check out your resource provider's ActivationSpec object,
* which should support local transactions through a provider-specific config flag,
* e.g. ActiveMQActivationSpec's "useRAManagedTransaction" bean property.
*
* <pre class="code">
* &lt;bean class="org.springframework.jca.endpoint.GenericMessageEndpointManager"&gt;
* &lt;property name="resourceAdapter" ref="resourceAdapter"/&gt;
* &lt;property name="messageEndpointFactory"&gt;
* &lt;bean class="org.springframework.jca.endpoint.GenericMessageEndpointFactory"&gt;
* &lt;property name="messageListener" ref="messageListener"/&gt;
* &lt;/bean&gt;
* &lt;/property&gt;
* &lt;property name="activationSpec"&gt;
* &lt;bean class="org.apache.activemq.ra.ActiveMQActivationSpec"&gt;
* &lt;property name="destination" value="myQueue"/&gt;
* &lt;property name="destinationType" value="javax.jms.Queue"/&gt;
* &lt;property name="useRAManagedTransaction" value="true"/&gt;
* &lt;/bean&gt;
* &lt;/property&gt;
* &lt;/bean&gt;</pre>
*
* @author Juergen Hoeller
* @since 2.5
* @see javax.resource.spi.ResourceAdapter#endpointActivation
* @see javax.resource.spi.ResourceAdapter#endpointDeactivation
* @see javax.resource.spi.endpoint.MessageEndpointFactory
* @see javax.resource.spi.ActivationSpec
*/
public class GenericMessageEndpointManager implements SmartLifecycle, InitializingBean, DisposableBean {
private ResourceAdapter resourceAdapter;
private MessageEndpointFactory messageEndpointFactory;
private ActivationSpec activationSpec;
private boolean autoStartup = true;
private int phase = Integer.MAX_VALUE;
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 after this endpoint
* manager has been initialized and the context has been refreshed.
* <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;
}
/**
* Return the value for the 'autoStartup' property. If "true", this
* endpoint manager will start upon a ContextRefreshedEvent.
*/
public boolean isAutoStartup() {
return this.autoStartup;
}
/**
* Specify the phase in which this endpoint manager should be started
* and stopped. The startup order proceeds from lowest to highest, and
* the shutdown order is the reverse of that. By default this value is
* Integer.MAX_VALUE meaning that this endpoint manager starts as late
* as possible and stops as soon as possible.
*/
public void setPhase(int phase) {
this.phase = phase;
}
/**
* Return the phase in which this endpoint manager will be started and stopped.
*/
public int getPhase() {
return this.phase;
}
/**
* 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());
}
}
/**
* Activates the configured message endpoint.
*/
public void start() {
synchronized (this.lifecycleMonitor) {
if (!this.running) {
try {
getResourceAdapter().endpointActivation(getMessageEndpointFactory(), getActivationSpec());
}
catch (ResourceException ex) {
throw new IllegalStateException("Could not activate message endpoint", ex);
}
this.running = true;
}
}
}
/**
* Deactivates the configured message endpoint.
*/
public void stop() {
synchronized (this.lifecycleMonitor) {
if (this.running) {
getResourceAdapter().endpointDeactivation(getMessageEndpointFactory(), getActivationSpec());
this.running = false;
}
}
}
public void stop(Runnable callback) {
synchronized (this.lifecycleMonitor) {
this.stop();
callback.run();
}
}
/**
* Return whether the configured message endpoint is currently active.
*/
public boolean isRunning() {
synchronized (this.lifecycleMonitor) {
return this.running;
}
}
/**
* Deactivates the message endpoint, preparing it for shutdown.
*/
public void destroy() {
stop();
}
}

View File

@@ -0,0 +1,8 @@
/**
*
* This package provides a facility for generic JCA message endpoint management.
*
*/
package org.springframework.jca.endpoint;

View File

@@ -0,0 +1,137 @@
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.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<Object>, InitializingBean {
private ManagedConnectionFactory managedConnectionFactory;
private ConnectionManager connectionManager;
private Object connectionFactory;
/**
* Set the JCA ManagerConnectionFactory that should be used to create
* the desired connection factory.
* <p>The ManagerConnectionFactory will usually be set up as separate bean
* (potentially as inner bean), populated with JavaBean properties:
* a ManagerConnectionFactory is encouraged to follow the JavaBean pattern
* by the JCA specification, analogous to a JDBC DataSource and a JDO
* PersistenceManagerFactory.
* <p>Note that the ManagerConnectionFactory implementation might expect
* a reference to its JCA 1.5 ResourceAdapter, expressed through the
* {@link javax.resource.spi.ResourceAdapterAssociation} interface.
* Simply inject the corresponding ResourceAdapter instance into its
* "resourceAdapter" bean property in this case, before passing the
* ManagerConnectionFactory into this LocalConnectionFactoryBean.
* @see javax.resource.spi.ManagedConnectionFactory#createConnectionFactory()
*/
public void setManagedConnectionFactory(ManagedConnectionFactory managedConnectionFactory) {
this.managedConnectionFactory = managedConnectionFactory;
}
/**
* Set the JCA ConnectionManager that should be used to create the
* desired connection factory.
* <p>A ConnectionManager implementation for local usage is often
* included with a JCA connector. Such an included ConnectionManager
* might be set as default, with no need to explicitly specify one.
* @see javax.resource.spi.ManagedConnectionFactory#createConnectionFactory(javax.resource.spi.ConnectionManager)
*/
public void setConnectionManager(ConnectionManager connectionManager) {
this.connectionManager = connectionManager;
}
public void afterPropertiesSet() throws ResourceException {
if (this.managedConnectionFactory == null) {
throw new IllegalArgumentException("Property 'managedConnectionFactory' is required");
}
if (this.connectionManager != null) {
this.connectionFactory = this.managedConnectionFactory.createConnectionFactory(this.connectionManager);
}
else {
this.connectionFactory = this.managedConnectionFactory.createConnectionFactory();
}
}
public Object getObject() {
return this.connectionFactory;
}
public Class<?> getObjectType() {
return (this.connectionFactory != null ? this.connectionFactory.getClass() : null);
}
public boolean isSingleton() {
return true;
}
}

View File

@@ -0,0 +1,148 @@
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.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<ResourceAdapter>, 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 ResourceAdapter getObject() {
return this.resourceAdapter;
}
public Class<? extends ResourceAdapter> getObjectType() {
return (this.resourceAdapter != null ? this.resourceAdapter.getClass() : ResourceAdapter.class);
}
public boolean isSingleton() {
return true;
}
/**
* Stops the ResourceAdapter.
* @see javax.resource.spi.ResourceAdapter#stop()
*/
public void destroy() {
this.resourceAdapter.stop();
}
}

View File

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

View File

@@ -0,0 +1,9 @@
/**
*
* Provides generic support classes for JCA usage within Spring,
* mainly for local setup of a JCA ResourceAdapter and/or ConnectionFactory.
*
*/
package org.springframework.jca.support;

View File

@@ -0,0 +1,67 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jca.work;
import javax.resource.spi.work.Work;
import org.springframework.util.Assert;
/**
* Simple Work adapter that delegates to a given Runnable.
*
* @author Juergen Hoeller
* @since 2.0.3
* @see javax.resource.spi.work.Work
* @see Runnable
*/
public class DelegatingWork implements Work {
private final Runnable delegate;
/**
* Create a new DelegatingWork.
* @param delegate the Runnable implementation to delegate to
*/
public DelegatingWork(Runnable delegate) {
Assert.notNull(delegate, "Delegate must not be null");
this.delegate = delegate;
}
/**
* Return the wrapped Runnable implementation.
*/
public final Runnable getDelegate() {
return this.delegate;
}
/**
* Delegates execution to the underlying Runnable.
*/
public void run() {
this.delegate.run();
}
/**
* This implementation is empty, since we expect the Runnable
* to terminate based on some specific shutdown signal.
*/
public void release() {
}
}

View File

@@ -0,0 +1,252 @@
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.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 AsyncTaskExecutor 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(AsyncTaskExecutor asyncTaskExecutor) {
this.asyncTaskExecutor = asyncTaskExecutor;
}
public void doWork(Work work) throws WorkException {
doWork(work, WorkManager.INDEFINITE, null, null);
}
public void doWork(Work work, long startTimeout, ExecutionContext executionContext, WorkListener workListener)
throws WorkException {
Assert.state(this.syncTaskExecutor != null, "No 'syncTaskExecutor' set");
executeWork(this.syncTaskExecutor, work, startTimeout, false, executionContext, workListener);
}
public long startWork(Work work) throws WorkException {
return startWork(work, WorkManager.INDEFINITE, null, null);
}
public long startWork(Work work, long startTimeout, ExecutionContext executionContext, WorkListener workListener)
throws WorkException {
Assert.state(this.asyncTaskExecutor != null, "No 'asyncTaskExecutor' set");
return executeWork(this.asyncTaskExecutor, work, startTimeout, true, executionContext, workListener);
}
public void scheduleWork(Work work) throws WorkException {
scheduleWork(work, WorkManager.INDEFINITE, null, null);
}
public void scheduleWork(Work work, long startTimeout, ExecutionContext executionContext, WorkListener workListener)
throws WorkException {
Assert.state(this.asyncTaskExecutor != null, "No 'asyncTaskExecutor' set");
executeWork(this.asyncTaskExecutor, work, startTimeout, false, executionContext, workListener);
}
/**
* Execute the given Work on the specified TaskExecutor.
* @param taskExecutor the TaskExecutor to use
* @param work the Work to execute
* @param startTimeout the time duration within which the Work is supposed to start
* @param blockUntilStarted whether to block until the Work has started
* @param executionContext the JCA ExecutionContext for the given Work
* @param workListener the WorkListener to clal for the given Work
* @return the time elapsed from Work acceptance until start of execution
* (or -1 if not applicable or not known)
* @throws WorkException if the TaskExecutor did not accept the Work
*/
protected long executeWork(TaskExecutor taskExecutor, Work work, long startTimeout,
boolean blockUntilStarted, ExecutionContext executionContext, WorkListener workListener)
throws WorkException {
if (executionContext != null && executionContext.getXid() != null) {
throw new WorkException("SimpleTaskWorkManager does not supported imported XIDs: " + executionContext.getXid());
}
WorkListener workListenerToUse = workListener;
if (workListenerToUse == null) {
workListenerToUse = new WorkAdapter();
}
boolean isAsync = (taskExecutor instanceof AsyncTaskExecutor);
DelegatingWorkAdapter workHandle = new DelegatingWorkAdapter(work, workListenerToUse, !isAsync);
try {
if (isAsync) {
((AsyncTaskExecutor) taskExecutor).execute(workHandle, startTimeout);
}
else {
taskExecutor.execute(workHandle);
}
}
catch (TaskTimeoutException ex) {
WorkException wex = new WorkRejectedException("TaskExecutor rejected Work because of timeout: " + work, ex);
wex.setErrorCode(WorkException.START_TIMED_OUT);
workListenerToUse.workRejected(new WorkEvent(this, WorkEvent.WORK_REJECTED, work, wex));
throw wex;
}
catch (TaskRejectedException ex) {
WorkException wex = new WorkRejectedException("TaskExecutor rejected Work: " + work, ex);
wex.setErrorCode(WorkException.INTERNAL);
workListenerToUse.workRejected(new WorkEvent(this, WorkEvent.WORK_REJECTED, work, wex));
throw wex;
}
catch (Throwable ex) {
WorkException wex = new WorkException("TaskExecutor failed to execute Work: " + work, ex);
wex.setErrorCode(WorkException.INTERNAL);
throw wex;
}
if (isAsync) {
workListenerToUse.workAccepted(new WorkEvent(this, WorkEvent.WORK_ACCEPTED, work, null));
}
if (blockUntilStarted) {
long acceptanceTime = System.currentTimeMillis();
synchronized (workHandle.monitor) {
try {
while (!workHandle.started) {
workHandle.monitor.wait();
}
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
return (System.currentTimeMillis() - acceptanceTime);
}
else {
return WorkManager.UNKNOWN;
}
}
/**
* Work adapter that supports start timeouts and WorkListener callbacks
* for a given Work that it delegates to.
*/
private static class DelegatingWorkAdapter implements Work {
private final Work work;
private final WorkListener workListener;
private final boolean acceptOnExecution;
public final Object monitor = new Object();
public boolean started = false;
public DelegatingWorkAdapter(Work work, WorkListener workListener, boolean acceptOnExecution) {
this.work = work;
this.workListener = workListener;
this.acceptOnExecution = acceptOnExecution;
}
public void run() {
if (this.acceptOnExecution) {
this.workListener.workAccepted(new WorkEvent(this, WorkEvent.WORK_ACCEPTED, work, null));
}
synchronized (this.monitor) {
this.started = true;
this.monitor.notify();
}
this.workListener.workStarted(new WorkEvent(this, WorkEvent.WORK_STARTED, this.work, null));
try {
this.work.run();
}
catch (RuntimeException ex) {
this.workListener.workCompleted(
new WorkEvent(this, WorkEvent.WORK_COMPLETED, this.work, new WorkCompletedException(ex)));
throw ex;
}
catch (Error err) {
this.workListener.workCompleted(
new WorkEvent(this, WorkEvent.WORK_COMPLETED, this.work, new WorkCompletedException(err)));
throw err;
}
this.workListener.workCompleted(new WorkEvent(this, WorkEvent.WORK_COMPLETED, this.work, null));
}
public void release() {
this.work.release();
}
}
}

View File

@@ -0,0 +1,290 @@
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jca.work;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
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 = 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);
}
}
public Future<?> submit(Runnable task) {
FutureTask<Object> future = new FutureTask<Object>(task, null);
execute(future, TIMEOUT_INDEFINITE);
return future;
}
public <T> Future<T> submit(Callable<T> task) {
FutureTask<T> future = new FutureTask<T>(task);
execute(future, TIMEOUT_INDEFINITE);
return future;
}
/**
* This task executor prefers short-lived work units.
*/
public boolean prefersShortLivedTasks() {
return true;
}
//-------------------------------------------------------------------------
// Implementation of the JCA WorkManager interface
//-------------------------------------------------------------------------
public void doWork(Work work) throws WorkException {
this.workManager.doWork(work);
}
public void doWork(Work work, long delay, ExecutionContext executionContext, WorkListener workListener)
throws WorkException {
this.workManager.doWork(work, delay, executionContext, workListener);
}
public long startWork(Work work) throws WorkException {
return this.workManager.startWork(work);
}
public long startWork(Work work, long delay, ExecutionContext executionContext, WorkListener workListener)
throws WorkException {
return this.workManager.startWork(work, delay, executionContext, workListener);
}
public void scheduleWork(Work work) throws WorkException {
this.workManager.scheduleWork(work);
}
public void scheduleWork(Work work, long delay, ExecutionContext executionContext, WorkListener workListener)
throws WorkException {
this.workManager.scheduleWork(work, delay, executionContext, workListener);
}
}

View File

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

View File

@@ -0,0 +1,9 @@
/**
*
* Convenience package for obtaining a GlassFish JCA WorkManager for use in
* web applications. Provides a Spring TaskExecutor adapter for GlassFish.
*
*/
package org.springframework.jca.work.glassfish;

View File

@@ -0,0 +1,58 @@
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.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 {
/**
* Identify a specific JBossWorkManagerMBean to talk to,
* through its JMX object name.
* <p>The default MBean name is "jboss.jca:service=WorkManager".
* @see JBossWorkManagerUtils#getWorkManager(String)
*/
public void setWorkManagerMBeanName(String mbeanName) {
setWorkManager(JBossWorkManagerUtils.getWorkManager(mbeanName));
}
/**
* Obtains the default JBoss JCA WorkManager through a JMX lookup
* for the JBossWorkManagerMBean.
* @see JBossWorkManagerUtils#getWorkManager()
*/
@Override
protected WorkManager getDefaultWorkManager() {
return JBossWorkManagerUtils.getWorkManager();
}
}

View File

@@ -0,0 +1,76 @@
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.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;
import org.springframework.util.Assert;
/**
* 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 DEFAULT_WORK_MANAGER_MBEAN_NAME = "jboss.jca:service=WorkManager";
/**
* Obtain the default JBoss JCA WorkManager through a JMX lookup
* for the default JBossWorkManagerMBean.
* @see org.jboss.resource.work.JBossWorkManagerMBean
*/
public static WorkManager getWorkManager() {
return getWorkManager(DEFAULT_WORK_MANAGER_MBEAN_NAME);
}
/**
* Obtain the default JBoss JCA WorkManager through a JMX lookup
* for the JBossWorkManagerMBean.
* @param workManagerObjectName the JMX object name to use
* @see org.jboss.resource.work.JBossWorkManagerMBean
*/
public static WorkManager getWorkManager(String mbeanName) {
Assert.hasLength(mbeanName, "JBossWorkManagerMBean name must not be empty");
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(mbeanName);
Object workManagerMBean = MBeanServerInvocationHandler.newProxyInstance(mconn, objectName, mbeanClass, false);
Method getInstanceMethod = workManagerMBean.getClass().getMethod("getInstance");
return (WorkManager) getInstanceMethod.invoke(workManagerMBean);
}
catch (Exception ex) {
throw new IllegalStateException(
"Could not initialize JBossWorkManagerTaskExecutor because JBoss API is not available: " + ex);
}
}
}

View File

@@ -0,0 +1,9 @@
/**
*
* Convenience package for obtaining a JBoss JCA WorkManager for use in
* web applications. Provides a Spring TaskExecutor adapter for JBoss.
*
*/
package org.springframework.jca.work.jboss;

View File

@@ -0,0 +1,9 @@
/**
*
* Convenience classes for scheduling based on the JCA 1.5 WorkManager facility,
* as supported within JCA 1.5 ResourceAdapters.
*
*/
package org.springframework.jca.work;

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.transaction;
/**
* Exception thrown when a transaction can't be created using an
* underlying transaction API such as JTA.
*
* @author Rod Johnson
* @since 17.03.2003
*/
public class CannotCreateTransactionException extends TransactionException {
/**
* Constructor for CannotCreateTransactionException.
* @param msg the detail message
*/
public CannotCreateTransactionException(String msg) {
super(msg);
}
/**
* Constructor for CannotCreateTransactionException.
* @param msg the detail message
* @param cause the root cause from the transaction API in use
*/
public CannotCreateTransactionException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@@ -0,0 +1,80 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.transaction;
/**
* Exception that represents a transaction failure caused by a heuristic
* decision on the side of the transaction coordinator.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @since 17.03.2003
*/
public class HeuristicCompletionException extends TransactionException {
/**
* Values for the outcome state of a heuristically completed transaction.
*/
public static final int STATE_UNKNOWN = 0;
public static final int STATE_COMMITTED = 1;
public static final int STATE_ROLLED_BACK = 2;
public static final int STATE_MIXED = 3;
public static String getStateString(int state) {
switch (state) {
case STATE_COMMITTED:
return "committed";
case STATE_ROLLED_BACK:
return "rolled back";
case STATE_MIXED:
return "mixed";
default:
return "unknown";
}
}
/**
* The outcome state of the transaction: have some or all resources been committed?
*/
private int outcomeState = STATE_UNKNOWN;
/**
* Constructor for HeuristicCompletionException.
* @param outcomeState the outcome state of the transaction
* @param cause the root cause from the transaction API in use
*/
public HeuristicCompletionException(int outcomeState, Throwable cause) {
super("Heuristic completion: outcome state is " + getStateString(outcomeState), cause);
this.outcomeState = outcomeState;
}
/**
* Return the outcome state of the transaction state,
* as one of the constants in this class.
* @see #STATE_UNKNOWN
* @see #STATE_COMMITTED
* @see #STATE_ROLLED_BACK
* @see #STATE_MIXED
*/
public int getOutcomeState() {
return outcomeState;
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.transaction;
/**
* Exception thrown when the existence or non-existence of a transaction
* amounts to an illegal state according to the transaction propagation
* behavior that applies.
*
* @author Juergen Hoeller
* @since 21.01.2004
*/
public class IllegalTransactionStateException extends TransactionUsageException {
/**
* Constructor for IllegalTransactionStateException.
* @param msg the detail message
*/
public IllegalTransactionStateException(String msg) {
super(msg);
}
/**
* Constructor for IllegalTransactionStateException.
* @param msg the detail message
* @param cause the root cause from the transaction API in use
*/
public IllegalTransactionStateException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.transaction;
/**
* Exception that gets thrown when an invalid isolation level is specified,
* i.e. an isolation level that the transaction manager implementation
* doesn't support.
*
* @author Juergen Hoeller
* @since 12.05.2003
*/
public class InvalidIsolationLevelException extends TransactionUsageException {
/**
* Constructor for InvalidIsolationLevelException.
* @param msg the detail message
*/
public InvalidIsolationLevelException(String msg) {
super(msg);
}
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.transaction;
/**
* Exception that gets thrown when an invalid timeout is specified,
* that is, the specified timeout valid is out of range or the
* transaction manager implementation doesn't support timeouts.
*
* @author Juergen Hoeller
* @since 12.05.2003
*/
public class InvalidTimeoutException extends TransactionUsageException {
private int timeout;
/**
* Constructor for InvalidTimeoutException.
* @param msg the detail message
* @param timeout the invalid timeout value
*/
public InvalidTimeoutException(String msg, int timeout) {
super(msg);
this.timeout = timeout;
}
/**
* Return the invalid timeout value.
*/
public int getTimeout() {
return timeout;
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.transaction;
/**
* Exception thrown when attempting to work with a nested transaction
* but nested transactions are not supported by the underlying backend.
*
* @author Juergen Hoeller
* @since 1.1
*/
public class NestedTransactionNotSupportedException extends CannotCreateTransactionException {
/**
* Constructor for NestedTransactionNotSupportedException.
* @param msg the detail message
*/
public NestedTransactionNotSupportedException(String msg) {
super(msg);
}
/**
* Constructor for NestedTransactionNotSupportedException.
* @param msg the detail message
* @param cause the root cause from the transaction API in use
*/
public NestedTransactionNotSupportedException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.transaction;
/**
* Exception thrown when an operation is attempted that
* relies on an existing transaction (such as setting
* rollback status) and there is no existing transaction.
* This represents an illegal usage of the transaction API.
*
* @author Rod Johnson
* @since 17.03.2003
*/
public class NoTransactionException extends TransactionUsageException {
/**
* Constructor for NoTransactionException.
* @param msg the detail message
*/
public NoTransactionException(String msg) {
super(msg);
}
/**
* Constructor for NoTransactionException.
* @param msg the detail message
* @param cause the root cause from the transaction API in use
*/
public NoTransactionException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

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

View File

@@ -0,0 +1,80 @@
/*
* Copyright 2002-2005 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.transaction;
/**
* Interface that specifies an API to programmatically manage transaction
* savepoints in a generic fashion. Extended by TransactionStatus to
* expose savepoint management functionality for a specific transaction.
*
* <p>Note that savepoints can only work within an active transaction.
* Just use this programmatic savepoint handling for advanced needs;
* else, a subtransaction with PROPAGATION_NESTED is preferable.
*
* <p>This interface is inspired by JDBC 3.0's Savepoint mechanism
* but is independent from any specific persistence technology.
*
* @author Juergen Hoeller
* @since 1.1
* @see TransactionStatus
* @see TransactionDefinition#PROPAGATION_NESTED
* @see java.sql.Savepoint
*/
public interface SavepointManager {
/**
* Create a new savepoint. You can roll back to a specific savepoint
* via <code>rollbackToSavepoint</code>, and explicitly release a
* savepoint that you don't need anymore via <code>releaseSavepoint</code>.
* <p>Note that most transaction managers will automatically release
* savepoints at transaction completion.
* @return a savepoint object, to be passed into rollbackToSavepoint
* or releaseSavepoint
* @throws NestedTransactionNotSupportedException if the underlying
* transaction does not support savepoints
* @throws TransactionException if the savepoint could not be created,
* for example because the transaction is not in an appropriate state
* @see java.sql.Connection#setSavepoint
*/
Object createSavepoint() throws TransactionException;
/**
* Roll back to the given savepoint. The savepoint will be
* automatically released afterwards.
* @param savepoint the savepoint to roll back to
* @throws NestedTransactionNotSupportedException if the underlying
* transaction does not support savepoints
* @throws TransactionException if the rollback failed
* @see java.sql.Connection#rollback(java.sql.Savepoint)
*/
void rollbackToSavepoint(Object savepoint) throws TransactionException;
/**
* Explicitly release the given savepoint.
* <p>Note that most transaction managers will automatically release
* savepoints at transaction completion.
* <p>Implementations should fail as silently as possible if
* proper resource cleanup will still happen at transaction completion.
* @param savepoint the savepoint to release
* @throws NestedTransactionNotSupportedException if the underlying
* transaction does not support savepoints
* @throws TransactionException if the release failed
* @see java.sql.Connection#releaseSavepoint
*/
void releaseSavepoint(Object savepoint) throws TransactionException;
}

View File

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

View File

@@ -0,0 +1,46 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.transaction;
import org.springframework.core.NestedRuntimeException;
/**
* Superclass for all transaction exceptions.
*
* @author Rod Johnson
* @since 17.03.2003
*/
public abstract class TransactionException extends NestedRuntimeException {
/**
* Constructor for TransactionException.
* @param msg the detail message
*/
public TransactionException(String msg) {
super(msg);
}
/**
* Constructor for TransactionException.
* @param msg the detail message
* @param cause the root cause from the transaction API in use
*/
public TransactionException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@@ -0,0 +1,92 @@
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.transaction;
/**
* Representation of the status of a transaction.
*
* <p>Transactional code can use this to retrieve status information,
* and to programmatically request a rollback (instead of throwing
* an exception that causes an implicit rollback).
*
* <p>Derives from the SavepointManager interface to provide access
* to savepoint management facilities. Note that savepoint management
* is only available if supported by the underlying transaction manager.
*
* @author Juergen Hoeller
* @since 27.03.2003
* @see #setRollbackOnly()
* @see PlatformTransactionManager#getTransaction
* @see org.springframework.transaction.support.TransactionCallback#doInTransaction
* @see org.springframework.transaction.interceptor.TransactionInterceptor#currentTransactionStatus()
*/
public interface TransactionStatus extends SavepointManager {
/**
* Return whether the present transaction is new (else participating
* in an existing transaction, or potentially not running in an
* actual transaction in the first place).
*/
boolean isNewTransaction();
/**
* Return whether this transaction internally carries a savepoint,
* that is, has been created as nested transaction based on a savepoint.
* <p>This method is mainly here for diagnostic purposes, alongside
* {@link #isNewTransaction()}. For programmatic handling of custom
* savepoints, use SavepointManager's operations.
* @see #isNewTransaction()
* @see #createSavepoint
* @see #rollbackToSavepoint(Object)
* @see #releaseSavepoint(Object)
*/
boolean hasSavepoint();
/**
* Set the transaction rollback-only. This instructs the transaction manager
* that the only possible outcome of the transaction may be a rollback, as
* alternative to throwing an exception which would in turn trigger a rollback.
* <p>This is mainly intended for transactions managed by
* {@link org.springframework.transaction.support.TransactionTemplate} or
* {@link org.springframework.transaction.interceptor.TransactionInterceptor},
* where the actual commit/rollback decision is made by the container.
* @see org.springframework.transaction.support.TransactionCallback#doInTransaction
* @see org.springframework.transaction.interceptor.TransactionAttribute#rollbackOn
*/
void setRollbackOnly();
/**
* Return whether the transaction has been marked as rollback-only
* (either by the application or by the transaction infrastructure).
*/
boolean isRollbackOnly();
/**
* Flush the underlying session to the datastore, if applicable:
* for example, all affected Hibernate/JPA sessions.
*/
void flush();
/**
* Return whether this transaction is completed, that is,
* whether it has already been committed or rolled back.
* @see PlatformTransactionManager#commit
* @see PlatformTransactionManager#rollback
*/
boolean isCompleted();
}

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