Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit c82fed3

Browse files
author
Dave Cramer
committed
Added DataSource code and tests submitted by Aaron Mulder
1 parent 6410c22 commit c82fed3

File tree

10 files changed

+1572
-0
lines changed

10 files changed

+1572
-0
lines changed
Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
package org.postgresql.jdbc2.optional;
2+
3+
import javax.naming.*;
4+
import java.io.PrintWriter;
5+
import java.sql.*;
6+
7+
/**
8+
* Base class for data sources and related classes.
9+
*
10+
* @author Aaron Mulder (ammulder@chariotsolutions.com)
11+
* @version $Revision: 1.1 $
12+
*/
13+
public abstract class BaseDataSource implements Referenceable {
14+
// Load the normal driver, since we'll use it to actually connect to the
15+
// database. That way we don't have to maintain the connecting code in
16+
// multiple places.
17+
static {
18+
try {
19+
Class.forName("org.postgresql.Driver");
20+
} catch (ClassNotFoundException e) {
21+
System.err.println("PostgreSQL DataSource unable to load PostgreSQL JDBC Driver");
22+
}
23+
}
24+
25+
// Needed to implement the DataSource/ConnectionPoolDataSource interfaces
26+
private transient PrintWriter logger;
27+
// Don't track loginTimeout, since we'd just ignore it anyway
28+
29+
// Standard properties, defined in the JDBC 2.0 Optional Package spec
30+
private String serverName = "localhost";
31+
private String databaseName;
32+
private String user;
33+
private String password;
34+
private int portNumber;
35+
36+
/**
37+
* Gets a connection to the PostgreSQL database. The database is identified by the
38+
* DataSource properties serverName, databaseName, and portNumber. The user to
39+
* connect as is identified by the DataSource properties user and password.
40+
*
41+
* @return A valid database connection.
42+
* @throws SQLException
43+
* Occurs when the database connection cannot be established.
44+
*/
45+
public Connection getConnection() throws SQLException {
46+
return getConnection(user, password);
47+
}
48+
49+
/**
50+
* Gets a connection to the PostgreSQL database. The database is identified by the
51+
* DataAource properties serverName, databaseName, and portNumber. The user to
52+
* connect as is identified by the arguments user and password, which override
53+
* the DataSource properties by the same name.
54+
*
55+
* @return A valid database connection.
56+
* @throws SQLException
57+
* Occurs when the database connection cannot be established.
58+
*/
59+
public Connection getConnection(String user, String password) throws SQLException {
60+
try {
61+
Connection con = DriverManager.getConnection(getUrl(), user, password);
62+
if (logger != null) {
63+
logger.println("Created a non-pooled connection for " + user + " at " + getUrl());
64+
}
65+
return con;
66+
} catch (SQLException e) {
67+
if (logger != null) {
68+
logger.println("Failed to create a non-pooled connection for " + user + " at " + getUrl() + ": " + e);
69+
}
70+
throw e;
71+
}
72+
}
73+
74+
/**
75+
* This DataSource does not support a configurable login timeout.
76+
* @return 0
77+
*/
78+
public int getLoginTimeout() throws SQLException {
79+
return 0;
80+
}
81+
82+
/**
83+
* This DataSource does not support a configurable login timeout. Any value
84+
* provided here will be ignored.
85+
*/
86+
public void setLoginTimeout(int i) throws SQLException {
87+
}
88+
89+
/**
90+
* Gets the log writer used to log connections opened.
91+
*/
92+
public PrintWriter getLogWriter() throws SQLException {
93+
return logger;
94+
}
95+
96+
/**
97+
* The DataSource will note every connection opened to the provided log writer.
98+
*/
99+
public void setLogWriter(PrintWriter printWriter) throws SQLException {
100+
logger = printWriter;
101+
}
102+
103+
/**
104+
* Gets the name of the host the PostgreSQL database is running on.
105+
*/
106+
public String getServerName() {
107+
return serverName;
108+
}
109+
110+
/**
111+
* Sets the name of the host the PostgreSQL database is running on. If this
112+
* is changed, it will only affect future calls to getConnection. The default
113+
* value is <tt>localhost</tt>.
114+
*/
115+
public void setServerName(String serverName) {
116+
if(serverName == null || serverName.equals("")) {
117+
this.serverName = "localhost";
118+
} else {
119+
this.serverName = serverName;
120+
}
121+
}
122+
123+
/**
124+
* Gets the name of the PostgreSQL database, running on the server identified
125+
* by the serverName property.
126+
*/
127+
public String getDatabaseName() {
128+
return databaseName;
129+
}
130+
131+
/**
132+
* Sets the name of the PostgreSQL database, running on the server identified
133+
* by the serverName property. If this is changed, it will only affect
134+
* future calls to getConnection.
135+
*/
136+
public void setDatabaseName(String databaseName) {
137+
this.databaseName = databaseName;
138+
}
139+
140+
/**
141+
* Gets a description of this DataSource-ish thing. Must be customized by
142+
* subclasses.
143+
*/
144+
public abstract String getDescription();
145+
146+
/**
147+
* Gets the user to connect as by default. If this is not specified, you must
148+
* use the getConnection method which takes a user and password as parameters.
149+
*/
150+
public String getUser() {
151+
return user;
152+
}
153+
154+
/**
155+
* Sets the user to connect as by default. If this is not specified, you must
156+
* use the getConnection method which takes a user and password as parameters.
157+
* If this is changed, it will only affect future calls to getConnection.
158+
*/
159+
public void setUser(String user) {
160+
this.user = user;
161+
}
162+
163+
/**
164+
* Gets the password to connect with by default. If this is not specified but a
165+
* password is needed to log in, you must use the getConnection method which takes
166+
* a user and password as parameters.
167+
*/
168+
public String getPassword() {
169+
return password;
170+
}
171+
172+
/**
173+
* Sets the password to connect with by default. If this is not specified but a
174+
* password is needed to log in, you must use the getConnection method which takes
175+
* a user and password as parameters. If this is changed, it will only affect
176+
* future calls to getConnection.
177+
*/
178+
public void setPassword(String password) {
179+
this.password = password;
180+
}
181+
182+
/**
183+
* Gets the port which the PostgreSQL server is listening on for TCP/IP
184+
* connections.
185+
*
186+
* @return The port, or 0 if the default port will be used.
187+
*/
188+
public int getPortNumber() {
189+
return portNumber;
190+
}
191+
192+
/**
193+
* Gets the port which the PostgreSQL server is listening on for TCP/IP
194+
* connections. Be sure the -i flag is passed to postmaster when PostgreSQL
195+
* is started. If this is not set, or set to 0, the default port will be used.
196+
*/
197+
public void setPortNumber(int portNumber) {
198+
this.portNumber = portNumber;
199+
}
200+
201+
/**
202+
* Generates a DriverManager URL from the other properties supplied.
203+
*/
204+
private String getUrl() {
205+
return "jdbc:postgresql://"+serverName+(portNumber == 0 ? "" : ":"+portNumber)+"/"+databaseName;
206+
}
207+
208+
public Reference getReference() throws NamingException {
209+
Reference ref = new Reference(getClass().getName(), PGObjectFactory.class.getName(), null);
210+
ref.add(new StringRefAddr("serverName", serverName));
211+
if (portNumber != 0) {
212+
ref.add(new StringRefAddr("portNumber", Integer.toString(portNumber)));
213+
}
214+
ref.add(new StringRefAddr("databaseName", databaseName));
215+
if (user != null) {
216+
ref.add(new StringRefAddr("user", user));
217+
}
218+
if (password != null) {
219+
ref.add(new StringRefAddr("password", password));
220+
}
221+
return ref;
222+
}
223+
224+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package org.postgresql.jdbc2.optional;
2+
3+
import javax.sql.ConnectionPoolDataSource;
4+
import javax.sql.PooledConnection;
5+
import java.sql.SQLException;
6+
import java.io.Serializable;
7+
8+
/**
9+
* PostgreSQL implementation of ConnectionPoolDataSource. The app server or
10+
* middleware vendor should provide a DataSource implementation that takes advantage
11+
* of this ConnectionPoolDataSource. If not, you can use the PostgreSQL implementation
12+
* known as PoolingDataSource, but that should only be used if your server or middleware
13+
* vendor does not provide their own. Why? The server may want to reuse the same
14+
* Connection across all EJBs requesting a Connection within the same Transaction, or
15+
* provide other similar advanced features.
16+
*
17+
* <p>In any case, in order to use this ConnectionPoolDataSource, you must set the property
18+
* databaseName. The settings for serverName, portNumber, user, and password are
19+
* optional. Note: these properties are declared in the superclass.</p>
20+
*
21+
* <p>This implementation supports JDK 1.3 and higher.</p>
22+
*
23+
* @author Aaron Mulder (ammulder@chariotsolutions.com)
24+
* @version $Revision: 1.1 $
25+
*/
26+
public class ConnectionPool extends BaseDataSource implements Serializable, ConnectionPoolDataSource {
27+
private boolean defaultAutoCommit = false;
28+
29+
/**
30+
* Gets a description of this DataSource.
31+
*/
32+
public String getDescription() {
33+
return "ConnectionPoolDataSource from "+org.postgresql.Driver.getVersion();
34+
}
35+
36+
/**
37+
* Gets a connection which may be pooled by the app server or middleware
38+
* implementation of DataSource.
39+
*
40+
* @throws java.sql.SQLException
41+
* Occurs when the physical database connection cannot be established.
42+
*/
43+
public PooledConnection getPooledConnection() throws SQLException {
44+
return new PooledConnectionImpl(getConnection(), defaultAutoCommit);
45+
}
46+
47+
/**
48+
* Gets a connection which may be pooled by the app server or middleware
49+
* implementation of DataSource.
50+
*
51+
* @throws java.sql.SQLException
52+
* Occurs when the physical database connection cannot be established.
53+
*/
54+
public PooledConnection getPooledConnection(String user, String password) throws SQLException {
55+
return new PooledConnectionImpl(getConnection(user, password), defaultAutoCommit);
56+
}
57+
58+
/**
59+
* Gets whether connections supplied by this pool will have autoCommit
60+
* turned on by default. The default value is <tt>false</tt>, so that
61+
* autoCommit will be turned off by default.
62+
*/
63+
public boolean isDefaultAutoCommit() {
64+
return defaultAutoCommit;
65+
}
66+
67+
/**
68+
* Sets whether connections supplied by this pool will have autoCommit
69+
* turned on by default. The default value is <tt>false</tt>, so that
70+
* autoCommit will be turned off by default.
71+
*/
72+
public void setDefaultAutoCommit(boolean defaultAutoCommit) {
73+
this.defaultAutoCommit = defaultAutoCommit;
74+
}
75+
76+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package org.postgresql.jdbc2.optional;
2+
3+
import javax.naming.spi.ObjectFactory;
4+
import javax.naming.*;
5+
import java.util.Hashtable;
6+
7+
/**
8+
* Returns a DataSource-ish thing based on a JNDI reference. In the case of a
9+
* SimpleDataSource or ConnectionPool, a new instance is created each time, as
10+
* there is no connection state to maintain. In the case of a PoolingDataSource,
11+
* the same DataSource will be returned for every invocation within the same
12+
* VM/ClassLoader, so that the state of the connections in the pool will be
13+
* consistent.
14+
*
15+
* @author Aaron Mulder (ammulder@chariotsolutions.com)
16+
* @version $Revision: 1.1 $
17+
*/
18+
public class PGObjectFactory implements ObjectFactory {
19+
/**
20+
* Dereferences a PostgreSQL DataSource. Other types of references are
21+
* ignored.
22+
*/
23+
public Object getObjectInstance(Object obj, Name name, Context nameCtx,
24+
Hashtable environment) throws Exception {
25+
Reference ref = (Reference)obj;
26+
if(ref.getClassName().equals(SimpleDataSource.class.getName())) {
27+
return loadSimpleDataSource(ref);
28+
} else if (ref.getClassName().equals(ConnectionPool.class.getName())) {
29+
return loadConnectionPool(ref);
30+
} else if (ref.getClassName().equals(PoolingDataSource.class.getName())) {
31+
return loadPoolingDataSource(ref);
32+
} else {
33+
return null;
34+
}
35+
}
36+
37+
private Object loadPoolingDataSource(Reference ref) {
38+
// If DataSource exists, return it
39+
String name = getProperty(ref, "dataSourceName");
40+
PoolingDataSource pds = PoolingDataSource.getDataSource(name);
41+
if(pds != null) {
42+
return pds;
43+
}
44+
// Otherwise, create a new one
45+
pds = new PoolingDataSource();
46+
pds.setDataSourceName(name);
47+
loadBaseDataSource(pds, ref);
48+
String min = getProperty(ref, "initialConnections");
49+
if (min != null) {
50+
pds.setInitialConnections(Integer.parseInt(min));
51+
}
52+
String max = getProperty(ref, "maxConnections");
53+
if (max != null) {
54+
pds.setMaxConnections(Integer.parseInt(max));
55+
}
56+
return pds;
57+
}
58+
59+
private Object loadSimpleDataSource(Reference ref) {
60+
SimpleDataSource ds = new SimpleDataSource();
61+
return loadBaseDataSource(ds, ref);
62+
}
63+
64+
private Object loadConnectionPool(Reference ref) {
65+
ConnectionPool cp = new ConnectionPool();
66+
return loadBaseDataSource(cp, ref);
67+
}
68+
69+
private Object loadBaseDataSource(BaseDataSource ds, Reference ref) {
70+
ds.setDatabaseName(getProperty(ref, "databaseName"));
71+
ds.setPassword(getProperty(ref, "password"));
72+
String port = getProperty(ref, "portNumber");
73+
if(port != null) {
74+
ds.setPortNumber(Integer.parseInt(port));
75+
}
76+
ds.setServerName(getProperty(ref, "serverName"));
77+
ds.setUser(getProperty(ref, "user"));
78+
return ds;
79+
}
80+
81+
private String getProperty(Reference ref, String s) {
82+
RefAddr addr = ref.get(s);
83+
if(addr == null) {
84+
return null;
85+
}
86+
return (String)addr.getContent();
87+
}
88+
89+
}

0 commit comments

Comments
 (0)