comparison geo-backend/src/main/java/de/intevation/gnv/geobackend/sde/datasources/ArcSDEConnectionPool.java @ 129:110e3ac1b7d2

Library Dependencies Added to pom.xml-File Import of SDE-Datasources geo-backend/trunk@5 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Tim Englich <tim.englich@intevation.de>
date Wed, 02 Sep 2009 09:07:03 +0000
parents
children
comparison
equal deleted inserted replaced
128:9b3f5a067c29 129:110e3ac1b7d2
1 /*******************************************************************************
2 * Copyright © 2007 52°North Initiative for Geospatial Open Source Software GmbH
3 *
4 * Author: Oliver Meyer, University of Muenster
5 *
6 * Contact: Andreas Wytzisk, 52°North Initiative for Geospatial Open Source
7 * Software GmbH, Martin-Luther-King-Weg 24, 48155 Muenster, Germany,
8 * info@52north.org
9 *
10 * This program is free software; you can redistribute it and/or modify it under
11 * the terms of the GNU General Public License version 2 as published by the
12 * Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; even without the implied WARRANTY OF MERCHANTABILITY or FITNESS
16 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program (see gnu-gpl v2.txt). If not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA or
22 * visit the Free Software Foundation’s web page, http://www.fsf.org.
23 *
24 ******************************************************************************/
25 // Last changes on: 2007-06-03
26 // Last changes by: Oliver Meyer
27
28 package de.intevation.gnv.geobackend.sde.datasources;
29
30 import java.util.Date;
31 import java.util.Enumeration;
32 import java.util.Hashtable;
33 import java.util.Iterator;
34 import java.util.Set;
35 import java.util.Timer;
36 import java.util.TimerTask;
37 import java.util.Map.Entry;
38
39 import org.apache.log4j.Logger;
40
41 import com.esri.sde.sdk.client.SeConnection;
42 import com.esri.sde.sdk.client.SeException;
43
44 import de.intevation.gnv.geobackend.sde.datasources.exception.ConnectionException;
45 import de.intevation.gnv.geobackend.sde.datasources.exception.TechnicalException;
46
47 /**
48 * Connection Pool for ArcSDE databases.
49 *
50 * @author Oliver Meyer
51 * @version 1.0
52 */
53 public class ArcSDEConnectionPool {
54
55 /**
56 * Default Logging instance
57 */
58 private static final Logger sLogger = Logger.getLogger(ArcSDEConnectionPool.class);
59 private static boolean sDebug = sLogger.isDebugEnabled();
60
61 /**
62 * timer for holding connections
63 */
64 private Timer timer;
65
66 /**
67 * the logger, used to log exceptions and additonaly information
68 */
69 private static Logger log = Logger.getLogger(ArcSDEConnectionPool.class);
70
71 /**
72 * Hashtable containing the connections as keys and Boolean as value (False if the connection is not used)
73 */
74 private Hashtable<SeConnection, Boolean> connections;
75
76 private static ArcSDEConnectionPool sInstance = null;
77
78 private static ArcSDEConnectionParams sParams = null;
79
80 public static ArcSDEConnectionPool getInstance() throws TechnicalException {
81 if (sInstance == null) {
82 throw new TechnicalException("The ArcSDEConnectionPool has to be configured first!");
83 }
84 return sInstance;
85 }
86
87 public static boolean isConfigured() {
88 return sParams != null;
89 }
90
91 public static void configure(ArcSDEConnectionParams pParams) throws TechnicalException {
92 if (sDebug) sLogger.debug("configure()");
93
94 if (sInstance == null) {
95 synchronized (ArcSDEConnectionPool.class) {
96 sInstance = new ArcSDEConnectionPool(pParams);
97 }
98 } else {
99 throw new TechnicalException("The ArcSDEConnectionPool is already configured: " + pParams.toString());
100 }
101
102 }
103
104
105 private ArcSDEConnectionPool(ArcSDEConnectionParams pParams) throws ConnectionException {
106 if (sDebug) sLogger.debug("ArcSDEConnectionPool()");
107 sParams = pParams;
108
109 connections = new Hashtable<SeConnection, Boolean>();
110 initPool(sParams.getInitConnections());
111 timer = new Timer("ArcSDEConnectionPoolTimer");
112 startConnectionTask();
113 }
114
115 /**
116 * help method for initializing the connection pool
117 *
118 * @param initConnections number of initial connections
119 * @throws OwsExceptionReport if creating connections failed while initializing the connection pool
120 */
121 protected void initPool(int initConnections) throws ConnectionException {
122
123 // initialize connections;
124 // "false" indicates that the connection is not used yet
125 for (int i = 0; i < initConnections; ++i) {
126 SeConnection con = getNewConnection();
127 connections.put(con, Boolean.FALSE);
128 }
129 }
130
131 /**
132 * Method returns an available connection from the pool, and sets it on "not available". After the query
133 * operation, you have to "give back" the connection to the pool with the returnConnection method!
134 *
135 * @return ArcSDE connection to execute the query
136 * @throws OwsExceptionReport If all connections are in use and no further connection could be established
137 * @throws OwsExceptionReport
138 */
139 protected SeConnection getConnection() throws ConnectionException {
140
141 SeConnection con = null;
142
143 Enumeration<SeConnection> cons = connections.keys();
144
145 // no other operation (maybe adding a connection) while checking which
146 // (or whether a) connection is available
147 synchronized (connections) {
148
149 while (cons.hasMoreElements()) {
150 con = cons.nextElement();
151 Boolean b = connections.get(con);
152
153 // checking whether connection is available
154 if (b == Boolean.FALSE) {
155 // connection is available, now test, whether connection is
156 // OK (with setAutoCommit)
157 try {
158 con.setTransactionAutoCommit(1000);
159 }
160 catch (SeException sdeEx) {
161 // problem with connection, so remove and create new
162 // connection
163 connections.remove(con);
164
165 con = getNewConnection();
166
167 }
168 // set connection "not available" (Value=true)
169 connections.put(con, Boolean.TRUE);
170 return con;
171 }
172 }
173 }
174
175 // if no connections are available, create new one
176 if (connections.size() <= sParams.getMaxConnections()) {
177
178 con = getNewConnection();
179
180 connections.put(con, Boolean.TRUE);
181 }
182 // if maximal number of connections is arrived, throw exception!
183 else {
184 throw new ConnectionException("All db connections are in use. Please try again later!");
185 }
186
187 // return new Connection
188 return con;
189 }
190
191 /**
192 * abstract method creates a new connection; must be implemented by all subclasses!
193 *
194 * @return Returns connection - new connection to the database
195 * @throws OwsExceptionReport if creating a new connection failed
196 */
197 private SeConnection getNewConnection() throws ConnectionException {
198 SeConnection con;
199
200 // creating new connection
201 try {
202
203 con = new SeConnection(sParams.getServer(), sParams.getInstance(), sParams.getDatabase(), sParams.getUser(), sParams.getPwd());
204
205 // Class.forName("org.postgresql.Driver");
206 // con = DriverManager.getConnection(props.getProperty("CONNECTION"), props);
207
208 }
209 catch (SeException sdeEx) {
210 throw new ConnectionException("Establishing a connection to database failed: " + sdeEx.toString(), sdeEx);
211 }
212
213 return con;
214 }
215
216 /**
217 * Invoke this method after executing the query with this connection, so that the connection is already
218 * available in the pool
219 *
220 * @param con the connection which was used and now is available again
221 */
222 public void returnConnection(SeConnection con) {
223 if (connections.containsKey(con)) {
224 connections.put(con, Boolean.FALSE);
225 }
226 }
227
228 /**
229 * method sends a query for every connection
230 */
231 private void holdConnections() {
232 Set<Entry<SeConnection, Boolean>> entrySet = connections.entrySet();
233 Iterator<Entry<SeConnection, Boolean>> iter = entrySet.iterator();
234 SeConnection con = null;
235 while (iter.hasNext()) {
236 Entry<SeConnection, Boolean> entry = iter.next();
237
238 //Connection in use?
239 if (entry.getValue() == false) {
240 con = entry.getKey();
241 try {
242 con.setTransactionAutoCommit(1000);
243 }
244 catch (SeException sdeEx) {
245
246 //if sql exception occurs, try to built new connection and put connection into pool
247 connections.remove(con);
248 try {
249 SeConnection conNew = getNewConnection();
250 connections.put(conNew, Boolean.FALSE);
251 }
252 catch (ConnectionException e) {
253 log.debug("Erroe while refreshing connections: " + e.getMessage());
254 }
255 log.error("An error occurred while holding connections through query!", sdeEx);
256 }
257 }
258 }
259 }
260
261 /**
262 * method invokes the schedule method of the timer with a new InstantFeederTask, the actual date and the
263 * period from the config file as parameters.
264 *
265 * @throws OwsExceptionReport if creation of the InstantFeederTask failed
266 */
267 private void startConnectionTask() throws ConnectionException {
268 timer.schedule(new ConnectionTask(), new Date(), sParams.getTimeToHold());
269 }
270
271 /**
272 * connection task used for holding connections and making sure, that these
273 *
274 * @author Christoph Stasch
275 */
276 protected class ConnectionTask extends TimerTask {
277
278 /**
279 * overwritten run method of TimerTask which queries offeringIDs from db to make sure, that
280 * connections won't be blocked by the firewalls
281 */
282 public void run() {
283 holdConnections();
284 }
285
286 }
287
288 }

http://dive4elements.wald.intevation.org