Back to: Java Struts Tutorials
Struts 2 Value Stack and OGNL
In this article, I am going to discuss Struts 2 Value Stack and OGNL with Examples. Please read our previous article where we discussed Struts 2 Results Types.
What is Value Stack?
In Struts 2, the Value Stack is a fundamental component that is used to store and access data during the processing of an action. It serves as a context-specific data storage mechanism, allowing easy access to data within the various components involved in handling a request.
The Value Stack is a stack-like data structure, where each element represents a context-specific object or value. It is designed to facilitate the transfer and retrieval of data between the action, the view (JSP or other template), and other components in the request processing flow.
Points to Remember While Working with Struts 2 Value Stack:
Here are some key points to understand about the Value Stack:
- Data Storage: The Value Stack stores various types of data, including action properties, request parameters, session attributes, and other objects involved in the request processing. It provides a unified storage mechanism, ensuring easy access and management of data across different components.
- Accessing Data: Components like JSP views, Struts tags, and custom tags can directly access the data on the Value Stack. This eliminates the need for explicit data passing between components and allows seamless integration of data into the views.
- Object Lookup: The Value Stack uses a “find value” algorithm to locate objects or values based on the given key or expression. It searches the stack from top to bottom, looking for the requested object. This hierarchical lookup enables accessing objects at different scopes, such as action-specific data, request-level data, or even framework-specific data.
- Push and Pop Operations: The Value Stack supports push and pop operations, allowing you to add or remove objects from the stack. This is useful when you want to introduce temporary data or control the visibility of certain objects within a specific context.
- OGNL Integration: The Value Stack integrates with the Object-Graph Navigation Language (OGNL), which is a powerful expression language. OGNL simplifies data access and manipulation on the Value Stack, providing features like property navigation, method invocation, and conditional expressions.
The Value Stack stores various types of data that are relevant to the current request being processed. It acts as a container for different objects and values, making them accessible to different components within the request processing flow. Here are some common types of data that can be stored in the Value Stack:
- Action Properties: The properties of the action class associated with the current request are stored in the Value Stack. These properties can be accessed and manipulated by the view layer, allowing the presentation of dynamic data.
- Request Parameters: The parameters submitted with the request, such as form inputs or query parameters, are typically stored in the Value Stack. These values can be retrieved and utilized in the view layer to display or process user input.
- Action Errors and Messages: Any error messages or informational messages generated during the action processing can be stored in the Value Stack. This allows the view layer to display these messages to the user, providing feedback or validation results.
- Model Objects: Other objects relevant to the request, often referred to as model objects, can also be stored in the Value Stack. These can include domain objects, DTOs (Data Transfer Objects), or any other objects needed for data manipulation or display in the view layer.
- Framework Objects: The Value Stack can also store framework-related objects, such as Struts 2 tags, utility objects, or contextual information specific to the Struts 2 framework.
It’s important to note that the Value Stack follows a hierarchical structure, with different scopes of data available. The stack is searched from top to bottom to locate the desired object or value, allowing for easy access to data in different contexts. For example, action properties will be searched first, followed by request parameters and other stored objects.
By storing these various types of data in the Value Stack, Struts 2 provides a convenient and organized way to manage and access the relevant information throughout the request processing lifecycle. This enables the separation of concerns and promotes a more efficient development workflow.
The Value Stack object provides several methods to manipulate and access data stored in it. Here are some commonly used methods of the Value Stack object:
- push(Object obj): This method pushes an object onto the top of the Value Stack. It adds the object to the stack, making it the most accessible object for data retrieval.
- pop(): This method removes the topmost object from the Value Stack and returns it. It allows you to remove an object from the stack, typically used when you want to control the visibility or lifespan of an object within a specific context.
- findValue(String expr): This method finds and returns the value of an expression on the Value Stack. The expression can be a simple property name or a more complex OGNL expression. It searches the stack from top to bottom, locating the requested value.
- findString(String expr): This method finds and returns the value of an expression as a string. It automatically converts the value to a string representation, making it convenient for displaying in the view layer.
- getRoot(): This method retrieves the root object on the Value Stack. The root object represents the topmost object in the stack and is typically the action object associated with the current request.
- getContext(): This method retrieves the OGNL context associated with the Value Stack. The context provides additional functionality for OGNL expressions, such as setting variables, controlling type conversion, or invoking methods.
- set(String expr, Object value): This method sets the value of an expression on the Value Stack. It allows you to update or assign a new value to a specific expression.
- getParameter(String name): This method retrieves a request parameter value from the Value Stack. It is useful for accessing parameters submitted with the request, such as form inputs or query parameters.
These are just a few examples of the methods available on the Value Stack object. The Value Stack provides a rich set of methods to manipulate and retrieve data, allowing easy integration between the action layer, view layer, and other components involved in request processing.
Overall, the Value Stack in Struts 2 provides a unified data storage and retrieval mechanism, enabling easy communication between different components involved in request processing. It simplifies the passing of data from actions to views and allows the views to access and display the necessary information without explicitly referencing request attributes or session objects.
What is OGNL in Struts 2?
OGNL (Object-Graph Navigation Language) is an expression language used in Struts 2 for accessing and manipulating objects and their properties. It is a powerful and flexible language that simplifies data access and manipulation within the Struts 2 framework.
Here are some key features and concepts related to OGNL in Struts 2:
- Expression Language: OGNL provides a concise and intuitive syntax for navigating and manipulating object graphs. It allows you to access object properties, invoke methods, perform arithmetic and logical operations, and handle conditional expressions.
- Object Navigation: OGNL allows you to navigate through the object graph by specifying property names and using dot notation. For example, you can access the name property of an object user using the expression user.name.
- Property Access: OGNL provides a simple way to access object properties, including nested properties. You can chain property names together to access properties at different levels of the object hierarchy. For example, user.address.city accesses the city property of the address property of the user object.
- Method Invocation: OGNL allows you to invoke methods on objects using a syntax similar to property access. You can call parameterless methods or pass arguments to methods using parentheses. For example, user.getName() invokes the getName() method on the user object.
- Collection and Array Operations: OGNL supports operations on collections and arrays, such as accessing elements by index, iterating over collection items, and performing filtering or transformation operations.
- Conditional Expressions: OGNL provides conditional expressions using the ternary operator (? 🙂 and logical operators (&&, ||, !). This allows you to perform conditional checks and control the flow of expressions.
- OGNL Integration in Struts 2: Struts 2 integrates OGNL as its default expression language. It is extensively used in Struts 2 tags, views (such as JSP or FreeMarker templates), and other components to access and display data from the Value Stack and manipulate object properties.
By using OGNL in Struts 2, developers can easily access, manipulate, and display data within the framework. OGNL simplifies the process of binding data between the action layer and the view layer, enabling efficient development and separation of concerns.
Implementing Value Stack and OGNL in Struts2
This project will be implemented using ActionSupport. Hence, we have made a copy of the program from the “Struts2 ActionSupport” article. The files and their content are as follows:
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.dotnet</groupId> <artifactId>strutex</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <dependencies> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-core</artifactId> <version>6.1.2.1</version> </dependency> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-convention-plugin</artifactId> <version>6.1.2.1</version> </dependency> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts-taglib</artifactId> <version>1.3.10</version> </dependency> <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> <version>6.0.0</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.11.0</version> <configuration> <source>17</source> <target>17</target> </configuration> </plugin> </plugins> </build> </project>
src/main/webapp/WEB-INF/web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemalocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/web-app_3_0.xsd" id="apache-struts-config-example" version="3.0"> <display-name>Struts Config XML</display-name> <filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
src/main/webapp/index.html
<!DOCTYPE html> <html> <head> <title>Example of Struts</title> </head> <body> <form action="hello.action"> <p>What is your name?</p> <input type="text" name="userName"/> <input type="submit" value="submit"/> </form> </body> </html>
src/main/java/com/dotnet/HelloAction.java
package com.dotnet; import org.apache.struts2.convention.annotation.Action; import com.opensymphony.xwork2.ActionSupport; @Action("/hello") public class HelloAction extends ActionSupport { public String execute() { if(userName.equalsIgnoreCase("world")) return SUCCESS; else return ERROR; } private String userName; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } }
src/main/webapp/results.jsp
<%@ taglib prefix="s" uri="/struts-tags" %> <%@ page contentType="text/html; charset=UTF-8" %> <!DOCTYPE html> <html> <head> <title>Results page</title> </head> <body> <p>Hello <s:property value="userName"/>!</p> </body> </html>
src/main/resources/struts.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd"> <struts> <package name="default" extends="struts-default"> <action name="hello" class="com.dotnet.HelloAction" method="execute"> <result name="success">/results.jsp</result> <result name="error">/error.jsp</result> </action> </package> </struts>
src/main/webapp/error.jsp
<%@ page contentType = "text/html; charset = UTF-8" %> <%@ taglib prefix = "s" uri = "/struts-tags" %> <html> <head> <title>Access Denied</title> </head> <body> You are not authorized to view this page. </body> </html>
Step 1: Modify the HelloAction.java file as follows:
package com.dotnet; import java.util.HashMap; import java.util.Map; import org.apache.struts2.convention.annotation.Action; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionSupport; import com.opensymphony.xwork2.util.ValueStack; @Action("/hello") public class HelloAction extends ActionSupport { public String execute() { ValueStack stack = ActionContext.getContext().getValueStack(); Map<String, Object> context = new HashMap<String, Object>(); context.put("key1", new String("This is key1")); context.put("key2", new String("This is key2")); stack.push(context); System.out.println("Size of the value stack: " + stack.size()); return SUCCESS; } private String userName; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } }
We have performed the following modifications
- Imported the required packages
- Modified the execute() function to use the value stack.
The execute() function obtains a new object of type ValueStack and adds two values to it. It then asks for the ValueStack’s size.
Step 2: Since the execute() function does not return an ERROR anymore, the error.jsp file is not used. you may delete the file from your project directory. If you decide to do so, remember to modify the struts.xml file to reflect this change:
Step 3: Modify the results.jsp file as follows:
<%@ page contentType = "text/html; charset = UTF-8" %> <%@ taglib prefix = "s" uri = "/struts-tags" %> <html> <head> <title>Hello World</title> </head> <body> Entered value : <s:property value = "name"/><br/> Value of key 1 : <s:property value = "key1" /><br/> Value of key 2 : <s:property value = "key2" /> <br/> </body> </html>
This page is now supposed to print the values from the ValueStack.
Step 4: Compile and execute the program on the Tomcat server. The following page must open in your default browser:
Enter any name and click on the submit button. This should redirect you to the results.jsp page. It should look like this:
Also, if you look into the terminal, the following statement will be printed:
In the next article, I am going to discuss Struts 2 Uploading Files with Examples. Here, in this article, I try to explain Struts 2 Value Stack and OGNL with Examples and I hope you enjoy this Struts 2 Value Stack and OGNL article.