Controller Component In Struts

Introduction

 
The core of Struts, which is based on MVC architecture, is a controller component. The controller is a Servlet that receives a request from the application. It manages the data flow between the Model and the View by delegating the handling of requests to the RequestProcessor class.
 

ActionServlet Class

 
ActionServlet class is responsible for initializing the struts framework for a web application and receiving all the requests. It is a concrete class and may be used as it is in an application or can be extended. In a strut based Web application, there will be a single instance of the ActionServlet class, which will essentially be responsible for receiving all the incoming requests.
 
ActionServlet class is configured in the deployment descriptor web.xml file. There are two ways to configure the ActionServlet class in the web.xml file. In the first case, the path mapping technique is used to configure the ActionServlet. The code below demonstrates the use of the path mapping technique.
 
Source code
  1. <!—Action Servlet Configuration-->  
  2. <servlet>  
  3.     <servlet-name>action</servlet-name>  
  4.     <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>  
  5.     <init-param>  
  6.         <param-name>config  
  7.             <param-name>  
  8.                 <param-value>/WEB-INF/struts-config.xml</param-value>  
  9.             </init-param>  
  10.         </servlet>  
  11.         <!—Action Servlet Mapping- -><servlet-mapping><servlet-name>action</servlet-name><url-pattern>/do/*</url-pattern></servlet-mapping>   
Using path mapping techniques, all the requests are routed to the ActionServlet class that matches the specified path. The default path as shown in web.xml file is /do/*.
 
The second technique used for configuring ActionServlet class is extension mapping, as shown in source code below:
  1. <!—Action Servlet Mapping-->  
  2.   
  3. <servlet-mapping>    
  4.    <servlet-name>action</servlet-name>    
  5.    <url-pattern>*.do</url-pattern>    
  6. </servlet-mapping>    
In the extension mapping technique, all requests with the specified extension is mapped to ActionServlet class. By default the extension is .do , but one can specify any extension.
 
The HTTP request is received by the ActionServlet class through the doGet() and doPost() methods. The request in turn is handled by the process() method. The process() method invokes the selectModule() method which receives the request and the ServletContext object. The selectModule() method selects the appropriate module to handle the request by obtaining the path from the request.getServletPath() method.
 
Some of the methods of this class are,
 
init()
 
The Struts ActionServlet class will be loaded by the servlet container depending on the initialization parameter specified in the web.xmlfile. The class will be loaded either when the container starts or when the first request is received by the servlet. The init() method is invoked for both the cases before any request processing is done by the servlet. During the invocation of the init() method, the following activities take place:
  1. The org.apache.struts.action.ActionResource bundle from which the internal messages are obtained is initialized.
  2. The initialization parameters such as config, debug, and so on are loaded from the web.xml file. These parameters control the behavior of the ActionServlet class.
  3. The Servlet name and the Servlet mapping information which are present in the web.xml file is loaded and initialized. These are used when submitting the HTML form to the correct URL destinations and are used throughout the framework. The DTDs (Document Type Definition’s) that are used by the framework are registered during this initialization process.
  4. For the default application, the Struts configuration data present in the config initialization parameters are loaded and initialized. An ApplicationConfig object is first created by parsing the default Struts configuration file and then stored in the ServletContext.
  5. For the default application, all the message resource that is specified in the struts configuration file is loaded, initialized, and stored in the ServletContext based on the key attribute specified in the message-resource element.
  6. All the data sources specified in the struts configuration file are initialized and stored.
  7. All the plug-in specified in the struts configuration file is loaded and initialized.
  8. Once the default application has been loaded, the init() method will perform all the steps 4 to 7 for each of the application modules that are specified.
Fig 1: Sequence of steps for ActionServlet class
 
Syntax
 
public void init() throws ServletException
 
Some of the other methods for implementing the controller functionality are,
 
getModuleConfig()
 
This method returns the module configuration object for the current module, ModuleConfig interface is the collection of static configuration information that describes a Struts-based module
 
Syntax
 
Protected ModuleConfig getModuleConfig(javax.servlet.http.HttpServletRequest request)
 
Where request represents the Servlet request that is being processed
 
getProcessorForModule()
 
The method returns the RequestProcessor object for the given module or null if one does not exist. This method will not create a RequestProcessor object and it accepts the configuration object as a parameter.
 
Syntax
 
private RequestProcessor getProcessorForModule(ModuleConfig config)
 
where config represents an instance of ModuleConfig
 
parseModuleConfigFile()
 
This method parses a modules configuration file.
 
Syntax
 
protected void parseModuleConfigFile(org.apace.commons.digester. Digester digester , java.lang.String path) throws javax.servlet.UnavailableException
where
digester represents an instance of Digester
path represents the path to the configuration file that is to be parsed
 

RequestProcessor Class

 
The RequestProcessor class was added to customize the request handling behavior of an application. The main purpose of the RequestProcessor class is to break down each request into small tasks. Each task is then carried out by a different method. This enables each and every individual part of a request to be customized. Each application module can have its own customized request handler.
 
Some of the methods for implementing the request processing functionality are,
 
processActionPerform()
 
This method will ask the specific Action class object to handle this request and returns an instance of the ActionForward class, which is returned by the Actionclass for further processing.
 
Syntax
 
protected ActionForward processActionPerform (javax.servlet.http.HttpServletRequest request , javax.servlet.http.HttpServletResponse response, Action action, ActionForm form, ActionMapping mapping) throws java.io.IOException, javax.servlet.ServletException
where
request represents the servlet request object that is being processed.
response represents the servlet response object that is being created.
action represents the Action object that is to be used.
form represents the ActionForm object that will be parsed to this Action object.
mapping represents the ActionMapping object to pass to this Action.
IOException throws an IOException if an input/output error occurs.
servletException throws a ServletException if a servlet exception occurs.
 
processValidate()
 
This method will call the Validate() method of the specific ActionForm object provided the request’s ActionMapping parameter has not disabled validation. If any errors are found during validation they are forwarded to the input path.
 
Syntax
 
protected boolean processvalidate(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, ActionForm form, ActionMapping mapping) throws java.io.IOException, javax.servlet.ServletException
 where
request represents the servlet request object that is being processed.
response represents the servlet response object that is being created.
form represents the ActionForm object that is being populated.
mapping represents the ActionMapping object that is being used.
IOException throws an IOException if an input/output error occurs.
ServletException throws a ServletException if a servlet exception occurs.
 
processRoles()
 
This method will check if the current user has a role that will allow the user to access the requested resource. The method returns a boolean value of true and false. A true value indicates normal processing and the false value indicates that processing should terminate.
 
Syntax
 
protected boolean processRoles(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, ActionForm form, ActionMapping mapping) throws java.io.IOException, javax.servlet.ServletException
 where
request represents the servlet request object that is being processed.
response represents the servlet response object that is being created.
mapping represents the ActionMapping object that is being used.
IOException throws an IOException if an input/output error occurs.
ServletException throws a ServletException if a servlet exception occurs.
 

Action Class

 
The action class is responsible for processing specific requests. In other words, the task performed by the Action class should be cohesive and related to one business operation. This class is also responsible for transferring data between the View layer and the business process in the model layer and vice versa.
 
Each action is mapped to a path in the struts configuration file as shown in code below,
  1. <action-mappings>    
  2.    <action path=”/UpdateProduct” type=”com.app.struts.UpdateProductAction”/>    
  3. </action-mappings>    
Some of the methods of this class are:
 
getErrors()
 
The method retrieves errors that are placed by the previous actions in the request object. Instead of creating a new ActionMessages() object this method can be invoked at the beginning of an Action.  The method returns errors or an instance of ActionMessages class.
 
Syntax
 
protected ActionMessages getErrors(javax.servlet.http.HttpServletRequest req)
where
req represents a servlet request that is being processed
 
getLocale()
 
The method returns the currently selected locale of the user.
 
Syntax
 
protected java.util.Locale getLocale(javax.servlet.http.HttpServletRequest req)
Where
req represents a servlet request that is being processed
 
getMessages()
 
The method retrieves the existing method placed by previous actions in the request. The method returns messages that are present in the HTTP request object or it will create a new instance of ActionMessages class.
 
Syntax
 
protected ActionMessages getMessages (javax.servlet.http.HttpServletRequest req)
Where
 req represents a servlet request that is being processed
 
getServlet()
 
The method returns an object of the attached servlet class.
 
Syntax
 
public ActionServlet getServlet()
 

ActionForward Class

 
The execute() method of the Action class returns the next view, which should be shown to the user. ActionForward class provides information for the next view. It is an effective wrapper.
 
The following are the properties of the ActionForward class:
  • name: specifies the logical name for the ActionForward.
  • path: specifies the URI for the ActionForward
  • redirect: Redirects the control, if true. However , default is false. 
  • contextRelative :Interprets the path value. If false, path value is represent as context relative. 
The path property can contain any URI. It can also contain a query. Based on the redirect attribute, the RequestDispatcher interface may either execute forward or redirect for the ActionForward.
 
ActionForward class is configured in strut-config.xml file so that it represents a destination. The ActionForward is defined in the action-mapping elements as shown in code below:
  1. <action-mappings>  
  2.    <forward name=”success” path=”welcome.do” />  
  3. </action-mappings>   
Let's look with the help of an example:
  • Copy the “struts-proj.war” to the “…\tomcat\webapps” folder. If you start Tomcat, Tomcat will automatically expand the web archive file. Also, you may manually expand the war file to examine the Struts startup skeleton.
  • Name your software application. Under “…\tomcat\webapps”, right-click the “struts-blank” and rename it called “MyProj”. It looks like below:
  • Note that skeleton “web.xml”, jars, and TLD files for the Struts tag library are already copied, expanded from “struts-proj.war”.
  • Use a Struts tag. Create “index.jsp” in the “\MyProj” folder in a struts framework “Hello World”.
    1. <%@ page language="java" %>    
    2. <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>    
    3. <head><title>Welcome</title></head>    
    4. <body>    
    5.    Hello World!!<p>    
    6.    <html:link page="/do/searchAct"> Search </html:link>    
    7. </body>   
  • Note that we are using the Struts HTML taglib to do our link to a page we will create later.
  • Browse the “index.jsp” (http://localhost:8080/MyProj/index.jsp).
Struts-Config File
 
Let’s look at the “…\WEB-INF\web.xml” file.
  1. <?xml version="1.0" ?>  
  2. <!DOCTYPE "http://java.sun.com/J2EE/DTDS/web-app.dtd">  
  3. <web-app>  
  4.     <!-- Action Servlet Configuration -->  
  5.     <servlet>  
  6.         <servlet-name>action</servlet-name>  
  7.         <servletclass>    
  8. org.apache.struts.action.ActionServlet    
  9.   
  10.         </servlet-class>  
  11.         <init-param>  
  12.             <param-name>Application</param-name>  
  13.             <param-value>AppResource</param-value>  
  14.         </init-param>  
  15.         <init-param>  
  16.             <param-name>config</param-name>  
  17.             <param-value>/WEB-INF/struts-config.xml  
  18.             </paramvalue>  
  19.         </init-param>  
  20.         <init-param>  
  21.             <param-name>Debug</param-name>  
  22.             <param-value>2</param-value>  
  23.         </init-param>  
  24.         <init-param>  
  25.             <param-name>Detail</param-name>  
  26.             <param-value>2</param-value>  
  27.         </init-param>  
  28.         <init-param>  
  29.             <param-name>Validate</param-name>  
  30.             <param-value>true</param-value>  
  31.         </init-param>  
  32.         <load-on-startup>2</load-on-startup>  
  33.     </servlet>  
  34.     <!-- Action Servlet Mapping -->  
  35.     <servlet-mapping>  
  36.         <servlet-name>action</servlet-name>  
  37.         <url-pattern>/do/*</url-pattern>  
  38.     </servlet-mapping>  
  39.     <!-- The Welcome File List -->  
  40.     <welcome-file-list>  
  41.         <welcome-file>index.jsp</welcome-file>  
  42.     </welcome-file-list>  
  43.     <!-- Struts Tag Library Descriptors -->  
  44.     <taglib>  
  45.         <taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri>  
  46.         <taglib-location>/WEB-INF/strutsbean.tld</taglib-location>  
  47.     </taglib>  
  48.     <taglib>  
  49.         <taglib-uri>/WEB-INF/struts-logic.tld  
  50.         </tagliburi>  
  51.         <taglib-location>/WEB-INF/strutslogic.tld</taglib-location>  
  52.     </taglib>  
  53.     <taglib>    
  • Modified the <url-pattern> for the “action” <servlet-name> to “/do/*”. Struts normally has the “/*.do” pattern for the action servlet.
  • Have a single servlet that will run things like, a mapping to forward, and tag libraries that will help to develop web application.
  • Anything send to “/do/” will be handled by Struts. Struts uses another configuration file, “struts-config.xml”.
  • To understand the Struts MVC, let’s create some folders like “data” and “app” in the “…\WEBINF\classes” directory.
In the “data” directory, we will store the classes this will act as a Model Layer, JavaBeans that extend the Struts FormBean. In the “app” directory, we will store the classes that will act as a controller layer, the application code that extends Struts Action with perform() method.
  • Create a “pages” folder in the “…\WEB-INF” directory to hold the View (pages) layer which will consist of JSP’s.
  • We have the “...\WEB-INF\classes\data” (Model) , the “...\WEB-INF\pages” (View), & the “...\WEBINF\classes\app” (Controller) folders.
  • Read the “struts-config.xml” file.
    1. <?xml version="1.0" ?>  
    2. <struts-config>  
    3.     <global-forwards>  
    4.         <!-- <forward name="search" path="/do/searchAct"/> -->  
    5.     </global-forwards>  
    6.     <form-beans>  
    7.         <form-bean name="SerchFrom" type="data.SerchFrom"/>  
    8.         <form-bean name=" NameLastFrom " type="data.NameLastFrom"/>  
    9.     </form-beans>  
    10.     <action-mappings>  
    11.         <action path= "/searchAct" type= "app.SearchAct" name= "SerchFrom"    
    12. scope="request" input="/WEB-INF/pages/SearchPage.jsp">  
    13.             <forward name="SearchPage" path="/WEBINF/pages/SearchPage.jsp"/>  
    14.             <forward name=" NameLastAct " path="/do/NameLastAct"/>  
    15.         </action>  
    16.         <action path= "/NameLastAct" type= "app.NameLastAct" scope="request" input="/WEB-INF/pages/NameLastPage.jsp">  
    17.             <forward name="nameLastPage" path="/WEBINF/pages/NameLastPage.jsp"/>  
    18.             <forward name="nameZoomAct" path="/do/nameZoomAct"/>  
    19.         </action>  
    20.     </action-mappings>  
    21. </struts-config>   
  • Note that “web.xml” will forward “/do” to action servlet. The action servlet will read “struts-config.xml” to determine which class will handle the action.
  • “index.jsp” above asks for a “/do/searchAct”. The request is forwarded to the Struts action which determines the handler class. The class is “app.SearchAct”.
  • When we click on ‘Search’ link in “index.jsp”, we will ask “app.SearchAct” to handle the request through perform() method. perform() forwards the request to a particular page. Reading “struts-config.xml”, “app.SearchAct” can forward to a “SearchPage” under “/pages” and ask for another action “/do” of ‘NameLastAct’. 
Create an action class “…\WEBINF\classes\app\SearchAct.java”
  1. package app;  
  2. import java.io.*;  
  3. import java.util.*;  
  4. import javax.servlet.*;  
  5. import javax.servlet.http.*;  
  6. import org.apache.struts.action.*;  
  7. import data.*;  
  8. public class SearchAct extends Action {  
  9.     public ActionForward perform(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException,  
  10.         ServletException {  
  11.             return (mapping.findForward("SearchPage"));  
  12.         }  
  13. // perform() will forwarding to “SearchPage” and  “struts-config.xml” tells to go to “\pages” to display this request and the page name to display.    
Create a “SearchPage.jsp” in “…\WEB-INF\pages” folder:
  1. <%@ page language="java" %><%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>  
  2. <head>  
  3.     <title> Search </title>  
  4.     <html:base/>  
  5. </head>  
  6. <body>  
  7.     <html:form action="/searchAct">  
  8.         <p>First Name:    
  9.   
  10.             <html:text property="FirstName"/>  
  11.             <p>  
  12.                 <p>Last Name:    
  13.   
  14.                     <html:text property="LastName"/>  
  15.                     <p>  
  16.                         <html:submit property="submit" value="Submit"/>  
  17.                     </html:form>  
  18.                 </body>    
Create a JavaBean to handle the data (“…\WEBINF\classes\data\SerchFrom”)
  1. package data;  
  2. import org.apache.struts.action.*;  
  3. public class SerchFrom extends ActionForm {  
  4.     private String FirstName;  
  5.     private String LastName;  
  6.     public String getFirstName() {  
  7.         return (this.FirstName);  
  8.     }  
  9.     public String getLastName() {  
  10.         return (this.LastName);  
  11.     }  
  12.     public void setFirstName(String aFirstName) {  
  13.         this.FirstName = aFirstName;  
  14.     }  
  15.     public void setLastName(String aLastName) {  
  16.         this.LastName = aLastName;  
  17.     }  
  18. }   
For this simple bean, we have two properties with accessor and mutator methods. How they map with a view? For this “SearchPage.jsp” asks for the name to search in application. The controller forwards to a page that binds data to a bean. This is the foundation of the Struts framework.
 
Enter Data now, as shown in the fig below:
 
  • Now we have data in our bean and the controller can access it. We need to be able to pass this data to the next page that will eventually display for retrieval.
  • Update controller to take data and looks again the “struts-config.xml”. The “SearchAct” controller will forward to 2 different places, in order that the controller should decide where to approach.
  • Modified “SearchAct.java” with if / then logic as below:
    1. package app;  
    2. import java.io.*;  
    3. import java.util.*;  
    4. import javax.servlet.*;  
    5. import javax.servlet.http.*;  
    6. import org.apache.struts.action.*;  
    7. import data.*;  
    8. public class SearchAct extends Action {  
    9.     public ActionForward perform(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException,  
    10.         ServletException {  
    11.             boolean data = false;  
    12.             HttpSession session = request.getSession();  
    13.             String fname = ((SerchFrom) form).getFirstName(); // for decode the bean    
    14.             String lname = ((SerchFrom) form).getLastName();  
    15.             if ((fname != null) | (lname != null)) {  
    16.                 session.setAttribute("SerchFrom", form);  
    17.                 data = true;  
    18.                 System.out.println("Search" + fname + lname);  
    19.             }  
    20.             if (data) return (mapping.findForward("NameLastAct"));  
    21.             else return (mapping.findForward("SearchPage"));  
    22.         }  
    23. }  
  • In the first case, we had no data, it sent it to a page for us to enter data, and then it got back to the control.
  • We have data, and it is captured in the bean. So the controller can now take a peek at that data and forward it to another controller.
  • You can see that one of the arguments passed to perform() in the form bean. This is done by Struts.
  • So if there is none, we have our first case and we go to the page to enter it.
  • If we have data, so go on to our next page, the page that will display the retrieval data later.
  • Recall that we should ask the controller to display our page. Sometimes one controller controls many pages.
  • In the second case, go to the ‘NameLastAct’ controller. According to “struts-config.xml”, the class is stored in the “app” folder as ‘NameLastAct’ and we have already data in another bean. The bean for the “NameLastPage.jsp” page will have different fields. i,e. it will need a different Form bean. Each page should have its own form bean and its own controller.
  • So we have data from one bean that needs to go to another bean. So Action performs () should re-map it, and then display the data searching for, just to make sure that to pass data from one page to another page.
The source code for our second controller “…\WEBINF\classes\app\NameLastAct.java”
  1. package app;  
  2. import java.io.*;  
  3. import java.util.*;  
  4. import javax.servlet.*;  
  5. import javax.servlet.http.*;  
  6. import org.apache.struts.action.*;  
  7. import data.*;  
  8. public class NameLastAct extends Action {  
  9.     public ActionForward perform(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException,  
  10.         ServletException {  
  11.             HttpSession session = request.getSession();  
  12.             boolean data = false;  
  13.             NameLastFrom nl = new NameLastFrom(); // decode the bean    
  14.             SerchFrom sfrm = new SerchFrom();  
  15.             String fname = null;  
  16.             String lname = null;  
  17.             sfrm = (SerchFrom) session.getAttribute("SerchFrom");  
  18.             if (sfrm != null) {  
  19.                 fname = sfrm.getFirstName();  
  20.                 lname = sfrm.getLastName();  
  21.                 nl.setSearchFirstName(fname);  
  22.                 nl.setSearchLastName(lname);  
  23.                 session.setAttribute("NameLastFrom", nl);  
  24.                 data = true;  
  25.             }  
  26.             System.out.println("NameLst" + fname + lname + nl.getSearchFirstName() + nl.getSearchLastName());  
  27.             if (data) return (mapping.findForward("NameLastPage"));  
  28.             else return (mapping.findForward("NameLastPage"));  
  29.         }  
  30. }   
So we will get the bean out of the session, create a new bean, and then put it in the session.
Second form bean (“…\WEBINF\classes\data\NameLastFrom.java”)
  1. package data;  
  2. import org.apache.struts.action.*;  
  3. public class NameLastFrom extends ActionForm {  
  4.     private String searchFirstName;  
  5.     private String searchLastName;  
  6.     public String getSearchFirstName() {  
  7.         return (this.searchFirstName);  
  8.     }  
  9.     public String getSearchLastName() {  
  10.         return (this.searchLastName);  
  11.     }  
  12.     public void setSearchFirstName(String aFirstName) {  
  13.         this.searchFirstName = aFirstName;  
  14.     }  
  15.     public void setSearchLastName(String aLastName) {  
  16.         this.searchLastName = aLastName;  
  17.     }  
  18. }   
  • Second JSP page (“…\WEBINF\pages\NameLastPage.jsp”)
    1. <%@ page language="java" %><%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %><%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>  
    2. <head>  
    3.     <title> Names Lst </title>  
    4.     <html:base/>  
    5. </head>  
    6. <body>  
    7.     <p>    
    8. Search for:  
    9.         <p>  
    10.             <bean:write name="NameLastFrom" property="searchFirstName"/>  
    11.             <p>  
    12.                 <bean:write name="NameLastFrom" property="searchLastName"/>  
    13.                 <p>   
Note using a <bean:write> tag and not the <html:text> tag this time for just displaying data.
 

Summary

 
The core of struts, which is based on MVC architecture, is the controller component. The controller is Servlet. ActionServlet class is responsible for initializing the struts framework for a web application and receiving all the requests. RequestProcessor class breaks down each request into small tasks to be carried out by different methods. Action class is the heart of the framework and acts as a bridge between the client request and business operation. ActionForward class encapsulates a forward. In the given example, first, we created the struts pages and looked at how to create and read the “struts-config.xml” file. In the Struts folders, (“data”, “pages”, and “app”) are consistent with an MVC approach.