B4J Tutorial [Server] Building web servers with B4J

Status
Not open for further replies.
Edit: Web Apps tutorial: http://www.b4x.com/android/forum/threads/webapp-web-apps-overview.39811/

The server implementation is based on a popular and powerful Java server library named Jetty (license)
The database connection pooling implementation is based on c3p0 (license).


B4J Server features:
  • High performance web server
  • Automatic handling of static files
  • Simple to develop custom "handlers"
  • Support for GET, POST, DELETE and PUT requests
  • Support for multipart requests (file uploads)
  • Standard logging
  • Each handler can either be multi-threaded or single-threaded
  • Simple and powerful database connections pooling
  • Server can run on Windows, Mac and Linux (including board computers such as Raspberry Pi)

Possible usages
  • Internal or external web sites
  • Backend solutions (with or without UI) that can optionally connect to any type of database


If you never worked with web servers then it is recommended to start with a HTTP tutorial such as this one: http://net.tutsplus.com/tutorials/t...rotocol-every-web-developer-must-know-part-1/

I also recommend you to use a proper browser with debugging plugin such as FireFox + FireBug. The ability to inspect the requests and responses is very useful.

How it works

A server program is a non-UI program.
In the Main module you should create a Server object, configure it, start it and call StartMessageLoop:
B4X:
Sub Process_Globals
   Private srvr As Server
End Sub

Sub AppStart (Args() As String)
   srvr.Initialize("srvr")
   srvr.Port = 8888
   srvr.StaticFilesFolder = File.Combine(File.DirApp, "www")
   srvr.AddHandler("/hello", "HelloPage", False)
   srvr.AddHandler("/FormExampleHelper", "FormExampleHelper", False)
   srvr.AddHandler("/FileUpload", "FileUpload", False)
   srvr.Start
   StartMessageLoop
End Sub

As you can see in the above code, the port is set to 8888.
StaticFilesFolder sets the folder (and subfolders) that will be used to serve static files. Any file that is not generated by your code is a static file (html, js, css, images, etc.).
Files outside of this folder cannot be accessed. This is important for security reasons.
Note that if the url points to a folder then the index.html file in that folder will be served (if it exists).

Handlers

A handler is a B4J class that is mapped to a URL. A handler class is responsible for getting the request and providing the response.

Each request is handled by a new instance of the handler class. A handler class should have an empty Initialize and a Handle sub with the following signature:
B4X:
Sub Handle(req As ServletRequest, resp As ServletResponse)

You should read the data from the ServletRequest and write the response to the ServletResponse.

For example:
B4X:
Sub Handle(req As ServletRequest, resp As ServletResponse)
resp.Write("Hello World!")
End Sub

The attached example includes three handlers:
HelloPage - A simple handler that creates the following page:

SS-2014-01-27_16.49.30.png

Note that this page was served from a Raspberry Pi board :)

FormExampleHelper - This handler receives a submitted form and prints the form's fields. It is used by two html pages. A simple form page and a page that uses Ajax (with JQuery) to send the form.

FileUpload - This handler receives a multipart form with a file and other fields. It logs the fields and the file size.

Threading

When you add a handler you need to specify whether you want it to be a single threaded handler or a multithreaded handler. By default you should use multithreaded handlers (third parameter should be false).

A multithreaded handler means that your handler code will be run by a thread from the server threads pool. Multiple instances of the same handler and other handlers can be executed in the same time. As long as you don't access any global variable out of the current handler instance you should be safe.

A single threaded handler will always be executed by the main thread. This means that if there are multiple requests they will be queued and executed one by one. Single threaded handlers can be useful in many cases. Some examples:
- A handler that accesses a SQLite database, which is less suitable for concurrent connections. See this tutorial for concurrent access to SQLite: https://www.b4x.com/android/forum/t...ent-access-to-sqlite-databases.39904/#content
- A handler that writes to a specific file.
- A handler that sends a job to the printer

Note that when you run your code in Debug mode the handlers will always run in the main thread.

Datebase Connections Pooling

Many web servers are based on databases. Databases, such as MySQL and others, can properly handle concurrent queries and transactions. The ConnectionPool object handles a pool of database connections. You can then get a connection (SQL object) from the pool, work with it and close it, which will actually return it to the pool.

The pool is responsible for maintaining the connections.
An alternative for a connections pool is a process global SQL variable. However for it to work properly all the handlers should be single threaded handlers.

As explained in the SQL tutorial you should use #AdditionalJar attribute to add a reference to the JDBC jar. You should then make a public process global pool variable and use it from the handler.


To try this example, run it from B4J and point the browser to 127.0.0.1:8888
This will load the index.html file that is available in the www folder.

Examples & Tutorials:

Online examples: https://www.b4x.com:51041
Other server tutorials: http://www.b4x.com/android/forum/pages/results/?query=[server]&page=1&prefix=0
 

Attachments

  • ServerHelloWorld.zip
    79.8 KB · Views: 6,396
Last edited:

AscySoft

Active Member
Licensed User
Longtime User
Last edited:

AscySoft

Active Member
Licensed User
Longtime User
As I mentioned in post #44 I was able to create an exe from jar file. It works OK like this. However using apache.common.procrun tool, (see link #45 in this post) I was able to install a working windows service that point to my jar server app, without converting this to an exe. Read carefully the syntax on that page for more info.

The only thing that is not working to well is the "stop" service command. So I must ask Erel (when he have time of course) to modify the main java class generated by build command to include a StopClass signature as in procrun documentation, if it's possible. Erel please see this:<<--StopMethod -default Main -Name of method to be called when service is stopped. It must be static void and have argument (String args[]). Only applies to jvm mode.>>

I was able to bypass this by setting a 10 sec timeout on stop command, but this is taking >1 minute to stop, generating errors (see stderr logs if you want).

If somebody wants to install a service this way, I can provide full working batch cmd script.
 

sulsys

Member
Licensed User
Longtime User
This works really well. Things I found.
- If I run the batch file from the jre7\bin directory it works. If I run from another directory pointing back to bin\java.exe I receive a java error.

- I would like to control the output file path. Is is relative to where the java.exe is located? Can the path be very specific? Such as "D:\uploads"
 

avacondios

Active Member
Licensed User
Longtime User
hi again, does it supports any type for user authentication ?
Sure. All the non-WebSockets examples here are rest api servers: http://basic4ppc.com:51042/

Thanks Erel, how about the webclient authentication, before to access a Restful API server, written on B4J ? Do we have any example ? The scenario is the following : User to call the GetAuthentication API function and the B4J, to return a unique token, so to evaluate for the next restful API calls ( example, GetCustomers)

BR/Antonis
 

aaronk

Well-Known Member
Licensed User
Longtime User
I understand that the code/example in post 1 doesn't work with PHP scripts but is there a way to allow PHP scripts ?
 

aaronk

Well-Known Member
Licensed User
Longtime User
Not sure that I understand your question. B4J servers cannot run PHP scripts.
I think you answered my question. I was hoping to use PHP with this but looks like it can't be done.

Is there a way to replace text on the page before it gets sent to the user in the browser?
For example, if I have a page with the following HTML code, how would you replace $test$ with something else before it gets sent to the browser?

Within the B4J app make it so that the app replaces $test$ with 'hello' before it sends it to the browser

HTML:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
</head>
<body>
    <h1>This is a static page</h1>
    <h1>$test$</h1>
    <a href='/'>Back</a>
</body>
 

rwblinn

Well-Known Member
Licensed User
Longtime User
Hi,

have a look at the HelloWorld example in the post here.

The WebApp is what you are looking for. The principle is that you need to define a selector in the HTML code (as DIV) and then replace during Websocket connection.

HTML
B4X:
...
<div id="lblhelloworld"></div>
...

B4J
B4X:
Sub Class_Globals
    Private ws As WebSocket
    Private lblhelloworld As JQueryElement    'Label showing Hello World
End Sub

B4X:
Private Sub WebSocket_Connected (WebSocket1 As WebSocket)
    ws = WebSocket1
    lblhelloworld.setHtml("<H3>Hello World</H3><P>" & DateTime.Date(DateTime.Now) & "&nbsp;" & DateTime.Time(DateTime.Now))
End Sub
 
  • Like
Reactions: ZJP

vfafou

Well-Known Member
Licensed User
Longtime User
Hello!
Is it possible to upgrade c3p0 library to 0.9.5 version?
I have the problem of slow test queries with MySQL.
Thank you in advance!
 
Status
Not open for further replies.
Top