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