B4J Library [B4X] jRDC2 - B4J implementation of RDC (Remote Database Connector)

Status
Not open for further replies.

RDC is a middleware server that makes it simple to safely connect clients and remote SQL database servers.

jRDC2 is the latest version. All new projects should use this version.

jRDC2 is made of two components:

- B4J server. The server receives the requests from the clients, issues the SQL commands against the database and returns the results.
In many cases the server will be hosted on the same computer that hosts the database server.
- Client module. The client which is compatible with B4A, B4J and B4i is responsible for sending the requests and handling the responses.

jRDC2 can work with any database that provides a JDBC driver. All popular databases are supported.
It is much more powerful than the PHP based solution and it has excellent performance.
It is also safer as the SQL commands are set in the server side.

Server configuration

1. Add the relevant JDBC jar file to the additional libraries folder.
2. Add a reference to this jar with:
B4X:
#AdditionalJar: mysql-connector-java-5.1.27-bin
3. Edit config.properties file that is located in the Files tab.


For example:

SS-2013-08-04_16.10.20.png


Note that the configuration fields are case sensitive.

DriverClass / JdbcUrl - The values of these two fields are specific to each database platform. You will usually find the specification together with the required driver jar file.

User / Password - Database user and password.

ServerPort - The Java server will listen to this provided port.

Debug - Option not used any more. It is automatically enabled when you run the server in debug mode (from the IDE).

SQL Commands - A list of commands. Each command starts with 'sql.'. The commands can include question marks (parameterised queries). Question marks will be replaced with the values provided by the Android clients. Note that the command name is case sensitive and it doesn't include the 'sql.' prefix.

4. Run the program and test it locally by putting this link in the local browser: http://localhost:17178/test

Note that the server port must be open for incoming connections in the firewall.

Client configuration

1. Add to Main module (must be in Main module):
B4X:
Sub Process_Globals
   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.0.6:17178/rdc"
End Sub
Change the link with the ip address or host name of the server hosting jRDC2. It must end with /rdc.

2. Add DBRequestManager class to your project.
It depends on RandomAccessFile and OkHttpUtils2 libraries (or the matching libraries in B4J or B4i).

3. Add these two subs:
B4X:
Sub CreateRequest As DBRequestManager
   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

A new DBRequestManager is created for each request.

Example of sending a SELECT request:
B4X:
Sub GetRecord (id As Int)
   Dim req As DBRequestManager = CreateRequest
   Dim cmd As DBCommand = CreateCommand("select_animal", Array(id))
   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
End Sub
The select_animal command is defined in the config file:
B4X:
sql.select_animal=SELECT name, image, id FROM animals WHERE id = ?

Note that you can make multiple requests at the same time.
The result is a DBResult object.

Example of sending an INSERT request:
B4X:
Sub InsertRecord (Name As String)
   Dim cmd As DBCommand = CreateCommand("insert_animal", Array(Name, Null))
   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
In this case a single command was sent. You can send multiple commands at once.
The insert_animal command is defined in the config file:
B4X:
sql.create_table=CREATE TABLE IF NOT EXISTS animals (\
     id INTEGER PRIMARY KEY AUTO_INCREMENT,\
     name CHAR(30) NOT NULL,\
     image BLOB)
sql.insert_animal=INSERT INTO animals VALUES (null, ?,?)


Notes

- Running a B4J server program on your hosted server: [server] Run a Server on a VPS
- There are three utility methods in DBRequestManager: FileToBytes, ImageToBytes and BytesToImage. You can use them when working with blobs.
- Extending jRDC2 to support B4R: https://www.b4x.com/android/forum/threads/rdc-based-on-mqtt.72416/#content

Updates

v2.23 - Adds support for CLOB fields (large strings).
v2.22 - Fixes an issue with null time values.
v2.21 - Date and time fields are converted to ticks (long numbers) automatically in select queries.
Note that the VERSION1 code is excluded by default. It is only relevant if there are clients running the old RDC code.


Please start a new thread for any question you have.
 

Attachments

  • DBRequestManager.bas
    4.4 KB · Views: 7,440
  • jRDC2.zip
    5.5 KB · Views: 3,016
Last edited:

kris A

Member
Licensed User
Longtime User
I am handling large amount of data from the server. Does jrdc2 handle compression?
 

kris A

Member
Licensed User
Longtime User
Any additional libraries or commands to use the B4XSerializator compression or is this automatically handled by the jdrc2?
 

kris A

Member
Licensed User
Longtime User
After Upgrade DBRequestManager.bas v2, My server got error :

Screenshot_1.png


My client B4a got error :

java.util.zip.ZipException: Not in GZIP format
Error: Server Error

My Server :
windows 10
JDK 1.8.0
driver mysql : mysql-connector-java-5.1.27-bin
 

IlCasti

Active Member
Licensed User
Longtime User
How about unknow method?

Dim method As String = req.GetParameter("method") is empty..

srvr.AddHandler("/rdc", "RDCHandler", False)

this from web request "http://localhost:3307/rdc"

laptop is in a private domain in a lan and in a private wireless connection

any idea?

thanks
 
Last edited:

Scotter

Active Member
Licensed User
...
jRDC2 is a new version of jRDC. It uses B4XSerializator to convert the data. This makes the whole solution simpler and more powerful.
...
Notes

- The configuration debug option was removed. It will be set automatically when you run the server in debug mode.
- Libraries required:
B4J: jRandomAccessFile 2.20+ and JavaObject v2.05+: https://www.b4x.com/android/forum/threads/updates-to-internal-libaries.48274/#post-389794
B4A: RandomAccessFile 2.20+: https://www.b4x.com/android/forum/threads/updates-to-internal-libraries.59340/#post-389929
B4i: iRandomAccessFile 1.50+: https://www.b4x.com/android/forum/threads/updates-to-internal-libraries.48179/page-3#post-389925

Hi -
Sorry if this is a newb question:
If I'm running B4A 6.50, how much of this stuff do I already have?
Thanks!
 

jorgesegura

Member
Licensed User
Longtime User
I am trying to run ExecuteQuery.
But I get this error cannot serialize object
Server side

Error occurs this line in B4J
Dim data() As Byte = ser.ConvertObjectToBytes(res)
 

Attachments

  • 1.png
    1.png
    64.1 KB · Views: 660

schalkgreyling

Member
Licensed User
Longtime User
Hi guys,

I'm busy migrating my jRDC to a command line linux system. I can connect to the database (mysql on linux) from my Windows pc with jRDC but when I run the .jar on the linux system and executes a query I get the following:

2017-03-28 19:38:56.600:INFO::main: Logging initialized @344ms
2017-03-28 19:39:01.968:INFO:eek:ejs.Server:main: jetty-9.3.z-SNAPSHOT
2017-03-28 19:39:02.025:INFO:eek:ejsh.ContextHandler:main: Started o.e.j.s.ServletContextHandler@2892dae4{/,file:///home/klasie/www,AVAILABLE}
2017-03-28 19:39:02.028:INFO:eek:ejs.AbstractNCSARequestLog:main: Opened /home/klasie/logs/b4j-2017_03_28.request.log
2017-03-28 19:39:02.041:INFO:eek:ejs.ServerConnector:main: Started ServerConnector@31275903{HTTP/1.1,[http/1.1]}{0.0.0.0:17178}
2017-03-28 19:39:02.042:INFO:eek:ejs.Server:main: Started @5787ms
jRDC is running (version = 2.1)

(TimeoutException) com.mchange.v2.resourcepool.TimeoutException: A client timed out while waiting to acquire a resource from com.mchange.v2.resourcepool.BasicResourcePool@79acf084 -- timeout at awaitAvailable()
(CannotAcquireResourceException) com.mchange.v2.resourcepool.CannotAcquireResourceException: A ResourcePool could not acquire a resource from its primary factory or source.
(TimeoutException) com.mchange.v2.resourcepool.TimeoutException: A client timed out while waiting to acquire a resource from com.mchange.v2.resourcepool.BasicResourcePool@79acf084 -- timeout at awaitAvailable()
(CannotAcquireResourceException) com.mchange.v2.resourcepool.CannotAcquireResourceException: A ResourcePool could not acquire a resource from its primary factory or source.

Command: , took: 5966ms, client=192.168.1.211
Command: , took: 21232ms, client=192.168.1.211

I'm suspecting it's got to do with the mysql-driver but i'm not too familiar with linux so i'm not sure where to start/what is required to run the jar. When I run the same .jar on windows after the "Command:" i see the login command being posted. But not on the Linux system.

Any help would be appreciated.

Regards,
 
Last edited:

Cableguy

Expert
Licensed User
Longtime User
Yes, it should be the same I as the root server...
In my case I was using my web domain name and working ok
 

Alexander Stolte

Expert
Licensed User
Longtime User
Hello, what i do wrong?

B4X:
Sub btn_registy_Click
    Dim cmd As DBCommand
    cmd.Initialize
    cmd.Name = "registry"
    cmd.Parameters = Array As Object(txb_username.Text, txb_email.Text , txb_password.text, "1")
    reqManager.ExecuteQuery(cmd, 0, Null) 'NULL
End Sub

Sub JobDone(Job As HttpJob)
    If Job.Success = False Then
        Log("Error: " & Job.ErrorMessage)
    Else
        If Job.JobName = "DBRequest" Then
            reqManager.HandleJobAsync(Job, "ReqManager")
        End If
    End If
    Job.Release
End Sub

Sub ReqManager_Result(result As DBResult)
    reqManager.PrintTable(result)
End Sub

this ends in a Error:
B4X:
(SQLServerException) com.microsoft.sqlserver.jdbc.SQLServerException: Es wurde kein Resultset von der Anweisung zurückgegeben
in english: no resultset is response

on my config File:
B4X:
sql.registry=INSERT INTO Users (username, email, password, user_ID) VALUES (?,?,?,?

what i have forgott?
 

Cableguy

Expert
Licensed User
Longtime User
You are inserting values, not retrieving them, so no record set is returned...
Try "SELECT FROM"
 
Status
Not open for further replies.
Top