B4J Question Custom RDC server.

dragonguy

Active Member
Licensed User
Longtime User
i want to create a custom RDC for multi database connection.

i really new in here, not really know how to do that.

please give me advice.

i already read the threads "[Server] Building web servers with B4J" and "[Server] Data Collection Solution - Device, Desktop and Web reports", but really not understand.

now i start at here:

B4X:
#Region  Project Attributes
    #CommandLineArgs:
    #MergeLibraries: true
    #AdditionalJar: mysql-connector-java-5.1.29-bin
#End Region

Sub Process_Globals
    Private srvr As Server
    Public pool As ConnectionPool
End Sub

Sub AppStart (Args() As String)
    srvr.Initialize("srvr")
    srvr.Port = 25641
   
    pool.Initialize("com.mysql.jdbc.Driver", "jdbc:mysql://192.168.0.82:25640/attendance?characterEncoding=utf8", _
        "root", "")
    Log("Testing the database connection")
    pool.GetConnection.Close

    srvr.Start
    Log("Server started")
    StartMessageLoop
End Sub

so what next? hope you guys give me a advice and trick to move on this project.
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
RDC is a very general solution. You don't need to reimplement it. Instead implement a solution for your specific case.

The first step is to add a Handler before the server is started.
B4X:
srvr.AddHandler("/addAnimal", "AddAnimal", false)

Now you can add this class module (named AddAnimal):
B4X:
'Class module
Sub Class_Globals
   
End Sub

Public Sub Initialize

End Sub

Public Sub Handle(req As ServletRequest, resp As ServletResponse)
   Dim raf As RandomAccessFile
   raf.Initialize3(Bit.InputStreamToBytes(req.InputStream), False)
   Dim anml As Animal = raf.ReadObject(0)
   Dim sql1 As SQL = main.pool1.GetConnection
   sql1.ExecNonQuery2("INSERT INTO animals VALUES(?, ?, ?)", Array As Object(anml.Name, anml.Age, anml.Location))
   sql1.Close
   resp.Write("Animal added successfully.")
End Sub
This handler reads an "Animal" object from the stream, then it gets a db connection from the pool and inserts the data to the database.

The handler is called with a HttbJob from the device code:
B4X:
Sub SendObject (Obj As Object)
  raf.WriteObject(Obj, True, 0)
  Dim size As Int = raf.CurrentPosition
  Dim data(size) As Byte
  raf.CurrentPosition = 0
  Do While raf.CurrentPosition < size
  raf.ReadBytes(data, raf.CurrentPosition, size - raf.CurrentPosition, _
  raf.CurrentPosition)
  Loop
 
  Dim j As HttpJob
  j.Initialize("send object", Me)
  j.PostBytes(link & "/AddAnimal", data)
End Sub

I recommend you to start with a simple handler and then move to the one that receives data from the device (try to run some of the examples).
 
Upvote 0

dragonguy

Active Member
Licensed User
Longtime User
i has test the code, report no error but when add record i found error.

main code:

B4X:
Sub Process_Globals
    Private srvr As Server
    Public pool As ConnectionPool
    Public SQL1 As SQL
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    srvr.Initialize("srvr")
    srvr.Port = 25741

    pool.Initialize("com.mysql.jdbc.Driver", "jdbc:mysql://127.0.0.1:25740/attendance", "root", "1234")
    Log("Testing the database connection")
    SQL1.Initialize2("com.mysql.jdbc.Driver", "jdbc:mysql://127.0.0.1:25740/attendance","root","1234")
    srvr.AddHandler("/AddLoc", "AddLoc", False)
    srvr.AddHandler("/Report", "Report", False)

    srvr.Start
    Log("Server started")

End Sub

Public Sub ReadObject (In As InputStream) As Object
    Dim out As OutputStream
    out.InitializeToBytesArray(0)
    File.Copy2(In, out)
    Dim raf2 As RandomAccessFile
    raf2.Initialize3(out.ToBytesArray, False)
    Dim res As Object = raf2.ReadObject(0)
    raf2.Close
    Return res
End Sub

Report code:
B4X:
'Class module
Sub Class_Globals
End Sub
'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize
End Sub
Public Sub Handle(req As ServletRequest, resp As ServletResponse)
    Dim html As String = DBUtils.ExecuteHtml(Main.SQL1, "SELECT * FROM section_loc ORDER BY LocType ASC", Null)
    resp.ContentType = "text/html"
    resp.Write(html)
End Sub

AddLoc code:

B4X:
Sub Class_Globals
    Type sectionLoc (LocName As String, Desc As String)
End Sub

'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize

End Sub

Public Sub Handle(req As ServletRequest, resp As ServletResponse)

  Dim loc As sectionLoc = Main.ReadObject(req.InputStream)
    Dim m As Map
    m.Initialize
    m.Put("LocType", loc.LocName)
    m.Put("Desc1", loc.Desc)
    DBUtils.InsertMaps(Main.SQL1, "section_loc", Array As Object(m))
    resp.Write("Location added successfully.")

End Sub

Device code:
B4X:
Sub SendObject (Obj As Object)
  raf.WriteObject(Obj, True, 0)
  Dim size As Int = raf.CurrentPosition
  Dim data(size) As Byte
  raf.CurrentPosition = 0
  Do While raf.CurrentPosition < size
  raf.ReadBytes(data, raf.CurrentPosition, size - raf.CurrentPosition, _
  raf.CurrentPosition)
  Loop
  Dim j As HttpJob
  j.Initialize("send object", Me)
  j.PostBytes(link & "/AddLoc", data)
End Sub

here is error code:

B4X:
Program started.
Mar 31, 2014 11:55:44 AM com.mchange.v2.log.MLog <clinit>
INFO: MLog clients using java 1.4+ standard logging.
Mar 31, 2014 11:55:44 AM com.mchange.v2.c3p0.C3P0Registry banner
INFO: Initializing c3p0-0.9.2.1 [built 20-March-2013 11:16:28 +0000; debug? true; trace: 10]
Testing the database connection
2014-03-31 11:55:44.604:INFO:oejs.Server:JavaFX Application Thread: jetty-9.1.z-SNAPSHOT
2014-03-31 11:55:44.635:INFO:oejsh.ContextHandler:JavaFX Application Thread: Started o.e.j.s.ServletContextHandler@5997bce2{/,file:/C:/Users/User/Desktop/B4J/Server/Objects/www,AVAILABLE}
2014-03-31 11:55:44.638:INFO:oejs.AbstractNCSARequestLog:JavaFX Application Thread: Opened C:\Users\User\Desktop\B4J\Server\Objects\logs\b4j-2014_03_31.request.log
2014-03-31 11:55:44.661:INFO:oejs.ServerConnector:JavaFX Application Thread: Started ServerConnector@675af91a{HTTP/1.1}{0.0.0.0:25641}
Server started
ExecuteHtml: SELECT * FROM section_loc ORDER BY LocType ASC
ExecuteHtml: SELECT * FROM section_loc ORDER BY LocType ASC
Class not found: b4a.example.main$_sectionloc, trying: b4j.example.main$_sectionloc
Error occurred on line: 35 (main).
java.lang.ClassNotFoundException: b4j.example.main$_sectionloc
    at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:186)
    at anywheresoftware.b4a.randomaccessfile.RandomAccessFile.readType(RandomAccessFile.java:485)
    at anywheresoftware.b4a.randomaccessfile.RandomAccessFile.readObject(RandomAccessFile.java:437)
    at anywheresoftware.b4a.randomaccessfile.RandomAccessFile.readHelper(RandomAccessFile.java:374)
    at anywheresoftware.b4a.randomaccessfile.RandomAccessFile.ReadObject(RandomAccessFile.java:335)
    at b4j.example.main._readobject(main.java:118)
    at b4j.example.addloc._handle(addloc.java:58)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:558)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:221)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:156)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:93)
    at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:82)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:84)
    at anywheresoftware.b4j.object.JServlet$Handle.run(JServlet.java:114)
    at com.sun.javafx.application.PlatformImpl$4.run(PlatformImpl.java:173)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.access$100(WinApplication.java:29)
    at com.sun.glass.ui.win.WinApplication$3$1.run(WinApplication.java:73)
    at java.lang.Thread.run(Thread.java:722)
 
Last edited:
Upvote 0

dragonguy

Active Member
Licensed User
Longtime User
Thanks! Solve my problem. Now everything has been ok, now need to set up the configuration file. Is it create the text file to store configuration setting? Then when server start it going read the setting file?
 
Upvote 0

dragonguy

Active Member
Licensed User
Longtime User
Thanks! i successful using file.readmap to read the setting properties.
my code here:
B4X:
         Dim Map1 As Map
    Map1 = File.ReadMap(File.DirAssets, "config.properties")
    Dim DriverClass As String = Map1.Get("DriverClass")
    Dim JdbcUrl As String    = Map1.Get("JdbcUrl")
    Dim User As String    = Map1.Get("User")
    Dim Password As String    = Map1.Get("Password")
    Dim ServerPort As String    = Map1.Get("ServerPort")
    Dim Debug As String    = Map1.Get("Debug")
    lblDriverClass.Text=DriverClass
    lblJdbcUrl.text=JdbcUrl
    lblUser.Text=User
    lblPassword.text=Password
    lblServerPort.Text=ServerPort
    lblDebug.Text=Debug

but how about SQL command? how to read the sql.select_Name line? Is it same using file.readmap to read it?
 
Last edited:
Upvote 0

dragonguy

Active Member
Licensed User
Longtime User
if user computer didn't have a driver, how can i set #AdditionalJar folder for it? just copy the driver files to that folder.
 
Upvote 0

dragonguy

Active Member
Licensed User
Longtime User
sure i also got connect to ms access database
code here:
B4X:
#AdditionalJar: mysql-connector-java-5.1.29-bin
    #AdditionalJar: ucanaccess-2.0.3.jar
    #AdditionalJar: commons-lang-2.6.jar
    #AdditionalJar: commons-logging-1.0.4.jar
    #AdditionalJar: hsqldb.jar
    #AdditionalJar: jackcess-2.0.3.jar
if i add the code like above, is it no need to copy the driver to end user computer?
 
Upvote 0

dragonguy

Active Member
Licensed User
Longtime User
now another question here
main code:
B4X:
Sub Process_Globals
    Private srvr As Server
    Public mysql_pool1 As ConnectionPool
    Type SectionLocation (Name As String)
End Sub

Sub AppStart (Args() As String)

    Dim Map1 As Map
    Map1 = File.ReadMap(File.DirAssets, "config.properties")
    Dim ServerPort As String    = Map1.Get("ServerPort")

    Dim mysql_pool1_DriverClass As String = Map1.Get("mysql_pool1_DriverClass")
    Dim mysql_pool1_JdbcUrl As String    = Map1.Get("mysql_pool1_JdbcUrl")
    Dim mysql_pool1_User As String    = Map1.Get("mysql1_pool_User")
    Dim mysql_pool1_Password As String    = Map1.Get("mysql_pool1_Password")

    srvr.Initialize("srvr")
    srvr.Port = ServerPort

    srvr.AddHandler("/Section_Location", "Section_Location", False)
    mysql_pool1.Initialize(mysql_pool1_DriverClass, mysql_pool1_JdbcUrl, mysql_pool1_User, mysql_pool1_Password)

    srvr.Start
    Log("Server started")
    StartMessageLoop

End Sub

Public Sub ReadObject (In As InputStream) As Object
    Dim out As OutputStream
    out.InitializeToBytesArray(0)
    File.Copy2(In, out)
    Dim raf2 As RandomAccessFile
    raf2.Initialize3(out.ToBytesArray, False)
    Dim res As Object = raf2.ReadObject(0)
    raf2.Close
    Return res
End Sub

Section_location code:
B4X:
Sub Class_Globals

End Sub

Public Sub Initialize

End Sub

Public Sub Handle(req As ServletRequest, resp As ServletResponse)
    Dim name As SectionLocation = Main.ReadObject(req.InputStream)
    Dim sql1 As SQL = Main.mysql_pool1.GetConnection

    'problem at here how can i send back data to device?
    'how device put data to ListView
    'sql string like this ""SELECT ShortName FROM attendee_profile WHERE AccessPlace = ?  order by ShortName ASC, AccessPlace ASC",Array As Object(name)
End Sub
 
Upvote 0

dragonguy

Active Member
Licensed User
Longtime User
here is android code

B4X:
Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    Dim Timer1 As Timer
    Dim Timer2 As Timer
    Dim Timer3 As Timer
    Dim Timer4 As Timer
End Sub

Sub Globals
    Dim clv1 As ListView
    Dim clv2 As ListView
    Dim myProgressDialog As CustomProgressDialog
    Dim Label2 As Label
    Dim Label3 As Label
    Dim Label5 As Label
    Dim Name_door As String=""
    Dim VerStatus As String
    Dim sf As StringFunctions
    Dim status As String="0"
    sf.Initialize
   
    Private link As String = "http://192.168.168.182:25750"
    Private raf As RandomAccessFile
    Type SectionLocation (Name As String)
End Sub

Sub Activity_Create(FirstTime As Boolean)
   
    Activity.LoadLayout("1")
    raf.Initialize(File.DirInternalCache, "temp", False)
   
    If FirstTime Then
        Timer1.Initialize("Timer1",1000)
        Timer2.Initialize("Timer2",1000)
        Timer3.Initialize("Timer3",2500)
        Timer4.Initialize("Timer4",2500)
    End If
   
    Timer1.Enabled=True
    Timer2.Enabled=False
    Timer3.Enabled=False
    Timer4.Enabled=False

    VerStatus="  Status: Checking App Version..."
  
End Sub

Sub SendObject (Obj As Object)
  raf.WriteObject(Obj, True, 0)
  Dim size As Int = raf.CurrentPosition
  Dim data(size) As Byte
  raf.CurrentPosition = 0
  Do While raf.CurrentPosition < size
    raf.ReadBytes(data, raf.CurrentPosition, size - raf.CurrentPosition, _
      raf.CurrentPosition)
  Loop
 
  Dim j As HttpJob
  j.Initialize("send object", Me)
  j.PostBytes(link & "/Section_Location", data)
End Sub

Sub GetName(strName As String)
    Name_door=strName
    Dim a As SectionLocation
        a.Initialize
        a.Name=strName
        SendObject (a)
End Sub

Sub JobDone(j As HttpJob)
    If j.Success Then
        If j.JobName = "send object" Then
            Log(j.GetString)
            
        End If
    Else
        Log("Error: " & j.ErrorMessage)
        Msgbox(j.ErrorMessage, "Error")
    End If
    j.Release
    ProgressDialogHide
End Sub
 
Upvote 0

dragonguy

Active Member
Licensed User
Longtime User
not really understand, Erel have any example? i like to learn from there. now i stuck at here, so bored.
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
Here is one option. Add this sub to the server code:
B4X:
Public Sub SendObject(obj As Object, resp As ServletResponse)
   Dim filename As String = "server_" & Main.srvr.CurrentThreadIndex
   Dim raf As RandomAccessFile
   raf.Initialize(File.DirTemp, filename, False)
   raf.WriteObject(obj, True, 0)
   Dim size As Int = raf.CurrentPosition
   Dim data(size) As Byte
   raf.CurrentPosition = 0
   Do While raf.CurrentPosition < size
     raf.ReadBytes(data, raf.CurrentPosition, size - raf.CurrentPosition, _
       raf.CurrentPosition)
   Loop
   resp.OutputStream.WriteBytes(data, 0, data.Length)
   raf.Close
End Sub

With this code you can send a List or Type or almost any other object to the device.
In the case above you can do something like:
B4X:
Dim results As List
results.Initialize
Dim RS As ResultSet = SQL1.ExecuteQuery(...)
Do While RS.NextRow
 results.Add(RS.GetString("col1"))
Loop
RS.Close
Main.SendObject(results, resp)

Now in the Android code you can use the same ReadObject from the server to read the result (use HttpJob.GetInputStream in JobDone).
 
Upvote 0
Top