/*
 * 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
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

package org.objectweb.jonas_jms;

import java.io.Serializable;
import java.util.Iterator;
import java.util.LinkedList;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.Referenceable;

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.JMSSecurityException;
import javax.jms.XAConnectionFactory;

import org.objectweb.jonas_jms.api.JmsManager;

import org.objectweb.util.monolog.api.BasicLevel;

/**
 * @author Laurent Chauvirey, Frederic Maistre, Nicolas Tachker
 * Contributor(s):
 * Philippe Durieux
 * Jeff Mesnil connection anonymous
 * Philippe Coq
 */

public class JConnectionFactory implements  ConnectionFactory, Referenceable, Serializable {

    protected JmsManager jms;
    protected String name;
    protected XAConnectionFactory xacf;

    private LinkedList connectionpool = new LinkedList();

    /**
     * Constructor.
     * @param name - ConnectionFactory name
     */
    public JConnectionFactory(String name) {
        this.name = name;
        jms = JmsManagerImpl.getJmsManager();
        xacf = jms.getXAConnectionFactory();
    }

    /**
     * Empty Constructor called by subclasses.
     */
    protected JConnectionFactory() {
    }


    // -----------------------------------------------------------------------
    // ConnectionFactory implementation
    // -----------------------------------------------------------------------

    /**
     * Create a connection for an anonymous user.
     *
     * @return a newly created connection.
     * @throws JMSException - if JMS Provider fails to create Connection
     * due to some internal error. required resources for a Connection.
     * @throws JMSSecurityException - if client authentication fails due to
     * invalid user name or password.
     */
    public Connection createConnection() throws JMSException {
        TraceJms.logger.log(BasicLevel.DEBUG,"");
        JConnection c = (JConnection) getJConnection();
        if (c == null) {
            c = new JConnection(this, xacf);
        }
        return (Connection) c;
    }

    /**
     * Create a connection with specified user identity.
     * The connection is created in stopped mode. No messages will
     * be delivered until Connection.start method is explicitly called.
     *
     * @param userName - the caller's user name
     * @param password - the caller's password
     *
     * @throws JMSException - if JMS Provider fails to create Connection
     * due to some internal error. required resources for a Connection.
     * @throws JMSSecurityException - if client authentication fails due to
     * invalid user name or password.
     */
    public Connection createConnection(String userName, String password) throws JMSException {
        TraceJms.logger.log(BasicLevel.DEBUG,"");
        JConnection c = (JConnection) getJConnection(userName);
        if (c == null) {
            c = new JConnection(this, xacf, userName, password);
        }
        return (Connection) c;
    }

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

    /**
     * Free a Connection and return it to the pool
     * @param con - Connection to be freed
     */
    public void freeJConnection(JConnection con) {
        TraceJms.logger.log(BasicLevel.DEBUG,  "");
        synchronized (connectionpool) {
            connectionpool.addLast(con);
        }
    }

    void cleanPool() {
        TraceJms.logger.log(BasicLevel.DEBUG,  "");
        JConnection con = null;
        synchronized (connectionpool) {
            Iterator i = connectionpool.iterator();
            while (i.hasNext()) {
                con = (JConnection) i.next();
                try {
                    con.finalClose();
                } catch (JMSException e) {
                }
            }
        }
    }

    /**
     * Get a Connection from the pool for an anonymous user
     *
     * @return a Connection for an anonymous user
     */
    public JConnection getJConnection() {
        return getJConnection(JConnection.INTERNAL_USER_NAME);
    }

    /**
     * Get a Connection from the pool for the specified user
     *
     * @param user User wanting a connection
     * @return Connection from the pool for the specified user
     */
    public JConnection getJConnection(String user) {
        TraceJms.logger.log(BasicLevel.DEBUG,  "");
        JConnection con = null;
        synchronized (connectionpool) {
            Iterator i = connectionpool.iterator();
            while (i.hasNext()) {
                con = (JConnection) i.next();
                if (con.getUser().equals(user)) {
                    i.remove();
                    break;
                }
            }
        }
        return con;
    }



    // -----------------------------------------------------------------------
    // Referenceable implementation
    // -----------------------------------------------------------------------

    public Reference getReference() throws NamingException {
        TraceJms.logger.log(BasicLevel.DEBUG,  "");
        return new Reference(getClass().getName(), "org.objectweb.jonas_jms.JObjectFactory", null);
    }


}
