/*
* Copyright 2007-2010 Sun Microsystems, Inc.
*
* This file is part of Project Darkstar Server.
*
* Project Darkstar Server is free software: you can redistribute it
* and/or modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation and
* distributed hereunder to you.
*
* Project Darkstar Server is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Sun designates this particular file as subject to the "Classpath"
* exception as provided by Sun in the LICENSE file that accompanied
* this code.
*
* --
*/
package com.sun.sgs.service;
import com.sun.sgs.app.ExceptionRetryStatus;
import com.sun.sgs.app.TransactionAbortedException;
import com.sun.sgs.app.TransactionNotActiveException;
import com.sun.sgs.app.TransactionTimeoutException;
/**
* This interface represents a single transaction. It is used by
* participants to join a transaction and manage state associated with
* a transaction.
* <p>
* Note that some transaction implementations may only support transactions
* with at most one durable transaction participant, because of the need to
* communicate the outcome of prepared transactions to transaction participants
* following a crash when there are multiple durable participants.
* <p>
* All implementations of <code>Transaction</code> must implement
* <code>equals</code> and <code>hashCode</code>. Two
* <code>Transaction</code>s are equal if and only if they represent
* the same transaction.
* <p>
* The implementations of the {@link #join join}, {@link #abort abort}, and
* {@link #registerListener registerListener} methods of this interface are not
* thread-safe. Callers should insure that calls they make to these methods
* are made from the thread that created the transaction.
*/
public interface Transaction {
/**
* Returns the unique identifier for this <code>Transaction</code>. If
* two <code>Transaction</code>s have the same identifier then they
* represent the same transaction. This will always return a unique
* copy of the identifier.
*
* @return the transaction's identifier
*/
byte[] getId();
/**
* Returns the time at which this <code>Transaction</code> was created.
* This is a value in milliseconds measured from 1/1/1970. This is
* typically used for determining whether a <code>Transaction</code>
* has run too long, or how it should be re-scheduled, but in
* practice may be used as a participant sees fit.
*
* @return the creation time-stamp
*/
long getCreationTime();
/**
* Returns the length of time in milliseconds that this
* <code>Transaction</code> is allowed to run before it should timeout.
*
* @return the timeout length
*/
long getTimeout();
/**
* Checks if this <code>Transaction</code> has timed out, throwing a
* <code>TransactionTimeoutException</code> if it has.
*
* @throws TransactionNotActiveException if the transaction is not active
* @throws TransactionTimeoutException if the transaction has timed out
* @throws IllegalStateException if called from a thread that is not the
* thread that created this transaction
*/
void checkTimeout();
/**
* Tells the <code>Transaction</code> that the given
* <code>TransactionParticipant</code> is participating in the
* transaction. A <code>TransactionParticipant</code> is allowed to
* join a <code>Transaction</code> more than once, but will only
* be registered as a single participant.
* <p>
* If the transaction has been aborted, then the exception thrown will have
* as its cause the value provided in the first call to {@link #abort
* abort}, if any. If the cause implements {@link ExceptionRetryStatus},
* then the exception thrown will, too, and its {@link
* ExceptionRetryStatus#shouldRetry shouldRetry} method will return the
* value returned by calling that method on the cause. If no cause was
* supplied, then the exception will either not implement {@code
* ExceptionRetryStatus} or its {@code shouldRetry} method will return
* {@code false}.
*
* @param participant the <code>TransactionParticipant</code> joining
* the transaction
*
* @throws TransactionNotActiveException if the transaction has been
* aborted
*
* @throws IllegalStateException if {@link TransactionParticipant#prepare
* prepare} has been called on any
* transaction participant and the
* transaction has not been aborted, or if
* called from a thread that is not the
* thread that created this transaction
*
* @throws UnsupportedOperationException if <code>participant</code> does
* not implement {@link NonDurableTransactionParticipant} and the
* implementation cannot support an additional durable transaction
* participant
*/
void join(TransactionParticipant participant);
/**
* Aborts the transaction, specifying the cause. This notifies all
* participants that the transaction has aborted, and invalidates all
* future use of this transaction. The caller should always follow a call
* to <code>abort</code> by throwing an exception that details why the
* transaction was aborted. If the exception could be caught by application
* code, then the exception thrown should be a {@link
* TransactionAbortedException}, created by wrapping the original cause if
* needed. Throwing an exception is needed not only to communicate the
* cause of the abort and whether to retry the exception, but also because
* the application code associated with this transaction will continue to
* execute normally unless an exception is raised. Supplying the cause to
* this method allows future calls to the transaction to include the cause
* to explain why the transaction is no longer active.
* <p>
* If the transaction has been aborted, then the exception thrown will have
* as its cause the value provided in the first call to {@link #abort
* abort}, if any. If the cause implements {@link ExceptionRetryStatus},
* then the exception thrown will, too, and its {@link
* ExceptionRetryStatus#shouldRetry shouldRetry} method will return the
* value returned by calling that method on the cause.
*
* @param cause the exception that caused the abort
*
* @throws TransactionNotActiveException if the transaction has been
* aborted
*
* @throws IllegalStateException if all transaction participants have been
* prepared and {@link #abort abort} has not
* been called, or if called from a thread
* that is not the thread that created this
* transaction
*/
void abort(Throwable cause);
/**
* Returns information about whether {@link #abort abort} has been called
* on this transaction.
*
* @return {@code true} if {@code abort} has been called on this
* transaction, else {@code false}
*/
boolean isAborted();
/**
* Returns the cause supplied in the first call to {@link #abort abort} on
* this transaction, or {@code null} if {@code abort} has not been called.
*
* @return the exception that caused the abort or {@code null}
*/
Throwable getAbortCause();
/**
* Registers a listener that will be notified just before this transaction
* is prepared, and after it commits or aborts. <p>
*
* The {@code listener}'s {@link TransactionListener#beforeCompletion
* beforeCompletion} method will be called after the main work of the
* transaction is complete, just before the transaction is prepared. The
* transaction will still be considered active at the time of the call,
* although calls should not be made to independent {@link Service}s. If
* the call to {@code beforeCompletion} throws an exception, then this
* transaction will be aborted, and the exception will be treated as if it
* were thrown by the main body of the transaction. The {@code listener}'s
* {@code beforeCompletion} method will not be called if this transaction
* is aborted before it reaches the preparation stage, including if an
* earlier call to {@code beforeCompletion} on another listener throws an
* exception or aborts this transaction. <p>
*
* The {@code listener}'s {@link TransactionListener#afterCompletion
* afterCompletion} method will be called after this transaction is
* committed or aborted. <p>
*
* Any number of listeners can be registered for this transaction by making
* multiple calls to this method. If multiple listeners are registered,
* the order in which the listeners are called is unspecified.
*
* @param listener the listener
* @throws TransactionNotActiveException if this transaction is not
* active
* @throws IllegalStateException if called from a thread that is not the
* thread that created this transaction
*/
void registerListener(TransactionListener listener);
}