1
0
mirror of https://github.com/postgres/postgres.git synced 2025-05-05 09:19:17 +03:00
postgres/src/interfaces/jdbc/org/postgresql/PostgresqlDataSource.java
Bruce Momjian 960c186184 the bug was not fixed in the snapshot of November 5th. Also the enterprise
edition of the driver did not compile. I have fixed both issues again. I have
attached the modified files to this email, maybe you can check them into the
repository. (Fixes are marked with //FIXME). Enterprise edition driver now
compiles and seems to work.

Jan Thomae
2000-11-10 22:06:26 +00:00

604 lines
17 KiB
Java

/**
* Redistribution and use of this software and associated documentation
* ("Software"), with or without modification, are permitted provided
* that the following conditions are met:
*
* 1. Redistributions of source code must retain copyright
* statements and notices. Redistributions must also contain a
* copy of this document.
*
* 2. Redistributions in binary form must reproduce the
* above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. The name "Exolab" must not be used to endorse or promote
* products derived from this Software without prior written
* permission of Exoffice Technologies. For written permission,
* please contact info@exolab.org.
*
* 4. Products derived from this Software may not be called "Exolab"
* nor may "Exolab" appear in their names without prior written
* permission of Exoffice Technologies. Exolab is a registered
* trademark of Exoffice Technologies.
*
* 5. Due credit should be given to the Exolab Project
* (http://www.exolab.org/).
*
* THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Copyright 1999 (C) Exoffice Technologies Inc. All Rights Reserved.
*
* $Id: PostgresqlDataSource.java,v 1.2 2000/11/10 22:06:26 momjian Exp $
*/
package org.postgresql;
import java.io.PrintWriter;
import java.io.Serializable;
import java.util.Properties;
import java.util.Hashtable;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.DriverManager;
import java.rmi.Remote;
import javax.sql.DataSource;
import javax.naming.Referenceable;
import javax.naming.Reference;
import javax.naming.StringRefAddr;
import javax.naming.RefAddr;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.NamingException;
import javax.naming.spi.ObjectFactory;
// FIXME
//import postgresql.util.PSQLException;
//import postgresql.xa.XADataSourceImpl;
import org.postgresql.util.PSQLException;
import org.postgresql.xa.XADataSourceImpl;
//---------
/**
* Implements a JDBC 2.0 {@link javax.sql.DataSource} for the
* PostgreSQL driver with JNDI persistance support. XA and pooled
* connection support is also available, but the application must
* used the designated DataSource interface to obtain them.
* <p>
* The supported data source properties are:
* <pre>
* description (optional)
* databaseName (required)
* loginTimeout (optional)
* user (optional)
* password (optional)
* serverName (optional)
* portNumber (optional)
* transactionTimeout (optional for XA connections)
* </pre>
* This data source may be serialized and stored in a JNDI
* directory. Example of how to create a new data source and
* register it with JNDI:
* <pre>
* PostgresqlDataSource ds;
* InitialContext ctx;
*
* ds = new PostgresqlDataSource();
* ds.setDatabaseName( "test" );
* ds.setUser( "me" );
* ds.setPassword( "secret" );
* ctx = new InitialContext();
* ctx.rebind( "/comp/jdbc/test", ds );
* </pre>
* Example for obtaining the data source from JNDI and
* opening a new connections:
* <pre>
* InitialContext ctx;
* DataSource ds;
*
* ctx = new InitialContext();
* ds = (DataSource) ctx.lookup( "/comp/jdbc/test" );
* ds.getConnection();
* </pre>
*
*
* @author <a href="arkin@exoffice.com">Assaf Arkin</a>
* @version 1.0
* @see XADataSourceImpl
* @see DataSource
* @see Connection
*/
public class PostgresqlDataSource
extends XADataSourceImpl
implements DataSource, Referenceable,
ObjectFactory, Serializable
{
/**
* Holds the timeout for opening a new connection, specified
* in seconds. The default is obtained from the JDBC driver.
*/
private int _loginTimeout;
/**
* Holds the user's account name.
*/
private String _user;
/**
* Holds the database password.
*/
private String _password;
/**
* Holds the name of the particular database on the server.
*/
private String _databaseName;
/**
* Description of this datasource.
*/
private String _description = "PostgreSQL DataSource";
/**
* Holds the database server name. If null, this is
* assumed to be the localhost.
*/
private String _serverName;
/**
* Holds the port number where a server is listening.
* The default value will open a connection with an
* unspecified port.
*/
private int _portNumber = DEFAULT_PORT;
/**
* The default port number. Since we open the connection
* without specifying the port if it's the default one,
* this value can be meaningless.
*/
private static final int DEFAULT_PORT = 0;
/**
* Holds the log writer to which all messages should be
* printed. The default writer is obtained from the driver
* manager, but it can be specified at the datasource level
* and will be passed to the driver. May be null.
*/
private transient PrintWriter _logWriter;
/**
* Each datasource maintains it's own driver, in case of
* driver-specific setup (e.g. pools, log writer).
*/
// FIXME
// private transient postgresql.Driver _driver;
private transient org.postgresql.Driver _driver;
//---------
public PostgresqlDataSource()
{
_logWriter = DriverManager.getLogWriter();
_loginTimeout = DriverManager.getLoginTimeout();
}
public Connection getConnection()
throws SQLException
{
// Uses the username and password specified for the datasource.
return getConnection( _user, _password );
}
public synchronized Connection getConnection( String user, String password )
throws SQLException
{
Connection conn;
Properties info;
String url;
if ( _driver == null ) {
try {
// Constructs a driver for use just by this data source
// which will produce TwoPhaseConnection-s. This driver
// is not registered with the driver manager.
// FIXME
// _driver = new postgresql.Driver();
_driver = new org.postgresql.Driver();
//-----------
//FIXME
// _driver.setLogWriter( _logWriter );
// Method seems to be unavailable. Just commented it out.
//----------
} catch ( SQLException except ) {
if ( _logWriter != null )
_logWriter.println( "DataSource: Failed to initialize JDBC driver: " + except );
throw except;
}
}
// Use info to supply properties that are not in the URL.
info = new Properties();
info.put( "loginTimeout", Integer.toString( _loginTimeout ) );
// DriverManager will do that and not rely on the URL alone.
if ( user == null ) {
user = _user;
password = _password;
}
if ( user == null || password == null )
throw new PSQLException( "postgresql.ds.userpswd" );
info.put( "user", user );
info.put( "password", password );
if ( _serverName != null )
info.put( "PGHOST", _serverName );
if ( _portNumber != DEFAULT_PORT )
info.put( "PGPORT", Integer.toString( _portNumber ) );
if ( _databaseName != null )
info.put( "PGDBNAME", _databaseName );
// Construct the URL suitable for this driver.
url = "jdbc:postgresql:";
// Attempt to establish a connection. Report a successful
// attempt or a failure.
try {
conn = _driver.connect( url, info );
// FIXME
// if ( ! ( conn instanceof postgresql.jdbc2.Connection ) ) {
if ( ! ( conn instanceof org.postgresql.jdbc2.Connection ) ) {
//--------
if ( _logWriter != null )
_logWriter.println( "DataSource: JDBC 1 connections not supported" );
throw new PSQLException( "postgresql.ds.onlyjdbc2" );
}
} catch ( SQLException except ) {
if ( _logWriter != null )
_logWriter.println( "DataSource: getConnection failed " + except );
throw except;
}
if ( conn != null && _logWriter != null )
_logWriter.println( "DataSource: getConnection returning " + conn );
return conn;
}
public PrintWriter getLogWriter()
{
return _logWriter;
}
public synchronized void setLogWriter( PrintWriter writer )
{
// Once a log writer has been set, we cannot set it since some
// thread might be conditionally accessing it right now without
// synchronizing.
if ( writer != null ) {
if ( _driver != null )
// FIXME
// _driver.setLogWriter( writer );
// Method seems to be unavailable. Commented it out.
//----------
_logWriter = writer;
}
}
public void setLoginTimeout( int seconds )
{
_loginTimeout = seconds;
}
public synchronized int getLoginTimeout()
{
return _loginTimeout;
}
/**
* Sets the name of the particular database on the server.
* The standard name for this property is <tt>databaseName</tt>.
*
* @param databaseName The name of the particular database on the server
*/
public synchronized void setDatabaseName( String databaseName )
{
if ( databaseName == null )
throw new NullPointerException( "DataSource: Argument 'databaseName' is null" );
_databaseName = databaseName;
}
/**
* Returns the name of the particular database on the server.
* The standard name for this property is <tt>databaseName</tt>.
*
* @return The name of the particular database on the server
*/
public String getDatabaseName()
{
return _databaseName;
}
/**
* Sets the description of this datasource.
* The standard name for this property is <tt>description</tt>.
*
* @param description The description of this datasource
*/
public synchronized void setDescription( String description )
{
if ( description == null )
throw new NullPointerException( "DataSource: Argument 'description' is null" );
_description = description;
}
/**
* Returns the description of this datasource.
* The standard name for this property is <tt>description</tt>.
*
* @return The description of this datasource
*/
public String getDescription()
{
return _description;
}
/**
* Sets the database password.
* The standard name for this property is <tt>password</tt>.
*
* @param password The database password
*/
public synchronized void setPassword( String password )
{
_password = password;
}
/**
* Returns the database password.
* The standard name for this property is <tt>password</tt>.
*
* @return The database password
*/
public String getPassword()
{
return _password;
}
/**
* Sets the port number where a server is listening.
* The standard name for this property is <tt>portNumber</tt>.
*
* @param portNumber The port number where a server is listening
*/
public synchronized void setPortNumber( int portNumber )
{
_portNumber = portNumber;
}
/**
* Returns the port number where a server is listening.
* The standard name for this property is <tt>portNumber</tt>.
*
* @return The port number where a server is listening
*/
public int getPortNumber()
{
return _portNumber;
}
/**
* Sets the database server name.
* The standard name for this property is <tt>serverName</tt>.
*
* @param serverName The database server name
*/
public synchronized void setServerName( String serverName )
{
_serverName = serverName;
}
/**
* Returns the database server name.
* The standard name for this property is <tt>serverName</tt>.
*
* @return The database server name
*/
public String getServerName()
{
return _serverName;
}
/**
* Sets the user's account name.
* The standard name for this property is <tt>user</tt>.
*
* @param user The user's account name
*/
public synchronized void setUser( String user )
{
_user = user;
}
/**
* Returns the user's account name.
* The standard name for this property is <tt>user</tt>.
*
* @return The user's account name
*/
public String getUser()
{
return _user;
}
/**
* Returns true if this datasource and the other are equal.
* The two datasources are equal if and only if they will produce
* the exact same connections. Connection properties like database
* name, user name, etc are comapred. Setup properties like
* description, log writer, etc are not compared.
*/
public synchronized boolean equals( Object other )
{
if ( other == this )
return true;
if ( other == null || ! ( other instanceof PostgresqlDataSource ) )
return false;
PostgresqlDataSource with;
with = (PostgresqlDataSource) other;
if ( _databaseName != null && _databaseName.equals( with._databaseName ) )
if ( _portNumber == with._portNumber &&
( ( _serverName == null && with._serverName == null ) ||
( _serverName != null && _serverName.equals( with._serverName ) ) ) )
if ( ( _user == null && with._user == null ) ||
( _user != null && _password != null && _user.equals( with._user ) &&
_password.equals( with._password ) ) )
return true;
return false;
}
public String toString()
{
if ( _description != null )
return _description;
else {
String url;
url = "jdbc:postgresql:";
if ( _serverName != null ) {
if ( _portNumber == DEFAULT_PORT )
url = url + "//" + _serverName + "/";
else
url = url + "//" + _serverName + ":" + _portNumber + "/";
} else if ( _portNumber != DEFAULT_PORT )
url = url + "//localhost:" + _portNumber + "/";
if ( _databaseName != null )
url = url + _databaseName;
return "DataSource " + url;
}
}
public synchronized Reference getReference()
{
Reference ref;
// We use same object as factory.
ref = new Reference( getClass().getName(), getClass().getName(), null );
// Mandatory properties
ref.add( new StringRefAddr( "description", _description ) );
ref.add( new StringRefAddr( "databaseName", _databaseName ) );
ref.add( new StringRefAddr( "loginTimeout", Integer.toString( _loginTimeout ) ) );
// Optional properties
if ( _user != null )
ref.add( new StringRefAddr( "user", _user ) );
if ( _password != null )
ref.add( new StringRefAddr( "password", _password ) );
if ( _serverName != null )
ref.add( new StringRefAddr( "serverName", _serverName ) );
if ( _portNumber != DEFAULT_PORT )
ref.add( new StringRefAddr( "portNumber", Integer.toString( _portNumber ) ) );
ref.add( new StringRefAddr( "transactionTimeout", Integer.toString( getTransactionTimeout() ) ) );
return ref;
}
public Object getObjectInstance( Object refObj, Name name, Context nameCtx, Hashtable env )
throws NamingException
{
Reference ref;
// Can only reconstruct from a reference.
if ( refObj instanceof Reference ) {
ref = (Reference) refObj;
// Make sure reference is of datasource class.
if ( ref.getClassName().equals( getClass().getName() ) ) {
PostgresqlDataSource ds;
RefAddr addr;
try {
ds = (PostgresqlDataSource) Class.forName( ref.getClassName() ).newInstance();
} catch ( Exception except ) {
throw new NamingException( except.toString() );
}
// Mandatory properties
ds._description = (String) ref.get( "description" ).getContent();
ds._databaseName = (String) ref.get( "databaseName" ).getContent();
ds._loginTimeout = Integer.parseInt( (String) ref.get( "loginTimeout" ).getContent() );
// Optional properties
addr = ref.get( "user" );
if ( addr != null )
ds._user = (String) addr.getContent();
addr = ref.get( "password" );
if ( addr != null )
ds._password = (String) addr.getContent();
addr = ref.get( "serverName" );
if ( addr != null )
ds._serverName = (String) addr.getContent();
addr = ref.get( "portNumber" );
if ( addr != null )
ds._portNumber = Integer.parseInt( (String) addr.getContent() );
addr = ref.get( "transactionTimeout" );
if ( addr != null )
setTransactionTimeout( Integer.parseInt( (String) addr.getContent() ) );
return ds;
} else
throw new NamingException( "DataSource: Reference not constructed from class " + getClass().getName() );
} else if ( refObj instanceof Remote )
return refObj;
else
return null;
}
}