July 21, 2011

XML Namespaces example with 2 XML Schemas (XSDs)

A working example of a XML document that references and contains elements from 2 XML Schema Documents (XSDs). Both the XSDs contain an element with a common name, demonstrating the utility of XML namespaces.

XSD-1: schema01.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns:s="http://example.org/s">

   <xs:import namespace="http://example.org/s" 
              schemaLocation="schema02.xsd"/>

   <xs:element name="root" type="RootType"/>

   <xs:complexType name="RootType">
     <xs:sequence>
       <xs:element name="qty" type="xs:integer" maxOccurs="unbounded"/>
       <xs:element ref="s:qty" maxOccurs="unbounded"/>
     </xs:sequence>
   </xs:complexType>
</xs:schema>

XSD-2: schema02.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
       targetNamespace="http://example.org/s"t
       xmlns:s="http://example.org/s"
       elementFormDefault="qualified">

   <xs:element name="qty" type="xs:string"/>

</xs:schema>

XML: test.xml

<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:noNamespaceSchemaLocation="schema01.xsd" 
       xmlns:s="http://example.org/s">
   <qty>12</qty>
   <s:qty>Twelve</s:qty>
</root>

July 20, 2011

Creating a new XML document with DOM Parser and persisting the DOM Tree

The following code example demonstrates the power of the DOM Parser by creating an XML document on-the-fly with the create methods from the DOM Parser API - something that is not possible to do with a SAX Parser. The code also shows how to take a DOM Tree and convert it to a String (XML content). This String can then be persisted to an XML document file.

package info.icontraining.parsers;

import java.io.StringWriter;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource; 
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.*;
import org.xml.sax.*;

public class DOMParserNewDocument implements ErrorHandler {
   public static void main(String[] args) throws TransformerException {

      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

      try {
         factory.setNamespaceAware(true);
         factory.setValidating(true);

         DocumentBuilder dom = factory.newDocumentBuilder();            
         dom.setErrorHandler(new DOMParserNewDocument());
         Document doc = dom.newDocument();

         Element invoiceElement = doc.createElement("Invoice");
         Attr invoiceNumberAttr = doc.createAttribute("invoice-number");
         invoiceNumberAttr.setNodeValue("123456");
         invoiceElement.setAttributeNode(invoiceNumberAttr);
         doc.appendChild(invoiceElement);

         Element dateElement = doc.createElement("date");         
         Element monthElement = doc.createElement("month");         
         Element dayElement = doc.createElement("day");
         Element yearElement = doc.createElement("year");

         monthElement.appendChild(doc.createTextNode("July"));
         dayElement.appendChild(doc.createTextNode("22"));
         yearElement.appendChild(doc.createTextNode("2011"));

         dateElement.appendChild(monthElement);          
         dateElement.appendChild(dayElement);
         dateElement.appendChild(yearElement);

         invoiceElement.appendChild(dateElement);  
         // convert DOM tree to XML string
   
         Transformer transformer =
                        TransformerFactory.newInstance().newTransformer();
         transformer.setOutputProperty(OutputKeys.INDENT, "yes");

         StreamResult result = new StreamResult(new StringWriter());
         DOMSource source = new DOMSource(doc);
         transformer.transform(source, result);

         String xmlString = result.getWriter().toString();
         System.out.println(xmlString);
     
      } catch (ParserConfigurationException e) {
         e.printStackTrace();
      } 
   }
 
   public void fatalError(SAXParseException err)
        throws SAXException {
      System.out.println("** Fatal Error"
                          + ", line " + err.getLineNumber()
                          + ", uri " + err.getSystemId());
      System.out.println(" " + err.getMessage());
   }

   public void error(SAXParseException err)        
         throws SAXParseException {
      System.out.println("** Error"
                          + ", line " + err.getLineNumber()
                          + ", uri " + err.getSystemId());
      System.out.println(" " + err.getMessage());
   }

   public void warning(SAXParseException err)         
        throws SAXParseException {
      System.out.println("** Warning"
                          + ", line " + err.getLineNumber()
                          + ", uri " + err.getSystemId());
      System.out.println(" " + err.getMessage());
   }
}

Parsing XML with a DOM Parser

The DOM Parser in the example code below is a validating parser. The parser code, processes the element, attribute and the text nodes of the document and prints them to the console (while ignoring the rest of the XML artifacts). It does not modify the XML document eventhough it maintains an in-memory representation of the XML Document.

package info.icontraining.parsers;

import java.io.IOException;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.*;

public class DOMParserWithDTD implements ErrorHandler {
 
   public static void main(String[] args) throws SAXException, IOException  {
  
      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
  
      try {
         factory.setNamespaceAware(true);
         factory.setValidating(true);
         factory.setFeature("http://apache.org/xml/features/validation/schema", true);
         factory.setIgnoringElementContentWhitespace(true);
   
         DocumentBuilder dom = factory.newDocumentBuilder();
         dom.setErrorHandler(new TestDOMParser());
         Document doc = dom.parse("Invoice.xml");
   
         processNode(doc);

      } catch (ParserConfigurationException e) {
         e.printStackTrace();
      }     
   } 
   
   private static void processNode(Node node) {

      NodeList list = node.getChildNodes();   
      for(int i=0; i<list.getLength(); i++) {
 
         if (list.item(i).getNodeType() == Node.ELEMENT_NODE) {
            processElementNode(list.item(i));
            processNode(list.item(i));
         }
   
         if (list.item(i).getNodeType() == Node.TEXT_NODE) {
            processTextNode(list.item(i));
         }
      }
   }
 
   private static void processTextNode(Node text) {  
      if (text.getNodeValue().trim().length() != 0)
         System.out.println(text.getNodeValue().trim());
   }    

   private static void processElementNode(Node element) {
  
      String temp = "";
      temp = temp + "<" + element.getNodeName();
  
      if (element.hasAttributes()) {
         NamedNodeMap map = element.getAttributes();
        
         for(int i=0; i<map.getLength(); i++) {
            temp = temp + " " + map.item(i).getNodeName();
            temp = temp + "=\"" + map.item(i).getNodeValue() + "\"";
         }
      }
  
      temp = temp + ">";
      System.out.println(temp);
   }
 
   public void fatalError(SAXParseException err) throws SAXException {

      System.out.println("** Fatal Error" 
                          + ", line " + err.getLineNumber() 
                          + ", uri " + err.getSystemId());
      System.out.println(" " + err.getMessage());
   }     

   public void error(SAXParseException err) throws SAXParseException {
      System.out.println("** Error" 
                          + ", line " + err.getLineNumber() 
                          + ", uri " + err.getSystemId());
      System.out.println(" " + err.getMessage());
   }

   public void warning(SAXParseException err) throws SAXParseException {
      System.out.println("** Warning" 
                          + ", line " + err.getLineNumber()              
                          + ", uri " + err.getSystemId());
      System.out.println(" " + err.getMessage());
   }
}

July 18, 2011

Access outer class instance from within the inner class method

MyOuter is the outer class which contains MyInner which is the inner class. The seeOuter() method within the inner class can access the inner class instance with the this keyword. In order to access the outer class instance from within the seeOuter() method, the syntax is use the outer class name with the this keyword - the syntax looks like this: OuterClassName.this

The code example below demonstrates the same,

package info.icontraining.basic;

public class MyOuter {
     private int x = 3;
 
   class MyInner {
      private int x = 5;
  
      public void seeOuter() {
         System.out.println("Inner x is = " + this.x);
         System.out.println("Outer x is = " + MyOuter.this.x );
      }
   }
 
   public static void main(String[] args) {
      MyOuter.MyInner inner = new MyOuter().new MyInner();
      inner.seeOuter();
   }
}

July 16, 2011

Externalizing literal values from the applicationContext.xml into a properties file

0) Refer to the example for wiring collections into a spring bean here

1) Add the following configuration in the applicationContext.xml to enable externalizing literal values into a properties file

<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
   <property name="location"   
       value="classpath:resources/MessageResources.properties" />
</bean>

2) Add a new properties file - MessageResources.properties in the resources package (within the src folder). Add the following contents in the MessageResources.properties

list.string1=String 1 externalized
list.string2=String 2 externalized
list.string3=String 3 externalized

3) Modify the configuration for the bean in the wiring collections example, in the applicationContext.xml, as follows,

<bean id="listExample"
         class="info.icontraining.spring.CollectionsExample">
   <property name="myList">
      <list>
         <value>${list.string1}</value>
         <value>${list.string2}</value>
         <value>${list.string3}</value>
      </list>
   </property>
   <property name="myMap">
      <map>
         <entry key="key1" value="value1" />
         <entry key="key2" value="value2" />
         <entry key="key3" value="value3" />
      </map>
   </property>
</bean>

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

http://localhost:8080/TestWebApp/springTest.jsp

Wiring Collections in a Spring bean

0) Setup the Spring framework in the web application by executing the Hello World example at this link

1) Create the interface for the spring bean, ICollections.java, as follows,

package info.icontraining.spring;

public interface ICollections {
   public void printList();
   public void printMap();
}

2) Create a spring bean class, CollectionsExample.java as follows,

package info.icontraining.spring;

import java.util.*;

public class CollectionsExample implements ICollections {

   List list;
   Map map;
 
   public void printList() {
      for(String s: list) {
         System.out.println(s);
      }
   }
 
   public void printMap() {
      for(String s: map.keySet()) {
         System.out.println(s + ": " + map.get(s));
      }
   }
 
   public void setMyList(List list) {
      this.list = list;
   }
 
   public void setMyMap(Map map) {
      this.map = map;
   }
}

3) Add the following configuration for the spring bean in the applicationContext.xml file in WebContent/WEB-INF folder - this configuration injects a List and a Map into the spring bean.

<bean id="listExample" class="info.icontraining.spring.CollectionsExample">
   <property name="myList">
      <list>
         <value>String 1</value>
         <value>String 2</value>
         <value>String 3</value>
      </list>
   </property>
   <property name="myMap">
      <map>
         <entry key="key1" value="value1" />
         <entry key="key2" value="value2" />
         <entry key="key3" value="value3" />
      </map>
   </property>
</bean>

4) Create a JSP, springTest.jsp as follows,

<%@ page  import="org.springframework.context.*,org.springframework.web.context.*,info.icontraining.spring.*"%>
<html>
<body>
View output on Server console
<%
ApplicationContext factory =
  (ApplicationContext) this.getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE); ICollections collection = (ICollections)factory.getBean("listExample");
collection.printList();
collection.printMap();
%>

</body>
</html>

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

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

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