/* JFox, the OpenSource J2EE Application Server
 *
 * Copyright (C) 2002 huihoo.com
 * Distributable under GNU LGPL license
 * See the GNU Lesser General Public License for more details.
 */

package org.jfox.jdbc.xa;

import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.XAConnection;
import javax.sql.XADataSource;

import org.huihoo.jfox.logging.Logger;
import org.huihoo.jfox.pool.ObjectFactory;
import org.huihoo.jfox.pool.PoolableObject;

/**
* 利用XADataSource,负责生成 XAConnection,并负责 enlist 其 XAResource
 *
 * @author <a href="mailto:young_yy@hotmail.com">Young Yang</a>
 */

public class XAConnectionFactory implements ObjectFactory {
  private XADataSource xads = null;

  private String url = "";
  private String user = "";
  private String password = "";
  private int transactionIsolation = Connection.TRANSACTION_READ_COMMITTED;

  private XAConnectionPool pool = null;

  private static Logger logger = Logger.getLogger(XAConnectionFactory.class.getName());

  public XAConnectionFactory(String url,String user, String password){
    this.url = url;
    this.user = user;
    this.password = password;
    try {
//      xads = XADataSourceFactory.getXADataSource(url);
      xads = createXADataDataSource();
    }
    catch(Exception e) {
      e.printStackTrace();
      throw new RuntimeException("create xadatasource error",e);
    }
  }

  String getUser() {
    return user;
  }

  String getPassword() {
    return password;
  }

  String getDbURL(){
    return url;
  }

  public Class getObjectClass() {
    return XAConnection.class;
  }

  public PoolableObject makeObject() throws Exception {
    logger.debug("make object");
    PoolableXAConnection poolxaconn = new PoolableXAConnection(getXAConnection(user,password),transactionIsolation,url,user,password);
    poolxaconn.setPool(pool);
    return poolxaconn;
  }

  /**
   * 用不同池的用户名和密码连接,不返回给池,设置 notPoolable
   */
  PoolableObject makeObject(String user, String password) throws Exception {
    logger.debug("make object by " + user + " & " + password);
    PoolableXAConnection pxaconn = new PoolableXAConnection(getXAConnection(user,password),transactionIsolation,url,user,password);
    pxaconn.notPoolable();
    return pxaconn;
  }

  public void destroyObject(PoolableObject object) throws Exception {
    logger.debug("destroyObject " + object);
    PoolableXAConnection poolXaConn = (PoolableXAConnection)object;
    poolXaConn.close();
    poolXaConn = null;
  }

  /**
   * isMarkedError: 在操作过程中,该 XAConnection 已经出错了
   * isPoolable: 使用特别的 getXAConnection(user,password) 创建,不进入池
   * @param object
   * @return
   */
  public boolean validateObject(PoolableObject object) {
    boolean isAvailable = PoolableXAConnection.class.isAssignableFrom(object.getClass()) && object.isAvailable();
    logger.debug("validate object " + object + " " + isAvailable);
    return isAvailable;
  }

  XAConnection getXAConnection(String user, String password) throws SQLException {
    return xads.getXAConnection(user,password);
  }

  int getLoginTimeout() throws SQLException {
    return xads.getLoginTimeout();
  }

  void setLoginTimeout(int seconds) throws SQLException {
    xads.setLoginTimeout(seconds);
  }

  PrintWriter getLogWriter() throws SQLException {
    return xads.getLogWriter();
  }

  void setLogWriter(PrintWriter out) throws SQLException {
    xads.setLogWriter(out);
  }

  void setPool(XAConnectionPool pool){
    this.pool = pool;
  }

  void setTransactionIsolation(int level) throws SQLException {
    transactionIsolation = level;
  }

  private XADataSource createXADataDataSource() throws Exception {
    String protocol = getProtocol();
    ClassLoader loader = Thread.currentThread().getContextClassLoader();
    String className = this.getClass().getPackage().getName() + "." + protocol.toLowerCase() + "." + protocol.toUpperCase() + "XADataSourceFactory";
    XADataSourceFactory xadsf = (XADataSourceFactory)loader.loadClass(className).newInstance();
    return xadsf.newXADataSource(url);
  }

  private String getProtocol(){
    int index1 = url.indexOf(":");
    int index2 = url.indexOf(":", index1+1);
    String protocol = url.substring(index1+1,index2);
    return protocol;
  }

  public static void main(String[] args) {

  }
}