Home | | Internet & World Wide Web HOW TO PROGRAM | | Internet Programming | | Web Programming | Accessing Databases in Web Applications - JavaServer

Chapter: Internet & World Wide Web HOW TO PROGRAM - Rich Internet Application Server Technologies - Ajax-Enabled JavaServer Faces Web Applications

| Study Material, Lecturing Notes, Assignment, Reference, Wiki description explanation, brief detail |

Accessing Databases in Web Applications - JavaServer

1. Building a Web Application That Displays Data from a Database 2. Modifying the Page Bean File for the AddressBook Application

Accessing Databases in Web Applications

 

Many web applications access databases to store and retrieve persistent data. In this sec-tion, we build a web application that uses a Java DB database to store contacts in the ad-dress book and display contacts from the address book on a web page.

 

The web page enables the user to enter new contacts in a form. This form consists of Text Field components for the contact’s first name, last name, street address, city, state and zip code. The form also has a Submit button to send the data to the server and a Clear button to reset the form’s fields. The application stores the address book information in a database named AddressBook, which has a single table named Addresses. (We provide this database in the examples directory for this chapter. You can download the examples from  www.deitel.com/books/iw3htp4/). This example also introduces the Table JSF component, which displays the addresses from the database in tabular format. We show how to configure the Table component shortly.

 

1. Building a Web Application That Displays Data from a Database

 

We now explain how to build the AddressBook application’s GUI and set up a data bind-ing that allows the Table component to display information from the database. We present the generated JSP file later in the section, and we discuss the related page bean file in Section 27.2.2. To build the AddressBook application, perform the following steps:

 

Step 1: Creating the Project

In Netbeans, create a Visual Web Application project named AddressBook. Rename the JSP and page bean files to AddressBook using the refactoring tools.

 

Step 2: Creating the Form for User Input

 

In Design mode, add a Static Text component to the top of the page that reads "Add a contact to the address book:" and use the component’s style property to set the font size to 18px. Add six Text Field components to the page and rename them fnameTextField, lnameTextField, streetTextField, cityTextField, stateTextField and zipTextField. Set each Text Field’s required property to true by selecting the Text Field, then clicking the required property’s checkbox. Label each Text Field with a Label component and associate the Label with its corresponding Text Field. Finally, add a Submit and a Clear button. Set the Submit button’s primary property to true to make it stand out more on the page than the Clear button and to allow the user to submit a new contact by pressing Enter rather than by clicking the Submit button. Set the Clear button’s reset property to true to prevent validation when the user clicks the Clear button. Since we are clearing the fields, we don’t need to ensure that they contain information. We discuss the action han-dler for the Submit button after we present the page bean file. The Clear button does not need an action-handler method, because setting the reset property to true automatically configures the button to reset all of the page’s input fields. When you have finished these steps, your form should look like Fig. 27.1.


Step 3: Adding a Table Component to the Page

 

Drag a Table component from the Basic section of the Palette to the page and place it just below the two Button components. Name it addressesTable. The Table component for-mats and displays data from database tables. In the Properties window, change the Table’s title property to Contacts. We show how to configure the Table to interact with the AddressBook database shortly.

 

Step 4: Creating a Java DB Database

This example uses a database called AddressBook to store the address information. To cre-ate this database, perform the following steps:

 

1.  Select Tools > Java DB Database > Create Java DB Database….

 

2. Enter the name of the database to create (AddressBook), a username (iw3htp4) and a password (iw3htp4), then click OK to create the database.

 

(jdbc:derby://localhost:1527/AddressBook). This URL indicates that the database resides on the local machine and accepts connections on port 1527.

 

Step 5: Adding a Table and Data to the AddressBook Database

 

You can use the Runtime tab to create tables and to execute SQL statements that populate the database with data:

 

1. Click the Runtime tab and expand the Databases node.

 


2. Expand the node for the AddressBook database, right click the Tables node and select Execute Command… to open a SQL Command editor in Netbeans. We pro-vided the file AddressBook.sql in this chapter’s examples folder. Open that file in a text editor, copy the SQL statements and paste them into the SQL Command editor in Netbeans. Then, highlight all the SQL commands, right click inside the SQL Command editor and select Run Selection. This will create the Addresses tables with the sample data shown in Fig. 27.2. You may need to refresh the node of the     tab to see the new table.


Step 6: Binding the Table Component to the Addresses Table of the AddressBook

 

Database

Now that we’ve configured a data source for the Addresses database table, we can configure the Table component to display the AddressBook data. Simply drag the database table from the Servers tab and drop it on the Table component to create the binding.

 

To select specific columns to display, right click the Table component and select Bind to Data to display the Bind to Data dialog containing the list of the columns in the Addresses database table (Fig. 27.3). The items under the Selected heading will be dis-played in the Table. To remove a column, select it and click the < button. We’d like to display all the columns in this example, so you should simply click OK to exit the dialog.

 

By default, the Table uses the database table’s column names in all uppercase letters as headings. To change these headings, select a column and edit its headerText property in the Properties window. To select a column, click the column’s name in the Design mode. We also changed the id property of each column to make the variable names in the code more readable. In Design mode, your Table’s column heads should appear as in Fig. 27.4.



An address book might contain many contacts, so we’d like to display only a few at a time. Clicking the checkbox next to the table’s paginationControls property in the Prop-erties window configures this Table for automatic pagination. This adds buttons to the bottom of the Table for moving forward and backward between groups of contacts. You may use the Table Layout dialog’s Options tab to select the number of rows to display at a time. To view this tab, right click the Table, select Table Layout…, then click the Options tab. For this example, we set the Page Size property to 5.

 

Next, set the addressesTable’s internalVirtualForm property. Virtual forms allow subsets of a form’s input components to be submitted to the server. Setting this property prevents the pagination control buttons on the Table from submitting the Text Fields on the form every time the user wishes to view the next group of contacts. Virtual forms are discussed in Section 27.4.1.

 

Binding the Table to a data provider added a new addressesDataProvider object (an instance of class CachedRowSetDataProvider) to the AddressBook node in the Outline window. A CachedRowSetDataProvider provides a scrollable RowSet that can be bound to a Table component to display the RowSet’s data. This data provider is a wrapper for a CachedRowSet object. If you click the addressesDataProvider element in the Outline window, you’ll see in the Properties window that its CachedRowSet property is set to addressesRowSet, an object (in the session bean) that implements interface CachedRowSet.

 

Step 7: Modifying addressesRowSet’s SQL Statement

The CachedRowSet object wrapped by our addressesDataProvider is configured by default to execute a SQL query that selects all the data in the Addresses table of the Ad-dressBook database. You can edit this SQL query by expanding the SessionBean node in the Outline window and double clicking the addressesRowSet element to open the query editor window (Fig. 27.5). We’d like to edit the SQL statement so that records with du-plicate last names are sorted by last name, then by first name. To do this, click in the Sort Type column next to the LASTNAME row and select Ascending. Then, repeat this for the FIRSTNAME row. Notice that the expression

 

ORDER BY IW3HTP4.ADDRESSES.LASTNAME ASC,

 

IW3HTP4.ADDRESSES.FIRSTNAME ASC

 

was added to the SQL statement at the bottom of the editor.

 

Step 8: Adding Validation

It is important to validate the form data on this page to ensure that the data can be suc-cessfully inserted into the AddressBook database. All of the database’s columns are of type varchar (except the ID column) and have length restrictions. For this reason, you should


either add a Length Validator to each Text Field component or set each Text Field compo-nent’s maxLength property. We chose to set the maxLength property of each. The first name, last name, street, city, state and zip code Text Field components may not exceed 30, 30, 150, 30, 2 and 5 characters, respectively.

 

Finally, drag a Message Group component onto your page to the right of the Text Fields. A Message Group component displays system messages. We use this component to display an error message when an attempt to add a contact to the database fails. Set the Message Group’s showGlobalOnly property to true to prevent component-level valida-tion error messages from being displayed here.

 

JSP File for a Web Page That Interacts with a Database

The JSP file for the application is shown in Fig. 27.6. This file contains a large amount of generated markup for components you learned in Chapter 26. We discuss the markup for only the components that are new in this example.

 

24  <?xml version="1.0" encoding="UTF-8"?>

 

25  <!-- Fig. 27.6: AddressBook.jsp -->

 

26  <!-- AddressBook JSP with an add form and a Table JSF component. -->

 

27  <jsp:root version="1.2"

 

28        xmlns:f="http://java.sun.com/jsf/core"

 

29        xmlns:h="http://java.sun.com/jsf/html"

 

30        xmlns:jsp="http://java.sun.com/JSP/Page"

 

31        xmlns:webuijsf="http://www.sun.com/webui/webuijsf">

 

32        <jsp:directive.page contentType="text/html;charset=UTF-8"

 

pageEncoding="UTF-8"/>

11        <f:view>

 

12        <webuijsf:page binding="#{AddressBook.page1}" id="page1">

 

13        <webuijsf:html binding="#{AddressBook.html1}" id="html1">

 

14        <webuijsf:head binding="#{AddressBook.head1}" id="head1">

 

15        <webuijsf:link binding="#{AddressBook.link1}" id="link1"

16        url="/resources/stylesheet.css"/>

 

17        </webuijsf:head>

 

18        <webuijsf:body binding="#{AddressBook.body1}" id="body1"

 

 

19        style="-rave-layout: grid">

20        <webuijsf:form binding="#{AddressBook.form1}" id="form1">

21        <webuijsf:staticText binding="#{AddressBook.staticText1}"

22        id="staticText1" style="font-size: 18px; left: 24px;

23        top: 24px; position: absolute"

24        text="Add a contact to the address book:"/>

25        <webuijsf:label binding="#{AddressBook.fnameLabel}"

26        for="fnameTextField" id="fnameLabel" style=

27        "position: absolute; left: 24px; top: 72px"

28        text="First name:"/>

29        <webuijsf:textField binding="#{AddressBook.fnameTextField}"

30        id="fnameTextField" maxLength="30" required="true"

31        style="left: 100px; top: 72px; position: absolute;

32        width: 192px"/>

33        <webuijsf:label binding="#{AddressBook.lnameLabel}"

34        for="lnameTextField" id="lnameLabel" style="left: 312px;

35        top: 72px; position: absolute" text="Last name:"/>

36        <webuijsf:textField binding="#{AddressBook.lnameTextField}"

37        id="lnameTextField" maxLength="30" required="true"

38        style="left: 390px; top: 72px; position: absolute;

39        width: 214px"/>

40        <webuijsf:label binding="#{AddressBook.streetLabel}"

41        for="streetTextField" id="streetLabel" style="position:

42        absolute; left: 24px; top: 96px" text="Street:"/>

43        <webuijsf:textField binding=

44        "#{AddressBook.streetTextField}" id="streetTextField"

45        maxLength="150" required="true" style="left: 100px;

46        top: 96px; position: absolute; width: 504px"/>

47        <webuijsf:label binding="#{AddressBook.cityLabel}"

48        for="cityTextField" id="cityLabel" style="left: 24px;

49        top: 120px; position: absolute" text="City:"/>

50        <webuijsf:textField binding="#{AddressBook.cityTextField}"

51        id="cityTextField" maxLength="30" required="true"

52        style="left: 100px; top: 120px; position: absolute;

53        width: 240px"/>

54        <webuijsf:label binding="#{AddressBook.stateLabel}"

55        for="stateTextField" id="stateLabel" style="left: 360px;

56        top: 120px; position: absolute" text="State:"/>

57        <webuijsf:textField binding="#{AddressBook.stateTextField}"

58        id="stateTextField" maxLength="2" required="true"

59        style="left: 412px; top: 120px; position: absolute;

60        width: 48px"/>

61        <webuijsf:label binding="#{AddressBook.zipLabel}"

62        for="zipTextField" id="zipLabel" style="left: 490px;

63        top: 120px; position: absolute" text=" Zip:"/>

64        <webuijsf:textField binding="#{AddressBook.zipTextField}"

65                                id="zipTextField" maxLength="5" required="true"                          

66                                style="left: 534px; top: 120px; position: absolute;

67                                width: 70px"/>                                   

68        <webuijsf:button actionExpression=                         

69                                "#{AddressBook.submitButton_action}" binding=                          

70                                "#{AddressBook.submitButton}" id="submitButton"                                 

71                                primary="true" style="left: 100px; top: 168px;                                 

72                                position: absolute; width: 100px" text="Submit"/>

73        <webuijsf:button binding="#{AddressBook.clearButton}"

74                                id="clearButton" reset="true" style="left: 215px; top:

75                                168px; position: absolute; width: 100px" text="Clear"/>

76        <webuijsf:messageGroup binding=                           

77                                "#{AddressBook.messageGroup1}" id="messageGroup1"

78                                showGlobalOnly="true" style="left: 624px; top: 72px;

79                                position: absolute"/>                          

80                    <webuijsf:table augmentTitle="false" binding=                                

81                                "#{AddressBook.addressesTable}" id="addressesTable"                 

82                                paginateButton="true" paginationControls="true"                            

83                                style="left: 24px; top: 216px; position: absolute"                  

84                                title="Contacts" width="816">                                 

85                                <webuijsf:tableRowGroup binding=                         

86                                "#{AddressBook.tableRowGroup1}" id="tableRowGroup1"          

87                                rows="5"                                

88                                sourceData="#{AddressBook.addressesDataProvider}"      

89                                sourceVar="currentRow">                            

90                                <webuijsf:tableColumn binding=                              

91                                "#{AddressBook.fnameColumn}" headerText=                               

92                                "First Name" id="fnameColumn"                              

93                                sort="ADDRESSES.FIRSTNAME">                                  

94                                <webuijsf:staticText binding=                                   

95                                "#{AddressBook.staticText2}" id="staticText2"      

96                                text="#{currentRow.value[                           

97                                'ADDRESSES.FIRSTNAME']}"/>                          

98                                </webuijsf:tableColumn>                              

99                                <webuijsf:tableColumn binding=                              

100                              "#{AddressBook.lnameColumn}"                             

101                              headerText="Last Name" id="lnameColumn"                                   

102                              sort="ADDRESSES.LASTNAME">                                   

103                              <webuijsf:staticText binding=                                   

104                              "#{AddressBook.staticText3}" id="staticText3"

105                              text="#{currentRow.value[                           

106                              'ADDRESSES.LASTNAME']}"/>                           

107                              </webuijsf:tableColumn>                              

108                              <webuijsf:tableColumn binding=                              

109                              "#{AddressBook.streetColumn}" headerText="Street"

110                              id="streetColumn" sort="ADDRESSES.STREET">                        

111                              <webuijsf:staticText binding=                                   

112                              "#{AddressBook.staticText4}" id="staticText4"

113                              text="#{currentRow.value[                           

114                              'ADDRESSES.STREET']}"/>                                   

115                              </webuijsf:tableColumn>                              

            116      <webuijsf:tableColumn binding=

117      "#{AddressBook.cityColumn}" headerText="City"

118      id="cityColumn" sort="ADDRESSES.CITY">

119      <webuijsf:staticText binding=

120      "#{AddressBook.staticText5}" id="staticText5"

121      text="#{currentRow.value['ADDRESSES.CITY']}"/>

122      </webuijsf:tableColumn>

123      <webuijsf:tableColumn binding=

124      "#{AddressBook.stateColumn}" headerText="State"

125      id="stateColumn" sort="ADDRESSES.STATE">

126      <webuijsf:staticText binding=

127      "#{AddressBook.staticText6}" id="staticText6"

128      text="#{currentRow.value['ADDRESSES.STATE']}"/>

129      </webuijsf:tableColumn>

130      <webuijsf:tableColumn binding=

131      "#{AddressBook.zipColumn}" headerText="Zip"

132      id="zipColumn" sort="ADDRESSES.ZIP" width="106">

133      <webuijsf:staticText binding=

134      "#{AddressBook.staticText7}" id="staticText7"

135      text="#{currentRow.value['ADDRESSES.ZIP']}"/>

136      </webuijsf:tableColumn>

137      </webuijsf:tableRowGroup>

138      </webuijsf:table>

139      </webuijsf:form>

 

140      </webuijsf:body>

 

141      </webuijsf:html>

 

142      </webuijsf:page>

 

143      </f:view>

 

144      </jsp:root>



Fig. 27.6 | AddressBook JSP with an add form and a Table JSF component

Lines 21–75 contain the JSF components for the form that gathers user input. Lines 80–138 define the Table element (webuijsf:table) that displays address information from the database. JSF Tables may have multiple groups of rows displaying different data. This Table has a single webuijsf:tableRowGroup with a start tag in lines 85–89. The row group’s sourceData attribute is bound to our addressesDataProvider and given the variable  name  currentRow.  The  row  group  also  defines  the  Table’s  columns.  Each webuijsf:tableColumn element (e.g., lines 90–98) contains a webuijsf:staticText element with its text attribute bound to a column in the data provider currentRow. These webuijsf:staticText elements enable the Table to display each row’s data.

 

Session Bean for the AddressBook Application

Figure 27.7 displays the SessionBean1.java file generated by Netbeans for the Address-Book application. The CachedRowSet that the Table component’s data provider uses to ac-cess the AddressBook database is a property of this class (lines 31–41).

 

// Fig. 27.7: SessionBean1.java

 

// Session bean that initializes the data source for the

 

// AddressBook database.

 

package addressbook;

import com.sun.rave.web.ui.appbase.AbstractSessionBean;

 

import com.sun.sql.rowset.CachedRowSetXImpl;

 

import javax.faces.FacesException;


public class SessionBean1 extends AbstractSessionBean

{

 

private int __placeholder;

 

private void _init() throws Exception

{

 

addressesRowSet.setDataSourceName(

 

"java:comp/env/jdbc/dataSource" );

 

addressesRowSet.setCommand(

 

"SELECT ALL IW3HTP4.ADDRESSES.FIRSTNAME, \n" +

 

"IW3HTP4.ADDRESSES.LASTNAME, \n" +

 

"IW3HTP4.ADDRESSES.STREET, \n" +

 

"IW3HTP4.ADDRESSES.CITY, \n" +

 

"IW3HTP4.ADDRESSES.STATE, \n" +

 

"IW3HTP4.ADDRESSES.ZIP \n" +

 

"FROM IW3HTP4.ADDRESSES\n" +

 

"ORDER BY IW3HTP4.ADDRESSES.LASTNAME ASC, \n" +

 

"IW3HTP4.ADDRESSES.FIRSTNAME ASC " );

 

addressesRowSet.setTableName( "ADDRESSES" );

 

} // end method _init

 

private CachedRowSetXImpl addressesRowSet = new CachedRowSetXImpl();

 

public CachedRowSetXImpl getAddressesRowSet()

{

 

return addressesRowSet;

}

 

public void setAddressesRowSet( CachedRowSetXImpl crsxi )

{

 

this.addressesRowSet = crsxi;

}

// To save space, we omitted the code in lines 42-78. The complete

 

// source code is provided with this chapter's examples.

  } // end class SessionBean1

 

Fig. 27.7 | Session Bean that initializes the data source for the AddressBook database.

 

The _init method (lines 14–29) configures addressesRowSet to interact with the AddressBook database (lines 16–28). Lines 16–17 connect the row set to the database. Lines 18–27 set addressesRowSet’s SQL command to the query configured in Fig. 27.5. Line 28 sets the RowSet’s table name.

 

2. Modifying the Page Bean File for the AddressBook Application

 

After building the web page and configuring the components used in this example, double click the Submit button to create an action event handler for this button in the page bean file. The code to insert a contact into the database will be placed in this method. The page bean with the completed event handler is shown in Fig. 27.8 below.

30  // Fig. 27.8: AddressBook.java

 

31  // Page bean for AddressBook.jsp.

 

32  package addressbook;

4

1     import com.sun.data.provider.RowKey;

 

2     import com.sun.data.provider.impl.CachedRowSetDataProvider;

 

3     import com.sun.rave.web.ui.appbase.AbstractPageBean;

 

4     import com.sun.webui.jsf.component.Body;

 

5     import com.sun.webui.jsf.component.Button;

 

6       import com.sun.webui.jsf.component.Form;

 

7       import com.sun.webui.jsf.component.Head;

 

8       import com.sun.webui.jsf.component.Html;

 

9       import com.sun.webui.jsf.component.Label;

 

10    import com.sun.webui.jsf.component.Link;

 

11    import com.sun.webui.jsf.component.MessageGroup;

 

12    import com.sun.webui.jsf.component.Page;

 

13    import com.sun.webui.jsf.component.StaticText;

 

14    import com.sun.webui.jsf.component.Table;

 

15    import com.sun.webui.jsf.component.TableColumn;

 

16    import com.sun.webui.jsf.component.TableRowGroup;

 

17    import com.sun.webui.jsf.component.TextField;

 

18    import com.sun.webui.jsf.model.DefaultTableDataProvider;

 

19    import javax.faces.FacesException;

24

15    public class AddressBook extends AbstractPageBean

16    {

 

17          private int __placeholder;

28

21          private void _init() throws Exception

22          {

 

23                 addressesDataProvider.setCachedRowSet(

 

24                       ( javax.sql.rowset.CachedRowSet ) getValue(

1                                 "#{SessionBean1.addressesRowSet}" ) );

 

2                    addressesTable.setInternalVirtualForm( true );

 

3             } // end method _init

36

89          // To save space, we omitted the code in lines 37-505. The complete

 

90          // source code is provided with this chapter's examples.

39

13          public void prerender()

14          {

 

15                 addressesDataProvider.refresh();

 

16          } // end method prerender

510

22          public void destroy()

23          {

 

24                 addressesDataProvider.close();

 

25          } // end method destroy

515

1             // To save space, we omitted the code in lines 516-530. The complete

 

2             // source code is provided with this chapter's examples.

518

 

1     // action handler that adds a contact to the AddressBook database

 

2              // when the user clicks Submit

 

3              public String submitButton_action()

4              {

 

5                     if ( addressesDataProvider.canAppendRow() )

6                     {

7                           try

8                           {

 

9                                 RowKey rk = addressesDataProvider.appendRow();

 

addressesDataProvider.setCursorRow( rk );

542      addressesDataProvider.setValue( "ADDRESSES.FIRSTNAME",

 

fnameTextField.getValue() );            

543                             

544      addressesDataProvider.setValue( "ADDRESSES.LASTNAME",              

545      lnameTextField.getValue() );             

546      addressesDataProvider.setValue( "ADDRESSES.STREET",                      

547      streetTextField.getValue() );              

548      addressesDataProvider.setValue( "ADDRESSES.CITY",               

549      cityTextField.getValue() );                

550      addressesDataProvider.setValue( "ADDRESSES.STATE",            

551      stateTextField.getValue() );               

552      addressesDataProvider.setValue( "ADDRESSES.ZIP",                  

553      zipTextField.getValue() );                  

554      addressesDataProvider.commitChanges();                

555                             

556      // reset text fields

 

557      lnameTextField.setValue( "" );

 

558      fnameTextField.setValue( "" );

 

559      streetTextField.setValue( "" );

 

560      cityTextField.setValue( "" );

 

561      stateTextField.setValue( "" );

 

562      zipTextField.setValue( "" );

563      } // end try

 

564      catch ( Exception ex )

565      {

 

566      error( "The address book was not updated.  " +

567      ex.getMessage() );

 

568      } // end catch

569      } // end if

570

571      return null;

 

572      } // end method submitButton_action

 

573      } // end class AddressBook

 

Fig. 27.8 | Page bean for adding a contact to the address book.

 

Lines 533–572 contain the event-handling code for the Submit button. Line 535 determines whether a new row can be appended to the data provider. If so, a new row is appended at line 539. Every row in a CachedRowSetDataProvider has its own key; method appendRow returns the key for the new row. Line 540 sets the data provider’s cursor to the new row, so that any changes we make to the data provider affect that row. Lines 542–553 set each of the row’s columns to the values entered by the user in the cor responding Text Fields. Line 554 stores the new contact by calling method commitChanges of class CachedRowSetDataProvider to insert the new row into the AddressBook database.

 

Lines 557–562 clear the form’s Text Fields. If these lines are omitted, the fields will retain their current values after the database is updated and the page reloads. Also, the Clear button will not work properly if the Text Fields are not cleared. Rather than emptying the Text Fields, it resets them to the values they held the last time the form was submitted.

 

Lines 564–568 catch any exceptions that might occur while updating the Address-Book database. Lines 566–567 display a message indicating that the database was not updated as well as the exception’s error message in the page’s MessageGroup component.

 

In method prerender, line 508 calls CachedRowSetDataProvider method refresh.

 

This re-executes the wrapped CachedRowSet’s SQL statement and re-sorts the Table’s rows so that the new row is displayed in the proper order. If you do not call refresh, the new address is displayed at the end of the Table (since we appended the new row to the end of the data provider). The IDE automatically generated code to free resources used by the data provider (line 513) in the destroy method.



Study Material, Lecturing Notes, Assignment, Reference, Wiki description explanation, brief detail


Copyright © 2018-2020 BrainKart.com; All Rights Reserved. Developed by Therithal info, Chennai.