B4J Tutorial [Server] Send and receive objects

Discussion in 'B4J Tutorials' started by Erel, Jan 28, 2014.

  1. Erel

    Erel Administrator Staff Member Licensed User

    This is an old example. Better use B4XSerializator to serialize objects.

    One of the nice things about using B4J server as the backend of B4A applications is that you can send and receive objects such as custom types and collections of custom types instead of working with bytes or strings.

    In this example we have two custom types:
    Code:
    Type Order(ProductKey As String, Amount As Int, Comment As String)
    Type OrderResult(NumberOfOrders As Int, Success As Boolean)
    These types are declared both in the server and the client applications.

    The client will send a list of Orders and the server will return an OrderResult object. The serialization of the objects is done with RandomAccessFile.WriteObject / ReadObject. It supports all primitive types, custom types, arrays and collections. Note that Bitmaps are not supported.

    Client Code

    Code:
    Sub Process_Globals
       
    Type Order(ProductKey As String, Amount As Int, Comment As String)
       
    Type OrderResult(NumberOfOrders As Int, Success As Boolean)
     
       
    Private raf As RandomAccessFile
       
    'server link
       Private link As String = "http://192.168.0.100:51042/order"
    End Sub

    Sub Activity_Create(FirstTime As Boolean)
       
    If FirstTime Then
         raf.Initialize(
    File.DirInternal, "temp"False)
       
    End If
     
       
    Dim Orders As List
       Orders.Initialize
       
    For i = 1 To 20
         
    Dim o As Order
         o.Initialize
         o.ProductKey = 
    "Item #" & i
         o.Amount = 
    7
         o.Comment = 
    "abcdef"
         Orders.Add(o)
       
    Next
       SendObject(Orders)
    End Sub

    Sub SendObject (Obj As Object)
       raf.WriteObject(Obj, 
    True0)
       
    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, data)
    End Sub

    Sub ReadObject (In As InputStreamAs 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

    Sub JobDone(j As HttpJob)
       
    If j.Success Then
         
    Dim result As OrderResult = ReadObject(j.GetInputStream)
         
    Log(result)
       
    Else
         
    Log("Error: " & j.ErrorMessage)
       
    End If
       j.Release
    End Sub
    Server code

    Main module:
    Code:
    Sub Process_Globals
       
    Type Order(ProductKey As String, Amount As Int, Comment As String)
       
    Type OrderResult(NumberOfOrders As Int, Success As Boolean)
       
    Private srvr As Server
    End Sub

    Sub AppStart (Args() As String)
       srvr.Initialize(
    "")
       srvr.Port = 
    51042
       srvr.AddHandler(
    "/order""OrderHandler"False)
       srvr.Start
       StartMessageLoop
    End Sub
    OrderHander class:
    Code:
    Sub Class_Globals
       
    'The buffer must be large enough to hold the result object.
       Private bufferSize As Int = 1000
    End Sub

    Public Sub Initialize

    End Sub

    Sub Handle(req As ServletRequest, resp As ServletResponse)
       
    Dim orders As List = ReadObject(req.InputStream)
       
    Dim result As OrderResult
       result.Initialize
       
    For Each o As Order In orders
         
    'work with the order
         Log(o.ProductKey & ", " & o.Amount & ", " & o.Comment)
         result.NumberOfOrders = result.NumberOfOrders + 
    1
       
    Next
       result.Success = 
    True
       SendObject(result, resp.OutputStream)
    End Sub

    Sub ReadObject (In As InputStreamAs 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

    Sub SendObject (Obj As Object, Out As OutputStream)
       
    Dim raf As RandomAccessFile
       
    Dim buffer(bufferSize) As Byte
       raf.Initialize3(buffer, 
    False)
       raf.WriteObject(Obj, 
    True0)
       Out.WriteBytes(buffer, 
    0, raf.CurrentPosition)
    End Sub
    Note that the server writes the object into a temporary buffer. The buffer must be large enough in order to hold the serialized data. You can check raf.CurrentPosition after writing the object to get an estimation of the required size. Another option is to use a temporary file as done in the client. However for this to work properly you need to set the handler to run in single threaded mode.

    Note that you will see the following message in the logs:
    You can ignore it. It happens on the first time that a type with a different package is discovered.
     
    Last edited: Mar 30, 2018
  2. Asim A Baki

    Asim A Baki Active Member Licensed User

    How to change the server to accept multiple clients?
     
  3. Erel

    Erel Administrator Staff Member Licensed User

    You don't need to change anything. The above code can handle multiple clients.
     
  4. Asim A Baki

    Asim A Baki Active Member Licensed User

    Sorry I tried but it didn't work, the first client is only the one can send

    anyhow, I already handled this by mexing some code from CCTV example
     
  5. NinJavier

    NinJavier Member Licensed User

    Is this example can be worth to send files (b4a) and receive files (B4j)?
     
  6. Erel

    Erel Administrator Staff Member Licensed User

  7. driesvp

    driesvp Member Licensed User

    Dear,

    When receiving an object from my B4JServer to my Android I receive an error: java.lang.classnotfoundexception: Veos.JavaServer.main$_dbresult.

    The received object refers to B4JServer nevertheless it's downloaded on my phone. On the phone I declared dbresult in Process_globals of Main.

    How to solve this?

    Thanks!
     
  8. Erel

    Erel Administrator Staff Member Licensed User

    Can you post the exact message from the logs? What happens after this message? Does the app crash?
     
  9. driesvp

    driesvp Member Licensed User

    I will post the message later this evening but I already can tell you that the app crashes.
    It's the only error message (in red) that I receive.
     
  10. Erel

    Erel Administrator Staff Member Licensed User

    Make sure that the B4A type is indeed named DBResult. Also make sure that you are using RandomAccessFile v1.6+.
     
  11. driesvp

    driesvp Member Licensed User

    The problem: I used an older version of RandomAccessFile. Problem solved, thanks!
     
  12. driesvp

    driesvp Member Licensed User

    When using this routine, it doesn't work when the received recordset is too big. Anyone an idea how to solve this?

    Code:
    Public Sub ReadObject (In As InputStreamAs Object
        
    Try
            
    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
        
    Catch
            res=
    ""
        
    End Try
      
    End Sub
     
  13. Erel

    Erel Administrator Staff Member Licensed User

    Please remove the Try / Catch block and post the full error message.
     
  14. driesvp

    driesvp Member Licensed User

    I receive this error message:

    LastException java.lang.ArrayIndexOutOfBoundsException: length=0; index=0

    It's happening on this line:
    Dim res As Object = raf2.ReadObject(0)
     
  15. Erel

    Erel Administrator Staff Member Licensed User

    Can you post the full error message (with the stack trace) from the logs?
     
  16. driesvp

    driesvp Member Licensed User

    How can I copy the log from B4a to this post?
     
  17. Erel

    Erel Administrator Staff Member Licensed User

    Right click on the logs.
     
  18. driesvp

    driesvp Member Licensed User

    Thanks! :)

    LogCat connected to: B4A-Bridge: Sony Ericsson LT26i
    --------- beginning of /dev/log/system
    --------- beginning of /dev/log/main
    ** Service (databaseconnectie) Start **
    ** Service (databaseconnectie) Start **
    ** Service (databaseconnectie) Start **
    ~i:** Activity (main) Resume **
    ~i:** Activity (main) Pause, UserClosed = false **
    ~i:** Activity (main) Create, isFirst = false **
    ~i:** Activity (main) Resume **
    ~i:** Activity (main) Pause, UserClosed = false **
    ~i:** Activity (main) Create, isFirst = false **
    ~i:** Activity (main) Resume **
    ~i:** Service (service1) Create **
    ~i:** Service (service1) Start **
    Connected to B4A-Bridge (Wifi)
    ** Service (databaseconnectie) Start **
    Installing file.
    ~i:** Activity (main) Pause, UserClosed = false **
    PackageAdded: package:Veos.OnderhoudSmeren
    ** Activity (main) Create, isFirst = true **
    ** Activity (main) Create, isFirst = true **
    ** Activity (main) Resume **
    ** Activity (main) Resume **
    ** Service (databaseconnectie) Create **
    ** Service (databaseconnectie) Create **
    ** Service (databaseconnectie) Start **
    ** Service (databaseconnectie) Start **
    ** Activity (main) Pause, UserClosed = false **
    ** Activity (main) Pause, UserClosed = false **
    ** Activity (overzichtwerkbonnen) Create, isFirst = true **
    ** Activity (overzichtwerkbonnen) Create, isFirst = true **
    ** Activity (overzichtwerkbonnen) Resume **
    ** Activity (overzichtwerkbonnen) Resume **
    startService: class Veos.OnderhoudSmeren.httputils2service
    startService: class Veos.OnderhoudSmeren.httputils2service
    ** Service (httputils2service) Create **
    ** Service (httputils2service) Create **
    ** Service (httputils2service) Start **
    ** Service (httputils2service) Start **
    srobjects_readobject (B4A line: 34)
    Dim res As Object = raf2.ReadObject(0)
    java.lang.ArrayIndexOutOfBoundsException: length=0; index=0
    at anywheresoftware.b4a.randomaccessfile.RandomAccessFile$ByteArrayChannel.read(RandomAccessFile.java:665)
    at anywheresoftware.b4a.randomaccessfile.RandomAccessFile.ReadInt(RandomAccessFile.java:137)
    at anywheresoftware.b4a.randomaccessfile.RandomAccessFile.readHelper(RandomAccessFile.java:375)
    at anywheresoftware.b4a.randomaccessfile.RandomAccessFile.ReadObject(RandomAccessFile.java:364)
    at Veos.OnderhoudSmeren.srobjects._readobject(srobjects.java:106)
    at Veos.OnderhoudSmeren.objectedit._jobuitgevoerd(objectedit.java:53)
    at Veos.OnderhoudSmeren.srobjects._jobdone(srobjects.java:68)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:511)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:167)
    at anywheresoftware.b4a.keywords.Common$4.run(Common.java:885)
    at android.os.Handler.handleCallback(Handler.java:615)
    at android.os.Handler.dispatchMessage(Handler.java:92)
    at android.os.Looper.loop(Looper.java:213)
    at android.app.ActivityThread.main(ActivityThread.java:4787)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:511)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:556)
    at dalvik.system.NativeStart.main(Native Method)
    java.lang.ArrayIndexOutOfBoundsException: length=0; index=0
    srobjects_readobject (B4A line: 34)
    Dim res As Object = raf2.ReadObject(0)
    java.lang.ArrayIndexOutOfBoundsException: length=0; index=0
    at anywheresoftware.b4a.randomaccessfile.RandomAccessFile$ByteArrayChannel.read(RandomAccessFile.java:665)
    at anywheresoftware.b4a.randomaccessfile.RandomAccessFile.ReadInt(RandomAccessFile.java:137)
    at anywheresoftware.b4a.randomaccessfile.RandomAccessFile.readHelper(RandomAccessFile.java:375)
    at anywheresoftware.b4a.randomaccessfile.RandomAccessFile.ReadObject(RandomAccessFile.java:364)
    at Veos.OnderhoudSmeren.srobjects._readobject(srobjects.java:106)
    at Veos.OnderhoudSmeren.objectedit._jobuitgevoerd(objectedit.java:53)
    at Veos.OnderhoudSmeren.srobjects._jobdone(srobjects.java:68)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:511)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:167)
    at anywheresoftware.b4a.keywords.Common$4.run(Common.java:885)
    at android.os.Handler.handleCallback(Handler.java:615)
    at android.os.Handler.dispatchMessage(Handler.java:92)
    at android.os.Looper.loop(Looper.java:213)
    at android.app.ActivityThread.main(ActivityThread.java:4787)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:511)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:556)
    at dalvik.system.NativeStart.main(Native Method)
    java.lang.ArrayIndexOutOfBoundsException: length=0; index=0
    ** Activity (overzichtwerkbonnen) Pause, UserClosed = false **
    ** Activity (overzichtwerkbonnen) Pause, UserClosed = false **
    ** Activity (overzichtwerkbonnen) Create, isFirst = false **
    ** Activity (overzichtwerkbonnen) Create, isFirst = false **
    ~i:** Activity (main) Resume **
    ~i:** Activity (main) Pause, UserClosed = false **
    ~i:** Activity (main) Create, isFirst = false **
    ~i:** Activity (main) Resume **
    ~i:** Activity (main) Pause, UserClosed = false **
    Connected to B4A-Bridge (Wifi)
    sending message to waiting queue (CallSubDelayed - UpdateStatus)
    Connected to B4A-Bridge (Wifi)
    sending message to waiting queue (CallSubDelayed - UpdateStatus)
     
  19. Erel

    Erel Administrator Staff Member Licensed User

    The array is empty for some reason.
     
  20. driesvp

    driesvp Member Licensed User

    ok, then it must have something to do with the code on the B4J server side. When I limit the query to max 20 records it's working.
    Is it possible that the buffersize need to be enlarged on the server?

    Code:
    Sub SendObject (Obj As Object, Out As OutputStream)
        
    Dim raf As RandomAccessFile
        
    Dim bufferSize As Int = 1000
        
    Dim buffer(bufferSize) As Byte
        raf.Initialize3(buffer, 
    False)
        raf.WriteObject(Obj, 
    True0)
        Out.WriteBytes(buffer, 
    0, raf.CurrentPosition)
       
    End Sub
     
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice