Sunday, March 6, 2011

Struts2, Tiles2, Spring, Hibernate, JQuery plugin - Linked Dialogs

Disclaimer:
All the software applications that appear below represent trademarks and they are the property of their respective owners.
Use and implement my notes in this article at your own risk.

Discussion here:
1. General Considerations;
2. Prerequisites;
3. JQuery Dialogs;
4. Linking dialogs;
5. Modals Data source;
6. KeyValuePairBean;
7. Struts 2 Actions;
8. DAOs;
9. Annotated Hibernate entities;

1. General Considerations:
This sample is purposed to show how to link 3 JQuery modal dialogs together; the 3 dialogs will represent records from the tables "zone", "country", "city" of the "blog" database.
The sample will be presented somehow in a "top-down" fashion, ie. starting from View, then Controller, then Model components of the MVC web app architecture.

NOTE: if you don't know for example what is "blog" database, or other aspects, then you should read the "Struts2, Tiles2, Spring, Hibernate, JQuery plugin - General Considerations", which is used as a basis for this sample.

2. Prerequisites:
Make sure you have read the "Struts2, Tiles2, Spring, Hibernate, JQuery plugin - General Considerations", and installed and configured all that is written there;

3. JQuery Dialogs:
The JQuery dialog refers to the "<sj:dialog />" object which is offered by the JQuery plugin taglib, namely "struts2-jquery-plugin-2.5.0.jar".
In order to use this plugin, you will have to include the following line in your JSP file:
<<
<%@ taglib prefix="sj" uri="/struts-jquery-tags"%>
>>
Thus, you made the JQuery modal available to be used in your JSP file.

An JQuery dialog used for zones ("dialog_zone") will look like:
<<
    <s:url id="urlDialogZones" action="selectZone" />
    <sj:dialog
        id="dialog_zone"
        href="%{urlDialogZones}"
           buttons="{
               'Cancel':function() { $('#dialog_zone').dialog('close'); },
               'Select':function() { selectDialogItem('zone'); }
           }"
           autoOpen="false"
           dataType="html"
           width="500"
           height="200"
           modal="true"
           position="['center', 0]"
           title="Zones select"
           />

>>
NOTE: <s:url id="urlDialogZones" action="selectZone" /> defines the Struts Action data source for the dialog which will be discussed at "7. Struts 2 Actions".

4. Linking dialogs
Supposing you have other modals for countries, cities, you may want to obtain which cities are from a country and which countries are from a zone.
The JQuery modal for countries ("dialog_country") looks like:
<<
    <s:url id="urlDialogCountries" action="selectCountry" />
    <sj:dialog
        id="dialog_country"
        href="%{urlDialogCountries}"
           buttons="{
               'Cancel':function() { $('#dialog_country').dialog('close'); },
               'Select':function() { selectDialogItem('country'); }
           }"
           autoOpen="false"
           dataType="html"
           width="500"
           height="200"
           modal="true"
           position="['center', 0]"
           title="Country select"
           />

>>

If you want to link "dialog_country" to "dialog_zone", then you will have to use the "loadDialog(dialog)" javaScript function which assigns the data source for each of the dialogs:
<<
    $("#dialog_" + dialog).dialog({
        open: function(event, ui) {
            // setting additional parameters to dialog
            var dialogUrl = "/blogmodal/select" + dialog + ".action";
            if (lcDialog == "country")
                dialogUrl += "?cod_zone=" + $("#input_zone_cod_selected").val();
            if (dialog == "city")
                dialogUrl += "?cod_country=" + $("#input_country_cod_selected").val();
             $("#dialog_" + dialog).load(dialogUrl);
         }
    });
    $("#dialog_" + dialog).dialog('open');


>>

The same happens also for cities, the difference being the correspondence is now between countries and cities.

5. Modals Data source
A JQuery modal is usually rendered by HTML data sources.
So, the Struts Action should return a HTML type result. It will do this by rendering a JSP page that is loaded into corresponded modal. So, the zones, countries, cities are exposed using Java Lists and then, a "<s:iterator />" Struts JSP tag is used to construct a HTML table that will be the data source for the modal dialog.
For example, the data source for "dialog_zone" is obtained by creating the HTML table with the help of "selectZone.jsp":
<<
<s:if test="%{zones != null && zones.size() > 0}">
<table id="table_zone">
    <thead>
        <tr>
            <th>Zone Code</th>
            <th>Zone Name</th>
        </tr>
    </thead>
    <tbody>
        <s:iterator value="%{zones}" var="z">
            <tr id="tr_zone_<s:property value="%{#z.key}" />">
                <td id="td_cod_zone_<s:property value="%{#z.key}" />"><s:property value="%{#z.key}" /></td>
                <td id="td_name_zone_<s:property value="%{#z.value}" />"><s:property value="%{#z.value}" /></td>
            </tr>
        </s:iterator>
    </tbody>
</table>
</s:if>

>>

6. KeyValuePairBean:
This bean is used as a structure to store key/value pair for JQuery modals.

7. Struts 2 Actions:
At "5. Modals Data source" you noted the existence of a variable named "zones"; this is the Java List that is iterated by "<s:iterator />" Struts JSP tag.

To populate for example the zones, you will use this code:
<<
    @Override
    @Action(value="/selectZone", results={
        @Result(name="success", location="/jsp/selectZone.jsp"),
        @Result(name="input", location="/jsp/empty.jsp")
    })
    public String execute() {
        try {
            List<Zone> listZones = (List<Zone>)zoneDAO.findAll();
            zones = new ArrayList<KeyValuePairBean>();
            for (Zone zone : listZones) {
                zones.add(new KeyValuePairBean(zone.getCod(), zone.getName()));
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return ActionSupport.INPUT;
        }
        return ActionSupport.SUCCESS;
    }

>>

Here:
"zones" is the Java List which will be rendered to be used by "<s:iterator />" Struts JSP tag;
"zoneDAO" is the DAO (see "6. DAOs") managed by Spring over the Hibernate entities which contains methods as "findAll()" in order to obtain data from database;

Also, you may observe here annotations to define the "success" and "input" results (overcomes) of the action "selectZone".

In the same action you should define getters and setters for "List<KeyValuePairBean> zones".

Same you should do for countries and cities.
NOTE: to see how the Struts 2 Actions are accessed, and how their results are rendered, checkout also the "struts.xml" and "tiles.xml" files.

8. DAOs
DAOs, namely Data Access Objects, are used by Spring to obtain data from database via Hibernate.
DAOS are part of the business layer of a database web app.
A DAO class extends in this case the "HibernateDaoSupport" and contains methods to access the database via annotated Hibernate entities.
Any DAO should be described as a bean in the "applicationContext.xml" file in order to be seen by the sessionFactory; for example, for zones:
<<
    <bean id="ZoneDAO" class="blog.hibernate.dao.ZoneDAO">
        <property name="sessionFactory">
            <ref bean="sessionFactory" />
        </property>
    </bean>

>>

From Java point of view, a DAO should use a session manager, in this case, "HibernateDaoSupport" which is a Spring class that manages Hibernate sessions over annotated entities.
NOTE: a method that uses Hibernate session to get data from database uses HQL (Hibernate Query Language); to understand the HQL syntax you should google for HQL documentation.

9. Annotated Hibernate entities
An annotated entity is a POJO class that describes a database table by means of annotations.
It represents the Model from the MVC architecture.
For example, for the database table "zone", it was defined the Zone.java entity class; to refer table "zone" from database "blog", annotations are placed at the top of the class definition:
<<
@Entity
@Table(name = "zone", catalog = "blog")

>>
, while for each of table "zone" fields, there are specified on their value getters: primary key, foreign key, column name, field length, aso, if they exist.
Here are some examples of annotations, taken from Zone.java:
<<
    @Id
    @GeneratedValue
    @Column(name = "cod", unique = true, nullable = false, length = 4)

>>
<<
    @Column(name = "name", nullable = false, length = 45)
>>
<<
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "zone")
>>

NOTE: if MyEclipse is used as IDE, you may generate both DAO and entity for each table by using Hibernate Reverse Engineering perspective.

2 comments:

  1. Can you please send me the source code for this tutorial.

    ReplyDelete
  2. @Syam: you forgot to put the email addr. I haven't found it on the profile.

    ReplyDelete