Sunday, March 6, 2011

Struts2, Tiles2, Spring, Hibernate, JQuery plugin - Using JODReports for ODT Templates

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. ODT Templates;
4. JODReports Configuration;
5. KeyValuePairBean;
6. Struts 2 Actions;
7. DAOs;
8. Annotated Hibernate entities;

1. General Considerations:
This sample is purposed to show how to export OpenOffice ODT, Microsoft Word DOC, Adobe PDF documents by using an OpenOffice ODT template; We will export 3 fields, all string type: the title of the document, a chosen Zone fron "zone" table from "blog" database and an author. The document type will be chosen by user (ODT, DOC, PDF).

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;

Besides the components above, you should also google for the following Java libraries and put them on the buid path of the app:
- "jodconverter-2.2.2.jar";
- "jodreports-2.4.0.jar";
- "juh-2.3.0.jar";
- "jurt-2.3.0.jar";
- "ridl-2.3.0.jar";
- "unoil-2.3.0.jar";
- "xom-1.2.5.jar".

3. ODT Templates:
ODT Template is actually a synonim for an OpenOffice Writer document - ie. the analogue of the Microsoft Word DOC document;
the term of template is used because the ODT will be used in a given form in which some input fields were mapped; these fields will be completed with the Java values we send from our app.
ODT is used because of its simplicity in use.

4. JODReports Configuration:
JOD is a Java tool that behaves as a reporting tool; it allows the rendering of ODT templates as sources by using OpenOffice components, a kind of mail merge.
JOD is capable to export ODT files by itself, but if we want to convert files in DOC or PDF we will need to call the OpenOffice service whose engine will convert the ODT results to documents as DOC and PDF.
So, you will have to install also OpenOffice 3.x and to create a batch file (*.bat) that will launch the OpenOffice service engine. Your batch file should contain:
<<
"C:\Program Files\OpenOffice.org 3\program\soffice" -headless -accept="socket,host=127.0.0.1,port=8100;urp;" -nofirststartwizard
>>
In this case, OpenOffice service will rule on the 8100 port.
The OpenOffice service should be launched before your app is started. If you intend to restart the machine for several times, then you should better load this batch file on startup.
Integration of JOD OpenOffice document conversion capabilities with Struts2 is made via Spring services.
You will have to paste these beans definitions in your applicationContext.xml:
<<
    <bean id="openOfficeConnection" class="com.artofsolving.jodconverter.openoffice.connection.SocketOpenOfficeConnection" destroy-method="disconnect">
        <constructor-arg index="0">
            <value>127.0.0.1</value>
        </constructor-arg>
        <constructor-arg index="1">
            <value>8100</value>
        </constructor-arg>
    </bean>

    <bean id="documentFormatRegistry" class="com.artofsolving.jodconverter.DefaultDocumentFormatRegistry"/>

    <bean id="documentConverter" class="com.artofsolving.jodconverter.openoffice.converter.OpenOfficeDocumentConverter">
        <constructor-arg index="0">
            <ref bean="openOfficeConnection"/>
        </constructor-arg>
        <constructor-arg index="1">
            <ref bean="documentFormatRegistry"/>
        </constructor-arg>
    </bean>

>>

5. KeyValuePairBean:
This bean is used as a structure to store key/value pair for zone list elements.

6. Struts 2 Actions:
When using Struts, the results are rendered by using Struts Actions, which represent the level of Controller from MVC architecture.
Our Struts action should return a stream type result, as the result is in fact the exported document.
The Struts Action is denoted "writeODFAction". We will send to it the HTTP parameters "title", "zones", "author" and "documentType" by using this JSP Struts code written in "jod.jsp":
<<
    <s:form action="writeODF" id="writeODF">
    <s:property value="odfTry" />
        <s:textfield id="title" name="title" label="Title of the document" labelposition="left"></s:textfield>
        <s:select id="zones" name="zones" labelposition="left" label="Zone" list="%{zones}" listKey="value" listValue="value" />
        <s:textfield id="author" name="author" label="Author" labelposition="left"></s:textfield>
        <s:select name="documentType" label="Document Type" labelposition="left" list="#{'odt':'odt','doc':'doc','pdf':'pdf'}"></s:select>
        <s:submit cssClass="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only ui-button-text" name="btnSubmitODT" value="create document from template" />
    </s:form>

>>
The data existent in "<s:select id="zones" name="zones" />" is obtained with the help of the starting action, namely "JodAction", using the code:
<<
            List<Zone> listZones = (List<Zone>)zoneDAO.findAll();
            zones = new ArrayList<KeyValuePairBean>();
            for (Zone zone : listZones) {
                zones.add(new KeyValuePairBean(zone.getCod(), zone.getName()));
            }

>>

When sent the 4 HTTP parameters, getters/setters should be created in "writeODFAction".

The main code for "writeODFAction" is here:
<<
    @Override
    @Action(value="/writeODF", results={
        @Result(name="success", type="stream", params={"contentType", "${contentType}", "inputName", "documentStream", "contentDisposition", "filename=${fileName}.${fileType}", "bufferSize", "1024"}),
        @Result(name="input", location="/jsp/empty.jsp")
    })
    public String execute() {
        try {
           
            DocumentFormat outputFormat = documentFormatRegistry.getFormatByFileExtension(documentType);
            Resource templateDirectory = getTemplateDirectory(odtFileName);
           
            File templateFile = null;           
            if (templateDirectory.exists()) {
                templateFile = templateDirectory.getFile();
            } else {
                templateFile = getTemplateFile(odtFileName).getFile();
                if (!templateFile.exists()) {
                    addActionError(getText("error", new String[] {"Template not found!"}));
                    return ActionSupport.INPUT;
                }
            }

            DocumentTemplateFactory documentTemplateFactory = new DocumentTemplateFactory();
            DocumentTemplate template = documentTemplateFactory.getTemplate(templateFile);
            ByteArrayOutputStream odtOutputStream = new ByteArrayOutputStream();
           
            Map<String, Object> data = new HashMap<String, Object>();
            data.put("title", title);
            data.put("zones", zones);
            data.put("author", author);

            template.createDocument(data, odtOutputStream);
           
            setContentType(outputFormat.getMimeType());
            setFileName(odtFileName);
            setFileType(outputFormat.getFileExtension());

            if ("odt".equals(outputFormat.getFileExtension())) {
                setDocumentStream(new ByteArrayInputStream(odtOutputStream.toByteArray()));
            } else {
                ByteArrayInputStream odtInputStream = new ByteArrayInputStream(odtOutputStream.toByteArray());
                ByteArrayOutputStream docOutputStream = new ByteArrayOutputStream();
                DocumentFormat inputFormat = documentFormatRegistry.getFormatByFileExtension("odt");
                documentConverter.convert(odtInputStream, inputFormat, docOutputStream, outputFormat);
                setDocumentStream(new ByteArrayInputStream(docOutputStream.toByteArray()));
            }

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return ActionSupport.SUCCESS;
    }

>>
Notice the presence of various methods:
"getTemplateDirectory()" - obtains the physical directory path with the help of Spring Resource;
"getTemplateFile" - obtains the physical directory path with the help of Spring Resource;

contentType, fileName, fileType are used to render a "stream" action result, together with the "documentStream".
You may observe here annotations to define the "success" and "input" results (overcomes) of the action "writeODFAction".

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.

7. 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.

8. 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.

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

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 JQGrids;
4. Linking JQGrids;
5. KeyValuePairBean;
6. Struts 2 Actions;
7. DAOs;
8. Annotated Hibernate entities;

1. General Considerations:
This sample is purposed to show how to link 3 JQuery JQGrids together; the 3 grids 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 JQGrids:
The JQuery JQGrid refers to the "<sjg:grid />" object which is offered by the JQuery JQGrid plugin taglib, namely "struts2-jquery-grid-plugin-2.5.0.jar".
In order to use this plugin, you will have to include the following lines in your JSP file:
<<
<%@ taglib prefix="sj" uri="/struts-jquery-tags"%>
<%@ taglib prefix="sjg" uri="/struts-jquery-grid-tags"%>

>>
Thus, you made the JQuery JQGrid available to be used in your JSP file.

An JQuery JQGrid used for zones ("gridZones") will look like:
<<
        <s:url id="urlSelectZones" action="selectZone" />
        <sjg:grid
            id="gridZones"
              caption="Zones"
              dataType="json"
              href="%{urlSelectZones}"
            width="400"
              altRows="true"
              pager="true"
              navigator="true"    
              navigatorSearch="true"
              navigatorSearchOptions="{sopt:['eq','ne','lt','le','gt','ge','bw','bn','in','ni','ew','en','cn','nc'], multipleSearch: true}"
              navigatorAdd="false"
              navigatorEdit="false"
              navigatorView="true"
              navigatorDelete="false"
              gridModel="gridModel"
              rowList="5,10,15,20"
              rowNum="5"
              editinline="false"
              onSelectRowTopics="/zoneRowSelect">
                <sjg:gridColumn width="50" name="key" align="center" index="cod" title="Code" editable="false" sortable="true" search="true" searchoptions="{sopt:['eq','bw','ew','cn']}" />
                <sjg:gridColumn width="350" name="value" index="name" title="Name" editable="false" sortable="true" search="true" searchoptions="{sopt:['eq','bw','ew','cn']}" />
        </sjg:grid>

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

4. Linking JQGrids
Supposing you have other JQGrids for countries, cities, you may want to obtain which cities are from a country and which countries are from a zone.
The JQuery JQGrid for countries ("gridCountries") looks like:
<<
        <s:url id="urlSelectCountries" action="selectCountry" />
        <sjg:grid
            id="gridCountries"
              caption="Countries"
              dataType="json"
              href="%{urlSelectCountries}"
            width="400"
              altRows="true"
              pager="true"
              navigator="true"    
              navigatorSearch="true"
              navigatorSearchOptions="{sopt:['eq','ne','lt','le','gt','ge','bw','bn','in','ni','ew','en','cn','nc'], multipleSearch: true}"
              navigatorAdd="false"
              navigatorEdit="false"
              navigatorView="true"
              navigatorDelete="false"
              gridModel="gridModel"
              rowList="5,10,15,20"
              rowNum="5"
              editinline="false"
              onSelectRowTopics="/countryRowSelect">
                <sjg:gridColumn width="50" name="key" align="center" index="cod" title="Code" editable="false" sortable="true" search="true" searchoptions="{sopt:['eq','bw','ew','cn']}" />
                <sjg:gridColumn width="350" name="value" index="name" title="Name" editable="false" sortable="true" search="true" searchoptions="{sopt:['eq','bw','ew','cn']}" />
        </sjg:grid>

>>

If you want to link "gridCountries" to "gridZones", then you will use a "<sj:a />" Struts JSP tag will will behave as a "select" button:
<<
    <sj:a id="btnSelectZone" button="true">select zone &gt;&gt;</sj:a>
>>

Then, when user clicks this button, the following javaScript code executes:
<<
    $("#btnSelectZone").click(function(){
        var gridZonesId = $("#gridZones").jqGrid("getGridParam", "selrow");
        var cod_zone = $("#gridZones").jqGrid('getCell', gridZonesId, 'key');
        var name_zone = $("#gridZones").jqGrid('getCell', gridZonesId, 'value');
        $("#gridCountries").jqGrid('setGridParam', {
            url: "/bloggrid/selectCountry.action?cod_zone=" + cod_zone,
            page: 1
        });
       
        $("#gridCountries").trigger("reloadGrid");
           $("#divGridCountries").css("display", "");
    })

>>

This javaScript code practically gets the selected row in the "gridZones" and passes it as HTTP parameter "cod_zone" to "gridCountries"; when gridCountries is loaded with the content served by "selectCountry.action" it will trigger the "reloadGrid" event.

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

5. KeyValuePairBean:
This bean is used as a structure to store key/value pair for JQGrid columns denoted by "<sjg:gridColumn />" Struts JSP tags.

6. Struts 2 Actions:
A JQuery JQGrid is rendered by JSON data source.
So, the Struts action should return a JSON type result.
To be sure of this, you have to include this annotation to your struts action:
<<
@ParentPackage("blog-json")
>>
This will use the Struts "blog-json" package defined in struts.xml, ie. it will extend the "json-default" package of the Struts2; "json-default" uses "struts2-json-plugin-2.2.1.jar" to render a JSON result.

To populate for example the zones, you will use this code:
<<
    @Override
    @Action(value = "/selectZone", results = {
            @Result(name = "success", type = "json"),
            @Result(name = "input", location = "/jsp/empty.jsp") })
    public String execute() {
        try {
            List<KeyValuePairBean> list = new ArrayList<KeyValuePairBean>();
            List<Zone> listZones = (List<Zone>) zoneDAO.findAll();
            for (Zone zone : listZones) {
                list.add(new KeyValuePairBean(zone.getCod(), zone.getName()));
            }

            if (list != null && !list.isEmpty()) {
                if (getSord() != null && getSord().equalsIgnoreCase("asc")) {
                    sortList(list);
                }
                if (getSord() != null && getSord().equalsIgnoreCase("desc")) {
                    sortList(list);
                    Collections.reverse(list);
                }
                setRecords(list.size());

                if (getTotalrows() != null) {
                    setRecords(getTotalrows());
                }

                Integer to = (getRows() * getPage());
                Integer from = to - getRows();

                if (to > getRecords())
                    to = getRecords();

                List<KeyValuePairBean> listClone = cloneList(list);
                if (isLoadonce()) {
                    if (getTotalrows() != null && getTotalrows() > 0) {
                        setGridModel(listClone.subList(0, getTotalrows()));
                    } else {
                        setGridModel(list);
                    }
                } else {
                    if (filters != null && !filters.isEmpty()) {
                        setGridModel(returnGridModel(listClone, from, to));
                    } else {
                        setGridModel(listClone.subList(from, to));
                    }
                }

                setTotal((int) Math.ceil((double) getRecords()
                        / (double) getRows()));
            }

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return ActionSupport.INPUT;
        }
        return ActionSupport.SUCCESS;
    }

>>

Here:
"gridModel" is the Java List which will be rendered as a JSON object;
"zoneDAO" is the DAO (see "6. DAOs") managed by Spring over the Hibernate entities which contains methods as "findByCriteria()" in order to obtain data from database; you will find it in the sample source;
The "execute()" method contains also code for sorting, finding, paging the JQGrid.
The sorting is done by using Java Collections class, while the finding is done by using "returnGridModel()".

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 "String term" and "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.

7. 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.

8. 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.

For any other aspects do not hesitate to contact.

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.

Struts2, Tiles2, Spring, Hibernate, JQuery plugin - Using TreeView

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 TreeView
5. TreeViewBean;
6. Struts 2 actions;
7. DAOs;
8. Annotated Hibernate entities;

1. General Considerations:
This sample is purposed to show how to use the JQuery treeView; the 3 autocompleters 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 TreeView:
The JQuery treeView refers to the rendered tree object which is offered by the JQuery javaScript libraries: jquery.cookie.js, jquery.treeview.js, jquery.treeview.async.js.
In order to use this plugin, you will have to include the following lines in your JSP file:
<<
<script src="js/jquery.cookie.js" type="text/javascript"></script>
<script src="js/jquery.treeview.js" type="text/javascript"></script>
<script src="js/jquery.treeview.async.js" type="text/javascript"></script>

>>
Thus, you made the JQuery treeView available to be used in your JSP file.

An definition of the JQuery treeView will look like:
<<
        <ul id="tree" class="filetree treeview"></ul>
>>

To populate the treeView by using Struts Actions, you should write this javaScript code (be sure the HTML element "<ul id=tree />" is already rendered):
<<
    $("#tree").treeview({
        url: "selectTree.action"
    })

>>
In our case, the tree will contain all data from zones, countries, cities and will be populated using results from "selectTree.action".

4. TreeViewBean:
This bean is used as a structure to store an element of the treeView. This element maybe a node or a leaf, in other words, there are elements that have children and other that don't have.
The structure of a treeView element contains:
<<
    String id;
    String text;
    Boolean expanded;
    String classes;
    Boolean hasChildren;
    String href;
    List<TreeViewBean> children;

>>

The bean is used in a recursive way, ie a child will have the same fields in its structure. In our case, zones has countries as children and countries has cities as children.
NOTE: the "href" TreeView field was added by me in "jquery.treeview.async.js", so, remove it if you get some error with the original "jquery.treeview.async.js".

6. Struts 2 Actions:
A JQuery treeView uses JSON as source.
So, the Struts action should return a JSON type result.
To be sure of this, you have to include this annotation to your struts action:
<<
@ParentPackage("blog-json")
>>
This will use the Struts "blog-json" package defined in struts.xml, ie. it will extend the "json-default" package of the Struts2; "json-default" uses "struts2-json-plugin-2.2.1.jar" to render a JSON result.

To populate for example the zones, you will use this code:
<<
    @Override
    @Action(value="/selectTree", results={
        @Result(name="success", type="json", params={"root","treeList"}),
        @Result(name="input", location="/jsp/empty.jsp")
    })
    public String execute() {
        try {
            List<Zone> zonesList = (List<Zone>)zoneDAO.findAll();
            List<TreeViewBean>zones = new ArrayList<TreeViewBean>();
            if (zonesList != null && !zonesList.isEmpty())
            for (Zone zone : zonesList) {
                List<Country> countriesList = (List<Country>)countryDAO.findByCriteria("zone.cod", zone.getCod());
                List<TreeViewBean>countries = new ArrayList<TreeViewBean>();
                if (countriesList != null && !countriesList.isEmpty())
                for (Country country : countriesList) {
                    List<City> citiesList = (List<City>)cityDAO.findByCriteria("country.cod", country.getCod());
                    List<TreeViewBean>cities = new ArrayList<TreeViewBean>();
                    if (citiesList != null && !citiesList.isEmpty())
                    for (City city : citiesList) {
                        cities.add(new TreeViewBean(String.valueOf(city.getId()), city.getName(), true, "file", "/blogtree/index?city_id=" + city.getId()));
                    }
                    countries.add(new TreeViewBean(country.getCod(), country.getName(), true, "important", cities));
                }
                zones.add(new TreeViewBean(zone.getCod(), zone.getName(), true, "folder", countries));
            }
            setTreeList(zones);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return ActionSupport.INPUT;
        }
        return ActionSupport.SUCCESS;
    }


>>

Here:
"treeList" is the Java List which will be rendered as a JSON object;
"zoneDAO", "countryDAO and cityDAO are the DAO (see "6. DAOs") managed by Spring over the Hibernate entities which contains methods as "findByCriteria()" in order to obtain data from database;

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

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

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.

7. 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.

8. 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.

Saturday, March 5, 2011

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

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 Autocompleters;
4. Linking autocompleters;
5. KeyValuePairBean;
6. Struts 2 Actions;
7. DAOs;
8. Annotated Hibernate entities;

1. General Considerations:
This sample is purposed to show how to link 3 JQuery autocompleters together; the 3 autocompleters 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 Autocompleters:
The JQuery autocompleter refers to the "<sj:autocompleter />" 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 autocompleter available to be used in your JSP file.

An JQuery autocompleter used for zones ("auto_zone") will look like:
<<
        <s:url id="url_zones" action="selectZone" />
        <sj:autocompleter
            id="auto_zone"
            name="name_zone"
            href="%{url_zones}"
            label="World Zones"
            list="zones"
            listKey="key"
            listValue="value"
            delay="30"
            loadMinimumCount="2"
            onSelectTopics="/autoZoneChange"
            />

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

4. Linking autocompleters
Supposing you have other autocompleters for countries, cities, you may want to obtain which cities are from a country and which countries are from a zone.
The JQuery autocompleter for countries ("auto_country") looks like:
<<
        <s:url id="url_countries" action="selectCountry" />
        <sj:autocompleter
            id="auto_country"
            name="name_country"
            href="%{url_countries}"
            label="World Countries"
            list="countries"
            listKey="key"
            listValue="value"
            delay="30"
            loadMinimumCount="2"
            onSelectTopics="/autoCountryChange"
            listenTopics="/autoZoneChanged"
            />

>>

If you want to link "auto_country" to "auto_zone", then you will have to use the "/autoZoneChange" event of "auto_zone" autocompleter; this will happen in JavaScript like this:
<<
    $.subscribe("/autoZoneChange",function(event, data){
        var ui = event.originalEvent.ui;
        if (ui.item && ui.item.text.length > 0) {
            //setting the URL of the child linked autocompleter
            setJQueryAutocompleterURL("/blogac/selectCountry.action", "cod_zone=" + ui.item.text, "countries", "auto_country", "name_country", "/autoCountryChange", "/autoZoneChanged");
        }
    },null);

>>

Note the presence of a JavaScript function, namely "setJQueryAutocompleterURL":
<<
function setJQueryAutocompleterURL(href, hrefparameter, list, id, name, selectTopics, listenTopics) {
    var opt_auto = {};
    opt_auto.delay = 30;
    opt_auto.minimum = 2;
    opt_auto.selectBox = false;
    opt_auto.selectBoxIcon = false;
    opt_auto.list = list;
    opt_auto.listkey = "key";
    opt_auto.listvalue = "value";
    opt_auto.jqueryaction = "autocompleter";
    opt_auto.id = id;
    opt_auto.name = name;
    opt_auto.onselecttopics = selectTopics;
    opt_auto.href = href;
    opt_auto.hrefparameter = hrefparameter;
    opt_auto.listentopics = listenTopics;
 
    jQuery.struts2_jquery.bind(jQuery('#' + id),opt_auto);
}

>>
This function practically passes the HTTP parameter "cod_zone" from "auto_zone" to "auto_country" when the "auto_zone" completed to render and user changed a value in it; when the user selects a zone, the "/autoCountryChange" event fires, and the function "setJQueryAutocompleterURL" populates the "auto_country" autocompleter with countries belonging to that zone.
Note that the "auto_country" autocompleter is waiting for another event to be published, namely "/autoZoneChanged", so, it will not be populated until after this event fires.

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

5. KeyValuePairBean:
This bean is used as a structure to store key/value pair for autocompleters.

6. Struts 2 Actions:
A JQuery autocompleter is rendered by various type of sources: Java list, JSON, JavaScript array, aso.
If you want to use JQuery Ajax capabilities, then you should render a JQuery autocompleter by using JSON type source.
When using Struts, the results are rendered by using Struts Actions, which represent the level of Controller from MVC architecture.
So, the Struts action should return a JSON type result.
To be sure of this, you have to include this annotation to your struts action:
<<
@ParentPackage("blog-json")
>>
This will use the Struts "blog-json" package defined in struts.xml, ie. it will extend the "json-default" package of the Struts2; "json-default" uses "struts2-json-plugin-2.2.1.jar" to render a JSON result.

To populate for example the zones, you will use this code:
<<
    @Override
    @Action(value="/selectZone", results={
        @Result(name="success", type="json"),
        @Result(name="input", location="/jsp/empty.jsp")
    })
    public String execute() {
        if (term != null && term.trim().length() > 1) {
            try {
                List<Zone> listZones = (List<Zone>)zoneDAO.findByCriteria("name", "%" + term.trim() + "%");
                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:
"term" is sent by JQuery autocompleter and represents what was written in the "auto_zone" autocompleter to find zones;
"zones" is the Java List which will be rendered as a JSON object;
"zoneDAO" is the DAO (see "6. DAOs") managed by Spring over the Hibernate entities which contains methods as "findByCriteria()" 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 "String term" and "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.

7. 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.

8. 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.

Struts2, Tiles2, Spring, Hibernate, JQuery plugin - General Considerations

Struts2, Tiles2, Spring, Hibernate, JQuery plugin - General Considerations

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.

The following topics are discussed:
1. General Considerations - overview of the subject;
2. Prerequisites - what you need to setup a JEE MVC app;
3. Installation - installation of the tools needed (platforms, IDEs, aso);
4. Assembly librairies - setting up the used JEE librairies;
5. Configuration - setting up the JEE app;
6. MySQL database - database description;
7. Considerations;

1. General Considerations:
This section gives you some hints in how to setup a JEE application that uses Struts2, Tiles2, Spring, Hibernate and JQuery plugin for Struts2 as a MVC (Model View Controller) web app.
It is also used as a basis configuration for the next samples posted on this blog, namely:
"Struts2, Tiles2, Spring, Hibernate, JQuery plugin - Linked Autocompleters",
"Struts2, Tiles2, Spring, Hibernate, JQuery plugin - Using TreeView",
"Struts2, Tiles2, Spring, Hibernate, JQuery plugin - Linked Dialogs",
"Struts2, Tiles2, Spring, Hibernate, JQuery plugin - Linked JQGrids",
"Struts2, Tiles2, Spring, Hibernate, JQuery plugin - Using JODReports for ODT Templates",
"Struts2, Tiles2, Spring, Hibernate, JQuery - DisplayTag Plugin",
"Struts2, Tiles2, Spring, Hibernate, JQuery Plugin - Tabbed Panel".

So, as the samples say, we will deal with specific approaches for: JQuery Autocompleter, JQuery TreeView, JQuery Dialog and JQuery JQGrid.

2. Prerequisites:
2.1 Operating System;
2.2. Java;
2.3. Development IDE;
2.4. Tomcat 7;
2.5. Struts2 Framework;
2.6. Spring 3.0.5 Framework;
2.7. Hibernate 3.6.0;
2.8. MySQL 5;
2.9. MySQL Connector;
2.10. JQuery;
2.11. Logging errors;
2.12. JSON;

2.1. Operating System
I used WinXP SP3 for this sample, but you may use any OS on which you may install Java Virtual Machine.

2.2. Java
You will need Java JDK 1.6.0_x. Go download'it from Oracle website.

2.3. Development IDE
You may use Netbeans, Eclipse with WTP, MyEclipse, aso.
In my case, I used MyEclipse for Spring v. 8.6.

Generally speaking, you will need an IDE that supports JEE, not only JSE.

2.4. Tomcat 7
I used Apache Tomcat 7 as web container, but you may use any web servers that supports JEE deployments.

2.5. Struts2 Framework
I used Struts v. 2.2.1 with Tiles v. 2.2.2.
You need to download latest Struts2 Framework librairies, so google for'em;
Also, google for the latest Tiles2 librairies, as they will be used, too.

2.6. Spring 3.0.5 Framework

I used Spring v. 3.0.5
You need to download latest Spring Framework librairies, so google for'em;

2.7. Hibernate 3.6.0
Hibernate v. 3.6.0 was used, so, google it.

2.8. MySQL 5
I used MySQL 5, as I have it configured on the machine, but you may use any database support with the condition to configure the database connection driver.
Download MySQL 5 from Oracle, together with a visual database manager for MySQL; I used MySQL Administrator, but you may find others: Workbench, Heidi, Navicat, aso.

2.9. MySQL Connector
I used mysql-connector-java-5.1.14-bin.jar
Also, for Tomcat you may need: tomcat-jdbc.jar

2.10. JQuery

You will need the JQuery plugins for Struts2:
struts2-jquery-plugin-2.5.0.jar
struts2-jquery-grid-plugin-2.5.0.jar

Also, you will need other JQuery components:
JQuery UI theme: ui-lightness
jquery.treeview.js
jquery.treeview.async.js
jquery.cookie.js

2.11. Logging errors
log4j-1.2.16.jar
jul-to-slf4j-1.6.1.jar
log4j-over-slf4j-1.6.1.jar
slf4j-simple-1.6.1.jar

2.12. JSON

JSON plugin struts-2.2.1/lib/struts2-json-plugin-2.2.1.jar from Struts 2.2.1 will be used to form Struts2 action result, but you will also need a JSON parser: json-org.jar

3. Installation
Once you downloaded all the above, you'll have to install:
- Java JDK; install to default specified location;
- Apache Tomcat 7 - install to default location; use the default specified port (8080) for tomcat HTTP web connector;
- Development IDE - install to specified location;
- MySQL - download to specified default location; use the default specified port (3306) for MySQL service database connectivity; also install the MySQL database manager (Administrator, Workbench, Heidi, aso) to default specified location;

Note: if installed, do not install again.

4. Assembly librairies
After you downloaded all the above, and installed the items at 3), a good approach is to keep'em the Java librairies in their directories, in order to have access to their sources for debug purposes.
Anyhow, you should have these on the application library path:
    Hibernate 3.6.0
        hibernate-distribution-3.6.0.Final/hibernate3.jar
        hibernate-distribution-3.6.0.Final/lib/required/antlr-2.7.6.jar
        hibernate-distribution-3.6.0.Final/lib/required/slf4j-api-1.6.1.jar
        hibernate-distribution-3.6.0.Final/lib/required/dom4j-1.6.1.jar
        hibernate-distribution-3.6.0.Final/lib/required/javassist-3.12.0.GA.jar
        hibernate-distribution-3.6.0.Final/lib/required/jta-1.1.jar
        hibernate-distribution-3.6.0.Final/lib/bytecode/cglib/cglib-2.2.jar
        hibernate-distribution-3.6.0.Final/lib/jpa/hibernate-jpa-2.0-api-1.0.0.Final.jar
   
    Spring 3.0.5
        spring-framework-3.0.5.RELEASE/dist/org.springframework.aop-3.0.5.RELEASE.jar
        spring-framework-3.0.5.RELEASE/dist/org.springframework.asm-3.0.5.RELEASE.jar
        spring-framework-3.0.5.RELEASE/dist/org.springframework.aspects-3.0.5.RELEASE.jar
        spring-framework-3.0.5.RELEASE/dist/org.springframework.beans-3.0.5.RELEASE.jar
        spring-framework-3.0.5.RELEASE/dist/org.springframework.context-3.0.5.RELEASE.jar
        spring-framework-3.0.5.RELEASE/dist/org.springframework.context.support-3.0.5.RELEASE.jar
        spring-framework-3.0.5.RELEASE/dist/org.springframework.core-3.0.5.RELEASE.jar
        spring-framework-3.0.5.RELEASE/dist/org.springframework.expression-3.0.5.RELEASE.jar
        spring-framework-3.0.5.RELEASE/dist/org.springframework.instrument-3.0.5.RELEASE.jar
        spring-framework-3.0.5.RELEASE/dist/org.springframework.instrument.tomcat-3.0.5.RELEASE.jar
        spring-framework-3.0.5.RELEASE/dist/org.springframework.jdbc-3.0.5.RELEASE.jar
        spring-framework-3.0.5.RELEASE/dist/org.springframework.jms-3.0.5.RELEASE.jar
        spring-framework-3.0.5.RELEASE/dist/org.springframework.orm-3.0.5.RELEASE.jar
        spring-framework-3.0.5.RELEASE/dist/org.springframework.oxm-3.0.5.RELEASE.jar
        spring-framework-3.0.5.RELEASE/dist/org.springframework.transaction-3.0.5.RELEASE.jar
        spring-framework-3.0.5.RELEASE/dist/org.springframework.web-3.0.5.RELEASE.jar
        spring-framework-3.0.5.RELEASE/dist/org.springframework.web.servlet-3.0.5.RELEASE.jar
        spring-framework-3.0.5.RELEASE/dist/org.springframework.web.struts-3.0.5.RELEASE.jar
   
    Struts 2.2.1
        struts-2.2.1/lib/xwork-core-2.2.1.jar
        struts-2.2.1/lib/aopalliance-1.0.jar
        struts-2.2.1/lib/classworlds-1.1.jar
        struts-2.2.1/lib/commons-beanutils-1.7.0.jar
        struts-2.2.1/lib/commons-chain-1.2.jar
        struts-2.2.1/lib/commons-collections-3.2.jar
        struts-2.2.1/lib/commons-digester-2.0.jar
        struts-2.2.1/lib/commons-fileupload-1.2.1.jar
        struts-2.2.1/lib/commons-io-1.3.2.jar
        struts-2.2.1/lib/commons-lang-2.3.jar
        struts-2.2.1/lib/commons-logging-1.0.4.jar
        struts-2.2.1/lib/commons-logging-api-1.1.jar
        struts-2.2.1/lib/commons-validator-1.3.1.jar
        struts-2.2.1/lib/freemarker-2.3.16.jar
        struts-2.2.1/lib/json-lib-2.1-jdk15.jar
        struts-2.2.1/lib/ognl-3.0.jar
        struts-2.2.1/lib/sslext-1.2-0.jar
        struts-2.2.1/lib/struts2-convention-plugin-2.2.1.jar
        struts-2.2.1/lib/struts2-core-2.2.1.jar
        struts-2.2.1/lib/struts2-embeddedjsp-plugin-2.2.1.jar
        struts-2.2.1/lib/struts2-json-plugin-2.2.1.jar
        struts-2.2.1/lib/struts2-spring-plugin-2.2.1.jar
        struts-2.2.1/lib/struts2-tiles-plugin-2.2.1.jar
        struts-2.2.1/lib/oro-2.0.8.jar
        struts-2.2.1/lib/velocity-tools-1.3.jar
        struts-2.2.1/lib/velocity-1.6.3.jar
   
    Tiles 2.2
        tiles-2.2.2/tiles-ognl-2.2.2.jar
        tiles-2.2.2/tiles-servlet-2.2.2.jar
        tiles-2.2.2/tiles-api-2.2.2.jar
        tiles-2.2.2/tiles-core-2.2.2.jar
        tiles-2.2.2/tiles-jsp-2.2.2.jar
        tiles-2.2.2/tiles-template-2.2.2.jar
        tiles-2.2.2/tiles-el-2.2.2.jar

Note: Not all of the above are required, but is better to have references to all the vendor distributed packages.
Note: Besides the above, you will also need the librairies from 2.7. -> 2.10 on the app path.

5. Configuration
Following JEE web app architecture, you will configure:
5.1. JEE app;
5.2. web.xml;
5.3. struts.xml;
5.4. tiles.xml;
5.5. applicationContext.xml;
5.6. context.xml;
5.7. log4j.properties;

5.1. JEE app
With your IDE development, create a new JEE project; name it "blogac".
Under "blogac" you should have:
- the "src" directory, in which will reside all your Java code;
- the "META-INF" directory that will store the connection file (context.xml) to the database via the MySQL JDBC driver and the MANIFEST.MF project descriptor file;
- the "WEB-INF" directory that will store the web dependecy files: librairies (lib subfolder), web.xml, applicationContext.xml, tiles.xml;
- other web used subfolders: css, js, images, aso;

Basically, the structure should look like in the image below taken from MyEclipse for Spring IDE:
JEE project structure:



5.2. web.xml
This is the web app descriptor, located under "WEB-INF" application directory:
<<
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
      version="3.0" metadata-complete="true">
     
    <session-config>
        <session-timeout>30</session-timeout>
    </session-config>
     
      <filter>
        <filter-name>hibernateFilter</filter-name>
        <filter-class>blog.filters.HibernateFilter</filter-class>
        <init-param>    
             <param-name>singleSession</param-name>      
             <param-value>true</param-value>  
        </init-param> 
        <init-param>
            <param-name>sessionFactoryBeanName</param-name>
            <param-value>sessionFactory</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>hibernateFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping> 
         
      <filter>
          <filter-name>struts2</filter-name>
          <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
      </filter>
      <filter-mapping>
          <filter-name>struts2</filter-name>
          <url-pattern>/*</url-pattern>
      </filter-mapping>
 
    <listener>
       <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
    </listener>     
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <listener>
        <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
    </listener>
    <listener>
        <listener-class>org.apache.tiles.web.startup.simple.SimpleTilesListener</listener-class>
    </listener>
       
      <welcome-file-list>
        <welcome-file>index.html</welcome-file>
      </welcome-file-list>
</web-app>

>>
In this file there are configured filters and listeners for: hibernate, struts2, spring, log4j, tiles and the welcome file "index.html".

5.3. struts.xml
This is the configuration file of the Struts 2 Framework, located under "src" application directory:
<<
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
    <constant name="struts.objectFactory" value="org.apache.struts2.spring.StrutsSpringObjectFactory" />
    <constant name="struts.objectFactory.spring.autoWire" value="type" />
    <constant name="struts.enable.DynamicMethodInvocation" value="false" />
    <constant name="struts.devMode" value="true" />
    <constant name="struts.convention.result.path" value="/jsp"/>
    <constant name="struts.convention.action.packages" value="blog.actions"/>
    <constant name="struts.convention.classes.reload" value="false" />

    <package name="blog-struts" extends="struts-default" namespace="/">
        <result-types>
            <result-type name="tiles" class="org.apache.struts2.views.tiles.TilesResult" />
        </result-types>
    </package>

</struts>

>>
Here are specified: the DTD for struts2, the communication between Struts2 and Spring, debug mode, annotation convention for Struts2 actions, package types for Struts2 action, tiles result.

5.4. tiles.xml;
Here is the layout configuration of Tiles, located under "WEB-INF" app directory.
For start you put just these:
<<
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE tiles-definitions PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration 2.1//EN" "http://tiles.apache.org/dtds/tiles-config_2_1.dtd">

<tiles-definitions>
    <definition name="site.definition" template="/jsp/siteDefinition.jsp" />

    <definition name="page.index" extends="site.definition">
        <put-attribute name="title" value="blog" />
        <put-attribute name="header" value="/jsp/header.jsp" />
        <put-attribute name="content" value="/jsp/index.jsp" />
        <put-attribute name="footer" value="/jsp/footer.jsp" />
    </definition>

    <definition name="page.empty" extends="page.index">
        <put-attribute name="content" value="/jsp/empty.jsp" />
    </definition>

</tiles-definitions>

>>
Practically, you defined a layout with: header, content and footer that refers firstly to "/jsp/index.jsp" page and will be used as a tiles template; then, another page will extend this template by substituting the "content" page with "/jsp/empty.jsp". Later, you may add other pages that will use tiles for the View.

5.5. applicationContext.xml
This is the Spring configuration file, located unde "WEB-INF" directory. It describes how Spring uses Hibernate to connect to the database.
To have Spring and Hibernate configured, you will need at least these:
<<
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"   
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <context:annotation-config/>
    <context:component-scan base-package="blog" />

    <bean id="dsBlog" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiName" value="java:comp/env/jdbc/dsBlog" />
        <property name="resourceRef" value="true" />
    </bean>
   
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        <property name="dataSource" ref="dsBlog" />
        <property name="packagesToScan"> 
               <list>
                <value>blog.hibernate.dao.**.*</value>
               </list> 
          </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
                <prop key="hibernate.max_fetch_depth">3</prop>
                <prop key="hibernate.show_sql">false</prop>
            </props>
        </property>
    </bean>
        
    <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>   
   
    <tx:annotation-driven transaction-manager="txManager" />
</beans>

>>
So, you specified here: the DTDs used to verify Spring persistence, Spring AOP, Spring transactions, Spring annotations context; which package to scan the Spring annotations; the bean that will look for the database objects (JNDI); the session factory that will use the JNDI bean to create Spring management of the Hibernate sessions over the Hibernate annotated entities; the Spring transaction manager that will use the session factory.

5.6. context.xml

This is located under "META-INF" folder and will configure the MySQL JDBC driver for MySQL database:
<<
<?xml version="1.0" encoding="UTF-8"?>
<Context reloadable="false">
    <Resource
        auth="Container"
        name="jdbc/dsBlog"
        type="javax.sql.DataSource"
        factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
        driverClassName="org.gjt.mm.mysql.Driver"
        url="jdbc:mysql://localhost:3306/blog"
        username="root"
        password=""
        defaultAutoCommit="true"
        defaultReadOnly="false"
        defaultTransactionIsolation="READ_COMMITTED"
        jdbcInterceptors="org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer"
        fairQueue="false"
        maxActive="200"
        initialSize="20"  
        maxIdle="30"  
        minIdle="20"  
        maxWait="10000"  
        removeAbandoned="true"  
        removeAbandonedTimeout="300"
        testOnBorrow="true"
        testOnReturn="false"
        testWhileIdle="false"
        minEvictableIdleTimeMillis="30000"  
        timeBetweenEvictionRunsMillis="30000"          
        validationInterval="30000"
        validationQuery="select 1" />
</Context>

>>
You probably will not need all the properties in the resource above, so you'll have to google for the MySQL JDBC driver connectivity documentation.

5.7. log4j.properties
This is located under "src" app directory and will configure log4j to log the app errors:
<<
log4j.rootLogger=ERROR, dest1
log4j.appender.dest1=org.apache.log4j.DailyRollingFileAppender
log4j.appender.dest1.File=${catalina.home}/logs/blog.log
log4j.appender.dest1.DatePattern='.'yyyy-MM-dd
log4j.appender.dest1.layout=org.apache.log4j.PatternLayout
log4j.appender.dest1.layout.ConversionPattern=[%5p] [%t] %d{dd.MM.yyyy HH:mm:ss} %c (%F:%M:%L)%n%m%n%n

log4j.logger.blog=ERROR

log4j.logger.org.springframework=ERROR
log4j.logger.org.springframework.security=ERROR
log4j.logger.org.hibernate=ERROR
log4j.logger.org.apache=ERROR

>>
So, only ERROR type events will be logged to "${catalina.home}/logs/blog.log"; log4j will be used later by slf4j to log the individual errors of Spring, Hibernate, JDBC, aso.

6. MySQL database
The database used in the following samples, namely "blog", contains 3 tables: zone, country, city. These tables are linked by foreign keys that will create a correspondence of the kind - zones include countries and countries include cities.
Use the following script to create the MySQL "blog" database from MySQL command line prompt:
<<
CREATE DATABASE IF NOT EXISTS blog;
USE blog;


DROP TABLE IF EXISTS `zone`;
CREATE TABLE `zone` (
  `cod` varchar(4) NOT NULL,
  `name` varchar(45) NOT NULL,
  PRIMARY KEY  (`cod`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

INSERT INTO `zone` (`cod`,`name`) VALUES
 ('AS','Asia'),
 ('EU','Europe'),
 ('NA','North America'),
 ('SA','South America');


DROP TABLE IF EXISTS `country`;
CREATE TABLE `country` (
  `cod` varchar(4) NOT NULL,
  `name` varchar(45) NOT NULL,
  `cod_zone` varchar(4) NOT NULL,
  PRIMARY KEY  (`cod`),
  KEY `FK_country_zone` (`cod_zone`),
  CONSTRAINT `FK_country_zone` FOREIGN KEY (`cod_zone`) REFERENCES `zone` (`cod`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

INSERT INTO `country` (`cod`,`name`,`cod_zone`) VALUES
 ('AG','Argentina','SA'),
 ('BR','Brasil','SA'),
 ('CA','Canada','NA'),
 ('CN','China','AS'),
 ('DE','Germany','EU'),
 ('FR','France','EU'),
 ('GR','Greece','EU'),
 ('RU','Russia','AS'),
 ('US','United States','NA');

DROP TABLE IF EXISTS `city`;
CREATE TABLE `city` (
  `id` int(10) unsigned NOT NULL auto_increment,
  `cod_country` varchar(4) NOT NULL,
  `name` varchar(45) NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `FK_city_country` (`cod_country`),
  CONSTRAINT `FK_city_country` FOREIGN KEY (`cod_country`) REFERENCES `country` (`cod`)
) ENGINE=InnoDB AUTO_INCREMENT=25 DEFAULT CHARSET=latin1;


INSERT INTO `city` (`id`,`cod_country`,`name`) VALUES
 (1,'DE','Berlin'),
 (2,'DE','Dortmund'),
 (3,'DE','Munchen'),
 (4,'FR','Paris'),
 (5,'FR','Marseille'),
 (6,'FR','Bordeaux'),
 (7,'GR','Athens'),
 (8,'GR','Thesaloniki'),
 (9,'GR','Larissa'),
 (10,'US','Seattle'),
 (11,'US','New York'),
 (12,'US','Detroit'),
 (13,'US','Los Angeles'),
 (14,'CA','Toronto'),
 (15,'CA','Montreal'),
 (16,'CA','Vancouver'),
 (17,'BR','Janeiro'),
 (18,'BR','Brasil'),
 (19,'AG','Aires'),
 (20,'RU','Moscow'),
 (21,'RU','Stalingrad'),
 (22,'RU','Petersburg'),
 (23,'CN','Beijing'),
 (24,'CN','Nanjang');
>>

7. Considerations

Having all the above installed and configured, you may start to develop a JEE web app, under the MVC (Model View Controller) architecture, by using Hibernate annotated entities as Model, Struts2 + Tiles2 + JQuery as View, Struts2 for actions (Controller level) and Spring for managing the business components.