Spanish ¿ Como utilizar codigos de modulo para tener acceso a rutinas publicas ?

Sergio Castellari

Active Member
Licensed User
Hola gente,

Mi pequiñisima APP va creciendo de a poco. Desearia, colocar subrutinas o funciones en distintos modulos, a lo cuales luego referenciar. ¿Como debo hacerlo?
La APP, utiliza jRDC2 para conectarse a MySQL en un VPS. Anda perfecto.
Decidi (para organizar) "pasar" las rutinas de conexion a jRDC2 a un modulo nuevo. Copie las subRutinas y les agregue el prefijo (con el nombre del modulo) a las llamadas en el MAIN. Todo parece OK...peeerooo, me aparecieron los siguientes errores:

B4X:
Funciones - 19: Code modules do not support Me keyword.
Funciones - 9: Variable 'rdcLink' no usada (warning #9)
y este es el codigo que "quite"de MAIN (y funcionaba perfecto) y lo coloque en el modulo nuevo llamado "Funciones"

B4X:
Sub Process_Globals
    'Estas variables globales se declararán una vez cuando se inicie la aplicación.
    'Se puede acceder a estas variables desde todos los módulos.
    Type DBResult (Tag As Object, Columns As Map, Rows As List)
  Type DBCommand (Name As String, Parameters() As Object)
  Private const rdcLink As String = "http://192.168.1.40:17178/rdc"
End Sub

Sub AuditSQL (cTexto As String)
    Log("Entre a AuditSQL: " & cTexto)
End Sub

Sub CreateRequest As DBRequestManager
     'Por cada solicitud, se crea un nuevo DBRequest...
   Dim req As DBRequestManager
   req.Initialize(Me,rdcLink)
   Return req
End Sub

Sub CreateCommand(Name As String, Parameters() As Object) As DBCommand
   Dim cmd As DBCommand
   cmd.Initialize
   cmd.Name = Name
   If Parameters <> Null Then cmd.Parameters = Parameters
   Return cmd
End Sub
¿ Que estoy haciendo mal? Mi deseo, es tener las "funciones" de acceso a jRDC2 en un modulo general, para luego ser utilizado desde cualquier otra parte de la APP ?

Saludos,
Sergio
 

Sergio Castellari

Active Member
Licensed User
Quite los errores cambiando en esta linea "Me" por "" y desaparecieron los errores y compila:

B4X:
   req.Initialize("",rdcLink)
pero cuando ejecuto la APP y pretendo acceder a MySQL por medio de jRDC2...me envia el siquiente ERROR:

Registo conectado a: samsung SM-J710MN
--------- beginning of main
*** Service (starter) Create ***
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
*** Service (httputils2service) Create ***
** Service (httputils2service) Start **
ResponseError. Reason: java.lang.ClassNotFoundException: b4j.example.funciones$_dbcommand, Response: <html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<title>Error 500 java.lang.ClassNotFoundException: b4j.example.funciones$_dbcommand</title>
</head>
<body><h2>HTTP ERROR 500</h2>
<p>Problem accessing /rdc. Reason:
<pre> java.lang.ClassNotFoundException: b4j.example.funciones$_dbcommand</pre></p><hr><a href="http://eclipse.org/jetty">Powered by Jetty:// 9.4.z-SNAPSHOT</a><hr/>
</body>
</html>
¿ Que esta sucediendo? ¿Que esta mal?
 

José J. Aguilar

Well-Known Member
Licensed User
Hola Sergio:

No me da tiempo ahora a echarle un ojo a tu código. Te recomendaría que echases un vistazo a la documentación de las clases, tienen ventajas sobre los módulos de código.
Te adjunto un pequeño ejemplo de cómo pasé jRDC2 a una clase, estoy casi empezando con ellas, así que puede haber cosas mejorables.
Modifica el código de la clase y déjalo como necesites, ya que yo por ejemplo modifiqué un poco GetRecord
 

Attachments

  • 10.8 KB Views: 44
Last edited:

Sergio Castellari

Active Member
Licensed User
@José J. Aguilar GENIAL!

Arme la "clase" según como me lo enviaste....y logré que me LEA los registros igual que antes....
...peeeroooo....ahora como LEO la "respuesta" y le doy el mismo tratamiento que venia haciendole...???
¿¿ Como debo manejarme con un MAP ??

Saludos,
Sergio

PD: Primer aprendizaje: DEBO USAR UNA CLASE en lugar de modulo de codigo para tener acceso global a sus rutinas!!!
 

José J. Aguilar

Well-Known Member
Licensed User
No hace falta que te manejes con un MAP.
La respuesta ahora es un MAP porque como te indiqué, yo modifiqué el código de GETRECORD. Pon el tuyo que estabas usando antes y deberías entonces manejar la respuesta igual.

Descarga de nuevo el ejemplo ya que me salté la línea para agregar los parámetros, y quizás lo veas algo más fácil.

saludos,
 

Sergio Castellari

Active Member
Licensed User
ok, lo de "parametros" me habia dado cuenta, y simplemente lo cambie por Null, que era lo que venia usando...

AJA...entiendo que vos entregas la respuesta en un MAP (¿Es mejor utilizar un MAP? nunca lo usé ni se como funciona) ¿y Como lo hago para que me entregue como ANTES?

Si veo que manipulas "Respuestas.put" ...pero no entiendo bien que que haces con esos mensajes...jejeje

La idea (me imagino) que al igual que TU, es tener la clase "jRDC2" completa y disponible para luego utilizarla en toda la aplicacion

Saludos,
 

José J. Aguilar

Well-Known Member
Licensed User
AJA...entiendo que vos entregas la respuesta en un MAP (¿Es mejor utilizar un MAP? nunca lo usé ni se como funciona)
No es que sea mejor, yo es que en la respuesta necesitaba varias cosas, y las metí en un MAP (entre las cosas que metí, metí también el DBResult)
Antes tú llamabas a GetRecord, y dentro de ese sub, hacías lo que querías con el resultado
B4X:
       Wait For (req) req_Result(res As DBResult)
       'work with result
       req.PrintTable(res)
Pero ahora vas a llamar a esa Sub desde distintas partes del programa, y querrás trabajar con el resultado (res) desde esa parte del programa, por tanto, tendrás que hacer la Sub GetRecord te devuelva el resultado. Yo lo he devuelto en un mapa porque necesitaba que GetRecord me devuelva varias cosas, pero si sólo quieres el resultado, pues modíficala por ejemplo con:


Modifica mi sub

B4X:
Public Sub GetRecord (Command As String, parameters() As String) As ResumableSub
    Dim req As DBRequestManager = CreateRequest
    Dim cmd As DBCommand = CreateCommand(Command, parameters)
    Wait For (req.ExecuteQuery(cmd, 0, Null)) JobDone(j As HttpJob)
    If j.Success Then
        req.HandleJobAsync(j, "req")
        Wait For (req) req_Result(Res As DBResult)
        'work with result
        'req.PrintTable(Res)
    Else
        Log("ERROR: " & j.ErrorMessage)
    End If
    j.Release
    Return Res
End Sub
Ahora para recibir los datos, tendrías que modificar
B4X:
Wait For(jRDC.GetRecord("selectParteTrabajoView", Parametros)) Complete (Respuesta As DBResult) 'Modifica el tipo de respuesta, ya que ahora la sub devuelve un DBResult en vez de un Map
 

Sergio Castellari

Active Member
Licensed User
ahora...como utilizo InsertRecord ? (que lo tome de tu clase)

Intente de esta forma:

B4X:
    Dim cUsuario = "PEPE", cNetName = "Mobil", cFecha = "2020-04-21", _
        cDet = cTexto, cTip = "A" , cTime = "12:30:00" As String
    Wait For (jConex.InsertRecord("auditSQL", Array(cFecha,cTime,cUsuario,cNetName,cDet,cTip)))
me da error
Funciones - 15: El &#237;ndice estaba fuera del intervalo. Debe ser un valor no negativo e inferior al tama&#241;o de la colecci&#243;n.<br />Nombre del par&#225;metro: index
Funciones - 13: Variable 'cUsuario' no usada (warning #9)
Funciones - 13: Variable 'cNetName' no usada (warning #9)
Funciones - 13: Variable 'cFecha' no usada (warning #9)
Funciones - 13: Variable 'cDet' no usada (warning #9)
Funciones - 13: Variable 'cTip' no usada (warning #9)
Funciones - 13: Variable 'cTime' no usada (warning #9)
Funciones - 6: La variable 'jConex' nunca recibe un valor. (warning #10)
la instruccion "auditSQL" ya la incorporé en el servidor jRDC2

¿Que me esta faltando?

Saludos,
 

José J. Aguilar

Well-Known Member
Licensed User
Pues no sé, das muy pocas pistas.
De dónde sale este error?
Funciones - 15: El &#237;ndice estaba fuera del intervalo. Debe ser un valor no negativo e inferior al tama&#241;o de la colecci&#243;n.<br />Nombre del par&#225;metro: index

Cual es el SQL de "auditSQL"? ¿Qué te dice el error de B4J?

El array no debería ser?
B4X:
Array as String(cFecha,cTime,cUsuario,cNetName,cDet,cTip)
 

Sergio Castellari

Active Member
Licensed User
el error ESE, es de la linea 3 en el trozo que pase.

"auditSQL" es asi en el servidor jRDC2 :
sql.auditSQL=Insert Into AUDIT Values(?,?,?,?,?,?)

Me doy cuenta que tengo una falla al llamar el InsertRecord, pero no me doy cuenta que?....se que aqui no hay respuesta....
 

José J. Aguilar

Well-Known Member
Licensed User
Hola:

Lo siento, con esos datos no sabría cual es el error.
De qué tipo son los campos de AUDIT? Qué error te da B4J?

A mí me funciona por ejemplo:
B4X:
Public Sub InsertRecord (Command As String, parameters() As String)
    Dim cmd As DBCommand = CreateCommand(Command, parameters)
    Dim j As HttpJob = CreateRequest.ExecuteBatch(Array(cmd), Null)
    Wait For(j) JobDone(j As HttpJob)
    If j.Success Then
        Log("Inserted successfully!")
    End If
    j.Release
End Sub

jrdc.InsertRecord("pruebaINSERT", Array As String("jose", "2020-04-08 00:00:00", "prueba"))
1587501178355.png


Lo ideal serías que hicieras que la Sub InsertRecord devolviese true o false si se añade con éxito, así cuando lo llames lo harías con un wait for (igual que al hacer el select) y ahí podrías gestionar si se ha insertado o no el registro. Pero es lo dejo para que estudies.

Se me ocurre que hagas un LOG de (cUsuario & cNetName & cFecha & cDet & cTexto & cTip & cTime) y lo copies e intentes ejecutar en tu base de datos a mano un:
Insert Into AUDIT Values(.... pega aquí los valores de tu log)

Pero vamos, el error que te de debería saltarte en el log de B4J.

Mira también lo que te indiqué del array al final del post, ya que lo edité, y como lo miraste al poco, quizás no lo había editado aún para añadir esa frase.
 

Sergio Castellari

Active Member
Licensed User
Hola José,

He resuelto el tema del InsertRecord, cambiándole para que me retorne TRUE o FALSE si pudo hacer la inserción y así me funciono!!!.

Y he avanzado un poco mas...
Puse este código dentro del modulo de Clase:

B4X:
'******************************************************************
'* AuditSQL() Sirve para GUARDAR la tira de Auditoria             *
'*           Recibe: cUsuario ---> Nombre del Usuario que ingresó *
'*                   cAuditoria -> Texto del contenido auditado   *
'*                                                                *
'*        Retorna: TRUE ---> Inserción exitosa                    *
'*                FALSE ---> Fallo al insertar                    *                       
'*************************************************** 21-04-2020 ***
Public Sub AuditSQL (cUsuario As String, cAuditoria As String) As ResumableSub
    DateTime.DateFormat = "yyyy-MM-dd"                        'Doy formato a la Fecha
    Dim cFecha = DateTime.Date(DateTime.Now) As String
    Dim cTime = DateTime.Time(DateTime.now) As String
    Dim cDet = "[Movil] " & cAuditoria  As String
    'Log("fecha: " & cFecha)
    Dim aCom() As String
    aCom = Array As String(cFecha,cTime, cUsuario,"TELEFONO",cDet,"A")
    Dim res As Boolean
    Dim cmd As DBCommand = CreateCommand("auditSQL", aCom)
    Dim j As HttpJob = CreateRequest.ExecuteBatch(Array(cmd), Null)
    Wait For(j) JobDone(j As HttpJob)
    res = j.Success
    If j.Success Then
        Log("Auditoría OK !!!")
    Else
        Log("Auditoría FALLO !!!")
    End If
    j.Release
    Return res
End Sub
y ahora desde el MAIN puedo escribir esto:
Wait For (jConex.AuditSQL(cUsrIng,"Ingreso al Sistema")) Complete (lResp As Boolean)

Y ANDA JOYA!!!!

Ahora quisiera tener el USUARIO en una variable publica, es decir con alcance en toda la aplicación...pero NO LOGRO HACERLO!!!
cUsrIng es LOCAL, solo es vista dentro de MAIN, pero no la puedo ver desde los otros modulos...
¿Como se puede lograr eso?
Crei que con declararla Public en "Sub Process_Globals" alcanzaba....


Saludos y desde ya gracias!
Sergio
 
Top