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