Java 2 Ada

Review Web Application: Listing the reviews

By stephane.carrez

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. 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 class='review' id="p_#{review.id}">
        <div class='review-title'>
            <h2><a href="#{review.site}">#{review.title}</a></h2>
            <ul class='review-info'>
                <li><span>By #{review.reviewer_name}</span></li>
                <li>
                    <h:outputText styleClass='review-date' value="#{review.date}" converter="dateConverter"/>
                </li>
                <h:panelGroup rendered="#{review.reviewer_id == user.id}">
                    <li>
                        <a href="#{contextPath}/reviews/edit-review.html?id=#{review.id}">#{reviewMsg.review_edit_label}</a>
                    </li>
                    <li>
                        <a href="#"
                           onclick="return ASF.OpenDialog(this, 'deleteDialog', '#{contextPath}/reviews/forms/delete-review.html?id=#{review.id}');">
                           #{reviewMsg.review_delete_label}
                        </a>
                    </li>
                </h:panelGroup>
            </ul>
        </div>
        <awa:wiki styleClass='review-text post-text' value="#{review.text}" format="dotclear"/>
    </div>
</h:list>

Understanding the request flow

Let's see the whole request flow to better understand what happens.

To display the list of reviews, the user's browser makes an HTTP GET request to the page /reviews/list.html. This page maps to the XHTML file web/reviews/list.xhtml that we created in the previous tutorial.

The Ada Server Faces framework handles the request by first reading the XHTML file and building a tree of components that represent the view to render. Within that tree of component, the <f:metadata> component allows to make a pre-initialization of components and beans before the component tree is rendered.

For the pre-initialization, the reviewList Ada bean is created because it is referenced in an EL expression used by the <f:viewParam> component or by the <f:viewAction>. For this creation, the Create_Review_List_Bean constructor that we registered is called. The page attribute is set on the reviewList Ada bean if it was passed as a URL request parameter.

The load action is then called by Ada Server Faces and the current review list page is retrieved by executing the SQL query.

As soon as the load action terminates, the rendering of the component tree can be processed. The reviewList Ada bean contains the information to display and the <h:list> component iterates over the list and renders each row at a time.

C

Conclusion

After the previous tutorial we were able to create a review and populate our database with one or several reviews. We are now able to display the list of reviews to our users.

The next tutorial will focus on using the Votes module to bring some voting capabilities in the review web application. Meanwhile, you may browse and study the sources:

db/reviews-list.xml

atlas-reviews-beans.ads

atlas-reviews-beans.adb

review-list.xhtml

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

Review Web Application: Creating a review

By stephane.carrez

In previous tutorials we have seen how to create and setup the project, design the UML model to generate the Ada implementation and the database schema. In this tutorial we will see how to design the page to create a review, implement the operations to create and populate the database with the new review.

Adding the review creation form

We will start with the presentation layer by adding two pages in our web application. A first page will contain the list of reviews and the second page will contain a form to create or update a review.

AWA uses the Facelets technology to allow developers write and design the presentation layer of the web application. This technology is commonly used in J2EE applications. A page is represented by an XML file that contains HTML code, includes some stylesheets, Javascript files and makes the link between the presentation and the web application.

Adding pages

Dynamo provides at least two commands that help in adding presentation files. The add-page command adds a simple page that can be edited and filled with real content. We will use it for the creation of the page to display the list of reviews.

dynamo add-page reviews/list

The add-form command creates another template of page that includes an HTML form to let a user submit some data to the web application.

dynamo add-form reviews/edit-review

These two commands will create the following files and they can now be modified.

./web/reviews/list.xhtml
./web/reviews/edit-review.xhtml
./web/reviews/forms/edit-review-form.xhtml

The create review form

In Facelets, an HTML form is created by using the <h:form> component from the HTML JSF namespace. This component will generate the HTML form tag and it will also manage the form submission.

The ASF framework provides a set of widget components that facilitate the design of web application. The <w:inputText> component renders a title field with an HTML <label> and an HTML <input> text. We will use it to let the user enter the review title and the site URL being reviewed. The HTML <textarea> is provided by the JSF component <h:inputTextArea>. The review submit form is defined by the following XML extract:

<h:form xmlns:h="http://java.sun.com/jsf/html
  xmlns:w="http://code.google.com/p/ada-asf/widget">
  <h:inputHidden id='entity-id' value='#{review.id}' required='false'/>
  <w:inputText title='Title' value='#{review.title}'/>
  <w:inputText title='Site' value='#{review.site}'/>
  <h:inputTextArea rows='20' value='#{review.text}'/>
  <h:commandButton value='Save'
     action='#{review.save}'/>
</h:form>

Before closing the <h:form> component, we will put a <h:commandButton> that will render the form submit button.

How it works

Before going further, let's see how all this works. The principle below is exactly the same for a Java Server Faces application.

First, when the page is rendered the UEL expressions that it contains are evaluated. The #{review.title}, #{review.site} and #{review.text} are replaced by the content provided by the review object which is an Ada Bean provided by the Review_Bean tagged record.

When the page is submitted by the user, the input values submitted in the form are saved in the review bean, again by using the UEL expression. The <h:commandButton> action is then executed. This is also an UEL that indicates a method to invoke on the bean.

To sum up, the UEL makes the binding between the presentation layer in Facelets files and the Ada or Java beans.

The Ada Bean layer provides getter and setter to allow the UEL to retrieve and set values. For this, the Review_Bean tagged record implements two operations that are defined in the Bean interface:

overriding
function Get_Value (From : in Review_Bean;
                    Name : in String) return Util.Beans.Objects.Object;

overriding
procedure Set_Value (From : in out Review_Bean;
                    Name : in String;
                    Value : in Util.Beans.Objects.Object);

The Get_Value operation is called to retrieve one of the Ada Bean member attribute and the Set_Value operation is called during form submission to set the member attribute.

demo-awa-request-flow.png

Then the form button is pressed, the HTML form is submitted and received by the server. The <h:form> component identifies the form submission and each input component will validate the input fields. When everything has been validated, the <h:commandButton> component invokes the Save procedure that is declared as follows in the Review_Bean tagged record:

overriding
procedure Save (Bean : in out Review_Bean;
                Outcome : in out Ada.Strings.Unbounded.Unbounded_String);

In the Ada Bean layer, we have to call the business logic to perform the save operation.

The business logic part is provided by the Ada module whose initial skeleton was generated by Dynamo. That layer is responsible for defining how the data is created, retrieved and modified. As far as we are concerned, this is rather simple since we only have to verify the permission and save the review object within some transaction. In other modules, several objects may be envolved and more complex rules may be defined for the integrity and validity of these objects.

The last part of the architecture is the data model layer that was in fact generated by Dynamo from the UML model. It is responsible for loading and saving Ada objects into the database.

The Review_Bean type declaration

When we designed our UML model, we have created the Review_Bean UML class and gave that class the Bean stereotype. We also declared two operations (save and delete) on that class. With this definition, Dynamo has generated in the Atlas.Reviews.Models package the Review_Bean abstract type. This type is abstract because we have to implement the Save and Delete operations. These are the two operations that can be called by an action such as used by the <h:commandButton> component.

The Atlas.Reviews.Models package is a generated package and it must not be modified. To implement our Ada Bean, we will add the Review_Bean type in our own package: the Atlas.Reviews.Beans package.

For this the Review_Bean type will inherit from the Atlas.Reviews.Models.Review_Bean type and it will implement the required operations. The type declaration looks like this:

package Atlas.Reviews.Beans is
...
type Review_Bean is new Atlas.Reviews.Models.Review_Bean with record
   Module : Atlas.Reviews.Modules.Review_Module_Access := null;
end record;
...

The Review_Bean implementation

The Save and Delete procedure must be implemented and since the whole business logic is managed by the module layer, we just have to call the associated module procedure as follows:

overriding
procedure Save (Bean : in out Review_Bean;
                Outcome : in out Ada.Strings.Unbounded.Unbounded_String);
begin
   Bean.Module.Save (Bean);
end Save;

overriding
procedure Delete (Bean : in out Review_Bean;
                Outcome : in out Ada.Strings.Unbounded.Unbounded_String);
begin
   Bean.Module.Delete (Bean);
end Delete;

The Review_Bean creation

The AWA framework must be able to create the review bean instance when a page is processed. For this, there are three steps that are necessary:

  • we must define a create function whose role is to allocate the Review_Bean instance and return it. At the same time, the function can setup some pre-defined values for the object. The Dynamo tool has generated for us an example of such function so that there is nothing to do.
function Create_Review_Bean (Module : in Atlas.Reviews.Modules.Review_Module_Access)
   return Util.Beans.Basic.Readonly_Bean_Access is
   Object : constant Review_Bean_Access := new Review_Bean;
begin
   Object.Module := Module;
   return Object.all'Access;
end Create_Review_Bean;
  • the creation function must be registered in the AWA framework under a name that identifies the create function. Again, an example of this registration has been generated by Dynamo and we are going to use it as is.
Register.Register (Plugin => Plugin,
                 Name   => "Atlas.Reviews.Beans.Reviews_Bean",
                 Handler => Atlas.Reviews.Beans.Create_Review_Bean'Access);
  • the last step is the configuration step. In the module XML configuration file, we must declare the Ada bean name and indicate what create function must be called to create it. We will use the managed-bean XML declaration that comes from Java Server Faces. We can declare as many Ada beans as we want each of them with a different name.
  <managed-bean>
    <description>An example of a bean (change description and bean name)</description>
    <managed-bean-name>review</managed-bean-name>
    <managed-bean-class>Atlas.Reviews.Beans.Reviews_Bean</managed-bean-class>
    <managed-bean-scope>request</managed-bean-scope>
  </managed-bean>

When the UEL expression #{review.title} is used, the AWA framework looks for the Ada bean represented by review and identified by the managed-bean-name entry. It then calls the create function defined by the managed-bean-class. The Ada bean object is then stored either in the request context, a session context or an application context. This is defined by the managed-bean-scope entry. The request scope means that the Ada bean object is created once for each request. Concurrent page accesses will use their own Ada bean object instance. The session scope means that the Ada bean object is shared between requests on the same session. The application scope means that the Ada bean object is global to the application, shared by every request and every user.

Adding the module operations

Now, we must add two operations on the business logic to save a review and delete a review. The Dynamo code generator provides the add-module-operation command that will help us in this task. Let's run it:

dynamo add-module-operation reviews review Save
dynamo add-module-operation reviews review Delete

The first parameter is the name of the module where the new operation is added. This is the name of the module that was created by using the add-module operation. In our case, this is the reviews module.

The second parameter is the name of the database entity or database table if you prefer.

The add-module-operation command modifies the Ada module specification and body to define and implement the following operation:

package Atlas.Reviews.Modules is
...
procedure Save (Model  : in Review_Module;
                Entity : in out Atlas.Reviews.Models.Review_Ref'Class);
...

The object to save in the Review table is passed as parameter to the Save operation. The procedure body that was generated is rather simple but functional: it just saves the object in the database within a transaction. In many cases it is ready to use but you may also need to modify the operation to either change the implementation or even add new parameters.

Saving our review

Before saving our review entity object, we want to associate it with the current user. We have to know who is the current user and for this we can use the AWA service context. The AWA service context is an object that is provided by the AWA.Services.Contexts package and that provides some useful contextual information for the business logic:

  • It indicates the optional user that is authenticated and is doing the call,
  • It gives access to the database connections that the business logic can use,
  • It allows to manage database transactions.

The current service context is retrieved by using the AWA.Services.Contexts.Current function and we can use the Get_User function to know the current user. The Save procedure implementation is the following:

package ASC renames AWA.Services.Contexts;
procedure Save (Model  : in Review_Module;
                  Entity : in out Atlas.Reviews.Models.Review_Ref'Class) is
   Ctx   : constant ASC.Service_Context_Access := ASC.Current;
   DB    : ADO.Sessions.Master_Session := AWA.Services.Contexts.Get_Master_Session (Ctx);
begin
   Ctx.Start;
   if not Entity.Is_Inserted then
      Entity.Set_Reviewer (Ctx.Get_User);
      Entity.Set_Create_Date (Ada.Calendar.Clock);
   end if;
   Entity.Save (DB);
   Ctx.Commit;
end Save;

Setting up the permissions

Because we want to bring some minimal security to the Review Web Application, we are going to setup some permissions that will be enforced by the business logic layer when a save or delete operation is done. The AWA framework uses the Ada Security to implement and enforce permissions. For this we need:

  • An Ada definition of the permission,
  • Adding a verification to enforce the permission in the new module operations,
  • A definition of the permission rules.
Generating the permission

Dynamo provides the add-permissions command to help us in the first task. It generates some Ada code that declares the permissions. It also provides a default configuration for the new permissions.

dynamo add-permissions reviews review

The first parameter is the name of our module where the new permissions are declared and the second parameter is the name of the database entity. The command will modify the Ada module specification and add the following lines:

package Atlas.Reviews.Modules is
...
package ACL_Create_Reviews is new Security.Permissions.Definition ("review-create");
package ACL_Delete_Reviews is new Security.Permissions.Definition ("review-delete");
package ACL_Update_Reviews is new Security.Permissions.Definition ("review-update");

Each of these package instantiation, declares a single permission identified by a name.

Enforcing security

Now that we have our permission, we can enforce the security in the Save and Delete operation. This is done by using the Check operation provided by the AWA.Permissions package.

To verify that the user has the permission to create a new review, we can use the following call:

AWA.Permissions.Check (Permission => ACL_Create_Reviews.Permission);

Now, if we have a review to modify, we will use the update permission and also give the review object to the Check operation so that it can verify if that particular review can be modified.

AWA.Permissions.Check (Permission => ACL_Update_Reviews.Permission,
                       Entity => Entity);
Configuring the permission

Until now we have created the permission and enforced it in the business logic. We have not defined the rules that tell what is really checked to verify the permission. The configuration part is defined in the XML file config/reviews.xml that was generated when the reviews module was created. The add-permissions command has modified the XML file to provide some default configuration. It has generated a XML permission for the review-create, review-update and review-delete permissions.

The review-create permission is defined as follows:

<auth-permission>
    <name>review-create</name>
</auth-permission>

This XML definition associate the Authenticated Permission controller to the review-create permission. With that controller the permission is granted if the security context has a principal (ie, a user is authenticated).

The review-update permission has another definition that we must change. Basically, we want that only the reviewer that created the review can update the review. For this we will use the entity permission controller provided by AWA. The XML definition is the following:

<entity-permission>
    <name>review-update</name>
    <entity-type>altas_review</entity-type>
    <sql>
       SELECT r.id FROM atlas_review AS r
       WHERE r.id = :entity_id AND r.reviewer_id = :user_id
    </sql>
</entity-permission>

When the permission is checked, the entity permission controller will use the SQL statement to verify the permission. The SQL statement has three parameters:

  1. user_id is the ID of the user associated with the security context. If there is no authentified user, the permission is refused.
  2. entity_id is the ID of the database entity as passed to the Check procedure and propagated to the permission controller.
  3. entity_type is a unique number that identifies the database entity type or database table if you prefer. It is created and setup automatically according to the entity type defined in the entity-type XML member. It is not used in our example.

The above SQL statement verifies that the review exists and was created by the current user.

To learn more about permission, you may look at the AWA permissions documentation.

A word about navigation rules

We have seen that when the review creation form is submitted the <h:commandButton> component has invoked the Save procedure of our Review_Bean object. The review object has been created and saved in the database and we kept the relation between the new review and the user.

We must now decide what should happen for the user to see the result. We could display a new form, update some page content or redirect to a new page. All this is defined by the navigation rules.

The navigation rules is the Java Server Faces mechanism that controls and defines what is the next page or view that must be displayed to a user.

In the definition below, the navigation rule defines that the user is redirected to the page /reviews/list.xhtml if the current page was /reviews/edit-review.xhtml and the operation returned success.

<navigation-rule>
  <from-view-id>/reviews/edit-review.xhtml</from-view-id>
    <navigation-case>
      <from-outcome>success</from-outcome>
      <to-view-id>/reviews/list.xhtml</to-view-id>
      <redirect/>
    </navigation-case>
</navigation-rule>

The Review Web Application video

To help you in creating the review page and see how the whole process looks like in reality, I've created the following short video that details the above tutorial steps.

Conclusion

We have created a review form for the web application and we made the link between the presentation layer and the Ada code through the use of Ada Beans.

We implemented the business logic and saw how the review object is saved in the database. We defined the security of the application by creating specific permissions and we enforced the security in the Save and Delete operations.

The next tutorial will describe how to display a list of reviews for our application.

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