/*
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999 Bull S.A.
 * Contact: jonas-team@objectweb.org
 * 
 * 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; either
 * version 2.1 of the License, or any later version.
 * 
 * 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.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * Initial developer(s): Laurent Chauvirey, Frederic Maistre, Nicolas Tachker
 * Contributor(s): 
 * Philippe Durieux
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

package org.objectweb.jonas_jms;

import java.io.Serializable;
import javax.jms.BytesMessage;
import javax.jms.JMSException;
import javax.jms.MapMessage;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.ObjectMessage;
import javax.jms.Session;
import javax.jms.StreamMessage;
import javax.jms.TextMessage;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;

public abstract class JSession implements Session, XAResource {

    protected XAResource xares = null;	// The underlaying XAResource 
    protected boolean txover = true;
    protected Transaction currtx = null;
    protected boolean closed = false;
    protected JConnection jconn;
    protected static TransactionManager tm = null;

    /**
     * Constructor
     */
    public JSession(JConnection jconn) {
	this.jconn = jconn;
	if (tm == null) {
	    tm = JmsManagerImpl.getTransactionManager();
	}
    }

    // -----------------------------------------------------------------------
    // Internal Methods
    // -----------------------------------------------------------------------

    /**
     * Get the underlaying MOM Session.
     */
    abstract protected Session getMOMSession() throws JMSException;

    abstract protected void MOMSessionClose();

    /**
     * 
     */
    protected void PhysicalClose() {
	MOMSessionClose();
    }

    // -----------------------------------------------------------------------
    // Session Implementation
    // -----------------------------------------------------------------------

    /**
     * 
     */
    public void close() throws JMSException {
	TraceJms.debug("JSession: close");
	closed = true;
	if (txover) {
	    PhysicalClose();
	} else {
	    // delist XAResource now, that will lead to an XA-end call
	    if (currtx == null) {
		TraceJms.error("JSession close: should be in a tx");
	    } else {
		try {
		    currtx.delistResource(this, XAResource.TMSUCCESS);
		} catch (SystemException e) {
		    TraceJms.error("JSession close: cannot delist session:"+e);
		    throw new JMSException(e.toString());
		}
	    }
	}
    }

    /**
     * 
     */
    public void commit() throws JMSException {
	TraceJms.debug("JSession: commit");
	throw new JMSException("JSession: commit Operation Not Allowed");
    }

    /**
     * 
     */
    public BytesMessage createBytesMessage() throws JMSException {
	TraceJms.debug("JSession: createBytesMessage");
	return getMOMSession().createBytesMessage();
    }

    /**
     * 
     */
    public MapMessage createMapMessage() throws JMSException {
	TraceJms.debug("JSession: createMapMessage");
	return getMOMSession().createMapMessage();
    }

    /**
     * 
     */
    public Message createMessage() throws JMSException {
	TraceJms.debug("JSession: createMessage");
	return getMOMSession().createMessage();
    }

    /**
     * 
     */
    public ObjectMessage createObjectMessage() throws JMSException {
	TraceJms.debug("JSession: createObjectMessage");
	return getMOMSession().createObjectMessage();
    }

    /**
     * 
     */
    public ObjectMessage createObjectMessage(Serializable object) throws JMSException {
	TraceJms.debug("JSession: createObjectMessage");
	return getMOMSession().createObjectMessage(object);
    }

    /**
     * 
     */
    public StreamMessage createStreamMessage() throws JMSException {
	TraceJms.debug("JSession: createStreamMessage");
	return getMOMSession().createStreamMessage();
    }

    /**
     * 
     */
    public TextMessage createTextMessage() throws JMSException {
	TraceJms.debug("JSession: createTextMessage");
	return getMOMSession().createTextMessage();
    }

    /**
     * 
     */
    public TextMessage createTextMessage(String text) throws JMSException {
	TraceJms.debug("JSession: createTextMessage");
	return getMOMSession().createTextMessage(text);
    }

    /**
     * 
     */
    public MessageListener getMessageListener() throws JMSException {
	TraceJms.debug("JSession: getMessageListener");
	return getMOMSession().getMessageListener();
    }
    
    /**
     * 
     */
    public boolean getTransacted() throws JMSException {
	TraceJms.debug("JSession: getTransacted");
	return getMOMSession().getTransacted();
    }

    /**
     * 
     */
    public void recover() throws JMSException {
	TraceJms.debug("JSession: recover");
	throw new JMSException("JSession: recover Operation Not Allowed");
    }

    /**
     * 
     */
    public void rollback() throws JMSException {
	TraceJms.debug("JSession: rollback");
	throw new JMSException("JSession: rollback Operation Not Allowed");
    }

    /**
     * 
     */
    public void run() {
	TraceJms.debug("JSession: run");
	try {
	    getMOMSession().run();
	} catch (JMSException e) {
	    TraceJms.error("JSession: run "+e);
	}
    }

    /**
     * 
     */
    public void setMessageListener(MessageListener listener) throws JMSException {
	TraceJms.debug("JSession: setMessageListener");
	getMOMSession().setMessageListener(listener);
    }

    // -----------------------------------------------------------------------
    // XAResource Implementation
    // -----------------------------------------------------------------------

    /**
     *
     */	
    public void commit(Xid xid, boolean onePhase) throws XAException {
	TraceJms.debug("JSession: commit");
	TraceJms.debug("Xid = "+xid);
	xares.commit(xid, onePhase);
	if (txover) {
	    TraceJms.error("JSession: commit tx over ???");
	}
	txover = true;
	if (closed) {
	    PhysicalClose();
	}
    }

    /**
     *
     */	
    public void end(Xid xid, int flags) throws XAException {
	TraceJms.debug("JSession: end");
	TraceJms.debug("Xid = "+xid);
	if (txover) {
	    TraceJms.error("JSession: end tx over ???");
	}
	xares.end(xid, flags);
    }

    /**
     *
     */	
    public void forget(Xid xid) throws XAException {
	TraceJms.debug("JSession: forget");
	TraceJms.debug("Xid = "+xid);
	xares.forget(xid);
    }

    /**
     *
     */	
    public int getTransactionTimeout() throws XAException {
	TraceJms.debug("JSession: getTransactionTimeout");
	return xares.getTransactionTimeout();
    }

    /**
     *
     */	
    public boolean isSameRM(XAResource xar) throws XAException {
	TraceJms.debug("JSession: isSameRM");
	return xares.isSameRM(xar);
    }

    /**
     *
     */	
    public int prepare(Xid xid) throws XAException {
	TraceJms.debug("JSession: prepare");
	TraceJms.debug("Xid = "+xid);
	return xares.prepare(xid);
    }

    /**
     *
     */	
    public Xid[] recover(int flag) throws XAException {
	TraceJms.debug("JSession: recover");
	return xares.recover(flag);
    }

    /**
     *
     */	
    public void rollback(Xid xid) throws XAException {
	TraceJms.debug("JSession: rollback");
	TraceJms.debug("Xid = "+xid);
	xares.rollback(xid);
	if (txover) {
	    TraceJms.error("JSession: rollback tx over ???");
	}
	txover = true;
	if (closed) {
	    PhysicalClose();
	}
    }

    /**
     *
     */	
    public boolean setTransactionTimeout(int seconds) throws XAException {
	TraceJms.debug("JSession: setTransactionTimeout");
	return xares.setTransactionTimeout(seconds);
    }

    /**
     *
     */	
    public void start(Xid xid, int flags) throws XAException {
	TraceJms.debug("JSession: start");
	TraceJms.debug("Xid = "+xid);
	txover = false;
	xares.start(xid, flags);
    }


}

