org.kchine.rpf.db.DBLayer.java Source code

Java tutorial

Introduction

Here is the source code for org.kchine.rpf.db.DBLayer.java

Source

/*
 * Biocep: R-based Platform for Computational e-Science.
 *  
 * Copyright (C) 2007-2009 Karim Chine - karim.chine@m4x.org
 *  
 * Copyright (C) 2007 EMBL-EBI-Microarray Informatics
 *  
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.kchine.rpf.db;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.URL;
import java.net.URLClassLoader;
import java.rmi.AccessException;
import java.rmi.AlreadyBoundException;
import java.rmi.NotBoundException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.StringTokenizer;
import java.util.Vector;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import org.apache.commons.logging.Log;
import org.kchine.rpf.LookUpInterrupted;
import org.kchine.rpf.LookUpTimeout;
import org.kchine.rpf.PoolUtils;
import org.kchine.rpf.RPFSessionInfo;
import org.neilja.net.interruptiblermi.InterruptibleRMIThreadFactory;

import static org.kchine.rpf.PoolUtils.*;

/**
 * @author Karim Chine karim.chine@m4x.org
 */
public abstract class DBLayer implements DBLayerInterface {

    private Connection _connection;
    private ConnectionProvider _connectionProvider;
    private static final Log _log = org.apache.commons.logging.LogFactory.getLog(DBLayer.class);

    abstract void lock(Statement stmt) throws SQLException;

    abstract void unlock(Statement stmt) throws SQLException;

    abstract String sysdateFunctionName();

    abstract boolean isNoConnectionError(SQLException sqle);

    abstract boolean isConstraintViolationError(SQLException sqle);

    public DBLayer(Connection connection) {
        _connection = connection;
        if (_connection != null) {
            try {
                _connection.setAutoCommit(false);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void checkConnection() throws SQLException {
        if (_connection == null && _connectionProvider != null) {
            _connection = _connectionProvider.newConnection();
            try {
                _connection.setAutoCommit(false);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println("Connection Created Successfully");
        }
    }

    public void bind(String name, Remote obj, HashMap<String, Object> options)
            throws RemoteException, AlreadyBoundException, AccessException {

        Statement stmt = null;
        ResultSet rset = null;
        try {
            checkConnection();
            stmt = _connection.createStatement();
            lock(stmt);
            rset = stmt.executeQuery("select count(*) from SERVANTS where NAME='" + name + "'");
            rset.next();
            if (rset.getInt(1) > 0) {
                throw new AlreadyBoundException();
            }
        } catch (AlreadyBoundException abe) {
            try {
                if (stmt != null) {
                    unlock(stmt);
                    _connection.commit();
                }
            } catch (Exception e) {
                throw new RemoteException("", e);
            }
            throw abe;
        } catch (SQLException sqle) {
            if (isNoConnectionError(sqle) && canReconnect()) {
                bind(name, obj);
            } else {
                throw new RemoteException("", sqle);
            }
        } finally {
            if (rset != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", e);
                }
            if (stmt != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", e);
                }
        }

        stmt = null;
        String stub_hex = stubToHex(obj);
        try {
            stmt = _connection.createStatement();
            stmt.execute(
                    "Insert into SERVANTS (NAME,STUB_HEX,IN_USE,PING_FAILURES,REGISTER_TIME,PROCESS_ID,HOST_NAME,HOST_IP,OS,CODEBASE,JOB_ID,JOB_NAME,NOTIFY_EMAIL,NOTIFIED) "
                            + "values ('" + name + "','" + stub_hex + "',0,0," + sysdateFunctionName() + ",'"
                            + options.get("process.id") + "','" + options.get("host.name") + "','"
                            + options.get("host.ip") + "','" + options.get("os.name") + "',"
                            + (options.get("java.rmi.server.codebase") == null ? "NULL"
                                    : "'" + options.get("java.rmi.server.codebase") + "',")
                            + (options.get("job.id") == null ? "NULL" : "'" + options.get("job.id") + "'") + ","
                            + (options.get("job.name") == null ? "NULL" : "'" + options.get("job.name") + "'") + ","
                            + (options.get("notify.email") == null ? "NULL"
                                    : "'" + options.get("notify.email") + "'")
                            + ",0)");
        } catch (SQLException sqle) {
            sqle.printStackTrace();
            if (isConstraintViolationError(sqle))
                throw new AlreadyBoundException();
            else
                throw new RemoteException("", (sqle));
        } finally {
            try {
                if (stmt != null) {
                    unlock(stmt);
                    _connection.commit();
                }
            } catch (Exception e) {
                throw new RemoteException("", (e));
            }
            if (stmt != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
        }
    }

    public void bind(String name, Remote obj) throws RemoteException, AlreadyBoundException, AccessException {
        HashMap<String, Object> options = new HashMap<String, Object>();
        options.put("process.id", getProcessId());
        options.put("host.name", getHostName());
        options.put("host.ip", getHostIp());
        options.put("os.name", System.getProperty("os.name"));
        options.put("java.rmi.server.codebase", System.getProperty("java.rmi.server.codebase"));
        options.put("job.id", System.getProperty("job.id"));
        options.put("job.name", System.getProperty("job.name"));
        options.put("notify.email", System.getProperty("notify.email"));
        bind(name, obj, options);
    }

    public String[] list() throws RemoteException, AccessException {
        Vector<String> result = new Vector<String>();
        Statement stmt = null;
        ResultSet rset = null;
        try {
            checkConnection();
            stmt = _connection.createStatement();
            rset = stmt.executeQuery("select NAME from SERVANTS");
            while (rset.next()) {
                result.add(rset.getString(1));
            }
        } catch (SQLException sqle) {
            if (isNoConnectionError(sqle) && canReconnect()) {
                return list();
            } else {
                throw new RemoteException("", (sqle));
            }
        } finally {
            if (rset != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
            if (stmt != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
        }

        return result.toArray(new String[0]);

    }

    public Remote lookup(String name) throws RemoteException, NotBoundException, AccessException {
        Statement stmt = null;
        ResultSet rset = null;
        try {
            checkConnection();
            stmt = _connection.createStatement();
            rset = stmt.executeQuery("select STUB_HEX,CODEBASE from SERVANTS where NAME='" + name + "'");
            if (rset.next()) {

                final String stubHex = rset.getString(1);
                final String codeBaseStr = rset.getString(2);
                final ClassLoader cl = (codeBaseStr != null
                        ? new URLClassLoader(PoolUtils.getURLS(codeBaseStr), DBLayer.class.getClassLoader())
                        : DBLayer.class.getClassLoader());
                System.out.println("codeBaseStr ::" + codeBaseStr);

                final Object[] resultHolder = new Object[1];
                Runnable lookupRunnable = new Runnable() {
                    public void run() {
                        try {
                            resultHolder[0] = hexToStub(stubHex, cl);
                        } catch (Exception e) {
                            final boolean wasInterrupted = Thread.interrupted();
                            if (wasInterrupted) {
                                resultHolder[0] = new LookUpInterrupted();
                            } else {
                                resultHolder[0] = e;
                            }
                        }
                    }
                };

                Thread lookupThread = InterruptibleRMIThreadFactory.getInstance().newThread(lookupRunnable);
                lookupThread.start();

                long t1 = System.currentTimeMillis();
                while (resultHolder[0] == null) {
                    if ((System.currentTimeMillis() - t1) > PoolUtils.LOOKUP_TIMEOUT_MILLISEC) {
                        lookupThread.interrupt();
                        resultHolder[0] = new LookUpTimeout();
                        registerPingFailure(name);
                        break;
                    }
                    Thread.sleep(10);
                }

                if (resultHolder[0] instanceof Throwable) {
                    if (resultHolder[0] instanceof NotBoundException)
                        throw (NotBoundException) resultHolder[0];
                    else
                        throw (RemoteException) resultHolder[0];
                }

                return (Remote) resultHolder[0];

            } else {
                throw new NotBoundException();
            }
        } catch (NotBoundException nbe) {
            throw nbe;
        } catch (AccessException ae) {
            throw ae;
        } catch (LookUpTimeout lue) {
            throw lue;
        } catch (LookUpInterrupted lui) {
            throw lui;
        } catch (SQLException sqle) {
            if (isNoConnectionError(sqle) && canReconnect()) {
                return lookup(name);
            } else {
                throw new RemoteException("", (sqle));
            }
        } catch (Exception e) {
            throw new RemoteException("", (e));
        } finally {
            if (rset != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
            if (stmt != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
        }
    }

    public void rebind(String name, Remote obj, HashMap<String, Object> options)
            throws RemoteException, AccessException {
        Statement stmt = null;
        ResultSet rset = null;
        try {
            checkConnection();
            stmt = _connection.createStatement();
            lock(stmt);
            rset = stmt.executeQuery("select count(*) from SERVANTS where NAME='" + name + "'");
            rset.next();
            if (rset.getInt(1) > 0) {
                stmt.execute("DELETE FROM SERVANTS WHERE NAME='" + name + "'");
            }
        } catch (SQLException sqle) {
            if (isNoConnectionError(sqle) && canReconnect()) {
                rebind(name, obj);
            } else {
                throw new RemoteException("", (sqle));
            }
        } finally {
            if (rset != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
            if (stmt != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
        }

        stmt = null;
        String stub_hex = stubToHex(obj);

        try {

            stmt = _connection.createStatement();
            stmt.execute(
                    "Insert into SERVANTS (NAME,STUB_HEX,IN_USE,PING_FAILURES,REGISTER_TIME,PROCESS_ID,HOST_NAME,HOST_IP,OS,CODEBASE,JOB_ID,JOB_NAME,NOTIFY_EMAIL,NOTIFIED) "
                            + "values ('" + name + "','" + stub_hex + "',0,0," + sysdateFunctionName() + ",'"
                            + options.get("process.id") + "','" + options.get("host.name") + "','"
                            + options.get("host.ip") + "','" + options.get("os.name") + "',"
                            + (options.get("java.rmi.server.codebase") == null ? "NULL"
                                    : "'" + options.get("java.rmi.server.codebase") + "',")
                            + (options.get("job.id") == null ? "NULL" : "'" + options.get("job.id") + "'") + ","
                            + (options.get("job.name") == null ? "NULL" : "'" + options.get("job.name") + "'") + ","
                            + (options.get("notify.email") == null ? "NULL"
                                    : "'" + options.get("notify.email") + "'")
                            + ",0)");

        } catch (SQLException sqle) {
            throw new RemoteException("", (sqle));
        } finally {
            try {
                if (stmt != null) {
                    unlock(stmt);
                    _connection.commit();
                }
            } catch (Exception e) {
                throw new RemoteException("", (e));
            }
            if (stmt != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
        }
    }

    public void rebind(String name, Remote obj) throws RemoteException, AccessException {
        HashMap<String, Object> options = new HashMap<String, Object>();
        options.put("process.id", getProcessId());
        options.put("host.name", getHostName());
        options.put("host.ip", getHostIp());
        options.put("os.name", System.getProperty("os.name"));

        options.put("java.rmi.server.codebase", System.getProperty("java.rmi.server.codebase"));
        options.put("job.id", System.getProperty("job.id"));
        options.put("job.name", System.getProperty("job.name"));
        options.put("notify.email", System.getProperty("notify.email"));

        rebind(name, obj, options);
    }

    public void unbind(String name) throws RemoteException, NotBoundException, AccessException {

        Statement stmt = null;
        ResultSet rset = null;
        try {
            checkConnection();
            stmt = _connection.createStatement();
            lock(stmt);
            stmt.execute("DELETE FROM SERVANTS WHERE NAME='" + name + "'");
        } catch (SQLException sqle) {
            if (isNoConnectionError(sqle) && canReconnect()) {
                unbind(name);
            } else {
                throw new RemoteException("", (sqle));
            }
        } finally {
            try {
                if (stmt != null) {
                    unlock(stmt);
                    _connection.commit();
                }
            } catch (Exception e) {
                throw new RemoteException("", (e));
            }
            if (stmt != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
            if (rset != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
        }
    }

    public Vector<String> list(String[] prefixes) throws RemoteException, AccessException {
        Vector<String> result = new Vector<String>();
        Statement stmt = null;
        ResultSet rset = null;
        try {
            checkConnection();
            stmt = _connection.createStatement();

            String stmtStr = "select NAME from SERVANTS where IN_USE=0 AND PING_FAILURES<"
                    + PoolUtils.PING_FAILURES_NBR_MAX + " AND (NAME like '" + prefixes[0] + "%'";
            for (int i = 1; i < prefixes.length; ++i)
                stmtStr += " OR NAME like '" + prefixes[i] + "%'";
            stmtStr += ")";

            rset = stmt.executeQuery(stmtStr);

            while (rset.next()) {
                result.add(rset.getString(1));
            }
        } catch (SQLException sqle) {
            if (isNoConnectionError(sqle) && canReconnect()) {
                return list(prefixes);
            } else {
                throw new RemoteException("", (sqle));
            }
        } finally {
            if (rset != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
            if (stmt != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
        }
        return result;
    }

    public Vector<HashMap<String, Object>> listKillable() throws RemoteException, AccessException {
        return getTableData("SERVANTS", "PING_FAILURES>=" + PoolUtils.PING_FAILURES_NBR_MAX);
    }

    public Vector<HashMap<String, Object>> listKillable(String nodeIp, String nodePrefix)
            throws RemoteException, AccessException {
        return getTableData("SERVANTS", "PING_FAILURES>=" + PoolUtils.PING_FAILURES_NBR_MAX + " AND " + "HOST_IP='"
                + nodeIp + "' AND NAME like '" + nodePrefix + "%'");
    }

    public void lock() throws RemoteException, AccessException {
        Statement stmt = null;
        try {
            checkConnection();
            stmt = _connection.createStatement();
            lock(stmt);
        } catch (SQLException sqle) {
            if (isNoConnectionError(sqle) && canReconnect()) {
                lock();
            } else {
                throw new RemoteException("", (sqle));
            }
        } finally {
            if (stmt != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
        }
    }

    public void unlock() throws RemoteException, AccessException {
        Statement stmt = null;
        try {
            checkConnection();
            stmt = _connection.createStatement();
            unlock(stmt);
        } catch (SQLException sqle) {
            if (isNoConnectionError(sqle) && canReconnect()) {
                unlock();
            } else {
                throw new RemoteException("", (sqle));
            }
        } finally {
            if (stmt != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
        }
    }

    public void reserve(String name) throws RemoteException, NotBoundException, AccessException {
        Statement stmt = null;
        try {
            checkConnection();
            stmt = _connection.createStatement();
            stmt.execute("UPDATE SERVANTS SET IN_USE=1, BORROW_TIME=" + sysdateFunctionName()
                    + ",BORROW_HOST_NAME='" + getHostName() + "'" + ",BORROW_HOST_IP='" + getHostIp() + "'"
                    + ",BORROW_PROCESS_ID='" + getProcessId() + "'" + ",BORROW_SESSION_INFO_HEX="
                    + (RPFSessionInfo.get() == null ? "NULL" : "'" + objectToHex(RPFSessionInfo.get()) + "'")
                    + ",RETURN_TIME=NULL" + ",RETURN_HOST_NAME=NULL" + ",RETURN_HOST_IP=NULL"
                    + ",RETURN_PROCESS_ID=NULL" + " WHERE NAME='" + name + "'");
        } catch (SQLException sqle) {
            if (isNoConnectionError(sqle) && canReconnect()) {
                reserve(name);
            } else {
                throw new RemoteException("", (sqle));
            }
        } finally {
            if (stmt != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
        }
    }

    public void unReserve(String name) throws RemoteException, NotBoundException, AccessException {
        Statement stmt = null;
        try {
            checkConnection();
            stmt = _connection.createStatement();
            stmt.execute("UPDATE SERVANTS SET IN_USE=0  " + ",RETURN_TIME=" + sysdateFunctionName()
                    + ",RETURN_HOST_NAME='" + getHostName() + "'" + ",RETURN_HOST_IP='" + getHostIp() + "'"
                    + ",RETURN_PROCESS_ID='" + getProcessId() + "'" + " WHERE NAME='" + name + "'");
        } catch (SQLException sqle) {
            if (isNoConnectionError(sqle) && canReconnect()) {
                unReserve(name);
            } else {
                throw new RemoteException("", (sqle));
            }
        } finally {
            if (stmt != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
        }
    }

    public void registerPingFailure(String name) throws RemoteException, NotBoundException, AccessException {
        Statement stmt = null;
        try {
            checkConnection();
            stmt = _connection.createStatement();
            stmt.execute("update SERVANTS SET PING_FAILURES=(PING_FAILURES+1) WHERE NAME='" + name + "'");
        } catch (SQLException sqle) {
            if (isNoConnectionError(sqle) && canReconnect()) {
                registerPingFailure(name);
            } else {
                throw new RemoteException("", (sqle));
            }
        } finally {
            if (stmt != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
        }
    }

    public void incrementNodeProcessCounter(String nodeName)
            throws RemoteException, NotBoundException, AccessException {
        Statement stmt = null;
        try {
            checkConnection();
            stmt = _connection.createStatement();
            stmt.execute(
                    "update NODE_DATA set PROCESS_COUNTER=(PROCESS_COUNTER+1) WHERE NODE_NAME='" + nodeName + "'");
            _connection.commit();
        } catch (SQLException sqle) {
            if (isNoConnectionError(sqle) && canReconnect()) {
                incrementNodeProcessCounter(nodeName);
            } else {
                throw new RemoteException("", (sqle));
            }
        } finally {
            if (stmt != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
        }
    }

    public void updateServantNodeName(String servantName, String nodeName)
            throws RemoteException, NotBoundException, AccessException {
        Statement stmt = null;
        try {
            checkConnection();
            stmt = _connection.createStatement();
            stmt.execute("update SERVANTS SET NODE_NAME='" + nodeName + "' WHERE NAME='" + servantName + "'");
            _connection.commit();
        } catch (SQLException sqle) {
            if (isNoConnectionError(sqle) && canReconnect()) {
                updateServantNodeName(servantName, nodeName);
            } else {
                throw new RemoteException("", (sqle));
            }
        } finally {
            if (stmt != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
        }
    }

    public void updateServantAttributes(String servantName, HashMap<String, Object> attributes)
            throws RemoteException, NotBoundException, AccessException {
        Statement stmt = null;
        try {
            checkConnection();
            stmt = _connection.createStatement();
            stmt.execute("update SERVANTS SET ATTRIBUTES_HEX='" + PoolUtils.objectToHex(attributes)
                    + "' WHERE NAME='" + servantName + "'");
            _connection.commit();
        } catch (SQLException sqle) {
            if (isNoConnectionError(sqle) && canReconnect()) {
                updateServantAttributes(servantName, attributes);
            } else {
                throw new RemoteException("", (sqle));
            }
        } finally {
            if (stmt != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
        }
    }

    public void commit() throws SQLException {
        _connection.commit();
    }

    public Remote getRemoteObject(String stub, String codeBaseStr) throws RemoteException {
        try {
            ClassLoader cl = null;
            if (codeBaseStr != null) {
                cl = new URLClassLoader(new URL[] { new URL(codeBaseStr) }, DBLayer.class.getClassLoader());
            }
            return hexToStub(stub, cl);
        } catch (Exception e) {
            throw new RemoteException("", (e));
        }
    }

    public HashMap<String, PoolDataDB> getPoolDataHashMap() throws RemoteException, AccessException {
        HashMap<String, PoolDataDB> result = new HashMap<String, PoolDataDB>();
        Statement stmt = null;
        ResultSet rset = null;
        try {
            checkConnection();
            stmt = _connection.createStatement();
            rset = stmt.executeQuery("select POOL_NAME,POOL_PREFIXES,TIMEOUT from POOL_DATA");
            while (rset.next()) {
                result.put(rset.getString(1),
                        new PoolDataDB(rset.getString(1), getPrefixes(rset.getString(2)), rset.getInt(3)));
            }
        } catch (SQLException sqle) {
            throw new RemoteException("", (sqle));
        } finally {
            if (rset != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
            if (stmt != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
        }
        return result;
    }

    public static String[] getPrefixes(String prefixes) {
        StringTokenizer st = new StringTokenizer(prefixes, ",");
        Vector<String> pv = new Vector<String>();
        while (st.hasMoreElements())
            pv.add((String) st.nextElement());
        return pv.toArray(new String[0]);
    }

    public Vector<PoolDataDB> getPoolData() throws RemoteException, AccessException {
        Vector<HashMap<String, Object>> nodeTable = getTableData("POOL_DATA");
        Vector<PoolDataDB> result = new Vector<PoolDataDB>();
        for (HashMap<String, Object> hm : nodeTable) {
            result.add(new PoolDataDB((String) hm.get("POOL_NAME"), getPrefixes((String) hm.get("POOL_PREFIXES")),
                    (Integer) hm.get("TIMEOUT")));
        }
        return result;
    }

    public Vector<NodeDataDB> getNodeData(String condition) throws RemoteException, AccessException {
        Vector<HashMap<String, Object>> nodeTable = getTableData("NODE_DATA", condition);
        Vector<NodeDataDB> result = new Vector<NodeDataDB>();
        for (HashMap<String, Object> hm : nodeTable) {
            String pwd = (String) hm.get("PWD");
            if (!pwd.equals("")) {
                pwd = decipherPwd(pwd);
            }
            result.add(new NodeDataDB((String) hm.get("NODE_NAME"), (String) hm.get("HOST_IP"),
                    (String) hm.get("HOST_NAME"), (String) hm.get("LOGIN"), pwd, (String) hm.get("INSTALL_DIR"),
                    (String) hm.get("CREATE_SERVANT_COMMAND"), (String) hm.get("KILL_SERVANT_COMMAND"),
                    (String) hm.get("OS"), (Integer) hm.get("SERVANT_NBR_MIN"), (Integer) hm.get("SERVANT_NBR_MAX"),
                    (String) hm.get("POOL_PREFIX"), (Integer) hm.get("PROCESS_COUNTER")));
        }
        return result;
    }

    public void addNode(NodeDataDB nodeData) throws RemoteException {
        Statement stmt = null;
        try {
            checkConnection();
            stmt = _connection.createStatement();
            stmt.execute(
                    "INSERT INTO NODE_DATA(NODE_NAME, HOST_IP,HOST_NAME,LOGIN,PWD,INSTALL_DIR,CREATE_SERVANT_COMMAND, KILL_SERVANT_COMMAND ,OS,SERVANT_NBR_MIN,SERVANT_NBR_MAX,POOL_PREFIX, PROCESS_COUNTER) values ("
                            + "'" + nodeData.getNodeName() + "'," + "'" + nodeData.getHostIp() + "'," + "'"
                            + nodeData.getHostName() + "'," + "'" + nodeData.getLogin() + "'," + "'"
                            + (nodeData.getPwd().trim().equals("") ? "" : cipherPwd(nodeData.getPwd())) + "'," + "'"
                            + nodeData.getInstallDir() + "'," + "'" + nodeData.getCreateServantCommand() + "',"
                            + "'" + nodeData.getKillServantCommand() + "'," + "'" + nodeData.getOS() + "',"
                            + nodeData.getServantNbrMin() + "," + nodeData.getServantNbrMax() + "," + "'"
                            + nodeData.getPoolPrefix() + "'" + ",0" + ")");

            _connection.commit();
        } catch (SQLException sqle) {
            if (isNoConnectionError(sqle) && canReconnect()) {
                addNode(nodeData);
            } else {
                throw new RemoteException("", (sqle));
            }
        } finally {
            if (stmt != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
        }
    }

    public void addPool(PoolDataDB poolData) throws RemoteException {
        Statement stmt = null;
        try {
            checkConnection();
            String prefixes = "";
            for (int i = 0; i < poolData.getPrefixes().length; ++i)
                prefixes += poolData.getPrefixes()[i] + (i == poolData.getPrefixes().length - 1 ? "" : ",");
            stmt = _connection.createStatement();
            stmt.execute("INSERT INTO POOL_DATA(POOL_NAME, TIMEOUT,POOL_PREFIXES) values (" + "'"
                    + poolData.getPoolName() + "'," + poolData.getBorrowTimeout() + "," + "'" + prefixes + "')");

            _connection.commit();
        } catch (SQLException sqle) {
            if (isNoConnectionError(sqle) && canReconnect()) {
                addPool(poolData);
            } else {
                throw new RemoteException("", (sqle));
            }
        } finally {
            if (stmt != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
        }
    }

    public void updateNode(NodeDataDB nodeData) throws RemoteException {
        Statement stmt = null;

        String ip = nodeData.getHostIp().trim();
        String host = nodeData.getHostName().trim();
        String prefix = nodeData.getPoolPrefix().trim();
        String nodeName = nodeData.getNodeName();

        if (ip.equals("")) {
            try {
                ip = InetAddress.getByName(nodeData.getHostName()).getHostAddress();
            } catch (Exception e) {
                throw new RemoteException("", (e));
            }
        }

        try {
            checkConnection();
            stmt = _connection.createStatement();
            String updateStr = "UPDATE NODE_DATA set " + " HOST_IP=" + "'" + ip + "'," + " HOST_NAME=" + "'" + host
                    + "'," + " POOL_PREFIX=" + "'" + prefix + "'," + " LOGIN=" + "'" + nodeData.getLogin() + "',"
                    + " PWD=" + "'" + (nodeData.getPwd().trim().equals("") ? "" : cipherPwd(nodeData.getPwd()))
                    + "'," + " INSTALL_DIR=" + "'" + nodeData.getInstallDir() + "'," + " CREATE_SERVANT_COMMAND="
                    + "'" + nodeData.getCreateServantCommand() + "'," + " KILL_SERVANT_COMMAND=" + "'"
                    + nodeData.getKillServantCommand() + "'," + " OS=" + "'" + nodeData.getOS() + "',"
                    + " SERVANT_NBR_MIN=" + nodeData.getServantNbrMin() + "," + " SERVANT_NBR_MAX="
                    + nodeData.getServantNbrMax() + "" + " where NODE_NAME='" + nodeName + "'";
            System.out.println(updateStr);
            stmt.execute(updateStr);
            _connection.commit();

        } catch (SQLException sqle) {
            sqle.printStackTrace();
            if (isNoConnectionError(sqle) && canReconnect()) {
                updateNode(nodeData);
            } else {
                throw new RemoteException("", (sqle));
            }
        } finally {
            if (stmt != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
        }
    }

    public void removeNode(String nodeName) throws RemoteException {
        Statement stmt = null;
        try {
            checkConnection();
            stmt = _connection.createStatement();
            String deleteStr = "delete from NODE_DATA where NODE_NAME='" + nodeName + "'";
            stmt.execute(deleteStr);
            _connection.commit();
        } catch (SQLException sqle) {
            if (isNoConnectionError(sqle) && canReconnect()) {
                removeNode(nodeName);
            } else {
                throw new RemoteException("", (sqle));
            }
        } finally {
            if (stmt != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
        }
    }

    public void removePool(String poolName) throws RemoteException {
        Statement stmt = null;
        try {
            checkConnection();
            stmt = _connection.createStatement();
            String deleteStr = "delete from POOL_DATA where POOL_NAME='" + poolName + "'";
            stmt.execute(deleteStr);
            _connection.commit();
        } catch (SQLException sqle) {
            if (isNoConnectionError(sqle) && canReconnect()) {
                removePool(poolName);
            } else {
                throw new RemoteException("", (sqle));
            }
        } finally {
            if (stmt != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
        }
    }

    public void updatePool(PoolDataDB poolData) throws RemoteException {
        Statement stmt = null;

        String prefixes = "";
        for (int i = 0; i < poolData.getPrefixes().length; ++i)
            prefixes += poolData.getPrefixes()[i] + (i == poolData.getPrefixes().length - 1 ? "" : ",");

        try {
            checkConnection();
            stmt = _connection.createStatement();
            String updateStr = "UPDATE POOL_DATA set TIMEOUT=" + poolData.getBorrowTimeout() + ","
                    + " POOL_PREFIXES='" + prefixes + "' where POOL_NAME='" + poolData.getPoolName() + "'";
            System.out.println(updateStr);
            stmt.execute(updateStr);
            _connection.commit();

        } catch (SQLException sqle) {
            sqle.printStackTrace();
            if (isNoConnectionError(sqle) && canReconnect()) {
                updatePool(poolData);
            } else {
                throw new RemoteException("", (sqle));
            }
        } finally {
            if (stmt != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
        }
    }

    public void unlockServant(String servantName) throws RemoteException {
        Statement stmt = null;
        try {
            checkConnection();
            stmt = _connection.createStatement();
            stmt.execute("UPDATE SERVANTS SET IN_USE=0, PING_FAILURES=0" + ",BORROW_HOST_NAME=NULL"
                    + ",BORROW_HOST_IP=NULL" + ",BORROW_PROCESS_ID=NULL" + ",BORROW_SESSION_INFO_HEX=NULL"
                    + ",RETURN_TIME=" + sysdateFunctionName() + ",RETURN_HOST_NAME='" + getHostName() + "'"
                    + ",RETURN_HOST_IP='" + getHostIp() + "'" + ",RETURN_PROCESS_ID='" + getProcessId() + "'"
                    + " WHERE NAME='" + servantName + "'");

        } catch (SQLException sqle) {
            if (isNoConnectionError(sqle) && canReconnect()) {
                unlockServant(servantName);
            } else {
                throw new RemoteException("", (sqle));
            }
        } finally {
            if (stmt != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
        }
    }

    public Vector<HashMap<String, Object>> getTableData(String tableName) throws RemoteException {
        return getTableData(tableName, null);
    }

    public Vector<HashMap<String, Object>> getTableData(String tableName, String condition) throws RemoteException {
        Vector<HashMap<String, Object>> result = new Vector<HashMap<String, Object>>();
        Statement stmt = null;
        ResultSet rset = null;
        try {
            checkConnection();
            stmt = _connection.createStatement();
            rset = stmt.executeQuery("select * from " + tableName
                    + (condition == null || condition.equals("") ? "" : " WHERE " + condition));
            while (rset.next()) {
                HashMap<String, Object> hm = new HashMap<String, Object>();
                for (int i = 1; i <= rset.getMetaData().getColumnCount(); ++i) {
                    hm.put(rset.getMetaData().getColumnName(i), rset.getObject(i));
                }
                result.add(hm);
            }
        } catch (SQLException sqle) {
            if (isNoConnectionError(sqle) && canReconnect()) {
                return getTableData(tableName, condition);
            } else {
                throw new RemoteException("", (sqle));
            }
        } finally {
            if (rset != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
            if (stmt != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
        }
        return result;
    }

    public String getNameFromStub(Remote stub) throws RemoteException, AccessException {

        ByteArrayOutputStream baoStream = new ByteArrayOutputStream();
        try {
            new ObjectOutputStream(baoStream).writeObject(stub);
        } catch (Exception e) {
            e.printStackTrace();
        }
        String stub_hex = bytesToHex(baoStream.toByteArray());

        Statement stmt = null;
        ResultSet rset = null;
        try {
            checkConnection();
            stmt = _connection.createStatement();
            rset = stmt.executeQuery("select NAME from SERVANTS where STUB_HEX='" + stub_hex + "'");
            if (!rset.next())
                throw new RemoteException("no corresponding servant in DB");
            return rset.getString(1);

        } catch (SQLException sqle) {
            if (isNoConnectionError(sqle) && canReconnect()) {
                return getNameFromStub(stub);
            } else {
                throw new RemoteException("", (sqle));
            }
        } finally {
            if (rset != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
            if (stmt != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
        }

    }

    public void unregisterAll() throws RemoteException, NotBoundException, AccessException {
        if (getProcessId().equals(UNKOWN))
            return;

        Statement stmt = null;
        ResultSet rset = null;
        try {
            checkConnection();
            stmt = _connection.createStatement();
            lock(stmt);
            stmt.execute("UPDATE SERVANTS SET IN_USE=0  " + ",RETURN_TIME=" + sysdateFunctionName()
                    + ",RETURN_HOST_NAME='" + getHostName() + "'" + ",RETURN_HOST_IP='" + getHostIp() + "'"
                    + ",RETURN_PROCESS_ID='" + getProcessId() + "'" + " WHERE BORROW_HOST_IP='" + getHostIp()
                    + "' AND BORROW_PROCESS_ID='" + getProcessId() + "'");
        } catch (SQLException sqle) {
            if (isNoConnectionError(sqle) && canReconnect()) {
                unregisterAll();
            } else {
                throw new RemoteException("", (sqle));
            }
        } finally {
            try {
                if (stmt != null) {
                    unlock(stmt);
                    _connection.commit();
                }
            } catch (Exception e) {
                throw new RemoteException("", (e));
            }
            if (stmt != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
            if (rset != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
        }
    }

    public static String replaceCode(String s) {
        int p1 = 0;
        while ((p1 = s.indexOf("<%=")) != -1) {
            int p2 = s.indexOf("%>", p1 + 3);
            String expression = s.substring(p1 + 3, p2);
            String className = expression.substring(0, expression.lastIndexOf('.'));
            String functionName = expression.substring(expression.lastIndexOf('.') + 1,
                    expression.lastIndexOf("()"));
            String replaceWith = "ERROR";
            try {
                replaceWith = (String) Class.forName(className).getMethod(functionName, (Class[]) null).invoke(null,
                        (Object[]) null);
            } catch (Exception e) {
                e.printStackTrace();
            }
            s = s.substring(0, p1) + replaceWith + s.substring(p2 + 2);
        }
        return s;
    }

    public void applyDBScript(InputStream scriptInputStream)
            throws RemoteException, NotBoundException, AccessException {
        Statement stmt = null;
        ResultSet rset = null;
        try {
            checkConnection();
            stmt = _connection.createStatement();

            BufferedReader br = new BufferedReader(new InputStreamReader(scriptInputStream));
            String line = null;
            StringBuffer sbuffer = new StringBuffer();
            try {
                while ((line = br.readLine()) != null) {
                    sbuffer.append(line.trim());
                    sbuffer.append(" ");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

            StringTokenizer st = new StringTokenizer(replaceCode(sbuffer.toString()), ";");
            while (st.hasMoreElements()) {
                String statmentStr = ((String) st.nextElement()).trim();
                if (statmentStr.equals(""))
                    continue;

                System.out.println("<" + statmentStr + ">");

                try {
                    if (statmentStr.trim().equalsIgnoreCase("commit")) {
                        _connection.commit();
                    } else {
                        stmt.execute(statmentStr);
                    }
                    System.out.println("OK");
                } catch (SQLException sqle) {
                    if (statmentStr.toUpperCase().startsWith("DROP")) {
                        System.out.println("NOK / " + statmentStr + " Failed ");
                    } else {
                        sqle.printStackTrace();
                    }
                }

            }
        } catch (SQLException sqle) {

            if (isNoConnectionError(sqle) && canReconnect()) {
                applyDBScript(scriptInputStream);
            } else {
                throw new RemoteException("", (sqle));
            }

        } finally {
            if (stmt != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
            if (rset != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
        }
    }

    public boolean canReconnect() {
        if (_connectionProvider == null)
            return false;
        _log.info("try to reconnect");

        Statement stmt = null;
        try {
            stmt = _connection.createStatement();
            stmt.executeQuery("select POOL_NAME from POOL_DATA");
            _log.info("reconnection aborted, connection was up");
            return false;
        } catch (SQLException sqle) {

        } finally {
            if (stmt != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                }
        }

        Connection connection = null;
        try {
            connection = _connectionProvider.newConnection();
            stmt = connection.createStatement();
            stmt.executeQuery("select POOL_NAME from POOL_DATA");
        } catch (SQLException sqle) {
            _log.info("reconnection failed");
            return false;
        } finally {
            if (stmt != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    return false;
                }
        }
        _connection = connection;

        _log.info("reconnection succeeded");
        return true;
    }

    public void setConnectionProvider(ConnectionProvider connectionProvider) {
        this._connectionProvider = connectionProvider;
    }

    public static DBLayer getLayer(String dbtype, Connection conn) throws Exception {
        String className = "org.kchine.rpf.db.DBLayer" + ("" + dbtype.charAt(0)).toUpperCase()
                + dbtype.substring(1);
        return (DBLayer) Class.forName(className).getConstructor(new Class[] { Connection.class })
                .newInstance(new Object[] { conn });
    }

    public static DBLayer getLayer(String dbtype, ConnectionProvider connProvider) throws Exception {
        Connection c = null;
        try {
            c = connProvider.newConnection();
        } catch (Exception e) {
            e.printStackTrace();
        }
        DBLayer result = getLayer(dbtype, c);
        result.setConnectionProvider(connProvider);
        return result;
    }

    static String _pwdKey = "800761F89437B3B0F47F753792A7D69E49E65B5191D52652";
    static SecretKey _key = null;

    static SecretKey getSecretKey() {
        try {
            DESedeKeySpec keyspec = new DESedeKeySpec(PoolUtils.hexToBytes(_pwdKey));
            SecretKeyFactory desEdeFactory = SecretKeyFactory.getInstance("DESede");
            SecretKey k = desEdeFactory.generateSecret(keyspec);
            return k;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    static String cipherPwd(String pwd) {
        try {
            Cipher cipher = Cipher.getInstance("DESede");
            cipher.init(Cipher.ENCRYPT_MODE, getSecretKey());
            byte[] ciphertext = cipher.doFinal(PoolUtils.objectToBytes(pwd));
            return PoolUtils.bytesToHex(ciphertext);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    static String decipherPwd(String cipheredpwd) {
        try {
            Cipher cipher = Cipher.getInstance("DESede");
            cipher.init(Cipher.DECRYPT_MODE, getSecretKey());
            return (String) PoolUtils.bytesToObject(cipher.doFinal(PoolUtils.hexToBytes(cipheredpwd)));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public void setJobID(String servantName, String jobID) throws RemoteException {
        Statement stmt = null;
        try {
            checkConnection();
            stmt = _connection.createStatement();
            stmt.execute("update SERVANTS SET JOB_ID='" + jobID + "' WHERE NAME='" + servantName + "'");
            _connection.commit();
        } catch (SQLException sqle) {
            if (isNoConnectionError(sqle) && canReconnect()) {
                setJobID(servantName, jobID);
            } else {
                throw new RemoteException("", (sqle));
            }
        } finally {
            if (stmt != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
        }
    }

    public void setNotified(String servantName, boolean notified) throws RemoteException {
        Statement stmt = null;
        try {
            checkConnection();
            stmt = _connection.createStatement();
            stmt.execute(
                    "update SERVANTS SET NOTIFIED=" + (notified ? "1" : "0") + " WHERE NAME='" + servantName + "'");
            _connection.commit();
        } catch (SQLException sqle) {
            if (isNoConnectionError(sqle) && canReconnect()) {
                setNotified(servantName, notified);
            } else {
                throw new RemoteException("", (sqle));
            }
        } finally {
            if (stmt != null)
                try {
                    stmt.close();
                } catch (Exception e) {
                    throw new RemoteException("", (e));
                }
        }
    }
}