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.

27 comments:

  1. it s nice posting and i can understand easily above steps.
    could you please send me code for this sample without lib.

    thanks,
    nandha

    nandhamyr@gmail.com

    ReplyDelete
    Replies
    1. That great example,
      Could you send me source code
      Thien
      thiennew2009@yahoo.com

      Delete
  2. Hi nandha - done, check the email.

    ReplyDelete
  3. getting error when adding
    <<
    @ParentPackage("blog-json")
    >>

    could you please send me code for this sample without lib for me as well.
    mailid: madhuparimi2003@gmail.com

    thanks
    madhu

    ReplyDelete
  4. done madhu, check the mail, sorry for being so late

    ReplyDelete
  5. I also appreciate this article, altough i also need the code of the same without lib, kindly send me on saurabhneekhra@yahoo.co.in,
    Many Thanks !!

    ReplyDelete
  6. Hi Vsorinel,

    I got the code, it was a big help for me, Apart from this I was using DisplayTag library in my application, which i am not able to run properly. the page having dosplayTag code is not getting rendered. It would be nice if you have any working code with the displayTag for any data table display same in Struts2. Thanks :)

    ReplyDelete
  7. Hi nikh, the DisplayTag was designed to be used with Struts1; however, with small updates it may be used with Struts2 also; to get the code rendered, you have to be sure you are not using any Struts2 tags before using the displayTag - more exactly - remove all the struts2 tags that you written at the head of displayTag; will send you soon a struts2 sample of using displayTag.

    ReplyDelete
  8. @Nikh: Some hints regarding the use of DisplayTag you may find here: http://vsorinel.blogspot.com/2011/07/struts2-tiles2-spring-hibernate-jquery.html

    ReplyDelete
  9. Looks good !!!
    Can you please send me the source code to search2006@rediffmail.com without lib ?

    ReplyDelete
  10. Thanks for sharing your knowledge.

    Can you please send me the source code in order to better understand what you are explaining.

    cquezadav@hotmail.com

    Thank you very much in advance.

    ReplyDelete
  11. Please send code with lib.

    sannanaidu.s@inbox.com

    Thanks You,

    ReplyDelete
  12. Thanks for sharing your knowledge.

    Can you please send me the source code in order to better understand what you are explaining.

    sannanaidu.s@inbox.com

    Thank you very much in advance.

    ReplyDelete
  13. Thanks for sharing your knowledge.

    Can you please send me the source code in order to better understand what you are explaining.

    sannanaidu.s@inbox.com

    Thank you very much in advance.

    ReplyDelete
  14. Thanks for sharing your knowledge.

    Can you please send me the source code in order to better understand what you are explaining.

    sasschowdary@gmail.com

    Thank you very much in advance.

    ReplyDelete
  15. @sass, sannanaidu: I cannot send you all the librairies; the ones described at General Considerations (Struts 2, Spring, Hibernate, aso) have about 550MB. You may find these on the net, just google for'em.
    The code you requested I just mailed; the 3rd party internal librairies required for jquery and autocompleters are included in the archive (blogac.zip).

    ReplyDelete
  16. thanks for giving this tutorial. i want full source code. in my application i want to show all countries. when one country selected that particular country states will be showed. so i want total application. plz as soon as possible send it to me.

    reddy90143@gmail.com

    Thank you very much in advance

    ReplyDelete
  17. Nice tutorial.
    Thank you for taking time to write this very helpful tutorial.
    Please, can you send me the complete code of all the 4 series of the tutorial (obviously without the libs).
    My email: softcons99@yahoo.com
    Many Thanks,
    Kwame

    ReplyDelete
  18. hi can you please send me the source code of this article into the adresse mail swallow55@hotmail.fr


    thks

    ReplyDelete
  19. i am using struts2 hibernate for my project,i want email autocomplete in compose mail.mails from database,please help me

    ReplyDelete
    Replies
    1. @venkat: I only can send you the code for the sample above; you may change the code in the way you need; for example you may use RegExp to validate the email autocompleter; to send you the code above I need your email address, as I couldn't find it on your profile.

      Delete
  20. mohdwasim2008@gmail.com
    plz send complete code

    ReplyDelete
  21. Hi,

    It looks great but I can't manage to make it work. Could you send me the code also please?

    hacotjerome@gmail.com

    Thx in advance.
    Regards,

    Jerome

    ReplyDelete
  22. Hi,

    This is one of the best blog it like to read.
    Can you also help me with source code plase.
    Email-dev.pandey@gmail.com

    Dev

    ReplyDelete
  23. Hi all,
    I know there were guys that wanted the code and probably I couldn't send them the code in useful time. First of all I want to apologize to all these guys.
    Second, due to latest activity, I really have no time to maintain this blog, so I want you guys understand I CANNOT SEND THE CODE ANYMORE.
    In this case, you have 2 solutions:
    1) the main aspects for each sample are already posted on respective topics; practically, if you read the "general considerations" and the related topics, you will not need the code; you just need to configure a new app and paste there the code from the topics;
    2) if you really want the code, then ALL THE GUYS THAT PUT THEIR EMAILS ON THE COMMENTS ABOVE HAVE RECEIVED THE CODE; so, if I cannot respond, then maybe they can ;) in fact, it is a distributable code, isn't it ? ;)
    I hope you guys understand the above, thanx, vsorinel.

    ReplyDelete
  24. Nice work. Can you please send me the source code of this example. My email id is:- cmr.ashok@gmail.com

    ReplyDelete