[STRUTS] Probl鑝s mapping

Hello,

I try to do a simple struts application with struts v1.2.7. This application begins with an identification form (user + password). When a user try to connect on the application, a query is sent to the database. If the user is registered the user is redirected on the main page, named employeliste.jsp. If not the user is redirected on the identification page and errors are screened on it.

My problem is :

When i enter a good name user and a good password, there is a failure because i'm redirected on a white page whitout code, errors or logs...

I tried to see where the problem is and i saw that the authentification process is OK, because the mapping.findForward of my class LoginAction.java give an answer.

Here you will find :

struts-config.xml :

<?xml version="1.0" encoding="ISO-8859-1" ?>

<!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>

<data-source type="com.mysql.jdbc.jdbc2.optional.MysqlDataSource">

<set-property property="driverClass" value="com.mysql.jdbc.Driver" />

<set-property property="url" value="jdbc:mysql://localhost/employes" />

<set-property property="maxCount" value="5" />

<set-property property="maxCount" value="1" />

<set-property property="user" value="root" />

<set-property property="password" value="*****" />

</data-source>

</data-sources>

<form-beans>

<form-bean name="loginForm" type="com.monAppli.LoginForm" />

</form-beans>

<global-forwards>

<forward name="login" path="/login.jsp"/>

</global-forwards>

<action-mappings>

<action path="/Login"

type="com.monAppli.LoginAction"

name="loginForm"

validate="true"

input="/login.jsp"

scope="request"

>

<forward name="succes" path="/EmployeListe.do"/>

</action>

<action path="/EmployeListe"

type="com.monAppli.EmployeListeAction"

scope="request"

className="com.monAppli.EmployesActionMapping"

>

<set-property property="loginRequired" value="true"/>

<forward name="succes" path="/employeliste.jsp"/>

</action>

</action-mappings>

<message-resources parameter="com.monAppli.ApplicationResources"/>

</struts-config>

LoginAction.java :

package com.monAppli;

import java.io.IOException;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.servlet.http.HttpSession;

import org.apache.struts.Globals;

import org.apache.struts.action.Action;

import org.apache.struts.action.ActionForm;

import org.apache.struts.action.ActionForward;

import org.apache.struts.action.ActionMapping;

import org.apache.struts.action.ActionErrors;

import org.apache.struts.action.ActionError;

import javax.sql.DataSource;

import java.sql.Connection;

import java.sql.Statement;

import java.sql.ResultSet;

import java.sql.SQLException;

publicclass LoginActionextends Action{

protected String getUser(String username,String password){

String user =null;

Connection conn =null;

Statement stmt =null;

ResultSet rs =null;

DataSource dataSource = (DataSource)servlet.getServletContext().getAttribute(Globals.DATA_SOURCE_KEY);

try{

conn = dataSource.getConnection();

stmt = conn.createStatement();

rs = stmt.executeQuery("select * from employes where username='"+username+"' and password='"+password+"'");

if(rs.next()){

user = rs.getString("username");

//Iteration sur le resultat

System.err.println("Username : "

+ rs.getString("username")

+" Password : " + rs.getString("password"));

}else{

System.err.println("-->Utilisateur non trouv?lt;--");

}

}catch (SQLException e){

System.err.println(e.getMessage());

}finally{

if (rs !=null){

try{

rs.close();

}catch (SQLException sqle){

System.err.println(sqle.getMessage());

}

rs =null;

}

if (stmt !=null){

try{

stmt.close();

}catch (SQLException sqle){

System.err.println(sqle.getMessage());

}

stmt =null;

}

if (conn !=null){

try{

conn.close();

}catch (SQLException sqle){

System.err.println(sqle.getMessage());

}

conn =null;

}

}

return user;

}

public ActionForward execute(ActionMapping mapping,

ActionForm form,

HttpServletRequest request,

HttpServletResponse response)

throws IOException, ServletException{

String user =null;

//Cible par d閒aut en cas de succ鑣

String target =new String("succes");

//Utilisation de LoginForm pour obtenir les param鑤res de la Qry

String username = ((LoginForm)form).getUserName();

String password = ((LoginForm)form).getPassword();

user = getUser(username, password);

//Cible en cas d'echec

if (user ==null){

target =new String("login");

ActionErrors errors =new ActionErrors();

errors.add(ActionErrors.GLOBAL_ERROR,

new ActionError("errors.login.unknown",

username));

//Enregister les erreurs trouv閑s dans le formulaire original

if (!errors.isEmpty()){

saveErrors(request, errors);

}

}else{

HttpSession session =request.getSession();

session.setAttribute("USER", user);

System.err.println(" Username plac?dans session : "+session.getAttribute("USER")+"");

}

//Transmission de la requ阾e ?la vue appropri閑

System.err.println(" Login Target : "+target+"");

return (mapping.findForward(target));

}

}

EmployeListeAction

package com.monAppli;

import java.io.IOException;

import javax.servlet.ServletException;

import javax.servlet.ServletContext;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.servlet.http.HttpSession;

import org.apache.struts.Globals;

import org.apache.struts.action.Action;

import org.apache.struts.action.ActionForm;

import org.apache.struts.action.ActionForward;

import org.apache.struts.action.ActionMapping;

import org.apache.struts.action.ActionErrors;

import org.apache.struts.action.ActionError;

import javax.sql.DataSource;

import java.sql.Connection;

import java.sql.Statement;

import java.sql.ResultSet;

import java.sql.SQLException;

import java.util.HashMap;

import java.util.ArrayList;

public class EmployeListeAction extends Action{

protected ArrayList getEmployes(){

Employe employe = null;

ArrayList employes = new ArrayList();

Connection conn = null;

Statement stmt = null;

ResultSet rs = null;

ServletContext context = servlet.getServletContext();

DataSource dataSource = (DataSource)context.getAttribute(Globals.DATA_SOURCE_KEY);

try{

conn = dataSource.getConnection();

stmt = conn.createStatement();

rs = stmt.executeQuery("select * from employes, roles, "

+ "services where employes.roleid=roles.roleid "

+ "and employes.depid = services.depid");

while (rs.next()){

employe = new Employe();

employe.setUserName(rs.getString("username"));

employe.setName(rs.getString("name"));

employe.setRolename(rs.getString("rolename"));

employe.setPhone(rs.getString("phone"));

employe.setEmail(rs.getString("email"));

employe.setRoleid(new Integer(rs.getInt("roleid")));

employe.setDepid(new Integer(rs.getInt("depid")));

employe.setDepartment(rs.getString("depname"));

employes.add(employe);

}

}catch (SQLException e){

System.err.println(e.getMessage());

}finally{

if (rs !=null){

try{

rs.close();

}catch (SQLException sqle){

System.err.println(sqle.getMessage());

}

rs = null;

}

if (stmt !=null){

try{

stmt.close();

}catch (SQLException sqle){

System.err.println(sqle.getMessage());

}

stmt = null;

}

if (conn !=null){

try{

conn.close();

}catch (SQLException sqle){

System.err.println(sqle.getMessage());

}

conn = null;

}

}

return employes;

}

public ActionForward execute(ActionMapping mapping,

HttpServletRequest request,

HttpServletResponse response)

throws IOException, ServletException{

//Cible par d閒aut en cas de succ閟

String target = new String("succes");

EmployesActionMapping employesMapping = (EmployesActionMapping)mapping;

HttpSession session = request.getSession();

System.err.println(" USER : -"+session.getAttribute("USER")+"-");

//Cette action necessite elle l'identification de l'utilisateur ?

if (employesMapping.isLoginRequired()){

if(session.getAttribute("USER") == null){

//L'utilisateur n'est pas identifi?

target = new String("login");

ActionErrors errors = new ActionErrors();

errors.add(ActionErrors.GLOBAL_ERROR, new ActionError("errors.login.required"));

//Signaler les erreurs 関entuelles au formulaire original

if(!errors.isEmpty()){

saveErrors(request, errors);

}

}

}

ArrayList employes = null;

employes = getEmployes();

//Cible en cas d'echec

if (employes == null){

target = new String("login");

}else{

request.setAttribute("employes", employes);

}

//Forward to the appropriate view

System.err.println(" Employes Target : -"+target+"-");

return (mapping.findForward(target));

}

}

My custom mapping EmployesActionMapping :

package com.monAppli;

import org.apache.struts.action.ActionMapping;

publicclass EmployesActionMappingextends ActionMapping{

protectedboolean loginRequired =false;

publicvoid setLoginRequired(boolean loginRequired){

this.loginRequired = loginRequired;

}

publicboolean isLoginRequired(){

return loginRequired;

}

}

My JSP page who doesn't show me a result(employeliste.jsp) :

<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>

<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>

<logic:notPresent name="USER">

<logic:forward name="login" />

</logic:notPresent>

<html>

<head>

<title><bean:message key="app.title" /></title>

</head>

<body>

<table width="650" border="0" cellspacing="0" cellpadding="0">

<tr>

<td colspan="7"> </td>

</tr>

<tr bgcolor="#000000">

<td colspan="7" height="68" width="48%">

<div align="left">

<img src="images/hp_logo_monAppli.gif"

width="220" height="74">

</div>

</td>

</tr>

<tr>

<td colspan="7"> </td>

</tr>

</table>

<html:errors />

<table width="750" border="0" cellspacing="0" cellpadding="0">

<tr align="left">

<th><bean:message key="app.username" /></th>

<th><bean:message key="app.name" /></th>

<th><bean:message key="app.phone" /></th>

<th><bean:message key="app.email" /></th>

<th><bean:message key="app.department" /></th>

<th><bean:message key="app.role" /></th>

</tr>

<!--iteration sur les r閟ultat de la requete -->

<logic:iterate id="employe" name="employes">

<tr align="left">

<td>

<bean:write name="employe" property="username" />

</td>

<td>

<bean:write name="employe" property="name" />

</td>

<td>

<bean:write name="employe" property="phone" />

</td>

<td>

<bean:write name="employe" property="email" />

</td>

<td>

<bean:write name="employe" property="department" />

</td>

<td>

<bean:write name="employe" property="rolename" />

</td>

<td>

<a href="Edit.do?username=<bean:write name='employe' property='username' />">Modifier</a>

<a href="Delete.do?username=<bean:write name='employe' property='username' />">Supprimer</a>

</td>

</tr>

</logic:iterate>

<tr>

<td colspan="7"><hr></td>

</tr>

</table>

<font size="-1" face="arial">

<a href="addemploye.jsp">Ajouter un employ?lt;/a>

</font>

</body>

</html>

My web.xml :

<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app PUBLIC"-//SUN Microsystems, Inc.//DTD Web Application 2.3//EN""http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>

<servlet>

<servlet-name>action</servlet-name>

<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>

<init-param>

<param-name>debug</param-name>

<param-value>5</param-value>

</init-param>

<init-param>

<param-name>config</param-name>

<param-value>/WEB-INF/struts-config.xml</param-value>

</init-param>

<init-param>

<param-name>mapping</param-name>

<param-value>com.eyrolles.EmployesActionMapping</param-value>

</init-param>

<load-on-startup>1</load-on-startup>

</servlet>

<servlet-mapping>

<servlet-name>action</servlet-name>

<url-pattern>*.do</url-pattern>

</servlet-mapping>

<welcome-file-list>

<welcome-file>login.jsp</welcome-file>

</welcome-file-list>

<taglib>

<taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>

<taglib-location>/WEB-INF/struts-html.tld</taglib-location>

</taglib>

<taglib>

<taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri>

<taglib-location>/WEB-INF/struts-bean.tld</taglib-location>

</taglib>

<taglib>

<taglib-uri>/WEB-INF/struts-logic.tld</taglib-uri>

<taglib-location>/WEB-INF/struts-logic.tld</taglib-location>

</taglib>

</web-app>

[22522 byte] By [DarkWarka] at [2007-10-2 7:32:35]
# 1

Hello,

To tell you the truth, I haven't used:

...

className="com.monAppli.EmployesActionMapping">

<set-property property="loginRequired" value="true"/>

...

I don't know if my situation was like yours but take a look at this alternative:

My application has some resources that are availabe for public use as well as some resources that are available just for logged users(to put it simple because logged users have <> privileges, but to make it clear lets just use non-logged vs logged users)

I implemented my own RequestProcessor's processRole method alternative, how does it work?

First you declare your action as follow in your struts configuration file:

...

<action path="/list-employees" roles="logged-users" type="com.orly_otero.struts.Actions.ListEmployees">

<forward name="list-employees.success" path="/list-employees.page" />

</action>

...

The path attribute in the forward element is a *.page pattern because I'm using Tiles, if you are not, the you simple write path="/WEB-INF/jsps/list-employess.jsp", but look at the roles attribute: roles="logged-users"

Next step is to declare your own controller processor after <action-mappings> element:

...

<controller processorClass="com.orly_otero.struts.Processors.CustomRequestProcessor" />

...

From now on this is going to be your struts-module processor controller, that behavies like the default controller but it will meet your need by redifining the processRoles method:

...

public class CustomRequestProcessor extends TilesRequestProcessor{ //Because I'm using Tiles, in your case it might be just RequestProcessor, although I'm not 100% sure.

protected boolean processRoles(HttpServletRequest request, HttpServletResponse response,

ActionMapping mapping) throws IOException, ServletException{

HttpSession session=request.getSession(false);

String id=(String)session.getAttribute("id-user");

ActionForward forward=null;

UserVO userVO=null;

Properties appProps=utils.PropertiesUtil.getInstance().getAppProperties();

String actionPath=(String)appProps.getProperty(Const.ACTION_PREFIX)+mapping.getPath()+(String)appProps.getProperty(Const.ACTION_SUFFIX);

/*I use this actionPath because my implementation semantics is to forward to login page in case user is not logged, but once logged, he/she will be redirected(forwarded) to the last protected page he/she attempt to access while not logged.

Another comment is related to PREFIX and SUFFIX contants, I used them because I first wrote my app using the ..../exec/MyAction1, ... pattern to invoke struts servlet controller, but as it has restrictions while using with more than one struts module in the same application, I switched to *.do pattern, and as I had to recode some files, I decide to make as portable as I can, just in case a future solution or approach come up, the switch wont require recode again.

*/

//DB Query.

if (id!=null){ //User once was logged.

try{

userVO=UserManagerBD.getInstance().getUser(id);

//Singleton+Business Delegate pattern to implement DB access, Delegate pattern uses DAO object.

}

catch(ApplicationException ae){}

}

if (userVO!=null) request.setAttribute("user", userVO);

else{ //User was logged and then deleted.

session.removeAttribute("id-user");

request.removeAttribute("user");

}

//Obtain the list of roles from action config.

String roles=Misc.arr2Str(mapping.getRoleNames());

//... Deleted code to put it simple.

if (forward==null){ //No denied resource so far.

if (roles==null){ //No roles=>No restriction.

if (actionPath.toLowerCase().indexOf("login")==-1) session.removeAttribute("protected-page");

return true;

}

String parameters="";

Enumeration paramNames=request.getParameterNames();

if (paramNames.hasMoreElements()){

parameters="?";

do{

String pName=(String)paramNames.nextElement();

String[] pValues=request.getParameterValues(pName);

for(int i=0;i<pValues.length; i++){

if (parameters.length()>1) parameters=parameters+"&";

parameters=parameters+pName+"="+pValues[i];

}

}while(paramNames.hasMoreElements());

}

if (roles.indexOf("logged-user")!=-1){ //"logged-user" privileges.

if (userVO==null){

//Store forward name to redirect to it once logged.

session.setAttribute("protected-page", actionPath+parameters);

//Invoke declarative exception handling.

forward=processException(request, response, new SecurityViolationException(), null, mapping);

}

}

if (roles.indexOf("privileged-user")!=-1){ //"privileged-user".

if (isUserInRole(userVO, "privileged-user")) return true;

session.setAttribute("protected-page", actionPath+parameters);

forward=processException(request, response, new PrivilegedZoneSecurityViolationException(), null, mapping);

}

}

if (forward!=null) processForwardConfig(request, response, forward); //Some exception.

return (forward==null);

}

//Method to query DB.

protected boolean isUserInRole(ValueObject vo, String role){

//TODO: Query database to use user payment properties. Not available yet.

return true;

}

...

This should give you the idea behind your custom RequestProcessor class implementation.

Why INHO this should be the recommended approach, well it has to be first with my own needs and with some concepts regarding J2EE patterns and Struts tips.

Using this approach, when a logged user ask for a protected resource, the processor gives control to the specified action declared in mapping struts file, but if the user is not logged then the declared action is not going to be reached never, that means that you code this logic only one time in your struts module and use it every time in mapping actions by specifying the roles attribute. If you code this logic in actions you must take care of including every piece of in every action that maps to a resource you want to protect, if you forget protecting one action, you must recode again, while with this approach is done by changing a configuration text file.

NOTE: I used declarative exception handling that I didn't make references to, but it's a simple concept of struts that you could learn fast in case you don't know yet.

Hope this help.

Feel free to contact me if there is anything unclear.

Regards,

OO

P.S. Sorry about my English

orly_oteroa at 2007-7-16 21:12:30 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 2
i'm Sorry but could you be less complicated... I'm a new biz and i'm sur that there is more simple !!! Please help me !!!
DarkWarka at 2007-7-16 21:12:30 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 3

Hi, I supposing that the difficult part is the CustomRequestProcessor class:

public class CustomRequestProcessor extends RequestProcessor{ //Try to make sure this is the correct base class since I'm using TilesRequestProcessor

protected boolean processRoles(HttpServletRequest request, HttpServletResponse response,

ActionMapping mapping) throws IOException, ServletException{

HttpSession session=request.getSession(false);

String id=(String)session.getAttribute("id-user"); //Variable you store in session context once a user get logged.

ActionForward forward=null;

UserVO userVO=null; //Value Object pattern, a simple Java Bean with loginName, firstName, etc. attributes and their corresponding getter and setter methods.

//DB Query.

if (id!=null){ //User is/was logged. WAS logged means that he was

//successfully logged but as in the worst scenario, an

//administrator delete him from DB.

//(He was unsubscribed from the system)

try{

/*Here goes your custom logic. If you want you could use jdbc here.*/

//In my case:

userVO=UserManagerBD.getInstance().getUser(id);

//Singleton+Business Delegate+Service Locator+DAO patterns to implement DB access.

}

catch(ApplicationException ae){}

}

if (userVO!=null) request.setAttribute("user", userVO); //Because frstName and lastName are displayed in every page.

else{ //User not logged in.

//Making sure a deleted user cannot be active in the system.

session.removeAttribute("id-user");

request.removeAttribute("user");

}

//Obtain the list of roles from action config.

String roles=Misc.arr2Str(mapping.getRoleNames());

//gives me a "role1, role2, role3, ..." depending on the roles you want to define.

if (roles.indexOf("logged-user")!=-1){ //"logged-user" privileges.

if (userVO==null){ //User is trying to access a protected page and he/she is not logged.

//Invoke declarative exception handling.

forward=processException(request, response, new SecurityViolationException(), null, mapping);

}

}

}

//If forward variable is not null means that it was instantiated to a

//custom forward, meaning that a valid authetication was not reached.

if (forward!=null) processForwardConfig(request, response, forward); //Some exception.

return (forward==null); //true means forward to the accessed protected resource.

}

Now configure struts-config.xml as follow:

...

<global-exceptions>

<exception key="error-security.logged-user" type="com.orly_otero.struts.Exceptions.SecurityViolationException" path="/login.do" />

...

</global-exceptions>

...

<action path="/list-employees" roles="logged-users" type="com.orly_otero.struts.Actions.ListEmployees">

<forward name="list-employees.success" path="/list-employees.page" /> <!-- change path to the location of your .jsp file -->

</action>

...

</action-mappings>

<controller processorClass="com.orly_otero.struts.Processors.CustomRequestProcessor" />

orly_oteroa at 2007-7-16 21:12:30 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 4
Sorry, I forgot:error-security.logged-user=Must log in as a registered user to access this page.Ad this entry in your application.properties files.
orly_oteroa at 2007-7-16 21:12:30 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...