mirror of
https://github.com/KeymonSoft/jRDC-Multi.git
synced 2026-04-17 21:06:24 +00:00
- VERSION 5.09.14
``` feat: Implement hot-swap for DB config reload and JSON POST support **Cambios Principales:** 1. **Hot-Swap para recarga de configuraciones de DB sin reiniciar servidor** 2. **Migración a ReentrantLock para sincronización por incompatibilidad con Sync** 3. **Soporte para peticiones POST con Content-Type: application/json** 4. **Mejoras en inicialización del pool de conexiones y soporte multi-DB** **Problemas Resueltos:** - Falta de "Hot-Swap" en `reload`: El comando no permitía recarga dinámica de configuraciones sin reinicio - Ausencia de mecanismo de cierre de pools en RDCConnector para liberación ordenada de conexiones - Incompatibilidad con `Sync` en entorno B4X - Procesamiento incorrecto de peticiones POST con Content-Type: application/json - Inicialización incorrecta de pools C3P0 con TotalConnections: 0 - Configuración inconsistente de parámetros críticos de C3P0 - jdbcUrl truncada/vacía en logs por shadowing de variables **Cambios Implementados:** **Manager.bas:** - Reemplazo completo de lógica para comando "reload" - Creación de nuevos conectores antes de reemplazar los antiguos - Sincronización con ReentrantLock para acceso thread-safe - Patrón seguro de bloqueo sin `Finally` usando bandera booleana - Cierre explícito de oldConnectors después del reemplazo - Validación de inicialización y control de errores robusto - Registro detallado en log HTML del proceso **RDCConnector.bas:** - Implementación de método `Public Sub Close()` para liberar pools C3P0 - Corrección de shadowing de variable `config` en LoadConfigMap - Reordenamiento de Initialize - Configuración completa de C3P0 antes de adquirir conexiones - Forzar reportes de errores con acquireRetryAttempts y breakAfterAcquireFailure - Activación forzada del pool con conexión temporal **Main.bas:** - Declaración de `MainConnectorsLock As JavaObject` (ReentrantLock) - Inicialización del lock en AppStart - Declaración separada de conectores (con1, con2, con3, con4) **DBHandlerJSON.bas:** - Detección de peticiones POST con Content-Type: application/json - Lectura de JSON desde InputStream en lugar de parámetro URL - Cierre explícito del InputStream para liberación de recursos - Corrección de nombres de variables para evitar conflictos - Mensajes de error mejorados para ambos métodos (legacy y nuevo) **Beneficios:** - Recarga en caliente de configuraciones DB sin interrupción de servicio - Mayor disponibilidad y mantenibilidad del servidor - Prevención de fugas de recursos con cierre ordenado de pools - Compatibilidad con estándares APIs web (POST application/json) - Inicialización robusta y confiable de pools de conexiones - Mejor reporting de errores y diagnóstico de problemas - Soporte multi-DB más estable y confiable ```
This commit is contained in:
351
RDCConnector.bas
351
RDCConnector.bas
@@ -4,152 +4,271 @@ ModulesStructureVersion=1
|
||||
Type=Class
|
||||
Version=4.19
|
||||
@EndOfDesignText@
|
||||
'Class module
|
||||
' Módulo de clase: RDCConnector
|
||||
' Esta clase gestiona el pool de conexiones a una base de datos específica.
|
||||
' Cada instancia de RDCConnector maneja la conexión y los comandos para una base de datos.
|
||||
|
||||
Sub Class_Globals
|
||||
Private pool As ConnectionPool
|
||||
Private DebugQueries As Boolean
|
||||
Dim commands As Map
|
||||
Public serverPort As Int
|
||||
Public usePool As Boolean = True
|
||||
Dim config As Map
|
||||
Private pool As ConnectionPool ' Objeto principal para gestionar el pool de conexiones de la base de datos (usa C3P0 internamente).
|
||||
Private DebugQueries As Boolean ' Bandera para activar/desactivar el modo de depuración de queries.
|
||||
Dim commands As Map ' Almacena los comandos SQL específicos de esta base de datos, cargados de su archivo de configuración.
|
||||
Public serverPort As Int ' El puerto que el servidor HTTP usará, obtenido del archivo de configuración principal (config.properties).
|
||||
Public usePool As Boolean = True ' Indica si se debe usar el pool de conexiones (siempre True en este diseño).
|
||||
Dim config As Map ' Almacena la configuración completa (JdbcUrl, User, Password, etc.) cargada de su respectivo archivo .properties.
|
||||
End Sub
|
||||
|
||||
'Initializes the object. You can add parameters to this method if needed.
|
||||
' Subrutina de inicialización para el conector de una base de datos específica.
|
||||
' Se llama una vez por cada base de datos (DB1, DB2, DB3, DB4) al iniciar el servidor.
|
||||
' DB: El identificador único de la base de datos (ej. "DB1", "DB2").
|
||||
Public Sub Initialize(DB As String)
|
||||
' Log("RDCConnector Initialize")
|
||||
If DB.EqualsIgnoreCase("DB1") Then DB = "" 'Esto para el config.properties por default
|
||||
Dim config As Map = LoadConfigMap(DB)
|
||||
Log($"Inicializamos ${DB}, usuario: ${config.Get("User")}"$)
|
||||
pool.Initialize(config.Get("DriverClass"), config.Get("JdbcUrl"), config.Get("User"), config.Get("Password"))
|
||||
Dim jo As JavaObject = pool
|
||||
' Si el identificador es "DB1", se usa una cadena vacía para que File.ReadMap cargue "config.properties" (el archivo por defecto).
|
||||
If DB.EqualsIgnoreCase("DB1") Then DB = ""
|
||||
|
||||
' PASO 1: Cargar la configuración desde el archivo .properties correspondiente.
|
||||
' Es CRUCIAL que se asigne a la variable de CLASE 'config' (sin 'Dim' local)
|
||||
' para que la configuración cargada del archivo sea persistente para esta instancia del conector.
|
||||
config = LoadConfigMap(DB)
|
||||
|
||||
' Bloque Try-Catch para la inicialización y configuración del pool.
|
||||
' Esto capturará cualquier error crítico que impida la conexión inicial a la base de datos.
|
||||
Try
|
||||
' PASO 2: Inicializar el objeto B4X ConnectionPool.
|
||||
' Esto crea la instancia subyacente de com.mchange.v2.c3p0.ComboPooledDataSource (la librería C3P0).
|
||||
' En este punto, C3P0 solo se inicializa como objeto. Aún no intenta hacer conexiones activas.
|
||||
' Se le pasan los parámetros básicos para que C3P0 pueda construirse.
|
||||
pool.Initialize(config.Get("DriverClass"), config.Get("JdbcUrl"), config.Get("User"), config.Get("Password"))
|
||||
|
||||
Dim jo As JavaObject = pool ' Obtener la referencia JavaObject para acceder a métodos de configuración avanzados de C3P0.
|
||||
|
||||
' PASO 3: Aplicar *todas* las propiedades de configuración de C3P0 INMEDIATAMENTE.
|
||||
' Esto debe ocurrir *después* de 'pool.Initialize' pero *antes* de que C3P0 intente realmente adquirir conexiones.
|
||||
' Esto asegura que las configuraciones sean efectivas desde el primer intento de conexión.
|
||||
|
||||
' Lectura de los valores desde el archivo de configuración, con valores por defecto si no se encuentran.
|
||||
Dim initialPoolSize As Int = config.GetDefault("InitialPoolSize", 3)
|
||||
Dim minPoolSize As Int = config.GetDefault("MinPoolSize", 2)
|
||||
Dim maxPoolSize As Int = config.GetDefault("MaxPoolSize", 5)
|
||||
Dim acquireIncrement As Int = config.GetDefault("AcquireIncrement", 5)
|
||||
|
||||
' Leer valores del config.properties o usar valores por defecto
|
||||
' Si el parámetro no se encuentra en el archivo .properties, se usará el segundo valor (el por defecto).
|
||||
Dim initialPoolSize As Int = config.GetDefault("InitialPoolSize", 3) ' Por defecto 3
|
||||
Dim minPoolSize As Int = config.GetDefault("MinPoolSize", 2) ' Por defecto 3
|
||||
Dim maxPoolSize As Int = config.GetDefault("MaxPoolSize", 5) ' Por defecto 5
|
||||
|
||||
jo.RunMethod("setInitialPoolSize", Array(initialPoolSize)) ' Sets the inital pool size to 2
|
||||
jo.RunMethod("setMinPoolSize", Array(minPoolSize)) ' Sets the min pool size to 2
|
||||
jo.RunMethod("setMaxPoolSize", Array(maxPoolSize)) ' Max number of concurrent connections
|
||||
|
||||
' Define el tiempo máximo de inactividad en SEGUNDOS.
|
||||
' Una conexión que permanezca en el pool sin ser usada por más de 300 segundos (5 minutos)
|
||||
' será cerrada para liberar recursos, siempre y cuando no se viole el tamaño mínimo del pool (minPoolSize).
|
||||
jo.RunMethod("setMaxIdleTime", Array As Object(300))
|
||||
|
||||
' Define la "edad" o tiempo de vida máximo de una conexión en SEGUNDOS.
|
||||
' Después de 900 segundos (15 minutos) desde su creación, la conexión será marcada para ser
|
||||
' eliminada y reemplazada por una nueva la próxima vez que regrese al pool.
|
||||
' Esto previene problemas con conexiones "viciadas" y mantiene el pool saludable.
|
||||
jo.RunMethod("setMaxConnectionAge", Array As Object(900))
|
||||
|
||||
' Define el tiempo máximo de espera por una conexión en MILISEGUNDOS.
|
||||
' Si todas las conexiones del pool están ocupadas, una nueva petición esperará hasta
|
||||
' 60000 milisegundos (1 minuto). Si ninguna conexión se libera en ese lapso, la petición
|
||||
' fallará con un error. Esto evita que la aplicación se congele bajo carga pesada.
|
||||
jo.RunMethod("setCheckoutTimeout", Array As Object(60000))
|
||||
|
||||
' com.mchange.v2.c3p0.ComboPooledDataSource [
|
||||
' acquireIncrement -> 3,
|
||||
' acquireRetryAttempts -> 30,
|
||||
' acquireRetryDelay -> 1000,
|
||||
' autoCommitOnClose -> False,
|
||||
' automaticTestTable -> Null,
|
||||
' breakAfterAcquireFailure -> False,
|
||||
' checkoutTimeout -> 20000,
|
||||
' connectionCustomizerClassName -> Null,
|
||||
' connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester,
|
||||
' contextClassLoaderSource -> caller,
|
||||
' dataSourceName -> 2rvxvdb7cyxd8zlw6dyb|63021689,
|
||||
' debugUnreturnedConnectionStackTraces -> False,
|
||||
' description -> Null,
|
||||
' driverClass -> oracle.jdbc.driver.OracleDriver,
|
||||
' extensions -> {},
|
||||
' factoryClassLocation -> Null,
|
||||
' forceIgnoreUnresolvedTransactions -> False,
|
||||
' forceSynchronousCheckins -> False,
|
||||
' forceUseNamedDriverClass -> False,
|
||||
' identityToken -> 2rvxvdb7cyxd8zlw6dyb|63021689,
|
||||
' idleConnectionTestPeriod -> 600,
|
||||
' initialPoolSize -> 3,
|
||||
' jdbcUrl -> jdbc:oracle:thin:@//10.0.0.110:1521/DBKMT,
|
||||
' maxAdministrativeTaskTime -> 0,
|
||||
' maxConnectionAge -> 0,
|
||||
' maxIdleTime -> 1800,
|
||||
' maxIdleTimeExcessConnections -> 0,
|
||||
' maxPoolSize -> 5,
|
||||
' maxStatements -> 150,
|
||||
' maxStatementsPerConnection -> 0,
|
||||
' minPoolSize -> 3,
|
||||
' numHelperThreads -> 3,
|
||||
' preferredTestQuery -> DBMS_SESSION.SET_IDENTIFIER('whatever'),
|
||||
' privilegeSpawnedThreads -> False,
|
||||
' properties -> {password=******, user=******},
|
||||
' propertyCycle -> 0,
|
||||
' statementCacheNumDeferredCloseThreads -> 0,
|
||||
' testConnectionOnCheckin -> False,
|
||||
' testConnectionOnCheckout -> True,
|
||||
' unreturnedConnectionTimeout -> 0,
|
||||
' userOverrides -> {},
|
||||
' Configuración de los parámetros del pool de conexiones C3P0:
|
||||
jo.RunMethod("setInitialPoolSize", Array(initialPoolSize)) ' Define el número de conexiones que se intentarán crear al iniciar el pool.
|
||||
jo.RunMethod("setMinPoolSize", Array(minPoolSize)) ' Fija el número mínimo de conexiones que el pool mantendrá abiertas.
|
||||
jo.RunMethod("setMaxPoolSize", Array(maxPoolSize)) ' Define el número máximo de conexiones simultáneas.
|
||||
jo.RunMethod("setAcquireIncrement", Array(acquireIncrement)) ' Cuántas conexiones nuevas se añaden en lote si el pool se queda sin disponibles.
|
||||
jo.RunMethod("setMaxIdleTime", Array As Object(config.GetDefault("MaxIdleTime", 300))) ' Tiempo máximo de inactividad de una conexión antes de cerrarse (segundos).
|
||||
jo.RunMethod("setMaxConnectionAge", Array As Object(config.GetDefault("MaxConnectionAge", 900))) ' Tiempo máximo de vida de una conexión (segundos).
|
||||
jo.RunMethod("setCheckoutTimeout", Array As Object(config.GetDefault("CheckoutTimeout", 60000))) ' Tiempo máximo de espera por una conexión del pool (milisegundos).
|
||||
|
||||
' LÍNEAS CRÍTICAS PARA FORZAR UN COMPORTAMIENTO NO SILENCIOSO DE C3P0:
|
||||
' Por defecto, C3P0 puede reintentar muchas veces y no lanzar una excepción si las conexiones iniciales fallan.
|
||||
' Estas líneas fuerzan a C3P0 a ser estricto y reportar errores de inmediato.
|
||||
jo.RunMethod("setAcquireRetryAttempts", Array As Object(1)) ' Limita los intentos iniciales de adquisición a 1.
|
||||
jo.RunMethod("setBreakAfterAcquireFailure", Array As Object(True)) ' ¡Forza a C3P0 a lanzar una excepción si falla al adquirir conexiones!
|
||||
|
||||
' PASO 4: Forzar la creación de conexiones iniciales y verificar el estado.
|
||||
' Este paso es VITAL. Obliga a C3P0 a intentar establecer las conexiones iniciales (InitialPoolSize)
|
||||
' *con la configuración ya establecida*. Si hay un problema de conectividad real, la excepción
|
||||
' se capturará aquí y se reportará.
|
||||
Dim tempCon As SQL = pool.GetConnection ' Adquiere una conexión para forzar al pool a inicializarse.
|
||||
If tempCon.IsInitialized Then
|
||||
tempCon.Close ' Devolvemos la conexión inmediatamente al pool para que esté disponible.
|
||||
End If
|
||||
|
||||
' com.mchange.v2.c3p0.ComboPooledDataSource [
|
||||
' acquireIncrement -> 3,
|
||||
' acquireRetryAttempts -> 30,
|
||||
' acquireRetryDelay -> 1000,
|
||||
' autoCommitOnClose -> False,
|
||||
' automaticTestTable -> Null,
|
||||
' breakAfterAcquireFailure -> False,
|
||||
' checkoutTimeout -> 20000,
|
||||
' connectionCustomizerClassName -> Null,
|
||||
' connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester,
|
||||
' contextClassLoaderSource -> caller,
|
||||
' dataSourceName -> 2rvxvdb7cyxd8zlw6dyb|63021689,
|
||||
' debugUnreturnedConnectionStackTraces -> False,
|
||||
' description -> Null,
|
||||
' driverClass -> oracle.jdbc.driver.OracleDriver,
|
||||
' extensions -> {},
|
||||
' factoryClassLocation -> Null,
|
||||
' forceIgnoreUnresolvedTransactions -> False,
|
||||
' forceSynchronousCheckins -> False,
|
||||
' forceUseNamedDriverClass -> False,
|
||||
' identityToken -> 2rvxvdb7cyxd8zlw6dyb|63021689,
|
||||
' idleConnectionTestPeriod -> 600,
|
||||
' initialPoolSize -> 3,
|
||||
' jdbcUrl -> jdbc:oracle:thin:@//10.0.0.110:1521/DBKMT,
|
||||
' maxAdministrativeTaskTime -> 0,
|
||||
' maxConnectionAge -> 0,
|
||||
' maxIdleTime -> 1800,
|
||||
' maxIdleTimeExcessConnections -> 0,
|
||||
' maxPoolSize -> 5,
|
||||
' maxStatements -> 150,
|
||||
' maxStatementsPerConnection -> 0,
|
||||
' minPoolSize -> 3,
|
||||
' numHelperThreads -> 3,
|
||||
' preferredTestQuery -> DBMS_SESSION.SET_IDENTIFIER('whatever'),
|
||||
' privilegeSpawnedThreads -> False,
|
||||
' properties -> {password=******, user=******},
|
||||
' propertyCycle -> 0,
|
||||
' statementCacheNumDeferredCloseThreads -> 0,
|
||||
' testConnectionOnCheckin -> False,
|
||||
' testConnectionOnCheckout -> True,
|
||||
' unreturnedConnectionTimeout -> 0,
|
||||
' userOverrides -> {},
|
||||
' usesTraditionalReflectiveProxies -> False
|
||||
' ]
|
||||
' ]
|
||||
'
|
||||
Catch
|
||||
' Si ocurre un error durante la inicialización del pool o al forzar la conexión,
|
||||
' este Log es CRÍTICO para el diagnóstico, especialmente en un entorno de producción.
|
||||
Log($"RDCConnector.Initialize para ${DB}: ERROR CRÍTICO al inicializar/forzar conexión: ${LastException.Message}"$)
|
||||
End Try
|
||||
|
||||
' Configuración de depuración de queries. Se activa automáticamente si el proyecto se ejecuta en modo DEBUG.
|
||||
#If DEBUG
|
||||
' DebugQueries = True
|
||||
#Else
|
||||
DebugQueries = False
|
||||
#End If
|
||||
|
||||
' Dim jo2 As JavaObject = pool
|
||||
' Log(jo2.GetField("END_TO_END_CLIENTID_INDEX"))
|
||||
|
||||
' jo.RunMethod("setPreferredTestQuery", Array("BEGIN DBMS_SESSION.SET_IDENTIFIER('whatever'); END;"))
|
||||
' jo.RunMethod("setPreferredTestQuery", Array("alter session set current_schema=MYSCHEMA"))
|
||||
' jo2.RunMethod("setClientIdentifier",Array( "MAX")) ' Tiempo máximo de inactividad antes de cerrar una conexión
|
||||
#if DEBUG
|
||||
DebugQueries = True
|
||||
#else
|
||||
DebugQueries = False
|
||||
#end if
|
||||
' Se obtiene el puerto del servidor HTTP desde la configuración de esta base de datos.
|
||||
' Nota: En el diseño actual, el puerto principal lo define DB1 (config.properties).
|
||||
serverPort = config.Get("ServerPort")
|
||||
|
||||
' Asegura que el identificador DB no sea una cadena vacía para la carga de comandos.
|
||||
If DB = "" Then DB = "DB1"
|
||||
|
||||
' Carga los comandos SQL predefinidos de esta base de datos en el mapa global 'commandsMap'.
|
||||
LoadSQLCommands(config, DB)
|
||||
End Sub
|
||||
|
||||
' Carga el mapa de configuración (JdbcUrl, User, Password, etc.) desde el archivo .properties correspondiente.
|
||||
' DB: El identificador de la base de datos (ej. "DB1", "DB2").
|
||||
' Retorna un Mapa con la configuración leída.
|
||||
Private Sub LoadConfigMap(DB As String) As Map
|
||||
Private DBX As String = ""
|
||||
If DB <> "" Then DBX = "." & DB
|
||||
Log("===========================================")
|
||||
Log($"Leemos el config${DBX}.properties"$)
|
||||
If DB <> "" Then DBX = "." & DB ' Construye el sufijo del nombre de archivo (ej. ".DB2").
|
||||
Log($"Leemos el config${DBX}.properties"$) ' Mantenemos este log para confirmación de carga.
|
||||
Return File.ReadMap("./", "config" & DBX & ".properties")
|
||||
End Sub
|
||||
|
||||
' Obtiene la sentencia SQL completa para un comando dado desde el mapa de comandos cargado.
|
||||
' DB: El identificador de la base de datos.
|
||||
' Key: El nombre del comando SQL (ej. "select_user").
|
||||
' Retorna la sentencia SQL como String.
|
||||
Public Sub GetCommand(DB As String, Key As String) As String
|
||||
Log("==== GetCommand ====")
|
||||
' Log("|" & DB & "|" & Key & "|")
|
||||
commands = Main.commandsMap.get(DB).As(Map)
|
||||
commands = Main.commandsMap.get(DB).As(Map) ' Obtiene los comandos de la DB específica del mapa global.
|
||||
If commands.ContainsKey("sql." & Key) = False Then
|
||||
Log("*** Command not found: " & Key)
|
||||
Log("*** Command not found: " & Key) ' Este log es importante mantenerlo si un comando no se encuentra.
|
||||
End If
|
||||
' Log(commands.ContainsKey("sql." & Key))
|
||||
Log("========= Traemos """ & Key & """ ==========")
|
||||
Log(">>>>>> " & commands.Get("sql." & Key) & " <<<<<<")
|
||||
Return commands.Get("sql." & Key)
|
||||
Return commands.Get("sql." & Key) ' Retorna la sentencia SQL.
|
||||
End Sub
|
||||
|
||||
' Obtiene una conexión SQL funcional del pool de conexiones para la base de datos especificada.
|
||||
' DB: El identificador de la base de datos.
|
||||
' Retorna un objeto SQL (la conexión a la base de datos).
|
||||
Public Sub GetConnection(DB As String) As SQL
|
||||
Log("==== GetConnection ==== ")
|
||||
If DB.EqualsIgnoreCase("DB1") Then DB = "" 'Esto para el config.properties or default
|
||||
If DB.EqualsIgnoreCase("DB1") Then DB = ""
|
||||
' En modo de depuración, recarga los comandos SQL en cada petición.
|
||||
' Esto permite modificar queries en config.properties sin reiniciar el servidor.
|
||||
If DebugQueries Then LoadSQLCommands(LoadConfigMap(DB), DB)
|
||||
Return pool.GetConnection
|
||||
Return pool.GetConnection ' Retorna una conexión del pool.
|
||||
End Sub
|
||||
|
||||
' Carga todos los comandos SQL del mapa de configuración en el mapa global 'commandsMap'.
|
||||
' config2: El mapa de configuración de la DB actual.
|
||||
' DB: El identificador de la base de datos.
|
||||
Private Sub LoadSQLCommands(config2 As Map, DB As String)
|
||||
Log("==== LoadSQLCommands ==== ")
|
||||
Log($"Cargamos los comandos desde el config.${DB}.properties"$)
|
||||
Dim newCommands As Map
|
||||
newCommands.Initialize
|
||||
For Each k As String In config2.Keys
|
||||
If k.StartsWith("sql.") Then
|
||||
newCommands.Put(k, config2.Get(k))
|
||||
If k.StartsWith("sql.") Then ' Busca claves que comiencen con "sql." (ej. "sql.select_user").
|
||||
newCommands.Put(k, config2.Get(k)) ' Añade el comando al mapa.
|
||||
End If
|
||||
Next
|
||||
commands = newCommands
|
||||
' Log($"Inicializado: ${DB} "$ & Main.commandsMap.IsInitialized)
|
||||
Main.commandsMap.Put(DB, commands)
|
||||
commands = newCommands ' Actualiza el mapa de comandos de esta instancia de RDCConnector.
|
||||
Main.commandsMap.Put(DB, commands) ' Almacena el mapa de comandos en el mapa global 'commandsMap' de Main.
|
||||
End Sub
|
||||
|
||||
' Nuevo: Obtiene estadísticas detalladas del pool de conexiones.
|
||||
Public Sub GetPoolStats As Map
|
||||
Dim stats As Map
|
||||
stats.Initialize
|
||||
' Log("--- RDCConnector.GetPoolStats llamado ---") ' Log de inicio
|
||||
|
||||
If pool.IsInitialized Then
|
||||
' Log("RDCConnector.GetPoolStats: Pool está inicializado. Intentando obtener métricas.")
|
||||
Dim jo As JavaObject = pool ' Convertimos el objeto pool a JavaObject para acceder a sus métodos.
|
||||
Try
|
||||
' --- Métricas en tiempo real del pool ---
|
||||
Dim totalConn As Object = jo.RunMethod("getNumConnectionsAllUsers", Null)
|
||||
stats.Put("TotalConnections", totalConn)
|
||||
' Log($"RDCConnector.GetPoolStats: TotalConnections = ${totalConn}"$)
|
||||
|
||||
Dim busyConn As Object = jo.RunMethod("getNumBusyConnectionsAllUsers", Null)
|
||||
stats.Put("BusyConnections", busyConn)
|
||||
' Log($"RDCConnector.GetPoolStats: BusyConnections = ${busyConn}"$)
|
||||
|
||||
Dim idleConn As Object = jo.RunMethod("getNumIdleConnectionsAllUsers", Null)
|
||||
stats.Put("IdleConnections", idleConn)
|
||||
' Log($"RDCConnector.GetPoolStats: IdleConnections = ${idleConn}"$)
|
||||
|
||||
' --- Valores de configuración del pool (para referencia) ---
|
||||
Dim initialSize As Object = jo.RunMethod("getInitialPoolSize", Null)
|
||||
stats.Put("InitialPoolSize", initialSize)
|
||||
' Log($"RDCConnector.GetPoolStats: InitialPoolSize = ${initialSize}"$)
|
||||
|
||||
Dim minSize As Object = jo.RunMethod("getMinPoolSize", Null)
|
||||
stats.Put("MinPoolSize", minSize)
|
||||
' Log($"RDCConnector.GetPoolStats: MinPoolSize = ${minSize}"$)
|
||||
|
||||
Dim maxSize As Object = jo.RunMethod("getMaxPoolSize", Null)
|
||||
stats.Put("MaxPoolSize", maxSize)
|
||||
' Log($"RDCConnector.GetPoolStats: MaxPoolSize = ${maxSize}"$)
|
||||
|
||||
Dim acquireInc As Object = jo.RunMethod("getAcquireIncrement", Null)
|
||||
stats.Put("AcquireIncrement", acquireInc)
|
||||
' Log($"RDCConnector.GetPoolStats: AcquireIncrement = ${acquireInc}"$)
|
||||
|
||||
Dim maxIdle As Object = jo.RunMethod("getMaxIdleTime", Null)
|
||||
stats.Put("MaxIdleTime", maxIdle)
|
||||
' Log($"RDCConnector.GetPoolStats: MaxIdleTime = ${maxIdle}"$)
|
||||
|
||||
Dim maxAge As Object = jo.RunMethod("getMaxConnectionAge", Null)
|
||||
stats.Put("MaxConnectionAge", maxAge)
|
||||
' Log($"RDCConnector.GetPoolStats: MaxConnectionAge = ${maxAge}"$)
|
||||
|
||||
Dim checkoutTime As Object = jo.RunMethod("getCheckoutTimeout", Null)
|
||||
stats.Put("CheckoutTimeout", checkoutTime)
|
||||
' Log($"RDCConnector.GetPoolStats: CheckoutTimeout = ${checkoutTime}"$)
|
||||
|
||||
Catch
|
||||
Log("RDCConnector.GetPoolStats: ERROR CRÍTICO al obtener estadísticas del pool: " & LastException.Message)
|
||||
stats.Put("Error", LastException.Message)
|
||||
End Try
|
||||
Else
|
||||
Log("RDCConnector.GetPoolStats: ADVERTENCIA: Pool NO está inicializado. Retornando mapa con error.")
|
||||
stats.Put("Error", "Pool de conexiones no inicializado para esta DB.")
|
||||
End If
|
||||
|
||||
' *** CORRECCIÓN: Usamos JSONGenerator para serializar el mapa a String para el Log ***
|
||||
Dim tempJsonGen As JSONGenerator ' Declaramos un JSONGenerator temporal
|
||||
tempJsonGen.Initialize(stats) ' Lo inicializamos con el mapa 'stats'
|
||||
' Log("--- RDCConnector.GetPoolStats finalizado. Retornando stats: " & tempJsonGen.ToString & " ---") ' Log de fin con JSON
|
||||
|
||||
Return stats
|
||||
End Sub
|
||||
|
||||
' *** NUEVA SUBRUTINA: Cierra el pool de conexiones de forma ordenada usando JavaObject ***
|
||||
' Este método es crucial para liberar los recursos de la base de datos
|
||||
' cuando un conector RDC ya no es necesario o va a ser reemplazado.
|
||||
Public Sub Close
|
||||
If pool <> Null And pool.IsInitialized Then
|
||||
Log($"RDCConnector: Cerrando pool de conexiones."$)
|
||||
' Convertimos el objeto pool de B4X a un JavaObject para poder llamar a su método 'close()'
|
||||
' que no está expuesto directamente en la envoltura de B4X.
|
||||
Dim joPool As JavaObject = pool
|
||||
joPool.RunMethod("close", Null) ' Llamamos al método 'close()' del objeto Java subyacente de C3P0.
|
||||
End If
|
||||
End Sub
|
||||
Reference in New Issue
Block a user