Mercurial > dive4elements > gnv-client
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 } |