Pages

Advertisement

Wednesday, December 10, 2008

SQL Tips For Oracle Pivots

Every SQL writer has at times wanted to write a Select statement that presented the data horizontally as a series of columns rather than vertically as a series rows.  Displaying the data as a series of columns rather than roles is called pivoting.  In order to accomplish pivoting the SQL writer had to employ various coding techniques such as unioned Select statements or using the Case statement.  Oracle 11g has given us a new operator called Pivot that allows us to pivot data with a much smaller statement.  This article describes how to use this operator in your statements.

First let's look at some sample data.  Listing 1 portrays a Select statement that displays the number of employees in the various departments.  The statement displays the employee count as a series of rows.  Each row displays a particular department and the employee count.  Notice that an in-line view was needed to compute the employee count and the in-line view result set was joined to the Department table.  This is done because there are some departments without employees and a dense result set is desired.  The new Pivot operator also allows you to generate a dense result set, but in a different manner.

 

select department, nvl(cnt,0) cnt
from department
  left join (select fk_department, count(*) cnt
             from employee
             group by fk_department) on (department = fk_department)


DEPARTMENT     CNT                   
---------------------      ------
WEL                        6                     
INT                          7                     
POL                        8                     
CEN                        0                     
                     

5 rows selected

            
Traditionally data was pivoted using the Decode function, Case statements, or unioned Select statements.  The latter technique is illustrated in Listing 2.  The listing contains an in-line view that has a unioned select statement for each pivoted value (i.e distinct department value).  Each statement consists of an aggregation of the target value (i.e. employees).  The resulting aggregation is displayed in one of the statement's columns.  Each statement contains an expression for each of the pivoted columns, but only the column that pertains to the statement's Where clause value is populated.  The unioned result sets are then summarized by the outer statement creating the pivoted result set.  The main problem with this technique is the need to pre-define each column and select statement.  
 



select sum(int) int, sum(wel) wel, sum(cen) cen, sum(pol) pol
from
 (select count(*) INT, 0 WEL, 0 CEN, 0 POL
 from employee
 where fk_department = 'INT'
union
 select 0, count(*), 0, 0
 from employee
 where fk_department = 'WEL'
union
 select 0, 0, count(*), 0
 from employee
 where fk_department = 'CEN'
union
 select 0, 0, 0, count(*)
 from employee
 where fk_department = 'POL')

 

INT     WEL   CEN   POL                   
-------- -------- --------- --------
      7       6         0       8                    
  
 

1 rows selected


Oracle 11g has given us the Pivot and Unpivot operators.  These operators help in reducing the amount of code but do not solve the problem most developers would like solved, computing dynamic columns.  Developers have long wanted a statement that dynamically creates the needed columns rather than having to code for each value.  Unfortunately the new operator does not do this either.  However, the operators might help in reducing the amount of code that must be written.  For this reason, its good to look at them.

Below is a template of the Pivot operator along with a description of its parameters.  The Unpivot operator is shown later in this article.

XML                          - This parameter causes the result set to be returned in XML format
Aggregate function     - The aggregate function (i.e. sum, count, min, max)  used to compute the pivot matrix value.
Expression                - The aggregated column
Alias                         -  Aggregate column alias
Column_list               -  The column whose values determine the pivot location
Subquery                  -  The Pivot expression columns

PIVOT [XML] (<aggregate function> (expression) [AS<alias>]
FOR (<column_list>)
IN <subquery>)

Listing 3 depicts the Pivot operator.  The statement produces the same result set as the traditional statement shown in Listing 2.  The statement produces a row that displays a count of the INT, WEL, CEN, and POL department employees.  The statement is placed in an in-line view.  Notice that Fk_department values are placed in the Subquery parameter list.  The values in this list determine the columns in the Pivot table.  The select statement above the Pivot operator actually produces more Fk_department values than are listed in the Subquery parameter list.  The For clause matches the aggregated FK_department values produced by the upper query to the values in the Subquery list.  If a value does not exist in the Subquery list, it is not displayed as a column.
 

select *
from
  (select fk_department
   from employee)
   pivot
    (count(fk_department)
      for fk_department in ('INT', 'WEL', 'CEN', 'POL'));

 

'INT'         'WEL'       'CEN'     'POL'                                                                            
----------    ----------   ----------  ----------                                                                             
        7            6            0          8                                                       
                     


Finer aggregated matrix values can also be displayed by adding additional columns to the master Select list and not listing them in the Pivot clause.  The additional values that increase the aggregation grain are displayed on the Y-Axis.  This is shown in Listing 4.  The statement displays department wages by current position. The Fk_department values are displayed along the X-Axis as headings.  The current positions are displayed in the first column or Y-Axis.  The sum of wages values are displayed in the matrix area. Notice the statement is essentially the same as Listing 3 except for the inclusion of the Current_positions column.

 

select *
 from
  (select current_position, fk_department, wages
   from employee)
   pivot
   (sum(wages)
     for fk_department in ('INT', 'WEL', 'CEN', 'POL'));
 


CURRENT_POSITIO    'INT'      'WEL'     'CEN'      'POL'                                                            
-----------------------------    ----------   ----------   ----------   ----------                                                            
VICE PRESIDENT         9500       8500                                                                                  
LABORER 3                13000                                                                                  
SALESPERSON 1                                                7500                                                            
JANITOR                       9500                                                                                             
CLERK 2                     14000                                                                                             
TREASURER                                                      12500                                                             
...                                                                          
SYSTEM ANALYST                                                                                                         
TREASURER CLERK                                           12000                                                            
CLERK 1                                                             25400                                                            
MAINT. MAN 2             10000                                                                                  
ADMINISTRATOR                                                   9800                                                             

 


The example statement shown in Listing 5 illustrates that multiple matrix aggregations can be included in the statement.  The Listing 4 statement was modified with the inclusion of a count value.  The statement now displays department wages and employee counts by current position.  A numeric literal value was added to the select clause and a summary function added to the Pivot clause.  The additions are bolded.

Listing 5 - Department wages and employee count by current position
 

SQL> select *
  2  from
  3  (select current_position, fk_department, wages, 1 cnt
  4  from employee)
  5  pivot
  6  (sum(wages) as wages, sum(cnt) as count
  7    for fk_department in ('INT', 'WEL', 'CEN', 'POL'));

 

CURRENT_POSITIO  'INT'_WAGES  'INT'_COUNT  'WEL'_WAGES  'WEL'_COUNT  'CEN'_WAGES  'CEN'_COUNT  'POL'_WAGES  'POL'_COUNT        
-----------------------------   -------------------   ------------------  ----------------------   --------------------   ---------------------   --------------------  ----------------------  --------------------        
VICE PRESIDENT                 9500                    1                8500                     1                                                        
LABORER 3                                                                    13000                      1                                                        
SALESPERSON 1                                                                                                                                                           7500                     1        
JANITOR                               9500                    1                                                                                
CLERK 2                              14000                   1                                                                                 
...                                          
TREASURER CLERK                                                                                                                                                     12000                     1        
CLERK 1                                                                                                                                                                       25400                     2        
MAINT. MAN 2                                                                 10000                      1                                                        
ADMINISTRATOR                                                                                                                                                             9800                    1        


Let's now look at the Unpivot operator.  This operator does the opposite of the Pivot operator.  It takes values displayed on a single row and moves them into a series of rows.  A template of the operator follows as well as a description of the parameters.

Include|Exclude Nulls                 - Determines whether null column values are displayed as a row.  
Column list                                - The matix column
For column list                           - The heading for the X-Axis column values
In column list                             -  The X-Axis columns

UNPIVOT [<INCLUDE | EXCLUDE> NULLS] (<column_list>) FOR (<column_list>)
IN (<column_list>) [AS (<constant_list>)])

The first step is to generate a result set that can be unpivoted.  Listing 6 displays a statement that creates a view using one of the earlier example select statements (Listing 40.  The view creates a pivot table of department wages by current position.

Listing 6 - Department wages by current position view
 

create view pivotTable as
  select *
  from
  (select current_position, fk_department, wages
  from employee)
  pivot
  (sum(wages)
  for fk_department in ('INT' as int, 'WEL' as wel,
   'CEN' as cen, 'POL' as pol));


View created.


Now let's unpivot the result set.  Listing 7 shows a select statement with the unpivot operator.  The statement begins with a Select statement against the view created in Listing 6.  Notice the following:

1.  The "Include Nulls" option was used.  If a department current position did not have wages, the row is included anyway
2.  The parameter values in the column list were column names not literal values that we have seen in other examples.
3.  There are no summary functions used in the Unpivot clause.

Listing 7 - Using the Unpivot operator to create rows

 SQL> select *
  2  from pivotTable
  3  unpivot include nulls
  4  (wages for fk_department in (INT, WEL, CEN, POL));

 

CURRENT_POSITIO             FK_      WAGES                                                                                         
-----------------------------------------  ---------   ----------                                                                                         
VICE PRESIDENT                INT           9500                                                                                         
VICE PRESIDENT                WEL        8500                                                                                         
VICE PRESIDENT                CEN                                                                                                    
VICE PRESIDENT                POL                                                                                                    
LABORER 3                         INT                                                                                                    
LABORER 3                         WEL      13000                                                                                         
LABORER 3                         CEN                                                                                                     
...                                                                                         
TREASURER CLERK            INT                                                                                                    
TREASURER CLERK            WEL                                                                                                    
TREASURER CLERK            CEN                                                                                                    
TREASURER CLERK            POL      12000                                                                                         
CLERK 1                              INT                                                                                                    
CLERK 1                              WEL


Technorati Tags:

Monday, February 11, 2008

Router Hangs due to Azureus

Mostly every torrent downloader requires to connect to more peers and seeds so it makes changes to windows tcpip config file to more than the maximum number of connections allowed ... some of the possibilities would be ... and i mentioned how to make your Internet stable ..

You have limited your upload speed ?
Install your old version of Azureus and test again. If the problem goes away either update to Azureus CVS (simply replace azuerus2.jar) and retest.
A colleague guessed that maybe Azureus was causing my router to crash?
Quite likely. If the above doesn't fix the issue, try each step below, restart the client and test after each step.


1) Open the UpNP tab and see what the messages are
2) Disable uPnP at client
3) Ensure DHT UDP port is forwarded to the client, not just open the port but forward also.
4) Disable DHT at client (DHT overwhelms some routers with connections)
4) Set your network adaptor and IP in Advnaced Network settings and specify ports

Hiding whole web page & displaying image instead of it during Ajax processing ..

When a WebGrid triggers an AJAX request, there is a delay until the request completes and is displayed on the client. In some cases, the programmer will want to hide or otherwise disable input on the WebGrid until this processing finishes. This article shows how to display an image or other "Loading" message while these requests process.

Additional Information

You can use the WebGrid’s BeforeXmlHttpRequest and AfterXmlHttpResponse client-side events to hide the grid and display a loading message.
Note that these events are only raised when an AJAX request is created by the WebGrid itself, not when processing custom AJAX requests.
This approach only works in NetAdvantage 2006 Volume 1 and later. In previous versions, the WebGrid is non-responsive during the BeforeXmlHttpRequest event.

Step-By-Step Example

The following functions hide the WebGrid and display an image when an AJAX request from the WebGrid starts, and hides the image and displays the WebGrid when the AJAX response finishes processing. In this example, both "grd" and "loadinggif" are the IDs of DIV elements which respectively contain the WebGrid and the loading image.
In JavaScript:

function grid_BeforeXmlHttpRequest(gridName,type)
{
    document.getElementById("grd").style.visibility = 'hidden';
    document.getElementById("loadinggif").style.visibility = 'visible';
}
function UltraWebGrid1_AfterXmlHttpResponseProcessed(gridName)
{
    document.getElementById("grd").style.visibility = 'visible';
    document.getElementById("loadinggif").style.visibility = 'hidden';
}

When both these DIV elements are positioned identically, it appears as though the image replaces the grid for the period it takes to process the AJAX request and response .

Sample Downloads

kb_displayloadingimageduringxmlrequests_cs.zip

Demonstrates replacing a WebGrid with a loading image while processing an AJAX request

Fade in Animation in Asp.net

Animation Using Ajax Toolkit

While the AJAX Control Toolkit is focused primarily on providing great AJAX controls and extenders, it also includes a powerful animation framework which you can use to add awesome visual effects on your pages. This walkthrough describes the basics of using this framework to create declarative animations.

The animations are implemented in JavaScript as an ASP.NET AJAX class hierarchy and can be invoked via JavaScript by calling the Animation's play function. This is very useful when writing to the animation classes from code, but writing complex animations ends up being time consuming and error prone. To make it very easy to use the animation framework without writing any JavaScript, the Toolkit provides the ability to declare animations via XML markup.

Extenders with animation support, like the AnimationExtender, expose various events, like OnClick, that can be associated with a generic XML animation declaration. Within this declaration, you specify which types of animation effects you would like to occur. For example, to make a Panel with ID = "MyPanel" disappear from the page when clicked, you could add an AnimationExtender like this:

<ajaxToolkit:AnimationExtender id="MyExtender"
runat="server" TargetControlID="MyPanel">
<Animations>
<OnClick>
<FadeOut Duration=".5" Fps="20" />
</OnClick>
</Animations>
</ajaxToolkit:AnimationExtender>



Let's take a closer look at exactly what's going on in the XML above. The AnimationExtender is used to indicate that we want to make our animation target the control with ID = "MyPanel". The Animations section is where all generic animations are declared. OnClick indicates that when the target is clicked we will play the animation nested inside it. Finally, FadeOut defines the specific animation that will be played and sets the values of its Duration and Fps properties.



That's what this simple code does animation does ...



U can try implementing Ajax toolkit in ur Asp.net Application for much more pretty animation ...

Friday, January 25, 2008

Hack a Windows 2000 system through IPC$

I got this nice article from one the site to hack a win 2000 system through IPC$...

The initial step involve in this are ...

1 : Scanning for open Win2k systems
2: Connecting to the IPC$
3: Connecting and using Computer Management.
4. Disable NTLM
5: Starting the Telnet service
6: Creating user accounts and adding them to a group
7: Covering your tracks
8: How to protect your Win2k system from this attack

-----------------------------------------------------------------------------------------------------
You need to be running a Win2k system:

Superscan version 3.00 by Foundstone (246kb). Homepage
NetBrute Scanner 1.0.0.7 (247KB). Homepage
PQWak V1.0 (24KB)
----------------------------------------------------------------------------------------------------


1: Scanning for open Win2k systems


A. Open SuperScan 2.05 (Port scanner)
B. Select a IP range
C. Check "Only scan responsive pings" and "All selected ports in list"
D. Only scan ports 139 (NetBIOS), and 1025 (Network Blackjack)
E. When a system with both Netbios and BlackJack is found, open NetBrute, and scan that IP to see if there is an IPC$

 

2: Connecting to the IPC$


A. Open a DOS window
B. Type in " net use \\ipaddress\ipc$ "" /user:administrator "
C. If you connect to the system, it will say, " The command was completed successfully "
D. If it says, “bad username or password”, Try running PQWak.exe to crack the share name password. Then insert the password like so:
net use \\ipaddress\ipc$ "password" /user:administrator
E. Users usually have only one password for everything. So try the c$ share pass as the administrator password to connect to the IPC$

3: Connecting using Computer Management


A. Open Computer Management.
B. Click “Action”, then “Connect to Another Computer”
C. Type in the IP address.

4. Disable NTLM


A. Open “regedit”
B. Connect to the following registry key:
HKEY_LOCAL_MACHINE--Software--Microsoft--Telnet Server--1.0—->NTLM
C. Set the value data from (2) to (1)
D. That will enable login to the telnet server without being connected to the IPC$ or a trusted domain.

5. Starting the Telnet service


A. In Computer Management, click “Services and Applications”
B. Click Services
C. Right click on the Telnet Service and open Properties.
D. Set the service to Automatic, and start the service.

6: Creating user accounts and adding them to a group


A. Open a dos window, and type the following: telnet IPaddress
B. If prompted to type a username and password, type Administrator with no password.
C. To create a user account, type the following: Net user username password /add
D. Replace “Username” and “password” with whatever you like.
E. To add a user account to a domain, type the following: Net localgroup administrators username /add Or Net group administrators username /add

7: Covering your tracks


A. Open a dos window, and type the following: Net use \\ipaddress\ipc$ /delete
B. While logged on to Computer Management. Check if the Security Logs are being audited in Event Viewer. If they are, clear them. :-)

8: How to protect your Win2k system from this attack


A. Open Regedit
B. Connect to the following:
C. HKEY_LOCAL_MACHINE--System--CurrentControlSet--Control--Lsa-->restrictanonymous
D. Change the "Value Data" from 0 to 1. It should say 0x00000001(1)
E. That will disable remote logon to a null IPC$
F. Always have a complicated administrator password with Windows2000 or any other OS
G. Install a firewall. www.zonealarm.com

Parmalink

Wednesday, January 23, 2008

Developing Struts with Easy Struts for Eclipse

 

This article shows you how to develop a Struts application in the Eclipse IDE, with the help of the Easy Struts plug-in. You'll get an introduction to Easy Struts, installation and configuration steps, and instructions on building a basic Struts application through a progressive example. Different ways of enhancing the Struts application -- such as connecting to a database, modularizing the application, internationalizing and localizing content, handling exceptions, and creating custom plug-ins -- are also covered. Finally, you will learn how to deploy your Struts application on the Tomcat Web server.

The Easy Struts plug-in manages all the complex configuration files, so you can focus on developing logic. Let's look at the 10 functions of Easy Struts that help you build a complete application:

  1. Add Easy Struts support. Adds all the necessary Struts libraries to the project classpath, and creates the configuration files and the default resource properties file.
  2. Easy Form. Creates a JSP file with the form properties, as well as a Form bean class with form properties getter and setter methods, and adds a form bean definition to the configuration file.
  3. Easy Action. Creates an Action class and adds an action mapping definition to the configuration file.
  4. Easy Action associated with a form. Creates a JSP file with the form properties, a Form bean class with form properties getter and setter methods, and an Action class. Also addes a form bean definition and an action mapping definition to the configuration file.
  5. Easy Forward. Creates local forwards and global forwards, which define where the control will be forwarded to.
  6. Easy Exception. Handles exceptions.
  7. Easy Message resources. Creates resource properties files, which is especially important for internationalization and localization of content.
  8. Easy Plug-in. Creates plug-ins.
  9. Easy Datasource. Connects the application to a data source.
  10. Easy Module. Modularizes the application.

In this article, we will cover 8 of the 10 functions (we will not cover functions 2 and 3: Easy Form and Easy Action). Before you can start developing a Struts application, you should have all the necessary programs and plug-ins installed, and know the basics of Java programming, HTML, and JSP scripts, as well as XML and XSLT.

Installing and configuring prerequisites

You need to install Eclipse 2.1, Struts 1.1, Tomcat Web server, and Easy Struts, along with Sysdeo Tomcat plug-ins for Eclipse, MySQL database server, and a JDBC driver for MySQL. Eclipse is the IDE. Struts 1.1 provides libraries for running a Struts application. Tomcat is the Web container hosting the application. The Sysdeo Tomcat plug-in enables developers to start and stop the Tomcat Web server within the Eclipse environment. A JDBC driver for MySQL converts a JDBC call into the network protocol used by the MySQL database. After installation, you will need to configure the two plug-ins for Eclipse.

Installation

See the Resources section below for download links to the following:

  1. Download Eclipse v2.1 from the Eclipse Web site. You can install it by unpacking it to any folder of your choice, which we will refer to as eclipse_home in this article.
  2. Download Struts 1.1 from the Apache Web site. You can install it by unpacking it to any folder of your choice, which we will refer to as struts_home in this article.
  3. Download the Tomcat Web server from the Apache Web site. You can install it by unpacking it to any folder of your choice, which we will refer to as tomcat_home in this article. This article assumes v4.1.18.
  4. Download the latest Tomcat plug-in for Eclipse from the Sysdeo Web site. You can install it by unpacking it to eclipse_home/eclipse/plugins. This article assumes v2.2.
  5. Download Easy Struts for Eclipse plug-in v0.6.4 from SourceForge. You can install it by unpacking it to eclipse_home/eclipse/plugins.
  6. Download the J2SE SDK from the Sun Web site. You can install it in any folder of your choice, which we will refer to as java_home in this article. This article assumes v1.4.2.
  7. Download the MySQL database server from the MySQL Web site. You can install it in any folder of your choice.
  8. Download the JDBC driver for MySQL from the MySQL Web site. You should unpack it and copy and paste mysql-connector-java-x.x.xx-stable/mysql-connector-java-x.x.xx-stable-bin.jar to your project workspace. We will return to this later. This article assumes v3.0.

Configuration

Configuring the Sysdeo Tomcat Plug-in

To configure the Sysdeo Tomcat Plug-in, do the following:

  1. Start Eclipse.
  2. Configure the Tomcat plug-in. To do this, go to the "Window" menu, select the "Preferences" item, and choose the "Tomcat" option on the popup view. Then do the following:
    • Set "Tomcat version" to your Tomcat version.
    • Set "Tomcat home" to tomcat_home/jakarta-tomcat-4.1.18.
    • Set "Perspective to switch when Tomcat is started" to Java.
    • Under Option "Tomcat", suboption "JVM Settings" -> "Classpath", add the Jar/Zip for tools.jar, which is in the folder java_home/lib/. This is for compiling JSPs.
  3. Set the classpath variable TOMCAT_HOME for project classpath reference. To do this, choose the option "Java" on the same popup view as in step 2, select suboption "Classpath Variables" and add a new variable "TOMCAT_HOME" whose path is tomcat_home/jakarta-tomcat-4.1.18.
  4. Ensure that the "Tomcat" menu and the 3 toolbar buttons are accessible. By now, you should be able to see a "Tomcat" menu and 3 Tomcat toolbar buttons (as shown in Figure 1) in the Java perspective. If not, go to the "Window" menu, choose the "Customize Perspective..." item, open the option tree marked "Other" and check the "Tomcat" suboption.
  5. Make sure the Sysdeo Tomcat plug-in works. To verify, use the menu or toolbar to Start/Stop Tomcat.

Figure 1. Tomcat toolbar buttons
Tomcat toolbar buttons

Configuring the Easy Struts Plug-in

To configure the Easy Struts Plug-in, refer to Figure 2 and do the following:

  1. Select a Struts version. To do this, go to the "Window" menu, choose the "Preference" item, choose the "Easy Struts" option and select the "Struts 1.1" tab.
  2. Add JARs. You should add "Add JARs" for all .jar files in struts_home\jakarta-struts-1.1\lib.
  3. Add TLDs. Next, add "Add TLDs" for all .tld files in struts_home\ jakarta-struts-1.1\lib.

Figure 2. Configure the Easy Struts plug-in
Configure the Easy Struts plug-in

Developing a Struts application

In this section, we will cover the basic steps involved in building a Struts application using the Easy Struts plug-in. First, you will create a Tomcat project. Next, you will add Easy Struts support to the Tomcat project. Then you can try the "Easy Action associated with a form" function. Next, you will do some necessary modifications to the source code generated automatically in the previous step. Then you can test the application running on the Tomcat Web server. Finally, you can examine the "Easy Forward" function.

Creating a Tomcat Project

To create a Tomcat project, go to the "File" menu, choose the "New" item, and choose "Project" from the submenu. Then do the following:

  1. Go to the "Java" option, select "Tomcat Project" and click "Next" (see also Figure 3).
  2. Fill in the project name and click "Next" (see also Figure 4).
  3. Check "Can update server.xml file". The system will update your server.xml file of the Tomcat Web server automatically. You may click "Finish" to complete the task now (see also Figure 5).

The result of creating a Tomcat project is shown in Figure 6.

Figure 3. Create a Tomcat project - Step 1
Create a Tomcat project - Step 1
Figure 4. Create a Tomcat project - Step 2
Create a Tomcat project - Step 2
Figure 5. Create a Tomcat project - Step 3
Create a Tomcat project - Step 3
Figure 6. Create a Tomcat project - Final Result
Create a Tomcat project - Final Result

Adding Easy Struts support

To add Easy Struts support to the Tomcat project, follow these two steps:

  1. Click the "New" toolbar button, select the "Easy Struts" suboption from the "Java" option, choose "Add Easy Struts support" and click "Next" to forward to the next step (see also Figure 7 -- we will refer to this view as the Easy Struts functions view in the rest of this article).
  2. Do the configurations shown in Figure 8. Ensure "Copy Struts binary" and "Copy Struts TLD" are checked.

The result of adding Easy Struts support is shown in Figure 9.

Figure 7. Easy Struts functions view
Easy Struts functions view

In Figure 8:

The URL pattern block tells the Struts to handle any file requests matching the pattern *.do by asking the container to forward them to the action servlet. Requests of all other patterns are not handled by Struts.

The Default application resource will be created in WEB-INF/classes/base package/.

Figure 8. Add Easy Struts support
Add Easy Struts support
Figure 9. Add Easy Struts support - Final Result
Add Easy Struts support - Final Result

Figure 7 shows the 10 functions provided by Easy Struts. We have looked at "Add Easy Struts Support". In the rest of this article, we will look at the 7 remaining functions (excluding "Easy Action" and "Easy Form"). In the rest of this section, we will use the "Easy Action associated with a form" and "Easy Forward" to build a simple but complete Struts application. "Easy Message resources", "Easy Plug In", "Easy Datasource", "Easy Exception" and "Easy Module" will be covered in the next section.

Working with Easy Action Associated with a Form

Go to the Easy Struts functions view, select "Easy Action associated with a form" and follow these steps to configure the form:

  1. Type in Use case; the Form name and Form type will be generated based upon the Use case by the system. You can modify the Form name and Form Type manually (see also Figure 10).
  2. Click "Add" in the Form properties block; use the view shown in Figure 11 to add form properties. For example, as shown in the figure, we are trying to add a text input field with the name "tel" and the value of "tel" should be of type int. We set "tel" to the initial value of zero. We can type in or use "Browse" for the "Type". We can type in or use pull down selection for the "JSP input type". The Struts system will generate a pair of getter and setter methods for each form property in the form bean class. Therefore, for a selection list, you should only create one <html:select> but not all the <html:option>s.
  3. Since you are developing a Web application, check the first two check boxes.
  4. click "Next" to continue.

Figure 10. Configure form
Configure form

Note

  • Form property names cannot start with a capital letter. Otherwise, you will be alerted that a getter method cannot be found when the action is called.
  • Form property names cannot be duplicates. If you really want to use two names that are the same, a prefix or suffix space will solve the problem.

Figure 11. Graphical representation of relations
Graphical representation of relations

By now, you should see something very similar to Figure 12. By default, the input value is "/form/owner.jsp", which means the JSP file is put in the "easyStruts/form" folder. You can change the JSP file location manually or by changing the preference setting. To change the preference setting, go to the "Window" menu, select "Preferences", click the "Easy Struts" option, choose the "Style" tab and set the "JSP form location" to blank. For example, in this article, we prefer the JSP files are stored directly in the easyStruts (project name) folder. So, change it to "/owner.jsp" as shown in Figure 12.

The attributes of action mapping shown in Figure 12 are as follows:

  • Path. Is the context-relative path of the submitted request. The path must have a prefix "/" and be unique.
  • Type. Is the name of the Action class being described by this ActionMapping.
  • Attribute. Is the name of the request-scope or session-scope attribute under which the form bean is accessed, if the name is not the same as the bean's specified name.
  • Scope. Specifies how long the values of a form bean, associated with this mapping, should be saved.
  • input. Specifies the context-relative path of the input form to which control should be returned if a validation error is encountered.
  • Validate. If this is set to true, it indicates the ActionForm.validate() method should be called on the form bean associated to this mapping.
  • Parameter. Can be used to pass extra information to the Action selected by this mapping.

Figure 12. Configure action
Configure action

Click "Next" and you should see something very similar to Figure 13. The properties shown in Figure 13 are action mapping properties, as follows:

  • Forward. Specifies the context−relative path of the servlet or JSP resource by which this request will be processed. ActionMapping can use findForward() to forward the control to the servlet or JSP resource.
  • Exception. The ExceptionHandlers associated with this mapping.

The forward and exception here are both local. We will discuss the global forward and exception later.

Figure 13. Configure forward
Configure forward

Local forward attributes:

  • name is the unique identifier, which can be used in the action mapping's findForward() method to return the path.
  • The contextRelative tag tells Struts that:
    • If it is set to true, path should be considered relative to the entire Web application.
    • If it is set to false, path should be considered relative to the module of a modular application.
  • If redirect is true, control will be transferred to the page with a redirect but not a forward. It means that a new request is created.

After you click "Finish" (see Figure 14), the system will generate com.asprise.struts.form.OwnerForm.java and com.asprise.struts.action.OwnerAction.java in easyStruts/WEB-INF/src/. Another file generated at the same time is easyStruts/owner.jsp. You will make some changes to the three files in the following sections, to complete the form, add user inputs validation methods and process the validation errors.

Figure 14. Add forward
Add forward

Modifying The ActionForm Class
Change all "Integer" to "int" in ActionForm.java, since you created the form property "tel" of type java.lang.Integer. Then code the validate() method to verify user inputs for the form properties. The complete validate() method is shown in Listing 1.

"error.noEmail" in ActionError("error.noEmail") is a key defined in the resource properties file, which is equal to "<li><font color=red>Enter your email</font> ". <html> code can be used in resource properties files. The argument property, in the method add(java.lang.String property, ActionError error) of ActionErrors class, is the name of a form property. This ActionError will only associate with the specified form property. For example, if email address is null or only contains spaces, the message "Enter your email" will be shown when the form is validated. If there is no "@" character in the email address, "Correct your email" will be shown, which is defined in the resource properties file with the key "error.wrongEmail". Both errors are only associated with the form property "email" (refer to Listing 1). We will return to this later.

Listing 1. OwnerForm.java

package com.asprise.struts.form;
 
import javax.servlet.http.HttpServletRequest;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
 
public class OwnerForm extends ActionForm {
 
   private String email;
   private String greet = "Mr.";
   private String address;
   private int tel = 0;
   private String name;
    
   public ActionErrors validate(
      ActionMapping mapping,
      HttpServletRequest request) {
 
      ActionErrors errors = new ActionErrors();
      if (greet == null || greet.trim().equals("")) {
         errors.add("greet", new ActionError("error.greet"));
      }
      if (name == null || name.trim().equals("")) { 
         errors.add("name", new ActionError("error.name"));
      }
      if (address == null || address.trim().equals("")) {
         errors.add("address", new ActionError("error.address"));
      }
      if (email == null || email.trim().equals("")) {
         errors.add("email", new ActionError("error.noEmail"));
      }
      else if (email.indexOf("@")==-1) {
         errors.add("email", new ActionError("error.wrongEmail"));
      }
      if (tel==0) {
         errors.add("tel", new ActionError("error.tel"));
      }
      return errors;
      }
      ...
 
   public String getEmail() {
      return email;
   }
 
   public void setEmail(String email) {
      this.email = email;
   }
   ...
}

<html> code can be used in resource properties files. The content of a resource property file is key-value pair (see Listing 2). The keys can be called in a source code file. The two keys errors.header and errors.footer are required by the system in every resource properties file.


Listing 2. ApplicationResources.properties

errors.header=<h4>Validation Error(s)</h4><ul>
errors.footer=</ul><hr>

error.greet=<li>Choose your greet
error.name=<li>Enter your name
error.address=<li>Enter your address
error.tel=<li>Enter your contact number
error.wrongEmail=<li>Correct your email
error.noEmail=<li>Enter your email

Modifying the Action class
The OwnerAction class simply displays a message like "Thank you, Miss Nancy Chen" in the local forward "success" path. Modify the execute() method of OwnerAction to code your logic, (every action class must implement the execute() method). Refer to Listing 3. It forwards control to success.jsp.


Listing 3. OwnerAction.java



public class OwnerAction extends Action {
 
   public ActionForward execute(
      ActionMapping mapping,
      ActionForm form,
      HttpServletRequest request,
      HttpServletResponse response)
      throws Exception {
 
      OwnerForm ownerForm = (OwnerForm) form;
      
      String greet = ownerForm.getGreet();
      String name = ownerForm.getName();
      request.setAttribute("name", name);
      request.setAttribute("greet", greet);
 
      // Forward control to the specified success target
 
      return (mapping.findForward("success"));
      }
}

Modifying the JSP File
First, complete the form by adding the <html:option>s for the <html:select> (see Listing 4). Then add a <html:errors /> after the form, which is used to demo the different behavior from the <html:error> tag with attribute "property". For example, <html:errors property="name"> will only reflect the user input validation error(s) associated with the form property "name". You can use add(String property, ActionError error) of the ActionErrors class to associate a form property with error(s). <html:errors /> will reflect all the validation errors in this form. The errors will be displayed in the location where the calling <html:error> is.

Listing 4. owner.jsp



<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html"%>
<html>
   <head>
      <meta
         name = "Generator"
         content = "Easy Struts Xslt generator for Eclipse (http://easystruts.sf.net).">
      <title>Struts Form for ownerForm</title>
   </head>
   <body>
      <html:form action="/owner">
         greet : <html:select property="greet">
                    <html:option value=""></html:option>
                    <html:option value="Mr.">Mr.</html:option>
                    <html:option value="Miss">Miss</html:option>
                    <html:option value="Mrs.">Mrs.</html:option>
                 </html:select><html:errors property="greet"/>
      name : <html:text property="name"/><html:errors property="name"/></br>
      address : <html:text property="address"/><html:errors property="address"/></br>
      email : <html:text property="email"/><html:errors property="email"/></br>
      tel : <html:text property="tel"/><html:errors property="tel"/></br>
         <html:submit/><html:cancel/>
      </html:form>
     <html:errors />
   <body>
</html>

Now, code success.jsp to display a message like "Thank you, Miss Nancy Chen". "Miss" is the greet of owner and "Nancy Chen" is the name of owner. The resulting file is shown in Listing 5.

Listing 5. success.jsp

<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%> 
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>

<logic:present name="name" scope="request">
Thank you,
<logic:present name="greet" scope="request">
<bean:write name="greet" scope="request"/>
</logic:present>
<bean:write name="name" scope="request"/>
</logic:present>

<logic:present> is one of the Struts logic tags. When the logic tag is with attribute "name", it is to check for the existence of a JSP bean with the specified name, in any scope. For the full list of <logic:present> attributes and the full list of Struts logic tags, refer to the Struts User Guide.

<bean:write> is one of the Struts bean tags. It is used to render the value of the specified bean property to the current JspWriter. When the bean tag has the attribute "name" and attribute "property", it specifies the attribute name of the bean whose property is accessed to retrieve the value specified by "property". If no "property" attribute is specified, the value of this bean itself will be rendered. For the full list of <logic:present> attributes and the full list of Struts logic tags, refer to the Struts User Guide.


Examining the struts-config.xml




When you double click the "struts-config.xml" within the Eclipse environment, the struts-config.xml will be displayed in a graphical user interface as shown in Figure 15. This enables developers to edit most of the Easy Struts functions easily. You can also view the source code of struts-config.xml by clicking the "source" tab.



Figure 15. struts-config.xml
struts-config.xml


Testing The Application
Restart the Tomcat server by clicking the Tomcat toolbar button. Then enter "http://127.0.0.1:8080/easyStruts/owner.jsp" in the URL address bar. Figure 16 is displayed. The validation results are shown in Figure 17. Note the different behaviors of <html:errors> with and without attribute "property". With "property", the system only returns the error(s) associated with this property. Without <property>, the system returns all the errors in the form. When all the inputs are correct, the system forwards control to success.jsp, which displays a message "Thank you, Miss Nancy Chen" (see Figure 18).

Figure 16. owner.jsp
owner.jsp
Figure 17. Form validation errors
Form validation errors
Figure 18. Success
Success

Using Easy Forward

The two kinds of ActionForwards provided by the Struts configuration are global forward and local forward. Global ActionForwards are visible to any Action object throughout the application. Local ActionForwards are only available to the Action object when it is called from the ActionMapping, which the Local ActionForwards is associated with. From the previous section, you saw how to create a local forward in the process of "Easy Action associated with a form". In this section, you will learn how to create a local or global forward using "Easy Forward".

Go to the Easy Struts functions view and click "Easy Forward". As a result, you should see something similar to Figure 19. If you leave the "Visibility" as blank, the result forward will be global. If you click the "Browse" button and choose "/owner", as shown in Figure 20, the result forward will be a local forward. Regardless of whether the forward is global or local, they can be referred in the Action class as mapping.findForward("failure");

We have already discussed "name", "Redirect" and "Context relative" attributes, shown in Figure 19, in the "Easy Action associated with a form" section.

Figure 19. Easy Forward - Global
Easy Forward - Global
Figure 20. Easy Forward - Local
Easy Forward - Local



Back to top

Enhancing the application

In the previous section, we examined three Easy Struts functions. In this section, you will code your own XSLT file to stylize JSP files and use the rest of the functions to Internationalize/Localize content, connect to data sources, handle custom exceptions, modularize the application and create custom plug-ins.

Stylizing JSP files by an XSLT file

You can have JSP files generated in a desired format by coding your own .xsl file and configuring the Easy Struts preference setting. To do the preference configuration, go to the "Window" menu, choose the "Preferences" item, select the "Easy Struts" option and click the "XSLT stylesheet" tab, and click "Browse" for "Jsp file stylesheet" to add our own .xsl file.

For example, the code shown in Listing 6 is our .xsl file. For each form property, it generates "property" and "value" attributes. For example, if you specify a text input named "name" with an initial value "nancy", the generated line in the JSP file will be name: <html:text property="name" value="nancy"></html:text>

Listing 6. myJsp.xsl
Graphical representation of relations

Localizing Content with Easy Message Resource

You can localize your application by creating localized resource properties files. To create a new resource properties file, go to the Easy Struts function view, select "Easy Message Resource". Do the configuration as shown in Figure 21, by which you will create a Chinese message resource. Note the name of the resource properties file must be ApplicationResources_xx_XX.properties. The small xx represents the local language, which is a two letter ISO-639 language code and the capital XX represents the local country, which is a two letter ISO-3166 country code.

Note: for the full list of two letter ISO-639 language codes, visit the languages page at Unicode.org. And for the full list of two letter ISO-3166 country codes, visit the countries page at Unicode.org


Easy message resource attributes:


  • If the null attribute is set to true, this causes a null string to be returned for an unknown message key.
  • The parameter is handed to the factory when the message resource bundle is created. The value of "parameter" is the path to the property file for property-file based factories.
  • The key attribute defines the ServletContext attribute key under which this message resources bundle is bound.

Figure 21. Create Chinese message resource
Create Chinese message resource

Resource properties files can be easily edited. You can use Notepad for the Chinese resource properties file. ApplicationResources_zh_CN.properties should be saved as Unicode (UTF-8) encoding. Next, set the local language to Chinese and location to China (in the case of Windows, you can do so using the Regional and Language Options in the Control Panel). Restart Tomcat to reflect the changes, and go to http://127.0.0.1:8080/easyStruts/owner.jsp. Now the validation errors are displayed in Chinese, as shown in Figure 22.

Figure 22. Validation errors in Chinese
Validation errors in Chinese

Connecting to a Database with Easy Datasource

In this section you will connect the Web application to a MySQL database. To do this, go to the Easy Struts function view, select "Easy Datasource" and do the configuration as shown in Figure 23. Note that you should put the JDBC driver in eclipse_home\eclipse\workspace\easyStruts\WEB-INF\lib.

Figure 23. Configure MySQL database
Configure MySQL database

Next, start the MySQL server, and create the database "crm" and the table "owner" as shown in Listing 7.

Listing 7. owner table

# Database : 'crm'
# Table structure for table 'owner'
#

CREATE TABLE 'owner' (
'id' int(6) NOT NULL default '0',
'greet' varchar(5) NOT NULL default '',
'name' varchar(50) NOT NULL default '',
'email' varchar(50) NOT NULL default '',
'address' varchar(100) NOT NULL default '',
'tel' int(10) NOT NULL default '0',
PRIMARY KEY ('id')
) TYPE=MyISAM;

Next, modify the execute() method in the OwnerAction class to connect to the database (refer to Listing 8). As you can see, this is where the key property used in the Easy Datasource comes into play. "org.apache.struts.action.DATA_SOURCE" is our key for datasource. Note that we catch the SQLException and rethrow it. In the next section, you will code your own exception handler to handle the SQLException.

Listing 8. OwnerAction.java - database connection



public ActionForward execute(
   ActionMapping mapping,
   ActionForm form,
   HttpServletRequest request,
   HttpServletResponse response)
   throws Exception {
 
   OwnerForm ownerForm = (OwnerForm) form;
   String greet = ownerForm.getGreet();
   String name = ownerForm.getName();  
   request.setAttribute("name", name);
   request.setAttribute("greet", greet);
   String address = ownerForm.getAddress();
   String email = ownerForm.getEmail();
   int tel = ownerForm.getTel();
   
   Connection conn = null;
   Statement stmt = null;
   ResultSet rs = null;
   
   DataSource dataSource = (DataSource)servlet.getServletContext().getAttribute(
      "org.apache.struts.action.DATA_SOURCE");
      try {
         conn = dataSource.getConnection();
         stmt = conn.createStatement();
         int id = 0;
         rs = stmt.executeQuery("select max(id) as counter from owner");
         while(rs.next()){
            id = rs.getInt("counter");
         }
         id += 1;
         stmt.executeUpdate("insert into owner values(
            "+id+", '"+greet+"', '"+name+"', '"+email+"', '"+address+"', "+tel+")");
         rs.close();
         stmt.close();
         conn.close();
      }
      catch(SQLException e){
         throw new SQLException("database error");
      }
      // Forward control to the specified success target
      return (mapping.findForward("success"));
}

You should restart the Tomcat server to let it connect to the data source on starting up and go to http://127.0.0.1:8080/easyStruts/owner.jsp. If all the inputs are correct, a record will be inserted into the "owner" table and control will be forwarded to success.jsp. You can check with the database whether there is a new record in the table "owner".

Handling Exceptions with Easy Exception

As mentioned in the previous section, you can code your own exception handler to handle the SQLException. First, go to the Easy Struts function view and select Easy Exception to declare the exception. Use the configuration shown in Figure 24. The name of the resource bundle that will hold the message resources for this exception is specified in the bundle attribute. The handler attribute specifies the class which is asked to handle this exception when it occurs. The key is defined in the message resource bundle. When the exception occurs, control is redirected to the file given in the path attribute. The scope attribute tells Struts how long the ActionErrors, created by handling the exception, should be saved (session or request). The type attribute specifies the type of exception to be intercepted by this handler.

Figure 24. Configure exceptions
Configure exceptions

After clicking on "Finish", the exception is declared. Then you should code the MyExceptionHandler.java (see Listing 9). It extends the ExceptionHandler class and like the Action class, it also implements the execute() method to return an ActionForward. As you can see, the "path" property of the Easy Exception can be retrieved using the getPath() method of ExceptionConfig class. You can get the key property using the getKey() method of ExceptionConfig class.

Listing 9. MyExceptionHandler.java



package com.asprise.struts.exception;
 
import javax.servlet.*;
import javax.servlet.http.*;
 
import org.apache.struts.action.*;
import org.apache.struts.config.*;
 
public class MyExceptionHandler extends ExceptionHandler {
   public ActionForward execute(
      Exception ex,
      ExceptionConfig ae,
      ActionMapping mapping,
      ActionForm formInstance,
      HttpServletRequest request,
      HttpServletResponse response)
   throws ServletException {
      request.setAttribute("myException",ex);
      request.setAttribute("myForm",formInstance);
      request.setAttribute("myKey",ae.getKey());
      return new ActionForward(ae.getPath());
   }
}

In the exception declaration, if an SQLException occurs, the control will be redirected to exception.jsp. Our exception.jsp displays the message defined in the default resource properties file with key "error.database", the exception type and the exception message when the exception is thrown. You can retrieve the exception key in MyExceptionHandler. You supply the key retrieved to the <bean:message> tag as shown in Listing 10.


Listing 10. exception.jsp

<%@ page import="java.sql.SQLException" %>
<%@ page import="com.asprise.struts.form.*" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%>

<%
OwnerForm myForm = (OwnerForm)request.getAttribute("myForm");
if (myForm != null) {
out.println("<font color=red>Sorry, "+myForm.getGreet());
out.println(" "+myForm.getName()+"</font>");
}
%>
<ul><bean:message key="<%=request.getAttribute(\"myKey\").toString()%>" />
<%
Object obj = request.getAttribute("myException");
if (obj != null) {
Throwable ex = (Throwable)obj;
out.println("<li><b>Type:</b>"+ex.toString());
out.println("<li><b>Message:</b>"+ex.getMessage());
}
%>

Define "error.database=<h3>An Exception Handled by MyExceptionHandler:</h3>". When an SQLException occurs, you should see something similar to Figure 25.

Figure 25. Handle exceptions - test result
Handle exceptions - test result

Modularizing the Application with Easy Module

In this section, you will create a new module named "newModule". To do this, go to the Easy Struts functions view, select "Easy Module" and type in Module name "newModule", as shown in Figure 26.

Figure 26. Configure module
Configure module

Restart Eclipse to reflect the new module. If there is an error org.xml.sax.SAXParseException: The content of element type "servlet" must match "(icon?,servlet-name,display-name?,description?,(servlet-class|jsp-file),init-param*,load-on-startup?,run-as?,security-role-ref*)"when the Web application starts, you can solve it by moving the new module configuration part directly below the one of default module in web.xml.

There are two ways to switch to the new module. First, create a new forward "success" as global or local in struts-config.xml (see Listing 11). Then you can switch to the new module by using mapping.findForward("success").

Listing 11. forward

<forward name="success"
contextRelative="true"
path="/newModule/index.do"
redirect="true"/>

Second, create an action as follows, whose type is a built in action SwitchAction:

 <action path="/switchTo" type="org.apache.struts.actions.SwitchAction" validate="false" />

Then in struts-config-newModule.xml, create the action mapping shown in Listing 12.

Listing 12. action mapping

<action-mappings>
<action path="/index" type="com.asprise.struts.newmodule.action.IndexAction">
<forward name="success" path="/index.jsp"/>
</action>
</action-mappings>

Next, code easyStruts/newModule/index.jsp. The index.jsp displays only one message "<h1>You are in module: newModule</h1>".

Now, start the Tomcat server, and enter http://127.0.0.1:8080/easyStruts/switchTo.do?prefix=/newModule&page=/index.do. The result is shown in Figure 27. If you want to switch back to the default module, you can enter http://127.0.0.1:8080/easyStruts/switchTo.do?prefix=&page=/owner.jsp

Figure 27. Switch between modules
Switch between modules

Note: You can specify the module name in all the Easy Struts functions except "Add Easy Struts support".

Creating Custom Plug-ins with Easy Plug-in

In this section, you will learn the last Easy Struts function -- Easy Plug-in. A common use of a Plug-in Action is to configure or load application-specific data as the Web application is starting up. Custom plug-in implements the Plug-in interface. Implementation of this interface requires a zero-argument constructor for use by ActionServlet, to ensure the plug-in is created properly. The two methods defined in the interface are init() and destroy(), which are called at application startup and shutdown respectively. You must implement these two methods.

To create a plug-in, go to the Easy Struts functions view, select Easy Plugin, type in Plugin class and add "Add" for properties. Add proxy and port properties, as shown in Figure 28.

Figure 28. Configure plugin
Configure plugin

Then, code the MyPlugin class, as shown in Listing 13. It implements the Plugin class. When the Web application starts, it displays a message saying "MyPlugin starting" and sets the system's proxy and port. When the Web application shuts down, a "MyPlugin Stopping" message is displayed.

Listing 13. MyPlugin.java



package com.asprise.struts.plugin;
 
import org.apache.struts.action.PlugIn;
import org.apache.struts.config.ModuleConfig;
import org.apache.struts.action.ActionServlet;
 
public class MyPlugin implements PlugIn{
   public String proxy;
   public String port;
   
   public MyPlugin(){
   }
   
   public void init(ActionServlet servlet, ModuleConfig config){
      System.err.print("********* MyPlugin Starting *******");
      System.setProperty("https.proxyHost", getProxy());
      System.setProperty("https.proxyPort", getPort());
      servlet.getServletContext().setAttribute("proxy", getProxy());
      servlet.getServletContext().setAttribute("port", getPort());
   }
      public void destroy(){
         System.err.print("********* MyPlugin Stopping *******");
      }
      public void setProxy(String prox){
         proxy = prox;
      }
      public String getProxy(){
         return this.proxy;
      }
      public void setPort(String por){
         port = por;
      }
      public String getPort(){
         return this.port;
      }
}

In the source code of JSP or another Java file, you can use getServletContext().getAttribute("proxy") to get the proxy value.


 

Deploying the application

To deploy the Struts application to client(s), you can simply export the application as a WAR file, distribute it to your client(s) and ask them to put the WAR file in the "webapps" folder of their Web server(s). Here are the steps to export the application as a WAR file:


  1. Go to the "Project" menu, choose the "Properties" menu, select the "Tomcat" option and click the "Export to WAR settings" tab.
  2. Click "Browse" of the "WAR file for export", and set the value to folder-of-your-choice/easyStruts.war. Save the setting.
  3. Then go to project popupmenu, select "Tomcat project" and click "Export to the WAR file sets in project properties" from the submenu.
  4. After the message "Operation successful" is displayed, you can go to the location specified in step 2 to get the WAR file.


Summary

In this article, we walked through the Easy Struts functions to develop a Struts application running on the Tomcat Web server. You learned how to process form properties validation, how to create local and global forward and exception, as well as how to do exception handling, how to connect to a data source, internationalize/localize the content, modularize the application, create custom plug-ins, as well as distribute the application to your clients.