In previous articles, we have seen that an Ada Server Faces application has a presentation layer composed of XHTML and CSS files. Similar to Java Server Faces, Ada Server Faces is a component-based model and we saw how to write the Ada beans used by the application. Later, we also learnt how an action bean can have a procedure executed when a button is pressed. Now, how can all these stuff fit together?
Well, to finish our cylinder volume example, we will see how to put everything together and get our running web application.
Application Initialization
An Ada Server Faces Application is represented by the Application
type which holds all the information to process and dispatch requests. First, let's declare a variable that represents our application.
Note: for the purpose of this article, we will assume that every variable is declared at some package level scope. If those variables are declared in another scope, the Access
attribute should be replaced by Unchecked_Access
.
with ASF.Applications.Main;
...
App : aliased ASF.Applications.Main.Application;
To initialize the application, we will also need some configuration properties and a factory object. The configuration properties are used to configure the various components used by ASF. The factory allows to customize some behavior of Ada Server Faces. For now, we will use the default factory.
with ASF.Applications;
...
C : ASF.Applications.Config;
Factory : ASF.Applications.Main.Application_Factory;
The initialization requires to define some configuration properties. The VIEW_EXT
property indicates the URI extension that are recognized by ASF to associate an XHTML file (the compute.html
corresponds to the XHTML file compute.xhtml
). The VIEW_DIR
property defines the root directory where the XHTML files are stored.
C.Set (ASF.Applications.VIEW_EXT, ".html");
C.Set (ASF.Applications.VIEW_DIR, "samples/web");
C.Set ("web.dir", "samples/web");
App.Initialize (C, Factory);
Servlets
Ada Server Faces uses the Ada Servlet framework to receive and dispatch web requests. It provides a Faces_Servlet
servlet which can be plugged in the servlet container. This servlet is the entry point for ASF to process incoming requests. We will also need a File_Servlet
to process the static files. Note that these servlets are implemented using tagged records and you can easily override the entry points (Do_Get
or Do_Post
) to implement specific behaviors.
with ASF.Servlets.Faces;
with ASF.Servlets.Files;
...
Faces : aliased ASF.Servlets.Faces.Faces_Servlet;
Files : aliased ASF.Servlets.Files.File_Servlet;
The servlet instances are registered in the application.
App.Add_Servlet (Name => "faces", Server => Faces'Access);
App.Add_Servlet (Name => "files", Server => Files'Access);
Once registered, we have to define a mapping that tells which URI path is mapped to the servlet.
App.Add_Mapping (Name => "faces", Pattern => "*.html");
App.Add_Mapping (Name => "files", Pattern => "*.css");
For the purpose of debugging, ASF provides a servlet filter that can be plugged in the request processing flow. The Dump_Filter
will produce a dump of the request with the headers and parameters.
with ASF.Filters.Dump;
...
Dump : aliased ASF.Filters.Dump.Dump_Filter;
The filter instance is registered as follows:
App.Add_Filter (Name => "dump", Filter => Dump'Access);
And a mapping is defined to tell which URL will trigger the filter.
App.Add_Filter_Mapping (Name => "dump", Pattern => "*.html");
Application and Web Container
The application object that we created is similar to a Java Web Application packaged in a WAR file. It represents the application and it must be deployed in a Web Container. With Ada Server Faces this is almost the same, the application needs a Web container. By default, ASF provides a web container based on the excellent Ada Web Server implementation (other web containers could be provided in the future based on other web servers).
with ASF.Server.Web;
...
WS : ASF.Server.Web.AWS_Container;
To register the application, we indicate the URI context path to which the application is associated. Several applications can be registered, each of them having a unique URI context path.
CONTEXT_PATH : constant String := "/volume";
...
WS.Register_Application (CONTEXT_PATH, App'Access);
Global Objects
An application can provide some global objects which will be available during the request processing through the EL expression. First, we will expose the application context path which allows to write links in the XHTML page that match the URI used for registering the application in the web container.
App.Set_Global ("contextPath", CONTEXT_PATH);
Below is an example of use of this contextPath
variable:
<link media="screen" type="text/css" rel="stylesheet"
href="#{contextPath}/themes/main.css"/>
Now, we will register the bean that we created for our application! This was explained in the Ada beans previous article.
with Volume;
...
Bean : aliased Volume.Compute_Bean;
...
App.Set_Global ("compute", Util.Beans.Objects.To_Object (Bean'Access));
''Note: For the purpose of this example, the Compute_Bean
is registered as a global object. This means that it will be shared by every request. A future article will explain how to get a session or a request bean as in Java Server Faces.''
Starting the server
Once the application is registered, we can start our server. Note that since Ada Web Server starts several threads that listen to requests, the Start
procedure does not block and returns as soon as the server is started. The delay is necessary to let the server wait for requests during some time.
WS.Start;
delay 1000.0;
What happens to a request?
Let's say the server receives a HTTP GET request on /volume/compute.html
. Here is what happens:
- Ada Web Server receives the HTTP request
- It identifies the application that matches
/volume
(our context path) and gives the control to it - The application identifies the servlet that processes the remaining URI, which is
compute.html
- It gives the control to the
Dump_Filter
filter and then to the Faces_Servlet
servlet, - The faces servlet identifies the XHTML facelet file and reads the
compute.xhtml
file - ASF builds the component tree that describes the page and invokes the render response phase
- While rendering, the EL expressions such as
#{compute.radius}
are evaluated and the value is obtained on our Bean
global instance. - The HTML content is produced as part of the rendering process and returned by AWS.
References
asf_volume_server.adb
volume.ads
volume.adb
compute.xhtml