/****************************************************************************** * Product: Adempiere ERP & CRM Smart Business Solution * * Copyright (C) 1999-2006 ComPiere, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * * under the terms version 2 of the GNU General Public License as published * * by the Free Software Foundation. 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, write to the Free Software Foundation, Inc., * * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * * For the text or an alternative of this public license, you may reach us * * ComPiere, Inc., 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA * * or via info@compiere.org or http://www.compiere.org/license.html * *****************************************************************************/ package org.compiere.db; import java.io.Serializable; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.SQLException; import java.util.logging.Level; import javax.naming.InitialContext; import javax.sql.DataSource; import javax.swing.JOptionPane; import org.compiere.model.MSystem; import org.compiere.util.CLogger; import org.compiere.util.Ini; /** * Adempiere DB Connection Descriptor * * @author Jorg Janke * @author Marek Mosiewicz<marek.mosiewicz@jotel.com.pl> - support for RMI over HTTP * @version $Id: CConnection.java,v 1.5 2006/07/30 00:55:13 jjanke Exp $ */ public class CConnection implements Serializable, Cloneable { /** * generated serial id */ private static final long serialVersionUID = -1823868178123935209L; /** Connection */ private volatile static CConnection s_cc = null; /** Logger */ private static final CLogger log = CLogger.getCLogger (CConnection.class); /** * Get/Set default client/server Connection * @return Connection Descriptor */ public synchronized static CConnection get () { if (s_cc == null) { String attributes = Ini.getProperty (Ini.P_CONNECTION); s_cc = new CConnection (null); s_cc.setAttributes (attributes); if (! attributes.contains("PWD=") && MSystem.isSecureProps()) { // get the password from secret properties String dbPwd = Ini.getVar("ADEMPIERE_DB_PASSWORD"); if (dbPwd != null) s_cc.setDbPwd(dbPwd); } if (log.isLoggable(Level.FINE)) log.fine(s_cc.toString()); } return s_cc; } // get /** * Get/Set default client/server Connection * @param apps_host optional apps host for new connections * @return Connection Descriptor * @deprecated */ public synchronized static CConnection get (String apps_host) { return get(); } // get /** * Get specific connection * @param type database Type, e.g. Database.DB_ORACLE * @param db_host db host * @param db_port db port * @param db_name db name * @return connection */ public static CConnection get (String type, String db_host, int db_port, String db_name) { return get (type, db_host, db_port, db_name, null, null); } // get /** * Get specific client connection * @param type database Type, e.g. Database.DB_ORACLE * @param db_host db host * @param db_port db port * @param db_name db name * @param db_uid db user id * @param db_pwd db user password * @return connection */ public static CConnection get (String type, String db_host, int db_port, String db_name, String db_uid, String db_pwd) { CConnection cc = new CConnection (db_host); cc.setAppsHost (db_host); // set Apps=DB cc.setType (type); cc.setDbHost (db_host); cc.setDbPort (db_port); cc.setDbName (db_name); // if (db_uid != null) cc.setDbUid (db_uid); if (db_pwd != null) cc.setDbPwd (db_pwd); return cc; } // get /** * @param host optional application/db host */ public CConnection (String host) { if (host != null) { m_apps_host = host; m_db_host = host; } } // CConnection /** Name of Connection */ private String m_name = "Standard"; /** Application Host */ private String m_apps_host = "MyAppsServer"; /** Database Type */ private String m_type = ""; /** Database Host */ private String m_db_host = "MyDBServer"; /** Database Port */ private int m_db_port = 0; /** Database name */ private String m_db_name = "MyDBName"; /** In Memory connection */ private boolean m_bequeath = false; /** Connection uses Firewall */ private boolean m_firewall = false; /** Firewall host */ private String m_fw_host = ""; /** Firewall port */ private int m_fw_port = 0; /** DB User name */ private String m_db_uid = "adempiere"; /** DB User password */ private String m_db_pwd = "adempiere"; /** Database */ private AdempiereDatabase m_db = null; /** ConnectionException */ private Exception m_dbException = null; /** Database Connection */ private boolean m_okDB = false; /** Info */ private String[] m_info = new String[2]; /** Server Version */ private String m_version = null; /** DataSource */ private DataSource m_ds = null; /** DB Info */ private String m_dbInfo = null; private int m_webPort; private int m_sslPort; /** * Get Name * @return connection name */ public String getName () { return m_name; } /** * Set Name * @param name connection name */ public void setName (String name) { m_name = name; } // setName /** * Set Name */ public void setName () { m_name = toString (); } // setName /** * Get Application Host * @return apps host */ public String getAppsHost () { return m_apps_host; } /** * Set Application Host * @param apps_host apps host */ public void setAppsHost (String apps_host) { m_apps_host = apps_host; m_name = toString (); } /** * @return web port */ public int getWebPort() { return m_webPort; } /** * set web port * @param webPort */ public void setWebPort(int webPort) { m_webPort = webPort; } /** * Set Web Port * @param webPortString web port as String */ public void setWebPort (String webPortString) { try { if (webPortString == null || webPortString.length() == 0) ; else setWebPort (Integer.parseInt (webPortString)); } catch (Exception e) { log.severe(e.toString ()); } } /** * @return ssl port */ public int getSSLPort() { return m_sslPort; } /** * set ssl port * @param sslPort */ public void setSSLPort(int sslPort) { m_sslPort = sslPort; } /** * Set SSL Port * @param sslPortString web port as String */ public void setSSLPort (String sslPortString) { try { if (sslPortString == null || sslPortString.length() == 0) ; else setSSLPort (Integer.parseInt (sslPortString)); } catch (Exception e) { log.severe(e.toString ()); } } /** * Get Apps Server Version * @return db host name */ public String getServerVersion () { return m_version; } // getServerVersion /************* * Get Database Host name * @return db host name */ public String getDbHost () { return m_db_host; } // getDbHost /** * Set Database host name * @param db_host db host */ public void setDbHost (String db_host) { m_db_host = db_host; m_name = toString (); m_okDB = false; } // setDbHost /** * Get Database Name (Service Name) * @return db name */ public String getDbName () { return m_db_name; } // getDbName /** * Set Database Name (Service Name) * @param db_name db name */ public void setDbName (String db_name) { m_db_name = db_name; m_name = toString (); m_okDB = false; } // setDbName /** * Get DB Port * @return port */ public int getDbPort () { return m_db_port; } // getDbPort /** * Set DB Port * @param db_port db port */ public void setDbPort (int db_port) { m_db_port = db_port; m_okDB = false; } // setDbPort /** * Set DB Port * @param db_portString db port as String */ public void setDbPort (String db_portString) { try { if (db_portString == null || db_portString.length() == 0) ; else setDbPort (Integer.parseInt (db_portString)); } catch (Exception e) { log.severe(e.toString ()); } } // setDbPort /** * Get Database Password * @return db password */ public String getDbPwd () { return m_db_pwd; } // getDbPwd /** * Set DB password * @param db_pwd db user password */ public void setDbPwd (String db_pwd) { m_db_pwd = db_pwd; m_okDB = false; } // setDbPwd /** * Get Database User * @return db user */ public String getDbUid () { return m_db_uid; } // getDbUid /** * Set Database User * @param db_uid db user id */ public void setDbUid (String db_uid) { m_db_uid = db_uid; m_name = toString (); m_okDB = false; } // setDbUid /** * RMI over HTTP * * Deprecated, always return false * @return true if RMI over HTTP (Wan Connection Profile) * @deprecated */ public boolean isRMIoverHTTP () { return false; } // isRMIoverHTTP /** * Should objects be created on Server ? * @return true if client and VPN/WAN * @deprecated */ public boolean isServerObjects() { return false; } // isServerObjects /** * Should objects be created on Server ? * @return true if client and Terminal/VPN/WAN * @deprecated */ public boolean isServerProcess() { return false; } // isServerProcess /** * Is this a Terminal Server ? * @return true if client and Terminal * @deprecated */ public boolean isTerminalServer() { return false; } // isTerminalServer /** * Is DB via Firewall * @return true if via firewall */ public boolean isViaFirewall () { return m_firewall; } /** * Method setViaFirewall * @param viaFirewall boolean */ public void setViaFirewall (boolean viaFirewall) { m_firewall = viaFirewall; m_okDB = false; } /** * Method setViaFirewall * @param viaFirewallString String */ public void setViaFirewall (String viaFirewallString) { try { setViaFirewall (Boolean.valueOf (viaFirewallString).booleanValue ()); } catch (Exception e) { log.severe(e.toString ()); } } /** * Get fire wall host * @return fire wall host */ public String getFwHost () { return m_fw_host; } /** * Set fire wall host * @param fw_host String */ public void setFwHost (String fw_host) { m_fw_host = fw_host; m_okDB = false; } /** * Get Firewall port * @return firewall port */ public int getFwPort () { return m_fw_port; } /** * Set Firewall port * @param fw_port firewall port */ public void setFwPort (int fw_port) { m_fw_port = fw_port; m_okDB = false; } /** * Set Firewall port * @param fw_portString firewall port as String */ public void setFwPort (String fw_portString) { try { if (fw_portString == null || fw_portString.length() == 0) ; else setFwPort (Integer.parseInt (fw_portString)); } catch (Exception e) { log.severe(e.toString ()); } } /** * Is it a bequeath connection * @return true if bequeath connection */ public boolean isBequeath () { return m_bequeath; } /** * Set Bequeath * @param bequeath bequeath connection */ public void setBequeath (boolean bequeath) { m_bequeath = bequeath; m_okDB = false; } /** * Set Bequeath * @param bequeathString bequeath connection as String (true/false) */ public void setBequeath (String bequeathString) { try { setBequeath (Boolean.valueOf (bequeathString).booleanValue ()); } catch (Exception e) { log.severe(e.toString ()); } } // setBequeath /** * Get Database Type * @return database type */ public String getType () { return m_type; } /** * Set Database Type and default settings. * Checked against installed databases * @param type database Type, e.g. Database.DB_ORACLE */ public void setType (String type) { if (Database.getDatabase(type) != null) { m_type = type; m_okDB = false; } // Oracle if (isOracle ()) { if (getDbPort () != Database.DB_ORACLE_DEFAULT_PORT) setDbPort (Database.DB_ORACLE_DEFAULT_PORT); setFwPort (Database.DB_ORACLE_DEFAULT_CM_PORT); } else { setBequeath (false); setViaFirewall (false); } // PostgreSQL if (isPostgreSQL ()) { if (getDbPort () != Database.DB_POSTGRESQL_DEFAULT_PORT) setDbPort (Database.DB_POSTGRESQL_DEFAULT_PORT); } } // setType /** * Supports BLOB * @return true if BLOB is supported */ public boolean supportsBLOB () { return m_db.supportsBLOB (); } // supportsBLOB /** * Is Oracle DB * @return true if Oracle */ public boolean isOracle () { return Database.DB_ORACLE.equals (m_type); } // isOracle /** * Is PostgreSQL DB * @return true if PostgreSQL */ public boolean isPostgreSQL () { return Database.DB_POSTGRESQL.equals (m_type); } // isPostgreSQL /** * Is Database Connection OK * @return true if database connection is OK */ public boolean isDatabaseOK () { return m_okDB; } // isDatabaseOK /** * Create DB data source * @return data source != null */ public boolean setDataSource() { if (m_ds == null && Ini.isClient()) { AdempiereDatabase getDB = getDatabase(); if (getDB != null) // no db selected m_ds = getDB.getDataSource(this); } return m_ds != null; } // setDataSource /** * Set DB Data Source * @param ds data source * @return data source != null */ public boolean setDataSource(DataSource ds) { if (ds == null && m_ds != null) getDatabase().close(); m_ds = ds; return m_ds != null; } // setDataSource /** * Get DB data source * @return DataSource */ public DataSource getDataSource () { return m_ds; } // getDataSource /** * Has DB data source * @return true if DataSource exists */ public boolean isDataSource () { return m_ds != null; } // isDataSource /** * Test Database Connection. *
	 *  -- Example --
	 *  Database: PostgreSQL - 7.1.3
	 *  Driver:   PostgreSQL Native Driver - PostgreSQL 7.2 JDBC2
	 *  -- Example --
	 *  Database: Oracle - Oracle8i Enterprise Edition Release 8.1.7.0.0 - Production With the Partitioning option JServer Release 8.1.7.0.0 - Production
	 *  Driver:   Oracle JDBC driver - 9.0.1.1.0
	 *  
* @param retest * @return Exception or null */ public Exception testDatabase(boolean retest) { if (!retest && m_ds != null && m_okDB) return null; if (getDatabase() != null) getDatabase().close(); m_ds = null; setDataSource(); // the actual test Connection conn = getConnection (true, Connection.TRANSACTION_READ_COMMITTED); if (conn != null) { try { readInfo(conn); conn.close (); } catch (Exception e) { log.severe (e.toString()); return e; } } return m_dbException; // from opening } // testDatabase /** * Read DB info from connection * @param conn * @throws SQLException */ public void readInfo(Connection conn) throws SQLException { DatabaseMetaData dbmd = conn.getMetaData (); m_info[0] = "Database=" + dbmd.getDatabaseProductName () + " - " + dbmd.getDatabaseProductVersion (); m_info[0] = m_info[0].replace ('\n', ' '); m_info[1] = "Driver =" + dbmd.getDriverName () + " - " + dbmd.getDriverVersion (); if (isDataSource()) m_info[1] += " - via DataSource"; m_info[1] = m_info[1].replace ('\n', ' '); if (log.isLoggable(Level.CONFIG)) log.config(m_info[0] + " - " + m_info[1]); } /** * Short String representation * @return appsHost{dbHost-dbName-uid} */ public String toString () { StringBuilder sb = new StringBuilder (m_apps_host); sb.append ("{").append (m_db_host) .append ("-").append (m_db_name) .append ("-").append (m_db_uid) .append ("}"); return sb.toString (); } // toString /** * Detail Info * @return info */ public String toStringDetail () { StringBuilder sb = new StringBuilder (m_apps_host); sb.append ("{").append (m_db_host) .append ("-").append (m_db_name) .append ("-").append (m_db_uid) .append ("}"); // Connection conn = getConnection (true, Connection.TRANSACTION_READ_COMMITTED); if (conn != null) { try { DatabaseMetaData dbmd = conn.getMetaData (); sb.append("\nDatabase=" + dbmd.getDatabaseProductName () + " - " + dbmd.getDatabaseProductVersion()); sb.append("\nDriver =" + dbmd.getDriverName () + " - " + dbmd.getDriverVersion ()); if (isDataSource()) sb.append(" - via DS"); conn.close (); } catch (Exception e) { } } conn = null; return sb.toString (); } // toStringDetail /** * Get DB Version Info * @return info */ public String getDBInfo() { if (m_dbInfo != null) return m_dbInfo; StringBuilder sb = new StringBuilder (); Connection conn = getConnection (true, Connection.TRANSACTION_READ_COMMITTED); if (conn != null) { try { DatabaseMetaData dbmd = conn.getMetaData (); sb.append(dbmd.getDatabaseProductVersion()) .append(";").append(dbmd.getDriverVersion()); if (isDataSource()) sb.append(";DS"); conn.close (); m_dbInfo = sb.toString (); } catch (Exception e) { log.log(Level.SEVERE, "", e); sb.append(e.getLocalizedMessage()); } } conn = null; return sb.toString(); } // toStringDetail /** * String representation. * Used also for Instantiation * @return string representation * @see #setAttributes(String) setAttributes */ public String toStringLong () { return toStringLong(true); } /** * String representation. * Used also for Instantiation * @param includePass flag to include the password in the String * @return string representation * @see #setAttributes(String) setAttributes */ public String toStringLong (boolean includePass) { StringBuilder sb = new StringBuilder ("CConnection["); sb.append ("name=").append (escape(m_name)) .append (",AppsHost=").append (escape(m_apps_host)) .append (",WebPort=").append (m_webPort) .append (",SSLPort=").append (m_sslPort) .append (",type=").append (escape(m_type)) .append (",DBhost=").append (escape(m_db_host)) .append (",DBport=").append (m_db_port) .append (",DBname=").append (escape(m_db_name)) .append (",BQ=").append (m_bequeath) .append (",FW=").append (m_firewall) .append (",FWhost=").append (escape(m_fw_host)) .append (",FWport=").append (m_fw_port) .append (",UID=").append (escape(m_db_uid)) ; // the format is read by setAttributes if (includePass) { sb.append (",PWD=").append (escape(m_db_pwd)); } sb.append("]"); return sb.toString (); } // toStringLong /** * Use html like escape sequence to escape = and , * @param value * @return escape value */ private String escape(String value) { if (value == null) return null; // use html like escape sequence to escape = and , value = value.replace("=", "&eq;"); value = value.replace(",", ","); return value; } /** * Set Attributes from String (parse {@link #toStringLong()}) * @param attributes attributes */ private void setAttributes (String attributes) { try { attributes = attributes.substring(attributes.indexOf("[")+1, attributes.length() - 1); String[] pairs= attributes.split("[,]"); for(String pair : pairs) { String[] pairComponents = pair.split("[=]"); String key = pairComponents[0]; String value = pairComponents.length == 2 ? unescape(pairComponents[1]) : ""; if ("name".equalsIgnoreCase(key)) { setName(value); } else if ("AppsHost".equalsIgnoreCase(key)) { setAppsHost(value); } else if ("type".equalsIgnoreCase(key)) { setType(value); } else if ("DBhost".equalsIgnoreCase(key)) { setDbHost(value); } else if ("DBport".equalsIgnoreCase(key)) { setDbPort(value); } else if ("DbName".equalsIgnoreCase(key)) { setDbName(value); } else if ("BQ".equalsIgnoreCase(key)) { setBequeath(value); } else if ("FW".equalsIgnoreCase(key)) { setViaFirewall(value); } else if ("FWhost".equalsIgnoreCase(key)) { setFwHost(value); } else if ("FWport".equalsIgnoreCase(key)) { setFwPort(value); } else if ("UID".equalsIgnoreCase(key)) { setDbUid(value); } else if ("PWD".equalsIgnoreCase(key)) { setDbPwd(value); } else if ("WebPort".equalsIgnoreCase(key)) { setWebPort(value); } else if ("SSLPort".equalsIgnoreCase(key)) { setSSLPort(value); } } } catch (Exception e) { log.log(Level.SEVERE, attributes + " - " + e.toString (), e); } } // setAttributes /** * @param value * @return un-escape value * @see CConnection#escape(String) */ private String unescape(String value) { value = value.replace("&eq;", "="); value = value.replace(",", ","); return value; } /** * Equals * @param o object * @return true if o equals this */ @Override public boolean equals (Object o) { if (o instanceof CConnection) { CConnection cc = (CConnection)o; if (cc.getAppsHost().equals (m_apps_host) && cc.getDbHost().equals (m_db_host) && cc.getDbPort() == m_db_port && cc.getDbName().equals(m_db_name) && cc.getType().equals(m_type) && cc.getDbUid().equals(m_db_uid) && cc.getDbPwd().equals(m_db_pwd)) return true; } return false; } // equals /** * Get Info.
* - Database, Driver, Status Info * @return info */ public String getInfo () { StringBuilder sb = new StringBuilder (m_info[0] != null ? m_info[0] : ""); sb.append (" - ").append (m_info[1] != null ? m_info[1] : "") .append ("\n").append (getDatabase ().toString ()); sb.append ("\nDatabaseOK=").append (isDatabaseOK ()); return sb.toString (); } // getInfo /** * Hashcode * @return hashcode of name */ @Override public int hashCode () { return m_name.hashCode (); } // hashCode /** * Get Database Adapter * @return database adapter instance */ public AdempiereDatabase getDatabase () { // different driver if (m_db != null && !m_db.getName ().equals (m_type)) m_db = null; if (m_db == null) { try { m_db = Database.getDatabase(m_type); if (m_db != null) // test class loader ability m_db.getDataSource(this); } catch (NoClassDefFoundError ee) { System.err.println("Environment Error - Check idempiere.properties - " + ee); if (Ini.isClient()) { if (JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog (null, "There is a configuration error:\n" + ee + "\nDo you want to reset the saved configuration?", "Adempiere Configuration Error", JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE)) Ini.deletePropertyFile(); } System.exit (1); } catch (Exception e) { log.severe(e.toString ()); } } return m_db; } // getDatabase /** * Get Connection URL * @return connection URL */ public String getConnectionURL () { getDatabase (); // updates m_db if (m_db != null) return m_db.getConnectionURL (this); else return ""; } // getConnectionURL /** * Get Connection. * Sets {@link #m_dbException}. * @param autoCommit true if autocommit connection * @param transactionIsolation transaction isolation level * @return Connection */ public Connection getConnection (boolean autoCommit, int transactionIsolation) { Connection conn = null; m_dbException = null; m_okDB = false; // getDatabase (); // updates m_db if (m_db == null) { m_dbException = new IllegalStateException("No Database Connector"); return null; } // try { conn = m_db.getCachedConnection(this, autoCommit, transactionIsolation); // Verify Connection if (conn != null) { if (conn.getTransactionIsolation() != transactionIsolation) conn.setTransactionIsolation (transactionIsolation); if (conn.getAutoCommit() != autoCommit) conn.setAutoCommit (autoCommit); m_okDB = true; } } catch (UnsatisfiedLinkError ule) { String msg = ule.getLocalizedMessage() + " -> Did you set the LD_LIBRARY_PATH ? - " + getConnectionURL(); m_dbException = new Exception(msg); System.err.println(msg); } catch (SQLException ex) { m_dbException = ex; if (conn == null) { System.err.println(getConnectionURL () + ", (1) AutoCommit=" + autoCommit + ",TrxIso=" + getTransactionIsolationInfo(transactionIsolation) + " - " + ex.getMessage()); } else { try { System.err.println(getConnectionURL () + ", (2) AutoCommit=" + conn.getAutoCommit() + "->" + autoCommit + ", TrxIso=" + getTransactionIsolationInfo(conn.getTransactionIsolation()) + "->" + getTransactionIsolationInfo(transactionIsolation) + " - " + ex.getMessage()); } catch (Exception ee) { System.err.println(getConnectionURL () + ", (1) AutoCommit=" + autoCommit + ",TrxIso=" + getTransactionIsolationInfo(transactionIsolation) + " - " + ex.getMessage()); } } } catch (Exception ex) { m_dbException = ex; System.err.println(getConnectionURL() + " - " + ex.getLocalizedMessage()); } return conn; } // getConnection /** * Get Database Exception of last connection attempt * @return Exception or null */ public Exception getDatabaseException () { return m_dbException; } /*************************************************************************/ /** * Get Application Server Initial Context * @param useCache if true, use existing cache * @return Initial Context or null * @deprecated */ @Deprecated(forRemoval = true, since = "11") public InitialContext getInitialContext (boolean useCache) { return null; } // getInitialContext /** * Convert Statement * @param origStatement original statement (Oracle syntax) * @return converted Statement * @throws Exception */ public String convertStatement (String origStatement) throws Exception { // make sure we have a good database if (m_db != null && !m_db.getName ().equals (m_type)) getDatabase (); if (m_db != null) return m_db.convertStatement (origStatement); throw new Exception ( "CConnection.convertStatement - No Converstion Database"); } // convertStatement /** * Get Status Info * @return info */ public String getStatus() { StringBuilder sb = new StringBuilder (m_apps_host); sb.append ("{").append (m_db_host) .append ("-").append (m_db_name) .append ("-").append (m_db_uid) .append ("}"); if (m_db != null) sb.append (m_db.getStatus()); return sb.toString (); } // getStatus /** * Get Transaction Isolation Info * @param transactionIsolation trx iso * @return transaction isolation level */ public static String getTransactionIsolationInfo(int transactionIsolation) { if (transactionIsolation == Connection.TRANSACTION_NONE) return "NONE"; if (transactionIsolation == Connection.TRANSACTION_READ_COMMITTED) return "READ_COMMITTED"; if (transactionIsolation == Connection.TRANSACTION_READ_UNCOMMITTED) return "READ_UNCOMMITTED"; if (transactionIsolation == Connection.TRANSACTION_REPEATABLE_READ) return "REPEATABLE_READ"; if (transactionIsolation == Connection.TRANSACTION_READ_COMMITTED) return "SERIALIZABLE"; return ""; } // getTransactionIsolationInfo @Override public Object clone() throws CloneNotSupportedException { CConnection c = (CConnection)super.clone(); String[] info = new String[2]; info[0] = m_info[0]; info[1] = m_info[1]; c.m_info = info; return c; } } // CConnection