2

I'm setting up an application that uses Struts 2.3 and Tiles 2. Some pages will be heavily Struts driven (e.g. lots of CRUD) while others will be simple, static HTML/JSP pages. I want to set up some actions that handle specific functionality and send all other URLs to a default action, which will check to see if the appropriate static page exists based on the supplied path. If not, a 404 error or some such will be generated instead.

In struts.xml, I have applied a basic configuration that appears like it should work; however, Struts seems to ignore the wildcard action. The non-wildcard actions work just fine.

Here's the struts.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
    "http://struts.apache.org/dtds/struts-2.3.dtd">
 
<struts>
    <!--
    You could also set the constants in the struts.properties file
    placed in the same directory as struts.xml
    -->
    <constant name="struts.devMode" value="true" />
    <!-- <constant name="struts.mapper.class" value="rest" /> -->
    
    <constant name="struts.action.extension" value="," />
    <constant name="struts.enable.SlashesInActionNames" value="true"/>
    <constant name="struts.mapper.alwaysSelectFullNamespace" value="false"/>
    <constant name="struts.patternMatcher" value="regex" />
    
    <!-- 
    <constant name="struts.convention.action.suffix" value="Controller"/>
    <constant name="struts.convention.action.mapAllMatches" value="true"/>
    <constant name="struts.convention.default.parent.package" value="rest-default"/>
    <constant name="struts.convention.package.locators" value="rest"/>
     -->
    
    <package name="base" extends="tiles-default" abstract="yes">
        <result-types>
            <result-type name="tiles" default="true" class="org.apache.struts2.views.tiles.TilesResult" />
            <result-type name="json" class="org.apache.struts2.json.JSONResult"/>
        </result-types>
    
        <interceptors>
            <interceptor name="json" class="org.apache.struts2.json.JSONInterceptor"/>
            <!-- <interceptor name="requestConstants" class="com.ibm.gbs.vdp.constants.ConstantsInterceptor" /> -->
            
            <interceptor-stack name="mainStack">
                <interceptor-ref name="defaultStack"/>
                <interceptor-ref name="json" />
                <!-- <interceptor-ref name="session" /> -->
                <!-- <interceptor-ref name="requestConstants" /> -->
            </interceptor-stack>
        </interceptors>
        
        <default-interceptor-ref name="mainStack" />
        
        <global-results>
            <result name="login" type="tiles">login</result>
        </global-results>
        
    </package>
 
    <!-- package start -->
    <package name="main" extends="base" namespace="/">
        <action name="login">
            <result type="tiles">login</result>
        </action>
        
        <action name="logout" class="com.gswt.common.action.LogoutAction">
            <result name="success">login</result>
        </action>
        
        <action name="*" class="com.installation.action.PageAction">
            <result type="tiles">standard-page</result>
        </action>
    </package>
    <!-- package end -->
    
    <!-- package start -->
    <package name="licenses" extends="base" namespace="/licenses">
        
    </package>
    <!-- package end -->
    
    <!-- package start -->
    <package name="checklists" extends="base" namespace="/checklists">
        
    </package>
    <!-- package end -->
    
    <!-- package start -->
    <package name="error" extends="base" namespace="/error">
        <action name="404">
            <result type="tiles">error-404</result>
        </action>
    </package>
    <!-- package end -->
 
</struts>

And here's an example of the error I receive:

There is no Action mapped for namespace [/] and action name [page] associated with context path []. - [unknown location]
    com.opensymphony.xwork2.DefaultActionProxy.prepare(DefaultActionProxy.java:185)
    org.apache.struts2.impl.StrutsActionProxy.prepare(StrutsActionProxy.java:63)
    org.apache.struts2.impl.StrutsActionProxyFactory.createActionProxy(StrutsActionProxyFactory.java:39)
    com.opensymphony.xwork2.DefaultActionProxyFactory.createActionProxy(DefaultActionProxyFactory.java:58)
    org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:553)
    org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:77)
    org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:99)
    com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:190)
    com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:125)
    com.ibm.ws.webcontainer.filter.WebAppFilterChain._doFilter(WebAppFilterChain.java:80)
    com.ibm.ws.webcontainer.filter.WebAppFilterManager.doFilter(WebAppFilterManager.java:908)
    com.ibm.ws.webcontainer.filter.WebAppFilterManager.invokeFilters(WebAppFilterManager.java:997)
    com.ibm.ws.webcontainer.extension.DefaultExtensionProcessor.invokeFilters(DefaultExtensionProcessor.java:1079)
    com.ibm.ws.webcontainer.extension.DefaultExtensionProcessor.handleRequest(DefaultExtensionProcessor.java:999)
    com.ibm.ws.webcontainer.webapp.WebApp.handleRequest(WebApp.java:3954)
    com.ibm.ws.webcontainer.webapp.WebGroup.handleRequest(WebGroup.java:276)
    com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:945)
    com.ibm.ws.webcontainer.WSWebContainer.handleRequest(WSWebContainer.java:1592)
    com.ibm.ws.webcontainer.channel.WCChannelLink.ready(WCChannelLink.java:191)
    com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleDiscrimination(HttpInboundLink.java:453)
    com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleNewRequest(HttpInboundLink.java:515)
    com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.processRequest(HttpInboundLink.java:306)
    com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.ready(HttpInboundLink.java:277)
    com.ibm.ws.ssl.channel.impl.SSLConnectionLink.determineNextChannel(SSLConnectionLink.java:1049)
    com.ibm.ws.ssl.channel.impl.SSLConnectionLink$MyReadCompletedCallback.complete(SSLConnectionLink.java:643)
    com.ibm.ws.ssl.channel.impl.SSLReadServiceContext$SSLReadCompletedCallback.complete(SSLReadServiceContext.java:1784)
    com.ibm.ws.tcp.channel.impl.AioReadCompletionListener.futureCompleted(AioReadCompletionListener.java:175)
    com.ibm.io.async.AbstractAsyncFuture.invokeCallback(AbstractAsyncFuture.java:217)
    com.ibm.io.async.AsyncChannelFuture.fireCompletionActions(AsyncChannelFuture.java:161)
    com.ibm.io.async.AsyncFuture.completed(AsyncFuture.java:138)
    com.ibm.io.async.ResultHandler.complete(ResultHandler.java:204)
    com.ibm.io.async.ResultHandler.runEventProcessingLoop(ResultHandler.java:775)
    com.ibm.io.async.ResultHandler$2.run(ResultHandler.java:905)
    com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1656)

What am I missing or doing wrong?

Roman C
  • 49,761
  • 33
  • 66
  • 176
Matt Hamann
  • 1,488
  • 12
  • 24

1 Answers1

3

Since you are using advanced wildcards then your action name should be a valid regex expression to match the configuration.

Like so

<action name="{.*}" class="com.installation.action.PageAction">
   <result type="tiles">standard-page</result>
</action>
Roman C
  • 49,761
  • 33
  • 66
  • 176
  • 1
    Surprisingly enough, that seems to work! However, I also get the following stack trace in my console on every request, which indicates to me that something still isn't quite right: http://pastebin.com/mfWqX5i9. You did solve the problem though, so I'll accept the answer :-) – Matt Hamann Jan 08 '14 at 20:00
  • Additionally, that syntax structure isn't mentioned anywhere in the docs, which makes things all the more frustrating! – Matt Hamann Jan 08 '14 at 20:03
  • OGNL has warnings setting unwanted parameter, this warning appears only in `devMode`. You may try to use a real parameter name with the pattern according the docs. – Roman C Jan 09 '14 at 13:58