/*
 * $Header: /home/cvspublic/jakarta-slide/proposals/tamino/src/store/org/apache/slide/store/tamino/datastore/XConnection.java,v 1.4 2005/01/19 15:19:01 pnever Exp $
 * $Revision: 1.4 $
 * $Date: 2005/01/19 15:19:01 $
 *
 * ====================================================================
 *
 * Copyright 1999-2004 The Apache Software Foundation.
 *
 * Licensed 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.slide.store.tamino.datastore;

import com.softwareag.common.instrumentation.logging.Level;
import com.softwareag.common.instrumentation.logging.Logger;
import com.softwareag.common.instrumentation.logging.LoggerFactory;
import com.softwareag.common.instrumentation.logging.LoggerUtil;
import com.softwareag.tamino.db.api.accessor.TAccessLocation;
import com.softwareag.tamino.db.api.accessor.TAccessorException;
import com.softwareag.tamino.db.api.accessor.TNonXMLObjectAccessor;
import com.softwareag.tamino.db.api.accessor.TStreamAccessor;
import com.softwareag.tamino.db.api.accessor.TXMLObjectAccessor;
import com.softwareag.tamino.db.api.common.TException;
import com.softwareag.tamino.db.api.connection.TConnection;
import com.softwareag.tamino.db.api.connection.TConnectionCloseException;
import com.softwareag.tamino.db.api.connection.TIsolationLevel;
import com.softwareag.tamino.db.api.connection.TLocalTransaction;
import com.softwareag.tamino.db.api.connection.TLockwaitMode;
import com.softwareag.tamino.db.api.objectModel.TXMLObjectModel;
import com.softwareag.tamino.db.api.objectModel.jdom.TJDOMObjectModel;
import org.apache.slide.store.tamino.common.XDatastoreException;
import org.apache.slide.util.ClassName;
import org.apache.slide.util.XAssertionFailed;
import org.apache.slide.common.Domain;

/**
 * XConnection wraps a connection to tamino. It provides methods to get
 * tamino accessors. <p>
 * An XConnection may be used by several stores to avoid physical 2 phase
 * commit if (1) the stores are running in the same thread (same transaction),
 * (2) the same taminodb is addressed and (3) the same tamino user is used.
 * The slide transaction manager guarantees, that the calling sequence is
 * correct.
 *
 * (23.11.2002 wam) LOCKWAIT true for READ, false in transaction mode
 *
 * @author martin.wallmer@softwareag.com
 *
 * @version $Revision: 1.4 $
 *
 */
public class XConnection {
    
    private static final String LOGNAME = LoggerUtil.getThisClassName();
    private static final String CLASSNAME = new ClassName(LOGNAME).getPlainName();
    private static Logger logger = LoggerFactory.getLogger(LOGNAME);
    
    private TConnection tConnection;
    private TLocalTransaction tTransaction;
    
    /** the pool id */
    private XConnectionKey dbKey;
    
    
    /** set to false when closed */
    private boolean isActive = true;
    
    /**
     * constructs a new XConnection. Only called from XConnectionPool.
     */
    public XConnection (TConnection tConnection)   {
        if (logger.isLoggable (Level.FINE) )
            logger.entering (CLASSNAME, "<init>", new Object[] {tConnection} );
        
        this.tConnection = tConnection;
        this.tConnection.setLockwaitMode (TLockwaitMode.YES);
        
        if (logger.isLoggable(Level.FINE) )
            logger.exiting (CLASSNAME, "<init>" );
    }
    
    /**
     * Sets this connections id within the connection pool
     *
     * @param    poolId              the connection key
     *
     */
    void setPoolId (XConnectionKey poolId) {
        this.dbKey = poolId;
    }
    
    
    XConnectionKey getPoolId () {
        return dbKey;
    }
    
    /**
     * Closes an XConnection. If this xConnection is used by more than one
     * dbSession, the first one will close and remove from connection pool,
     * the next calls are ignored.
     *
     * @throws   XDatastoreException
     *
     */
    public void close () throws XDatastoreException {
        if (tTransaction != null) {
            throw new XAssertionFailed ("use commit or rollback before closing connection " + toString());
        }
        if (isActive) {
            isActive = false;
            XConnectionPool.getInstance().removeXConnection (dbKey);
            try {
                tConnection.close();
                // debug only
                // ConnectionChecker.remove (this);
                
                if ("true".equalsIgnoreCase(Domain.getParameter("debug_tamino", "false"))) {
                    System.out.println("   === ["+Thread.currentThread().getName()+"] '''''CLOSE  "+dbKey);
                }
            } catch (TConnectionCloseException e) {
                throw new XDatastoreException (e);
            }
        }
    }
    
    /**
     * Returns a newNonXMLObjectAccessor for a specific location
     *
     * @param    location            a  TAccessLocation
     *
     * @return   a TNonXMLObjectAccessor
     *
     */
    public TNonXMLObjectAccessor newNonXMLObjectAccessor (TAccessLocation location) {
        ensureActive();
        return tConnection.newNonXMLObjectAccessor (location);
    }
    
    /**
     * Method newStreamAccessor
     *
     * @param    collection          a  String
     *
     * @return   a TStreamAccessor
     *
     */
    public TStreamAccessor newStreamAccessor (String collection) {
        return newStreamAccessor
            (TAccessLocation.newInstance (collection));
    }
    
    /**
     * returns a newStreamAccessor for a specific location
     *
     * @param    location            a  TAccessLocation
     *
     * @return   a TStreamAccessor
     *
     */
    private TStreamAccessor newStreamAccessor (TAccessLocation location) {
        ensureActive();
        return tConnection.newStreamAccessor (location);
    }
    
    
    /**
     * Method newXMLObjectAccessor
     *
     * @param    collection          a  String
     * @param    objectModel         a  TXMLObjectModel
     *
     * @return   a TXMLObjectAccessor
     *
     */
    public TXMLObjectAccessor newXMLObjectAccessor (String collection,
                                                    TXMLObjectModel objectModel) {
        return newXMLObjectAccessor (
            TAccessLocation.newInstance (collection), objectModel);
    }
    
    public TXMLObjectAccessor newXMLJObjectAccessor (String collection) {
        return newXMLObjectAccessor (collection, TJDOMObjectModel.getInstance());
    }
    
    /**
     * returns a newXMLObjectAccessor for a specific object model and location!
     *
     * @param    location            a  TAccessLocation
     * @param    objectModel         a  TXMLObjectModel
     *
     * @return   a TXMLObjectAccessor
     *
     */
    private TXMLObjectAccessor newXMLObjectAccessor (TAccessLocation location,
                                                     TXMLObjectModel objectModel) {
        ensureActive();
        return tConnection.newXMLObjectAccessor (location, objectModel);
    }
    
    public void ensureActive() {
        if (!isActive) {
            // System.out.println (this);
            throw new IllegalStateException ("connection already closed");
        }
    }
    
    /**
     * Starts a transaction for this connection. If already done, the call is
     * ignored.
     *
     * @throws   TException
     *
     */
    public void startTransactionIfNecessary () throws TException {
        ensureActive();
        if (! tConnection.usesLocalTransactionMode()) {
            tConnection.setIsolationLevel (TIsolationLevel.SHARED);
            tConnection.setLockwaitMode   (TLockwaitMode.YES);
            // tConnection.setLockwaitMode   (TLockwaitMode.NO);
            tTransaction = tConnection.useLocalTransactionMode();
            // REMOVE
            // System.out.println ("opened transaction " + tTransaction.toString());
        }
    }
    
    /**
     * Commits this transaction. If more than one dbSession share this
     * connection, the commit is done for the first call, the next calls are
     * ignored.
     *
     * @throws   TException
     *
     */
    public void commit () throws TException {
        if (isActive) {
            
            if (tTransaction != null) {
                tTransaction.commit();
                tConnection.useAutoCommitMode();
                
                // System.out.println ("committed transaction " + tTransaction.toString());
                tTransaction = null;
            }
        }
    }
    
    /**
     * Rollback this transaction. If more than one dbSession share this
     * connection, the commit is done for the first call, the next calls are
     * ignored.
     *
     * @throws   TException
     *
     */
    public void rollback() throws TException {
        if (isActive) {
            if (tTransaction != null) {
                tTransaction.rollback();
                tConnection.useAutoCommitMode();
                
                // System.out.println ("rolled back transaction " + tTransaction.toString());
                tTransaction = null;
            }
        }
    }
    
    /**
     * Return the version of the Tamino server this connection points to
     *
     * @return   a String
     *
     * @throws   TAccessorException
     *
     */
    String getServerVersion () throws TAccessorException {
        ensureActive();
        return tConnection.newSystemAccessor().getServerVersion();
    }
    
    
    
    /**
     * Return the wrapped Tconnection
     *
     * @return   a TConnection
     *
     *
     */
    public TConnection getTConnection() {
        return tConnection;
    }
    
    public boolean isActive () {
        return isActive;
    }
    
    public String toString () {
        return
            super.toString() + "; active: " + isActive;
    }
}



