Java 2 Ada

Ada Server Faces Application Example part 2: the Ada beans

By Stephane Carrez

The first article explained how to design the presentation page of an Ada Server Faces application. This article presents the Ada beans that are behind the presentation page.

Ada Bean and presentation layer

We have seen that the presentation page contains components that make references to Ada beans with an EL expression.

<h:inputText id='height' size='10' value='#{compute.height}'>
        <f:converter converterId="float" />
</h:inputText>

The #{compute.height} is an EL expression that refers to the height property of the Ada bean identified as compute.

Writing the Cylinder Ada Bean

The Ada bean is a instance of an Ada tagged record that must implement a getter and a setter operation. These operations are invoked through an EL expression. Basically the getter is called when the view is rendered and the setter is called when the form is submitted and validated. The Bean interface defines the two operations that must be implemented by the Ada type:

with Util.Beans.Basic;
with Util.Beans.Objects;
...
   type Compute_Bean is new Util.Beans.Basic.Bean with record
      Height : My_Float := -1.0;
      Radius : My_Float := -1.0;
   end record;

   --  Get the value identified by the name.
   overriding
   function Get_Value (From : Compute_Bean;
                       Name : String) return Util.Beans.Objects.Object;

   --  Set the value identified by the name.
   overriding
   procedure Set_Value (From  : in out Compute_Bean;
                        Name  : in String;
                        Value : in Util.Beans.Objects.Object);

The getter and setter will identify the property to get or set through a name. The value is represented by an Object type that can hold several data types (boolean, integer, floats, strings, dates, ...). The getter looks for the name and returns the corresponding value in an Object record. Several To_Object functions helps in creating the result value.

   function Get_Value (From : Compute_Bean;
                       Name : String) return Util.Beans.Objects.Object is
   begin
      if Name = "radius" and From.Radius >= 0.0 then
         return Util.Beans.Objects.To_Object (Float (From.Radius));

      elsif Name = "height" and From.Height >= 0.0 then
         return Util.Beans.Objects.To_Object (Float (From.Height));

      else
         return Util.Beans.Objects.Null_Object;
      end if;
   end Get_Value;

The setter is similar.

   procedure Set_Value (From  : in out Compute_Bean;
                        Name  : in String;
                        Value : in Util.Beans.Objects.Object) is
   begin
      if Name = "radius" then
         From.Radius := My_Float (Util.Beans.Objects.To_Float (Value));
      elsif Name = "height" then
         From.Height := My_Float (Util.Beans.Objects.To_Float (Value));
      end if;
   end Set_Value;

Register the Cylinder Ada Bean

The next step is to register the cylinder bean and associate it with the compute name. There are several ways to do that but for the purpose of this example, there will be a global instance of the bean. That instance must be aliased so that we can use the Access attributes.

 Bean  : aliased Compute_Bean;

The Ada bean is registered on the application object by using the Set_Global procedure. This creates a global binding between a name and an Object record. In our case, the object will hold a reference to the Ada bean.

App : aliased ASF.Applications.Main.Application;
...
   App.Set_Global ("compute", Util.Beans.Objects.To_Object (Bean'Unchecked_Access));

Next Time...

We have seen how the presentation layer and the Ada beans are associated. The next article will present the action binding that links the form submission action to an Ada bean method.

To add a comment, you must be connected. Login to add a comment

Ada Server Faces Application Example part 1: the presentation

By Stephane Carrez 1 comment

Ada Server Faces is a framework which allows to write and build web applications. This article presents through a simple example how to use ASF to write a simple web application.

ASF Overview

Ada Server Faces uses a model which is very close to Java Server Faces. JSF and ASF use a component-based model for the design and implementation of a web application. Like traditional MVC models, the presentation layer is separated from the control and model parts. Unlike the MVC model, JSF and ASF are not request-based meaning there is not a specific controller associated with the request. Instead, each component that is part of the page (view) participate in the control and each component brings a piece of the model.

This first article will focus on the presentation layer through a simple example.

Cylinder Volume Example

The example computes the volume of a cylinder. A simple form with two input fields allows to enter the cylinder dimensions (the unit does not matter).

Volume form

ASF Templating

The presentation part is implemented by a facelet file and a CSS file. The facelet file is an XML file which contains XHTML elements as well as facelets and JSF/ASF components. The facelets and ASF components are specified in their own XML namespace. The ASF components form a tree of components (UIComponent) which is then used for displaying and processing form submissions.

At the root of the XML file is an f:view component which represents the root of the component tree. The typical page layout looks as follows. Note the #{contextPath} notation in the link reference. This is an EL expression that will be evaluated when the view is displayed (rendered in JSF terminology).

<f:view contentType="text/html"
        xmlns:ui="http://java.sun.com/jsf/facelets"
        xmlns:f="http://java.sun.com/jsf/core"
        xmlns:c="http://java.sun.com/jstl/core"
	xmlns:u="http://code.google.com/p/ada-asf/util"
        xmlns:h="http://java.sun.com/jsf/html">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <link media="screen" type="text/css" rel="stylesheet"
      href="#{contextPath}/themes/main.css"/>
    <title>Volume Cylinder</title>
</head>
<body>
  <div>
     <h1>Compute the volume of a cylinder</h1>
     ...
  </div>
</body>
</html>
</f:view>

The form, input fields and submit buttons have to be specified using a JSF/ASF component. The JSF/ASF component will make the link between the presentation (view) and the controller (beans). The h:form is the JSF/ASF component that represents our form. Note that there is no need to specify any form action attribute: the form action will be managed by JSF/ASF.

The input fields are identified by the h:input components. The input field is linked to the bean through the value EL expression. This expression specifies the bean name and attribute. When rendering the view, JSF/ASF will fetch the value from the named bean. On form submission, JSF/ASF will populate the bean with the submitted value.

The h:input component can contain a f:converter element which indicates a conversion operation to call when displaying or before populating the bean value.

<h:form id='compute'>
  <dl>
    <dt>Height</dt>
    <dd>
      <h:inputText id='height' size='10' value='#{compute.height}'>
        <f:converter converterId="float" />
      </h:inputText>
    </dd>
    <dt>Radius</dt>
    <dd>
        <h:inputText id='radius' size='10' value='#{compute.radius}'>
           <f:converter converterId="float"/>
        </h:inputText>
    </dd>
    <dt></dt>
    <dd>
        <h:commandButton id='run' value='Compute'
       action="#{compute.run}"/>
    </dd>
  </dl>
</h:form>

At the form end, the h:commandButton represents the submit button and the controller action to invoke on form submission. The method to invoke is defined with an EL method expression in the action attribute. Before invoking the method, JSF/ASF will verify the submitted values, convert them according to associated converters, populate the beans with the values.

Style

The page style is provided by a specific CSS file. The dl/dt/dd list is rendered as a table using the following CSS definitions. By changing the CSS file, a new presentation can be provided to users.

dl {
  float: left;
  width: 500px;
  border: 1px solid #bcd;
  background-color: #ffffff;
  padding: 10px;
  -moz-border-radius: 6px;
  -webkit-border-radius: 6px 6px;
}
dt {
  clear: left;
  float: left;
  font-weight: bold;
  width: 20%;
  height: 20px;
  line-height: 24px;
  padding: 5px;
}
dd {
  float: left;
  padding: 5px;
}

Next time...

In this article, I've shown how to write the presentation and style part of an Ada Server Faces application. The next article will present the Ada beans that are associated with this example.

1 comment
To add a comment, you must be connected. Login to add a comment

Integrating the project subversion revision in an Ada application log

By Stephane Carrez

In software development it is often necessary to know the revision number that was used to build an application or a library. This is specially useful when a problem occurred to get and look at the good sources. Integrating this information automatically in the build process is a common practice. This article explains how an Ada application can report the subversion repository and revision in an application log.

Subversion keyword substitution

Subversion provides a substitution feature which allows to replace some pre-defined keywords by the file revision, the last modified date or the last author. In an Ada source, we could declare the following string variables:


package Version is
   Revision : constant String := "$Rev$";
   Head_URL : constant String := "$HeadURL$";
end Version;

To activate the keyword substitution you have to set some subversion property on the file:

$ svn propset svn:keywords "Revision HeadURL" version.ads

Each time the file is committed, the keywords will be replaced to integrate the new value. The expanded string will look like:

$Rev: 318 $
$HeadURL: https://ada-util.googlecode.com/svn/trunk $

The issue with subversion keyword substitution is that the information reported only concerns the file changed not the revision of the project (as returned by svnversion for example). In other words, it is necessary to change the version.ads file to get an updated revision number.

Keyword substitution with gnatprep

The gnatprep tool is a pre-processor provided by the GNAT Ada compiler. It reads an input file, evaluates some conditions and expressions (similar to cpp but slightly different) and produces an output file with substituted values. The file to pre-process is an Ada file that will have the .gpb extension to differentiate it from regular Ada files. For our concern we will use gnatprep to substitute some variables, a String and a number. The declaration could be the following:


package Version is
   Head_URL : constant String := $URL;
   Revision : constant Positive := $REVISION;
end Version;

To produce the expanded .ads file, we will invoke gnatprep and give it the URL and REVISION variables. The manual command would look like:

$ gnatprep -DREVISION=23 -DURL="https://..." \
    src/version.gpb src/version.ads

Running such command by hand can be cumbersome. It is easy to use a Makefile with a make target that will do the full job of extracting the latest revision and invoke gnatprep. The make target is the following (make sure to have a tab as first character in the gnatprep command):

version:
        gnatprep `svn info | grep '^[UR][eR][Lv]' | sed -e 's,URL: \(.*\),-DURL="\1",' -e 's,Revision: ,-DREVISION=,'` \
                  src/version.gpb src/version.ads

This make target could be run manually or be integrated as part of the build process so that it is executed each time a release build is performed.

Writing the log

The easy part is to report the application revision number either in a log or on the standard output.


with Ada.Text_IO;
...
   Ada.Text_IO.Put_Line ("Revision " & Positive'Image (Revision));

References

Subversion Keyword Substitution

Preprocessing Using gnatprep

To add a comment, you must be connected. Login to add a comment

How to fix GNAT symbolic traceback crash on Ubuntu

By Stephane Carrez

When you use the GNAT symbolic traceback feature with gcc 4.4 on Ubuntu 10.04, a segmentation fault occurs. This article explains why and proposes a workaround until the problem is fixed in the distribution.

Symbolic Traceback

The GNU Ada Compiler provides a support package to dump the exception traceback with symbols.


with Ada.Exceptions;
  use Ada.Exceptions;
with GNAT.Traceback.Symbolic;
  use GNAT.Traceback.Symbolic;
with Ada.Text_IO; use Ada.Text_IO;
...
exception
  when E : others =>
    Put_Line ("Exception: " & Exception_Name (E));
    Put_Line (Symbolic_Traceback (E));

GNAT Symbolic Traceback crash

On Ubuntu 10.04 and probably on other Debian distributions, the symbolic traceback crashes in convert_addresses:


Program received signal SIGSEGV, Segmentation fault.
0xb7ab20a6 in convert_addresses () from /usr/lib/libgnat-4.4.so.1
(gdb) where
#0  0xb7ab20a6 in convert_addresses () from /usr/lib/libgnat-4.4.so.1
#1  0xb7ab1f2c in gnat__traceback__symbolic__symbolic_traceback () from /usr/lib/libgnat-4.4.so.1
#2  0xb7ab2054 in gnat__traceback__symbolic__symbolic_traceback__2 () from /usr/lib/libgnat-4.4.so.1

The problem is caused by a patch that was applied on GCC 4.4 sources and which introduces a bug in convert_addresses function. Basically, the function is missing a filename argument which causes other arguments to be incorrect.


void convert_addresses (const char* filename,
         void* addrs[], int n_addr,
         char* buf, int*  len)

Since convert_addresses is provided by the libgnat-4.4.so dynamic library, we can easily replace this function by linking our program with the correct implementation. Get the convert_addresses.c, compile it and add it when you link your program:

$ gcc -c convert_addresses.c
$ gnatmake -Pproject -largs convert_addresses.o
To add a comment, you must be connected. Login to add a comment

Ada Servlet Example

By Stephane Carrez 1 comment

To write a web application, Java developers can use the servlet API. The servlet technology, created around 1997, is a simple and powerful framework on top of which many web applications and higher web frameworks have been created. This article shows how to write the same kind of web application in Ada.

Ada Servlet Framework

The Ada Servlet framework is provided by Ada Server Faces. It is an adaptation and implementation of the JSR 315 (Java Servlet Specification) for the Ada 05 language. The Ada API is very close to the Java API as it provides the Servlet, Filter, Request, Response and Session types with quite the same methods. It should be quite easy for someone who is familiar with Java servlets to write an Ada servlet.

The Ada Servlet implementation uses the Ada Web Server as a web server. In the future other other web servers such as Apache or Lighthttpd could be used.

Servlet Declaration

The servlet API is represented by the Servlet tagged type which represents the root of all servlets. A servlet must extend this Servlet tagged type and it can override one of the Do_Get, Do_Post, Do_Head Do_Delete, Do_Put, Do_Options or Do_Trace procedure. Each Do_XXX procedure receives a request object and a response object.


with ASF.Servlets;
with ASF.Requests;
with ASF.Responses;

package Volume_Servlet is
   use ASF;
   type Servlet is new Servlets.Servlet with null record;

   --  Called by the servlet container when a GET request is received.
   procedure Do_Get (Server   : in Servlet;
                     Request  : in out Requests.Request'Class;
                     Response : in out Responses.Response'Class);
end Volume_Servlet;

Servlet Implementation

The Do_Get procedure receives the request and response as parameter. Both objects are in out parameters because the servlet implementation can modify them. Indeed, the Java servlet API allows the servlet developer to set specific attributes on the request object (This allows to associate any kind of data to the request for later use when rendering the response).

Similar to the Java API, the response is written by using the Print_Stream object that is returned by the Get_Output_Stream function.


with ASF.Streams;
package body Volume_Servlet is
   procedure Do_Get (Server   : in Servlet;
                     Request  : in out Requests.Request'Class;
                     Response : in out Responses.Response'Class) is
      Output : Streams.Print_Stream := Response.Get_Output_Stream;
   begin
      Output.Write ("...");
      Response.Set_Status (Responses.SC_OK);
   end Do_Get;
end Volume_Servlet;

Note: the complete content is omitted for the clarity of this post.

Servlet Registration

With Java servlet 2.5 specification, servlets are registered exclusively through the web.xml application descriptor file. Since Java servlet 3.0, one can register servlets programmatically. With our Ada servlet, this is was we will do with the use of the Add_Servlet method.

Since the Ada runtime is not able to create dynamically an instance of any class (such as the Java newInstance method of the Java Class class), we have to create ourselves the servlet instance object and register it. The servlet instance is associated with a name.

Once registered, we have to define a mapping that tells which URL path is mapped to the servlet. This is done by the call to Add_Mapping: every URL that ends in .html will be handled by the servlet.

The Ada Server Faces framework provides a Web container in which the application must be registered (similar to the Java Web container). The registration is done by the Register_Application call which also specifies the URL prefix for the web application (Every URL starting with /volume will be served by this application).


with ASF.Server.Web;
with ASF.Servlets;
with Volume_Servlet;

procedure Volume_Server is
   Compute : aliased Volume_Servlet.Servlet;
   App     : aliased ASF.Servlets.Servlet_Registry;
   WS      : ASF.Server.Web.AWS_Container;
begin
   --  Register the servlets and filters
   App.Add_Servlet (Name => "compute",
                    Server => Compute'Unchecked_Access);

   --  Define servlet mappings
   App.Add_Mapping (Name => "compute",
                    Pattern => "*.html");

   WS.Register_Application ("/volume",
                            App'Unchecked_Access);

   WS.Start;

   delay 600.0;

end Volume_Server;

Compilation and Execution

The compilation of the Ada servlet example is done using a GNAT project file.

$ gnatmake -Psamples

It produces the volume_server which is our web server.

$ bin/volume_server

After the server is started, point your browser to http://localhost:8080/volume/index.html to look at the result.

References

volume_servlet.ads
volume_servlet.adb
volume_server.adb
HttpServlet
HttpServletResponse
HttpServletRequest

1 comment
To add a comment, you must be connected. Login to add a comment

Showing multiprocessor issue when updating a shared counter

By Stephane Carrez

When working on several Ada concurrent counter implementations, I was interested to point out the concurrent issue that exists in multi-processor environment. This article explains why you really have to take this issue seriously in multi-tasks applications, specially because multi-core processors are now quite common.

What's the issue

Let's say we have a simple integer shared by several tasks:

Counter : Integer;

And several tasks will use the following statement to increment the counter:

  Counter := Counter + 1;

We will see that this implementation is wrong (even if a single instruction is used).

Multi task increment sample

To show up the issue, let's define two counters. One not protected and another protected from concurrent accesses by using a specific data structure provided by the Ada Util library.


with Util.Concurrent.Counters;
..
  Unsafe  : Integer := 0;
  Counter : Util.Concurrent.Counters.Counter;

In our testing procedure, let's declare a task type that will increment both versions of our counters. Several tasks will run concurrently so that the shared counter variables will experience a lot of concurrent accesses. The task type is declared in a declare block inside our procedure so that we will benefit from task synchronisation at the end of the block (See RM 7.6, and RM 9.3).

Each task will increment both counters in a loop. We should expect the two counters to get the same value at the end. We will see this is not the case in multi-processor environments.


declare
  task type Worker is
    entry Start (Count : in Natural);
  end Worker;

  task body Worker is
    Cnt : Natural;
  begin
      accept Start (Count : in Natural) do
        Cnt := Count;
      end;
      for I in 1 .. Cnt loop
        Util.Concurrent.Counters.Increment (Counter);
        Unsafe := Unsafe + 1;
      end loop;
  end Worker;

Now, in the same declaration block, we will define an array of tasks to show up the concurrency.


   type Worker_Array is array (1 .. Task_Count) of Worker;
   Tasks : Worker_Array;

Our tasks are activated and they are waiting to get the counter. Let's make our tasks count 10 million times.


begin
  for I in Tasks'Range loop
    Tasks (I).Start (10_000_000);
  end loop;
end;

Before leaving the declare scope, Ada will wait until the tasks have finished. (yes, there is no need to write any pthread_join code). After this block, we can just print out the value stored in the two counters and compare them:


Log.Info ("Counter value at the end       : " & Integer'Image (Value (Counter)));
Log.Info ("Unprotected counter at the end : " & Integer'Image (Unsafe));

The complete source is available in the Ada Util project in multipro.adb.

The Results

With one task, everything is Ok (Indeed!):

Starting  1 tasks
Expected value at the end      :  10000000
Counter value at the end       :  10000000
Unprotected counter at the end :  10000000

With two tasks, the problem appears:

Starting  2 tasks
Expected value at the end      :  10000000
Counter value at the end       :  10000000
Unprotected counter at the end :  8033821

And it aggravates as the number of tasks increases.

Starting  16 tasks
Expected value at the end      :  10000000
Counter value at the end       :  10000000
Unprotected counter at the end :  2496811

(The above results have been produced on an Intel Core Quad; Similar problems show up on Atom processors as well)

Explanation

On x86 processors, the compiler can use an incl instruction for the unsafe counter increment. So, one instruction for our increment. You thought it was thread safe. Big mistake!

  incl %(eax)

This instruction is atomic in a mono-processor environment meaning that it cannot be interrupted. However, in a multi-processor environment, each processor has its own memory cache (L1 cache) and will read and increment the value into its own cache. Caches are synchronized but this is almost always too late. Indeed, two processors can read their L1 cache, increment the value and save it at the same time (thus, loosing one increment). This is what is happening with the unprotected counter.

Let's see how to do the protection.

Protection with specific assembly instruction

To avoid this, it is necessary to use special instructions that will force the memory location to be synchronized and locked until the instruction completes. On x86, this is achieved by the lock instruction prefix. The following is guaranteed to be atomic on multi-processors:

  lock
  incl %(eax)

The lock instruction prefix introduces a delay to the execution of the instruction it protects. This delay increases slightly when concurrency occurs but it remains acceptable (up to 10 times slower).

For Sparc, Mips and other processors, the implementation requires to loop until either a lock is get (Spinlock) or it is guaranteed that no other processor has modified the counter at the same time.

Source: Util.Concurrent.Counters.ads, Util.Concurrent.Counters.adb

Protection with an Ada protected type

A safe and portable counter implementation can be made by using Ada protected types. The protected type allows to define a protected procedure Increment which provides an exclusive read-write access to the data (RM 9.5.1). The protected function Value will offer a concurrent read-only access to the data.


package Util.Concurrent.Counters is
    type Counter is limited private;
    procedure Increment (C : in out Counter);
    function Value (C : in Counter) return Integer;
private
  protected type Cnt is
      procedure Increment;
      function Get return Integer;
   private
      N : Integer := 0;
   end Cnt;
   type Counter is limited record
      Value : Cnt;
   end record;
end Util.Concurrent.Counters;

Source: Util.Concurrent.Counters.ads, Util.Concurrent.Counters.adb

To add a comment, you must be connected. Login to add a comment