/*
 *    GeoTools - OpenSource mapping toolkit
 *    http://geotools.org
 *    (C) 2002-2006, GeoTools Project Managment Committee (PMC)
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License as published by the Free Software Foundation;
 *    version 2.1 of the License.
 *
 *    This library 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
 *    Lesser General Public License for more details.
 */
package org.geotools.data;

import java.io.IOException;
import java.util.Set;


/**
 * The controller for Transaction with FeatureStore.
 *
 * <p>
 * Shapefiles, databases, etc. are safely modified with the assistance of this
 * interface. Transactions are also to provide authorization when working with
 * locked features.
 * </p>
 *
 * <p>
 * All operations are considered to be working against a Transaction.
 * Transaction.AUTO_COMMIT is used to represent an immidiate mode where
 * requests are immidately commited.
 * </p>
 *
 * <p>
 * For more information please see DataStore and FeatureStore.
 * </p>
 *
 * <p>
 * Example Use:
 * </p>
 * <pre><code>
 * Transaction t = new DefaultTransaction("handle");
 * t.putProperty( "hint", new Integer(7) );
 * try {
 *     FeatureStore road = (FeatureStore) store.getFeatureSource("road");
 *     FeatureStore river = (FeatureStore) store.getFeatureSource("river");
 *
 *     road.setTransaction( t );
 *     river.setTransaction( t );
 *
 *     t.addAuthorization( lockID );  // provide authoriztion
 *     road.removeFeatures( filter ); // operate against transaction
 *     river.removeFeature( filter ); // operate against transaction
 *
 *     t.commit(); // commit operations
 * }
 * catch (IOException io){
 *     t.rollback(); // cancel operations
 * }
 * finally {
 *     t.close(); // free resources
 * }
 * </code></pre>
 * <p>
 * Example code walkthrough (from the perspective of Transaction):
 * </p>
 * <ol>
 * <li>A new transaction is created (an instanceof DefaultTransaction with a handle)</li>
 * <li>A hint is provided using Transaction.putProperty( key, value )</li>
 * <li>Transaction is provided to two FeatureStores, this may result
 *     in Transaction.State instances being registered</li>
 *     <ul>
 *     <li>TransactionStateDiff (stored by DataStore):
 *         Used for in memory locking is used by many DataStore's
 *         (like ShapefileDataStore).
 *         Lazy creation by AbstractDataStore.state(transaction).
 *         </li>
 *     <li>JDBCTransactionState (stored by ConnectionPool):
 *         Used to manage connection rollback/commit.
 *         Lazy creation as part of JDBCDataStore.getConnection(transaction).
 *         </li>
 *     <li>InProcessLockingManager.FeatureLock (stored by LockingManger):
 *         Used for per transaction FeatureLocks, used to free locked features
 *         on Transaction commit/rollback.
 *         </li>
 *     </ul>
 *     These instances of Transaction state may make use of any hint provided
 *     to Transaction.putProperty( key, value ) when they are connected with
 *     Transaction.State.setTransaction( transaction ).
 * <li>t.addAuthorization(lockID) is called, each Transaction.State has its
 *     addAuthroization(String) callback invoked with the value of lockID</li>
 * <li>FeatureStore.removeFeatures methods are called on the two DataStores.
 *     <ul>
 *     <li>PostgisFeatureStore.removeFeatures(fitler) handles operation
 *         without delegation.
 *         </li>
 *     <li>Most removeFeature(filter) implementations use the implementation
 *         provided by AbstractFeatureStore which delegates to FeatureWriter.
 *         </li>
 *     </ul>
 *     Any of these operations may make use of the
 *     Transaction.putProperty( key, value ).
 * <li>The transaction is commited, all of the Transaction.State methods have
 *     there Transaction.State.commit() methods called gicing them a chance
 *     to applyDiff maps, or commit various connections.
 *     </li>
 * <li>The transaction is closed, all of the Transaction.State methods have
 *     there Transaction.State.setTransaction( null ) called, giving them a
 *     chance to clean up diffMaps, or return connections to the pool.
 *     </li>
 * </ol>
 * @author Jody Garnett
 * @author Chris Holmes, TOPP
 * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/api/src/main/java/org/geotools/data/Transaction.java $
 * @version $Id: Transaction.java 23258 2006-12-06 19:30:14Z tmarti $
 */
public interface Transaction {
    /** Represents AUTO_COMMIT Mode */
    static final Transaction AUTO_COMMIT = new AutoCommitTransaction();

    //
    // External State
    //
    /**
     * Retrive a Transaction property held by this transaction.
     *
     * <p>
     * This may be used to provide hints to DataStore implementations, it
     * operates as a blackboard for client, FeatureSource communication.
     * </p>
     *
     * <p>
     * If this proves successful addAuthorization/getAuthorization will be
     * replaced with this mechanism.
     * </p>
     */
    Object getProperty(Object key);

    /**
     * List of Authorizations IDs held by this transaction.
     *
     * <p>
     * This list is reset by the next call to commit() or rollback().
     * </p>
     *
     * <p>
     * Authorization IDs are used to provide FeatureLock support.
     * </p>
     *
     * @return List of Authorization IDs
     */
    Set getAuthorizations();

    /**
     * Allows FeatureSource to squirel away information( and callbacks ) for
     * later.
     *
     * <p>
     * The most common example is a JDBC DataStore saving the required
     * connection for later operations.
     * </p>
     * <pre><code>
     * ConnectionState implements State {
     *     public Connection conn;
     *     public addAuthorization() {}
     *     public commit(){ conn.commit(); }
     *     public rollback(){ conn.rollback(); }
     * }
     * </code></pre>
     *
     * <p>
     * putState will call State.setTransaction( transaction ) to allow State a
     * chance to configure itself.
     * </p>
     *
     * @param key Key used to externalize State
     * @param state Externalized State
     */
    void putState(Object key, State state);

    /**
     * Allows FeatureSources to clean up information ( and callbacks ) they
     * earlier provided.
     *
     * <p>
     * Care should be taken when using shared State to not remove State
     * required by another FeatureSources.
     * </p>
     *
     * <p>
     * removeState will call State.setTransaction( null ) to allow State a
     * chance cleanup after itself.
     * </p>
     *
     * @param key Key that was used to externalize State
     */
    void removeState(Object key);

    /**
     * Allows DataStores to squirel away information( and callbacks ) for
     * later.
     *
     * <p>
     * The most common example is a JDBC DataStore saving the required
     * connection for later operations.
     * </p>
     *
     * @return Current State externalized by key, or <code>null</code> if not
     *         found
     */
    State getState(Object key);

    //
    // Flow Control
    //    

    /**
     * Makes all transactions made since the previous commit/rollback
     * permanent.
     *
     * <p>
     * FeatureSources will need to issue any changes notifications using a
     * FeatureEvent.FEATURES_CHANGED to all FeatureSources with the same
     * typeName and a different Transaction. FeatureSources with the same
     * Transaction will of been notified of changes as the FeaureWriter made
     * them.
     * </p>
     *
     * @throws DataSourceException if there are any datasource errors.
     *
     * @see #setAutoCommit(boolean)
     */
    void commit() throws IOException;

    /**
     * Undoes all transactions made since the last commit or rollback.
     *
     * <p>
     * FeatureSources will need to issue any changes notifications using a
     * FeatureEvent.FEATURES_CHANGED. This will need to be issued to all
     * FeatureSources with the same typeName and Transaction.
     * </p>
     *
     * @throws DataSourceException if there are problems with the datasource.
     * @throws UnsupportedOperationException if the rollback method is not
     *         supported by this datasource.
     *
     * @see #setAutoCommit(boolean)
     */
    void rollback() throws IOException;

    //
    // Locking Support
    // 

    /**
     * Provides an Authorization ID for this Transaction.
     *
     * <p>
     * All proceeding modifyFeatures,removeFeature, unLockFeatures, refreshLock
     * and ReleaseLock operations will make use of the provided authorization.
     * </p>
     *
     * <p>
     * Authorization is only maintained until the this Transaction is commited
     * or rolledback.
     * </p>
     *
     * <p>
     * That is operations will only succeed if affected features either:
     * </p>
     *
     * <ul>
     * <li>
     * not locked
     * </li>
     * <li>
     * locked with the provided authID
     * </li>
     * </ul>
     *
     * <p>
     * Authorization ID is provided as a String, rather than a FeatureLock, to
     * account for across process lock use.
     * </p>
     *
     * @param authID
     */
    void addAuthorization(String authID) throws IOException;

    /**
     * Provides a Transaction property for this Transasction.
     *
     * <p>
     * All proceeding FeatureSource (for FeatureReader/Writer) operations may
     * make use of the provided property.
     * </p>
     */
    void putProperty(Object key, Object value) throws IOException;

    /**
     * Provides an opportunity for a Transaction to free an State it maintains.
     * <p>
     * This method should call State.setTransaction( null ) on all State it
     * maintains.
     * </p>
     * <p>
     * It is hoped that FeatureStore implementations that have externalized
     * their State with the transaction take the opportunity to revert to
     * Transction.AUTO_COMMIT.
     * </p>
     * @throws IOException
     */
    void close() throws IOException;

    /**
     * DataStore implementations can use this interface to externalize the
     * state they require to implement Transaction Support.
     *
     * <p>
     * The commit and rollback methods will be called as required. The
     * intension is that several DataStores can share common transaction state
     * (example: Postgis DataStores sharing a connection to the same
     * database).
     * </p>
     *
     * @author jgarnett, Refractions Reasearch Inc.
     * @version CVS Version
     *
     * @see org.geotools.data
     */
    static public interface State {
        /**
         * Provides configuration information for Transaction.State
         *
         * <p>
         * setTransaction is called with non null <code>transaction</code> when
         * Transaction.State is <code>putState</code> into a Transaction. This
         * tranasction will be used to determine correct event notification.
         * </p>
         *
         * <p>
         * setTransaction is called with <code>null</code> when removeState is
         * called (usually during Transaction.close() ).
         * </p>
         *
         * @param transaction
         */
        void setTransaction(Transaction transaction);

        /**
         * Call back used for Transaction.setAuthorization()
         */
        void addAuthorization(String AuthID) throws IOException;

        /**
         * Call back used for Transaction.commit()
         */
        void commit() throws IOException;

        /**
         * Call back used for Transaction.rollback()
         */
        void rollback() throws IOException;
    }
}
