View Javadoc

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