home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Symantec Visual Cafe for Java 2.5
/
symantec-visual-cafe-2.5-database-dev-edition.iso
/
VCafe
/
prosrc.bin
/
JdbcConnection.java
< prev
next >
Encoding:
Amiga
Atari
Commodore
DOS
FM Towns/JPY
Macintosh
Macintosh JP
Macintosh to JP
NeXTSTEP
RISC OS/Acorn
Shift JIS
UTF-8
Wrap
Java Source
|
1998-03-18
|
41.9 KB
|
1,222 lines
/*
* @(#)JdbcConnection.java
*
* Copyright (c) 1997 Symantec Corporation. All Rights Reserved.
*
*/
package symantec.itools.db.beans.jdbc;
import java.io.* ;
import java.sql.* ;
import java.beans.*;
import java.lang.*;
import java.util.Properties ;
import java.util.Vector;
import java.util.Stack;
/**
* <P>The class that wraps a JDBC Connection object.
* Provides properties to establish a database connection as well as properties to
* modify the establish connection.
*
* Provides its own versioning logic.
*
*
*
* Is Event source for ConnectionEvents OPEN and CLOSE. Note the signature of closing
* a connection is setConnectionClosed (boolean) throws PropertyVetoException.
* This signature conforms with JavaBeans Design Pattern for Constrained Properties.
* Other beans can control whether a Connection should close by registering a
* VetoableChangeListener and throwing a PropertyVetoException when notified.
*
* Implements doAutoStart() by establishing a database connection during object
* de-serialization.
*
* @see JDBCBean
* @see java.sql.Connection
*
*/
public class JdbcConnection extends JDBCBean
implements symantec.itools.db.beans.binding.Connection
{
//PUBLIC SECTION
//Constructors
/**
* Default constructor. Bean-aware IDE's and serialization require all beans
* have a default constructor.
*/
public JdbcConnection () {
}
/**
* Constructor. Beans should provide a constructor with commonly-used properties
* as parameters. This allows the beans to be constructed programatically without
* having to call the properties' setter methods.
*
* @see Connection#connectFailed
* @see Connection#connect
*
* @param driverName. The fully qualified name of the JDBC Driver class.
* @param url. The JDBC compliant url that will be used to connect to a database.
* @param username. The name used to log onto the database.
* @param password. The password for the user.
*/
public JdbcConnection (String driverName, String URL,
String userName, String password) {
this();
setDriverName(driverName);
setURL(url);
setUserName(userName);
setPassword(password);
}
//Methods
/**
* Connects to the database referenced within the url property.
*
* If the driverName property is provided, the driver is loaded prior to obtaining a
* connection from the DriverManager. If the driverName is empty, the user is responsible
* for loading the driver prior to calling connect.
*
* The getConnectionProperties() method is called to build a Driver-specific Properties
* object. This method returns a Properties object with the userName and password properties
* set. Override this method to return additional properties that driverName expects.
*
* The connectFailed method will be called if an SQLException was thrown attempting to connect.
* Descendents of Connection can override this method to obtain a username, password, or url
* from the user via a dialog. After the database connection is established, the 'runtime' properties
* are applied to the database -- catalog, autocommit, transactionIsolation and readonly.
*
* @see java.sql.DriverManager#getConnection
* @see java.sql.Connection
* @see Connection#connectFailed
* @see Connection#getConnectionProps
*
* @exception SQLException
*/
public synchronized void connect () throws SQLException
{
if (!isConnectionClosed()) {
return; //allow multiple calls to connect.
}
String javaVendor = System.getProperty("java.vendor");
boolean javaVendorIsMicrosoft = javaVendor.startsWith("Microsoft");
String javaVersion = System.getProperty("java.version");
// Don't forget that a length of zero is OK
// as long as driver is registered by some other means.
if (getDriverName().length() != 0) {
//load the driver so it can register itself
try {
Driver drv=(Driver)Class.forName(getDriverName()).newInstance();
}
catch (ClassNotFoundException e) {
String reason = "Could not register JDBC driver. Driver class name: " + e.getMessage();
System.out.println(reason);
throw new SQLException(reason);
}
catch (Exception e) {
String reason = "Could not register JDBC driver. Driver class name: " + e.getMessage();
System.out.println(reason);
throw new SQLException(reason);
}
}
try {
// If Microsoft IE in Windows, then turn on system permissions
// to allow debugging from VC dbDE into IE. This is needed for
// creation of sockets to localhost, IP address, etc.
if (symantec.itools.lang.OS.isWindows() && javaVendorIsMicrosoft)
{
Class msSecurityAccess=Class.forName("symantec.itools.db.beans.jdbc.MSSecurityAccess");
Class classParam[]=new Class[3];
classParam[0]=Class.forName("java.lang.String");
classParam[1]=Class.forName("java.lang.String");
classParam[2]=Class.forName("java.lang.String");
java.lang.reflect.Method getConnection=msSecurityAccess.getMethod("getConnection",classParam);
String param[]={getURL(),getUserName(),getPassword()};
lowLevelConnection=(Connection)getConnection.invoke(null,param);
}
else{
lowLevelConnection = DriverManager.getConnection(getURL(),getConnectionProps());
}
}
catch (SQLException ex) {
System.out.println(ex.getMessage());
connectFailed(new ConnectFailedEvent(this, ConnectFailedEvent.GENERALERROR, ex.getMessage()));
if (isConnectionClosed()) {
throw new SQLException(ex.getMessage());
}
else {
return;
}
}
catch(Exception e){
System.out.println(e.getMessage());
}
if (lowLevelConnection != null) {
try {
DatabaseMetaData md = lowLevelConnection.getMetaData();
defaultTransactionIsolation = md.getDefaultTransactionIsolation();
}
catch (SQLException ex) {
System.out.println("Warning: could not determine default transaction isolation level: " + ex.getMessage());
System.out.println("Defaulting to TRANSACTION_NONE");
defaultTransactionIsolation = TRANSACTION_NONE;
}
//set connection properties
try {
lowLevelConnection.setAutoCommit(autoCommit);
}
catch (SQLException ex) {
System.out.println("Warning: could not apply autoCommit property to live connection: " + ex.getMessage());
}
try {
lowLevelConnection.setReadOnly(readOnly);
}
catch (SQLException ex) {
System.out.println("Warning: could not apply readOnly property to live connection: " + ex.getMessage());
}
try {
if (transactionIsolation != TRANSACTION_DEFAULT) {
lowLevelConnection.setTransactionIsolation(transactionIsolation);
}
}
catch (SQLException ex) {
System.out.println("Warning: could not apply transactionIsolation property to live connection: " + ex.getMessage());
}
try {
if (catalog.length() != 0 ) {
lowLevelConnection.setCatalog(catalog);
}
}
catch (SQLException ex) {
System.out.println("Warning: could not apply catalog property to live connection: " + ex.getMessage());
}
}
}
/**
* This method starts a transaction...
* - verify the connection supports transactions
* - push current state information on a stack
* - close open statements
* - Set auto-commit mode to false
*
* Note swallow any exceptions - if we can't begin a transaction
* we silently continue in auto-commit mode.
*
* @see endTransaction
*
* @return void
*/
public synchronized void beginTransaction()
{
try {
if (!getMetaData().supportsTransactions()) {
return;
}
boolean mode = isAutoCommit();
m_AutoCommitMode.push(new Boolean(mode));
m_TransactionState.push(new Boolean(true));
// foo : Since a save will now trigger a beginTransaction (master-detail)
// it becomes neccessary to restrict this to drivers like Access.
// What determines if a driver is like Access? there are two methods:
// supportsOpenStatementsAcrossCommit and supportsOpenStatementsAcrossRollback.
// This implies we should only close statements in commit() and rollback().
// foo : We should really track all statements, not just the latest.
// foo : Is this correct or is it just an Access bug?
java.sql.DatabaseMetaData md = getMetaData();
boolean supportsAcrossCommit = md.supportsOpenStatementsAcrossCommit();
boolean supportsAcrossRollback = md.supportsOpenStatementsAcrossRollback();
if (!supportsAcrossCommit || !supportsAcrossRollback) {
if (m_Statement != null) {
m_Statement.close();
}
}
setAutoCommit(false);
}
catch (Exception ex) {
}
}
/**
* This method ends a transaction...
* - verify the connection supports transactions
* - commit or rollback the present transaction
* - pop state information from a stack
* - Set auto-commit mode to true
*
* Note swallow any exceptions - if we can't end a transaction
* we silently continue in auto-commit mode.
*
* @see endTransaction
*
* @return void
*/
public synchronized void endTransaction(boolean commitTransaction)
{
try {
if (!getMetaData().supportsTransactions()) {
return;
}
Boolean transactionState = (Boolean)m_TransactionState.pop();
if (commitTransaction && transactionState.booleanValue()) {
commit();
}
else {
rollback();
}
Boolean mode = (Boolean)m_AutoCommitMode.pop();
if (mode.booleanValue()) {
setAutoCommit(true);
}
}
catch (Exception ex) {
}
}
/**
* This method prepares a SQL statement
*
* @see createStatement
*
* @param sql database DML string.
*
* @return PreparedStatement JDBC object.
*/
public PreparedStatement prepareStatement(String sql) throws SQLException
{
return lowLevelConnection.prepareStatement(sql);
}
/**
* This method creates a SQL statement
*
* @see prepareStatement
*
* @param none
*
* @return Statement JDBC object.
*/
public Statement createStatement() throws SQLException
{
return lowLevelConnection.createStatement();
}
/**
* This method executes a statement.
* - Execute DML
* - if error occurs push status onto current state stack
*
* @see createStatement
* @see prepareStatement
*
* @param statement JDBC object
* @param sql database DML string.
*
* @return int number of rows updated.
*/
public int executeStatement(Statement statement, String sql) throws SQLException
{
int rUpdated=0;
try {
if (statement instanceof PreparedStatement){
rUpdated=((PreparedStatement)statement).executeUpdate();
}
else if(statement instanceof Statement){
rUpdated=statement.executeUpdate(sql);
}
return rUpdated;
}
catch (SQLException ex) {
if (!m_TransactionState.empty()) {
Boolean state = (Boolean)m_TransactionState.peek();
if (state.booleanValue()) {
m_TransactionState.pop();
m_TransactionState.push(new Boolean(false));
}
}
throw ex;
}
}
/**
* This method executes a query.
* - Execute DML
* - if error occurs push status onto current state stack
*
* @see createStatement
* @see prepareStatement
*
* @param statement JDBC object
* @param sql database query string.
*
* @return ResultSet result of query.
*/
public ResultSet executeQuery(Statement statement, String sql) throws SQLException
{
m_Statement = statement;
ResultSet result = null;
try {
if (statement instanceof PreparedStatement){
result = ((PreparedStatement)statement).executeQuery();
}
else if(statement instanceof Statement){
result = statement.executeQuery(sql);
}
return result;
}
catch (SQLException ex) {
if (!m_TransactionState.empty()) {
Boolean state = (Boolean)m_TransactionState.peek();
if (state.booleanValue()) {
m_TransactionState.pop();
m_TransactionState.push(new Boolean(false));
}
}
throw ex;
}
}
/**
* This method will be called whenever an attempt to connect to a database fails.
* The default behavior is to return false which will abort the connection. Descendents
* can override this method to provide specific connection failure handling by
* prompting the user for a new url, userName, or password. Set the properties with
* the appropriate setter method and return true. Returning false will
* abort the connection. An integer retries is provided to limit the number of
* connection attempts.
*
* @see Connection#connect
*
* @param retries The number of times a connection was attempted.
* @param e The SQLException thrown for the connect failure.
*
* @return boolean A false aborts the connection attempt. A true will initiate
* another connection attempt using the new userName, password,
* or url that may have been set within this method.
*/
public void connectFailed (ConnectFailedEvent event)
{
try {
Class clazz = Class.forName(m_ConnectFailedListener);
ConnectFailedListener listener = (ConnectFailedListener)clazz.newInstance();
listener.connectFailed(event);
}
catch (Exception ex) {
// No point in telling we can't tell
}
Vector listeners;
try {
synchronized(this) {
listeners = (Vector)m_ConnectFailedListeners.clone();
}
for(int i = 0; i < listeners.size(); i++) {
((ConnectFailedListener)listeners.elementAt(i)).connectFailed(event);
}
}
catch(Exception ex) {
// No point in telling we can't tell
}
}
private String m_ConnectFailedListener = "symantec.itools.db.beans.jdbc.DefaultConnectFailedListener";
public void setConnectFailedListener(String listener)
{
m_ConnectFailedListener = listener;
}
public String getConnectFailedListener()
{
return m_ConnectFailedListener;
}
/**
* Commits all changes to the database.
*
* @see java.sqlConnection#commit
*
* @exception SQLException
*/
public synchronized void commit() throws SQLException
{
try {
if (getSQLConnection() != null) {
getSQLConnection().commit();
}
else {
throw new SQLException("Connection is closed");
}
}
catch (SQLException e) {
handleException (e);
}
}
/**
* Rollback all changes to the database.
*
* @see java.sql.Connection#rollback
*
* @exception SQLException
*/
public synchronized void rollback() throws SQLException
{
try {
if (getSQLConnection() != null) {
getSQLConnection().rollback();
}
else {
throw new SQLException("Connection is closed");
}
}
catch (SQLException e) {
handleException (e);
}
}
/**
* Returns the metadata of the connection.
*
* @see java.sql.Connection#getMetaData
* @see java.sql.DatabaseMetaData
*
*
* @return java.sql.DatabaseMetaData
* @exception SQLException
*/
public synchronized DatabaseMetaData getMetaData() throws SQLException
{
java.sql.DatabaseMetaData md = null ;
connect();
try {
if (getSQLConnection() != null) {
md = getSQLConnection().getMetaData();
}
else {
throw new SQLException("Connection is closed");
}
}
catch (SQLException e) {
handleException (e);
}
return md ;
}
//Accessors/Modifiers
/**
* Sets the identifier property. The identifier is an optional property of the Connection.
* If an identifier property is not defined, then the Connection
* will be identified by the standard combination of other properties.
*
* @param identifier. The string used to identify this connection.
*
*/
public void setIdentifier (String value) {
identifier = value;
}
/**
* Gets the identifier property.
*
* @return The value of the identifier property.
*/
public String getIdentifier () {
return identifier;
}
/**
* Sets the driverName property. The property is bound, so a PropertyChangeEvent will
* be sent to registered ProperyChange listeners. The driverName is an optional
* property of the Connection. If a driverName property is not defined, then it is
* up to the user of the bean to register the appropriate java.sql.Driver object
* with the DriverManager prior to calling connect.
*
* @see Connection#connect
* @see java.sql.DriverManager
* @see java.sql.Driver
*
* @param driverName. The fully qualified classname of an object that has
implemented the java.sql.Driver interface.
*
*/
public void setDriverName (String driverName)
{
if (java.beans.Beans.isDesignTime()) {
processPropertyChange(PROP_DRIVERNAME,this.driverName,driverName);
}
this.driverName = driverName ;
}
/**
* Gets the driverName property.
*
* @return The value of the driverName property.
*/
public String getDriverName () {
return driverName ;
}
/**
* Sets the url property. The property is bound, so a PropertyChangeEvent will
* be sent to registered ProperyChange listeners. The database url is in the
* form jdbc:subprotocol:subname.
*
* @see Connection#connect
* @see java.sql.DriverManager
* @see java.sql.Driver
*
* @param url The databse url
*
*/
public void setURL (String url)
{
if (java.beans.Beans.isDesignTime()) {
processPropertyChange(PROP_URL,this.url,url);
}
this.url = url;
}
/**
* Gets the url property.
*
* @return The value of the url property.
*/
public String getURL () {
return url ;
}
/**
* Sets the userName property. The property is bound, so a PropertyChangeEvent will
* be sent to registered ProperyChange listeners. The userName property is an optional
* property. If the value is not set, no user property will be added to connection
* properties in getConnectionProps. Note: an empty userName may result in a failure
* to connect. Override the connectFailed method to obtain a userName dynamically during
* the connection process.
*
* @see Connection#connect
* @see Connection#connectFailed
* @see Connection#getConnectionProps
*
* @param userName The name of the user.
*
*/
public void setUserName (String userName)
{
if (java.beans.Beans.isDesignTime()) {
processPropertyChange(PROP_USERNAME,this.userName,userName);
}
this.userName = userName ;
}
/**
* Gets the userName property.
*
* @return The value of the userName property.
*/
public String getUserName () {
return userName;
}
/**
* Sets the password property. The property is bound, so a PropertyChangeEvent will
* be sent to registered ProperyChange listeners. The password property is an optional
* property. If the value is not set, no password property will be added to connection
* properties in getConnectionProps. Note: an empty password may result in a failure
* to connect. Override the connectFailed method to obtain a password dynamically during
* the connection process.
*
* @see Connection#connect
* @see Connection#connectFailed
* @see Connection#getConnectionProps
*
* @param password The password for the user.
*/
public void setPassword (String password)
{
if (java.beans.Beans.isDesignTime()) {
processPropertyChange(PROP_PASSWORD,this.password,password);
}
this.password = password ;
}
/**
* Gets the password property.
*
* @return The value of the password property.
*/
public String getPassword () {
return password;
}
/**
* Sets the catalog property. The property is bound, so a PropertyChangeEvent will
* be sent to registered ProperyChange listeners. This property will be sent to
* the database if a connection is established.
*
* @see java.sql.Connection#setCatalog
*
* @param catalog The catalog name.
*
* @exception SQLException
*/
public synchronized void setCatalog (String catalog) throws SQLException
{
if (java.beans.Beans.isDesignTime()) {
processPropertyChange(PROP_CATALOG,this.catalog,catalog);
}
this.catalog = catalog ;
try {
if (lowLevelConnection != null) {
lowLevelConnection.setCatalog(catalog) ;
}
}
catch (SQLException e) {
handleException (e);
}
}
/**
* Gets the catalog property. If a database connection is established, the catalog
* property will be set to the catalog returned from java.sql.Connection.getCatalog().
*
* @see java.sql.Connection#getCatalog
*
* @return the value of the catalog property.
* @exception SQLException
*/
public synchronized String getCatalog () throws SQLException
{
try {
if (lowLevelConnection != null) {
catalog = lowLevelConnection.getCatalog();
}
}
catch (SQLException e) {
handleException (e);
}
return catalog;
}
/**
* Sets the autoCommit property. The property is bound, so a PropertyChangeEvent will
* be sent to registered ProperyChange listeners. This property will be sent to
* the database if a connection is established.
*
* @see java.sql.Connection#setAutoCommit
*
* @param autoCommit The autocommit flag.
*
* @exception SQLException
*/
public synchronized void setAutoCommit (boolean autoCommit)
throws SQLException
{
if (java.beans.Beans.isDesignTime()) {
processPropertyChange(PROP_AUTOCOMMIT,
new Boolean(this.autoCommit),new Boolean(autoCommit));
}
this.autoCommit = autoCommit ;
try {
if (lowLevelConnection != null) {
lowLevelConnection.setAutoCommit(autoCommit) ;
}
}
catch (SQLException e) {
handleException (e);
}
}
/**
* Gets the autoCommit property. If a database connection is established, the autoCommit
* property will be set to the autoCommit returned from java.sql.Connection.getAutoCommit().
*
* @see java.sql.Connection#getAutoCommit
*
* @return the value of the autocommit property.
* @exception SQLException
*/
public synchronized boolean isAutoCommit()
{
try {
if (getSQLConnection() != null) {
autoCommit = getSQLConnection().getAutoCommit();
}
}
catch (SQLException e) {
System.out.println("Warning: isAutoCommit was returning a corrupted value: " + e.getMessage());
}
return autoCommit ;
}
/**
* Sets the readOnly property. The property is bound, so a PropertyChangeEvent will
* be sent to registered ProperyChange listeners. This property will be sent to
* the database if a connection is established.
*
* @see java.sql.Connection#setReadOnly
*
* @param readOnly The readOnly flag.
*
* @exception SQLException
*/
public synchronized void setReadOnly (boolean readOnly)
throws SQLException
{
if (java.beans.Beans.isDesignTime()) {
processPropertyChange(PROP_READONLY,
new Boolean(this.readOnly),new Boolean(readOnly));
}
this.readOnly = readOnly ;
try {
if (lowLevelConnection != null) {
lowLevelConnection.setReadOnly(readOnly) ;
}
}
catch (SQLException e) {
handleException (e);
}
}
/**
* Gets the readOnly property. If a database connection is established, the readOnly
* property will be set to the readOnly returned from java.sql.Connection.isReadOnly().
*
* @see java.sql.Connection#isReadOnly
*
* @return the value of the readOnly property.
* @exception SQLException
*/
public synchronized boolean isReadOnly () throws SQLException
{
try {
if (getSQLConnection() != null)
readOnly = getSQLConnection().isReadOnly();
}
catch (SQLException e) {
handleException (e);
}
return readOnly ;
}
/**
* Gets the readOnly property. If a database connection is established, the readOnly
* property will be set to the readOnly returned from java.sql.Connection.isReadOnly().
*
* @see java.sql.Connection#isReadOnly
*
* @return the value of the readOnly property.
* @exception SQLException
*/
public synchronized boolean getReadOnly () throws SQLException
{
return isReadOnly() ;
}
/**
* Sets the transactionIsolation property. The property is bound, so a PropertyChangeEvent will
* be sent to registered ProperyChange listeners. This property will be sent to
* the database if a connection is established.
*
* @see java.sql.Connection#setTransactionIsolation
*
* @param TI The transactionIsolationLevel.
* TRANSACTION_NONE = 0;
* TRANSACTION_READ_UNCOMMITTED = 1;
* TRANSACTION_READ_COMMITTED = 2;
* TRANSACTION_REPEATABLE_READ = 4;
* TRANSACTION_SERIALIZABLE = 8;
*
* @exception SQLException
*/
/**
* Transactions are not supported.
*/
public final static int TRANSACTION_NONE = 0;
/**
* Dirty reads, non-repeatable reads and phantom reads can occur.
*/
public final static int TRANSACTION_READ_UNCOMMITTED = 1;
/**
* Dirty reads are prevented; non-repeatable reads and phantom
* reads can occur.
*/
public final static int TRANSACTION_READ_COMMITTED = 2;
/**
* Dirty reads and non-repeatable reads are prevented; phantom
* reads can occur.
*/
public final static int TRANSACTION_REPEATABLE_READ = 4;
/**
* Dirty reads, non-repeatable reads and phantom reads are prevented.
*/
public final static int TRANSACTION_SERIALIZABLE = 8;
/**
* Use the drivers default level
*/
public final static int TRANSACTION_DEFAULT = 16;
public synchronized void setTransactionIsolation (int TI)
throws SQLException
{
if (java.beans.Beans.isDesignTime()) {
processPropertyChange(PROP_TRANS_ISOLATION,
new Integer(transactionIsolation), new Integer(TI));
}
transactionIsolation = TI;
if (lowLevelConnection != null) {
try {
int currentLevel = lowLevelConnection.getTransactionIsolation();
if (transactionIsolation == TRANSACTION_DEFAULT) {
transactionIsolation = defaultTransactionIsolation;
}
if (transactionIsolation != currentLevel) {
lowLevelConnection.setTransactionIsolation(transactionIsolation) ;
}
}
catch (SQLException e) {
handleException (e);
}
}
}
/**
* Gets the transactionIsolation property. If a database connection is established, the
* transactionIsolation property will be set to the value returned from
* java.sql.Connection.getTransactionIsolation().
*
* @see java.sql.Connection#getTransactionIsolation
*
* @return the value of the property.
* @exception SQLException
*/
public synchronized int getTransactionIsolation () throws SQLException
{
try {
if (getSQLConnection() != null)
transactionIsolation = getSQLConnection().getTransactionIsolation();
}
catch (SQLException e) {
handleException (e);
}
return transactionIsolation ;
}
/**
* Sets the ConnectionClosed property. The property is constrained, so a VetoableChangeEvent will
* be sent to registered VetoableChange listeners. This property is a runtime only property.
* Setting this value to true will close the database connection. Registered listeners can
* veto the change if they are currently using the database connection.
*
* NOTE: Once BeanInfo object is created, this method should be renamed.!!!!
*
* @see java.sql.Connection#close
*
* @param close The close flag. A true value will close the database connection.
A false value does nothing.
*
* @exception SQLException
*/
public synchronized void setConnectionClosed(boolean close)
throws PropertyVetoException, SQLException
{
//I don't like this code or method
//Revisit it.
try {
if(isConnectionClosed() == close || close == false)
return ;
if (getSQLConnection() != null) {
processVetoableChange(JdbcConnection.PROP_CONNCLOSED,
new Boolean(false),new Boolean(true));
getSQLConnection().close();
lowLevelConnection = null ;
processPropertyChange(JdbcConnection.PROP_CONNCLOSED,
new Boolean(false),new Boolean(true));
}
}
catch (SQLException e) {
handleException (e);
}
}
/**
* Gets the connectionClosed property. If a database connection is established, the
* connectionClosed property will be set to the value returned from
* java.sql.Connection.isClosed() method. This property is a runtime property.
*
* @see java.sql.Connection#isClosed()
*
* @return the value of the connectionClosed property.
* @exception SQLException
*/
public synchronized boolean isConnectionClosed() throws SQLException
{
boolean closed = true ;
try {
if (getSQLConnection() != null)
closed = getSQLConnection().isClosed();
if (closed)
lowLevelConnection = null;
}
catch (SQLException e) {
handleException (e);
}
return closed ;
}
//Event listeners
/**
* Implementation of the PropertyChangeListener interface. Connection objects that
* have thier sharable property set to true, listen to other Connection objects in
* order to be notified of property changes. Descendents of Connection who implement
* the propertyChange method should call this method to maintain sharable logic.
*
* @see Connection#setSharable
*
* @param evt. The PropertyChangeEvent descibing the property that was changed.
*
*/
public void propertyChange (PropertyChangeEvent evt) {
super.propertyChange(evt);
if (evt.getSource() == this )
return ;
}
//Event sources
/**
* Adds ConnectFailedListener to internal list so
* that they could be sent ConnectFailedEvents.
*
* @param listener. An object implementing the listener interface.
*
*/
public synchronized void addConnectFailedListener(ConnectFailedListener listener)
{
m_ConnectFailedListeners.addElement(listener);
}
/**
* Removes ConnectFailedListeners from an internal list.
* The object will no longer be sent ConnectFailedEvents.
*
* @param listener. The ConnectFailedListener to remove.
*
*/
public synchronized void removeConnectFailedListener(ConnectFailedListener listener)
{
m_ConnectFailedListeners.removeElement(listener);
}
//Serialization
/**
* Implementation of the ObjectInputValidation interface. During the de-serialization
* process, registered ObjectInputValidation objects will have the validateObject method
* called after the object and its graph are completely de-serialized. Connection
* and their descendents should verify that the de-serialized object is of a version
* that is compatible with the current implementation. Each level of the hierarchy should
* provide their own versioning information. Descendents should check their version first
* and then call their superclass's validateObject method. Connection will verify its version
* and then check call JDBCBean.validateObject().
*
* If the autoStart property is true, doAutoStart() will be called by JDBCBean.
*
* @see JDBCBean#setAutoStart
* @see JDBCBean#doAutoStart
* @see Connection#connect
*
*
* @exception InvalidObjectException
*/
public void validateObject () throws InvalidObjectException {
//Check this object first, then call parent
if (!version.equals(JdbcConnection.CURRENTVERSION))
throw new InvalidObjectException ("Serialized version " +
version + "is not compatible with Connection version " +
JdbcConnection.CURRENTVERSION);
//check superclass for valid object
super.validateObject();
}
//PROTECTED SECTION
//Static Declarations
//Programatic property names -- Not localizable.
protected static String PROP_DRIVERNAME = "driverName" ;
protected static String PROP_URL = "url" ;
protected static String PROP_USERNAME = "userName" ;
protected static String PROP_PASSWORD = "password" ;
protected static String PROP_CATALOG = "catalog" ;
protected static String PROP_AUTOCOMMIT = "autoCommit" ;
protected static String PROP_READONLY = "readOnly" ;
protected static String PROP_CONNCLOSED = "connectionClosed" ;
protected static String PROP_TRANS_ISOLATION = "transactionIsolationLevel";
//Constructors
//Methods
/**
* This method will be called by the connect() method to return a Properties object
* containing java.sql.Driver specific connection properties. By default, this method
* returns a Properties object with the userName and password properties. Descendents of
* Connection can override this method to add additional Driver properties.
*
* @see Connection#connect
*
* @return A Properties object holding JDBC Connection properties.
*/
protected java.util.Properties getConnectionProps () {
java.util.Properties p = new Properties();
if (getUserName() != null) {
p.put("user", getUserName());
}
if (getPassword() != null) {
p.put("password", getPassword());
}
return p ;
}
/**
* This method will be called during the de-serialization process if the
* autoStart property is true. Descendents can override this method if they want
* to be notified when to go 'live'. Processing should be kept to a minimum or
* done in a separate thread. Exceptions should be suppressed to allow
* de-serialization to complete.
*
* Connection objects will attempt to establish a database connection by calling
* the connect() method. This is done in a separate thread to enable de-serialization
* to continue.
*
*/
protected void doAutoStart() {
//Connect to the database in another thread.
//so that deserialization can continue.
//Anonymous Inner class works well here. The class is defined
// and started. The run method will simply callback to this
//connection from its thread. The inner class has the connection
// as its outer scope so it has complete access.
new Thread() {
public void run () {
try {
connect();
}
catch (SQLException e) {
//eat the exception so de-serialization will continue
printMessage ("Attempt to connect to database " + getURL() + " via Driver "
+ getDriverName() + " failed: " + e.toString());
//insure handle is null
lowLevelConnection = null ;
}
} // end run()
}.start(); // start() the thread running
}
//Accessors/Modifiers
/** This method returns the JDBC connection object controlling the database connection.
*/
public synchronized java.sql.Connection getSQLConnection () {
return lowLevelConnection ;
}
//PRIVATE SECTION
//Static Declarations
//Connection version string
static private String CURRENTVERSION = "0.02" ;
//Serialization
/**
* During the serialization process, ObjectOutputStream will call this method.
* By default, ObjectOutputStream.defaultWriteObject is called.
*
* @param stream The ObjectOutputStream controlling the serialization.
*/
private void writeObject (ObjectOutputStream stream) throws IOException {
stream.defaultWriteObject();
}
/**
* During the de-serialization process, ObjectInputStream will call this method.
* By default, Connection calls ObjectInputStream.defaultReadObject().
*
* @param stream The ObjectInputStream controlling the de-serialization.
*
* @exception ClassNotFoundException, IOException
*/
private void readObject (ObjectInputStream stream) throws ClassNotFoundException,
IOException {
stream.defaultReadObject();
}
//Members
private String version = JdbcConnection.CURRENTVERSION ;
private String driverName = "symantec.itools.db.jdbc.Driver";
private String url = "";
private String userName = "";
private String password = "";
private boolean autoCommit = true;
private int transactionIsolation = TRANSACTION_DEFAULT;
private transient int defaultTransactionIsolation = TRANSACTION_DEFAULT;
private boolean readOnly = false;
private String catalog = "";
private String identifier = "jdbcConnection1";
private transient Vector m_ConnectFailedListeners = new Vector();
private transient Stack m_AutoCommitMode = new Stack();
private transient Stack m_TransactionState = new Stack();
private transient Statement m_Statement = null;
//Reference to JDBC Connection object.
private transient java.sql.Connection lowLevelConnection = null;
}