1 /*
2 * Copyright 2001,2004 The Apache Software Foundation.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.commons.scaffold.sql;
18
19
20 import java.sql.Connection;
21 import java.sql.SQLException;
22
23 import javax.naming.Context;
24 import javax.naming.InitialContext;
25 import javax.naming.NamingException;
26 import javax.sql.DataSource;
27
28
29 /**
30 * Base class for SQL connection adaptors. May be used as-is or subclassed.
31 * <p>
32 * This object does not provide any type of connection pooling.
33 * It simply provides a standard means for obtaining a connection
34 * whatever connection pool your application needs.
35 * Scaffold classes in the SQL package call this object internally.
36 * <p>
37 * To use as-is, a DataSource compliant connection pool must be
38 * available as "DATA_SOURCE" via JNDI. A subclass can
39 * locate the pool under any name by any means necessary.
40 *<p>
41 * A <code>ConnectionAdaptor</code> can be instantiated once at
42 * start-up, either from main() or via a servlet, like the
43 * Scaffold ConnectionServlet.
44 * Objects needing a connection can then call the static
45 * method
46 * <code>ConnectionAdaptor.getPool().getConnection()</code>.
47 * <p>
48 * Most implementations will expect callers to use and
49 * close the connections promptly, since they would
50 * usually be part of a pool.
51 * <p>
52 * Subclasses can provide their own resource name or
53 * getConnection() method, and a new constructor to
54 * set the protected pool field to their own
55 * instance. See <code>PoolmanAdaptor</code> for an example.
56 *
57 * @see org.apache.commons.scaffold.http.ConnectionServlet
58 * @see org.apache.commons.scaffold.sql.PoolmanAdaptor
59 * @author Ted Husted
60 * @version $Revision: 155464 $ $Date: 2005-02-26 13:26:54 +0000 (Sat, 26 Feb 2005) $
61 */
62 public class ConnectionAdaptor {
63
64
65 // ------------------------------------------------------------ message
66
67 /**
68 * A message for an exception if pool returns null.
69 */
70 private String message = "Connection pool " +
71 "not available. Check your configuration.";
72
73
74 /**
75 * Return a message for an exception if pool returns null.
76 *
77 * @return Message for an exception if pool returns null
78 */
79 protected String getMessage() {
80 return this.message;
81 }
82
83
84 /**
85 * Set a message for an exception if pool returns null.
86 * Adaptor subclasses can call this from their constructor.
87 *
88 * @param Message The message for an exception if pool returns null
89 */
90 protected void setMessage(String message) {
91 this.message = message;
92 }
93
94
95 // ---------------------------------------------------------------- key
96
97
98 /**
99 * The default DataSource name.
100 */
101 public static final String DATA_SOURCE_KEY = "DATA_SOURCE";
102
103
104 /**
105 * The default JNDI context for applications.
106 */
107 public static final String JNDI_CONTEXT_KEY = "java:comp/env";
108
109
110 /**
111 * The attribute under which our DataSource is stored
112 * [DATA_SOURCE_KEY].
113 */
114 private String key = DATA_SOURCE_KEY;
115
116
117 /**
118 * Return the attribute under which our datasource is stored.
119 * Subclasses may override this method to provide a different key,
120 * or set a new key at construction.
121 */
122 public String getKey() {
123 return this.key;
124 }
125
126
127 /**
128 * The attribute under which our datasource is stored.
129 * Adaptor subclasses can call this method from a constructor
130 * to change the default resource name.
131 */
132 public void setKey(String key) {
133 this.key = key;
134 }
135
136
137 // --------------------------------------------------------- datasource
138
139 /**
140 * Field to store singleton reference to default datasource.
141 *
142 * TODO: Add Map to store reference to other datasoruces.
143 */
144 protected static DataSource datasource;
145
146
147 /**
148 * Return datasource using JNDI lookup. Subclasses may
149 * override this method to provide other means of obtaining
150 * a datasource reference.
151 *
152 * @param key The attribute name for the resource.
153 * If null is passed, null is returned.
154 * @return null or the datasource object related to "key"
155 *
156 * TODO: Add cache to store references to the datasources by key.
157 */
158 protected DataSource getDataSource(String key)
159 throws SQLException {
160
161 if (null==key) return null;
162
163 try {
164
165 Context env = (Context) new
166 InitialContext().lookup(JNDI_CONTEXT_KEY);
167
168 return (DataSource) env.lookup(key);
169
170 }
171
172 catch (NamingException ne) {
173 // Recast naming exception,
174 // since that is what other routines only except
175 // and because another implementation may not generate this.
176 // Should only be an issue during initial setup
177
178 throw new SQLException(ne.getMessage());
179 }
180
181 } // end getDataSource
182
183
184 // --------------------------------------------------------- connection
185
186 /**
187 * Returns a JDBC connection from the default resource.
188 * Calls <code>getDatasource</code> to return the resource
189 * associated with the default attribute name [getKey()].
190 * <p>
191 * The default datasource object is cached and reused in subsequent
192 * calls.
193 *
194 * @return JDBC connection from resource layer.
195 * @exception SQLException on SQL or other errors. May wrap other
196 * exceptions depending on implementation. Will not return null.
197 */
198 public Connection getConnection() throws SQLException {
199
200 if (null==datasource) {
201
202 datasource = getDataSource(getKey());
203
204 if (null==datasource)
205 throw new SQLException(getMessage());
206 }
207
208 return (datasource.getConnection());
209
210 } // end getConnection
211
212
213 /**
214 * Returns a JDBC connection from a connection pool or other
215 * named resource, to be used and closed promptly.
216 * <p>
217 * Default implementation uses JNDI to lookup the resource named by
218 * getResource() ["DATASOURCE"].
219 * Will not return null.
220 *
221 * @return JDBC connection from resource layer.
222 * @exception SQLException on SQL or other errors. May wrap
223 * other exceptions depending on implementation.
224 * @param resource An attribute name for the resource to use for
225 * this connection or null to call getResource()
226 * @return A working connection; will not return null
227 * @exception SQLException On any SQL error or if pool returns null
228 */
229 public Connection getConnection(String key)
230 throws SQLException {
231
232 if (null==key) return getConnection();
233
234 DataSource ds = getDataSource(key);
235
236 if (null==ds)
237 throw new SQLException(getMessage());
238
239 return (ds.getConnection());
240
241 } // end getConnection
242
243
244 // --------------------------------------------------------------- pool
245
246
247 /**
248 * Field to store singleton reference to adaptor pool.
249 * This would usually be private for a singleton,
250 * but adaptor subclasses may set the pool upon initialization.
251 * <p>
252 * <code>if (null==pool) set pool = this</code>.
253 */
254 protected static ConnectionAdaptor pool;
255
256
257 /**
258 * Return adaptor instance to use in acquiring connection.
259 * <p>
260 * This is the main entry method to the object.
261 * Client's should call:<br>
262 * <code>Adaptor.getPool().getConnection()</code>
263 * to acquire a connection from the default pool.
264 */
265 public static ConnectionAdaptor getPool() {
266
267 if (null==pool) pool = new ConnectionAdaptor();
268 return pool;
269
270 } // end getPool
271
272
273 } // end ConnectionAdaptor
274