Java 2 Ada - Tag AWA2017-03-18T17:27:00+00:00Stephane Carrezurn:md5:d12e23c53b2436d6becce3d51ddbdf38AWAAtlas 1.0.0 the Ada Web Application demonstrator available as Docker imageurn:md5:c0d8708341b6ee900c3f4aa1a85a43b92017-03-18T17:27:00+00:002017-03-18T17:27:00+00:00Stephane CarrezAdaAWADocker
<div class="post-text"><p>The application features:</p><ul><li>A small blogging system,</li><li>A question and answer area,</li><li>A complete wiki system,</li><li>A document and image storage space,</li><li>Authentication with Google+ or Facebook.</li></ul><p><div class="wiki-img-center"><div class="wiki-img-inner"><img src="/images/Ada/atlas-mashup.png" longdesc="Atlas Screenshots" alt="atlas-mashup.png"></img></div></div></p><p>Atlas is now available as a Docker image so that you can easily try it.</p><h3>What is Docker ?</h3><p>Docker is a container platform that allows to run applications on the host but within an isolated environment. The container has its own libraries, its own network, its own root file system but it shares the same running Linux kernel as the host. Docker is based on <a href="https://linuxcontainers.org/">Linux containers</a> which provides kernel namespaces and cgroups. Docker provides a lot of abstractions that simplifies the creation, startup and management of containers.</p><p>To learn more about Docker, you may have a look at the <a href="https://docs.docker.com/engine/getstarted/">Get started with Docker</a> documentation.</p><h3>Using the Atlas Docker image</h3><p>The <a href="https://hub.docker.com/r/ciceron/atlas/">Atlas Docker</a> image is available at the <a href="https://docs.docker.com/docker-hub/">Docker Hub</a> cloud-based registry service. This registry allows you to get and synchronize your local Docker images easily by pulling them from the cloud.</p><p>Assuming that you have installed Docker, you can pull the <a href="https://hub.docker.com/r/ciceron/atlas/">Atlas Docker</a> image by using the following command:</p><pre><code> sudo docker pull ciceron/atlas
</code></pre><p>Beware that the Docker image is a 64-bit image so it runs only on Linux x86_64 hosts. Once you have obtained the image, you can create the container and start it as follows:</p><pre><code> sudo docker run --name atlas -p 8080:8080 ciceron/atlas
</code></pre><p>and then point your browser to <a href="http://localhost:8080/atlas/index.html">http://localhost:8080/atlas/index.html</a> The <code>-p 8080:8080</code> option tells Docker to expose the TCP/IP port 8080 from the container to the host so that you can access the web application.</p><p>The application will first display some installation page that allows you to choose the database, configure the mail server and the Google and Facebook connexions (most of the default values should be correct).</p><p>To stop and cleanup the docker container, you can use the following commands:</p><pre><code> sudo docker stop atlas
sudo docker rm atlas
</code></pre><h4>Learning more about Ada Web Application</h4><p>You may read the following tutorials to lean more about the technical details about setting up and building an <a href="https://github.com/stcarrez/ada-awa">Ada Web Application</a>:</p><ul><li>Step 1: <a href="http://blog.vacs.fr/vacs/blogs/post.html?post=2014/05/08/Ada-Web-Application-Setting-up-the-project">Ada Web Application: Setting up the project</a></li><li>Step 2: <a href="http://blog.vacs.fr/vacs/blogs/post.html?post=2014/05/18/Ada-Web-Application--Building-the-UML-model">Ada Web Application: Building the UML model</a></li><li>Step 3: <a href="http://blog.vacs.fr/vacs/blogs/post.html?post=2014/06/14/Review-Web-Application-Creating-a-review">Review Web Application: Creating a review</a></li><li>Step 4: <a href="http://blog.vacs.fr/vacs/blogs/post.html?post=2014/07/19/Review-Web-Application-Listing-the-reviews">Review Web Application: Listing the reviews</a></li></ul></div> Review Web Application: Listing the reviewsurn:md5:5461f4f9d59691737c7c02383cd16ae22014-07-20T14:00:00+00:002014-07-20T14:00:00+00:00Stephane CarrezTutorialAWAAda
<div class="post-text"><p>This tutorial has three steps:</p><ul><li>First the definition of the database query,</li><li>The implementation of the Ada review list bean,</li><li>The writing of the <a href="http://en.wikipedia.org/wiki/Facelets">XHTML facelet</a> presentation file.</li></ul><h4>Step 1: Database query to list the reviews</h4><p>Let's start with the database query that we will use to retrieve the reviews.</p><p>Since we need to access the list of reviews from the XHTML files, we will map the SQL query result to a list of <a href="https://code.google.com/p/ada-util/wiki/AdaBeans">Ada Beans</a> objects. For this, an <a href="https://code.google.com/p/ada-ado/wiki/QueryMapping">XML query mapping</a> is created to tell how to map the SQL query result into some Ada record. The XML query mapping is then processed by <a href="https://code.google.com/p/ada-gen/">Dynamo</a> to generate the <a href="https://code.google.com/p/ada-util/wiki/AdaBeans">Ada Beans</a> implementation. The XML query mapping is also read by <a href="https://code.google.com/p/ada-awa/">AWA</a> to get the SQL query to execute.</p><p>A template of the XML query mapping can be added to a project by using the dynamo <code>add-query</code> command. The first parameter is the module name (<code>reviews</code>) and the second parameter the name of the query (<code>list</code>). The command will generate the file <code>db/reviews-list.xml</code>.</p><pre><code>dynamo add-query reviews list
</code></pre><p>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 <code>class</code> declaration that describes the type to represent each row returned by our query. Within the <code>class</code>, a set of <code>property</code> definition describes the class attributes with their type and name.</p><pre><code class="lang-xml"><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>
</code></pre><p>Following the <code>class</code> declaration, the <code>query</code> 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 <a href="https://code.google.com/p/ada-gen/">Dynamo</a> code generator will use the <code>query</code> declaration to generate a query definition that can be referenced and used from the Ada code.</p><p>The SQL statement is defined within the <code>sql</code> XML entity. The optional <code>sql-count</code> XML entity is used to associate a count query that can be used for the pagination.</p><p>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:</p><pre><code class="lang-xml"><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>
</code></pre><p>The query has two named parameters represented by <code>:first</code> and <code>:last</code>. These parameters allow to paginate the list of reviews.</p><p>The complete source can be seen in the file: <a href="https://code.google.com/p/ada-awa/source/browse/trunk/awa/samples/db/reviews-list.xml">db/reviews-list.xml</a>.</p><p>Once the XML query is written, the Ada code is generated by <a href="https://code.google.com/p/ada-gen/">Dynamo</a> by reading the UML model and all the XML query mapping defined for the application. <a href="https://code.google.com/p/ada-gen/">Dynamo</a> merges all the definitions into the target Ada packages and generates the Ada code in the <code>src/model</code> directory. You can use the <code>generate</code> make target:</p><pre><code>make generate
</code></pre><p>or run the following command manually:</p><pre><code>dynamo generate db uml/atlas.zargo
</code></pre><p>From the <code>List_Info</code> class definition, <a href="https://code.google.com/p/ada-gen/">Dynamo</a> generates the <code>List_Info</code> tagged record. The record contains all the data members described in the <code>class</code> XML entity description. The <code>List_Info</code> represents one row returned by the SQL query. The attributes of the <code>List_Info</code> can be accessed from the XHTML files by using UEL expression and the property name defined for each attribute.</p><p>To describe the list of rows, <a href="https://code.google.com/p/ada-gen/">Dynamo</a> generates the <code>List_Info_Beans</code> package which instantiates the <code>Util.Beans.Basic.Lists</code> generic package. This provides an Ada vector for the <code>List_Info</code> type and an <a href="https://code.google.com/p/ada-util/wiki/AdaBeans">Ada bean</a> that gives access to the list.</p><pre><code class="lang-ada">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;
</code></pre><p>The generated code can be seen in <a href="https://code.google.com/p/ada-awa/source/browse/trunk/awa/samples/src/model/atlas-reviews-models.ads#185">src/model/atlas-reviews-models.ads</a>.</p><h4>Step 2: The review list bean</h4><p>In order to access the list of reviews from the XHTML facelet file, we must create an <a href="https://code.google.com/p/ada-util/wiki/AdaBeans">Ada bean</a> that provides the list of reviews. This <a href="https://code.google.com/p/ada-util/wiki/AdaBeans">Ada bean</a> is modelized in the UML model and we define:</p><ul><li>A set of attributes to manage the review list pagination (<code>page</code>, <code>page_size</code>, <code>count</code>)</li><li>An <a href="https://code.google.com/p/ada-util/wiki/AdaBeans">Ada bean</a> action that can be called from the XHTML facelet file (<code>load</code>)</li></ul><p>The <code>Review_List_Bean</code> tagged record will hold the list of reviews for us:</p><pre><code class="lang-ada">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;
</code></pre><p>We must now implement the <code>Load</code> operation that was described in the UML model and we are going to use our <code>list</code> query. For this, we use the <code>ADO.Queries.Context</code> to setup the query to retrieve the list of reviews. A call to <code>Set_Query</code> indicates the query that will be used. Since that query needs two parameters (<code>first</code> and <code>last</code>), we use the <code>Bind_Param</code> operation to give the two values. The list of reviews is then retrieved easily by calling the <code>Atlas.Reviews.Models.List</code> operation that was generated by <a href="https://code.google.com/p/ada-gen/">Dynamo</a>.</p><pre><code class="lang-ada">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;
</code></pre><h3>Review list bean creation</h3><p>The <a href="AWA">AWA</a> framework must be able to create an instance of the <code>Review_List_Bean</code> type. For this, we have to declare and implement a constructor function that allocates an instance of the <code>Review_List_Bean</code> type and setup some pre-defined values. When the instance is returned, the list of reviews is not loaded.</p><pre><code class="lang-ada">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;
</code></pre><p>The constructor function is then registered in the <code>Atlas.Reviews.Modules</code> package within the <code>Initialize</code> procedure. This registration allows to give a name for this constructor function and be able to specify it in the <code>managed-bean</code> bean declaration.</p><pre><code class="lang-ada">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;
</code></pre><h3>Review list bean declaration</h3><p>The <a href="http://docs.oracle.com/javaee/5/tutorial/doc/bnawq.html">managed-bean XML declaration</a> associates a name to a constructor function that will be called when the name is needed. The scope of the <a href="https://code.google.com/p/ada-util/wiki/AdaBeans">Ada bean</a> is set to <code>request</code> so that a new instance is created for each <a href="http://tools.ietf.org/html/rfc2616#section-9.3">HTTP GET</a> request.</p><pre><code class="lang-xml"> <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>
</code></pre><h4>Step 3: Listing the reviews: the XHTML facelet presentation file</h4><p>To load the reviews to be displayed we will use a <a href="http://www.oracle.com/technetwork/articles/java/jsf22-1377252.html">JSF 2.2 view action</a>. The review list page has a parameter <code>page</code> that indicates the page number to be displayed. The <code>f:viewParam</code> allows to retrieve that parameter and configure the <code>reviewList</code> Ada bean with it. Then, the <code>f:viewAction</code> defines the action that will be executed after the view parameters are extracted, validated and passed to the <a href="https://code.google.com/p/ada-util/wiki/AdaBeans">Ada bean</a>. In our case, we will call the <code>load</code> operation on our <code>reviewList</code> <a href="https://code.google.com/p/ada-util/wiki/AdaBeans">Ada bean</a>.</p><pre><code class="lang-xml"><f:metadata>
<f:viewParam id='page' value='#{reviewList.page}' required="false"/>
<f:viewAction action="#{reviewList.load}"/>
</f:metadata>
</code></pre><p>To summarize, the <code>reviewList</code> Ada bean is created, then configured for the pagination and filled with the current page content by running our SQL query.</p><p>The easy part is now to render the list of reviews. The XHTML file uses the <a href="http://demo.vacs.fr/demo/jsf/html/view.html"><h:list></a> component to iterate over the list items and render each of them. At each iteration, the <code><h:list></code> component initializes the <a href="https://code.google.com/p/ada-util/wiki/AdaBeans">Ada bean</a> <code>review</code> 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 <code>review.title</code> returns the <code>title</code> property.</p><pre><code class="lang-xml"><h:list var="review" value="#{reviewList.reviews}">
<div</code></pre></div> Review Web Application: Creating a reviewurn:md5:8a09dfbba43f631077b82532d414ac742014-06-14T18:29:00+00:002014-06-14T18:29:00+00:00Stephane CarrezTutorialAdaAWA
<div class="post-text"><h3>Adding the review creation form</h3><p>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.</p><p><a href="https://github.com/stcarrez/ada-awa/p/ada-awa">AWA</a> uses the <a href="http://en.wikipedia.org/wiki/Facelets">Facelets</a> 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.</p><h4>Adding pages</h4><p><a href="https://github.com/stcarrez/dynamo/">Dynamo</a> provides at least two commands that help in adding presentation files. The <code>add-page</code> 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.</p><pre><code>dynamo add-page reviews/list
</code></pre><p>The <code>add-form</code> command creates another template of page that includes an HTML form to let a user submit some data to the web application.</p><pre><code>dynamo add-form reviews/edit-review
</code></pre><p>These two commands will create the following files and they can now be modified.</p><pre><code>./web/reviews/list.xhtml
./web/reviews/edit-review.xhtml
./web/reviews/forms/edit-review-form.xhtml
</code></pre><h4>The create review form</h4><p>In Facelets, an HTML form is created by using the <code><h:form></code> component from the <a href="http://demo.vacs.fr/demo/jsf/html/view.html">HTML JSF</a> namespace. This component will generate the HTML <code>form</code> tag and it will also manage the form submission.</p><p>The <a href="https://github.com/stcarrez/ada-asf/">ASF framework</a> provides a set of <a href="http://demo.vacs.fr/demo/widgets/view.html">widget components</a> that facilitate the design of web application. The <code><w:inputText></code> component renders a title field with an HTML <code><label></code> and an HTML <code><input></code> text. We will use it to let the user enter the review title and the site URL being reviewed. The HTML <code><textarea></code> is provided by the JSF component <code><h:inputTextArea></code>. The review submit form is defined by the following XML extract:</p><pre><code class="lang-xml"><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>
</code></pre><p>Before closing the <code><h:form></code> component, we will put a <code><h:commandButton></code> that will render the form submit button.</p><h3>How it works</h3><p>Before going further, let's see how all this works. The principle below is exactly the same for a <a href="http://en.wikipedia.org/wiki/JavaServer_Faces">Java Server Faces</a> application.</p><p>First, when the page is rendered the <a href="http://en.wikipedia.org/wiki/Unified_Expression_Language">UEL</a> expressions that it contains are evaluated. The <code>#{review.title}</code>, <code>#{review.site}</code> and <code>#{review.text}</code> are replaced by the content provided by the <code>review</code> object which is an <a href="https://github.com/stcarrez/ada-util/wiki/AdaBeans">Ada Bean</a> provided by the <code>Review_Bean</code> tagged record.</p><p>When the page is submitted by the user, the input values submitted in the form are saved in the <code>review</code> bean, again by using the <a href="http://en.wikipedia.org/wiki/Unified_Expression_Language">UEL</a> expression. The <code><h:commandButton></code> action is then executed. This is also an <a href="http://en.wikipedia.org/wiki/Unified_Expression_Language">UEL</a> that indicates a method to invoke on the bean.</p><p>To sum up, the <a href="http://en.wikipedia.org/wiki/Unified_Expression_Language">UEL</a> makes the binding between the presentation layer in <a href="http://en.wikipedia.org/wiki/Facelets">Facelets</a> files and the Ada or Java beans.</p><p>The <a href="https://github.com/stcarrez/ada-util/wiki/AdaBeans">Ada Bean</a> layer provides getter and setter to allow the <a href="http://en.wikipedia.org/wiki/Unified_Expression_Language">UEL</a> to retrieve and set values. For this, the <code>Review_Bean</code> tagged record implements two operations that are defined in the <a href="https://github.com/stcarrez/ada-util/source/browse/trunk/src/util-beans-basic.ads">Bean</a> interface:</p><pre><code class="lang-ada">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);
</code></pre><p>The <code>Get_Value</code> operation is called to retrieve one of the <a href="https://github.com/stcarrez/ada-util/wiki/AdaBeans">Ada Bean</a> member attribute and the <code>Set_Value</code> operation is called during form submission to set the member attribute.</p><p><div class="wiki-img-center"><div class="wiki-img-inner"><img src="/images/samples/demo-awa-request-flow.png" longdesc="Presentation, Ada Beans and Module interactions" alt="demo-awa-request-flow.png"></img></div></div></p><p>Then the form button is pressed, the HTML form is submitted and received by the server. The <code><h:form></code> component identifies the form submission and each input component will validate the input fields. When everything has been validated, the <code><h:commandButton></code> component invokes the <code>Save</code> procedure that is declared as follows in the <code>Review_Bean</code> tagged record:</p><pre><code class="lang-ada">overriding
procedure Save (Bean : in out Review_Bean;
Outcome : in out Ada.Strings.Unbounded.Unbounded_String);
</code></pre><p>In the <a href="https://code.google.com/p/ada-util/wiki/AdaBeans">Ada Bean</a> layer, we have to call the business logic to perform the <code>save</code> operation.</p><p>The <a href="http://en.wikipedia.org/wiki/Business_logic">business logic</a> part is provided by the Ada module whose initial skeleton was generated by <a href="https://github.com/stcarrez/dynamo/">Dynamo</a>. 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.</p><p>The last part of the architecture is the data model layer that was in fact generated by <a href="https://github.com/stcarrez/dynamo/">Dynamo</a> from the UML model. It is responsible for loading and saving Ada objects into the database.</p><h3>The Review_Bean type declaration</h3><p>When we designed our UML model, we have created the <code>Review_Bean</code> UML class and gave that class the <code>Bean</code> stereotype. We also declared two operations (<code>save</code> and <code>delete</code>) on that class. With this definition, Dynamo has generated in the <code>Atlas.Reviews.Models</code> package the <code>Review_Bean</code> abstract type. This type is abstract because we have to implement the <code>Save</code> and <code>Delete</code> operations. These are the two operations that can be called by an action such as used by the <code><h:commandButton></code> component.</p><p>The <code>Atlas.Reviews.Models</code> package is a generated package and it must not be modified. To implement our <a href="https://code.google.com/p/ada-util/wiki/AdaBeans">Ada Bean</a>, we will add the <code>Review_Bean</code> type in our own package: the <code>Atlas.Reviews.Beans</code> package.</p><p>For this the <code>Review_Bean</code> type will inherit from the <code>Atlas.Reviews.Models.Review_Bean</code> type and it will implement the required operations. The type declaration looks like this:</p><pre><code class="lang-ada">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;
...
</code></pre><h3>The Review_Bean implementation</h3><p>The <code>Save</code> and <code>Delete</code> procedure must be implemented and since the whole <a href="http://en.wikipedia.org/wiki/Business_logic">business logic</a> is managed by the module layer, we just have to call the associated module procedure as follows:</p><pre><code class="lang-ada">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;
</code></pre><h3>The Review_Bean creation</h3><p>The <a href="https://github.com/stcarrez/ada-awa">AWA</a> framework must be able to create the <code>review</code> bean instance when a page is processed. For this, there are three steps that are necessary:</p><ul><li>we must define a create function whose role is to allocate the <code>Review_Bean</code> instance and return it. At the same time, the function can setup some pre-defined values for the object. The <a href="https://github.com/stcarrez/dynamo/">Dynamo</a> tool has generated for us an example of such function so that there is nothing to do.</li></ul><pre><code class="lang-ada">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;
</code></pre><ul><li>the creation function must be registered in the <a href="https://github.com/stcarrez/ada-awa">AWA</a> 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.</li></ul><pre><code class="lang-ada">Register.Register (Plugin => Plugin,
Name => "Atlas.Reviews.Beans.Reviews_Bean",
Handler => Atlas.Reviews.Beans.Create_Review_Bean'Access);
</code></pre><ul><li>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 <a href="http://docs.oracle.com/javaee/5/tutorial/doc/bnawq.html">managed-bean XML declaration</a> that comes from <a href="http://en.wikipedia.org/wiki/JavaServer_Faces">Java Server Faces</a>. We can declare as many Ada beans as we want each of them with a different name.</li></ul><pre><code class="lang-xml"> <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>
</code></pre><p>When the <a href="http://en.wikipedia.org/wiki/Unified_Expression_Language">UEL</a> expression <code>#{review.title}</code> is used, the AWA framework looks for the Ada bean represented by <code>review</code> and identified by the <code>managed-bean-name</code> entry. It then calls the create function defined by the <code>managed-bean-class</code>. The Ada bean object is then stored either in the <b>request</b> context, a <b>session</b> context or an <b>application</b> context. This is defined by the <code>managed-bean-scope</code> entry. The <b>request</b> 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 <b>session</b> scope means that the Ada bean object is shared between requests on the same session. The <b>application</b> scope means that the Ada bean object is global to the application, shared by every request and every user.</p><h3>Adding the module operations</h3><p>Now, we must add two operations on the <a href="http://en.wikipedia.org/wiki/Business_logic">business logic</a> to save a review and delete a review. The <a href="https://github.com/stcarrez/dynamo/">Dynamo</a> code generator provides the <code>add-module-operation</code> command that will help us in this task. Let's run it:</p><pre><code>dynamo add-module-operation reviews review Save
dynamo add-module-operation reviews review Delete
</code></pre><p>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 <code>add-module</code> operation. In our case, this is the <code>reviews</code> module.</p><p>The second parameter is the name of the database entity or database table if you prefer.</p><p>The <code>add-module-operation</code> command modifies the Ada module specification and body to define and implement the following operation:</p><pre><code class="lang-ada">package Atlas.Reviews.Modules is
...
procedure Save (Model : in Review_Module;
Entity : in out Atlas.Reviews.Models.Review_Ref'Class);
...
</code></pre><p>The object to save in the <code>Review</code> 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.</p><h3>Saving our review</h3><p>Before saving our review entity object, we want to associate it with the current user</p></div>