B4J Library jServer v4.0 - Based on Jetty 11

Starting from B4J v9.80 this library is included as an internal library. Old library: https://www.b4x.com/android/forum/threads/141323/#content
This is a new version of jServer. It is based on Jetty 11.0.9. Previous versions were based on an early version of Jetty 9.
There were many improvements in Jetty during the last couple of years: https://github.com/eclipse/jetty.project/releases

It requires Java 11+.
It works with the standalone packager with these declarations:
B4X:
#PackagerProperty: AdditionalModuleInfoString = provides org.slf4j.spi.SLF4JServiceProvider with org.eclipse.jetty.logging.JettyLoggingServiceProvider;
#PackagerProperty: AdditionalModuleInfoString = provides org.eclipse.jetty.io.ssl.ALPNProcessor.Server with org.eclipse.jetty.alpn.java.server.JDK9ServerALPNProcessor;
#PackagerProperty: AdditionalModuleInfoString = provides org.eclipse.jetty.http.HttpFieldPreEncoder with org.eclipse.jetty.http2.hpack.HpackFieldPreEncoder, org.eclipse.jetty.http.Http1FieldPreEncoder;
#PackagerProperty: AdditionalModuleInfoString = uses org.eclipse.jetty.util.security.CredentialProvider;
#PackagerProperty: AdditionalModuleInfoString = uses org.eclipse.jetty.io.ssl.ALPNProcessor.Server;
#PackagerProperty: IncludedModules = jdk.charsets, jdk.crypto.ec
#CustomBuildAction: After Packager, %WINDIR%\System32\robocopy.exe, www temp\build\bin\www /E

Note that http sessions are not created automatically for WebSockets. You can use this filter handler to create it: https://www.b4x.com/android/forum/threads/safari-session-variables-in-b4j-v4.61652/post-389898 (apparently it relied on a feature not supported by WebSocket specs).

b4j_ws.js v0.93 is attached. It includes a fix suggested by @alwaysbusy: https://www.b4x.com/android/forum/threads/jserver-v4-0-based-on-jetty-11.140437/post-889892
 

Attachments

  • b4j_ws.zip
    1.3 KB · Views: 976
Last edited:

alwaysbusy

Expert
Licensed User
Longtime User
If I understand correctly, the WebSocket specs
You are correct, that is also what I understand from it. Note that this is probably ABM only as it does some extensive caching to allow connection disruptions where the server caches a Java shadow in case of a re-connection (may be up to an hour later and the user will never notice anything happened). For this cache, the filter solution did work in all cases, except on iOS Safari, where it did not restore the saved state, but always created a new one. It has an effect our users love that is very close to a native app experience, even if they do not have a stable internet connection all the time.

This cache is a spec my boss came up with that probably isn't implemented anywhere else, so jServer itself does exactly what it needs to do. No need for you to look further into this. If it would cause problems, it is something I have to look at in ABM on how to resolve it. But at least I can rule out it has anything to do with the new jetty version ;)
 

ilan

Expert
Licensed User
Longtime User
hi, i dont know if this is the right thread to ask the question but after updating jserver when I run my project and open the browser and inspect it i get an error:

Uncaught SyntaxError: JSON.parse: unexpected character at line 1 column 2 of the JSON data
onmessage https://localhost/b4j_ws.js:64
b4j_ws.js:64:23
onmessage https://localhost/b4j_ws.js:64

do we need to update something on the b4j_ws file?

thanx

EDIT:

I also get those errors:

Error: p(...) is null undefined

Uncaught SyntaxError: JSON.parse: unexpected character at line 1 column 2 of the JSON data
onmessage https://127.0.0.1/b4j_ws.js:64
b4j_connect https://127.0.0.1/b4j_ws.js:63
<anonymous> https://127.0.0.1/login/index.html:97
jQuery 13
b4j_ws.js:64:23
onmessage https://127.0.0.1/b4j_ws.js:64
(Async: EventHandlerNonNull)
b4j_connect https://127.0.0.1/b4j_ws.js:63
<anonymous> https://127.0.0.1/login/index.html:97
jQuery 13
 
Last edited:

alwaysbusy

Expert
Licensed User
Longtime User
I just had a similar problem in my ABM ws file and it seems it needs some extra code because jetty somtimes sends empty Blobs you have to catch before it tries to parse it as Json.

This is the NEW code I've put in mine to resolve this:

1652285439160.png


Alwaysbusy
 
Last edited:

ilan

Expert
Licensed User
Longtime User
I just had a similar problem in my ABM ws file and it seems it needs some extra code because jetty somtimes sends empty Blobs you have to catch before it tries to parse it as Json.

This is the NEW code I've put in mine to resolve this:

View attachment 129143

Alwaysbusy
thank you very much @alwaysbusy this solved all errors :)
 

tchart

Well-Known Member
Licensed User
Longtime User
The previous version will be available for download. You can rename it to jServer3.xml/jar and keep both of them.
So just to confirm, jServer V4 will be the deafult internal library in a future update?
 

Erel

B4X founder
Staff member
Licensed User
Longtime User

Jmu5667

Well-Known Member
Licensed User
Longtime User
Would it be possible to have jServer3 and JServer4 as part of the internal libs going forward in B4J ?
 

prajinpraveen

Active Member
Licensed User
Longtime User
Not sure if i have to create separate threads for these. These are working well on Jserver 3


1. Does not initialize the map
block1:
ConnectedBrowsers = srvr.CreateThreadSafeMap    ' Start a thread safe map of all the connected browsers

2. java.lang.RuntimeException: Method: setPreferProxiedForAddress not found in: org.eclipse.jetty.server.CustomRequestLog
block:
    For Each h As JavaObject In GetHandlers(srvr)
        If GetType(h) = "org.eclipse.jetty.server.handler.RequestLogHandler" Then
            'TO log a actual IP address behind the proxy
            Dim requestLog As JavaObject = h.RunMethod("getRequestLog", Null)
            requestLog.RunMethod("setPreferProxiedForAddress", Array(True))                               
        End If
    Next

3. java.lang.RuntimeException: Object should first be initialized (JavaObject).

block1:
   Dim SessionManager As JavaObject  ' in process globals
    Dim jo As JavaObject = srvr
    SessionManager  = jo.GetFieldJO("context").RunMethodJO("getSessionHandler", Null).RunMethodJO("getSessionIdManager", Null)
    SessionManager.RunMethod("invalidateAll", Array(sessionid))   '>> Error


4.
block2:
        '    Possible log levels are  TRACE, DEBUG, INFO, WARN and ERROR
        inline.RunMethod("setLevel", Array("INFO"))  ' >> ERROR
Sub inline As JavaObject
    Return Me
End Sub


#IF JAVA
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;

public static void setLevel(String LogLevel){
    Logger root = (Logger)LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
    root.setLevel(Level.toLevel(LogLevel));
    }
#End If

' LOG

setting log level INFO
Error occurred on line: 113 (Main)
java.lang.reflect.InvocationTargetException
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at anywheresoftware.b4j.object.JavaObject.RunMethod(JavaObject.java:132)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at anywheresoftware.b4a.shell.Shell.runVoidMethod(Shell.java:673)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:240)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:167)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:109)
    at anywheresoftware.b4a.shell.ShellBA.raiseEvent2(ShellBA.java:98)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:96)
    at zms.main.main(main.java:32)
Caused by: java.lang.ClassCastException: class org.eclipse.jetty.logging.JettyLogger cannot be cast to class ch.qos.logback.classic.Logger (org.eclipse.jetty.logging.JettyLogger and ch.qos.logback.classic.Logger are in unnamed module of loader 'app')
    at zms.main.setLevel(main.java:1101)
    ... 20 more

I couldnt test further
 
Last edited:

MichalK73

Well-Known Member
Licensed User
Longtime User
I just had a similar problem in my ABM ws file and it seems it needs some extra code because jetty somtimes sends empty Blobs you have to catch before it tries to parse it as Json.

This is the NEW code I've put in mine to resolve this:

View attachment 129143

Alwaysbusy
Hey.
When can we expect a new version or fix for ABMaterial with jetty 4.0 ?
 

OliverA

Expert
Licensed User
Longtime User
Top