Wildcard action mapping with dummy data in Struts 2 - url-rewriting

I'm trying to map my Struts actions using wildcards.
Before, I used UrlRewrite Filter by Tuckey. But this question changed my mind.
So here's my problem: My URL's look like the following:
www.example.com/promoties/category-123
www.example.com/promoties/category-123/subcategory-456
In these examples, the words category and subcategory are dummy data used to make the URL more relevant for search engines.
Now I'd like to ignore this dummy data, as I'm just interested in the (last) ID. In the first case 123 in the last case 456.
I've tried the following without success:
<package name="promoties" namespace="/promoties" extends="struts-default">
<action name="([0-9a-zA-Z\-_]+)-{id:([0-9]+)}$" class="CategoryAction">
<result type="tiles">categorydetail</result>
</action>
</package>
Using following options in my struts.xml:
<constant name="struts.enable.SlashesInActionNames" value="true"/>
<constant name="struts.mapper.alwaysSelectFullNamespace" value="false"/>
<constant name="struts.patternMatcher" value="regex" />
Has anyone tried this before? How would I go about doing this in Struts2?

One way is to use simple wild card mapping and regulate the validation of the id component to struts2 validation. Here is an example which has been tested, but without validation.
struts.xml you'll see an action defined for category-* and category-*/subcategory-* in the second we'll just keep the second wild card.
<struts>
<constant name="struts.enable.DynamicMethodInvocation" value="false" />
<constant name="struts.devMode" value="true" />
<constant name="struts.ognl.allowStaticMethodAccess" value="true"/>
<constant name="struts.enable.SlashesInActionNames" value="true"/>
<constant name="struts.mapper.alwaysSelectFullNamespace" value="false"/>
<package namespace="" name="default" extends="struts-default">
<action name="category-*" class="test.TestBean">
<param name="id">{1}</param>
<result>/WEB-INF/content/test/results.jsp</result>
</action>
<action name="category-*/subcategory-*" class="test.TestBean">
<param name="id">{2}</param>
<result>/WEB-INF/content/test/results.jsp</result>
</action>
</package>
</struts>
test.TestBean here I used a String but in your case you'll change this to int or Integer. You'll want to validate that we did get an integer using validation xml or simply implementing com.opensymphony.xwork2.Validateable.
package test;
import com.opensymphony.xwork2.ActionSupport;
public class TestBean extends ActionSupport{
//public to avoid get/set to make example shorter
public String id;
}
/WEB-INF/content/test/results.jsp
<%#taglib prefix="s" uri="/struts-tags"%>
<html>
<body>
<h1>Wild Card Value</h1>
id: <s:property value="id"/>
</body>
</html>
Example 1
The url: example.com/category-helloBart produces...
Wild Card Value
id: helloBart
Example 2
The url: example.com/category-helloBart/subcategory-123 produces...
Wild Card Value
id: 123

Related

Unable to repopulate values after xml validation in Struts2 [duplicate]

This question already has an answer here:
Struts 2 Validation and Input fields repopulation
(1 answer)
Closed 6 years ago.
I was recently working with a login page with Struts2 framework and for validating the fields i used XML Validation feature provided by Struts2. And the fields are validated but the problem is that, if any of the field is not empty after validation the those field values are not repopulated in the corresponding field.The Example code is given.The version of the framework is 2.5.x.
Login.jsp
<s:form method="post" action="authenticate">
<div class="form-group">
<span class="input-icon">
<s:textfield name="strUserName" id="strUserName" cssClass="form-control" placeholder="Username or Email"></s:textfield>
<i class="fa fa-user"></i>
</span>
<span>
<s:fielderror fieldName="strUserName"/>
</span>
</div>
<div class="form-group">
<span class="input-icon">
<s:password name="strPassword" id="strPassword" cssClass="form-control" placeholder="Password"></s:password> <i class="fa fa-lock"></i>
</span>
<span>
<s:fielderror fieldName="strPassword"/>
</span>
</div>
</s:form>
struts.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<constant name="struts.enable.DynamicMethodInvocation" value="false" />
<constant name="struts.action.extension" value=",json"/>
<!-- Set to false before deploying the application -->
<constant name="struts.devMode" value="true" />
<constant name="struts.enable.SlashesInActionNames" value="true"/>
<constant name="struts.mapper.alwaysSelectFullNamespace" value="false"/>
<constant name="struts.configuration.xml.reload" value="false" />
<!-- constant to define global resource bundle -->
<constant name="struts.custom.i18n.resources" value="globalMessages" />
<constant name="struts.ui.theme" value="simple" />
<package name="<package_name>" namespace="/" extends="struts-default">
<action name="authenticate" class="<Action_class_name>" method="<method_name>">
<interceptor-ref name="store">
<param name="operationMode">STORE</param>
</interceptor-ref>
<interceptor-ref name="defaultStack" />
<result type="redirectAction">Successpage</result>
<result name="input" type="redirectAction">login</result>
</action>
<action name="login">
<interceptor-ref name="store">
<param name="operationMode">RETRIEVE</param>
</interceptor-ref>
<result>login.jsp</result>
</action>
</package>
</struts>
Action_name-validation.xml
<!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.3//EN"
"http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
<validators>
<validator type="requiredstring">
<param name="fieldname">strUserName</param>
<param name="trim">true</param>
<message key="errors.required"></message>
</validator>
<validator type="requiredstring">
<param name="fieldname">strPassword</param>
<param name="trim">true</param>
<message key="errors.required"></message>
</validator>
</validators>
Action_name.java
public class Action_name extends ActionSupport implements ModelDriven<UserModel> {
private UserModel user;
public String method_name() {
if(success){
return SUCCESS;
}else{
return INPUT;
}
}
#Override
public UserModel getModel() {
user = new UserModel();
return user;
}
}
Applicatin - intial run
Application - After Validation
value "xyz" is not repopulated after the validation.
There are two problems:
your login action
<action name="login">
<interceptor-ref name="store">
<param name="operationMode">RETRIEVE</param>
</interceptor-ref>
<result>login.jsp</result>
</action>
has only a single interceptor, the MessageStore one.
It should have instead at least the ModelDriven and the Parameters Interceptors to work correctly. For example
<action name="login">
<interceptor-ref name="store">
<param name="operationMode">RETRIEVE</param>
</interceptor-ref>
<interceptor-ref name="defaultStack" />
<result>login.jsp</result>
</action>
But note that this would lead to infinite recursion due to the MessageStore Interceptor always adding errors and the Workflow Interceptor always returning "input"; to avoid it you should define a secondary defaultStack in your struts.xml with all the intercpetors except the Workflow one, otherwise the MessageStore with RETRIEVE will make it loop or, if you haven't defined an input result for your login action, complaining about a missing input result.
The second error is that you are redirecting, and hence losing the parameters. You're using the MessageStore Interceptor to preserve Action Messages, Action Errors and Field Errors across the redirection, but every other parameter is lost. If you want to preserve a parameter across a redirectAction you must explicitly send it, or store it in session in the source action and retrieving it in the destination action. In your case, it would be better to simply return the JSP in case of input result, instead of redirecting:
<action name="authenticate" class="<Action_class_name>" method="<method_name>">
<interceptor-ref name="store">
<param name="operationMode">STORE</param>
</interceptor-ref>
<interceptor-ref name="defaultStack" />
<result type="redirectAction">Successpage</result>
<result name="input" >login.jsp</result>
</action>
<action name="login">
<interceptor-ref name="defaultStack" />
<result>login.jsp</result>
</action>

Struts 2 validation not working

I am trying to use struts 2 custom validation framework for validations, however that does not seem to be working. I am working on a very big project and the module I'm working on, I'm trying to implement this.
The problem struts 2 is not detecting my validation.xml. I tried creating a sample project and and used this validation.xml and it is working, but the same is not working in the project.
I am using model driven , I hope that should not be the problem.
The basic validations provided by action support are working fine but not my validations.
<interceptors>
<interceptor name="multiselect" class="org.apache.struts2.interceptor.MultiselectInterceptor" />
<interceptor name="browserCachingInterceptor" class="com.comviva.im.ui.interceptor.BrowserCachingInterceptor" />
<interceptor name="sessionHijackInterceptor" class="com.comviva.im.ui.interceptor.SessionHijackInterceptor" />
<interceptor name="tokenSession" class="org.apache.struts2.interceptor.TokenSessionStoreInterceptor" />
<interceptor-stack name="defaultSecurityStack">
<interceptor-ref name="defaultStack">
<param name="exception.logEnabled">true</param>
<param name="exception.logLevel">DEBUG</param>
</interceptor-ref>
<interceptor-ref name="tokenSession">
<param name="excludeMethods">*</param>
</interceptor-ref>
<interceptor-ref name="sessionHijackInterceptor" />
<interceptor-ref name="browserCachingInterceptor" />
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="defaultSecurityStack"></default-interceptor-ref>
The interceptor declaration is also fine.
I tried for days but still cant figure out the problem. the only option remaining is debug.
Can anybody suggest me where should I be looking for. Where is the validation.xml file is loaded in ActionInvocation so that I can check if validation file was loaded properly or not.
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.3//EN"
"http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
<validators>
<field name="nodeId">
<field-validator type="required">
<message key="errors.required"/>
</field-validator>
<field-validator type="int">
<param name="min">1</param>
<param name="max">10000</param>
<message>bar must be between ${min} and ${max}, current value is ${bar}.</message>
</field-validator>
</field>
<field name="selfISDNNumber">
<field-validator type="required">
<message key="errors.required"/>
</field-validator>
</field>
</validators>
This is extract from my action class:
public class NodeAction extends BaseAction implements ModelDriven<NodeConfigurationForm>, ParameterAware ,Preparable {
NodeConfigurationForm nodeConfigForm = new NodeConfigurationForm();
private static final Logger logger = Logger.getLogger(NodeAction.class);
private NodeConfigurationService configurationService;
private List<NodeConfiguration> nodeListTable = null;
Map<String , String[]> requestParams;
private int isFallBackChannelEnable;
private int smsSupportEnable;
private ServletContext servletContext;
MY NodeAction class extends BaseAction which extends ActionSupport which by default is validation aware.So NodeAction should work with custom validations also.
This is extract from my struts.xml regarding actions:
<action name="createGWNode" method="create" class="com.comviva.im.ui.ussdGateway.action.NodeAction">
<result name="success" type="tiles">createGWNode</result>
</action>
<action name="addGWNode" method="add" class="com.comviva.im.ui.ussdGateway.action.NodeAction">
<result name="success" type="chain">listGWNodes</result>
<result name="input" type="tiles">createGWNode</result>
<result name="error" type="tiles">createGWNode</result>
</action>
<action name="editGWNode" method="edit" class="com.comviva.im.ui.ussdGateway.action.NodeAction">
<result name="success" type="tiles">createGWNode</result>
</action>
<action name="updateGWNode" method="update" class="com.comviva.im.ui.ussdGateway.action.NodeAction">
<result name="success" type="redirect">listGWNodes</result>
<result name="input" type="tiles">createGWNode</result>
<result name="error" type="tiles">createGWNode</result>
</action>
And this is my jsp
<s:textfield name="nodeId" required="true" theme="simple" />reado
<s:radio name="status" list="#{'1':'Enable','0':'Disable'}" theme="simple"></s:radio>
<s:textfield name="gwInstanceName" theme="simple" />
<s:textarea name="description" cols="30" rows="2" theme="simple"/>
<s:textfield name="serverIp" theme="simple"/>
<s:textfield name="serverIp" theme="simple" readonly=< s:textfield name="loginUserId" theme="simple"/>
<s:password name="loginPassword" showPassword="true" theme="simple"/>
<s:textfield name=" selfISDNNumber " theme="simple "/>
<s:select name="logLevel " list="logLevelList " theme="simple "/>
Note: Please remove _ Underscore from selfISDN_num
Check proper jar files.
Xwork: Core 2.3.16.2 API
And check getter , setters
Note: Please check package name in struts.xml, does it extend struts-default?
<package name="Registration" namespace="/" extends="struts-default">
...
</package>
Finally found what was going wrong.
The DTD specified in validaiton.xml was wrong. The specifed DTD is for 2.3 onwards. I was using struts with a lower version.
I am now using
<!DOCTYPE validators PUBLIC
"-//OpenSymphony Group//XWork Validator 1.0//EN"
"http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">

Validating a form on a button click in struts 1.2

I am trying to validate user credentials details during application log in.I have changed my struts config and validation xml but the validation gets invoked on the page load itself.
I want that this validation should be invoked only during the click of a button(submit button).
My struts config is as under:
<action-mappings>
<action attribute="loginForm" input="jsp/LoginPage.jsp" name="loginForm"
parameter="method" path="/loginAction" scope="request"
type="com.pcs.bpems.portal.struts.action.LoginAction" validate="false">
<forward name="schoolloginpage" path="/jsp/SchoolLoginPage.jsp" />
</action>
<action attribute="loginForm" input="/jsp/SchoolLoginPage.jsp" name="loginForm"
parameter="method" path="/loginAction" scope="request"
type="com.pcs.bpems.portal.struts.action.LoginAction" validate="true">
<forward name="schoolloginpage" path="/jsp/SchoolLoginPage.jsp" />
<forward name="schoolhomepage" path="/ownerHome.do?method=showHome" />
</action>
My validation xml is as under
<form name="loginForm">
<field property="userId" depends="required,minlength">
<arg0 key="label.userName"/>
<var>
<var-name>minlength</var-name>
<var-value>6</var-value>
</var>
<arg1 key="${var:minlength}" resource="false" />
</field>
<field property="password" depends="required,minlength">
<arg0 key="label.password"/>
<var>
<var-name>minlength</var-name>
<var-value>6</var-value>
</var>
<arg1 key="${var:minlength}" resource="false" />
</field>
</form>
#Anish Try this code instead of your first LoginAction attribute,
<action path="/loginAction" parameter="method"
type="com.pcs.bpems.portal.struts.action.LoginAction" validate="false">
<forward name="schoolloginpage" path="/jsp/SchoolLoginPage.jsp" />
</action>
My thought is form name is not necessary for load the form, though you are made validate attribute to false. Let me know if this helps.
If you do not pass through the input, Struts performs the validation. There are several ways to solve it.
Request directly to the JSP
Make a request to the JSP file directly and not through the org.apache.struts.action.ActionServlet.
http://localhost:8080/MyContext/jsp/SchoolLoginPage.jsp
With a forward
<action path="/login" forward="/jsp/SchoolLoginPage.jsp" />
Use:
http://localhost:8080/MyContext/login.do

extract with multiple predicates and multiple predicates

I want to extract information from the jms-bus node. Specifically the busid,
//[local-name()='jms-bus'][#busid=//[local-name()='jms-listener']/#busidref]/#busid matches perfectly and returns quickstartGwChannel and quickstartESBChannel if the have matching providers and services.
However, I want to return the jms-bus(s) where it has a jms-listener is-gateway='true'
I am not sure where to put the 'and' clause. When I put it at the beginning //*[local-name()='jms-listener]/[#is-gateway='true']and .... it returns a boolean.
I need to extract from this xml
<providers>
<jms-provider name="JBossMQ" connection-factory="ConnectionFactory">
<jms-bus busid="quickstartGwChannel">
<jms-message-filter
dest-type="QUEUE"
dest-name="queue/quickstart_helloworld_Request_gw"
/>
</jms-bus>
<jms-bus busid="quickstartEsbChannel">
<jms-message-filter
dest-type="QUEUE"
dest-name="queue/quickstart_helloworld_Request_esb"
/>
</jms-bus>
</jms-provider>
</providers>
<services>
<service
category="FirstServiceESB"
name="SimpleListener"
description="Hello World">
<listeners>
<jms-listener name="JMS-Gateway"
busidref="quickstartGwChannel"
is-gateway="true"
/>
<jms-listener name="helloWorld"
busidref="X12"
is-gateway="false"
/>
</listeners>
<actions mep="OneWay">
<action name="action1"
class="org.jboss.soa.esb.samples.quickstart.helloworld.MyJMSListenerAction"
process="displayMessage"
/>
<action name="action2" class="org.jboss.soa.esb.actions.SystemPrintln">
<property name="printfull" value="false"/>
</action>
<!-- The next action is for Continuous Integration testing -->
<action name="testStore" class="org.jboss.soa.esb.actions.TestMessageStore"/>
</actions>
</service>
</services>
Something like this:
//*[local-name()='jms-bus']
[#busid=//*[local-name()='jms-listener']
[#is-gateway='true']/#busidref]/#busid
or
//*[local-name()='jms-bus']
[#busid=//*[local-name()='jms-listener' and #is-gateway='true']/#busidref]/#busid

Action not forwaded to tiles-definition from forward path in Action

My struts-config.xml has a few forward actions that point to tiles definitions. But it takes path as it is given & doesn't directed to the tiles-definition.xml & showing path does not start with a "/" character
My struts-config.xml is :
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN" "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">
<struts-config>
<data-sources />
<form-beans >
<form-bean name="feelSafeForm" type="com.feelsafe.struts.form.FeelSafeForm" />
</form-beans>
<global-exceptions />
<global-forwards >
<forward name="login1" path="/feelSafe.do?do=login" />
<forward name="admin" path="/feelSafe.do?do=admin1" />
</global-forwards>
<action-mappings >
<action
attribute="feelSafeForm"
input="/index.jsp"
name="feelSafeForm"
parameter="do"
path="/feelSafe"
scope="request"
type="com.feelsafe1.struts.action.FeelSafeAction">
<forward name="adminmainpage" path="feelsafe.adminmainpage" />
<forward name="login" path="feelsafe.login" />
</action>
</action-mappings>
<message-resources parameter="com.feelsafe.struts.ApplicationResources" />
<plug-in className="org.apache.struts.tiles.TilesPlugin">
<set-property property="definitions-parser-validate" value="true" />
<set-property property="moduleAware" value="true" />
<set-property property="definitions-config" value="/WEB-INF/tiles-definition.xml" />
</plug-in>
</struts-config>
tiles-definition.xml is :
<!DOCTYPE tiles-definitions PUBLIC
"-//Apache Software Foundation//DTD Tiles Configuration 1.1//EN"
"http://struts.apache.org/dtds/tiles-config_1_1.dtd">
<component-definitions>
<definition name="feelsafe.common" path="/feelsafeLayout/layout.jsp">
<put name="title" type="string" value="FeelSafe Hospital"/>
<put name="header1" value="/feelsafeLayout/header.jsp"/>
<put name="footer1" value="/feelsafeLayout/footer.jsp"/>
</definition>
<definition name="feelsafe.login" extends="feelsafe.common">
<put name="body1" value="/feelsafeJspFiles/login.jsp"/>
</definition>
<definition name="feelsafe.admin" extends="feelsafe.common">
<put name="body1" value="/feelsafeAdminJspFiles/adminlogin.jsp"/>
</definition>
</component-definitions>
When login is called, control goes to forward tag & gives 500 Error saying :
org.apache.jasper.JasperException: javax.servlet.ServletException:
javax.servlet.jsp.JspException: Exception forwarding for name login1:
javax.servlet.ServletException: java.lang.IllegalArgumentException:
Path feelsafe.login does not start with a "/" character
I get the same error when i removed this snippet from init params of my action servlet in web.xml
...
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
...
<init-param>
<param-name>chainConfig</param-name>
<param-value>org/apache/struts/tiles/chain-config.xml</param-value>
</init-param>
So when you use an old version of dtd like 1.1 try to add this init-param to action servlet to your web.xml file.
I tested on 1.3

Resources