/*
 * 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 net.jini.core.transaction;

import net.jini.core.lease.Lease;
import net.jini.core.lease.LeaseDeniedException;
import java.rmi.RemoteException;

/**
 * Interface for classes representing transactions returned by
 * <code>TransactionManager</code> servers for use with transaction
 * participants that implement the default transaction semantics.
 * The semantics: <p>
 *
 * The overall effect of executing a set of sibling pure transactions
 * concurrently is always equivalent to some sequential execution. <p>
 *
 * Ancestor transactions can execute concurrently with child transactions,
 * subject to the locking rules below. <p>
 *
 * Every transactional operation is described in terms of acquiring locks
 * on objects; these locks are held until the transaction completes.  Whatever
 * the lock rules are, conflict rules are defined such that if two operations
 * do not commute, then they acquire conflicting locks.  A transaction can
 * acquire a lock only if the conflicting locks are those held by ancestor
 * transactions (or itself). When a subtransaction commits, its locks are
 * inherited by the parent transaction. <p>
 *
 * If an object is defined to be created under a transaction, then the
 * existence of the object is only visible within that transaction and its
 * inferiors, but will disappear if the transaction aborts.  If an object is
 * defined to be deleted under a transaction, then the object is not visible
 * to any transaction (including the deleting transaction) but will reappear
 * if the transaction aborts.  When a nested transaction commits, visibility
 * state is inherited by the parent transaction. <p>
 *
 * Once a transaction reaches the <code>VOTING</code> stage, if all
 * execution under the transaction (and its subtransactions) has finished,
 * then the only reasons the transaction can abort are: the manager crashes
 * (or has crashed); one or more participants crash (or have crashed); or
 * an explicit abort. <p>
 *
 * Transaction deadlocks are not guaranteed to be prevented or even detected,
 * but managers and participants are permitted to break known deadlocks by
 * aborting transactions. <p>
 *
 * An orphan transaction (it or one of its ancestors is guaranteed to abort)
 * is not guaranteed to be detected. <p>
 *
 * Causal ordering information about transactions is not guaranteed to be
 * propagated. <p>
 *
 * As long as a transaction persists in attempting to acquire a lock that
 * conflicts with another transaction, the participant will persist in
 * attempting to resolve the outcome of the transaction that holds the
 * conflicting lock.
 *
 * 
 *
 * @see NestableTransaction
 * @see net.jini.core.transaction.server.TransactionManager
 * @see net.jini.core.transaction.server.NestableTransactionManager
 * @see TransactionFactory
 *
 * @since 1.0
 */
public interface Transaction {

    /** Class that holds return values from create methods. */
    public static class Created implements java.io.Serializable {
	static final long serialVersionUID = -5199291723008952986L;

	/**
	 * The transaction.
	 * @serial
	 */
        public final Transaction transaction;
	/**
	 * The lease.
	 * @serial
	 */
        public final Lease lease;

	/**
	 * Simple constructor.
	 *
	 * @param transaction the transaction created
	 * @param lease the lease granted
	 */
	public Created(Transaction transaction, Lease lease) {
	    this.transaction = transaction;
	    this.lease = lease;
        }

        // inherit javadoc
        public String toString() {
            return this.getClass().getName() 
                + "[lease=" + lease + ", transaction=" + transaction + "]";
        }
    }

    /**
     * Commit the transaction. Commit asks the transaction manager to
     * execute the voting process with the participants.  Returns if the
     * transaction successfully reaches either the <code>NOTCHANGED</code>
     * or the <code>COMMITTED</code> state, without waiting for the
     * transaction manager to notify all participants of the decision.
     * If the transaction must be aborted (because one or more participants
     * are unable to prepare), <code>CannotCommitException</code> is thrown
     * without waiting for the transaction manager to notify all participants
     * of the decision.
     *
     * @throws UnknownTransactionException if the transaction is unknown 
     *         to the manager. This may be because the transaction ID was 
     *         incorrect, or because the transaction has proceeded to 
     *         cleanup due to an earlier commit or abort, and has been 
     *         forgotten.
     * @throws CannotCommitException if the transaction reaches the ABORTED 
     *         state, or is known to have previously reached that state due 
     *         to an earlier commit or abort.
     * @throws RemoteException if a communication error occurs.
     */
    void commit()
	throws UnknownTransactionException, CannotCommitException,
	       RemoteException;

    /**
     * Commit the transaction, waiting for participants to be notified of
     * the decision. Commit asks the transaction manager to execute the
     * voting process with the participants.  Returns if the transaction
     * successfully reaches either the <code>NOTCHANGED</code> or the
     * <code>COMMITTED</code> state, and the transaction manager has
     * notified all participants of the decision, before the specified
     * timeout expires.  If the transaction must be aborted (because one
     * or more participants are unable to prepare),
     * <code>CannotCommitException</code> is thrown if the transaction
     * manager is able to notify all participants of the decision before
     * the specified timeout expires.  If the transaction manager reaches
     * a decision, but is unable to notify all participants of that
     * decision before the specified timeout expires, then
     * <code>TimeoutExpiredException</code> is thrown.  If the specified
     * timeout expires before the transaction manager reaches a decision,
     * <code>TimeoutExpiredException</code> is not thrown until the
     * manager reaches a decision.
     *
     * @param waitFor timeout to wait, from the start of the call until
     * all participants have been notified of the transaction manager's
     * decision
     *
     * @throws UnknownTransactionException if the transaction is unknown 
     *         to the manager. This may be because the transaction ID was 
     *         incorrect, or because the transaction has proceeded to 
     *         cleanup due to an earlier commit or abort, and has been 
     *         forgotten.
     * @throws CannotCommitException if the transaction reaches the ABORTED 
     *         state, or is known to have previously reached that state due 
     *         to an earlier commit or abort.
     * @throws TimeoutExpiredException if the timeout expires before all 
     *         participants have been notified.
     * @throws RemoteException if a communication error occurs.
     */
    void commit(long waitFor)
	throws UnknownTransactionException, CannotCommitException,
	       TimeoutExpiredException, RemoteException;

    /**
     * Abort the transaction. This can be called at any time by
     * any object holding a reference to the transaction.  Abort asks
     * the transaction manager to abort the transaction and to notify
     * each participant of the decision, resulting in them rolling back
     * any state changes made as part of the transaction.  Returns as
     * soon as the transaction manager records the abort decision, without
     * waiting for the transaction manager to notify all participants of
     * the decision.
     *
     * @throws UnknownTransactionException if the transaction is unknown 
     *         to the manager. This may be because the transaction ID was 
     *         incorrect, or because the transaction has proceeded to 
     *         cleanup due to an earlier commit or abort, and has been 
     *         forgotten.
     * @throws CannotAbortException if the transaction is known to have 
     *         previously reached the COMMITTED state due to an earlier 
     *         commit.
     * @throws RemoteException if a communication error occurs.
     */
    void abort()
	throws UnknownTransactionException, CannotAbortException,
	       RemoteException;

    /**
     * Abort the transaction, waiting for participants to be notified of
     * the decision. This can be called at any time by any object holding
     * a reference to the transaction.  Abort asks the transaction manager
     * to abort the transaction and to notify each participant of the
     * decision, resulting in them rolling back any state changes made as
     * part of the transaction.  Returns if the transaction manager records
     * the decision and is able to notify all participants of the decision
     * before the specified timeout expires.  If the transaction manager
     * is unable to notify all participants of the decision before the
     * specified timeout expires, then <code>TimeoutExpiredException</code>
     * is thrown.
     *
     * @param waitFor timeout to wait, from the start of the call until
     * all participants have been notified of the transaction manager's
     * decision.
     *
     * @throws UnknownTransactionException if the transaction is unknown 
     *         to the manager. This may be because the transaction ID was 
     *         incorrect, or because the transaction has proceeded to 
     *         cleanup due to an earlier commit or abort, and has been 
     *         forgotten.
     * @throws CannotAbortException if the transaction is known to have 
     *         previously reached the COMMITTED state due to an earlier 
     *         commit.
     * @throws TimeoutExpiredException if the timeout expires before all 
     *         participants have been notified.
     * @throws RemoteException if a communication error occurs.
     */
    void abort(long waitFor)
       throws UnknownTransactionException, CannotAbortException,
	      TimeoutExpiredException, RemoteException;
}
