/* JFox, the OpenSource J2EE Application Server
 *
 * Distributable under GNU LGPL license by gun.org
 * more details please visit http://www.huihoo.org/jfox
 */

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.jfox.framework.logger.Logger;
import org.jfox.pool.ObjectFactory;
import org.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 = this.getClass().getClassLoader();
        String className = this.getClass().getPackage().getName() + "." + protocol.toUpperCase() + "XADataSource";
        AbstractXADataSource xadsf = (AbstractXADataSource) loader.loadClass(className).getConstructor(new Class[]{String.class}).newInstance(new Object[]{url});
        return xadsf;
    }

    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) {

    }
}
