1
2
3
4
5 package atg.metier.dao.jdo;
6
7 /**
8 * <p>Titre : Pool de connexions aux bases de données en JDO</p>
9 * <p>Description : Gestion de pool de connexion</p>
10 * <p>Copyright : FERRARI Olivier</p>
11 * @author YSMAL Vincent
12 * @version 1.0
13 * Ce logiciel est régi par la licence CeCILL soumise au droit français et
14 * respectant les principes de diffusion des logiciels libres. Vous pouvez
15 * utiliser, modifier et/ou redistribuer ce programme sous les conditions
16 * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA
17 * sur le site http://www.cecill.info.
18 *
19 * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez
20 * pris connaissance de la licence CeCILL, et que vous en avez accepté les
21 * termes.
22 */
23 import java.io.FileInputStream;
24 import java.io.FileNotFoundException;
25 import java.io.IOException;
26 import java.util.Properties;
27 import javax.jdo.JDOHelper;
28 import javax.jdo.PersistenceManager;
29 import javax.jdo.PersistenceManagerFactory;
30 import atg.metier.dao.jdbc.exception.ATGDaoBaseIndisponibleException;
31 import atg.service.constante.AtgConstantes;
32 import atg.service.log.AtgLogManager;
33 import atg.util.service.ATGBasicClass;
34
35 /**
36 * @author Administrateur
37 */
38 public class ATGDaoJdoPoolDataSource extends ATGBasicClass
39 {
40 //***************************************************************************
41 //Attributs
42 //***************************************************************************
43
44 /**
45 * Référence du pool par défaut
46 */
47 public static final String CSTE_DEFAULT_REFERENCE = "Reference par defaut";
48
49 /**
50 * Instances uniques (pour une référence donnée) du pool de connections
51 */
52
53 private static java.util.Hashtable instances = new java.util.Hashtable();
54
55
56 /**
57 * nombre de connections maximum crées sur la base de données
58 */
59 private static final int MAX_CONNECTION = 10;
60
61 /**
62 * nombre de connections automatiquement crées au démarrage du pool
63 */
64 private static final int START_CONNECTION = 1;
65
66 /**
67 * Delai d'attente pour l'obtention d'une connection, exemple 3000 = 3
68 * secondes
69 */
70 private static final int MAX_WAIT = 3000;
71
72 /**
73 * delai au dela duquel une connexion est consideree comme perdue, exemple
74 * 60000 = 60 secondes
75 */
76 private static final int MAX_CTRL_TIME = 60000;
77
78 /**
79 * Attribut de la connexion standard
80 */
81
82
83
84
85
86 /**
87 * liste des connections créées mais non utilisées
88 */
89 private java.util.Vector freeConnections = null;
90
91 /**
92 * nombre de connections en cours (demandées mais pas encore libérées)
93 */
94 private int checkedOut = 0;
95
96 /**
97 * driver permettant d'obtenir une connection
98 */
99
100
101 /**
102 * référence du pool de données
103 */
104 protected String reference = "";
105
106 /**
107 * ensemble des connections creees sur la base de donnees
108 */
109 protected java.util.Hashtable ctrlConnexion = null;
110
111 protected static java.util.logging.Logger logger_ = null;
112
113 private PersistenceManagerFactory pmf = null;
114
115 /**
116 * Ecriture des logs
117 */
118 protected java.util.logging.Logger getLogger()
119 {
120 if (logger_ == null)
121 logger_ = AtgLogManager
122 .getLog(AtgConstantes.ATG_LOG_CATEGORY_METIER_DAO_JDO);
123
124 return logger_;
125 }
126
127 private ATGDaoJdoPoolDataSource(String reference)
128 {
129 String properties = atg.service.constante.AtgConstantesWF
130 .getValue("PATH_JDO_FILE");
131
132 Properties props = new Properties();
133 String nomFichier = properties + reference + "_JDO.properties";
134 try
135 {
136 props.load(new FileInputStream(nomFichier));
137
138
139
140 pmf = JDOHelper.getPersistenceManagerFactory(props);
141 }
142 catch (FileNotFoundException e)
143 {
144 this
145 .logSevere("Immpossible de trouver le fichier de properties pour le serveur JDO : "
146 + nomFichier);
147 }
148 catch (IOException e)
149 {
150 this.logSevere("Erreur d'entrée/sortie dans le fichier de properties : "
151 + nomFichier);
152 }
153 }
154
155 /**
156 * Renvoie une connection au serveur de persistance.
157 *
158 * @return PersistenceManager Reférence vers le gestionnaire de persistance
159 * Jdo
160 */
161 public PersistenceManager getPersistenceManager()
162 throws ATGDaoBaseIndisponibleException
163 {
164 try
165 {
166 PersistenceManager conn = getPersistenceManager(MAX_WAIT);
167 return conn;
168 }
169 catch (ATGDaoBaseIndisponibleException exception)
170 {
171
172 logSevere("Impossible de fournir une connection correcte : "
173 + exception.getCause() + " / " + exception.getMessage());
174 throw new ATGDaoBaseIndisponibleException();
175 }
176 }
177
178 /**
179 * Renvoie une connection à la base de données. Attend au maximum 'timeout'
180 * millisecondes l'obtention de la connection.
181 *
182 * @param timeout
183 * Temps d'attente maximum de la connection
184 * @throws java.sql.SQLException
185 * Exception SQL
186 * @return java.sql.Connection Connection à la base de données
187 */
188 protected synchronized PersistenceManager getPersistenceManager(long timeout)
189 throws ATGDaoBaseIndisponibleException
190 {
191 long startTime = System.currentTimeMillis();
192 long remaining = timeout;
193 PersistenceManager conn = null;
194
195 while ((conn = getPooledPersistenceManager()) == null)
196 {
197
198 try
199 {
200
201
202 logFinest("Attente d'une connection (" + timeout + ").");
203 wait(timeout);
204 }
205 catch (InterruptedException exception)
206 {
207
208 }
209
210
211
212 remaining = timeout - (System.currentTimeMillis() - startTime);
213
214 if (remaining <= 0)
215 {
216
217 throw new ATGDaoBaseIndisponibleException(
218 "getPersistenceManager() time-out");
219 }
220 }
221
222 if (!isConnectionOk(conn))
223 {
224
225 return getPersistenceManager(remaining);
226 }
227
228
229 checkedOut++;
230
231 return conn;
232 }
233
234 /**
235 * Renvoie une connection.
236 *
237 * @throws ATGDaoBaseIndisponibleException
238 * @return PersistenceManager Connection au gestionnaire de persistance
239 */
240 protected PersistenceManager getPooledPersistenceManager()
241 throws ATGDaoBaseIndisponibleException
242 {
243 PersistenceManager conn = null;
244
245
246 logFinest("Une connection est demandee au pool.");
247
248
249 if (freeConnections.size() > 0)
250 {
251
252 conn = (PersistenceManager) freeConnections.firstElement();
253 freeConnections.removeElementAt(0);
254 }
255 else
256 {
257
258
259 if (checkedOut == MAX_CONNECTION)
260 {
261 logWarning("Attention, le nombre maximum de connexions creees sur le serveur de persitance est atteint : "
262 + MAX_CONNECTION);
263 ckeckCtrlConnexion();
264 }
265
266
267
268
269
270
271
272 if (checkedOut < MAX_CONNECTION) conn = newConnection();
273 }
274
275 return conn;
276 }
277
278 /**
279 * Vérifie si toutes les connexions ont bien été rendues au pool.
280 */
281 public void ckeckCtrlConnexion()
282 {
283
284 java.util.Enumeration conns = ctrlConnexion.keys();
285
286
287 do
288 {
289 Object conn = conns.nextElement();
290 long delta = System.currentTimeMillis()
291 - ((Long) (ctrlConnexion.get(conn))).longValue();
292 if ((!freeConnections.contains(conn)) && (delta > MAX_CTRL_TIME))
293 {
294
295
296 ctrlConnexion.remove(conn);
297 logSevere("La connexion " + conn
298 + " est consideree comme perdue : elle n'a pas ete rendue au pool.");
299
300 checkedOut--;
301
302
303 ((PersistenceManager) conn).close();
304 }
305 }
306 while (conns.hasMoreElements());
307 }
308
309 /**
310 * Création d'une nouvelle connection.
311 *
312 * @throws ATGDaoBaseIndisponibleException
313 * @return PersistenceManager Nouvelle connection à la base de données
314 */
315 protected PersistenceManager newConnection()
316 throws ATGDaoBaseIndisponibleException
317 {
318 this.logFinest("Demande d'une reférence sur le Serveur de persistance");
319 PersistenceManager pm = (PersistenceManager) this.pmf
320 .getPersistenceManager();
321 if (pm != null)
322 {
323 logFinest(" getPersistenceManager()");
324
325 }
326 else
327 {
328 logSevere("Impossible de récupérer une instance de persistance manager");
329 }
330 return pm;
331 }
332
333 /**
334 * Contrôle si la connection specifiée est valide.
335 *
336 * @param conn
337 * Connection à tester
338 * @return boolean Connection valide ou non
339 */
340 protected boolean isConnectionOk(PersistenceManager conn)
341 {
342
343
344
345 if (!conn.isClosed())
346 {
347 conn.refreshAll();
348 return true;
349 }
350 else
351 return false;
352
353 }
354
355 /**
356 * Renvoie l'instance unique du pool de connections pour la référence donnée.
357 *
358 * @param reference
359 * Référence du pool de connection
360 * @return StdPoolDataSource Instance d'un pool d'accès aux données
361 */
362 static public ATGDaoJdoPoolDataSource getInstance(String reference)
363 {
364 if ((instances.get(reference) != null))
365 {
366
367 return (ATGDaoJdoPoolDataSource) (instances.get(reference));
368 }
369 else
370 {
371
372 ATGDaoJdoPoolDataSource instance = new ATGDaoJdoPoolDataSource(reference);
373
374 instance.initPool();
375
376 instances.put(reference, instance);
377
378 return instance;
379 }
380 }
381
382 /**
383 * Initialisation du pool. Appelé lors de l'instanciation.
384 */
385 protected void initPool()
386 {
387 freeConnections = new java.util.Vector();
388
389
390
391 for (int i = 0; i < START_CONNECTION; i++)
392 {
393 try
394 {
395 freeConnections.addElement(newConnection());
396 }
397 catch (ATGDaoBaseIndisponibleException exception)
398 {
399 logSevere("Impossible d'initialiser le pool de Connection Jdo!"
400 + exception.getCause() + " / " + exception.getMessage());
401 }
402 }
403 }
404 /**
405 * Libére la connection spécifiée.
406 * @param conn Connection à libérer
407 */
408 public synchronized void release(PersistenceManager conn) {
409
410 logFinest("Un persistance manager est liberee : " +
411 (freeConnections.size() + 1) + " persistance manager sont libres.");
412
413
414 freeConnections.addElement(conn);
415 checkedOut--;
416
417
418
419 notifyAll();
420 }
421 }