blob: 71974f6ea65021532645e21f3c17d12fb638bd11 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.openjpa.jta;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.RollbackException;
import javax.transaction.Status;
import javax.transaction.Synchronization;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.xa.XAResource;
/**
* A transaction for testing.
*
* @author Pinaki Poddar
*
*/
public class SimpleTransaction implements Transaction {
private final Set<Synchronization> synchs = new HashSet<>();
private Throwable rollbackCause;
private volatile int status = Status.STATUS_UNKNOWN;
/**
* Commits this transaction.
*/
@Override
public void commit() throws HeuristicMixedException, HeuristicRollbackException, RollbackException,
SecurityException, SystemException {
if (status == Status.STATUS_MARKED_ROLLBACK)
throw new RuntimeException(this + " can not commit. Marked for rollback");
status = Status.STATUS_COMMITTING;
List<Throwable> errors = new ArrayList<>();
for (Synchronization synch : synchs) {
try {
synch.beforeCompletion();
} catch (Throwable t) {
errors.add(t);
}
}
// do nothing
status = errors.isEmpty() ? Status.STATUS_COMMITTED : Status.STATUS_ROLLEDBACK;
for (Synchronization synch : synchs) {
try {
synch.afterCompletion(status);
} catch (Throwable t) {
errors.add(t);
}
}
status = errors.isEmpty() ? Status.STATUS_COMMITTED : Status.STATUS_UNKNOWN;
}
/**
* Not implemented.
* Raises UnsupportedOperationException.
*/
@Override
public boolean delistResource(XAResource arg0, int arg1) throws IllegalStateException, SystemException {
throw new UnsupportedOperationException();
}
/**
* Not implemented.
* Raises UnsupportedOperationException.
*/
@Override
public boolean enlistResource(XAResource arg0) throws IllegalStateException, RollbackException, SystemException {
return false;
}
/**
* Gets the status of this transaction.
* Raises UnsupportedOperationException.
*/
@Override
public int getStatus() throws SystemException {
return status;
}
void setStatus(int newStatus) throws SystemException {
status = newStatus;
}
/**
* Registers the given synchronization element.
*/
@Override
public void registerSynchronization(Synchronization synch) throws IllegalStateException, RollbackException,
SystemException {
synchs.add(synch);
}
/**
* Rolls back this transaction.
*/
@Override
public void rollback() throws IllegalStateException, SystemException {
status = Status.STATUS_ROLLING_BACK;
List<Throwable> errors = new ArrayList<>();
for (Synchronization synch : synchs) {
try {
synch.beforeCompletion();
} catch (Throwable t) {
errors.add(t);
}
}
for (Synchronization synch : synchs) {
try {
synch.afterCompletion(Status.STATUS_ROLLEDBACK);
} catch (Throwable t) {
errors.add(t);
}
}
status = errors.isEmpty() ? Status.STATUS_ROLLEDBACK : Status.STATUS_UNKNOWN;
if (!errors.isEmpty())
throw new RuntimeException(errors.get(0));
}
/**
* Marks this transaction for rollback only.
*/
@Override
public void setRollbackOnly() throws IllegalStateException, SystemException {
setRollbackOnly(null);
}
/**
* Marks this transaction for rollback only with the given underlying cause.
*/
void setRollbackOnly(Throwable cause) throws IllegalStateException, SystemException {
rollbackCause = cause;
status = Status.STATUS_MARKED_ROLLBACK;
}
Throwable getRollbackCause() {
return rollbackCause;
}
@Override
public String toString() {
return "TXN:"+hashCode() +"["+statusCode()+"]";
}
String statusCode() {
switch (status) {
case Status.STATUS_ACTIVE : return "active";
case Status.STATUS_COMMITTED : return "committed";
case Status.STATUS_COMMITTING : return "committing";
case Status.STATUS_MARKED_ROLLBACK : return "marked rollback";
case Status.STATUS_NO_TRANSACTION : return "none";
case Status.STATUS_PREPARED : return "prepared";
case Status.STATUS_PREPARING : return "preparing";
case Status.STATUS_ROLLEDBACK : return "rolled back";
case Status.STATUS_ROLLING_BACK : return "rolling back";
case Status.STATUS_UNKNOWN : return "unknown";
default : return "error";
}
}
}