/*
 * JORAM: Java(TM) Open Reliable Asynchronous Messaging
 * Copyright (C) 2004 - 2022 ScalAgent Distributed Technologies
 *
 * 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.
 */
package org.ow2.joram.jakarta.connector;

import jakarta.jms.IllegalStateException;
import jakarta.jms.JMSException;
import jakarta.jms.JMSSecurityException;
import jakarta.jms.XAConnection;
import jakarta.jms.XAConnectionFactory;
import jakarta.jms.XATopicConnectionFactory;
import javax.naming.Reference;
import javax.naming.StringRefAddr;
import jakarta.resource.ResourceException;
import jakarta.resource.spi.CommException;
import jakarta.resource.spi.ConnectionManager;
import jakarta.resource.spi.ConnectionRequestInfo;
import jakarta.resource.spi.SecurityException;

import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;
import org.ow2.joram.jakarta.jms.admin.AbstractConnectionFactory;
import org.ow2.joram.jakarta.jms.local.LocalConnectionFactory;
import org.ow2.joram.jakarta.jms.tcp.TcpConnectionFactory;

import fr.dyade.aaa.common.Debug;

/**
 * A <code>ManagedTopicConnectionFactoryImpl</code> instance manages
 * PubSub outbound connectivity to a given JORAM server.
 */
public class ManagedTopicConnectionFactoryImpl extends ManagedConnectionFactoryImpl {
  private static final long serialVersionUID = 1L;
  private static final Logger logger = Debug.getLogger(ManagedTopicConnectionFactoryImpl.class.getName());

  /**
   * Constructs a <code>ManagedTopicConnectionFactoryImpl</code> instance.
   */
  public ManagedTopicConnectionFactoryImpl() {}

  /**
   * Method called by an application server (managed case) for creating an
   * <code>OutboundTopicConnectionFactory</code> instance.
   *
   * @param cxManager  Application server's connections pooling manager.
   *
   * @exception ResourceException  Never thrown.
   */
  public Object createConnectionFactory(ConnectionManager cxManager) throws ResourceException {
    if (logger.isLoggable(BasicLevel.DEBUG))
      logger.log(BasicLevel.DEBUG, this + " createConnectionFactory(" + cxManager + ")");

    return new OutboundTopicConnectionFactory(this, cxManager);
  }

  /**
   * Method called in the non managed case for creating an
   * <code>OutboundTopicConnectionFactory</code> instance.
   *
   * @exception ResourceException  Never thrown.
   */
  public Object createConnectionFactory() throws ResourceException {
    if (logger.isLoggable(BasicLevel.DEBUG))
      logger.log(BasicLevel.DEBUG, this + " createConnectionFactory()");

    OutboundConnectionFactory factory =
      new OutboundTopicConnectionFactory(this, DefaultConnectionManager.getRef());

    Reference ref = new Reference(factory.getClass().getName(), "org.ow2.joram.jakarta.connector.ObjectFactoryImpl", null);
    ref.add(new StringRefAddr("hostName", getHostName()));
    ref.add(new StringRefAddr("serverPort", "" + getServerPort()));
    ref.add(new StringRefAddr("userName", getUserName()));
    ref.add(new StringRefAddr("password", getPassword()));
    ref.add(new StringRefAddr("identityClass", getIdentityClass()));

    factory.setReference(ref);
    return factory;
  }

  @Override
  protected XAConnectionFactory createFactory(ConnectionRequestInfo cxRequest) throws ResourceException {
  	XAConnectionFactory factory = null;

  	String hostName = getHostName();
  	int serverPort = getServerPort();
//  	if (isCollocated()) {
//  		hostName = "localhost";
//  		serverPort = -1;
//  	}

  	if (isCollocated()) {
  	  factory = LocalConnectionFactory.create();
  	} else {
  	  factory = TcpConnectionFactory.create(hostName, serverPort);
  	}

  	if (ra == null) {
      setResourceAdapter(new JoramAdapter());
    }
  	((AbstractConnectionFactory) factory).setCnxJMXBeanBaseName(ra.jmxRootName + "#"+ra.getName());
  	
  	if (logger.isLoggable(BasicLevel.DEBUG))
  		logger.log(BasicLevel.DEBUG, this + " createFactory factory = " + factory);
  	
  	return factory;
  }

  @Override
  protected XAConnection createXAConnection(XAConnectionFactory factory, String userName, String password) throws ResourceException {
  	XAConnection cnx = null;
 	 try {
 		 if (factory instanceof XATopicConnectionFactory)
 			 cnx = ((XATopicConnectionFactory) factory).createXATopicConnection(userName, password);
 		 else
 			 cnx = factory.createXAConnection(userName, password);
      if (logger.isLoggable(BasicLevel.DEBUG))
        logger.log(BasicLevel.DEBUG, this + " createXAConnection cnx = " + cnx);
    } catch (IllegalStateException exc) {
      if (out != null)
        out.print("Could not access the JORAM server: " + exc);
      throw new CommException("Could not access the JORAM server: " + exc);
    } catch (JMSSecurityException exc) {
      if (out != null)
        out.print("Invalid user identification: " + exc);
      throw new SecurityException("Invalid user identification: " + exc);
    } catch (JMSException exc) {
      if (out != null)
        out.print("Failed connecting process: " + exc);
      throw new ResourceException("Failed connecting process: " + exc);
    }
    return cnx;
  }

  /** Returns a code depending on the managed factory configuration. */
  public int hashCode() {
  	return ("PubSub:"
  			+ getHostName()
  			+ ":"
  			+ getServerPort()
  			+ "-"
  			+ getUserName()).hashCode();
  }

  /** Compares managed factories according to their configuration. */
  public boolean equals(Object o) {
    if (! (o instanceof ManagedTopicConnectionFactoryImpl))
      return false;

    ManagedConnectionFactoryImpl other = (ManagedConnectionFactoryImpl) o;
    return super.equals(o);
  }
}
