001: /*
002: * Copyright 2003 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 velosurf.sql;
018:
019: import java.sql.SQLException;
020: import java.sql.ResultSet;
021: import java.sql.Connection;
022:
023: import java.util.*;
024:
025: import velosurf.util.Logger;
026:
027: /** This class is a pool of PooledStatements.
028: *
029: * @author <a href=mailto:claude.brisson@gmail.com>Claude Brisson</a>
030: */
031: public class StatementPool implements Runnable, Pool {
032:
033: /** build a new pool.
034: *
035: * @param connectionPool connection pool
036: */
037: protected StatementPool(ConnectionPool connectionPool) {
038: this .connectionPool = connectionPool;
039: checkTimeoutThread = new Thread(this );
040: // checkTimeoutThread.start();
041: }
042:
043: /** get a valid statement.
044: *
045: * @exception SQLException thrown by the database engine
046: * @return a valid statement
047: */
048: public synchronized PooledSimpleStatement getStatement()
049: throws SQLException {
050: PooledSimpleStatement statement = null;
051: ConnectionWrapper connection = null;
052: for (Iterator<PooledSimpleStatement> it = statements.iterator(); it
053: .hasNext();) {
054: statement = it.next();
055: if (statement.isValid()) {
056: if (!statement.isInUse()
057: && !(connection = (ConnectionWrapper) statement
058: .getConnection()).isBusy()) {
059: // check connection
060: if (connection.check()) {
061: statement.notifyInUse();
062: return statement;
063: } else {
064: dropConnection(connection);
065: it.remove();
066: }
067: }
068: } else {
069: it.remove();
070: }
071: }
072: if (count == maxStatements)
073: throw new SQLException("Error: Too many opened statements!");
074: connection = connectionPool.getConnection();
075: statement = new PooledSimpleStatement(connection, connection
076: .createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
077: ResultSet.CONCUR_READ_ONLY));
078: statements.add(statement);
079: statement.notifyInUse();
080: return statement;
081: }
082:
083: // timeout loop
084: /** run the loop of statements checking and recycling.
085: */
086: public void run() {
087: while (running) {
088: try {
089: Thread.sleep(checkDelay);
090: } catch (InterruptedException e) {
091: }
092: long now = System.currentTimeMillis();
093: for (PooledSimpleStatement statement : statements) {
094: if (statement.isInUse()
095: && now - statement.getTagTime() > timeout)
096: statement.notifyOver();
097: }
098: }
099: }
100:
101: /** debug - two ints long array containing nb of statements in use and total nb of statements.
102: *
103: * @return 2 integers long array
104: */
105: public int[] getUsageStats() {
106: int[] stats = new int[] { 0, 0 };
107: for (PooledSimpleStatement statement : statements) {
108: if (!statement.isInUse())
109: stats[0]++;
110: }
111: stats[1] = statements.size();
112: return stats;
113: }
114:
115: /** close all statements.
116: */
117: public void clear() {
118: // close all statements
119: for (PooledSimpleStatement statement : statements) {
120: try {
121: statement.close();
122: } catch (SQLException sqle) { // don't care now...
123: Logger.log(sqle);
124: }
125: }
126: for (Iterator it = statements.iterator(); it.hasNext();)
127: statements.clear();
128: }
129:
130: /* drop all statements relative to a specific connection
131: * @param connection the connection
132: */
133: private void dropConnection(Connection connection) {
134: for (Iterator it = statements.iterator(); it.hasNext();) {
135: PooledSimpleStatement statement = (PooledSimpleStatement) it
136: .next();
137: try {
138: statement.close();
139: } catch (SQLException sqle) {
140: }
141: statement.setInvalid();
142: }
143: try {
144: connection.close();
145: } catch (SQLException sqle) {
146: }
147: }
148:
149: /** close statements on exit.
150: */
151: protected void finalize() {
152: clear();
153: }
154:
155: /** Connection pool.
156: */
157: private ConnectionPool connectionPool = null;
158:
159: /** number of statements.
160: */
161: private int count = 0;
162: /** statements.
163: */
164: private List<PooledSimpleStatement> statements = new ArrayList<PooledSimpleStatement>();
165: /** timeout checking thread.
166: */
167: private Thread checkTimeoutThread = null;
168: /** is the thread running?
169: */
170: private boolean running = true;
171:
172: /** delay between checks.
173: */
174: private static final long checkDelay = 30 * 1000;
175: /** timeout on which statements are automatically recycled if not used.
176: */
177: private static final long timeout = 10 * 60 * 1000;
178: /** maximum number of statements.
179: */
180: private static final int maxStatements = 50;
181: }
|