- 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.
This commit is contained in:
2025-09-18 22:30:22 -06:00
parent 51c829b876
commit 3b352bb105
14 changed files with 537 additions and 466 deletions

View File

@@ -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 ---