After the creation and setup of the AWA project and the UML model design we have seen how to create a review for the review web application. In this new tutorial, you will understand the details to list the reviews that have been created and published.
Review Web Application: Listing the reviews
By Stephane Carrez2014-07-20 14:00:00
This tutorial has three steps:
- First the definition of the database query,
- The implementation of the Ada review list bean,
- The writing of the XHTML facelet presentation file.
Step 1: Database query to list the reviews
Let's start with the database query that we will use to retrieve the reviews.
Since we need to access the list of reviews from the XHTML files, we will map the SQL query result to a list of Ada Beans objects. For this, an XML query mapping is created to tell how to map the SQL query result into some Ada record. The XML query mapping is then processed by Dynamo to generate the Ada Beans implementation. The XML query mapping is also read by AWA to get the SQL query to execute.
A template of the XML query mapping can be added to a project by using the dynamo add-query
command. The first parameter is the module name (reviews
) and the second parameter the name of the query (list
). The command will generate the file db/reviews-list.xml
.
dynamo add-query reviews list
The generated XML query mapping is an example of a query. You can replaced it or update it according to your needs. The first part of the XML query mapping is a class
declaration that describes the type to represent each row returned by our query. Within the class
, a set of property
definition describes the class attributes with their type and name.
<query-mapping package='Atlas.Reviews.Models'>
<class name="Atlas.Reviews.Models.List_Info" bean="yes">
<comment>The list of reviews.</comment>
<property type='Identifier' name="id">
<comment>the review identifier.</comment>
</property>
<property type='String' name="title">
<comment>the review title.</comment>
</property>
...
</class>
</query-mapping>
Following the class
declaration, the query
declaration describes a query by giving it a name and describing the SQL statement to execute. By having the SQL statement separate and external to the application, we can update, fix and tune the SQL without rebuilding the application. The Dynamo code generator will use the query
declaration to generate a query definition that can be referenced and used from the Ada code.
The SQL statement is defined within the sql
XML entity. The optional sql-count
XML entity is used to associate a count query that can be used for the pagination.
We want to display the review with the author's name and email address. The list will be sorted by date to show the newest reviews first. The SQL to execute is the following:
<query-mapping package='Atlas.Reviews.Models'>
...
<query name='list'>
<comment>Get the list of reviews</comment>
<sql>
SELECT
r.id,
r.title,
r.site,
r.create_date,
r.allow_comments,
r.reviewer_id,
a.name,
e.email,
r.text
FROM atlas_review AS r
INNER JOIN awa_user AS a ON r.reviewer_id = a.id
INNER JOIN awa_email AS e ON a.email_id = e.id
ORDER BY r.create_date DESC
LIMIT :first, :last
</sql>
<sql-count>
SELECT
count(r.id)
FROM atlas_review AS r
</sql-count>
</query>
</query-mapping>
The query has two named parameters represented by :first
and :last
. These parameters allow to paginate the list of reviews.
The complete source can be seen in the file: db/reviews-list.xml.
Once the XML query is written, the Ada code is generated by Dynamo by reading the UML model and all the XML query mapping defined for the application. Dynamo merges all the definitions into the target Ada packages and generates the Ada code in the src/model
directory. You can use the generate
make target:
make generate
or run the following command manually:
dynamo generate db uml/atlas.zargo
From the List_Info
class definition, Dynamo generates the List_Info
tagged record. The record contains all the data members described in the class
XML entity description. The List_Info
represents one row returned by the SQL query. The attributes of the List_Info
can be accessed from the XHTML files by using UEL expression and the property name defined for each attribute.
To describe the list of rows, Dynamo generates the List_Info_Beans
package which instantiates the Util.Beans.Basic.Lists
generic package. This provides an Ada vector for the List_Info
type and an Ada bean that gives access to the list.
package Atlas.Reviews.Models is
...
type List_Info is new Util.Beans.Basic.Readonly_Bean with record
...
package List_Info_Beans is
new Util.Beans.Basic.Lists (Element_Type => List_Info);
package List_Info_Vectors renames List_Info_Beans.Vectors;
subtype List_Info_List_Bean is List_Info_Beans.List_Bean;
subtype List_Info_Vector is List_Info_Vectors.Vector;
Query_List : constant ADO.Queries.Query_Definition_Access;
...
end Atlas.Reviews.Models;
The generated code can be seen in src/model/atlas-reviews-models.ads.
Step 2: The review list bean
In order to access the list of reviews from the XHTML facelet file, we must create an Ada bean that provides the list of reviews. This Ada bean is modelized in the UML model and we define:
- A set of attributes to manage the review list pagination (
page
,page_size
,count
) - An Ada bean action that can be called from the XHTML facelet file (
load
)
The Review_List_Bean
tagged record will hold the list of reviews for us:
package Atlas.Reviews.Beans is
...
type Review_List_Bean is new Atlas.Reviews.Models.Review_List_Bean with record
Module : Atlas.Reviews.Modules.Review_Module_Access := null;
Reviews : aliased Atlas.Reviews.Models.List_Info_List_Bean;
Reviews_Bean : Atlas.Reviews.Models.List_Info_List_Bean_Access;
end record;
type Review_List_Bean_Access is access all Review_List_Bean'Class;
end Atlas.Reviews.Beans;
We must now implement the Load
operation that was described in the UML model and we are going to use our list
query. For this, we use the ADO.Queries.Context
to setup the query to retrieve the list of reviews. A call to Set_Query
indicates the query that will be used. Since that query needs two parameters (first
and last
), we use the Bind_Param
operation to give the two values. The list of reviews is then retrieved easily by calling the Atlas.Reviews.Models.List
operation that was generated by Dynamo.
package body Atlas.Reviews.Beans is
...
overriding
procedure Load (Into : in out Review_List_Bean;
Outcome : in out Ada.Strings.Unbounded.Unbounded_String) is
Session : ADO.Sessions.Session := Into.Module.Get_Session;
Query : ADO.Queries.Context;
Count_Query : ADO.Queries.Context;
First : constant Natural := (Into.Page - 1) * Into.Page_Size;
Last : constant Positive := First + Into.Page_Size;
begin
Query.Set_Query (Atlas.Reviews.Models.Query_List);
Count_Query.Set_Count_Query (Atlas.Reviews.Models.Query_List);
Query.Bind_Param (Name => "first", Value => First);
Query.Bind_Param (Name => "last", Value => Last);
Atlas.Reviews.Models.List (Into.Reviews, Session, Query);
Into.Count := ADO.Datasets.Get_Count (Session, Count_Query);
end Load;
end Atlas.Reviews.Beans;
Review list bean creation
The AWA framework must be able to create an instance of the Review_List_Bean
type. For this, we have to declare and implement a constructor function that allocates an instance of the Review_List_Bean
type and setup some pre-defined values. When the instance is returned, the list of reviews is not loaded.
package body Atlas.Reviews.Beans is
...
function Create_Review_List_Bean (Module : in Atlas.Reviews.Modules.Review_Module_Access)
return Util.Beans.Basic.Readonly_Bean_Access is
Object : constant Review_List_Bean_Access := new Review_List_Bean;
begin
Object.Module := Module;
Object.Reviews_Bean := Object.Reviews'Access;
Object.Page_Size := 20;
Object.Page := 1;
Object.Count := 0;
return Object.all'Access;
end Create_Review_List_Bean;
end Atlas.Reviews.Beans;
The constructor function is then registered in the Atlas.Reviews.Modules
package within the Initialize
procedure. This registration allows to give a name for this constructor function and be able to specify it in the managed-bean
bean declaration.
package body Atlas.Reviews.Modules is
...
overriding
procedure Initialize (Plugin : in out Review_Module;
App : in AWA.Modules.Application_Access;
Props : in ASF.Applications.Config) is
begin
...
Register.Register (Plugin => Plugin,
Name => "Atlas.Reviews.Beans.Review_List_Bean",
Handler => Atlas.Reviews.Beans.Create_Review_List_Bean'Access);
end Initialize;
end Atlas.Reviews.Modules;
Review list bean declaration
The managed-bean XML declaration associates a name to a constructor function that will be called when the name is needed. The scope of the Ada bean is set to request
so that a new instance is created for each HTTP GET request.
<managed-bean>
<description>The list of reviews</description>
<managed-bean-name>reviewList</managed-bean-name>
<managed-bean-class>Atlas.Reviews.Beans.Review_List_Bean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
Step 3: Listing the reviews: the XHTML facelet presentation file
To load the reviews to be displayed we will use a JSF 2.2 view action. The review list page has a parameter page
that indicates the page number to be displayed. The f:viewParam
allows to retrieve that parameter and configure the reviewList
Ada bean with it. Then, the f:viewAction
defines the action that will be executed after the view parameters are extracted, validated and passed to the Ada bean. In our case, we will call the load
operation on our reviewList
Ada bean.
<f:metadata>
<f:viewParam id='page' value='#{reviewList.page}' required="false"/>
<f:viewAction action="#{reviewList.load}"/>
</f:metadata>
To summarize, the reviewList
Ada bean is created, then configured for the pagination and filled with the current page content by running our SQL query.
The easy part is now to render the list of reviews. The XHTML file uses the <h:list> component to iterate over the list items and render each of them. At each iteration, the <h:list>
component initializes the Ada bean review
to refer to the current row in the review list. We can then access each attribute defined in the XML query mapping by using the property name of that attribute. For example review.title
returns the title
property.
<h:list var="review" value="#{reviewList.reviews}">
<div
Tags
- Facelet
- NetBSD
- framework
- Mysql
- generator
- files
- application
- gcc
- ReadyNAS
- Security
- binutils
- ELF
- JSF
- Java
- bacula
- Tutorial
- Apache
- COFF
- collaboration
- planning
- project
- upgrade
- AWA
- C
- EL
- J2EE
- UML
- php
- symfony
- Ethernet
- Ada
- FreeBSD
- Go
- KVM
- MDE
- Proxy
- STM32
- Servlet
- backup
- lvm
- multiprocessing
- web
- Bean
- Jenkins
- release
- OAuth
- ProjectBar
- REST
- Rewrite
- Sqlite
- Storage
- USB
- Ubuntu
- bison
- cache
- crash
- Linux
- firefox
- performance
- interview
Add a comment
To add a comment, you must be connected. Login