1- package edu .acceso .borrarlo .backend ;
2-
3- import java .sql .Connection ;
4- import java .sql .SQLException ;
5- import java .util .HashMap ;
6- import java .util .Map ;
7- import java .util .Objects ;
8- import java .util .stream .Collectors ;
9-
10- import com .zaxxer .hikari .HikariConfig ;
11- import com .zaxxer .hikari .HikariDataSource ;
12-
13- /** Genera conexiones a la base de datos incluidas en un pool de conexiones */
14- public class ConnectionPool implements AutoCloseable {
15-
16- private static Map <Integer , ConnectionPool > instances = new HashMap <>();
17- private final HikariDataSource ds ;
18- public static short maxConnections = 10 ;
19- public static short minConnections = 1 ;
20-
21- private ConnectionPool (String url , String user , String password ) {
22- HikariConfig hconfig = new HikariConfig ();
23- hconfig .setJdbcUrl (url );
24- hconfig .setUsername (user );
25- hconfig .setPassword (password );
26- // Mínimo y máximo de conexiones.
27- hconfig .setMaximumPoolSize (maxConnections );
28- hconfig .setMinimumIdle (minConnections );
29- ds = new HikariDataSource (hconfig );
30- }
31-
32- /**
33- * Genera un pool de conexiones o reaprovecha uno ya creado
34- * si coinciden los parámetros de creación.
35- * @param url URL de la base de datos.
36- * @param user Usuario de conexión
37- * @param password Contraseña de conexión
38- * @return El pool de conexiones
39- */
40- public static ConnectionPool getInstance (String url , String user , String password ) {
41- int hashCode = Objects .hash (url , user , password );
42- ConnectionPool instance = instances .get (hashCode );
43- if (instance == null || instance .getDataSource ().isClosed ()) {
44- instance = new ConnectionPool (url , user , password );
45- instances .put (hashCode , instance );
46- }
47- return instance ;
48- }
49-
50- /**
51- * Genera un pool de conexiones o reaprovecha uno ya creado
52- * si ya se creo uno con la URL suministrada.
53- * @param url La URL de conexión.
54- * @return El pool de conexiones.
55- */
56- public static ConnectionPool getInstance (String url ) {
57- return ConnectionPool .getInstance (url , null , null );
58- }
59-
60- /**
61- * Devuelve un pool de conexiones cuando sólo hay un candidato posible.
62- * Como efecto secundario, elimina los pools cuyo DataSource esté cerrado.
63- * @return El pool de conexiones.
64- */
65- public static ConnectionPool getInstance () {
66- ConnectionPool .clear ();
67- switch (instances .size ()) {
68- case 1 :
69- ConnectionPool instance = instances .values ().iterator ().next ();
70- if (instance .isActive ()) return instance ;
71- else instances .clear ();
72- case 0 :
73- throw new IllegalArgumentException ("No hay definido ningún pool activo" );
74- default :
75- throw new IllegalArgumentException ("Ambiguo: hay definidos varios pools" );
76- }
77- }
78-
79- /**
80- * Elimina los pools cuyos DataSource estén cerrados.
81- */
82- public static void clear () {
83- instances = instances .entrySet ()
84- .stream ().filter (e -> e .getValue ().isActive ())
85- .collect (Collectors .toMap (Map .Entry ::getKey , Map .Entry ::getValue ));
86- }
87-
88- public Connection getConnection () throws SQLException {
89- return ds .getConnection ();
90- }
91-
92- public HikariDataSource getDataSource () {
93- return ds ;
94- }
95-
96- public boolean isActive () {
97- return !ds .isClosed ();
98- }
99-
100- @ Override
101- public void close () {
102- ds .close ();
103- }
1+ package edu .acceso .sqlutils ;
2+
3+ import java .util .HashMap ;
4+ import java .util .Map ;
5+ import java .util .Objects ;
6+ import java .util .stream .Collectors ;
7+
8+ import com .zaxxer .hikari .HikariConfig ;
9+ import com .zaxxer .hikari .HikariDataSource ;
10+
11+ /**
12+ * Pool de conexiones para manejar múltiples conexiones a una base de datos.
13+ * Utiliza HikariCP como proveedor de conexión y el patrón Singleton
14+ * para garantizar que solo haya una instancia por combinación de URL, usuario y contraseña.
15+ */
16+ public class ConnectionPool {
17+
18+ /** Mapa de instancias de ConnectionPool para implementar el patrón Singleton ampliado */
19+ private static Map <Integer , HikariDataSource > instances = new HashMap <>();
20+ /** Número máximo de conexiones en el pool */
21+ public static short maxConnections = 10 ;
22+ /** Número mínimo de conexiones en el pool */
23+ public static short minConnections = 1 ;
24+
25+ /**
26+ * Crea un {@link HikariDataSource} con la configuración dada.
27+ * @param url URL de la base de datos.
28+ * @param user Usuario de conexión
29+ * @param password Contraseña de conexión
30+ */
31+ private static HikariDataSource createHikariDataSource (String url , String user , String password ) {
32+ HikariConfig hconfig = new HikariConfig ();
33+ hconfig .setJdbcUrl (url );
34+ hconfig .setUsername (user );
35+ hconfig .setPassword (password );
36+ // Mínimo y máximo de conexiones.
37+ hconfig .setMaximumPoolSize (maxConnections );
38+ hconfig .setMinimumIdle (minConnections );
39+
40+ return new HikariDataSource (hconfig );
41+ }
42+
43+ /**
44+ * Genera y almacena una fuente de datos HikariCP con la configuración dada.
45+ * Si los parámetros de configuración coinciden, genera una excepción
46+ * @param url URL de la base de datos.
47+ * @param user Usuario de conexión
48+ * @param password Contraseña de conexión
49+ * @return La fuente de datos HikariCP.
50+ * @throws IllegalArgumentException Si ya existe un pool con la configuración proporcionada.
51+ */
52+ public static HikariDataSource getInstance (String url , String user , String password ) {
53+ int hashCode = Objects .hash (url , user , password );
54+ HikariDataSource instance = instances .get (hashCode );
55+ if (instance == null || instance .isClosed ()) {
56+ instance = createHikariDataSource (url , user , password );
57+ instances .put (hashCode , instance );
58+ return instance ;
59+ }
60+ else throw new IllegalArgumentException ("Ya existe un pool con la configuración proporcionada" );
61+ }
62+
63+ /**
64+ * Devuelve un {@link HikariDataSource} cuando no son necesarios usuario ni contraseña.
65+ * @param url La URL de conexión.
66+ * @return La fuente de datos HikariCP.
67+ */
68+ public static HikariDataSource getInstance (String url ) {
69+ return ConnectionPool .getInstance (url , null , null );
70+ }
71+
72+ /**
73+ * Devuelve un pool de conexiones cuando sólo hay un candidato posible.
74+ * Como efecto secundario, elimina los pools cuyo DataSource esté cerrado.
75+ * @return La fuente de datos HikariCP.
76+ * @throws IllegalArgumentException Si no hay ningún pool activo o si hay varios candidatos.
77+ */
78+ public static HikariDataSource getInstance () {
79+ ConnectionPool .clear ();
80+ switch (instances .size ()) {
81+ case 1 :
82+ HikariDataSource instance = instances .values ().iterator ().next ();
83+ if (!instance .isClosed ()) return instance ;
84+ else instances .clear ();
85+ case 0 :
86+ throw new IllegalArgumentException ("No hay definido ningún pool activo" );
87+ default :
88+ throw new IllegalArgumentException ("Ambiguo: hay definidos varios pools" );
89+ }
90+ }
91+
92+ /**
93+ * Elimina los DataSources cerrados del mapa de instancias.
94+ */
95+ public static void clear () {
96+ instances = instances .entrySet ()
97+ .stream ().filter (e -> !e .getValue ().isClosed ())
98+ .collect (Collectors .toMap (Map .Entry ::getKey , Map .Entry ::getValue ));
99+ }
100+
101+ /**
102+ * Cierra todos los pools de conexiones y elimina todas las instancias.
103+ */
104+ public static void reset () {
105+ instances .values ().forEach (HikariDataSource ::close );
106+ instances .clear ();
107+ }
104108}
0 commit comments