B4J Question ABMaterial and stateful dialogs

rbirago

Active Member
Licensed User
Longtime User
In the past I have developed some web apps and the main rule to have in mind was to recover the shared variables of the session in hidden fields or cookies or in a single-threaded map of every specific session.
Now I am approaching to ABMaterial to evolve a client/server B4J app into a web-app. Looking at ABMaterial (and websockets) tutorials it seems that any server specific handler page can be multithreaded . Does it means that the handler is stateful (a variable is maintained in memory across the session)? In my trials It doesn't seem so. Am I wrong? Have I to treat variables as in the past (hidden fields, cookies, single-threaded maps)?
thanks
Roberto
 

alwaysbusy

Expert
Licensed User
Longtime User
a variable is maintained in memory across the session
they are within a page, even when the connection is temporary lost but not within a session (or across pages so to say). For variables accross pages, you will have to set/get them in the ws.session (they must be Strings if I recall correctly, so for complex objects you can do that as a Json String):

B4X:
page.ws.session.SetAttribute("var1", var1)
page.ws.session.GetAttribute("var1")
page.ws.session.GetAttribute2("var1", defaultValue)
page.ws.session.RemoveAttribute("var1")

Alwaysbusy
 
Upvote 0

rbirago

Active Member
Licensed User
Longtime User
Perhaps there is something I don't understand: I tried to verify the stateful inside the same page varying the ABMaterial lesson 1 sample:
AboutPage:
'Class module
Sub Class_Globals
    Private ws As WebSocket 'ignore
    ' will hold our page information
    Public page As ABMPage
    ' page theme
    Private theme As ABMTheme
    ' to access the constants
    Private ABM As ABMaterial 'ignore   
    ' name of the page, must be the same as the class name (case sensitive!)
    Public Name As String = "AboutPage"
    ' name of the app, same as in ABMApplication
'    Public AppName As String = "template"
    
    Private ABMPageId As String = ""
    ' your own variables
    Private myToastId As Int
    Private Count1 As Int
    
End Sub

'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize
    ' build the local structure IMPORTANT!
    BuildPage
    If (Count1 = 0) Then Count1 = 100
    Log("session initialized")
End Sub

Private Sub WebSocket_Connected (WebSocket1 As WebSocket)
    '----------------------MODIFICATION-------------------------------
    Log("Connected")
    
    ws = WebSocket1
    
    ABMPageId = ABM.GetPageID(page, Name,ws)
    
    Dim session As HttpSession = ABM.GetSession(ws, ABMShared.SessionMaxInactiveIntervalSeconds)
    
    If session.IsNew Then
        Log("new session: " & session.Id)
        session.Invalidate
        ABMShared.NavigateToPage(ws, "", "./")
        Return
    End If
    If ABMShared.NeedsAuthorization Then
        If session.GetAttribute2("IsAuthorized", "") = "" Then
            ABMShared.NavigateToPage(ws, ABMPageId, "../")
            Return
        End If
    End If
    
    ABM.UpdateFromCache(Me, ABMShared.CachedPages, ABMPageId, ws)
    If page.ComesFromPageCache Then
        ' when we have a page that is cached it doesn't matter if it comes or not from a new connection we serve the cached version.
        Log("Comes from cache")
        page.Refresh
        page.FinishedLoading
    Else
        If page.WebsocketReconnected Then
            Log("Websocket reconnected")
            ' when we have a client that doesn't have the page in cache and it's websocket reconnected and also it's session is new - basically when the client had internet problems and it's session (and also cache) expired before he reconnected so the user has content in the browser but we don't have any on the server. So we need to reload the page.
            ' when a client that doesn't have the page in cache and it's websocket reconnected but it's session is not new - when the client had internet problems and when he reconnected it's session was valid but he had no cache for this page we need to reload the page as the user browser has content, reconnected but we have no content in cache
            ABMShared.NavigateToPage (ws, ABMPageId, "./" & page.PageHTMLName)
        Else
            ' when the client did not reconnected it doesn't matter if the session was new or not because this is the websockets first connection so no dynamic content in the browser ... we are going to serve the dynamic content...
            Log("Websocket first connection")
            page.Prepare
            ConnectPage
        End If
    End If
    Log("  -- This Page ID: "&ABMPageId)
    Count1 = Count1 + 1
    Log ("session# : " & session.Id & " count1 : " & Count1)
End Sub
I run the app in release mode and calling the url by my browser my log is as I was expecting:
B4X:
preparing for url refresh
Disconnected
session initialized
Connected
Waiting for value (1 ms)
Saving the first instance
Waiting for value (2 ms)
Websocket first connection
Waiting for value (5 ms)
  -- This Page ID: AboutPage1ac42e09-b30d-4716-a409-0aa6f15f88d2
session# : node01q1og7nu6vqjvneoi6d1dc7s51 count1 : 101
Now, if I recall the page by my browser my field COUNT1 is resetted as the log shows:
B4X:
preparing for url refresh
Disconnected
session initialized
Connected
Waiting for value (1 ms)
Saving the first instance
Waiting for value (2 ms)
Websocket first connection
Waiting for value (5 ms)
  -- This Page ID: AboutPage1ac42e09-b30d-4716-a409-0aa6f15f88d2
session# : node01q1og7nu6vqjvneoi6d1dc7s51 count1 : 101
 *** Page Event name: page_navigationbarclicked  (MyMap) {eventparams=action,value, action=About, value=../AboutPage, eventname=page_navigationbarclicked}
Waiting for value (1 ms)
Disconnected
session initialized
Connected
Waiting for value (5 ms)
Saving the first instance
Waiting for value (1 ms)
Websocket first connection
Waiting for value (11 ms)
  -- This Page ID: AboutPage1ac42e09-b30d-4716-a409-0aa6f15f88d2
session# : node01q1og7nu6vqjvneoi6d1dc7s51 count1 : 101
Where is my mistake?
thanks
Roberto
 
Upvote 0

alwaysbusy

Expert
Licensed User
Longtime User
You made no mistake, this is the breakdown:

1. if a reconnection is invoked by the user (e.g. by pressing reload or F5), then the variable will be reset
2. if a reconnection is invoked by e.g. a temporary connection loss, then the variable will not be reset but comes from the cache if it has not been scavenged yet (e.g. every 15 minutes, depending on your settings).

In case 2, you should see something like this (you can test it by setting the browser to offline in the Chrome - Dev Tools (F12) - Network Tab):
B4X:
Saving the first instance '<----------------------------------- caused by first entry or if the user pressed e.g. F5 to reload
[PageTestUpload0001: 2021-18-02 16:00:28] Websocket first connection
[PageTestUpload0001: 2021-18-02 16:00:29] PageTestUpload0001ea980423-6e43-490f-adcb-39bd774ec5fe
myToastId: 101
Disconnected '<----------- disconnected because I severed the internet connection in the Dev tools of Chrome
[PageTestUpload0001: 2021-18-02 16:02:22] Connected
UpdateFromCache: PageTestUpload0001ea980423-6e43-490f-adcb-39bd774ec5fe
Reading from cache '<------------------------------- websocket was disconnected, but we can retrieve the values from the variables from the cache.
[PageTestUpload0001: 2021-18-02 16:02:22] Comes from cache
[PageTestUpload0001: 2021-18-02 16:02:22] PageTestUpload0001ea980423-6e43-490f-adcb-39bd774ec5fe
myToastId: 102

if you want to save it also in case 1, then you will have to save it in the session with the methods above:

e.g.
B4X:
If page.ws.Session.HasAttribute("SessionCount1") Then
        count1 = page.ws.Session.GetAttribute("SessionCount1")
End If
  
count1 = count1 + 1
Log("count1: " & count1)
  
page.ws.Session.SetAttribute("SessionCount1", count1)

Alwaysbusy
 
Upvote 0

rbirago

Active Member
Licensed User
Longtime User
Referring always to lesson 1 sample:
If I call AboutPage in the log I see that the websocket is connected (of course...).
But if I use the page menu to go to ABMPageTemplate (the only other page in this sample) I see in the log a "disconnected" and then another "Connected".
The question is: why if I navigate between pages everytime the websocket reconnects (using the same Page Id)?
thanks
Roberto
 
Upvote 0
Top