B4J Library Modded jRDC2 w/SQLite support and more

Discussion in 'B4J Libraries & Classes' started by OliverA, Oct 31, 2017.

  1. OliverA

    OliverA Expert Licensed User

    Attached you'll find a modified version of jRDC2 (source https://www.b4x.com/android/forum/t...ation-of-rdc-remote-database-connector.61801/) that supports SQLite as the datastore out of the box. Support for V1 has been removed and therefore this is not a drop in replacement for jRDC2. This is more meant for people starting new with jRDC2. Comments are welcome (pro and con). Other modifications are listed in the main file and are relisted here:

    '2017/10/30 Update
    'Main module changes:
    'Added the logging of one of the IP addresses that the server is bound to. The method.
    ' to retrieve the IP address is similar to ServerSocket's GetMyIP method. It was adapted
    ' from https://issues.apache.org/jira/browse/JCS-40.
    'Added ability to assign server to a specific IP address.

    'RDCConnector changes:
    'Added IPAddress configuration option. Allows to set the jRDC server's IP address. An un-bindable
    ' address will crash the server.
    'Added HasIPAddress and GetIPAddress to access IPAddress configuration.
    'Added support for SQLite. If the DriverClass contains SQLite (case insensitive), then jRDC
    ' is configured for SQLite usage. SQLite does not use pools. Pool/non-pool handling gleaned
    ' from DBM.bas module of ABMaterial.
    'Added CreateFile configuration option. This option is used for the SQLite backend
    ' (if used). If set to True or set to 1, then the SQLite database will be created in
    ' case it does not exist yet. Any other settings are interpreted as False.
    'Added PoolSize configuration option. This is the size of the pool that should be used
    ' for pooled JDBC databases. This option was gleaned from the DBM.bas module of ABMaterial.
    'Modified GetCommand to return empty string ("") when no command found.
    'Modified GetConnection to handle non-pool SQL connections (SQLite).

    'RDCHandler changes:
    'Modified Handler to not close the databas connection in case a pool is not used, else SQLite
    ' will not function properly
    'Modified ExecuteQuery2 and ExecuteBatch2 to check cmd.Parameters for Null. This removed a
    ' Null pointer exception error message in case cmd.Parameters was Null. Also call
    ' ExecQuery/ExecNonQuery when no cmd.Parameters are given.
    'Modified ExecuteQuery2 and ExecuteBatch2 to check for valid command. If no valid command found,
    ' return 500 error with proper response. This takes care of a syntax exception error for the DB.
    ' in case of MySQL it looks something like this:
    ' com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax;
    ' check the manual that corresponds to your MySQL server version for the right syntax to use near 'null' at line 1
    'Modified Try/Catch block in ExecuteBatch2. Moved the code below the End Try that dealt with
    ' converting the DBResult object and sending it to the client into end of the Try block. This
    ' took care of an java.lang.IllegalStateException: WRITER exception caused by OutputStream when
    ' called after the Catch's SendError.
    'Added Try/Catch block to ExecuteQuery2. This should prevent the following on the B4X client
    ' side: java.io.EOFException: Unexpected end of ZLIB input stream
    'Removed all jRDC v1 functionality.

    'Miscellaneous notes:
    'The config.properties contains sql. directives that pertain to a jRDC version of the DBUtils
    ' demo.
    'Per usual, please ensure you have the proper #AdditionalJar set for the database backend
    ' of your choice (even for SQLite).

    Attached Files:

    Mashiane, derez, DonManfred and 5 others like this.
  2. Erel

    Erel Administrator Staff Member Licensed User

  3. inakigarm

    inakigarm Well-Known Member Licensed User

    Thanks Oliver; I'm working this days on a project that uses jRDC2 in a client -server scheme (Sqlite on local and Sqlite on server, synchronising the data on server with clients data)
    One mod I've done on jRDC2 is retrieving the sql commands from a sqlite db also (configProperties.db) because:
    - It's easier to modify/add sql commands from an helper application than the config.Properties file ( and as I'm not a very good programmer always I'very to modify the projected application in one way or another
    - Gets the project 'tidy' and more understandable
    - It'easier to apply the new added commands without the need of resetting the JRDC server application

    If you want, I can send you the code (obviously, it's not a complex mod)
  4. OliverA

    OliverA Expert Licensed User

    Both have been accounted for.
    Erel likes this.
  5. OliverA

    OliverA Expert Licensed User

    Same here. Both my "contributions" are based on already posted projects (Universal DBUtils and now this).
    Ha, I was going to take a stab at this next (a means of updating the SQL statements without restarting server).
    That would be great!
  6. Johan Hormaza

    Johan Hormaza Active Member Licensed User

    I would appreciate if you send it to me too
  7. Diceman

    Diceman Active Member Licensed User

    Oliver, I may have discovered a bug, or maybe I'm missing something. Can you shed some light on it?

    1) In HandleJobAsync the CallSubDelayed2() gets executed but the sub "req_result" is never executed. I have a breakpoint inside of "req_result" and a log statement and they never execute. I thought maybe it can't find the sub so I added an "if statement" to make sure the sub "result_req" exists before the CallSubDelated2() statement is executed.

    2) I had to put the "req_result" sub in jRDC2Utils because that is where mTarget is pointing to. The debugger shows mTarget.Name = "b4j.example.jrdc2utils". I would have thought req_result would belong in Main. I have one in there too, and it can't find it there either.

    Do you have any idea why req_result() sub is never executed? BTW, req_result() sub is also called in jRDC2Utils.ExecuteQuery but the code in req_result() never executes there either. I tried both Debug and Release modes.


    'This is the code from DBRequestManager

    Public Sub HandleJobAsync(Job As HttpJob, EventName As String)
    Dim ser As B4XSerializator
    Dim data() As Byte = Bit.InputStreamToBytes(Job.GetInputStream)
    Wait For (ser) ser_BytesToObject (Success As Boolean, NewObject As Object)
    If Success = False Then
    Log("Error reading response: " & LastException)
    End If
    Dim res As DBResult = NewObject
        res.Tag = Job.Tag
    If SubExists(mTarget, EventName & "_result"Then
    Log("Calling " & EventName & "_result")     '<-- This line gets executed and is shown in log  
            CallSubDelayed2(mTarget, EventName & "_result", res)    '<-- Line gets executed but sub is never executed (log stmt or breakpoint in "req_results" never executed)
    Log("Sub Does Not Exist: " & EventName & "_result")
    End If
    End Sub
    'This is the sub in jRDC2Utils that never executes.

    public Sub req_result(aDbResult As DBResult)
    Log("[jRDC2Utils.req_result] EXECUTED")
    End Sub
  8. OliverA

    OliverA Expert Licensed User

    I'm going to need more code from you to see what you are doing code wise (how you use DBRequestManager and/or JRDC2Utils) before I can give you an answer. As is, JRDC2Utils wraps DBRequestManager and handles the interception of the _result callback via Wait For(s).
  9. Diceman

    Diceman Active Member Licensed User

    So where should the user's actual "req_result" sub be defined? I haven't been able to get any req_result() sub to be executed whether it is defined in Main or jRDC2Utils. Is it operator error (me?) or a problem with the code? I define events all the time for the classes I define, but I never had to use "Wait For..." when calling an event.

    I have added tags "##:" throughout the client that explains the problem.
    There is No rush at looking at it. It is NOT holding me up. Whenever you get around to it. Thanks.

    Attached Files:

  10. OliverA

    OliverA Expert Licensed User

    When you use the jRDC2Utils module, you do not have to define, nor worry about "req_result". It is taken care of by the ExecuteQuery method of the jRDC2Utils module and this method returns the DBResult object that is returned by DBRequestManager's HandleJobAsync method. If you want to take care of the results yourself that are returned by HandeJobAsync, then
    1) Use ExecuteQuery2 of the jRDC2Utils module, which allows you to provide a caller object and method name to execute after retrieving the results (technically it's just a wrapper of ExecuteQuery)
    2) Don't use jRDC2Utils, but just follow the examples given by @Erel's post on jRDC2 client usage (https://www.b4x.com/android/forum/t...ation-of-rdc-remote-database-connector.61801/).

    Answer to comments on the code you supplied:
    Nope, no hate from me. Yes, as it stands, jRDC2Utils works with one server and you provided two means it could be changed to handle more. My only comment here is that no event name is necessary, since jRDC2Utils either 1) takes care of that or 2) allows you to specify caller/method in the ExecuteQuery2 method.
    Strange. At what point is ValueChanged method called without having a row selected? Please note since my code is pretty much a straight rip of the DBUtils example, that bug would also be manifest there.

    Note: Technically all these discussions should be happening at the jRDC2 client example that uses this code (https://www.b4x.com/android/forum/threads/jrdc2-client-example-using-modded-jrdc2.85581/).
  11. Diceman

    Diceman Active Member Licensed User

    OliverA, thanks for your reply. I will try your suggestions and get back to you with the results.
  12. Diceman

    Diceman Active Member Licensed User

    Ok, I don't know how I missed seeing the sub ExecuteQuery2 that has an event parameter. Thanks.

    I will do some rudimentary benchmarking to see if changing jRDCUtils2 into a class causes any speed or memory problems if used on the server. I'm thinking of having one server call one or more other servers to get more data. It may be simpler just to pass the parameters to the jRDC2 code module so garbage collection is easier.

    I have included a couple of screenshots that may help. It is a trivial fix.

    Correct. I redownloaded these 2 files this morning and retested.

    Thanks again for your help. I'm up and running again. :)

    ClientInstructions.png ClientException.png
  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