
org.wildfly.transaction.client.LocalTransaction Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of wildfly-transaction-client-jakarta Show documentation
Show all versions of wildfly-transaction-client-jakarta Show documentation
Client library for applications using transactions with Wildfly Jakarta edition
The newest version!
/*
* JBoss, Home of Professional Open Source.
* Copyright 2016 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.wildfly.transaction.client;
import jakarta.transaction.HeuristicMixedException;
import jakarta.transaction.HeuristicRollbackException;
import jakarta.transaction.InvalidTransactionException;
import jakarta.transaction.RollbackException;
import jakarta.transaction.Synchronization;
import jakarta.transaction.SystemException;
import jakarta.transaction.Transaction;
import jakarta.transaction.TransactionManager;
import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;
import org.wildfly.common.Assert;
import org.wildfly.transaction.client._private.Log;
import org.wildfly.transaction.client.spi.LocalTransactionProvider;
/**
* A transaction from a local transaction provider.
*
* @author David M. Lloyd
*/
public final class LocalTransaction extends AbstractTransaction {
private final LocalTransactionContext owner;
private final Transaction transaction;
LocalTransaction(final LocalTransactionContext owner, final Transaction transaction) {
this.owner = owner;
this.transaction = transaction;
}
public void commit() throws RollbackException, HeuristicMixedException, HeuristicRollbackException, SecurityException, SystemException {
if (isImported()) {
throw Log.log.commitOnImported();
}
try {
owner.getProvider().commitLocal(transaction);
} catch (RollbackException re) {
addRollbackExceptions(re);
throw re;
} finally {
final XAOutflowedResources outflowedResources = RemoteTransactionContext.getOutflowedResources(this);
if (outflowedResources == null || outflowedResources.getEnlistedSubordinates() == 0) {
// we can drop the mapping, since we are both a master and have no enlisted subordinates
owner.getProvider().dropLocal(transaction);
} else {
// the memory mapping of transaction with subordinate enlistment may need to be adjusted
owner.getProvider().dropRemote(transaction);
}
}
}
void commitAndDissociate() throws RollbackException, HeuristicMixedException, HeuristicRollbackException, SecurityException, SystemException {
if (isImported()) {
throw Log.log.commitOnImported();
}
notifyAssociationListeners(false);
try {
owner.getProvider().getTransactionManager().commit();
} catch (RollbackException re) {
addRollbackExceptions(re);
throw re;
} finally {
final XAOutflowedResources outflowedResources = RemoteTransactionContext.getOutflowedResources(this);
if (outflowedResources == null || outflowedResources.getEnlistedSubordinates() == 0) {
// we can drop the mapping, since we are both a master and have no enlisted subordinates
owner.getProvider().dropLocal(transaction);
} else {
// the memory mapping of transaction with subordinate enlistment may need to be adjusted
owner.getProvider().dropRemote(transaction);
}
}
}
public void rollback() throws IllegalStateException, SystemException {
if (isImported()) {
throw Log.log.rollbackOnImported();
}
try {
owner.getProvider().rollbackLocal(transaction);
} finally {
final XAOutflowedResources outflowedResources = RemoteTransactionContext.getOutflowedResources(this);
if (outflowedResources == null || outflowedResources.getEnlistedSubordinates() == 0) {
// we can drop the mapping, since we are both a master and have no enlisted subordinates
owner.getProvider().dropLocal(transaction);
} else {
// the memory mapping of transaction with subordinate enlistment may need to be adjusted
owner.getProvider().dropRemote(transaction);
}
}
}
void rollbackAndDissociate() throws IllegalStateException, SystemException {
if (isImported()) {
throw Log.log.rollbackOnImported();
}
notifyAssociationListeners(false);
try {
owner.getProvider().getTransactionManager().rollback();
} finally {
final XAOutflowedResources outflowedResources = RemoteTransactionContext.getOutflowedResources(this);
if (outflowedResources == null || outflowedResources.getEnlistedSubordinates() == 0) {
// we can drop the mapping, since we are both a master and have no enlisted subordinates
owner.getProvider().dropLocal(transaction);
} else {
// the memory mapping of transaction with subordinate enlistment may need to be adjusted
owner.getProvider().dropRemote(transaction);
}
}
}
boolean importBacking() throws SystemException {
final ContextTransactionManager.State state = ContextTransactionManager.INSTANCE.getStateRef().get();
final Transaction transaction = owner.getProvider().getTransactionManager().getTransaction();
if (transaction == null) {
return false;
}
final LocalTransaction localTransaction = owner.getOrAttach(transaction, CreationListener.CreatedBy.MERGE);
if (state.transaction == null) {
state.transaction = localTransaction;
return true;
} else {
localTransaction.verifyAssociation();
return false;
}
}
void unimportBacking() {
final ContextTransactionManager.State state = ContextTransactionManager.INSTANCE.getStateRef().get();
if (state.transaction.equals(this)) {
state.transaction = null;
}
}
LocalTransactionProvider getProvider() {
return owner.getProvider();
}
public void setRollbackOnly() throws IllegalStateException, SystemException {
super.setRollbackOnly();
transaction.setRollbackOnly();
}
public int getStatus() throws SystemException {
return transaction.getStatus();
}
public int getTransactionTimeout() {
return owner.getProvider().getTimeout(transaction);
}
public boolean enlistResource(final XAResource xaRes) throws RollbackException, IllegalStateException, SystemException {
Assert.checkNotNullParam("xaRes", xaRes);
final int estimatedRemainingTime = getEstimatedRemainingTime();
if(estimatedRemainingTime == 0) throw Log.log.cannotEnlistToTimeOutTransaction(xaRes, this);
try {
xaRes.setTransactionTimeout(estimatedRemainingTime);
} catch (XAException e) {
throw Log.log.setTimeoutFailed(estimatedRemainingTime, e);
}
return transaction.enlistResource(xaRes);
}
public boolean delistResource(final XAResource xaRes, final int flag) throws IllegalStateException, SystemException {
Assert.checkNotNullParam("xaRes", xaRes);
return transaction.delistResource(xaRes, flag);
}
public void registerSynchronization(final Synchronization sync) throws RollbackException, IllegalStateException, SystemException {
Assert.checkNotNullParam("sync", sync);
transaction.registerSynchronization(new AssociatingSynchronization(sync));
}
/**
* Get the name of the node which initiated the transaction.
*
* @return the name of the node which initiated the transaction, or {@code null} if it could not be determined
*/
public String getParentName() {
return owner.getProvider().getNameFromXid(owner.getProvider().getXid(transaction));
}
/**
* Get the XID of the local transaction.
*
* @return the transaction XID (not {@code null})
*/
public Xid getXid() {
return owner.getProvider().getXid(transaction);
}
void registerInterposedSynchronization(final Synchronization sync) throws IllegalStateException {
Assert.checkNotNullParam("sync", sync);
owner.getProvider().registerInterposedSynchronization(transaction, new AssociatingSynchronization(sync));
}
public Object getResource(final Object key) throws NullPointerException {
return owner.getProvider().getResource(transaction, Assert.checkNotNullParamWithNullPointerException("key", key));
}
public void putResource(final Object key, final Object value) throws NullPointerException {
owner.getProvider().putResource(transaction, Assert.checkNotNullParamWithNullPointerException("key", key), value);
}
public Object putResourceIfAbsent(final Object key, final Object value) throws IllegalArgumentException {
return owner.getProvider().putResourceIfAbsent(transaction, Assert.checkNotNullParamWithNullPointerException("key", key), value);
}
Object getKey() {
return owner.getProvider().getKey(transaction);
}
boolean getRollbackOnly() {
return owner.getProvider().getRollbackOnly(transaction);
}
void suspend() throws SystemException {
notifyAssociationListeners(false);
TransactionManager transactionManager = owner.getProvider().getTransactionManager();
if (! transaction.equals(transactionManager.getTransaction())) {
throw Log.log.unexpectedProviderTransactionMismatch(transaction, transactionManager.getTransaction());
}
final Transaction transactionManagerTransaction = transactionManager.suspend();
if (! transaction.equals(transactionManagerTransaction)) {
throw Log.log.unexpectedProviderTransactionMismatch(transaction, transactionManagerTransaction);
}
}
void resume() throws SystemException {
TransactionManager transactionManager = owner.getProvider().getTransactionManager();
try {
transactionManager.resume(transaction);
} catch (InvalidTransactionException e) {
// should be impossible
throw Log.log.invalidTxnState();
}
final Transaction transactionManagerTransaction = transactionManager.getTransaction();
if (! transaction.equals(transactionManagerTransaction)) {
throw Log.log.unexpectedProviderTransactionMismatch(transaction, transactionManagerTransaction);
}
notifyAssociationListeners(true);
}
void verifyAssociation() {
TransactionManager transactionManager = owner.getProvider().getTransactionManager();
try {
final Transaction transactionManagerTransaction = transactionManager.getTransaction();
if (! transaction.equals(transactionManagerTransaction)) {
throw Log.log.unexpectedProviderTransactionMismatch(transaction, transactionManagerTransaction);
}
} catch (SystemException e) {
// should be impossible
throw Log.log.invalidTxnState();
}
}
/**
* Determine if this transaction was imported.
*
* @return {@code true} if the transaction was imported, {@code false} if it was initiated locally
*/
public boolean isImported() {
return owner.getProvider().isImported(transaction);
}
public T getProviderInterface(final Class providerInterfaceType) {
return owner.getProvider().getProviderInterface(transaction, providerInterfaceType);
}
public int hashCode() {
return transaction.hashCode();
}
public boolean equals(final Object obj) {
return obj instanceof LocalTransaction && equals((LocalTransaction) obj);
}
private boolean equals(final LocalTransaction obj) {
return this == obj || obj != null && transaction.equals(obj.transaction);
}
public String toString() {
return String.format("Local transaction (delegate=%s, owner=%s)", transaction, owner);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy