diff --git a/Cambios.bas b/Cambios.bas
index bbd64e0..15d13b1 100644
--- a/Cambios.bas
+++ b/Cambios.bas
@@ -10,174 +10,154 @@ Version=10.3
Sub Process_Globals
- '- VERSION X.XX.XX (cambios a implementar)
- '- Agregar que se puedan usar cualquier cantidad de archivos config.properties
- '- Agregar que se pueda recargar solo un archivo de configuracion o todos a la vez.
- '- Agregar que el "Test" del manager revise (con el query de Jorge) cuantas conexiones hay actualmente activas,
- '- o si no en el test, un nuevo handler, talvez "Conexiones".
- '- Agregar una forma de probar con carga el servidor
- '- Agregar la opcion de "Queries lentos"
-
- '- VERSION 5.09.15
- ' - feat: Consolidación de mejoras en monitoreo, gestión de pools y hot-swap de configuración.
- '
- ' Este commit integra y consolida todas las mejoras recientes en la robustez,
- ' monitoreo de rendimiento y flexibilidad del servidor jRDC2-Multi.
- '
- ' **Módulos Afectados:** Main.bas, RDCConnector.bas, DBHandlerB4X.bas, DBHandlerJSON.bas, Manager.bas, GlobalParameters.bas.
- '
- ' **Cambios Clave Implementados:**
- '
- ' 1. **Monitoreo Preciso y Robusto del Pool de Conexiones (C3P0) y Peticiones Activas:**
- ' * Se corrigieron las métricas de `BusyConnections` y `TotalConnections` en `query_logs` y el panel `Manager` para reflejar el estado real del pool de C3P0. Esto se logró capturando `BusyConnections` directamente del pool *inmediatamente después* de que un handler adquiere una conexión en `DBHandlerJSON.bas` y `DBHandlerB4X.bas` [1, 2].
- ' * El contador de peticiones activas por base de datos (`GlobalParameters.ActiveRequestsCountByDB`) ahora se incrementa y decrementa de forma consistente. Se asegura que la `dbKey` se resuelva *antes* de la operación de conteo y se aplica una coerción explícita a `Int` (`.As(Int)`) para todas las operaciones, resolviendo inconsistencias de tipo [3, 4].
- ' * La lógica de decremento en la subrutina `Private Sub CleanupAndLog` (presente en `DBHandlerJSON.bas` y `DBHandlerB4X.bas`) se hizo más robusta, verificando que el contador sea mayor que cero antes de decrementar para evitar valores negativos [5].
- ' * Beneficio: Monitoreo preciso y fiable en tiempo real del uso del pool de conexiones y la carga de peticiones activas, mejorando el diagnóstico y la estabilidad del servidor [5, 6].
- '
- ' 2. **Implementación Completa de "Hot-Swap" para Recarga de Configuraciones de DB:**
- ' * La lógica del comando `reload` en `Manager.bas` fue completamente rediseñada para permitir la recarga dinámica de configuraciones de bases de datos sin reiniciar el servidor [7, 8].
- ' * Se utiliza una instancia de `java.util.concurrent.locks.ReentrantLock` (`MainConnectorsLock`) declarada e inicializada en `Main.bas` para proteger de forma atómica la lectura y reemplazo del mapa `Main.Connectors`, que es compartido por múltiples hilos [9, 10].
- ' * Se añadió un método `Public Sub Close` en `RDCConnector.bas` [8], que utiliza `JavaObject` para invocar el método `close()` del `ConnectionPool` (C3P0) subyacente. Esto permite un cierre ordenado de los pools de conexión antiguos, liberando sus recursos de la base de datos de manera limpia durante el "hot-swap" [11, 12].
- ' * La implementación en `Manager.bas` incluye un manejo seguro del bloqueo sin `Finally` (usando una bandera booleana `lockAcquired`) y lógica de validación para abortar la recarga si ocurren errores críticos, manteniendo los conectores antiguos activos para evitar interrupciones del servicio [12, 13].
- ' * Beneficio: Capacidad crítica para actualizar configuraciones de conexión a bases de datos en caliente, mejorando la disponibilidad, simplificando el mantenimiento y previniendo fugas de recursos [14].
- '
- ' 3. **Manejo Mejorado de Peticiones POST con JSON en el Cuerpo:**
- ' * `DBHandlerJSON.bas` fue modificado para detectar y procesar correctamente las peticiones POST que envían el payload JSON directamente en el cuerpo (con `Content-Type: application/json`), en lugar de solo en el parámetro `j` de la URL [14, 15].
- ' * Se asegura la lectura completa del `InputStream` y su cierre explícito para liberar recursos [15, 16].
- ' * Beneficio: Compatibilidad con estándares API web modernos, mejorando la robustez y la adherencia a los estándares sin comprometer la retrocompatibilidad con el "Método Legacy" (GET con parámetro `j`) [16].
- '
- ' 4. **Robustecimiento de la Inicialización del Pool de Conexiones (C3P0):**
- ' * La subrutina `Initialize` en `RDCConnector.bas` fue reordenada y fortalecida. Ahora asegura que la configuración de C3P0 se cargue completamente en la variable de clase `config` y que todas las propiedades del pool se apliquen mediante `jo.RunMethod` *inmediatamente después* de `pool.Initialize` y *antes* de que el pool intente adquirir conexiones [17, 18].
- ' * Se añadieron las líneas `jo.RunMethod("setAcquireRetryAttempts", Array As Object(1))` y `jo.RunMethod("setBreakAfterAcquireFailure", Array As Object(True))` en `RDCConnector.bas`. Estas son cruciales para forzar a C3P0 a lanzar una `SQLException` explícita si falla al crear las conexiones iniciales, en lugar de fallar silenciosamente [18, 19].
- ' * Se implementó una "activación forzada" del pool (`Dim tempCon As SQL = pool.GetConnection` seguido de `tempCon.Close`) dentro de un bloque `Try...Catch` en `RDCConnector.Initialize`. Esto obliga al pool a establecer las conexiones iniciales (`InitialPoolSize`) con la configuración ya aplicada, permitiendo la captura de errores reales si la conexión a la base de datos falla [20].
- ' * Beneficio: Diagnóstico temprano y preciso de problemas de conexión a la base de datos, evitando situaciones donde `TotalConnections` mostraba `0` o la `jdbcUrl` aparecía truncada [19, 21].
- '
- ' 5. **Nuevas Funcionalidades en el Panel de Administración (Manager):**
- ' * Se añadió el comando `slowqueries` al `Manager` para permitir la visualización de las 20 consultas más lentas registradas en la tabla `query_logs` de SQLite [22].
- ' * Se mejoró el comando `totalcon` en `Manager.bas` para mostrar estadísticas detalladas de *todos* los pools de conexión C3P0 configurados, obteniendo métricas en tiempo real (TotalConnections, BusyConnections, IdleConnections, etc.) de cada `RDCConnector` [2, 22].
- ' * Beneficio: Mayor visibilidad y control proactivo sobre el rendimiento y el uso de recursos del servidor desde la interfaz de administración.
- '
- ' 6. **Optimización de la Gestión de Logs (`query_logs`):**
- ' * Se implementó un `Public timerLogs As Timer` en `Main.bas` [conversación], que se inicializa en `AppStart` y ejecuta periódicamente (cada 10 minutos) la subrutina `borraArribaDe15000Logs`.
- ' * La subrutina `borraArribaDe15000Logs` recorta la tabla `query_logs` en `users.db` para mantener solo los 15,000 registros más recientes, y luego realiza un `vacuum` para optimizar el espacio en disco utilizado por la base de datos SQLite [conversación].
- ' * Beneficio: Prevención del crecimiento excesivo de la base de datos de logs de rendimiento, manteniendo un historial manejable y optimizando el uso del almacenamiento a largo plazo.
-
- '- VERSION 5.09.14 (Ahora consolidado en 5.09.15)
- ' -feat: Implementación robusta de monitoreo de pool de conexiones y peticiones activas
- ' -Este commit resuelve problemas críticos en el monitoreo del pool de conexiones (C3P0) y el conteo de peticiones activas por base de datos, mejorando significativamente la visibilidad y fiabilidad del rendimiento del servidor jRDC2-Multi.
- ' -Problemas Identificados y Resueltos:
- ' -1. **Métricas de `BusyConnections` y `TotalConnections` inconsistentes o siempre en `0` en el `Manager` y `query_logs`:**
- ' * **Problema**: Anteriormente, la métrica `busy_connections` en `query_logs` a menudo reportaba `0` o no reflejaba el estado real. De manera similar, el panel de `Manager?command=totalcon` consistentemente mostraba `BusyConnections: 0` y `TotalConnections` estancadas en `InitialPoolSize`, a pesar de que Oracle sí reportaba conexiones activas. Esto generaba confusión sobre el uso real y la expansión del pool.
- ' * **Solución**: Se modificó la lógica en los *handlers* (`DBHandlerJSON.bas` y `DBHandlerB4X.bas`) para capturar la métrica `BusyConnections` directamente del pool de C3P0 **inmediatamente después de que el *handler* adquiere una conexión** (`con = Connector.GetConnection(finalDbKey)`). Este valor se pasa explícitamente a la subrutina `Main.LogQueryPerformance` para su registro en `query_logs` y para ser consumido por `Manager.bas` a través de `RDCConnector.GetPoolStats`. Esto garantiza que el valor registrado y reportado refleje con precisión el número de conexiones activas en el instante de su adquisición. Pruebas exhaustivas confirmaron que C3P0 sí reporta conexiones ocupadas y sí expande `TotalConnections` hasta `MaxPoolSize` cuando la demanda lo exige.
- ' -2. **Contador `handler_active_requests` no decrementaba correctamente:**
- ' * **Problema**: El contador de peticiones activas por base de datos (`GlobalParameters.ActiveRequestsCountByDB`) no mostraba un decremento consistente, resultando en un conteo que solo aumentaba o mostraba valores erráticos en los logs.
- ' * **Solución**:
- ' * Se aseguró la declaración `Public ActiveRequestsCountByDB As Map` en `GlobalParameters.bas`.
- ' * Se garantizó su inicialización como un `srvr.CreateThreadSafeMap` en `Main.AppStart` para un manejo concurrente seguro de los contadores.
- ' * En `DBHandlerJSON.bas`, la `dbKey` (obtenida del parámetro `dbx` del JSON) ahora se resuelve *antes* de incrementar el contador, asegurando que el incremento y el decremento se apliquen siempre a la misma clave de base de datos correcta.
- ' * Se implementó una coerción explícita a `Int` (`.As(Int)`) para todas las operaciones de lectura y escritura (`GetDefault`, `Put`) en `GlobalParameters.ActiveRequestsCountByDB`, resolviendo problemas de tipo que causaban inconsistencias y el fallo en el decremento.
- ' * La lógica de decremento en `Private Sub CleanupAndLog` (presente en ambos *handlers*) se hizo más robusta, verificando que el contador sea mayor que cero antes de decrementar para evitar valores negativos.
- ' -Beneficios de estos Cambios:
- ' * **Monitoreo Preciso y Fiable**: Las métricas `busy_connections` y `handler_active_requests` en `query_logs` y el panel `Manager` ahora son totalmente fiables, proporcionando una visión clara y en tiempo real del uso del pool de conexiones y la carga de peticiones activas por base de datos.
- ' * **Diagnóstico Mejorado**: La visibilidad interna del estado del pool de C3P0 durante las pruebas confirma que la configuración de `RDCConnector` es correcta y que el pool se expande y contrae según lo esperado por la demanda.
- ' * **Robustez del Código**: La gestión de contadores de peticiones activas es ahora consistente, thread-safe y a prueba de fallos de tipo, mejorando la estabilidad general del servidor bajo carga.
-
- '- VERSION 5.09.13.3 (Ahora consolidado en 5.09.15)
- '- Implementación de "Hot-Swap" para recarga de configuraciones de DB sin reiniciar el servidor.
- '- Migración a ReentrantLock para sincronización debido a incompatibilidad con 'Sync'.
- '- **Problemas Resueltos:**
- '- 1. **Falta de "Hot-Swap" en `reload`:** El comando `reload` en `Manager.bas` no permitía la recarga dinámica de las configuraciones de la base de datos (config.properties) sin necesidad de reiniciar el servidor. La implementación anterior simplemente re-inicializaba las instancias existentes de `RDCConnector` in-situ, sin liberar los recursos de los pools de conexión anteriores, lo cual era ineficiente y propenso a errores.
- '- 2. **Ausencia de un mecanismo de cierre de pools:** No existía un método `Close` en `RDCConnector.bas` que permitiera cerrar ordenadamente los `ConnectionPool` (C3P0) y liberar las conexiones a la base de datos, lo que era crítico para un "hot-swap" limpio .
- '- 3. **Incompatibilidad con `Sync`:** La palabra clave `Sync` de B4X no era reconocida por el entorno de desarrollo del usuario, impidiendo su uso para la sincronización de hilos necesaria en el "hot-swap".
- '- 4. **Ausencia de `Finally` en B4X:** La palabra clave `Finally` (común en otros lenguajes como Java para asegurar la liberación de recursos) no está disponible directamente en B4X, lo cual planteó un desafío para garantizar la liberación del `ReentrantLock` de forma segura.
- '- **Cambios Implementados:**
- '- **En `Main.bas`:**
- '- * **Declaración de `MainConnectorsLock`:** Se añadió `Public MainConnectorsLock As JavaObject` en `Sub Process_Globals` para declarar una instancia de `java.util.concurrent.locks.ReentrantLock`, que servirá como objeto de bloqueo global para proteger el mapa `Main.Connectors`.
- '- * **Inicialización de `MainConnectorsLock`:** Se inicializó `MainConnectorsLock.InitializeNewInstance("java.util.concurrent.locks.ReentrantLock", Null)` en `Sub AppStart`, asegurando que el objeto de bloqueo esté listo al inicio del servidor.
- '- **En `RDCConnector.bas`:**
- '- * **Método `Public Sub Close`:** Se añadió esta subrutina al final del módulo. Utiliza `JavaObject` para invocar `joPool.RunMethod("close", Null)` sobre la instancia subyacente de C3P0, permitiendo un cierre ordenado y la liberación de todas las conexiones del pool .
- '- **En `Manager.bas`:**
- '- * **Reemplazo completo de la lógica `If Command = "reload" Then`:**
- '- * **Creación de `newConnectors`:** Se crea un mapa temporal (`Dim newConnectors As Map`) para inicializar las **nuevas instancias** de `RDCConnector` con la configuración fresca de los archivos `.properties` .
- '- * **Preservación de `oldConnectors`:** Se almacena una referencia al mapa `Main.Connectors` actual en un nuevo mapa (`Dim oldConnectors As Map`) para tener acceso a los conectores antiguos que necesitan ser cerrados .
- '- * **Sincronización con `ReentrantLock`:** Para proteger la manipulación del mapa `Main.Connectors` (que es compartido por múltiples hilos), se utilizan `Main.MainConnectorsLock.RunMethod("lock", Null)` y `Main.MainConnectorsLock.RunMethod("unlock", Null)`. Esto asegura que el reemplazo del mapa sea atómico, es decir, que solo un hilo pueda acceder a `Main.Connectors` durante la lectura y la escritura .
- '- * **Manejo de Bloqueo Seguro sin `Finally`:** Dado que `Finally` no está disponible en B4X, se implementó un patrón con una bandera booleana (`lockAcquired`) dentro de un bloque `Try...Catch` para garantizar que `unlock()` siempre se ejecute si `lock()` fue exitoso, previniendo interbloqueos .
- '- * **Cierre explícito de `oldConnectors`:** Después de que los `newConnectors` reemplazan a los `oldConnectors`, se itera sobre el mapa `oldConnectors` y se llama a `oldRDC.Close` para cada conector, liberando sus recursos de base de datos de manera limpia .
- '- * **Validación de inicialización y control de errores:** Se agregó lógica para verificar el éxito de la inicialización de los nuevos conectores y abortar el "hot-swap" si ocurre un error crítico, manteniendo los conectores antiguos activos para evitar una interrupción del servicio .
- '- * **Registro detallado:** Se mejoró la salida del log HTML del `Manager` para mostrar el proceso de recarga, las estadísticas de los pools recién inicializados y el cierre de los antiguos, incluyendo JSON detallado de las métricas de C3P0 .
- '- • Beneficio: Estos cambios dotan al servidor jRDC2-Multi de una capacidad crítica para actualizar sus configuraciones de conexión a bases de datos en caliente, sin necesidad de reiniciar el servicio. Esto mejora la disponibilidad, simplifica el mantenimiento y previene fugas de recursos al asegurar el cierre ordenado de los pools de conexión antiguos.
-
- '- VERSION 5.09.13.2 (Ahora consolidado en 5.09.15)
- '- Módulo: DBHandlerJSON.bas
- '- Descripción de Cambios: Manejo de Peticiones POST con Content-Type: application/json
- '- • Problema Identificado: La implementación anterior de DBHandlerJSON procesaba las peticiones POST esperando que el payload JSON se encontrara en el parámetro j de la URL (req.GetParameter("j")). Esto impedía la correcta lectura de peticiones POST que utilizaban Content-Type: application/json, donde el JSON se envía directamente en el cuerpo de la petición (InputStream). Como resultado, los clientes recibían un error indicando la ausencia del parámetro j .
- '- • Solución Implementada:
- '- 1. Se modificó la lógica en el método Handle para detectar explícitamente las peticiones POST con Content-Type igual a application/json.
- '- 2. En estos casos, el payload JSON ahora se lee directamente del InputStream de la petición (req.InputStream).
- '- 3. Se utilizó Bit.InputStreamToBytes(Is0) para leer el cuerpo completo de la petición a un Array de bytes, seguido de BytesToString para convertirlo en la cadena JSON.
- '- 4. Se añadió el cierre explícito del InputStream (Is0.Close) para asegurar la liberación de recursos .
- '- 5. Se corrigió el nombre de la variable Is a Is0 para evitar un conflicto con la palabra reservada Is de B4X .
- '- 6. Se actualizó el mensaje de error para aclarar que el JSON puede faltar tanto en el parámetro j como en el cuerpo de la petición.
- '- • Beneficio: Esta corrección asegura que el DBHandlerJSON sea compatible con el "Método Recomendado" de POST con application/json, mejorando la robustez y la adherencia a los estándares de las APIs web, Sin comprometer la retrocompatibilidad con el "Método Legacy" (GET con parámetro j).
-
- '- VERSION 5.09.13 (Ahora consolidado en 5.09.15)
- ' feat: Mejora la inicialización del pool de conexiones y el soporte multi-DB.
- '
- ' **Problemas Resueltos:**
- '
- ' 1. **Inicialización de `TotalConnections: 0` en todos los pools:** Anteriormente, el Log mostraba 0 conexiones inicializadas para todas las bases de datos (DB1, DB2, DB3, DB4) durante `AppStart`, a pesar de que los `handlers` de `DBHandlerB4X` y `DBHandlerJSON` podían conectarse más tarde bajo demanda. Esto indicaba un fallo silencioso en la creación de conexiones iniciales por parte de C3P0.
- ' 2. **Configuración inconsistente de C3P0:** Parámetros críticos de C3P0 como `acquireRetryAttempts` y `breakAfterAcquireFailure` no se aplicaban correctamente al inicio, manteniendo los valores por defecto que ocultaban errores de conexión.
- ' 3. **`jdbcUrl` truncado/vacío:** Se observó que la `jdbcUrl` aparecía truncada o vacía en algunos logs de C3P0, indicando un problema en la carga de la configuración.
- '
- ' **Cambios Implementados:**
- '
- ' **En `Main.bas`:**
- '
- ' * **Declaración de conectores:** Se aseguró la declaración de variables `Dim conX As RDCConnector` separadas para cada conector (con1, con2, con3, con4) para evitar conflictos de variables y asegurar la inicialización correcta.
- '
- ' **En `RDCConnector.bas`:**
- '
- ' * **Corrección de shadowing de `config`:** Se modificó `LoadConfigMap(DB)` para asignar directamente a la variable de clase `config` (eliminando `Dim` local), resolviendo el problema de la `jdbcUrl` truncada y asegurando que cada `RDCConnector` use su configuración específica de manera persistente.
- ' * **Reordenamiento y robustecimiento de `Initialize`:**
- ' * **Carga de `config`:** Se asegura que `config` se cargue completamente en la variable de clase antes de cualquier operación del pool.
- ' * **Configuración de C3P0:** Todas las propiedades del pool (incluyendo `setInitialPoolSize`, `setMinPoolSize`, `setMaxPoolSize`, `setMaxIdleTime`, etc. ahora se aplican mediante `jo.RunMethod` *inmediatamente después* de `pool.Initialize` y *antes* de que el pool intente adquirir conexiones.
- ' * **Forzar reportes de errores:** Se añadieron las líneas `jo.RunMethod("setAcquireRetryAttempts", Array As Object(1))` y `jo.RunMethod("setBreakAfterAcquireFailure", Array As Object(True))`. Estas son cruciales para forzar a C3P0 a lanzar una `SQLException` explícita si falla al crear las conexiones iniciales, en lugar de fallar silenciosamente.
- ' * **Activación forzada del pool:** Se implementó `Dim tempCon As SQL = pool.GetConnection` seguido de `tempCon.Close` dentro de un bloque `Try...Catch`. Esto obliga al pool a establecer las conexiones iniciales (`InitialPoolSize`) con la configuración ya aplicada, permitiendo la captura de errores reales si la conexión falla.
-
- '- VERSION 5.09.08
- '- Se agregó que se puedan configurar en el config.properties los siguientes parametros:
- '- - setInitialPoolSize = 3
- '- - setMinPoolSize = 2
- '- - setMaxPoolSize = 5
- '- Se agregaron en duro a RDConnector los siguientes parametros:
- '- - setMaxIdleTime <-- Tiempo máximo de inactividad de la conexión.
- '- - setMaxConnectionAge <-- Tiempo de vida máximo de una conexión.
- '- - setCheckoutTimeout <-- Tiempo máximo de espera por una conexión.
- '- Se agregó en el config.properties, al final del "JdbcUrl" este parametro, que le indica al servidor de Oracle
- '- el nombre del cliente que se está conectando "?v$session.program=jRDC_Multi"
- '- VERSION 5.09.08
- '- Se cambio el codigo para que en lugar de esperar un mapa con los parametros del query y nombres de los parametros (par1, par2, etc) para definir el ordenamiento, ahora se espera una lista [1,"2",3], y el orden de los parametros se toma directamente del orden en el que se mandan, de la misma forma que en B4A.
- '- VERSION 5.09.04
- '- Se cambio el nombre del handler de B4X a DBHandlerB4X.
- '- Se quitaron los handlers que ya no servian.
- '- VERSION 5.09.01
- '- Se corrigieron errores en "Manager".
- '- Se cambiaron nombres de handlers.
- '- Se corrigio un error en la ruta de "www/login.html".
- '- VERSION 5.08.31
- '- Se corrigio que no avisaba cuando el query no requeria parametros y si se enviaban (en el JSONHandler)
- '- VERSION 5.08.30
- '- Se cambiaron los 4 handlers de B4A a uno solo que toma el DB de la ruta automáticamente.
- '- Se agregaron validaciones del numero de parametros y si el query no los requiere o se dan de mas o de menos, manda un error especificando eso, ya no se reciben errores directos de la base de datos, esto fue tanto para B4A como para JSON.
- '- Se modificó el Readme.md para incluir todos estos cambios.
- '- VERSION 5.08.25
- '- Se modificaron los archivos de reinicio de los servicios (servidor y Bow) y se cambio el menu del "manager" para que a seccion de "reload" incluya la liga a reinciar Bow.
- '- VERSION 5.08.02
- '- Se hizo un cambio para tratar de que las conexiones se "identifiquen" con Oracle y Jorge pueda saber que conexiones/recursos estamos ocupando
- '- VERSION 4.11.14
- '- Se agregó el parametro "setMaxPoolSize=5" para que solo genere 5 conexiones a la base de datos, antes generaba 15.
- '- Se quitaron lineas previamente comentadas.
- '- VERSION 4.11.09
- '- Commit inicial on Nov 9, 2024
+' - VERSION X.XX.XX (cambios a implementar)
+' - Agregar que se puedan usar cualquier cantidad de archivos config.properties
+' - Agregar que se pueda recargar solo un archivo de configuracion o todos a la vez.
+' - Agregar que el "Test" del manager revise (con el query de Jorge) cuantas conexiones hay actualmente activas,
+' - o si no en el test, un nuevo handler, talvez "Conexiones".
+' - Agregar una forma de probar con carga el servidor
+'
+' - VERSION 5.09.16
+' feat: Implementa tolerancia de parámetros configurable y mejora estabilidad general del servidor.
+' La tolerancia de parametros permite que si un query requiere 3 parametros y se mandan 4, NO mande un error,
+' solo manda a la base de datos los parametros correctos y tira los extras, y guarda una "ADVERTENCIA" en el Log de errores.
+'
+' Este commit introduce la funcionalidad de `parameterTolerance` configurable y aborda varias mejoras críticas para la estabilidad y eficiencia del jRDC2-Multi.
+'
+' Principales cambios y beneficios:
+' - **Tolerancia de Parámetros**: Añade la propiedad `parameterTolerance` en `config.properties` para controlar el manejo de parámetros de más. Cuando está habilitada, recorta los parámetros excesivos; si está deshabilitada (modo estricto, por defecto), genera un error, aumentando la robustez de la validación.
+' - **Inicialización Multi-DB Confiable**: Corrige la lógica de inicialización en `Main.AppStart` para `RDCConnector` de DB3 y DB4, asegurando que cada base de datos tenga su propio *pool* de conexiones correctamente configurado.
+' - **Optimización de Ejecución SQL**: Elimina llamadas duplicadas a `ExecQuery2` y `ExecNonQuery2` en `DBHandlerB4X.bas`, garantizando que solo los parámetros validados se utilicen y evitando ejecuciones redundantes en la base de datos.
+' - **Refactorización y Limpieza**: Se eliminó la declaración duplicada de `ActiveRequestsCountByDB` en `Main.bas` y la subrutina `Handle0` obsoleta en `Manager.bas`, mejorando la claridad y mantenibilidad del código.
+'
+' - VERSION 5.09.15
+'
+' 1. **Nuevas Funcionalidades en el Panel de Administración (Manager):**
+' * Se añadió el comando `slowqueries` al `Manager` para permitir la visualización de las 20 consultas más lentas registradas en la tabla `query_logs` de SQLite [22].
+' * Se mejoró el comando `totalcon` en `Manager.bas` para mostrar estadísticas detalladas de *todos* los pools de conexión C3P0 configurados, obteniendo métricas en tiempo real (TotalConnections, BusyConnections, IdleConnections, etc.) de cada `RDCConnector` [2, 22].
+' * Beneficio: Mayor visibilidad y control proactivo sobre el rendimiento y el uso de recursos del servidor desde la interfaz de administración.
+'
+' 2. **Optimización de la Gestión de Logs (`query_logs`):**
+' * Se implementó un `Public timerLogs As Timer` en `Main.bas` [conversación], que se inicializa en `AppStart` y ejecuta periódicamente (cada 10 minutos) la subrutina `borraArribaDe15000Logs`.
+' * La subrutina `borraArribaDe15000Logs` recorta la tabla `query_logs` en `users.db` para mantener solo los 15,000 registros más recientes, y luego realiza un `vacuum` para optimizar el espacio en disco utilizado por la base de datos SQLite [conversación].
+' * Beneficio: Prevención del crecimiento excesivo de la base de datos de logs de rendimiento, manteniendo un historial manejable y optimizando el uso del almacenamiento a largo plazo.
+'
+' - VERSION 5.09.14 (Ahora consolidado en 5.09.15)
+' -feat: Implementación robusta de monitoreo de pool de conexiones y peticiones activas
+' -Este commit resuelve problemas críticos en el monitoreo del pool de conexiones (C3P0) y el conteo de peticiones activas por base de datos, mejorando significativamente la visibilidad y fiabilidad del rendimiento del servidor jRDC2-Multi.
+' -Problemas Identificados y Resueltos:
+' -1. **Métricas de `BusyConnections` y `TotalConnections` inconsistentes o siempre en `0` en el `Manager` y `query_logs`:**
+' * **Problema**: Anteriormente, la métrica `busy_connections` en `query_logs` a menudo reportaba `0` o no reflejaba el estado real. De manera similar, el panel de `Manager?command=totalcon` consistentemente mostraba `BusyConnections: 0` y `TotalConnections` estancadas en `InitialPoolSize`, a pesar de que Oracle sí reportaba conexiones activas. Esto generaba confusión sobre el uso real y la expansión del pool.
+' * **Solución**: Se modificó la lógica en los *handlers* (`DBHandlerJSON.bas` y `DBHandlerB4X.bas`) para capturar la métrica `BusyConnections` directamente del pool de C3P0 **inmediatamente después de que el *handler* adquiere una conexión** (`con = Connector.GetConnection(finalDbKey)`). Este valor se pasa explícitamente a la subrutina `Main.LogQueryPerformance` para su registro en `query_logs` y para ser consumido por `Manager.bas` a través de `RDCConnector.GetPoolStats`. Esto garantiza que el valor registrado y reportado refleje con precisión el número de conexiones activas en el instante de su adquisición. Pruebas exhaustivas confirmaron que C3P0 sí reporta conexiones ocupadas y sí expande `TotalConnections` hasta `MaxPoolSize` cuando la demanda lo exige.
+' -2. **Contador `handler_active_requests` no decrementaba correctamente:**
+' * **Problema**: El contador de peticiones activas por base de datos (`GlobalParameters.ActiveRequestsCountByDB`) no mostraba un decremento consistente, resultando en un conteo que solo aumentaba o mostraba valores erráticos en los logs.
+' * **Solución**:
+' * Se aseguró la declaración `Public ActiveRequestsCountByDB As Map` en `GlobalParameters.bas`.
+' * Se garantizó su inicialización como un `srvr.CreateThreadSafeMap` en `Main.AppStart` para un manejo concurrente seguro de los contadores.
+' * En `DBHandlerJSON.bas`, la `dbKey` (obtenida del parámetro `dbx` del JSON) ahora se resuelve *antes* de incrementar el contador, asegurando que el incremento y el decremento se apliquen siempre a la misma clave de base de datos correcta.
+' * Se implementó una coerción explícita a `Int` (`.As(Int)`) para todas las operaciones de lectura y escritura (`GetDefault`, `Put`) en `GlobalParameters.ActiveRequestsCountByDB`, resolviendo problemas de tipo que causaban inconsistencias y el fallo en el decremento.
+' * La lógica de decremento en `Private Sub CleanupAndLog` (presente en ambos *handlers*) se hizo más robusta, verificando que el contador sea mayor que cero antes de decrementar para evitar valores negativos.
+' -Beneficios de estos Cambios:
+' * **Monitoreo Preciso y Fiable**: Las métricas `busy_connections` y `handler_active_requests` en `query_logs` y el panel `Manager` ahora son totalmente fiables, proporcionando una visión clara y en tiempo real del uso del pool de conexiones y la carga de peticiones activas por base de datos.
+' * **Diagnóstico Mejorado**: La visibilidad interna del estado del pool de C3P0 durante las pruebas confirma que la configuración de `RDCConnector` es correcta y que el pool se expande y contrae según lo esperado por la demanda.
+' * **Robustez del Código**: La gestión de contadores de peticiones activas es ahora consistente, thread-safe y a prueba de fallos de tipo, mejorando la estabilidad general del servidor bajo carga.
+'
+' - VERSION 5.09.13.3 (Ahora consolidado en 5.09.15)
+' - Implementación de "Hot-Swap" para recarga de configuraciones de DB sin reiniciar el servidor.
+' - Migración a ReentrantLock para sincronización debido a incompatibilidad con 'Sync'.
+' - **Problemas Resueltos:**
+' - 1. **Falta de "Hot-Swap" en `reload`:** El comando `reload` en `Manager.bas` no permitía la recarga dinámica de las configuraciones de la base de datos (config.properties) sin necesidad de reiniciar el servidor. La implementación anterior simplemente re-inicializaba las instancias existentes de `RDCConnector` in-situ, sin liberar los recursos de los pools de conexión anteriores, lo cual era ineficiente y propenso a errores.
+' - 2. **Ausencia de un mecanismo de cierre de pools:** No existía un método `Close` en `RDCConnector.bas` que permitiera cerrar ordenadamente los `ConnectionPool` (C3P0) y liberar las conexiones a la base de datos, lo que era crítico para un "hot-swap" limpio .
+' - 3. **Incompatibilidad con `Sync`:** La palabra clave `Sync` de B4X no era reconocida por el entorno de desarrollo del usuario, impidiendo su uso para la sincronización de hilos necesaria en el "hot-swap".
+' - 4. **Ausencia de `Finally` en B4X:** La palabra clave `Finally` (común en otros lenguajes como Java para asegurar la liberación de recursos) no está disponible directamente en B4X, lo cual planteó un desafío para garantizar la liberación del `ReentrantLock` de forma segura.
+' - **Cambios Implementados:**
+' - **En `Main.bas`:**
+' - * **Declaración de `MainConnectorsLock`:** Se añadió `Public MainConnectorsLock As JavaObject` en `Sub Process_Globals` para declarar una instancia de `java.util.concurrent.locks.ReentrantLock`, que servirá como objeto de bloqueo global para proteger el mapa `Main.Connectors`.
+' - * **Inicialización de `MainConnectorsLock`:** Se inicializó `MainConnectorsLock.InitializeNewInstance("java.util.concurrent.locks.ReentrantLock", Null)` en `Sub AppStart`, asegurando que el objeto de bloqueo esté listo al inicio del servidor.
+' - **En `RDCConnector.bas`:**
+' - * **Método `Public Sub Close`:** Se añadió esta subrutina al final del módulo. Utiliza `JavaObject` para invocar `joPool.RunMethod("close", Null)` sobre la instancia subyacente de C3P0, permitiendo un cierre ordenado y la liberación de todas las conexiones del pool .
+' - **En `Manager.bas`:**
+' - * **Reemplazo completo de la lógica `If Command = "reload" Then`:**
+' - * **Creación de `newConnectors`:** Se crea un mapa temporal (`Dim newConnectors As Map`) para inicializar las **nuevas instancias** de `RDCConnector` con la configuración fresca de los archivos `.properties` .
+' - * **Preservación de `oldConnectors`:** Se almacena una referencia al mapa `Main.Connectors` actual en un nuevo mapa (`Dim oldConnectors As Map`) para tener acceso a los conectores antiguos que necesitan ser cerrados .
+' - * **Sincronización con `ReentrantLock`:** Para proteger la manipulación del mapa `Main.Connectors` (que es compartido por múltiples hilos), se utilizan `Main.MainConnectorsLock.RunMethod("lock", Null)` y `Main.MainConnectorsLock.RunMethod("unlock", Null)`. Esto asegura que el reemplazo del mapa sea atómico, es decir, que solo un hilo pueda acceder a `Main.Connectors` durante la lectura y la escritura .
+' - * **Manejo de Bloqueo Seguro sin `Finally`:** Dado que `Finally` no está disponible en B4X, se implementó un patrón con una bandera booleana (`lockAcquired`) dentro de un bloque `Try...Catch` para garantizar que `unlock()` siempre se ejecute si `lock()` fue exitoso, previniendo interbloqueos .
+' - * **Cierre explícito de `oldConnectors`:** Después de que los `newConnectors` reemplazan a los `oldConnectors`, se itera sobre el mapa `oldConnectors` y se llama a `oldRDC.Close` para cada conector, liberando sus recursos de base de datos de manera limpia .
+' - * **Validación de inicialización y control de errores:** Se agregó lógica para verificar el éxito de la inicialización de los nuevos conectores y abortar el "hot-swap" si ocurre un error crítico, manteniendo los conectores antiguos activos para evitar una interrupción del servicio .
+' - * **Registro detallado:** Se mejoró la salida del log HTML del `Manager` para mostrar el proceso de recarga, las estadísticas de los pools recién inicializados y el cierre de los antiguos, incluyendo JSON detallado de las métricas de C3P0 .
+' - • Beneficio: Estos cambios dotan al servidor jRDC2-Multi de una capacidad crítica para actualizar sus configuraciones de conexión a bases de datos en caliente, sin necesidad de reiniciar el servicio. Esto mejora la disponibilidad, simplifica el mantenimiento y previene fugas de recursos al asegurar el cierre ordenado de los pools de conexión antiguos.
+'
+' - VERSION 5.09.13.2 (Ahora consolidado en 5.09.15)
+' - Módulo: DBHandlerJSON.bas
+' - Descripción de Cambios: Manejo de Peticiones POST con Content-Type: application/json
+' - • Problema Identificado: La implementación anterior de DBHandlerJSON procesaba las peticiones POST esperando que el payload JSON se encontrara en el parámetro j de la URL (req.GetParameter("j")). Esto impedía la correcta lectura de peticiones POST que utilizaban Content-Type: application/json, donde el JSON se envía directamente en el cuerpo de la petición (InputStream). Como resultado, los clientes recibían un error indicando la ausencia del parámetro j .
+' - • Solución Implementada:
+' - 1. Se modificó la lógica en el método Handle para detectar explícitamente las peticiones POST con Content-Type igual a application/json.
+' - 2. En estos casos, el payload JSON ahora se lee directamente del InputStream de la petición (req.InputStream).
+' - 3. Se utilizó Bit.InputStreamToBytes(Is0) para leer el cuerpo completo de la petición a un Array de bytes, seguido de BytesToString para convertirlo en la cadena JSON.
+' - 4. Se añadió el cierre explícito del InputStream (Is0.Close) para asegurar la liberación de recursos .
+' - 5. Se corrigió el nombre de la variable Is a Is0 para evitar un conflicto con la palabra reservada Is de B4X .
+' - 6. Se actualizó el mensaje de error para aclarar que el JSON puede faltar tanto en el parámetro j como en el cuerpo de la petición.
+' - • Beneficio: Esta corrección asegura que el DBHandlerJSON sea compatible con el "Método Recomendado" de POST con application/json, mejorando la robustez y la adherencia a los estándares de las APIs web, Sin comprometer la retrocompatibilidad con el "Método Legacy" (GET con parámetro j).
+'
+' - VERSION 5.09.13 (Ahora consolidado en 5.09.15)
+' feat: Mejora la inicialización del pool de conexiones y el soporte multi-DB.
+'
+' **Problemas Resueltos:**
+'
+' 1. **Inicialización de `TotalConnections: 0` en todos los pools:** Anteriormente, el Log mostraba 0 conexiones inicializadas para todas las bases de datos (DB1, DB2, DB3, DB4) durante `AppStart`, a pesar de que los `handlers` de `DBHandlerB4X` y `DBHandlerJSON` podían conectarse más tarde bajo demanda. Esto indicaba un fallo silencioso en la creación de conexiones iniciales por parte de C3P0.
+' 2. **Configuración inconsistente de C3P0:** Parámetros críticos de C3P0 como `acquireRetryAttempts` y `breakAfterAcquireFailure` no se aplicaban correctamente al inicio, manteniendo los valores por defecto que ocultaban errores de conexión.
+' 3. **`jdbcUrl` truncado/vacío:** Se observó que la `jdbcUrl` aparecía truncada o vacía en algunos logs de C3P0, indicando un problema en la carga de la configuración.
+'
+' **Cambios Implementados:**
+'
+' **En `Main.bas`:**
+'
+' * **Declaración de conectores:** Se aseguró la declaración de variables `Dim conX As RDCConnector` separadas para cada conector (con1, con2, con3, con4) para evitar conflictos de variables y asegurar la inicialización correcta.
+'
+' **En `RDCConnector.bas`:**
+'
+' * **Corrección de shadowing de `config`:** Se modificó `LoadConfigMap(DB)` para asignar directamente a la variable de clase `config` (eliminando `Dim` local), resolviendo el problema de la `jdbcUrl` truncada y asegurando que cada `RDCConnector` use su configuración específica de manera persistente.
+' * **Reordenamiento y robustecimiento de `Initialize`:**
+' * **Carga de `config`:** Se asegura que `config` se cargue completamente en la variable de clase antes de cualquier operación del pool.
+' * **Configuración de C3P0:** Todas las propiedades del pool (incluyendo `setInitialPoolSize`, `setMinPoolSize`, `setMaxPoolSize`, `setMaxIdleTime`, etc. ahora se aplican mediante `jo.RunMethod` *inmediatamente después* de `pool.Initialize` y *antes* de que el pool intente adquirir conexiones.
+' * **Forzar reportes de errores:** Se añadieron las líneas `jo.RunMethod("setAcquireRetryAttempts", Array As Object(1))` y `jo.RunMethod("setBreakAfterAcquireFailure", Array As Object(True))`. Estas son cruciales para forzar a C3P0 a lanzar una `SQLException` explícita si falla al crear las conexiones iniciales, en lugar de fallar silenciosamente.
+' * **Activación forzada del pool:** Se implementó `Dim tempCon As SQL = pool.GetConnection` seguido de `tempCon.Close` dentro de un bloque `Try...Catch`. Esto obliga al pool a establecer las conexiones iniciales (`InitialPoolSize`) con la configuración ya aplicada, permitiendo la captura de errores reales si la conexión falla.
+'
+' - VERSION 5.09.08
+' - Se agregó que se puedan configurar en el config.properties los siguientes parametros:
+' - - setInitialPoolSize = 3
+' - - setMinPoolSize = 2
+' - - setMaxPoolSize = 5
+' - Se agregaron en duro a RDConnector los siguientes parametros:
+' - - setMaxIdleTime <-- Tiempo máximo de inactividad de la conexión.
+' - - setMaxConnectionAge <-- Tiempo de vida máximo de una conexión.
+' - - setCheckoutTimeout <-- Tiempo máximo de espera por una conexión.
+' - Se agregó en el config.properties, al final del "JdbcUrl" este parametro, que le indica al servidor de Oracle
+' - el nombre del cliente que se está conectando "?v$session.program=jRDC_Multi"
+' - VERSION 5.09.08
+' - Se cambio el codigo para que en lugar de esperar un mapa con los parametros del query y nombres de los parametros (par1, par2, etc) para definir el ordenamiento, ahora se espera una lista [1,"2",3], y el orden de los parametros se toma directamente del orden en el que se mandan, de la misma forma que en B4A.
+' - VERSION 5.09.04
+' - Se cambio el nombre del handler de B4X a DBHandlerB4X.
+' - Se quitaron los handlers que ya no servian.
+' - VERSION 5.09.01
+' - Se corrigieron errores en "Manager".
+' - Se cambiaron nombres de handlers.
+' - Se corrigio un error en la ruta de "www/login.html".
+' - VERSION 5.08.31
+' - Se corrigio que no avisaba cuando el query no requeria parametros y si se enviaban (en el JSONHandler)
+' - VERSION 5.08.30
+' - Se cambiaron los 4 handlers de B4A a uno solo que toma el DB de la ruta automáticamente.
+' - Se agregaron validaciones del numero de parametros y si el query no los requiere o se dan de mas o de menos, manda un error especificando eso, ya no se reciben errores directos de la base de datos, esto fue tanto para B4A como para JSON.
+' - Se modificó el Readme.md para incluir todos estos cambios.
+' - VERSION 5.08.25
+' - Se modificaron los archivos de reinicio de los servicios (servidor y Bow) y se cambio el menu del "manager" para que a seccion de "reload" incluya la liga a reinciar Bow.
+' - VERSION 5.08.02
+' - Se hizo un cambio para tratar de que las conexiones se "identifiquen" con Oracle y Jorge pueda saber que conexiones/recursos estamos ocupando
+' - VERSION 4.11.14
+' - Se agregó el parametro "setMaxPoolSize=5" para que solo genere 5 conexiones a la base de datos, antes generaba 15.
+' - Se quitaron lineas previamente comentadas.
+' - VERSION 4.11.09
+' - Commit inicial on Nov 9, 2024
End Sub
\ No newline at end of file
diff --git a/ChangePassHandler.bas b/ChangePassHandler.bas
index 2ad28e0..2665945 100644
--- a/ChangePassHandler.bas
+++ b/ChangePassHandler.bas
@@ -32,8 +32,7 @@ Public Sub Handle(req As ServletRequest, resp As ServletResponse)
Try
Dim storedHash As String = Main.SQL1.ExecQuerySingleResult2("SELECT password_hash FROM users WHERE username = ?", Array As String(currentUser))
-
- Log("--- Probando con contraseña fija ---")
+
Log("Valor de la BD (storedHash): " & storedHash)
If storedHash = Null Or bc.checkpw(currentPass, storedHash) = False Then ' <<--- CAMBIO CLAVE AQUÍ
resp.Write("")
diff --git a/DBHandlerB4X.bas b/DBHandlerB4X.bas
index 4f0bacb..c6482d2 100644
--- a/DBHandlerB4X.bas
+++ b/DBHandlerB4X.bas
@@ -17,7 +17,7 @@ Sub Class_Globals
' La siguiente sección de constantes y utilidades se compila condicionalmente
' solo si la directiva #if VERSION1 está activa. Esto es para dar soporte
' a una versión antigua del protocolo de comunicación de DBRequestManager.
- #if VERSION1
+' #if VERSION1
' Constantes para identificar los tipos de datos en la serialización personalizada (protocolo V1).
Private const T_NULL = 0, T_STRING = 1, T_SHORT = 2, T_INT = 3, T_LONG = 4, T_FLOAT = 5 _
,T_DOUBLE = 6, T_BOOLEAN = 7, T_BLOB = 8 As Byte
@@ -25,7 +25,7 @@ Sub Class_Globals
Private bc As ByteConverter
' Utilidad para comprimir/descomprimir streams de datos (usado en V1).
Private cs As CompressedStreams
- #end if
+' #end if
' Mapa para convertir tipos de columna JDBC de fecha/hora a los nombres de métodos de Java
' para obtener los valores correctos de ResultSet.
@@ -68,13 +68,11 @@ Sub Handle(req As ServletRequest, resp As ServletResponse)
' Verifica si el dbKey extraído corresponde a una base de datos configurada y cargada en Main.
If Main.Connectors.ContainsKey(dbKey) = False Then
- ' Si la base de datos no es válida, se construye un mensaje de error y se envía.
Dim ErrorMsg As String = $"Invalid DB key specified in URL: '${dbKey}'. Valid keys are: ${Main.listaDeCP}"$
Log(ErrorMsg)
- SendPlainTextError(resp, 400, ErrorMsg) ' Envía una respuesta de error al cliente.
- ' No se llama a CleanupAndLog aquí, ya que el contador de peticiones no se ha incrementado
- ' y no se ha obtenido ninguna conexión del pool.
- Return ' Termina la ejecución del handler.
+ Main.LogServerError("ERROR", "DBHandlerB4X.Handle", ErrorMsg, dbKey, Null, req.RemoteAddress) ' <-- Nuevo Log
+ SendPlainTextError(resp, 400, ErrorMsg)
+ Return
End If
' === FIN DE LA LÓGICA DINÁMICA ===
@@ -130,7 +128,7 @@ Sub Handle(req As ServletRequest, resp As ServletResponse)
CleanupAndLog(dbKey, "error_in_" & method, duration, req.RemoteAddress, requestsBeforeDecrement, poolBusyConnectionsForLog, con)
Return ' Salida temprana si hay un error.
End If
- #if VERSION1
+' #if VERSION1
' Estas ramas se compilan solo si #if VERSION1 está activo (para protocolo antiguo).
Else if method = "query" Then
in = cs.WrapInputStream(in, "gzip") ' Descomprime el stream de entrada si es protocolo V1.
@@ -148,7 +146,7 @@ Sub Handle(req As ServletRequest, resp As ServletResponse)
CleanupAndLog(dbKey, "error_in_" & method, duration, req.RemoteAddress, requestsBeforeDecrement, poolBusyConnectionsForLog, con)
Return
End If
- #end if
+' #end if
Else if method = "batch2" Then
' Ejecuta un lote de comandos (INSERT, UPDATE, DELETE) utilizando el protocolo V2.
q = ExecuteBatch2(dbKey, con, in, resp)
@@ -158,18 +156,19 @@ Sub Handle(req As ServletRequest, resp As ServletResponse)
Return ' Salida temprana si hay un error.
End If
Else
- ' Si el método solicitado no es reconocido, se registra un error y se envía una respuesta adecuada.
- Log("Unknown method: " & method)
+ Dim ErrorMsg As String = "Unknown method: " & method
+ Log(ErrorMsg)
+ Main.LogServerError("ERROR", "DBHandlerB4X.Handle", ErrorMsg, dbKey, method, req.RemoteAddress) ' <-- Nuevo Log
SendPlainTextError(resp, 500, "unknown method")
- q = "unknown_method_handler" ' Aseguramos un valor para 'q' para que el log sea informativo.
+ q = "unknown_method_handler"
duration = DateTime.Now - start
CleanupAndLog(dbKey, q, duration, req.RemoteAddress, requestsBeforeDecrement, poolBusyConnectionsForLog, con)
- Return ' Salida temprana.
+ Return
End If
Catch ' --- CATCH: Maneja errores generales de ejecución o de SQL ---
- ' Si ocurre una excepción inesperada durante el procesamiento de la petición.
Log(LastException) ' Registra la excepción completa en el log.
+ Main.LogServerError("ERROR", "DBHandlerB4X.Handle", LastException.Message, dbKey, q, req.RemoteAddress) ' <-- Nuevo Log
SendPlainTextError(resp, 500, LastException.Message) ' Envía un error 500 al cliente.
q = "error_in_b4x_handler" ' Aseguramos un valor para 'q' en caso de excepción.
End Try ' --- FIN: Bloque Try principal ---
@@ -238,34 +237,33 @@ Private Sub ExecuteQuery2 (DB As String, con As SQL, in As InputStream, resp As
If sqlCommand = Null Or sqlCommand = "null" Or sqlCommand.Trim = "" Then
Dim errorMessage As String = $"El comando '${cmd.Name}' no fue encontrado en el config.properties de '${DB}'."$
Log(errorMessage)
+ Main.LogServerError("ERROR", "DBHandlerB4X.ExecuteQuery2", errorMessage, DB, cmd.Name, Null)
' Envía un error 400 (Bad Request) al cliente informando del problema.
SendPlainTextError(resp, 400, errorMessage)
Return "error" ' Retorna un texto para el log.
End If
' <<< FIN NUEVA VALIDACIÓN >>>
- ' --- INICIO VALIDACIÓN DE PARÁMETROS ---
- ' Comprueba si el SQL espera parámetros o si se recibieron parámetros.
- If sqlCommand.Contains("?") Or (cmd.Parameters <> Null And cmd.Parameters.Length > 0) Then
- ' Cuenta cuántos '?' hay en la sentencia SQL para saber cuántos parámetros se esperan.
- Dim expectedParams As Int = sqlCommand.Length - sqlCommand.Replace("?", "").Length
- ' Cuenta cuántos parámetros se recibieron.
- Dim receivedParams As Int
- If cmd.Parameters = Null Then receivedParams = 0 Else receivedParams = cmd.Parameters.Length
-
- ' Compara el número de parámetros esperados con los recibidos.
- If expectedParams <> receivedParams Then
- Dim errorMessage As String = $"Número de parametros equivocado para "${cmd.Name}". Se esperaban ${expectedParams} y se recibieron ${receivedParams}."$
- Log(errorMessage)
- ' Si no coinciden, envía un error 400 al cliente.
- SendPlainTextError(resp, 400, errorMessage)
- Return "error"
- End If
+ ' <<< INICIO VALIDACIÓN DE PARÁMETROS CENTRALIZADA >>>
+ ' Convertimos el array de Object() de cmd.Parameters a una List para la utilidad de validación.
+ Dim paramsAsList As List
+ paramsAsList.Initialize
+ If cmd.Parameters <> Null Then
+ For Each p As Object In cmd.Parameters
+ paramsAsList.Add(p)
+ Next
End If
- ' --- FIN VALIDACIÓN ---
- ' Ejecuta la consulta SQL con los parámetros proporcionados.
- Dim rs As ResultSet = con.ExecQuery2(sqlCommand, cmd.Parameters)
+ Dim validationResult As ParameterValidationResult = ParameterValidationUtils.ValidateAndAdjustParameters(cmd.Name, DB, sqlCommand, paramsAsList, Connector.IsParameterToleranceEnabled)
+
+ If validationResult.Success = False Then
+ SendPlainTextError(resp, 400, validationResult.ErrorMessage)
+ Return "error" ' Salida temprana si la validación falla.
+ End If
+
+ ' Ejecuta la consulta SQL con la lista de parámetros validada.
+ Dim rs As ResultSet = con.ExecQuery2(sqlCommand, validationResult.ParamsToExecute)
+ ' <<< FIN VALIDACIÓN DE PARÁMETROS CENTRALIZADA >>>
' Si el límite es 0 o negativo, lo establece a un valor muy alto (máximo entero).
If limit <= 0 Then limit = 0x7fffffff 'max int
@@ -367,28 +365,32 @@ Private Sub ExecuteBatch2(DB As String, con As SQL, in As InputStream, resp As S
con.Rollback ' Deshace la transacción si un comando es inválido.
Dim errorMessage As String = $"El comando '${cmd.Name}' no fue encontrado en el config.properties de '${DB}'."$
Log(errorMessage)
+ Main.LogServerError("ERROR", "DBHandlerB4X.ExecuteBatch2", errorMessage, DB, cmd.Name, Null)
SendPlainTextError(resp, 400, errorMessage)
Return "error"
End If
' <<< FIN NUEVA VALIDACIÓN >>>
- ' --- INICIO VALIDACIÓN DE PARÁMETROS DENTRO DEL BATCH ---
- If sqlCommand.Contains("?") Or (cmd.Parameters <> Null And cmd.Parameters.Length > 0) Then
- Dim expectedParams As Int = sqlCommand.Length - sqlCommand.Replace("?", "").Length
- Dim receivedParams As Int
- If cmd.Parameters = Null Then receivedParams = 0 Else receivedParams = cmd.Parameters.Length
- ' Si el número de parámetros no coincide, deshace la transacción y envía error.
- If expectedParams <> receivedParams Then
- con.Rollback
- Dim errorMessage As String = $"Número de parametros equivocado para "${cmd.Name}". Se esperaban ${expectedParams} y se recibieron ${receivedParams}."$
- Log(errorMessage)
- SendPlainTextError(resp, 400, errorMessage)
- Return "error"
- End If
+ ' <<< INICIO VALIDACIÓN DE PARÁMETROS CENTRALIZADA DENTRO DEL BATCH >>>
+ ' Convertimos el array de Object() de cmd.Parameters a una List para la utilidad de validación.
+ Dim paramsAsList As List
+ paramsAsList.Initialize
+ If cmd.Parameters <> Null Then
+ For Each p As Object In cmd.Parameters
+ paramsAsList.Add(p)
+ Next
End If
- ' --- FIN VALIDACIÓN ---
- con.ExecNonQuery2(sqlCommand, cmd.Parameters) ' Ejecuta el comando (no es una consulta, no devuelve filas).
+ Dim validationResult As ParameterValidationResult = ParameterValidationUtils.ValidateAndAdjustParameters(cmd.Name, DB, sqlCommand, paramsAsList, Connector.IsParameterToleranceEnabled)
+
+ If validationResult.Success = False Then
+ con.Rollback ' ¡Importante hacer rollback si la validación falla dentro de una transacción!
+ SendPlainTextError(resp, 400, validationResult.ErrorMessage)
+ Return "error" ' Salida temprana si la validación falla.
+ End If
+
+ con.ExecNonQuery2(sqlCommand, validationResult.ParamsToExecute) ' Ejecuta el comando con la lista de parámetros validada.
+ ' <<< FIN VALIDACIÓN DE PARÁMETROS CENTRALIZADA DENTRO DEL BATCH >>>
Next
res.Rows.Add(Array As Object(0)) ' Añade una fila simbólica al resultado para indicar éxito.
@@ -397,6 +399,7 @@ Private Sub ExecuteBatch2(DB As String, con As SQL, in As InputStream, resp As S
' Si cualquier comando falla, se captura el error.
con.Rollback ' Se deshacen todos los cambios hechos en la transacción.
Log(LastException) ' Registra la excepción.
+ Main.LogServerError("ERROR", "DBHandlerB4X.ExecuteBatch2", LastException.Message, DB, "batch_execution_error", Null)
SendPlainTextError(resp, 500, LastException.Message) ' Envía un error 500 al cliente.
End Try
@@ -410,7 +413,7 @@ End Sub
' --- Subrutinas para manejar la ejecución de queries y batches (Protocolo V1 - Compilación Condicional) ---
' Este código se compila solo si #if VERSION1 está activo, para mantener compatibilidad con clientes antiguos.
-#if VERSION1
+'#if VERSION1
' Ejecuta un lote de comandos usando el protocolo V1.
Private Sub ExecuteBatch(DB As String, con As SQL, in As InputStream, resp As ServletResponse) As String
@@ -434,28 +437,23 @@ Private Sub ExecuteBatch(DB As String, con As SQL, in As InputStream, resp As Se
con.Rollback ' Deshace la transacción si un comando es inválido.
Dim errorMessage As String = $"El comando '${queryName}' no fue encontrado en el config.properties de '${DB}'."$
Log(errorMessage)
+ Main.LogServerError("ERROR", "DBHandlerB4X.ExecuteBatch (V1)", errorMessage, DB, queryName, Null)
SendPlainTextError(resp, 400, errorMessage)
Return "error"
End If
- ' <<< FIN NUEVA VALIDACIÓN >>>
+ ' <<< FIN NUEVA VALIDACIÓN >>>
- ' --- INICIO VALIDACIÓN DE PARÁMETROS DENTRO DEL BATCH (V1) ---
- If sqlCommand.Contains("?") Or (params <> Null And params.Size > 0) Then
- Dim expectedParams As Int = sqlCommand.Length - sqlCommand.Replace("?", "").Length
- Dim receivedParams As Int
- If params = Null Then receivedParams = 0 Else receivedParams = params.Size
+ ' <<< INICIO VALIDACIÓN DE PARÁMETROS CENTRALIZADA DENTRO DEL BATCH (V1) >>>
+ Dim validationResult As ParameterValidationResult = ParameterValidationUtils.ValidateAndAdjustParameters(queryName, DB, sqlCommand, params, Connector.IsParameterToleranceEnabled)
- If expectedParams <> receivedParams Then
- con.Rollback
- Dim errorMessage As String = $"Número de parametros equivocado para "${queryName}". Se esperaban ${expectedParams} y se recibieron ${receivedParams}."$
- Log(errorMessage)
- SendPlainTextError(resp, 400, errorMessage)
- Return "error"
- End If
- End If
- ' --- FIN VALIDACIÓN ---
+ If validationResult.Success = False Then
+ con.Rollback ' ¡Importante hacer rollback si la validación falla dentro de una transacción!
+ SendPlainTextError(resp, 400, validationResult.ErrorMessage)
+ Return "error" ' Salida temprana si la validación falla.
+ End If
- con.ExecNonQuery2(sqlCommand, params) ' Ejecuta el comando.
+ con.ExecNonQuery2(sqlCommand, validationResult.ParamsToExecute) ' Ejecuta el comando con la lista de parámetros validada.
+ ' <<< FIN VALIDACIÓN DE PARÁMETROS CENTRALIZADA DENTRO DEL BATCH (V1) >>>
Next
con.TransactionSuccessful ' Confirma la transacción.
@@ -473,6 +471,7 @@ Private Sub ExecuteBatch(DB As String, con As SQL, in As InputStream, resp As Se
Catch
con.Rollback
Log(LastException)
+ Main.LogServerError("ERROR", "DBHandlerB4X.ExecuteBatch (V1)", LastException.Message, DB, "batch_execution_error_v1", Null)
SendPlainTextError(resp, 500, LastException.Message)
End Try
@@ -495,28 +494,23 @@ Private Sub ExecuteQuery(DB As String, con As SQL, in As InputStream, resp As Se
If theSql = Null Or theSql ="null" Or theSql.Trim = "" Then
Dim errorMessage As String = $"El comando '${queryName}' no fue encontrado en el config.properties de '${DB}'."$
Log(errorMessage)
+ Main.LogServerError("ERROR", "DBHandlerB4X.ExecuteQuery (V1)", errorMessage, DB, queryName, Null)
SendPlainTextError(resp, 400, errorMessage)
Return "error"
End If
- ' <<< FIN NUEVA VALIDACIÓN >>>
+ ' <<< FIN NUEVA VALIDACIÓN >>>
- ' --- INICIO VALIDACIÓN DE PARÁMETROS (V1) ---
- If theSql.Contains("?") Or (params <> Null And params.Size > 0) Then
- Dim expectedParams As Int = theSql.Length - theSql.Replace("?", "").Length
- Dim receivedParams As Int
- If params = Null Then receivedParams = 0 Else receivedParams = params.Size
+ ' <<< INICIO VALIDACIÓN DE PARÁMETROS CENTRALIZADA (V1) >>>
+ Dim validationResult As ParameterValidationResult = ParameterValidationUtils.ValidateAndAdjustParameters(queryName, DB, theSql, params, Connector.IsParameterToleranceEnabled)
- If expectedParams <> receivedParams Then
- Dim errorMessage As String = $"Número de parametros equivocado para "${queryName}". Se esperaban ${expectedParams} y se recibieron ${receivedParams}."$
- Log(errorMessage)
- SendPlainTextError(resp, 400, errorMessage)
- Return "error"
- End If
- End If
- ' --- FIN VALIDACIÓN ---
+ If validationResult.Success = False Then
+ SendPlainTextError(resp, 400, validationResult.ErrorMessage)
+ Return "error" ' Salida temprana si la validación falla.
+ End If
- ' Ejecuta la consulta.
- Dim rs As ResultSet = con.ExecQuery2(theSql, params)
+ ' Ejecuta la consulta con la lista de parámetros validada.
+ Dim rs As ResultSet = con.ExecQuery2(theSql, validationResult.ParamsToExecute)
+ ' <<< FIN VALIDACIÓN DE PARÁMETROS CENTRALIZADA (V1) >>>
If limit <= 0 Then limit = 0x7fffffff 'max int
@@ -691,7 +685,7 @@ Private Sub ReadList(in As InputStream) As List
Return l1
End Sub
-#end If ' Fin del bloque de compilación condicional para VERSION1
+'#end If ' Fin del bloque de compilación condicional para VERSION1
' Envía una respuesta de error en formato de texto plano.
' Esto evita la página de error HTML por defecto que genera resp.SendError.
@@ -716,6 +710,8 @@ Private Sub SendPlainTextError(resp As ServletResponse, statusCode As Int, error
Catch
' Si algo falla al intentar enviar la respuesta de error, lo registra en el log
' para que no se pierda la causa original del problema.
- Log("Error sending plain text error response: " & LastException)
+ Dim ErrorMsg As String = "Error sending plain text error response: " & LastException
+ Log(ErrorMsg)
+ Main.LogServerError("ERROR", "DBHandlerB4X.SendPlainTextError", ErrorMsg, Null, Null, Null)
End Try
End Sub
\ No newline at end of file
diff --git a/DBHandlerJSON.bas b/DBHandlerJSON.bas
index d2f74f5..24b822f 100644
--- a/DBHandlerJSON.bas
+++ b/DBHandlerJSON.bas
@@ -63,11 +63,12 @@ Sub Handle(req As ServletRequest, resp As ServletResponse)
' Validación inicial: Si no hay JSON, se envía un error 400.
If jsonString = Null Or jsonString = "" Then
- SendErrorResponse(resp, 400, "Falta el parámetro 'j' en el URL o el cuerpo JSON en la petición.")
+ Dim ErrorMsg As String = "Falta el parámetro 'j' en el URL o el cuerpo JSON en la petición."
+ SendErrorResponse(resp, 400, ErrorMsg)
+ Main.LogServerError("ERROR", "DBHandlerJSON.Handle", ErrorMsg, finalDbKey, queryNameForLog, req.RemoteAddress) ' <-- Nuevo Log
duration = DateTime.Now - start
- ' Llama a CleanupAndLog para registrar que hubo un error, pero con contadores a 0 o inicializados.
CleanupAndLog(finalDbKey, queryNameForLog, duration, req.RemoteAddress, requestsBeforeDecrement, poolBusyConnectionsForLog, con)
- Return ' Salida temprana si no hay JSON válido.
+ Return
End If
Dim parser As JSONParser
@@ -108,10 +109,12 @@ Sub Handle(req As ServletRequest, resp As ServletResponse)
' Validación: Si el dbKey no es válido o no está configurado en Main.listaDeCP.
If Main.listaDeCP.IndexOf(finalDbKey) = -1 Then
- SendErrorResponse(resp, 400, "Parámetro 'DB' inválido. El nombre '" & finalDbKey & "' no es válido.")
+ Dim ErrorMsg As String = "Parámetro 'DB' inválido. El nombre '" & finalDbKey & "' no es válido."
+ SendErrorResponse(resp, 400, ErrorMsg)
+ Main.LogServerError("ERROR", "DBHandlerJSON.Handle", ErrorMsg, finalDbKey, queryNameForLog, req.RemoteAddress) ' <-- Nuevo Log
duration = DateTime.Now - start
CleanupAndLog(finalDbKey, queryNameForLog, duration, req.RemoteAddress, requestsBeforeDecrement, poolBusyConnectionsForLog, con)
- Return ' Salida temprana si la DB no es válida.
+ Return
End If
con = Connector.GetConnection(finalDbKey) ' ¡La conexión a la BD se obtiene aquí del pool de conexiones!
@@ -135,31 +138,30 @@ Sub Handle(req As ServletRequest, resp As ServletResponse)
If sqlCommand = Null Or sqlCommand = "null" Or sqlCommand.Trim = "" Then
Dim errorMessage As String = $"El comando '${queryNameForLog}' no fue encontrado en el config.properties de '${finalDbKey}'."$
Log(errorMessage)
+ Main.LogServerError("ERROR", "DBHandlerJSON.Handle", errorMessage, finalDbKey, queryNameForLog, req.RemoteAddress) ' <-- Nuevo Log
SendErrorResponse(resp, 400, errorMessage)
duration = DateTime.Now - start
CleanupAndLog(finalDbKey, queryNameForLog, duration, req.RemoteAddress, requestsBeforeDecrement, poolBusyConnectionsForLog, con)
- Return ' Salida temprana.
+ Return
End If
' --- Lógica para ejecutar diferentes tipos de comandos basados en el parámetro 'execType' ---
If execType.ToLowerCase = "executequery" Then
- Dim rs As ResultSet
- ' Validación de parámetros para ExecuteQuery.
- If sqlCommand.Contains("?") Or paramsList.Size > 0 Then
- Dim expectedParams As Int = sqlCommand.Length - sqlCommand.Replace("?", "").Length
- Dim receivedParams As Int = paramsList.Size
- Log($"expectedParams: ${expectedParams}, receivedParams: ${receivedParams}"$)
- If expectedParams <> receivedParams Then
- SendErrorResponse(resp, 400, $"Número de parámetros equivocado para '${queryNameForLog}'. Se esperaban ${expectedParams} y se recibieron ${receivedParams}."$)
- duration = DateTime.Now - start
- CleanupAndLog(finalDbKey, queryNameForLog, duration, req.RemoteAddress, requestsBeforeDecrement, poolBusyConnectionsForLog, con)
- Return ' Salida temprana.
- End If
- rs = con.ExecQuery2(sqlCommand, paramsList) ' Ejecuta la consulta con parámetros.
- Else
- rs = con.ExecQuery(sqlCommand) ' Ejecuta la consulta sin parámetros.
+ ' --- INICIO VALIDACIÓN DE PARÁMETROS CENTRALIZADA ---
+ Dim validationResult As ParameterValidationResult = ParameterValidationUtils.ValidateAndAdjustParameters(queryNameForLog, finalDbKey, sqlCommand, paramsList, Connector.IsParameterToleranceEnabled)
+
+ If validationResult.Success = False Then
+ SendErrorResponse(resp, 400, validationResult.ErrorMessage)
+ duration = DateTime.Now - start
+ CleanupAndLog(finalDbKey, queryNameForLog, duration, req.RemoteAddress, requestsBeforeDecrement, poolBusyConnectionsForLog, con)
+ Return ' Salida temprana.
End If
+ Dim rs As ResultSet
+ ' Ejecuta la consulta SQL con la lista de parámetros validada.
+ rs = con.ExecQuery2(sqlCommand, validationResult.ParamsToExecute)
+ ' --- FIN VALIDACIÓN DE PARÁMETROS CENTRALIZADA ---
+
Dim ResultList As List
ResultList.Initialize ' Lista para almacenar los resultados de la consulta.
Dim jrs As JavaObject = rs ' Objeto Java subyacente del ResultSet para metadatos.
@@ -180,29 +182,29 @@ Sub Handle(req As ServletRequest, resp As ServletResponse)
SendSuccessResponse(resp, CreateMap("result": ResultList)) ' Envía la respuesta JSON de éxito.
Else If execType.ToLowerCase = "executecommand" Then
- ' Validación de parámetros para ExecuteCommand.
- If sqlCommand.Contains("?") Then
- Dim expectedParams As Int = sqlCommand.Length - sqlCommand.Replace("?", "").Length
- Dim receivedParams As Int = paramsList.Size
- If expectedParams <> receivedParams Then
- SendErrorResponse(resp, 400, $"Número de parámetros equivocado para '${queryNameForLog}'. Se esperaban ${expectedParams} y se recibieron ${receivedParams}."$)
- duration = DateTime.Now - start
- CleanupAndLog(finalDbKey, queryNameForLog, duration, req.RemoteAddress, requestsBeforeDecrement, poolBusyConnectionsForLog, con)
- Return ' Salida temprana.
- End If
- End If
- con.ExecNonQuery2(sqlCommand, paramsList) ' Ejecuta un comando (INSERT, UPDATE, DELETE).
- SendSuccessResponse(resp, CreateMap("message": "Command executed successfully")) ' Envía confirmación de éxito.
+ ' --- INICIO VALIDACIÓN DE PARÁMETROS CENTRALIZADA ---
+ Dim validationResult As ParameterValidationResult = ParameterValidationUtils.ValidateAndAdjustParameters(queryNameForLog, finalDbKey, sqlCommand, paramsList, Connector.IsParameterToleranceEnabled)
+ If validationResult.Success = False Then
+ SendErrorResponse(resp, 400, validationResult.ErrorMessage)
+ duration = DateTime.Now - start
+ CleanupAndLog(finalDbKey, queryNameForLog, duration, req.RemoteAddress, requestsBeforeDecrement, poolBusyConnectionsForLog, con)
+ Return ' Salida temprana.
+ End If
+
+ con.ExecNonQuery2(sqlCommand, validationResult.ParamsToExecute) ' Ejecuta un comando con la lista de parámetros validada.
+ SendSuccessResponse(resp, CreateMap("message": "Command executed successfully")) ' Envía confirmación de éxito.
+ ' --- FIN VALIDACIÓN DE PARÁMETROS CENTRALIZADA ---
Else
- ' Si el tipo de ejecución no es reconocido.
- SendErrorResponse(resp, 400, "Parámetro 'exec' inválido. '" & execType & "' no es un valor permitido.")
+ Dim ErrorMsg As String = "Parámetro 'exec' inválido. '" & execType & "' no es un valor permitido."
+ SendErrorResponse(resp, 400, ErrorMsg)
+ Main.LogServerError("ERROR", "DBHandlerJSON.Handle", ErrorMsg, finalDbKey, queryNameForLog, req.RemoteAddress) ' <-- Nuevo Log
' El flujo continúa hasta la limpieza final si no hay un Return explícito.
End If
Catch ' --- CATCH: Maneja errores generales de ejecución o de SQL/JSON ---
- ' Si ocurre una excepción inesperada durante el procesamiento de la petición.
Log(LastException) ' Registra la excepción completa en el log.
+ Main.LogServerError("ERROR", "DBHandlerJSON.Handle", LastException.Message, finalDbKey, queryNameForLog, req.RemoteAddress) ' <-- Nuevo Log
SendErrorResponse(resp, 500, LastException.Message) ' Envía un error 500 al cliente.
queryNameForLog = "error_processing_json" ' Para registrar que hubo un error en el log.
End Try ' --- FIN: Bloque Try principal ---
diff --git a/Files/config.DB2.properties b/Files/config.DB2.properties
index e64e7a3..70e6c4f 100644
--- a/Files/config.DB2.properties
+++ b/Files/config.DB2.properties
@@ -11,13 +11,19 @@ DriverClass=oracle.jdbc.driver.OracleDriver
#GOHAN ---> server
#JdbcUrl=jdbc:oracle:thin:@//10.0.0.205:1521/DBKMT
#JdbcUrl=jdbc:oracle:thin:@//10.0.0.236:1521/DBKMT
-JdbcUrl=jdbc:oracle:thin:@//192.168.101.13:1521/DBKMT?v$session.program=jRDC_Multi
+JdbcUrl=jdbc:oracle:thin:@//192.168.101.13:1521/DBKMT?v$session.program=jRDC_MultiSALMA
-# Configuración del pool de conexiones para DB2
+# Configuración del pool de conexiones
InitialPoolSize=3
MinPoolSize=2
-MaxPoolSize=10
-AcquireIncrement=5
+MaxPoolSize=15
+AcquireIncrement=2
+
+# Configuración de tolerancia de parámetros:
+# 1 = Habilita la tolerancia a parámetros de más (se recortarán los excesivos).
+# 0 = Deshabilita la tolerancia (el servidor será estricto y lanzará un error si hay parámetros de más).
+# Por defecto, si no se especifica o el valor es diferente de 1, la tolerancia estará DESHABILITADA (modo estricto).
+parameterTolerance=1
# SVR-KEYMON-PRODUCCION--> Usuario
User=SALMA
@@ -50,7 +56,7 @@ Debug=true
sql.traeConexion=select 'DB2' as conexion from dual
sql.select_soporte=select * from GUNA.soporte
sql.select_conexion=SELECT 'OK' AS VALOR FROM DUAL
-sql.traeConexion4=SELECT (?) AS p1, (?) AS p2, (?) AS p3 FROM DUAL
+sql.traeConexion4=SELECT 'DB2' as db, (?) AS p1, (?) AS p2, (?) AS p3 FROM DUAL
sql.select_version=select cat_ve_version from cat_version
sql.select_version_GV2=select cat_ve_version from GUNA.cat_version
sql.selectAlmacen=select * from cat_almacen where cat_al_id = ?
diff --git a/Files/config.DB3.properties b/Files/config.DB3.properties
index 9e96b5f..f98be91 100644
--- a/Files/config.DB3.properties
+++ b/Files/config.DB3.properties
@@ -11,20 +11,21 @@ DriverClass=oracle.jdbc.driver.OracleDriver
#GOHAN ---> server
#JdbcUrl=jdbc:oracle:thin:@//10.0.0.205:1521/DBKMT
#JdbcUrl=jdbc:oracle:thin:@//10.0.0.236:1521/DBKMT
-JdbcUrl=jdbc:oracle:thin:@//192.168.101.12:1521/DBKMT?v$session.program=jRDC_Multi
+JdbcUrl=jdbc:oracle:thin:@//192.168.101.13:1521/DBKMT?v$session.program=jRDC_MultiSALMA
-# Configuración del pool de conexiones para DB2
+# Configuración del pool de conexiones
InitialPoolSize=3
MinPoolSize=2
-MaxPoolSize=10
-AcquireIncrement=5
+MaxPoolSize=15
+AcquireIncrement=2
# SVR-KEYMON-PRODUCCION--> Usuario
-#User=GUNA
-#Password=GUNAD2015M
+User=SALMA
+Password=SALMAD2016M
+
+#User=TORRADOCONAUTO
+#Password=TORRADOCONAUTOD2016M
-User=TORRADOCONAUTO
-Password=TORRADOCONAUTOD2016M
#--> Puertos
#SAC - DFR - MDA / GOHAN -->COBRANZA
@@ -46,8 +47,19 @@ Debug=true
#################
##################
-sql.traeConexion=select 'DB3' as conexion from dual
+sql.traeConexion=select 'DB2' as conexion from dual
sql.select_soporte=select * from GUNA.soporte
+sql.select_conexion=SELECT 'OK' AS VALOR FROM DUAL
+sql.traeConexion4=SELECT 'DB2' as db, (?) AS p1, (?) AS p2, (?) AS p3 FROM DUAL
+sql.select_version=select cat_ve_version from cat_version
+sql.select_version_GV2=select cat_ve_version from GUNA.cat_version
+sql.selectAlmacen=select * from cat_almacen where cat_al_id = ?
+sql.sv=select * from cat_rutas where CAT_RU_RUTA = ?
+sql.verify_device=select * from kelloggs.GUIDs where almacen = ? and ruta = ?
+sql.registarMovil=insert into kelloggs.GUIDs (almacen, ruta, guid, estatus) values (?, ?, ?, 'ok')
+sql.update_usuario_guna_nobajas=UPDATE GUNA.CAT_LOGINS SET CAT_LO_ESTATUS = 'Activo',CAT_LO_CONECTADO ='0' WHERE CAT_LO_ESTATUS != 'Baja' and CAT_LO_USUARIO = (?)
+
+sql.proc_usuario=BEGIN EXECUTE IMMEDIATE ('DECLARE Cursor_SYS Sys_Refcursor; BEGIN SP_ACTIVAR_USUARIO( '''||(?)||''',Cursor_SYS); end;'); END;
sql.select_almacenes_KELL=select CAT_AG_ID, CAT_AG_NOMBRE from KELLOGGS.cat_agencias order by CAT_AG_NOMBRE
sql.select_almacenes_GUNA=select CAT_AG_ID, CAT_AG_NOMBRE from GUNA.cat_agencias order by CAT_AG_NOMBRE
diff --git a/Files/config.DB4.properties b/Files/config.DB4.properties
index a12e987..f98be91 100644
--- a/Files/config.DB4.properties
+++ b/Files/config.DB4.properties
@@ -11,13 +11,13 @@ DriverClass=oracle.jdbc.driver.OracleDriver
#GOHAN ---> server
#JdbcUrl=jdbc:oracle:thin:@//10.0.0.205:1521/DBKMT
#JdbcUrl=jdbc:oracle:thin:@//10.0.0.236:1521/DBKMT
-JdbcUrl=jdbc:oracle:thin:@//192.168.101.13:1521/DBKMT?v$session.program=jRDC_Multi
+JdbcUrl=jdbc:oracle:thin:@//192.168.101.13:1521/DBKMT?v$session.program=jRDC_MultiSALMA
-# Configuración del pool de conexiones para DB2
+# Configuración del pool de conexiones
InitialPoolSize=3
MinPoolSize=2
-MaxPoolSize=10
-AcquireIncrement=5
+MaxPoolSize=15
+AcquireIncrement=2
# SVR-KEYMON-PRODUCCION--> Usuario
User=SALMA
@@ -31,7 +31,7 @@ Password=SALMAD2016M
#SAC - DFR - MDA / GOHAN -->COBRANZA
#ServerPort=1783
#GUNA - SALMA - DURAKELO - DBC / SVR-KEYMON-PRODUCCION --> DISTRIBUIDORAS
-ServerPort=9000
+ServerPort=9010
#CMG - TORRADO / TRUNKS -->COBRANZA/ GM
#ServerPort=1781
@@ -47,9 +47,19 @@ Debug=true
#################
##################
-sql.traeConexion=select 'DB4' as conexion from dual
+sql.traeConexion=select 'DB2' as conexion from dual
sql.select_soporte=select * from GUNA.soporte
sql.select_conexion=SELECT 'OK' AS VALOR FROM DUAL
+sql.traeConexion4=SELECT 'DB2' as db, (?) AS p1, (?) AS p2, (?) AS p3 FROM DUAL
+sql.select_version=select cat_ve_version from cat_version
+sql.select_version_GV2=select cat_ve_version from GUNA.cat_version
+sql.selectAlmacen=select * from cat_almacen where cat_al_id = ?
+sql.sv=select * from cat_rutas where CAT_RU_RUTA = ?
+sql.verify_device=select * from kelloggs.GUIDs where almacen = ? and ruta = ?
+sql.registarMovil=insert into kelloggs.GUIDs (almacen, ruta, guid, estatus) values (?, ?, ?, 'ok')
+sql.update_usuario_guna_nobajas=UPDATE GUNA.CAT_LOGINS SET CAT_LO_ESTATUS = 'Activo',CAT_LO_CONECTADO ='0' WHERE CAT_LO_ESTATUS != 'Baja' and CAT_LO_USUARIO = (?)
+
+sql.proc_usuario=BEGIN EXECUTE IMMEDIATE ('DECLARE Cursor_SYS Sys_Refcursor; BEGIN SP_ACTIVAR_USUARIO( '''||(?)||''',Cursor_SYS); end;'); END;
sql.select_almacenes_KELL=select CAT_AG_ID, CAT_AG_NOMBRE from KELLOGGS.cat_agencias order by CAT_AG_NOMBRE
sql.select_almacenes_GUNA=select CAT_AG_ID, CAT_AG_NOMBRE from GUNA.cat_agencias order by CAT_AG_NOMBRE
diff --git a/Files/config.properties b/Files/config.properties
index e177db6..e30705b 100644
--- a/Files/config.properties
+++ b/Files/config.properties
@@ -13,11 +13,17 @@ DriverClass=oracle.jdbc.driver.OracleDriver
#JdbcUrl=jdbc:oracle:thin:@//10.0.0.236:1521/DBKMT
JdbcUrl=jdbc:oracle:thin:@//192.168.101.10:1521/DBKMT?v$session.program=jRDC_Multi
-# Configuración del pool de conexiones para DB1
+# Configuración del pool de conexiones
InitialPoolSize=3
MinPoolSize=2
-MaxPoolSize=10
-AcquireIncrement=5
+MaxPoolSize=15
+AcquireIncrement=2
+
+# Configuración de tolerancia de parámetros:
+# 1 = Habilita la tolerancia a parámetros de más (se recortarán los excesivos).
+# 0 = Deshabilita la tolerancia (el servidor será estricto y lanzará un error si hay parámetros de más).
+# Por defecto, si no se especifica o el valor es diferente de 1, la tolerancia estará DESHABILITADA (modo estricto).
+parameterTolerance=1
# SVR-KEYMON-PRODUCCION--> Usuario
User=GUNA
@@ -52,7 +58,7 @@ sql.select_revisaClienteCredito_GUNA2=select (select count(CAT_CL_CODIGO) from G
sql.traeConexion=select 'DB1' as conexion from dual
sql.traeConexion2=select 'DB1' as conexion from dual
sql.traeConexion3=select '1' as par1, 2 as par2 from dual
-sql.traeConexion4=SELECT (?) AS p1, (?) AS p2, (?) AS p3 FROM DUAL
+sql.traeConexion4=SELECT 'DB1' as db, (?) AS p1, (?) AS p2, (?) AS p3 FROM DUAL
sql.select_soporte=select * from GUNA.soporte
sql.select_conexion=SELECT 'OK' AS VALOR FROM DUAL
sql.selectAlmacen=select cat_al_id, cat_al_desc, cat_al_archftp from cat_almacen where cat_al_id = ?
diff --git a/Manager.bas b/Manager.bas
index 3dc59db..38325a2 100644
--- a/Manager.bas
+++ b/Manager.bas
@@ -154,14 +154,14 @@ Sub Handle(req As ServletRequest, resp As ServletResponse)
Dim newPoolStats As Map = newRDC.GetPoolStats
sbTemp.Append($" -> ${dbKey}: Nuevo conector inicializado. Conexiones: ${newPoolStats.Get("TotalConnections")}"$).Append("
" & CRLF)
-
+
Catch
sbTemp.Append($" -> ERROR CRÍTICO al inicializar nuevo conector para ${dbKey}: ${LastException.Message}"$).Append("
" & CRLF)
reloadSuccessful = False
Exit ' Si uno falla, abortamos la recarga completa para evitar un estado inconsistente.
End Try
Next
-
+
sb.Append(sbTemp.ToString) ' Añadimos los logs acumulados de la inicialización al StringBuilder principal.
If reloadSuccessful Then
@@ -380,112 +380,3 @@ Sub Handle(req As ServletRequest, resp As ServletResponse)
If GlobalParameters.mpLogs.IsInitialized Then GlobalParameters.mpLogs.Put(Command, "Manager : " & Command & " - Time : " & DateTime.Time(DateTime.Now))
End Sub
-
-Sub Handle0(req As ServletRequest, resp As ServletResponse)
- ' 1. --- Bloque de Seguridad (se mantiene igual) ---
- If req.GetSession.GetAttribute2("user_is_authorized", False) = False Then
- resp.SendRedirect("/login")
- Return
- End If
-
- Dim Command As String = req.GetParameter("command")
- If Command = "" Then Command = "ping"
- Log($"Command: ${Command}"$)
- resp.ContentType = "text/html"
-
- ' 2. --- Construimos la ESTRUCTURA de la página ---
- Dim sb As StringBuilder
- sb.Initialize
-
- ' Estilos para la página
- sb.Append("