001 /* 002 * Copyright 2001,2004 The Apache Software Foundation. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 package org.apache.commons.scaffold.sql; 018 019 020 import java.sql.Connection; 021 import java.sql.SQLException; 022 023 import javax.naming.Context; 024 import javax.naming.InitialContext; 025 import javax.naming.NamingException; 026 import javax.sql.DataSource; 027 028 029 /** 030 * Base class for SQL connection adaptors. May be used as-is or subclassed. 031 * <p> 032 * This object does not provide any type of connection pooling. 033 * It simply provides a standard means for obtaining a connection 034 * whatever connection pool your application needs. 035 * Scaffold classes in the SQL package call this object internally. 036 * <p> 037 * To use as-is, a DataSource compliant connection pool must be 038 * available as "DATA_SOURCE" via JNDI. A subclass can 039 * locate the pool under any name by any means necessary. 040 *<p> 041 * A <code>ConnectionAdaptor</code> can be instantiated once at 042 * start-up, either from main() or via a servlet, like the 043 * Scaffold ConnectionServlet. 044 * Objects needing a connection can then call the static 045 * method 046 * <code>ConnectionAdaptor.getPool().getConnection()</code>. 047 * <p> 048 * Most implementations will expect callers to use and 049 * close the connections promptly, since they would 050 * usually be part of a pool. 051 * <p> 052 * Subclasses can provide their own resource name or 053 * getConnection() method, and a new constructor to 054 * set the protected pool field to their own 055 * instance. See <code>PoolmanAdaptor</code> for an example. 056 * 057 * @see org.apache.commons.scaffold.http.ConnectionServlet 058 * @see org.apache.commons.scaffold.sql.PoolmanAdaptor 059 * @author Ted Husted 060 * @version $Revision: 155464 $ $Date: 2005-02-26 13:26:54 +0000 (Sat, 26 Feb 2005) $ 061 */ 062 public class ConnectionAdaptor { 063 064 065 // ------------------------------------------------------------ message 066 067 /** 068 * A message for an exception if pool returns null. 069 */ 070 private String message = "Connection pool " + 071 "not available. Check your configuration."; 072 073 074 /** 075 * Return a message for an exception if pool returns null. 076 * 077 * @return Message for an exception if pool returns null 078 */ 079 protected String getMessage() { 080 return this.message; 081 } 082 083 084 /** 085 * Set a message for an exception if pool returns null. 086 * Adaptor subclasses can call this from their constructor. 087 * 088 * @param Message The message for an exception if pool returns null 089 */ 090 protected void setMessage(String message) { 091 this.message = message; 092 } 093 094 095 // ---------------------------------------------------------------- key 096 097 098 /** 099 * 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