Showing posts with label Struts 2. Show all posts
Showing posts with label Struts 2. Show all posts

September 30, 2011

Accessing request headers in a Struts 2 action

1) Create an action class - HeaderReader.java - in the src folder of the web application

package info.icontraining.struts2;

import java.util.Enumeration;

import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.interceptor.ServletRequestAware;
import com.opensymphony.xwork2.ActionSupport;

public class HeaderReader extends ActionSupport implements ServletRequestAware {

   private HttpServletRequest request;
 
   public void setServletRequest(HttpServletRequest request) {
      this.request = request;
   }
 
   public String execute() {

      Enumeration e = request.getHeaderNames();
      String headerName = null;

      while(e.hasMoreElements()) {
         headerName = (String) e.nextElement();
         System.out.println(headerName + ": "); 
         System.out.println(request.getHeader(headerName) + "\n");
      }

      return SUCCESS;
   } 
}

2) Add a headers.html file to the WebContent folder of the web application

<html>
<body>
Check Server console log for Header names and values
</body>
</html>

3) Configure the action class in the struts.xml configuration file

<action name="headerReader" class="info.icontraining.struts2.HeaderReader">
   <result>headers.html</result> 
</action>

4) Test the example by accessing the following URL,

http://localhost:8080/WebAppName/headerReader.action

Setting a cookie in the response in Struts 2

1) Create an action class - CookieWriter.java - in the src folder of the web application

package info.icontraining.struts2;

import javax.servlet.http.Cookie;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionSupport;

public class CookieWriter extends ActionSupport {

   public String execute() throws Exception {
      ServletActionContext.getResponse()
                    .addCookie(new Cookie("firstName", "Dinesh"));
      return SUCCESS;
   }
}

2) Create the result JSP - cookieWrite.jsp - in the WebContent folder of the web application. The JSP displays the cookie sent in the response

<html>
<head>
<script type="text/javascript">

function readCookie(name) {
   var nameEQ = name + "=";
   var ca = document.cookie.split(';');
   for(var i=0;i < ca.length;i++) {
      var c = ca[i];
      while (c.charAt(0)==' ') 
         c = c.substring(1,c.length);
      if (c.indexOf(nameEQ) == 0) 
         alert("value of " + name + " cookie is " 
                    +  c.substring(nameEQ.length,c.length));
   }
   return null;
}
</script>
</head>
<body>
Setting cookie that came with the response.<br/><br/>
<a href="javascript:readCookie('firstName')" href="#">Read cookie</a>

</body>
</html>

3) Configure the action in the struts.xml configuration file

<action name="cookieWrite" class="info.icontraining.struts2.CookieWriter">
   <result>/cookieWrite.jsp</result>
</action>

4) Test the code by accessing the URL in the browser,

http://localhost:8080/WebAppName/cookieWrite.action

Reading a cookie from the request in Struts2

1) Create an action class - CookieReader.java - in the src folder of the Struts 2 enabled Web Application

package info.icontraining.struts2;

public class CookieReader {
 
   private String message;
   private String userName;
   public static final String SUCCESS = "success";

   public String getUserName() {
      return userName;
   }

   public void setUserName(String userName) {
      this.userName = userName;
   }

   public void setMessage(String message) {
      this.message = message;
   }
   
   public String getMessage() {
      return this.message;
   }
   
   public String execute() throws Exception {
      setMessage("Hello " + getUserName());
      return SUCCESS;
   }
}

2) Create the result JSP - cookieRead.jsp - in the WebContent folder of the web application

<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>Cookie Read Example</title>
</head>
<body>
   <h1><s:property value="message"/></h1>
</body>
</html>

3) Configure the action in the struts.xml, along with the configuration for the cookie interceptor. The <param> element indicates the name of the cookie that to be read from the request,

<action name="cookieRead" class="info.icontraining.struts2.CookieReader">
   <result>/cookieRead.jsp</result>
   <interceptor-ref name="cookie">
      <param name="cookiesName">userName</param>
   </interceptor-ref>
</action>

4) Create an .html file to set the cookie on the browser - cookieTest.html - add the file to the WebCon tent folder of the web application

<html>
<head>
<script type="text/javascript">
   document.cookie="userName=dinipc";
</script>
</head>
<body>
Cookie userName set.
</body>
</html>

5) Test the example by first accessing the cookieTest.html from the browser. This will set the cookie.

http://localhost:8080/WebAppName/cookieTest.html

Next, access the cookieRead.jsp from the browser

http://localhost:8080/WebAppName/cookieRead.jsp

September 28, 2011

Changing the Struts2 default .action extension

In order to change the default extension, which is .action, in Struts 2 to something else, configure the <constant> element in the struts.xml configuration file as follows,

<struts>
   
   <constant name="struts.action.extension" value="dud"/>

   <package name="myPackage" extends="struts-default">
   
   ...

   </package>
</struts>

Test the Hello World - Struts 2 example with the following URL in the browser,

http://localhost:8080/WebAppName/Name.dud

Session Management Example in Struts2

0|) Implement the Hello World Example for the Struts 2 framework as explained in this example

1) Modify the execute() method within the HelloWorld.java action class to set a session attribute on the SessionMap object as follows,

public String execute()  {

   ActionContext context = ActionContext.getContext();
     
   ((SessionMap) context.getSession()).put("username", getName());
     
   setCustomGreeting( GREETING + getName() );
   return Action.SUCCESS;
}

2) Modify the Hello.jsp result JSP to add an additional link as follows,

<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
  <title>HelloWorld</title>
</head>
<body>

  <h1><s:property value="customGreeting"/></h1>
  <br/><br/>

  <s:a action="Linked">Click here</s:a>
</body>
</html>

3) Add a JSP - linkedPage.jsp - in the WebContent folder of the Web application,

<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
  <title>Linked Page</title>
</head>
<body>
   <h1>In Linked Page: <s:property value="%{#session.username}"/></h1>
</body>
</html>

4) Configure the new action in the struts.xml file as follows,

<action name="Linked">
   <result>/linkedPage.jsp</result>
</action>

5) Test the example with the following URL in the browser,

http://localhost:8080/WebAppName/Name.action

July 16, 2011

Struts 2 - Spring framework Integration - Hello World Example

0) Ensure that both Struts 2 and Spring are setup in the web application. For Struts 2-enable the web application, refer this link and to Spring-enable the web application refer this link.

1) Download the Struts-Spring plugin jar from the link here and copy it in the WebContent/WEB-INF/lib folder of the web application

2) Modify the Struts 2 filter configuration in the web.xml file as follows,

<filter>
   <filter-name>struts2</filter-name>
   <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>

3) Copy the following configuration for the action element in the struts.xml file. The class attribute of the action element is assigned to the bean id from the applicationContext.xml rather than the actual class name

<action name="hello" class="greetingService">
   <result>/successSpring.jsp</result>
</action>

4) Modify the GreetingServiceImpl.java class to enter the following execute() and getGreeting() methods,

public String execute() { 
   return "success";
}

public String getGreeting() {
   return this.greeting;
}

5) Create a JSP - successSpring.jsp - in the WebContent folder of the web application

<%@taglib uri="/struts-tags" prefix="s"%>
<html>
<body>   <s:property value="greeting" />
</body>
</html>

6) Test the example with the following URL in the browser,

http://localhost:8080/WebAppName/hello.action

July 14, 2011

Declarative Exception Handling in Struts 2

1) Create an action class - ErrorProne.java - and place it in the src folder of the Web Application. The execute() method of this class throws an exception,

package info.icontraining.struts2;

public class ErrorProne { 
   public String execute() throws Exception {
      throw new Exception ( "Routine Code Explosion");
   }
}

2) Configure the action in the struts.xml file within the package element

<package ... >
   ...
   <global-results>
      <result name="Error">/error-struts2.jsp</result>
   </global-results>

   <global-exception-mappings>
      <exception-mapping exception="java.lang.Exception" result="Error"/>
   </global-exception-mappings>
   ...
   <action name="ErrorProne" class="info.icontraining.struts2.ErrorProne">
   ...
</package>

3) Create the custom JSP that will be displayed when the exception occurs - error-struts2.jsp

<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<body>
  <p>This is a custom error page that displays when an Exception is thrown in any Struts2 component</p>
  <br/>
  <s:property value="%{exception.message}" />
  <s:property value="%{exceptionStack}" />
</body>
</html>

3) Test the code with the following URL in the browser,

http://localhost:8080/WebAppName/ErrorProne.action

Struts 2 - Creating a custom logging interceptor

1) Create a class that implements the Interceptor interface and implement the intercept() method

package info.icontraining.struts2;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;

public class MyLoggingInterceptor implements Interceptor {

   public void destroy() { }

   public void init() { }

   public String intercept(ActionInvocation invocation) throws Exception {

      // pre-processing task
      String className = invocation.getAction().getClass().getName();
      long startTime = System.currentTimeMillis();  
      System.out.println("Before calling action: " + className);
  
      // invoking the next interceptor or the action
      String result = invocation.invoke();
  
      // post-processing task
      long endTime = System.currentTimeMillis();
      System.out.println("After calling action: " + className
  + " Time taken: " + (endTime - startTime) + " ms");
  
      return result;
   }
}

2) Configure the created interceptor in the struts.xml file. Make sure that this configuration appears at the top of the XML file within the <package> element

...
<package name="myPackage" extends="struts-default">

   <interceptors>
      <interceptor name="myLogger" 
         class="info.icontraining.struts2.MyLoggingInterceptor" />

      <interceptor-stack name="myStack">
         <interceptor-ref name="myLogger" />
         <interceptor-ref name="defaultStack" />
      </interceptor-stack>   
   </interceptors>

   <default-interceptor-ref name="myStack" />

   ...
</package>
...

3) Test the interceptor with any URL that invokes a Struts2 action. Check the server console for output statements from the interceptor.

http://localhost:8080/WebAppName/AnyAction.action

Struts 2 - Front-end validation with the Validation Framework

In this code example, we replace the validate() method for basic validation method in the example here with the validation framework.

Front-end validation with the Validation framework lets us configure the validations in a XML file (validation meta-data) and re-use the various, default validators that are provided by the framework.

1) Create the FeedbackForm.jsp and FeedbackDone.jsp files in the WebContent folder of the Web Application

FeedbackForm.jsp

<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<body>
<h4>Enter Feedback</h4>
  <s:form action="PostFeedback">
     <s:textfield name="emailAddress" label="Email Address" />
     <s:textfield name="phoneNumber" label="Phone Number" />
     <s:textarea name="message" label="Message" cols="20" rows="4" />
     <s:submit/>
  </s:form>
</body>
</html>

FeedbackDone.jsp

<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<body>
<h3>Your feedback is as follows</h3>
   <s:property value="emailAddress"/><br/>
   <s:property value="phoneNumber"/><br/>
   <s:property value="message"/><br/>
</body>
</html>

2) Create the action class - Feedback.java - in the src folder of the Web Application.

package info.icontraining.struts2;

import com.opensymphony.xwork2.*;

public class Feedback extends ActionSupport {

   public String execute() { 
      return Action.SUCCESS;
   }
 
   private String emailAddress;
   private String phoneNumber;
   private String message;
 
   public String getEmailAddress() {
      return emailAddress;
   }
   public void setEmailAddress(String emailAddress) {
      this.emailAddress = emailAddress;
   }
 
   public String getPhoneNumber() {
      return phoneNumber;
   }
   public void setPhoneNumber(String phoneNumber) {
      this.phoneNumber = phoneNumber;
   }
 
   public String getMessage() {
      return message;
   }
   public void setMessage(String message) {
      this.message = message;
   }
}

3) Configure the actions in the struts.xml configuration file,

<action name="Feedback" >
   <result>/FeedbackForm.jsp</result>
</action>
  
<action name="PostFeedback" class="info.icontraining.struts2.Feedback">
   <result>/FeedbackDone.jsp</result>
   <result name="input">/FeedbackForm.jsp</result>
</action>

4) Add a new validation framework XML configuration file for the action. This file should be added inside the package where the action class is present along with the properties file. The properties file will prevent the hard-coding of error messages inside the XML configuration file.

The naming convention for the Validation XML file for Struts 2 is ActionClassName-validation.xml
Therefore, create a file, Feedback-validation.xml and add it to the package in which the action class Feedback.java is present

<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN"
"http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
<validators>
   <field name="emailAddress">
      <field-validator type="requiredstring">
         <message>Please enter email address</message>
      </field-validator>
      <field-validator type="email">
         <message key="email.invalid" />
      </field-validator>
   </field>
   <field name="phoneNumber">
      <field-validator type="requiredstring">
         <message>Please enter phone number</message>
      </field-validator>
      <field-validator type="regex">
         <param name="expression"><![CDATA[^(\d){3}-(\d){3}-(\d){4}$]]></param>
         <message key="phone.invalid" />
      </field-validator>
   </field>
   <field name="message">
      <field-validator type="requiredstring">
         <message>Please enter message</message>
      </field-validator>
   </field>
</validators>

5) Add the Feedback.properties tile to the package in which the action class Feedback.java is present

email.invalid=Please enter valid email
phone.invalid=Please enter valid phone (xxx-xxx-xxxx)

6) Access the action by typing the following URL in the browser,

http://localhost:8080/WebAppName/Feedback.action

July 5, 2011

DispatchAction functionality in Struts2

In Struts 1.x, the in-built DispatchAction action allows us to group similar functional actions/requests into a single action.

1) In Struts 2, every action class is equipped to provide this functionality. First, there should be several methods (based on functions) similar in signature to the execute() method in the action class.

package info.icontraining.struts2;

import com.opensymphony.xwork2.*;

public class UserAction extends ActionSupport {

   private String message;

   public String execute() {
      message = "Inside execute method";
      return SUCCESS;
   }

   public String add() {
      message = "Inside add method";
      return SUCCESS;
   }

   public String update() {
      message = "Inside update method";
      return SUCCESS;
   }

   public String delete() {
      message = "Inside delete method";
      return SUCCESS;
   }

   public String getMessage() {
      return message;
   }

   public void setMessage(String message) {
      this.message = message;
   }
}

2) For each of the additional methods such as add(), update(), etc., other than the execute() method, that we would want to be executed on a client invocation, add a separate <action> element configuration in the struts.xml file

<action name="User" class="info.icontraining.struts2.UserAction">
   <result name="success">/success.jsp</result>
</action>

<action name="addUser" method="add" class="info.icontraining.struts2.UserAction">
   <result name="success">/success.jsp</result>
</action>

<action name="updateUser" method="update" class="info.icontraining.struts2.UserAction">
   <result name="success">/success.jsp</result>
</action>

<action name="deleteUser" method="delete" class="info.icontraining.struts2.UserAction">
   <result name="success">/success.jsp</result>
</action>

3) Add the following JSPs to invoke the respective methods (functions) in the action class. By default, the execute() method is invoked.

userActions.jsp

<%@taglib uri="/struts-tags" prefix="s"%>

<html>
<body><s:form action="User">
   <s:submit />
   <s:submit action="addUser" value="Add User" />
   <s:submit action="updateUser" value="Update User" />
   <s:submit action="deleteUser" value="Delete User" />
</s:form>
</body>
</html>

success.jsp

<%@taglib uri="/struts-tags" prefix="s"%>

<html>
<body>
   <s:property value="message" />
</body>
</html>

4) Test the code with the following URL in the browser,

http://localhost:8080/WebAppName/userActions.jsp

Session Management in Struts2

In order to set session-scoped attributes within a Struts2 action class, get hold of the session map either through the ActionContext object or by implementing the SessionAware interface as instructed in this example

To set an attribute from within an action class:

sessionMap.put("attributeName", "attributeValue");

To get an attribute from within an action class:

sessionMap.get("attributeName");

To set an attribute from within a result JSP:

<s:set name="attributeName" scope="session" value="attributeValue" />

To get an attribute from within a result JSP:

<s:property value="%{#session.attributeName}"/>

To programmatically invalidate a session:

sessionMap.invalidate();

To configuratively invalidate a session, refer to this example

Accessing Servlet API objects in a Struts2 action

Accessing through the ActionContext object

The ActionContext object can be procured anywhere within a Struts2 application by invoking a static method on the ActionContext class as follows,

ActionContext context = ActionContext.getContext();

The ActionContext object does not give direct access (references) to the Servlet API objects such as HttpServletRequest, HttpSession or ServletContext - instead it exposes the relevant attributes/parameters as plain Map objects. This prevents the binding of the Struts2 action classes to the Servlet API.

Accessing through the servlet-config interceptor

The servlet-config interceptor can cleanly inject the Servlet API objects into the action classes. The action class must implement certain interfaces and therefore contain implementation of the setter methods from the interfaces.

Following are the interfaces that the action classes can implement in order to get hold of the Servlet API objects,

interface ServletContextAware - sets the ServletContext
interface ServletRequestAware - sets the HttpServletRequest
interface ServletResponseAware - sets the HttpServletResponse
interface ParameterAware - sets a map of the request parameters
interface RequestAware - sets a map of the request attributes
interface SessionAware - sets a map of the session attributes
interface ApplicationAware - sets a map of the application attributes

For example, in the following action class, this is how the ServletContext can be injected.

package info.icontraining.struts2;

import javax.servlet.ServletContext;
import org.apache.struts2.util.ServletContextAware;

public class HelloWorld implements ServletContextAware {
 
   public String execute()  {
      // some code here
      return "success";
   }
     private ServletContext sc;
  
   public void setServletContext(ServletContext sc) {
      this.sc = sc;
   }
}

Breaking a large struts.xml into multiple smaller files

A large struts.xml can be broken in several smaller XML files - this makes the struts configuration modular and much convenient to work with in a team environment.

The <include> element can be used to apply the divide-and-conquer approach to Struts configuration files.

1) Modify the struts.xml file from this example to the following,

<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
   <include file="another-struts.xml" />
</struts>

Another number of modular, external XML files can be included in the struts.xml - they should be present anywhere in the classpath of the web application.

2) Add a new configuration file in the default package of the src folder of the web application, named another-struts.xml - add the following configuration in this file,

<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
   <constant name="struts.devMode" value="true" />

   <package name="myPackage" extends="struts-default">

      <action name="Name">
     <result>/NameCollector.jsp</result>
      </action>
  
      <action name="HelloWorld" class="info.icontraining.struts2.HelloWorld">
  <result>/Hello.jsp</result>
      </action>
     </package>
</struts>

Each included file such as another-struts.xml must be in the same format as the original struts.xml including the DOCTYPE at the top.

3) Test the code in the example with the same URL as the example referred to in step-1,

http://localhost:8080/WebAppName/Name.action

NOTE: Also refer the following URL - http://www.mkyong.com/struts2/struts-2-include-multiple-struts-configuration-files/

Struts 2 - Hello World Example (with Annotations)

1) Create a new Web Application Project in Eclipse. Download the Struts 2 jars and other dependent jars from the link here and copy them into the WebContent/WEB-INF/lib folder of the web application.

2) Copy the following configuration for the Struts2 FilterDispatcher in the web.xml file of the web application

<filter>
   <filter-name>struts2</filter-name>
   <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
   <init-param>
      <param-name>actionPackages</param-name>
      <param-value>info.icontraining.struts2</param-value>   
   </init-param>
</filter>
<filter-mapping>
   <filter-name>struts2</filter-name>
   <url-pattern>/*</url-pattern>
</filter-mapping>

The actionPackages parameter is used to specify the location (in terms of package names) of the action classes. Multiple packages can be specified by a comma-separated list.

3) Add the AnnotatedNameCollector.java class to the src folder of the web application. This class is an action class. Action classes in Struts2 with annotation-based configuration should either implement the Action interface or extend from the ActionSupport class or use a naming convention where the action class names end in the word 'Action'.

package info.icontraining.struts2;

import org.apache.struts2.config.Result;
import com.opensymphony.xwork2.ActionSupport;

@Result( value="/AnnotatedNameCollector.jsp" )
public class AnnotatedNameCollector extends ActionSupport {

}

The URL to access this action from the browser is derived by making the first character of the action class name smaller and appending the '.action' extension after the rest of the class name. So,

AnnotatedNameCollector.java can be accessed with the URL annotatedNameCollector.action

4) Add the AnnotatedHelloWorldAction class also to the src folder of the web application. In this case, the action class name ends with the word 'Action' and therefore does not need to extend the ActionSupport class or implement the Action interface

package info.icontraining.struts2;

import org.apache.struts2.config.Result;

@Result(name="SUCCESS", value="/HelloWorld.jsp" )
public class AnnotatedHelloWorldAction {

   private static final String GREETING = "Hello ";
     public String execute()  {
      setCustomGreeting( GREETING + getName() );
      return "SUCCESS";
   }

   private String name;
   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }
    
   private String customGreeting;
  
   public String getCustomGreeting() {
      return customGreeting;
   }
  
   public void setCustomGreeting( String customGreeting ){
      this.customGreeting = customGreeting;
   }
}

The URL to access this action from the browser is derived by making the first character of the action class  name smaller, dropping the 'Action' at the end of the class name and appending the '.action' extension after the rest of the class name. So,

AnnotatedHelloWorldAction.java can be accessed with the URL annotatedHelloWorld.action

5) Create the AnnotatedNameCollector.jsp and HelloWorld.jsp as below and add them to the WebContent folder of the web application

AnnotatedNameCollector.jsp

<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
  <head>
      <title>Name Collector</title>
  </head>
  <body>       <s:form action="annotatedHelloWorld">
        <s:textfield name="name" label="Your name"/>
        <s:submit/>
      </s:form>
  </body>
</html>

HelloWorld.jsp

<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
  <head>
     <title>HelloWorld</title>
  </head>
  <body>       
     <h1><s:property value="customGreeting"/></h1>
  </body>
</html>

6) Test the application by typing the following URL in the browser,

http://localhost:8080/WebAppName/annotatedNameCollector.action

June 26, 2011

Unable to load configuration - action - struts.xml

Topic: Struts 2.1.8.1

Application Server: JBoss 4.2.2 GA

Exception:

INFO  [STDOUT] 08:42:44,593 ERROR [Dispatcher] Dispatcher initialization failed
Unable to load configuration. - action - file:/C:/jboss-4.2.2.GA/jboss-4.2.2.GA/server/default/tmp/deploy/tmp6158064408942958403Struts2Demonstration-exp.war/WEB-INF/classes/struts.xml:16:74
 at com.opensymphony.xwork2.config.ConfigurationManager.getConfiguration(ConfigurationManager.java:58)
 at org.apache.struts2.dispatcher.Dispatcher.init_PreloadConfiguration(Dispatcher.java:374)
 at org.apache.struts2.dispatcher.Dispatcher.init(Dispatcher.java:418)
 at org.apache.struts2.dispatcher.FilterDispatcher.init(FilterDispatcher.java:190)
 at org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:275)
 at org.apache.catalina.core.ApplicationFilterConfig.setFilterDef(ApplicationFilterConfig.java:397)
 at org.apache.catalina.core.ApplicationFilterConfig.(ApplicationFilterConfig.java:108)
 at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:3722)
 at org.apache.catalina.core.StandardContext.start(StandardContext.java:4367)
 at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:790)
 at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:770)
 at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:553)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

Resolution:

The Struts 2 framework has dependencies on the following distributables:

- commons-fileupload-1.2.1.jar
- commons-io-1.3.2.jar
- commons-logging-1.0.4.jar
- commons-logging-api-1.1.jar
- freemarker-2.3.15,jar
- log4j-1.2.14.jar
- ognl-2.7.3.jar
- xwork-core-2.1.6.jar

Adding these jars to the WEB-INF/lib folder of the web application resolves this error. All these jars as as well as the Struts distribution may be downloaded from this link

April 13, 2011

Struts 2 - Transferring data onto JavaBean objects

1) Create a Register.jsp page as shown in the code below,

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>Register Page</title>
</head>
<body>
<h4>Enter Registration Information!</h4>
  
   <s:form action="doRegister">
      <s:textfield name="person.firstname" label="First Name"/>
      <s:textfield name="person.lastname" label="Last Name"/>
      <s:textfield name="person.age" label="Age"/>
      <s:submit/>
   </s:form>

</body>
</html>

2) Create the Register.java action class that contains the JavaBean object into the properties of which the incoming request data is to be transferred.


package info.icontraining.struts2;

import com.opensymphony.xwork2.*;

public class Register extends ActionSupport {

   public String execute() {
       return Action.SUCCESS;
   }
 
   private PersonBean person;

   public PersonBean getPerson() {
       return person;
   }
   public void setPerson(PersonBean person) {
       this.person = person;
   }
 
   public void validate() {
  
       if ( person.getFirstname().length() == 0 ){ 
            addFieldError( "person.firstname", "First name is required." );
       }
       if ( person.getLastname().length() == 0 ){ 
            addFieldError( "person.lastname", "Last name is required." );
       }
       if ( person.getAge() < 18 ){ 
            addFieldError( "person.age", "Age required & must be > 18" );
       }
   }  
}


3) Create the PersonBean.java class that is the JavaBean class in question,

package info.icontraining.struts2;

public class PersonBean {
 
   private String firstname;
   private String lastname;
   private int age;
 
   public String getFirstname() {
       return firstname;
   }
   public void setFirstname(String firstname) {
       this.firstname = firstname;
   }
   public String getLastname() {
       return lastname;
   }
   public void setLastname(String lastname) {
       this.lastname = lastname;
   }
   public int getAge() {
       return age;
   }
   public void setAge(int age) {
       this.age = age;
   }
}

4) Create the RegisterDone.jsp page that displays the incoming request data,

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>Register Done</title>
</head>
<body>
<h1>Thank You</h1>
<h3>for Registering!</h3>
<s:property value="person.firstname"/>
<s:property value="person.lastname"/>
<s:property value="person.age"/>

</body>
</html>

5) Configure the struts2 actions in the struts.xml file,

<action name="Register">
     <result>/Register.jsp</result>
</action>
  
<action name="doRegister" class="info.icontraining.struts2.Register">
     <result>/RegisterDone.jsp</result>
     <result name="input">/Register.jsp</result>
</action>

6) Test the code by typing the following URL in the browser,

http://localhost:8080/WebAppName/Register.action

Struts 2 - Externalizing String literals using Resource Bundles

Modify the example code at the following link - http://www.javaissues.com/2011/04/struts-2-basic-validation-with-validate.html

1) In the Login.java class modify the validate() method as follows:

public void validate() {
  
   boolean flag = false;
  
   if (getUsername().length() == 0) {
      addFieldError("username", getText("username.required"));
      flag = true;
   }
  
   if (getPassword().length() == 0) {
      addFieldError("password", getText("password.required"));
      flag = true;
   }
  
   if (!flag) 
      if (!getUsername().equals("dinesh") && !getPassword().equals("dinesh")) {
         addActionError(getText("username.password.incorrect"));
      }
   }

2) Add 2 resource bundles (.properties files) in the same package as the Login.java class. The details of the files are below,

Login.properties

username.required=Username is required
password.required=Password is required
username.password.incorrect=Username and/or Password is Incorrect

Login_hi.properties

username.required=Username is required in Hindi
password.required=Password is required in Hindi
username.password.incorrect=Username and/or Password is Incorrect in Hindi

3) Test the code by typing the following URL in the browser

http://localhost:8080/WebAppName/Login.action

Now, change the language setting in the browser to Hindi [hi] and type the above URL again in the browser.

April 12, 2011

Struts 2 Basic Validation with validate() method

1) Create a login.jsp page in the WebContent folder of the web application. The struts tag <s:actionerror> will display any validation error messages in the input.

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>Login Page</title>
</head>
<body>
<h4>Enter your Username and Password!</h4>
<s:actionerror />
<s:form action="doLogin">
     <s:textfield name="username" label="Username"/>
     <s:password name="password" label="Password"/>
     <s:submit/>
</s:form>
</body>
</html>

2) Add a Login.java action class in the src folder - the action class must extend the ActionSupport class in order to avail of the basic (programmatic) validation support of Struts2.

package info.icontraining.struts2;

import com.opensymphony.xwork2.*;

public class Login extends ActionSupport {

   public String execute() {
      return Action.SUCCESS;
   }
 
   private String username;
   private String password;
 
   public String getUsername() {
      return username;
   }
   public void setUsername(String username) {
      this.username = username;
   }
   public String getPassword() {
      return password;
   }
   public void setPassword(String password) {
      this.password = password;
   }
 
   public void validate() {
  
      boolean flag = false;
  
      if (getUsername().length() == 0) {
         addFieldError("username", "Username is required");
         flag = true;
      }
  
      if (getPassword().length() == 0) {
         addFieldError("password", "Password is required");
         flag = true;
      }
  
      if (!flag) 
         if (!getUsername().equals("dinesh") && !getPassword().equals("dinesh")) {
            addActionError("Username and/or Password incorrect. Please try again!");
         }
      }
}

The validate() method within the action class contains the code to validate the incoming user data. If validation errors occur it invokes the addFieldError() or the addActionError() methods.

3) Configure the struts.xml for the 2 actions, as follows,

<action name="Login">
 <result>/login.jsp</result>
</action>
  
<action name="doLogin" class="info.icontraining.struts2.Login">
 <result>/welcome.jsp</result>
 <result name="input">/login.jsp</result>
</action>

4) Create the welcome.jsp page which will be displayed when the user data is successfully validated

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>Welcome Page</title>
</head>
<body>
<h1>Welcome!</h1>
<h3>You have successfully logged in.</h3>
</body>
</html>

5) Test the code example by typing the following URL in the browser

http://localhost:8080/WebAppName/Login.action

- Press Submit without typing anything in the text fields
- Press Submit after typing in any one of the text fields
- Press Submit after typing something in both the text fields
- Press Submit after typing 'dinesh' in both the text fields

April 11, 2011

Struts 2 - There is no Action mapped for namespace / and action name

Exception:


There is no Action mapped for namespace / and action name Name. - [unknown location]
at com.opensymphony.xwork2.DefaultActionProxy.prepare(DefaultActionProxy.java:178)
at org.apache.struts2.impl.StrutsActionProxy.prepare(StrutsActionProxy.java:61)
at org.apache.struts2.impl.StrutsActionProxyFactory.createActionProxy(StrutsActionProxyFactory.java:39)
at com.opensymphony.xwork2.DefaultActionProxyFactory.createActionProxy(DefaultActionProxyFactory.java:47)
at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:478)
at org.apache.struts2.dispatcher.FilterDispatcher.doFilter(FilterDispatcher.java:395)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)



Application Server: JBoss 4.2.2GA / Tomcat

Resolution:

Unlike Struts 1, where the struts configuration file (struts-config.xml) is put in the WEB-INF folder of the web application, in Struts 2, the struts configuration file (struts.xml) should be present in the base class directory (or the root of the application classpath), i.e., in the WEB-INF/classes directory of the Application Deployment.

The resolution is to add the struts.xml file in the src folder of the Web Application in Eclipse (in the default package) instead of in the WebContent/WEB-INF of the application project in Eclipse

Struts 2 - Hello World Example

1) Download the Struts 2 framework jars and other dependent jars from the link here and copy them into the WebContent/WEB-INF/lib folder of the web application (in Eclipse).

2) Copy the following configuration for the Struts2 FilterDispatcher (which acts as the Controller) in the web.xml file of the Web Application

<filter>
  <filter-name>struts2</filter-name>
  <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
   
<filter-mapping>
  <filter-name>struts2</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

3) Create the HelloWorld.java class which is a POJO (and acts as the action class in Struts 2)

package info.icontraining.struts2;

public class HelloWorld {
 
   private static final String GREETING = "Hello ";

   public String execute()  {   
      setCustomGreeting( GREETING + getName() );
      return "success";
   }

   private String name;    

   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
    
   private String customGreeting;
    
   public String getCustomGreeting() {
      return customGreeting;
   }
   public void setCustomGreeting( String customGreeting ) {
      this.customGreeting = customGreeting;
   }
}

4) Create the NameCollector.jsp in the WebContent folder

<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
  <head>
    <title>Name Collector</title>
  </head>
  <body>
    <h4>Enter your name!</h4>  
    <s:form action="HelloWorld">
      <s:textfield name="name" label="Your name"/>
      <s:submit/>
    </s:form>
  </body> 
</html>

5) Create the Hello.jsp in the WebContent folder

<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
  <head>
    <title>HelloWorld</title>
  </head>
  <body>
     <h1><s:property value="customGreeting"/></h1>
  </body> 
</html>

6) Create the Struts2 Configuration file, struts.xml in the src folder of the Web Application (in the default package)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
   <constant name="struts.devMode" value="true" />
 
   <package name="myPackage" extends="struts-default">
    
      <action name="Name">
         <result>/NameCollector.jsp</result>
      </action>
  
      <action name="HelloWorld" class="info.icontraining.struts2.HelloWorld">
         <result name="success">/Hello.jsp</result>
      </action>

  </package>

</struts>

7) Test the code by typing the following URL in the browser:

http://localhost:8080/WebAppName/Name.action