Package org.geotools.arcsde.data

Source Code of org.geotools.arcsde.data.ArcTransactionState

/*
*    GeoTools - The Open Source Java GIS Toolkit
*    http://geotools.org
*
*    (C) 2002-2008, Open Source Geospatial Foundation (OSGeo)
*
*    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.arcsde.data;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.geotools.arcsde.session.Command;
import org.geotools.arcsde.session.ISession;
import org.geotools.arcsde.versioning.ArcSdeVersionHandler;
import org.geotools.arcsde.versioning.TransactionVersionHandler;
import org.geotools.data.FeatureListenerManager;
import org.geotools.data.Transaction;
import org.geotools.util.logging.Logging;

import com.esri.sde.sdk.client.SeConnection;
import com.esri.sde.sdk.client.SeException;
import com.esri.sde.sdk.client.SeObjectId;
import com.esri.sde.sdk.client.SeState;
import com.esri.sde.sdk.client.SeVersion;

/**
* Store the transaction state for <code>ArcSDEFeatureWriter</code> instances.
*
* @author Jake Fear
* @author Gabriel Roldan
* @source $URL:
*         http://svn.geotools.org/geotools/trunk/gt/modules/plugin/arcsde/datastore/src/main/java
*         /org/geotools/arcsde/data/ArcTransactionState.java $
* @version $Id$
*/
final class ArcTransactionState implements Transaction.State {
    private static final Logger LOGGER = Logging.getLogger(ArcTransactionState.class.getName());

    /**
     * ArcSDEDataStore we can use to look up a Session for our Transaction.
     * <p>
     * The ConnectionPool will hold this connection open for us until commit(), rollback() or
     * close() is called.
     */
    private ArcSDEDataStore dataStore;

    private Transaction transaction;

    private final FeatureListenerManager listenerManager;

    /**
     * Set of typename changed to fire changed events for at commit and rollback.
     */
    private final Set<String> typesChanged = new HashSet<String>();

    public SeState currentVersionState;

    public SeObjectId initialStateId;

    public SeVersion defaultVersion;

    private ArcSdeVersionHandler versionHandler = ArcSdeVersionHandler.NONVERSIONED_HANDLER;

    /**
     * Creates a new ArcTransactionState object.
     *
     * @param listenerManager
     * @param arcSDEDataStore
     *            connection pool where to grab a connection and hold it while there's a transaction
     *            open (signaled by any use of {@link #getConnection()}
     */
    ArcTransactionState(ArcSDEDataStore dataStore, final FeatureListenerManager listenerManager) {
        this.dataStore = dataStore;
        this.listenerManager = listenerManager;
    }

    private void setupVersioningHandling(final String versionName) throws IOException {
        // create a versioned handler only if not already settled up, as this method
        // may be called for each layer inside a transaction
        if (versionHandler == ArcSdeVersionHandler.NONVERSIONED_HANDLER) {
            ISession session = getConnection();
            versionHandler = new TransactionVersionHandler(session, versionName);
        }
    }

    /**
     * @param versioName
     *            the name of the version to work against
     * @return
     * @throws IOException
     */
    public ArcSdeVersionHandler getVersionHandler(final boolean ftIsVersioned,
            final String versionName) throws IOException {
        if (ftIsVersioned) {
            setupVersioningHandling(versionName);
        }
        return versionHandler;
    }

    /**
     * Registers a feature change event over a feature type.
     * <p>
     * To be called by {@link TransactionFeatureWriter#write()} so this state can fire a changed
     * event at {@link #commit()} and {@link #rollback()}.
     * </p>
     *
     * @param typeName
     *            the type name of the feature changed (inserted/removed/modified).
     */
    public void addChange(final String typeName) {
        typesChanged.add(typeName);
    }

    /**
     * Commits the transaction and returns the connection to the pool. A new one will be grabbed
     * when needed.
     * <p>
     * Preconditions:
     * <ul>
     * <li>{@link #setTransaction(Transaction)} already called with non <code>null</code> argument.
     * <li>
     * </ul>
     * </p>
     */
    public void commit() throws IOException {
        failIfClosed();
        final ISession session = this.getConnection();

        final Command<Void> commitCommand = new Command<Void>() {
            @Override
            public Void execute(ISession session, SeConnection connection) throws SeException,
                    IOException {

                try {
                    if (currentVersionState != null) {
                        SeObjectId parentStateId = initialStateId;
                        // Change the version's state pointer to the last edit state.
                        defaultVersion.changeState(currentVersionState.getId());
                        // Trim the state tree.
                        currentVersionState.trimTree(parentStateId, currentVersionState.getId());
                    }
                } catch (SeException se) {
                    LOGGER.log(Level.WARNING, se.getMessage(), se);
                    close();
                    throw se;
                }
                return null;
            }
        };

        try {
            session.issue(commitCommand);
            fireChanges(true);
            versionHandler.commitEditState();
        } catch (IOException e) {
            versionHandler.rollbackEditState();
            throw e;
        }
    }

    /**
     *
     */
    public void rollback() throws IOException {
        failIfClosed();
        try {
            versionHandler.rollbackEditState();
            // fire changes in the calling thread
            fireChanges(false);
        } catch (IOException se) {
            // release resources
            close();
            LOGGER.log(Level.WARNING, se.getMessage(), se);
            throw se;
        }
    }

    /**
     * Fires the per typename changes registered through {@link #addChange(String)} and clears the
     * changes cache.
     */
    private void fireChanges(final boolean commit) {
        for (String typeName : typesChanged) {
            listenerManager.fireChanged(typeName, transaction, commit);
        }
        typesChanged.clear();
    }

    /**
     *
     */
    public void addAuthorization(String authId) {
        // intentionally blank
    }

    /**
     * @see Transaction.State#setTransaction(Transaction)
     * @param transaction
     *            transaction information, <code>null</code> signals this state lifecycle end.
     * @throws IllegalStateException
     *             if close() is called while a transaction is in progress
     */
    public void setTransaction(final Transaction transaction) {
        if (Transaction.AUTO_COMMIT.equals(transaction)) {
            throw new IllegalArgumentException("Cannot use Transaction.AUTO_COMMIT here");
        }
        if (transaction == null) {
            // this is a call to free resources (ugly, but that's what the API
            // says)
            close();
        } else if (this.transaction != null) {
            // assert this assumption
            throw new IllegalStateException(
                    "Once a transaction is set, it is "
                            + "illegal to call Transaction.State.setTransaction with anything other than null: "
                            + transaction);
        }

        this.transaction = transaction;
    }

    /**
     * If this state has been closed throws an unchecked exception as its clearly a broken workflow.
     *
     * @throws IllegalStateException
     *             if the transaction state has been closed.
     */
    private void failIfClosed() throws IllegalStateException {
        if (dataStore == null) {
            throw new IllegalStateException("This transaction state has already been closed");
        }
    }

    /**
     * Releases resources and invalidates this state (signaled by setting the connection to null)
     */
    private void close() {
        if (dataStore == null) {
            return;
        }
        dataStore = null;
    }

    /**
     * Used only within the package to provide access to a single connection on which this
     * transaction is being conducted.
     *
     * @return connection
     * @throws IOException
     */
    ISession getConnection() throws IOException {
        failIfClosed();
        // the pool is keeping track of connection according to transaction for us
        return dataStore.getSession(transaction);
    }

    public Transaction getTransaction() {
        return transaction;
    }
}
TOP

Related Classes of org.geotools.arcsde.data.ArcTransactionState

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.