Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.wildfly.transaction.client.RemoteTransaction Maven / Gradle / Ivy
/*
* 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 java.net.URI;
import java.security.AccessController;
import java.security.GeneralSecurityException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicReference;
import javax.net.ssl.SSLContext;
import jakarta.transaction.HeuristicMixedException;
import jakarta.transaction.HeuristicRollbackException;
import jakarta.transaction.RollbackException;
import jakarta.transaction.Status;
import jakarta.transaction.Synchronization;
import jakarta.transaction.SystemException;
import javax.transaction.xa.XAResource;
import org.wildfly.common.Assert;
import org.wildfly.security.auth.client.AuthenticationConfiguration;
import org.wildfly.security.auth.client.AuthenticationContext;
import org.wildfly.security.auth.client.AuthenticationContextConfigurationClient;
import org.wildfly.transaction.TransactionPermission;
import org.wildfly.transaction.client._private.Log;
import org.wildfly.transaction.client.spi.RemoteTransactionProvider;
import org.wildfly.transaction.client.spi.SimpleTransactionControl;
/**
* @author David M. Lloyd
*/
public final class RemoteTransaction extends AbstractTransaction {
private final AtomicReference stateRef;
private final ConcurrentMap resources = new ConcurrentHashMap<>();
private final AuthenticationContext authenticationContext;
private final Object key = new Object();
private final int timeout;
static final AuthenticationContextConfigurationClient CLIENT = AccessController.doPrivileged(AuthenticationContextConfigurationClient.ACTION);
RemoteTransaction(final AuthenticationContext authenticationContext, final int timeout) {
this.authenticationContext = authenticationContext;
stateRef = new AtomicReference<>(Unlocated.ACTIVE);
this.timeout = timeout;
}
public Object getResource(final Object key) throws NullPointerException {
Assert.checkNotNullParamWithNullPointerException("key", key);
return resources.get(key);
}
public void putResource(final Object key, final Object value) throws NullPointerException {
Assert.checkNotNullParamWithNullPointerException("key", key);
if (value == null) resources.remove(key); else resources.put(key, value);
}
public Object putResourceIfAbsent(final Object key, final Object value) throws IllegalArgumentException {
Assert.checkNotNullParamWithNullPointerException("key", key);
return value == null ? resources.get(key) : resources.putIfAbsent(key, value);
}
Object getKey() {
return key;
}
void suspend() {
notifyAssociationListeners(false);
// no operation
}
void resume() {
notifyAssociationListeners(true);
// no operation
}
void verifyAssociation() {
// no operation
}
public int getTransactionTimeout() {
return timeout;
}
public T getProviderInterface(final Class providerInterfaceType) {
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(TransactionPermission.forName("getProviderInterface"));
}
return stateRef.get().getProviderInterface(providerInterfaceType);
}
public void commit() throws RollbackException, HeuristicMixedException, HeuristicRollbackException, SecurityException, SystemException {
final AtomicReference stateRef = this.stateRef;
try {
stateRef.get().commit(stateRef);
} catch (RollbackException re) {
addRollbackExceptions(re);
throw re;
}
}
void commitAndDissociate() throws RollbackException, HeuristicMixedException, HeuristicRollbackException, SecurityException, SystemException {
try {
commit();
} finally {
suspend();
}
}
public void rollback() throws IllegalStateException, SystemException {
final AtomicReference stateRef = this.stateRef;
stateRef.get().rollback(stateRef);
}
void rollbackAndDissociate() throws IllegalStateException, SystemException {
try {
rollback();
} finally {
suspend();
}
}
boolean importBacking() {
return false;
}
void unimportBacking() {
}
public void setRollbackOnly() throws IllegalStateException, SystemException {
super.setRollbackOnly();
final AtomicReference stateRef = this.stateRef;
stateRef.get().setRollbackOnly(stateRef);
}
public int getStatus() {
return stateRef.get().getStatus();
}
public boolean enlistResource(final XAResource xaRes) {
Assert.checkNotNullParam("xaRes", xaRes);
return false;
}
public boolean delistResource(final XAResource xaRes, final int flag) {
Assert.checkNotNullParam("xaRes", xaRes);
return false;
}
public void registerSynchronization(final Synchronization sync) throws RollbackException, IllegalStateException, SystemException {
Assert.checkNotNullParam("sync", sync);
stateRef.get().registerSynchronization(new AssociatingSynchronization(sync));
}
void registerInterposedSynchronization(final Synchronization sync) throws IllegalStateException {
Assert.checkNotNullParam("sync", sync);
stateRef.get().registerInterposedSynchronization(new AssociatingSynchronization(sync));
}
public int hashCode() {
return System.identityHashCode(this);
}
public boolean equals(final Object obj) {
return obj == this;
}
public String toString() {
return String.format("Remote transaction %s", stateRef.get());
}
/**
* Get the location of this remote transaction.
*
* @return the location of this remote transaction, or {@code null} if it has no location as of yet
*/
public URI getLocation() {
return stateRef.get().getLocation();
}
/**
* Attempt to set the location of this transaction, binding it to a remote transport provider.
*
* @param location the location to set (must not be {@code null})
* @throws IllegalArgumentException if there is no provider for the given location (or it is {@code null}), or the
* security context was invalid
* @throws IllegalStateException if the transaction is in an invalid state for setting its location
* @throws SystemException if the transport could not begin the transaction
*/
public void setLocation(URI location) throws IllegalArgumentException, IllegalStateException, SystemException {
Assert.checkNotNullParam("location", location);
final RemoteTransactionContext context = RemoteTransactionContext.getInstancePrivate();
final RemoteTransactionProvider provider = context.getProvider(location);
if (provider == null) {
throw Log.log.noProviderForUri(location);
}
final AuthenticationContextConfigurationClient client = CLIENT;
final AuthenticationConfiguration authenticationConfiguration = client.getAuthenticationConfiguration(location, authenticationContext, - 1, "jta", "jboss");
final SSLContext sslContext;
try {
sslContext = client.getSSLContext(location, authenticationContext, "jta", "jboss");
} catch (GeneralSecurityException e) {
throw new IllegalArgumentException(e);
}
final SimpleTransactionControl control;
if(stateRef.get() instanceof Located) {
control = null;
} else {
control = provider.getPeerHandle(location, sslContext, authenticationConfiguration).begin(getEstimatedRemainingTime());
}
try {
stateRef.get().join(stateRef, location, control);
} catch (Throwable t) {
try {
control.rollback();
} catch (Throwable t2) {
t2.addSuppressed(t);
throw t2;
}
throw t;
}
}
/**
* Attempt to clear the location set on this transaction, disassociating it
* with the remote transport provider. There is only a limited time window
* at which this can occur, before the transaction is ever used. Typically
* this is only useful for retrying an initial invocation on a transaction.
*
* @return whether the attempt was successful
*/
public boolean tryClearLocation() {
return stateRef.get().tryToDisassociate(stateRef);
}
abstract static class State {
State() {
}
abstract void join(AtomicReference stateRef, URI location, SimpleTransactionControl control) throws IllegalStateException;
boolean tryToDisassociate(AtomicReference stateRef) {
return false;
}
abstract void commit(AtomicReference stateRef) throws RollbackException, HeuristicMixedException, HeuristicRollbackException, SecurityException, SystemException;
abstract void rollback(AtomicReference stateRef) throws IllegalStateException, SystemException;
abstract void setRollbackOnly(AtomicReference stateRef) throws IllegalStateException, SystemException;
abstract int getStatus();
abstract void registerSynchronization(Synchronization sync) throws RollbackException, IllegalStateException, SystemException;
abstract void registerInterposedSynchronization(Synchronization sync) throws IllegalStateException;
T getProviderInterface(final Class providerInterfaceType) {
return null;
}
URI getLocation() {
return null;
}
}
abstract static class Unresolved extends State {
Unresolved() {
}
void registerSynchronization(final Synchronization sync) throws RollbackException, IllegalStateException, SystemException {
throw Log.log.registerSynchRemoteTransaction();
}
void registerInterposedSynchronization(final Synchronization sync) throws IllegalStateException {
throw Log.log.registerSynchRemoteTransaction();
}
}
static final class Unlocated extends Unresolved {
private final int status;
static final Unlocated ACTIVE = new Unlocated(Status.STATUS_ACTIVE);
static final Unlocated ROLLBACK_ONLY = new Unlocated(Status.STATUS_MARKED_ROLLBACK);
Unlocated(final int status) {
this.status = status;
}
void join(final AtomicReference stateRef, final URI location, final SimpleTransactionControl control) throws IllegalStateException {
State newState;
switch (status) {
case Status.STATUS_ACTIVE: newState = new Active(location, control); break;
case Status.STATUS_MARKED_ROLLBACK: newState = new RollbackOnly(location, control); break;
default: throw Assert.impossibleSwitchCase(status);
}
if (stateRef.compareAndSet(this, newState)) {
return;
} else {
stateRef.get().join(stateRef, location, control);
}
}
void commit(final AtomicReference stateRef) {
stateRef.set(InactiveState.COMMITTED);
}
void rollback(final AtomicReference stateRef) throws IllegalStateException, SystemException {
stateRef.set(InactiveState.ROLLED_BACK);
}
void setRollbackOnly(final AtomicReference stateRef) throws IllegalStateException, SystemException {
stateRef.set(Unlocated.ROLLBACK_ONLY);
}
int getStatus() {
return status;
}
boolean tryToDisassociate(AtomicReference stateRef) {
return true;
}
}
abstract static class Located extends Unresolved {
final URI location;
final SimpleTransactionControl control;
volatile boolean multipleJoins = false;
Located(final URI location, final SimpleTransactionControl control) {
this.location = location;
this.control = control;
}
void join(final AtomicReference stateRef, final URI location, final SimpleTransactionControl control) throws IllegalStateException {
if (! this.location.equals(location)) {
throw Log.log.locationAlreadyInitialized(location, this.location);
}
multipleJoins = true;
}
void rollback(final AtomicReference stateRef) throws IllegalStateException, SystemException {
if (! stateRef.compareAndSet(this, InactiveState.ROLLING_BACK)) {
stateRef.get().rollback(stateRef);
return;
}
try {
control.rollback();
} catch (SecurityException e) {
stateRef.set(this);
throw e;
} catch (Throwable t) {
stateRef.set(InactiveState.UNKNOWN);
throw t;
}
stateRef.set(InactiveState.ROLLED_BACK);
}
T getProviderInterface(final Class providerInterfaceType) {
return control.getProviderInterface(providerInterfaceType);
}
URI getLocation() {
return location;
}
}
static final class Active extends Located {
Active(final URI location, final SimpleTransactionControl control) {
super(location, control);
}
void commit(final AtomicReference stateRef) throws RollbackException, HeuristicMixedException, HeuristicRollbackException, SecurityException, SystemException {
if (! stateRef.compareAndSet(this, InactiveState.COMMITTING)) {
stateRef.get().commit(stateRef);
return;
}
try {
control.commit();
} catch (SecurityException e) {
stateRef.set(this);
throw e;
} catch (RollbackException | HeuristicRollbackException e) {
stateRef.set(InactiveState.ROLLED_BACK);
throw e;
} catch (Throwable t) {
stateRef.set(InactiveState.UNKNOWN);
throw t;
}
stateRef.set(InactiveState.COMMITTED);
}
int getStatus() {
return Status.STATUS_ACTIVE;
}
void setRollbackOnly(final AtomicReference stateRef) throws IllegalStateException, SystemException {
synchronized (stateRef) {
// there's no "marking rollback" state
final RollbackOnly newState = new RollbackOnly(location, control);
if (! stateRef.compareAndSet(this, newState)) {
stateRef.get().setRollbackOnly(stateRef);
}
control.setRollbackOnly();
}
}
boolean tryToDisassociate(AtomicReference stateRef) throws IllegalStateException {
return !multipleJoins && (stateRef.compareAndSet(this, Unlocated.ACTIVE) || stateRef.get().tryToDisassociate(stateRef));
}
}
static final class RollbackOnly extends Located {
RollbackOnly(final URI location, final SimpleTransactionControl control) {
super(location, control);
}
void commit(final AtomicReference stateRef) throws RollbackException, HeuristicMixedException, HeuristicRollbackException, SecurityException, SystemException {
rollback(stateRef);
throw Log.log.rollbackOnlyRollback();
}
void setRollbackOnly(final AtomicReference stateRef) {
// no operation
}
int getStatus() {
return Status.STATUS_MARKED_ROLLBACK;
}
void registerSynchronization(final Synchronization sync) throws RollbackException, IllegalStateException, SystemException {
throw Log.log.markedRollbackOnly();
}
}
static final class InactiveState extends State {
private final int status;
static final InactiveState ROLLED_BACK = new InactiveState(Status.STATUS_ROLLEDBACK);
static final InactiveState COMMITTED = new InactiveState(Status.STATUS_COMMITTED);
static final InactiveState UNKNOWN = new InactiveState(Status.STATUS_UNKNOWN);
static final InactiveState COMMITTING = new InactiveState(Status.STATUS_COMMITTING);
static final InactiveState ROLLING_BACK = new InactiveState(Status.STATUS_ROLLING_BACK);
private InactiveState(final int status) {
this.status = status;
}
void join(final AtomicReference stateRef, final URI location, final SimpleTransactionControl control) throws IllegalStateException {
throw Log.log.notActive();
}
void commit(final AtomicReference stateRef) throws RollbackException, HeuristicMixedException, HeuristicRollbackException, SecurityException, SystemException {
throw Log.log.notActive();
}
void rollback(final AtomicReference stateRef) throws IllegalStateException, SystemException {
throw Log.log.notActive();
}
void setRollbackOnly(final AtomicReference stateRef) throws IllegalStateException, SystemException {
if (status != Status.STATUS_ROLLING_BACK) {
throw Log.log.notActive();
}
}
int getStatus() {
return status;
}
void registerSynchronization(final Synchronization sync) throws RollbackException, IllegalStateException, SystemException {
throw Log.log.notActive();
}
void registerInterposedSynchronization(final Synchronization sync) throws IllegalStateException {
throw Log.log.notActive();
}
}
}