KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > mckoi > database > jdbcserver > MultiThreadedConnectionPoolServer


1 /**
2  * com.mckoi.database.jdbcserver.MultiThreadedConnectionPoolServer 21 Jun 2001
3  *
4  * Mckoi SQL Database ( http://www.mckoi.com/database )
5  * Copyright (C) 2000, 2001, 2002 Diehl and Associates, Inc.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * Version 2 as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License Version 2 for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * Version 2 along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  *
20  * Change Log:
21  *
22  *
23  */

24
25 package com.mckoi.database.jdbcserver;
26
27 import com.mckoi.database.User;
28 import com.mckoi.database.Database;
29 import com.mckoi.database.DatabaseSystem;
30 import com.mckoi.debug.*;
31 import java.io.IOException JavaDoc;
32 import java.util.ArrayList JavaDoc;
33 import java.util.LinkedList JavaDoc;
34 import java.util.ResourceBundle JavaDoc;
35
36 /**
37  * A multi-threaded implementation of a connection pool server. This starts
38  * a new thread for each connection made and processes each command as they
39  * arrive.
40  *
41  * @author Tobias Downer
42  */

43
44 final class MultiThreadedConnectionPoolServer implements ConnectionPoolServer {
45
46   /**
47    * If this is set to true then the server periodically outputs statistics
48    * about the connections.
49    */

50   private static final boolean DISPLAY_STATS = false;
51
52   /**
53    * The Database parent.
54    */

55   private Database database;
56
57   /**
58    * The list of all threads that were created to deal with incoming
59    * commands.
60    */

61   private ArrayList JavaDoc client_threads;
62
63
64   /**
65    * The Constructor. The argument is the configuration file.
66    */

67   MultiThreadedConnectionPoolServer(Database database) {
68     this.database = database;
69     client_threads = new ArrayList JavaDoc();
70   }
71
72   /**
73    * Returns a DebugLogger object that we can log debug messages to.
74    */

75   public final DebugLogger Debug() {
76     return database.Debug();
77   }
78
79   /**
80    * Connects a new ServerConnection into the pool of connections to clients
81    * that this server maintains. We then cycle through these connections
82    * determining whether any commands are pending. If a command is pending
83    * we spawn off a worker thread to do the task.
84    */

85   public void addConnection(ServerConnection connection) {
86     ClientThread client_thread = new ClientThread(connection);
87     synchronized(client_threads) {
88       client_threads.add(client_thread);
89     }
90     client_thread.start();
91   }
92
93   /**
94    * Closes this connection pool server down.
95    */

96   public void close() {
97     synchronized (client_threads) {
98       int size = client_threads.size();
99       for (int i = 0; i < size; ++i) {
100         ((ClientThread) client_threads.get(i)).close();
101       }
102     }
103   }
104
105   // ---------- Inner classes ----------
106

107   /**
108    * This thread blocks waiting for a complete command to arrive from the
109    * client it is connected to.
110    */

111   private class ClientThread extends Thread JavaDoc {
112
113     /**
114      * The ServerConnection object being serviced by this thread.
115      */

116     private ServerConnection server_connection;
117
118     /**
119      * If this is set to true, the thread run method should close off.
120      */

121     private boolean client_closed;
122
123     /**
124      * This is set to true if we are processing a request from the client.
125      */

126     private boolean processing_command;
127
128     /**
129      * The Constructor.
130      */

131     public ClientThread(ServerConnection connection) {
132       super();
133 // setPriority(NORM_PRIORITY - 1);
134
setName("Mckoi - Client Connection");
135
136       this.server_connection = connection;
137       client_closed = false;
138       processing_command = false;
139     }
140
141     /**
142      * Checks each connection in the 'service_connection_list' list. If there
143      * is a command pending, and any previous commands on this connection have
144      * completed, then this will spawn off a new process to deal with the
145      * command.
146      */

147     private void checkCurrentConnection() throws InterruptedException JavaDoc {
148       try {
149
150         // Wait if we are processing a command
151
synchronized(this) {
152           while (processing_command) {
153             if (client_closed) {
154               return;
155             }
156             // Wait 2 minutes just to make sure we don't miss a poll,
157
wait(120000);
158           }
159         }
160
161         // Block until a complete command is available
162
server_connection.blockForRequest();
163
164         processing_command = true;
165
166         database.execute(null, null, new Runnable JavaDoc() {
167           public void run() {
168
169             try {
170               // Process the next request that's pending.
171
server_connection.processRequest();
172             }
173             catch (IOException JavaDoc e) {
174               Debug().writeException(Lvl.INFORMATION, e);
175             }
176             finally {
177               // Not processing a command anymore so notify the ClientThread
178
processing_command = false;
179               synchronized (ClientThread.this) {
180                 ClientThread.this.notifyAll();
181               }
182             }
183
184           }
185         });
186
187       }
188       catch (IOException JavaDoc e) {
189         // If an IOException is generated, we must remove this provider from
190
// the list.
191
close();
192
193         // This happens if the connection closes.
194
Debug().write(Lvl.INFORMATION, this,
195                     "IOException generated while checking connections, " +
196                     "removing provider.");
197         Debug().writeException(Lvl.INFORMATION, e);
198       }
199
200     }
201
202     /**
203      * Call this method to stop the thread.
204      */

205     public synchronized void close() {
206       client_closed = true;
207       try {
208         server_connection.close();
209       }
210       catch (Throwable JavaDoc e) {
211         // ignore
212
}
213       notifyAll();
214     }
215
216     /**
217      * The Runnable method of the farmer thread.
218      */

219     public void run() {
220       while (true) {
221         try {
222
223           boolean closed = false;
224           synchronized (this) {
225             closed = client_closed;
226           }
227           // Exit if the farmer thread has been closed...
228
if (closed == true) {
229             // Remove this thread from the list of client threads.
230
synchronized(client_threads) {
231               client_threads.remove(this);
232             }
233             return;
234           }
235
236           checkCurrentConnection();
237
238         }
239         catch (Throwable JavaDoc e) {
240           Debug().write(Lvl.ERROR, this, "Connection Pool Farmer Error");
241           Debug().writeException(e);
242         }
243       }
244     }
245
246   };
247
248 }
249
Popular Tags