001: /*
002: * ====================================================================
003: * JAFFA - Java Application Framework For All
004: *
005: * Copyright (C) 2002 JAFFA Development Group
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or (at your option) any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this library; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020: *
021: * Redistribution and use of this software and associated documentation ("Software"),
022: * with or without modification, are permitted provided that the following conditions are met:
023: * 1. Redistributions of source code must retain copyright statements and notices.
024: * Redistributions must also contain a copy of this document.
025: * 2. Redistributions in binary form must reproduce the above copyright notice,
026: * this list of conditions and the following disclaimer in the documentation
027: * and/or other materials provided with the distribution.
028: * 3. The name "JAFFA" must not be used to endorse or promote products derived from
029: * this Software without prior written permission. For written permission,
030: * please contact mail to: jaffagroup@yahoo.com.
031: * 4. Products derived from this Software may not be called "JAFFA" nor may "JAFFA"
032: * appear in their names without prior written permission.
033: * 5. Due credit should be given to the JAFFA Project (http://jaffa.sourceforge.net).
034: *
035: * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
036: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
037: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
038: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
039: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
040: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
041: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
042: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
043: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
044: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
045: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
046: * SUCH DAMAGE.
047: * ====================================================================
048: */
049:
050: package org.jaffa.persistence.engines.jdbcengine.datasource;
051:
052: import java.io.IOException;
053: import java.sql.Connection;
054: import java.sql.SQLException;
055: import javax.naming.Context;
056: import javax.naming.InitialContext;
057: import javax.naming.NamingException;
058: import javax.sql.DataSource;
059: import org.apache.log4j.Logger;
060:
061: /** This is a JNDI specific implementation of IConnectionFactory.
062: * It assumes that the Jdbc Engine is being executed in the same VM in which a DataSource has already been defined.
063: * It will use JNDI to get a handle on the DataSource resource and a Connection from that DataSource.
064: *
065: * @author GautamJ
066: */
067: public class JndiDataSourceConnectionFactory implements
068: IConnectionFactory {
069:
070: private static final Logger log = Logger
071: .getLogger(JndiDataSourceConnectionFactory.class);
072:
073: // This is the number of times the createConnection will try to acquire a connection from the pool
074: private static final int RETRY_LIMIT = 10;
075:
076: // The default wait time, between connection retries, in milliseconds
077: private static final long DEFAULT_WAIT_TIME = 2000;
078:
079: // **************************************
080: // Properties for this Connection Factory
081: // **************************************
082: private String m_jndiDataSourceName;
083: private Long m_maxWait;
084:
085: /** Getter for property jndiDataSourceName.
086: * @return Value of property jndiDataSourceName.
087: *
088: */
089: public String getJndiDataSourceName() {
090: return m_jndiDataSourceName;
091: }
092:
093: /** Setter for property jndiDataSourceName.
094: * @param jndiDataSourceName New value of property jndiDataSourceName.
095: *
096: */
097: public void setJndiDataSourceName(String jndiDataSourceName) {
098: if (jndiDataSourceName == null
099: || jndiDataSourceName.length() == 0)
100: m_jndiDataSourceName = null;
101: else
102: m_jndiDataSourceName = jndiDataSourceName;
103: }
104:
105: /** Getter for property maxWait.
106: * @return Value of property maxWait.
107: *
108: */
109: public Long getMaxWait() {
110: return m_maxWait;
111: }
112:
113: /** Setter for property maxWait.
114: * @param maxWait New value of property maxWait.
115: *
116: */
117: public void setMaxWait(Long maxWait) {
118: m_maxWait = maxWait;
119: }
120:
121: // **************************************
122: // Implementation methods
123: // **************************************
124:
125: /** Creates a connection using the DataSource obtained via JNDI.
126: * @throws SQLException if any SQL error occurs
127: * @throws IOException if any IO error occurs
128: * @return a Connection
129: */
130: public Connection createConnection() throws SQLException,
131: IOException {
132: try {
133: Context initContext = new InitialContext();
134: DataSource dataSource = (DataSource) initContext
135: .lookup(getJndiDataSourceName());
136: Connection connection = null;
137:
138: for (int i = 0; i < RETRY_LIMIT; i++) {
139: try {
140: connection = dataSource.getConnection();
141: } catch (Exception e) {
142: // do nothing
143: }
144:
145: if (connection != null)
146: break;
147:
148: if (log.isDebugEnabled())
149: log
150: .debug((i + 1)
151: + " : Could not acquire Connection from JNDI DataSource. Will try again.");
152:
153: try {
154: Thread.sleep(getMaxWait() != null ? getMaxWait()
155: .longValue() : DEFAULT_WAIT_TIME);
156: } catch (Exception e) {
157: // do nothing
158: }
159: }
160:
161: if (connection == null) {
162: String str = "Could not acquire a connection from JNDI DataSource even after "
163: + RETRY_LIMIT + " tries";
164: log.error(str);
165: throw new SQLException(str);
166: }
167:
168: if (log.isDebugEnabled())
169: log
170: .debug("Acquired a pooled Connection from JNDI DataSource resource: "
171: + connection);
172: return connection;
173:
174: } catch (NamingException e) {
175: String str = "Error in performing a JNDI lookup for the JNDI DataSource resource: "
176: + getJndiDataSourceName();
177: log.error(str, e);
178: throw new IOException(str);
179: }
180:
181: }
182:
183: /** Returns the connection back to the pool.
184: * @param connection The connection to return back to the pool.
185: * @throws SQLException if any SQL error occurs
186: * @throws IOException if any IO error occurs
187: */
188: public void freeConnection(Connection connection)
189: throws SQLException, IOException {
190: if (log.isDebugEnabled())
191: log
192: .debug("Freeing up the pooled Connection back to the JNDI pool: "
193: + connection);
194: connection.close();
195: }
196:
197: /** Returns a true if the Prepared (and Call) Statements are to be cached for a connection.
198: * This will return a false. The JNDI DataSource is expected to specify a pool for the PreparedStatements.
199: * @return a true if the Prepared (and Call) Statements are to be cached for a connection.
200: */
201: public boolean usePreparedStatementCaching() {
202: return false;
203: }
204:
205: }
|