B4J Question ABMaterial upload files or text

walterf25

Expert
Licensed User
Longtime User
Hello all, i started building a server application using the ABMaterial library, so far everything is working as expected, i have been able to upload the project and run it from a VPS, everything is running great.

My question is, i followed this tutorial by @Erel where he shows how to upload a file or text https://www.b4x.com/android/forum/t...r-b4j-server-over-the-internet.37201/#content.

I would like to do the same thing in my application but i am using ABMaterial's template, how would I go about adding a handler which can receive the post call from another device, i tried the following
B4X:
srvr.AddHandler("/upload", "Upload", False)
In the Main module and have added a server handler class to the project named Upload, but when I try submitting a post method from another device i receive a
ResponseError: unknown error, status code: 404.

Is there anything i am missing, may be something simeple and obvious but i can't think of it.

Thanks everyone in advance.

Walter
 

alwaysbusy

Expert
Licensed User
Longtime User
Maybe you will have to add the appname as another filter automoatically redirects it to there?

B4X:
srvr.AddHandler("/" & ABMShared.AppName & "/upload", "upload", false)

put a log in ABMCacheControl and trace it in debug mode to see what happens. A 404 means file not found, but a handler should not care about that.

B4X:
Dim reqRequestURI As String = req.RequestURI
log(reqRequestURI) ' <----
 
Upvote 0

walterf25

Expert
Licensed User
Longtime User
Maybe you will have to add the appname as another filter automoatically redirects it to there?

B4X:
srvr.AddHandler("/" & ABMShared.AppName & "/upload", "upload", false)

put a log in ABMCacheControl and trace it in debug mode to see what happens. A 404 means file not found, but a handler should not care about that.

B4X:
Dim reqRequestURI As String = req.RequestURI
log(reqRequestURI) ' <----
I did what you suggested, but it still doesn't seem to work, any other suggestions, this is what the Main module looks like
B4X:
Sub AppStart (Args() As String)
    ' the user needs to login
    ''ABMShared.NeedsAuthorization = True
    '''SELECT rowid, count(*), strftime('%Y', Players_Year_Born) as valYear FROM members GROUP BY valYear
    ' Build the Theme
    ABMShared.BuildTheme("mytheme")   
    
    ' create the app
    Dim myApp As ABMApplication
    myApp.Initialize
        
    ' create the pages
    Dim myPage As ABMPageTemplate
    myPage.Initialize       
    
    Dim mypage2 As Members
    mypage2.Initialize
    
    Dim mypage3 As Location
    mypage3.Initialize
    
    Dim mypage4 As Upload
    mypage4.Initialize
    
        
    ' add the pages to the app
    myApp.AddPage(myPage.page)
    myApp.AddPage(mypage2.page)
    myApp.AddPage(mypage3.page)
    ''myApp.AddPage(mypage4.page)
    ''srvr.Initialize("srv")

    
    ' start the server
    srvr.Initialize("srvr")
    myApp.StartServer(srvr, "srvr", port)   
    srvr.AddBackgroundWorker("FetchData")
    Log("handler: " & ABMShared.AppName & "/upload")
    srvr.AddHandler(ABMShared.AppName & "/upload", "Upload", False)
    '''srvr.Start
            
    'ABMShared.RedirectOutput(File.DirApp, "logs.txt")
    
    #If DEBUG
        ' in debug mode, start the browser and open the app on all devices (DOES NOT WORK IF EDGE IS YOUR DEFAULT BROWSER!)
        ABM.ViewerOpenAllDevices("http://localhost:" & port & "/" & ABMShared.AppName & "/", 100)
        
        ' or open a specific device as default (DOES NOT WORK IF EDGE IS YOUR DEFAULT BROWSER!)
        'ABM.ViewerOpenDevice("http://localhost:" & port & "/" & ABMShared.AppName & "/", 300, ABM.VIEWER_TABLET)
        
        ' or just open de browser, no multiple devices
        'ABM.ViewerOpen("http://localhost:" & port & "/" & ABMShared.AppName & "/")
    #End If
            
    StartMessageLoop
End Sub

and my code in the Upload Handler module looks like this:
B4X:
Sub Class_Globals

End Sub

Public Sub Initialize
    
End Sub

Sub Handle(req As ServletRequest, resp As ServletResponse)
    Log("req type: " & req.GetParameter("type"))
    If req.Method <> "POST" Then
        resp.SendError(404, "method not supported.")
        Return
    End If
    'we need to call req.InputStream before calling GetParameter.
    'Otherwise the stream will be read internally (as the parameter might be in the post body).
    Dim In As InputStream = req.InputStream
    Dim reqType As String = req.GetParameter("type")
    If reqType = "" Then
        resp.SendError(404, "Missing type parameter.")
        Return
    End If
    Select reqType
        Case "text"
            Dim tr As TextReader
            tr.Initialize(In)
            Log("Received text message: " & CRLF & tr.ReadAll)
            resp.Write("Message received successfully.")
        Case "file"
''            Dim name As String = req.GetParameter("name")
''            Dim out As OutputStream = File.OpenOutput(Main.filesFolder, name, False)
''            File.Copy2(In, out)
''            out.Close
''            Log("Received file: " & name & ", size=" & File.Size(Main.filesFolder, name))
''            resp.Write("File received successfully.")
    End Select
End Sub

Thanks for your help, hope i can get this figured out.

Walter
 
Upvote 0

walterf25

Expert
Licensed User
Longtime User
this should definitely be done before startserver (best is to place it in startserver, and must be before srvr.start):

B4X:
srvr.AddBackgroundWorker("FetchData")
Log("handler: " & ABMShared.AppName & "/upload")
srvr.AddHandler(ABMShared.AppName & "/upload", "Upload", False)
I just moved this code before startserver, but it made no difference.

I i open my browser and go to the ip address like this:
then i receive a forbidden requires authentication message, but If I try to do a post method from my android device then I get a timed out exception.

Any other ideas.
Walter
 
Upvote 0

walterf25

Expert
Licensed User
Longtime User
still, it must before srvr.start, otherwise the server will not even know it has this handler. Try it now without the appname in your addHandler as it seems you have now another error message: forbidden requires authentication
I'm not calling srvr.start as it gives me an error when I do that.
I've tried it both ways with and without the appname in the addHandler.

I'm only using myapp.startserver(srvr, "srvr", port)

If I user srvr.start then i get the following error:
Analysing data from B4J source files... (2/2)
Loading icons for FileManager
loading C:\Users\eelab\DOCUME~1\TEMPLA~1.3\Objects: copymewithjar.needs...
Using cache system: 3.0
Needs material/awesome icons
2018-10-05 10:16:19.180:INFO::main: Logging initialized @1398ms to org.eclipse.jetty.util.log.StdErrLog
handler: template/upload
Building C:\Users\eelab\DOCUME~1\TEMPLA~1.3\Objects\copymewithjar.js.needs
Building core.min.1538759778346.css...
2018-10-05 10:16:19.318:INFO:eek:ejs.Server:main: jetty-9.4.z-SNAPSHOT; built: 2018-05-03T15:56:21.710Z; git: daa59876e6f384329b122929e70a80934569428c; jvm 1.8.0_171-b11
2018-10-05 10:16:19.363:INFO:eek:ejs.session:main: DefaultSessionIdManager workerName=node0
2018-10-05 10:16:19.363:INFO:eek:ejs.session:main: No SessionScavenger set, using defaults
2018-10-05 10:16:19.365:INFO:eek:ejs.session:main: node0 Scavenging every 660000ms
2018-10-05 10:16:19.392:INFO:eek:ejsh.ContextHandler:main: Started o.e.j.s.ServletContextHandler@4e718207{/,file:///C:/Users/eelab/Documents/Template_v1.3/Objects/www/,AVAILABLE}
2018-10-05 10:16:19.394:INFO:eek:ejs.AbstractNCSARequestLog:main: Opened C:\Users\eelab\Documents\Template_v1.3\Objects\logs\b4j-2018_10_05.request.log
2018-10-05 10:16:19.487:INFO:eek:ejs.AbstractConnector:main: Started ServerConnector@10a035a0{HTTP/1.1,[http/1.1]}{0.0.0.0:51044}
2018-10-05 10:16:19.487:INFO:eek:ejs.Server:main: Started @1706ms
Emulated network latency: 100ms
2018-10-05 10:16:19.497:INFO:eek:ejs.AbstractConnector:main: Stopped ServerConnector@10a035a0{HTTP/1.1,[http/1.1]}{0.0.0.0:51044}
2018-10-05 10:16:19.497:INFO:eek:ejs.session:main: node0 Stopped scavenging
2018-10-05 10:16:19.499:INFO:eek:ejsh.ContextHandler:main: Stopped o.e.j.s.ServletContextHandler@4e718207{/,file:///C:/Users/eelab/Documents/Template_v1.3/Objects/www/,UNAVAILABLE}
2018-10-05 10:16:19.528:INFO:eek:ejs.Server:main: jetty-9.4.z-SNAPSHOT; built: 2018-05-03T15:56:21.710Z; git: daa59876e6f384329b122929e70a80934569428c; jvm 1.8.0_171-b11
2018-10-05 10:16:19.532:INFO:eek:ejsh.ContextHandler:main: Started o.e.j.s.ServletContextHandler@4e718207{/,file:///C:/Users/eelab/Documents/Template_v1.3/Objects/www/,AVAILABLE}
2018-10-05 10:16:19.533:INFO:eek:ejs.AbstractNCSARequestLog:main: Opened C:\Users\eelab\Documents\Template_v1.3\Objects\logs\b4j-2018_10_05.request.log
2018-10-05 10:16:19.533:INFO:eek:ejs.session:main: DefaultSessionIdManager workerName=node0
2018-10-05 10:16:19.533:INFO:eek:ejs.session:main: No SessionScavenger set, using defaults
2018-10-05 10:16:19.533:INFO:eek:ejs.session:main: node0 Scavenging every 600000ms
2018-10-05 10:16:19.537:INFO:eek:ejs.AbstractConnector:main: Started ServerConnector@10a035a0{HTTP/1.1,[http/1.1]}{0.0.0.0:51044}
2018-10-05 10:16:19.537:INFO:eek:ejs.Server:main: Started @1756ms
2018-10-05 10:16:19.538:INFO:eek:ejs.session:main: node0 Scavenging every 990000ms
2018-10-05 10:16:19.541:INFO:eek:ejs.AbstractConnector:main: Stopped ServerConnector@10a035a0{HTTP/1.1,[http/1.1]}{0.0.0.0:51044}
Error occurred on line: 56
java.lang.IllegalStateException: Multiple servlets map to path /upload: anywheresoftware.b4j.object.JServlet-cb5822[mapped:EMBEDDED:null],anywheresoftware.b4j.object.JServlet-1e4a7dd4[mapped:EMBEDDED:null]
at org.eclipse.jetty.servlet.ServletHandler.updateMappings(ServletHandler.java:1433)
at org.eclipse.jetty.servlet.ServletHandler.setServletMappings(ServletHandler.java:1567)
at org.eclipse.jetty.servlet.ServletHandler.addServletWithMapping(ServletHandler.java:907)
at org.eclipse.jetty.servlet.ServletContextHandler.addServlet(ServletContextHandler.java:462)
at anywheresoftware.b4j.object.ServerWrapper.Start(ServerWrapper.java:167)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at anywheresoftware.b4a.shell.Shell.runVoidMethod(Shell.java:672)
at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:240)
at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:168)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:90)
at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:98)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:77)
at com.ab.template.main.main(main.java:29)
Worker ended (class com.ab.template.fetchdata)

Walter
 
Upvote 0

walterf25

Expert
Licensed User
Longtime User
when you run myapp.StartServer(), it already runs it for you so no, don't start it twice. What does it say in ABMCacheControl with the debug?
This is what i get in the ABMCacheControl with the log line I added:
requestURI: /template/ABMPageTemplate/ABMPageTemplate.1538760004447.css
requestURI: /template/core.min.1538760004447.css
requestURI: /template/ABMPageTemplate/index.html
requestURI: /template/ABMPageTemplate/index.html
requestURI: /ws/template/ABMPageTemplate
requestURI: /ws/template/ABMPageTemplate
Connected
Saving the first instance
Websocket first connection

Walter
 
Upvote 0
Top