Navigation Bar

Tuesday, November 3, 2009

Struts 2 : moving your application to Struts 2

The intent of this post is not primarily to describe the building of the application with Struts 2 framework.
The main intent is to show how to start building the application from a starting reference point, run the application, identify and fix the errors that keep coming at each step.

We use the "getquote" project which we have built using Struts 1.1.
On the way, we can also see the new features in Struts 2 and the scripts used in Struts 1.1 which are now no longer needed.
I am using Claude AI to resolve the errors that I get at compile and run time.

 We start off with a set of jar files given below

commons-fileupload2-core-2.0.0-M4.jar
commons-io-2.20.0.jar
commons-lang3-3.19.0.jar
commons-logging-1.3.5.jar
commons-logging-api-1.1.jar
freemarker-2.3.34.jar
javassist-3.29.0-GA.jar
ognl-3.3.5.jar
servlet-api.jar
struts2-core-7.1.1.jar
xwork-core-2.3.35.jar
I make the folder structure as described in my earlier posts and do a build. 
I get 12 errors as shown below.  
E:\install\tomcat\tomcat11013\webapps\getquote>ant
Buildfile: build.xml
     [echo] 111111...

compile-single:
     [echo] Compiling LookupForm.java ...
    [javac] Compiling 2 source files to E:\install\tomcat\tomcat11013\webapps\getquote\WEB-INF\classes
    [javac] E:\install\tomcat\tomcat11013\webapps\getquote\src\src\LookupAction.java:7: error: package org.apache.struts.action does not exist
    [javac] import org.apache.struts.action.Action;
    [javac]                                ^
    [javac] E:\install\tomcat\tomcat11013\webapps\getquote\src\src\LookupAction.java:8: error: package org.apache.struts.action does not exist
    [javac] import org.apache.struts.action.ActionForm;
    [javac]                                ^
    [javac] E:\install\tomcat\tomcat11013\webapps\getquote\src\src\LookupAction.java:9: error: package org.apache.struts.action does not exist
    [javac] import org.apache.struts.action.ActionForward;
    [javac]                                ^
    [javac] E:\install\tomcat\tomcat11013\webapps\getquote\src\src\LookupAction.java:10: error: package org.apache.struts.action does not exist
    [javac] import org.apache.struts.action.ActionMapping;
    [javac]                                ^
    [javac] E:\install\tomcat\tomcat11013\webapps\getquote\src\src\LookupAction.java:12: error: cannot find symbol
    [javac] public class LookupAction extends Action {
    [javac]                                   ^
    [javac]   symbol: class Action
    [javac] E:\install\tomcat\tomcat11013\webapps\getquote\src\src\LookupAction.java:19: error: cannot find symbol
    [javac]     public ActionForward execute (ActionMapping mapping,
    [javac]                                   ^
    [javac]   symbol:   class ActionMapping
    [javac]   location: class LookupAction
    [javac] E:\install\tomcat\tomcat11013\webapps\getquote\src\src\LookupAction.java:20: error: cannot find symbol
    [javac]             ActionForm form,
    [javac]             ^
    [javac]   symbol:   class ActionForm
    [javac]   location: class LookupAction
    [javac] E:\install\tomcat\tomcat11013\webapps\getquote\src\src\LookupAction.java:19: error: cannot find symbol
    [javac]     public ActionForward execute (ActionMapping mapping,
    [javac]            ^
    [javac]   symbol:   class ActionForward
    [javac]   location: class LookupAction
    [javac] E:\install\tomcat\tomcat11013\webapps\getquote\src\src\LookupForm.java:4: error: package org.apache.struts.action does not exist
    [javac] import org.apache.struts.action.ActionForm;
    [javac]                                ^
    [javac] E:\install\tomcat\tomcat11013\webapps\getquote\src\src\LookupForm.java:5: error: package org.apache.struts.action does not exist
    [javac] import org.apache.struts.action.ActionMapping;
    [javac]                                ^
    [javac] E:\install\tomcat\tomcat11013\webapps\getquote\src\src\LookupForm.java:7: error: cannot find symbol
    [javac] public class LookupForm extends ActionForm {
    [javac]                                 ^
    [javac]   symbol: class ActionForm
    [javac] E:\install\tomcat\tomcat11013\webapps\getquote\src\src\LookupForm.java:17: error: cannot find symbol
    [javac]     public void reset (ActionMapping mapping, HttpServletRequest request) {
    [javac]                        ^
    [javac]   symbol:   class ActionMapping
    [javac]   location: class LookupForm
    [javac] E:\install\tomcat\tomcat11013\webapps\getquote\src\src\LookupAction.java:15: warning: [removal] Double(double) in Double has been deprecated and marked for removal
    [javac]             return new Double (25.00);
    [javac]                    ^
    [javac] 12 errors
    [javac] 1 warning

The above errors are because I am importing packages from Struts 1.
For the Struts 2 framework we import com.opensymphony.xwork2.ActionSupport;

In LookupForm.java and LookupAction.java we replace the following Struts 1 packages
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
with the below Struts 2 package
import com.opensymphony.xwork2.ActionSupport;
I now run the ant script and the errors have come down to 6.
compile-single:
     [echo] Compiling LookupForm.java ...
    [javac] Compiling 2 source files to E:\install\tomcat\tomcat11013\webapps\getquote\WEB-INF\classes
    [javac] E:\install\tomcat\tomcat11013\webapps\getquote\src\src\LookupAction.java:9: error: cannot find symbol
    [javac] public class LookupAction extends Action {
    [javac]                                   ^
    [javac]   symbol: class Action
    [javac] E:\install\tomcat\tomcat11013\webapps\getquote\src\src\LookupAction.java:16: error: cannot find symbol
    [javac]     public ActionForward execute (ActionMapping mapping,
    [javac]                                   ^
    [javac]   symbol:   class ActionMapping
    [javac]   location: class LookupAction
    [javac] E:\install\tomcat\tomcat11013\webapps\getquote\src\src\LookupAction.java:17: error: cannot find symbol
    [javac]             ActionForm form,
    [javac]             ^
    [javac]   symbol:   class ActionForm
    [javac]   location: class LookupAction
    [javac] E:\install\tomcat\tomcat11013\webapps\getquote\src\src\LookupAction.java:16: error: cannot find symbol
    [javac]     public ActionForward execute (ActionMapping mapping,
    [javac]            ^
    [javac]   symbol:   class ActionForward
    [javac]   location: class LookupAction
    [javac] E:\install\tomcat\tomcat11013\webapps\getquote\src\src\LookupForm.java:6: error: cannot find symbol
    [javac] public class LookupForm extends ActionForm {
    [javac]                                 ^
    [javac]   symbol: class ActionForm
    [javac] E:\install\tomcat\tomcat11013\webapps\getquote\src\src\LookupForm.java:16: error: cannot find symbol
    [javac]     public void reset (ActionMapping mapping, HttpServletRequest request) {
    [javac]                        ^
    [javac]   symbol:   class ActionMapping
    [javac]   location: class LookupForm

We now keep adding some jar files from struts 2 to find the missing jar.
I add servlet-api.jar  and compile .. I still get the same set of errors.

I put these errors in Claude AI and I get the following output..

GiantRobot tells me
Key Differences:
No ActionForm - properties go directly in the action
No ActionMapping/ActionForward - return String values like "success"
No HttpServletRequest/Response in execute() - use interceptors or inject if needed
With the information at hand and with a sample Action class provided by Giant Robot, I make the following changes in my code and compile it. 
Put the getter and setter methods in the LookupAction.
import com.opensymphony.xwork2.ActionSupport;
LookupAction now extends only ActionSupport and does not require ActionForm, ActionMapping, HttpServletRequest and HttpServletResponse parameters.
There is no need to throw any Exceptions as in Struts 1.1 .. throws IOException, ServletException
The execute method also does not require an ActionForward and expects a String object like success or failure.
 
After resolving a few syntax errors my final code is below. ..To be Continued ...
 
package src;

import java.io.IOException;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import com.opensymphony.xwork2.ActionSupport;

public class LookupAction extends ActionSupport {
	
	private Double price = null;
	private String symbol;
	private String target = new String ("success");
			
    protected Double getQuote ( String symbol) {
        if ( symbol.equalsIgnoreCase ("SUNW") ) {
            return new Double (25.00);
        }
        return null;
    }
	
	public void validate() {
		if (symbol == null || symbol.trim().length() == 0) {
			addFieldError("symbol", "Symbol is required");
		}
	}
	
    public String getSymbol(){
		return (symbol);
	}

	public void setSymbol (String symbol) {
		this.symbol = symbol;
	}
	
	public Double getPrice(){
		return (price);
	}

	public void setPrice (Double price) {
		this.price = price;
	}


    public String execute (){
               
		price = getQuote(symbol);
		//Set the target to failure
		if (price == null) {
			target = new String ("failure");
		}
		else {
			target = new String ("success");
		}
		return target;
    } //execute
}

Make changes to index.jsp, result file quote.jsp, struts.xml and web.xml.
Changes and file structure will be shared.

Now start the tomcat server. I get the below error in /logs/catalina.2025-11-05.log.   
Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/getquote]]
		at org.apache.catalina.util.LifecycleBase.handleSubClassException(LifecycleBase.java:404)
		at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:179)
		at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:564)
		... 34 more
	Caused by: java.lang.NoClassDefFoundError: org/apache/logging/log4j/Logger
		at java.base/java.lang.Class.getDeclaredFields0(Native Method)
		at java.base/java.lang.Class.privateGetDeclaredFields(Class.java:3475)
		at java.base/java.lang.Class.getDeclaredFields(Class.java:2544)
		at org.apache.catalina.startup.WebAnnotationSet.loadFieldsAnnotation(WebAnnotationSet.java:199)
		at org.apache.catalina.startup.WebAnnotationSet.loadApplicationFilterAnnotations(WebAnnotationSet.java:111)
		at org.apache.catalina.startup.WebAnnotationSet.loadApplicationAnnotations(WebAnnotationSet.java:69)
		at org.apache.catalina.startup.ContextConfig.applicationAnnotationsConfig(ContextConfig.java:314)
		at org.apache.catalina.startup.ContextConfig.configureStart(ContextConfig.java:971)
		at org.apache.catalina.startup.ContextConfig.lifecycleEvent(ContextConfig.java:288)
		at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:109)
		at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:4334)
		at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:164)
		... 35 more
	Caused by: java.lang.ClassNotFoundException: org.apache.logging.log4j.Logger
		at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1225)
		at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1056)
add log4j-api-2.25.2.jar and log4j-core-2.24.1.jar jar files to the CATALINA_HOME/webapps/getquote/WEB-INF/lib folder.
Shutdown the webserver, cleanup the "work" folder and restart the web server.
Now the web server is starting correctly and the "getquote" application has got deployed without any errors.
We now run the application from broswer
http://localhost:8080/getquote/index.jsp
and now I get a run time error on the browser
HTTP Status 404 – Not Found
Type Status Report

Message JSP file [/getquote/index.jsp] not found

Description The origin server did not find a current representation for the target resource or is not willing to disclose that one exists.
In the localhost.2025-11-05.log I get error
Caused by: java.lang.ClassNotFoundException: org.apache.commons.text.StringSubstitutor
		at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1225)
		at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1056)
		... 75 more
05-Nov-2025 17:00:44.588 INFO [main] org.apache.catalina.core.ApplicationContext.log SessionListener: contextDestroyed()
05-Nov-2025 17:00:44.588 INFO [main] org.apache.catalina.core.ApplicationContext.log ContextListener: contextDestroyed()
05-Nov-2025 17:00:52.902 INFO [main] org.apache.catalina.core.ApplicationContext.log ContextListener: contextInitialized()
05-Nov-2025 17:00:52.903 INFO [main] org.apache.catalina.core.ApplicationContext.log SessionListener: contextInitialized()
05-Nov-2025 17:00:52.909 INFO [main] org.apache.catalina.core.ApplicationContext.log ContextListener: attributeAdded('StockTicker', 'async.Stockticker@4648ce9')
05-Nov-2025 17:00:55.522 SEVERE [main] org.apache.catalina.core.StandardContext.filterStart Exception starting filter [struts2]
	java.lang.NoClassDefFoundError: org/apache/commons/text/StringSubstitutor
I have hit a roadblock now, and I need the help of Giant Robot. Giant Robot tells me I need the commons-text-1.14.0.jar jar file. I add it and restart the server. In catalina.2025-11-05.log I get error
05-Nov-2025 17:48:39.017 SEVERE [main] org.apache.catalina.core.StandardContext.startInternal One or more Filters failed to start. Full details will be found in the appropriate container log file
05-Nov-2025 17:48:39.039 SEVERE [main] org.apache.catalina.core.StandardContext.startInternal Context [/getquote] startup failed due to previous errors
05-Nov-2025 17:48:39.089 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [E:\install\tomcat\tomcat11013\webapps\getquote] has finished in [3,123] ms
In localhost.2025-11-05.log I get error NoClassDefFoundError: com/github/benmanes/caffeine/cache/Caffeine
	Caused by: java.lang.NoClassDefFoundError: com/github/benmanes/caffeine/cache/Caffeine
		at org.apache.struts2.ognl.OgnlCaffeineCache.(OgnlCaffeineCache.java:43)
		at org.apache.struts2.ognl.DefaultOgnlCacheFactory.buildOgnlCache(DefaultOgnlCacheFactory.java:58)
		at org.apache.struts2.ognl.DefaultOgnlCacheFactory.buildOgnlCache(DefaultOgnlCacheFactory.java:47)
		at org.apache.struts2.ognl.OgnlUtil.(OgnlUtil.java:85)
		at java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:62)
		... 120 more
	Caused by: java.lang.ClassNotFoundException: com.github.benmanes.caffeine.cache.Caffeine
		at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1225)
		at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1056)
		... 125 more
Add the caffeine-3.2.2.jar.
http://localhost:8080/getquote/ gives below error
HTTP Status 500 – Internal Server Error
Type Exception Report

Message An exception occurred processing [/index.jsp] at line [35]

Description The server encountered an unexpected condition that prevented it from fulfilling the request.

Exception

org.apache.jasper.JasperException: An exception occurred processing [/index.jsp] at line [35]

32:     
33: 	
34: 		
35: 		
36: 	
37: 
38: Stacktrace: org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:566) org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:456) org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:330) org.apache.jasper.servlet.JspServlet.service(JspServlet.java:281) jakarta.servlet.http.HttpServlet.service(HttpServlet.java:710) org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter.handleRequest(StrutsPrepareAndExecuteFilter.java:151) org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter.tryHandleRequest(StrutsPrepareAndExecuteFilter.java:137) org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:125) Root Cause java.lang.NullPointerException: Cannot invoke "java.util.List.add(Object)" because "tags" is null org.apache.struts2.components.UIBean.evaluateParams(UIBean.java:835) org.apache.struts2.components.UIBean.end(UIBean.java:566) org.apache.struts2.views.jsp.ComponentTagSupport.doEndTag(ComponentTagSupport.java:36) org.apache.jsp.index_jsp._jspx_meth_s_005ftextfield_005f0(index_jsp.java:251) org.apache.jsp.index_jsp._jspx_meth_s_005fform_005f0(index_jsp.java:215) org.apache.jsp.index_jsp._jspService(index_jsp.java:170) org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:64) jakarta.servlet.http.HttpServlet.service(HttpServlet.java:710) org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:428) org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:330) org.apache.jasper.servlet.JspServlet.service(JspServlet.java:281) jakarta.servlet.http.HttpServlet.service(HttpServlet.java:710) org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter.handleRequest(StrutsPrepareAndExecuteFilter.java:151) org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter.tryHandleRequest(StrutsPrepareAndExecuteFilter.java:137) org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:125) Note The full stack trace of the root cause is available in the server logs. God's Word for the day
My child, treat yourself well, according to your means,
  and present worthy offerings to the Lord.
Remember that death does not tarry,
  and the decree of Hades has not been shown to you.
Do good to friends before you die,
  and reach out and give to them how much as you can.
Do not deprive yourself of a day's enjoyment;
  do not let your share of desired good pass you by.
Sirach 14:7-10

Do Not Worry
Therefore I tell you, do not worry about your life,
  what you will eat or what you will drink,
Or about your body, what you will wear.
  Is not life more than food and clothing?
Look at the birds of the air; they neither sow not reap, nor gather into barns,
  And yet your heavenly Father feeds them.
Are you not of more value than they?
Mathew 6:25-26

No comments:

Post a Comment