B4J Question B4J Server returning a list or map

Tadeu Botelho

Member
Licensed User
Longtime User
I'm working on server development by following the following example:
https://www.b4x.com/android/forum/t...device-desktop-and-web-reports.37254/#content
I need to return a list with data from a table:
ID, Name, Age, Email
With their respective data.
This list needs to be sent to a B4J application that is loading its data into a TableViewer.
Is there any example with these codes? Because I did not find anything like this:
'// B4J Server:
B4X:
Sub Handle(req As ServletRequest, resp As ServletResponse)
 Dim resp As Map = DBUtils.ExecuteMap(Main.SQL, "SELECT * FROM Animals")
 resp.ContentType = "Map" '// Map ? '// how to set a list or map to client?
 resp.Write(resp)
End Sub

'// B4J Client:
B4X:
Sub Process_Globals
 Private fx   As JFX
 Private MainForm  As Form
 Private TableView  As TableView 
 Private raf   As RandomAccessFile
 Private link   As String 
End Sub
Sub AppStart (Form1 As Form, Args() As String)
 MainForm = Form1
 MainForm.Show
 raf.Initialize(File.DirTemp, "temp", False)
 MainForm.Title = "Tabela {Pessoas} em http://IP:porta em {BdServidor.db}"
End Sub
Sub btnDadosExibirNoTableView_Action
 link = "http://localhost:51042"
 Dim j As HttpJob
 j.Initialize("report2", Me) 
 j.Download(link & "/Relatorio2")
 pi1.Visible = True
End Sub
Sub JobDone(j As HttpJob) 
 If j.Success Then
  If j.JobName = "report2" Then
   '// how to get a list or map in a tableview?
   TableView.Items.AddAllAt( j.GetString2("  Map????  ") )
  End if
 End If
End Sub

I will be very grateful for the help
 

OliverA

Expert
Licensed User
Longtime User
1) You may want to look into JRDC2 (https://www.b4x.com/android/forum/t...-rdc-remote-database-connector.61801/#content) for retrieving information from a database. There are a couple of modified versions here in the forum that may be of interest:

a) Modded jRDC2 w/SQLite support and more (https://www.b4x.com/android/forum/threads/modded-jrdc2-w-sqlite-support-and-more.85578/). This one out of the box uses SQLite and is therefore a little bit easier to set up. One of the commenters ( @inakigarm ) mentioned he had a modification that would allow for dynamically updating SQL statements (https://www.b4x.com/android/forum/threads/modded-jrdc2-w-sqlite-support-and-more.85578/#post-542226). There is a companion B4J client example (https://www.b4x.com/android/forum/threads/jrdc2-client-example-using-modded-jrdc2.85581/#content) that is a modified version of the DBUtils example. That example should also run against the original JRDC2 (Disclaimer: this is my mod).

b) Another customized version of JRDC2 by @tigrot (https://www.b4x.com/android/forum/threads/another-customised-version-of-jrdc2.72082/#content) adds file up/download capabilities and ad-hoc SQL queries.

c) jRDC Hikari mix by @MichalK73 (https://www.b4x.com/android/forum/threads/jrdc-hikari-mix.90033/#post-569115) changes the database pool used, adds method calls, some security and dynamic loading of methods/SQL queries, etc.​

2) If you insist on doing things your own way, then

on the server side you'll need something like this (BTW, you mentioned list, but are using a map, so I'm sticking with a map):

B4X:
Dim m as Map
'Code that fills the map here
'.
'Code to serialize map and transfer to client
Dim ser as B4XSerializator
Dim data() as Byte = ser.ConvertObjectToBytes(m)
resp.OutputStream.WriteBytes(data, 0, data.Length)

on the client side:

B4X:
'This is the code used instead of plain Job.GetString method
Dim ser as B4XSerializator
Dim data() as Byte = Bit.InputStreamToBytes(Job.GetInputStream)
Dim m As Map = ser.ConvertBytesToObject(data)

Note: Code not tested, just adopted from JRDC2/DBRequestManager source of original JRDC2. Adjust any variable names as necessary.
 
Upvote 0

XbNnX_507

Active Member
Licensed User
Longtime User
Another option would be to send a Json string intsead of Map.

Server Side.
Sub Handle(req As ServletRequest, resp As ServletResponse)
Dim resp As Map = DBUtils.ExecuteMap(Main.SQL, "SELECT * FROM Animals")
Dim JG as JSONGenerator '
JG.initialize(resp)
resp.ContentType =
"application/json"
resp.Write(JG.tostring)
End Sub

Client Side
Sub JobDone(j As HttpJob)
If j.Success Then
If j.JobName = "report2" Then
Dim jc As JSONParser
jc.NextObject
' Parse as needed
' add to tableview...

End if
End If
End Sub
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Upvote 0

XbNnX_507

Active Member
Licensed User
Longtime User
Is there any difference in the performance when using B4XSerializator or JSON?
if you are implementing server side code and client side code in B4X then i think is best to use B4Xserializator.
if you have no control over the client side code then i think JSon is a better option given the fact the B4XSerializator is a unique B4J B4A feature.
i Don't think there's a performance difference maybe Erel could answer that.
 
Upvote 0

KMatle

Expert
Licensed User
Longtime User
I work with lists with maps converted to Json strings. As I encrypt everythng the result are bytes which then can be sent via asyncstreams. On bigger environments I use Apache with php and OkHttputils. I convert the bytes to a Base64 string. Big advantage: It's always the same procedure in all environments.

No need for custom types. Lists and maps are just arrays. When converted to a Json structure all plattforms can handle it.
 
Upvote 0

Tadeu Botelho

Member
Licensed User
Longtime User
I work with lists with maps converted to Json strings. As I encrypt everythng the result are bytes which then can be sent via asyncstreams. On bigger environments I use Apache with php and OkHttputils. I convert the bytes to a Base64 string. Big advantage: It's always the same procedure in all environments.

No need for custom types. Lists and maps are just arrays. When converted to a Json structure all plattforms can handle it.

Is there a difference in performance when opting for this procedure?
 
Upvote 0

keirS

Well-Known Member
Licensed User
Longtime User
I work with lists with maps converted to Json strings. As I encrypt everythng the result are bytes which then can be sent via asyncstreams. On bigger environments I use Apache with php and OkHttputils. I convert the bytes to a Base64 string. Big advantage: It's always the same procedure in all environments.

No need for custom types. Lists and maps are just arrays. When converted to a Json structure all plattforms can handle it.

A Map is not an array.
 
Upvote 0

Tadeu Botelho

Member
Licensed User
Longtime User
if you are implementing server side code and client side code in B4X then i think is best to use B4Xserializator.
if you have no control over the client side code then i think JSon is a better option given the fact the B4XSerializator is a unique B4J B4A feature.
i Don't think there's a performance difference maybe Erel could answer that.

Your response was very helpful. Thank you!
I'm creating a server that will be consumed by clients that do not have access to source code. So the returns to those clients would be via JSON.
But most of the returns will be for systems made by me through the B4J Client.JAR and B4A Client.APK
So in this second situation I will work with the B4XSerializator because of the custom types. That in my case, I really enjoy working with them.
My only doubt is still only in performance between the two.
But so far my development with the B4X Platform is thriving.
I loved these magnificent B4X tools.
 
Upvote 0

KMatle

Expert
Licensed User
Longtime User
A Map is not an array.

This is correct. What I meant: If you convert a list/map structure to JSON and send it to php, they can be handled in php like arrays after decoding. The point is: This is compatible with all platforms. The serializator is a B4x thing. So I only use lists/maps encoded to a JSON string in all of my apps. One concept fits it all.
 
Upvote 0

schimanski

Well-Known Member
Licensed User
Longtime User
To the lot of experts here in the thread, I still have one question:

I use such server-handler with the code above:

B4X:
Sub Handle(req As ServletRequest, resp As ServletResponse)
 
    Dim NTask As NTask = serializator.ConvertBytesToObject(Bit.InputStreamToBytes(req.InputStream))
 
    If NTask.NTaskName="getdata" Then
        Dim bytes() As Byte = serializator.ConvertObjectToBytes(NachrichtenSyncDB.Get(req.GetParameter("absender")))
        resp.OutputStream.WriteBytes(bytes, 0, bytes.Length)
    Else
        If NTask.NTaskName="putdata" Then
           ...
           NachrichtenSyncDB.Put(req.GetParameter("absender"),  NTask.NTaskItem)
           ....

Only the server writes to it and the clients only reads over the handler. Do I have to use now a code-modul with the following code like cloudkvs does:

B4X:
Public Sub Put(Key As String, Value As Object)
    lock.WriteLock
    Try
        Private ser As B4XSerializator
        sql.ExecNonQuery2("INSERT OR REPLACE INTO " & Standort & " VALUES(?, ?)", Array As Object(Key, ser.ConvertObjectToBytes(Value)))
    Catch
        Log(LastException)
    End Try
    lock.WriteRelease
End Sub

or is it better to use a class-modul like keyvaluestore2 with this code:

B4X:
Public Sub Put(Key As String, Value As Object)
    Private ser As B4XSerializator
    sql1.ExecNonQuery2("INSERT OR REPLACE INTO main VALUES(?, ?)", Array As Object(Key, ser.ConvertObjectToBytes(Value)))
End Sub
 
Last edited:
Upvote 0

OliverA

Expert
Licensed User
Longtime User
code-modul with the following code like cloudkvs does
The Put method for CloudKVS that you are showing is part of the client portion. The client has no code module, it's a class module.

Read this article (https://msdn.microsoft.com/en-us/library/aa733572(v=vs.60).aspx) by Microsoft, where standard module is equivalent to code module.

Then look at the CloudKVS server where the same database is used for all access. In this case, each request gets a new handler, but each handler talks to the same database. In this case, a code module for the database portion makes sense. But, it could have been a class. That's actually how JRDC2 does it (and out of the box it only serves one database). In short, it's up to you.

As to KVS2, by making it a class module, you can actually have more than one KVS2 storage used per application. If it were a code module, you would restrict the application to only have one KVS2 store. BTW, since the CloudKVS client is a class module, your client application is not restricted to talking to only one CloudKVS server.

Hope I made it clear as mud.
 
Upvote 0

schimanski

Well-Known Member
Licensed User
Longtime User
Thanks for your efforts, OliverA. Your explanations are very useful. I decided to use a code module for the database portion like cloudkvs does!
 
Upvote 0
Top