RequestDispatcher return me PWC6199: Generated servlet error - requestdispatcher

Hello when I try to use requestDispatcher it does not forward the URL. I retrieve this strange error
PWC6199: Generated servlet error:
source value 1.5 is obsolete and will be removed in a future release
PWC6199: Generated servlet error:
target value 1.5 is obsolete and will be removed in a future release
PWC6199: Generated servlet error:
To suppress warnings about obsolete options, use -Xlint:-options.
I tried with sendredirect without success. What is wrong ?
My simple servlet MyServletSennesal is :
'import com.senesal.moustac.Utilisateur;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;<
public class MyServletSennesal extends HttpServlet {
protected void processRequest(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
System.out.println("Je suis dans la servlet sennesal");
HttpSession unesession = request.getSession(true);
String prenom = request.getParameter("txtprenom");
String nom = request.getParameter("txtnom");
Utilisateur usn = new Utilisateur(prenom, nom);
unesession.setAttribute("utilisateur", usn);
System.out.println("le User est ----->"+usn);
System.out.println("La session est ----->" +unesession);
String myurl="/WEB-INF/PageError.jsp";
RequestDispatcher rd;
if(unesession!=null){
myurl="/WEB-INF/bienvenue.jsp";
System.out.println("Premiere conditionnelle");
System.out.println("L'url --->" +myurl);
//getServletContext().getRequestDispatcher(myurl);
rd= request.getRequestDispatcher(myurl);
rd.forward(request, response);
//response.sendRedirect(myurl);
}else{
System.out.println("Seconde conditionnelle");
//getServletContext().getRequestDispatcher(myurl).include(request, response);
rd= request.getRequestDispatcher(myurl);
rd.forward(request, response);
}
}
// <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
/**
* Handles the HTTP <code>GET</code> method.
*
* #param request servlet request
* #param response servlet response
* #throws ServletException if a servlet-specific error occurs
* #throws IOException if an I/O error occurs
*/
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
/**
* Handles the HTTP <code>POST</code> method.
*
* #param request servlet request
* #param response servlet response
* #throws ServletException if a servlet-specific error occurs
* #throws IOException if an I/O error occurs
*/
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
/**
* Returns a short description of the servlet.
*
* #return a String containing servlet description
*/
#Override
public String getServletInfo() {
return "Short description";
}// </editor-fold>
}
My Web.xml
'<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
</web-app>`
My Bienvenue.jsp file
'<%#page import="com.senesal.moustac.Utilisateur"%>
<%#page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Bienvue</title>
</head>
<body>
<%
Utilisateur usr =(Utilisateur) session.getAttribute("utilisateur");
System.out.println("On est dans la JSP bienvenu");
System.out.println("Utilisateur ---->" +usr);
if (usr!=null){%>
<h1>Hello Bienvenu</h1>
<%} else {
System.out.println("probleme dans la jsp");
response.sendRedirect("PageError.jsp");
}%>
<% }%>
</body>
</html>'
MyPageError.jsp
'<%#page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Page Error</title>
</head>
<body>
<p>Une anomalie s'est produite </p>
<p>Retournez au départ</p>
</body>
</html>'
My class User aka Utilisateur
'package com.senesal.moustac;
public class Utilisateur {
private String strprenom;
private String strnom;
public Utilisateur() {
}
public Utilisateur(String strprenom, String strnom) {
this.strprenom = strprenom;
this.strnom = strnom;
}
public String getStrprenom() {
return strprenom;
}
public void setStrprenom(String strprenom) {
this.strprenom = strprenom;
}
public String getStrnom() {
return strnom;
}
public void setStrnom(String strnom) {
this.strnom = strnom;
}
#Override
public String toString() {
String strchaine = this.getStrprenom()+", "+this.getStrnom();
return strchaine;
}
}'
My project structure
Sorry for the image I did it non clickable because I don't know your politic regarding the imagehostigs websites. I prefer to avoid problem, if you don't have problem with Flickr notice me, and I will be set this link clickable.
https www flickr _com_photos_ 44522526# N06_34997725050 _ in_ dateposted-public

Related

File upload not working with Struts2 Model-Driven Interface

When I am using Model driven interface, my file upload operation is not working.
It is not popping any error, nor it is generating any log.
My code is attached hereby,
I want to know for file, do we have to generate its getters/setters in Model or Action with Model-Driven interface.
Atleast it should get uploaded to temp folder, as with struts by default uploads to temp.
Action
ProductAction.java
package com.fileupload.action;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import com.fileupload.model.FileUploadModel;
/**
* Action class to requests
* #package com.fileupload.action
*/
public class FileUploadAction extends ActionSupport implements ModelDriven<Object>{
FileUploadModel fileModel = new FileUploadModel();
#Override
public Object getModel() {
return fileModel;
}
}
Model ProductModel.java
package com.fileupload.model;
import java.io.File;
/**
* Model class to handle data
* #package com.fileupload.model
*/
public class FileUploadModel {
private String employeeName;
private File image;
private String imageFileName;
private String imageFileCotentType;
public File getImage() {
return image;
}
public void setImage(File image) {
this.image = image;
}
public String getImageFileName() {
return imageFileName;
}
public void setImageFileName(String imageFileName) {
this.imageFileName = imageFileName;
}
public String getImageFileCotentType() {
return imageFileCotentType;
}
public void setImageFileCotentType(String imageFileCotentType) {
this.imageFileCotentType = imageFileCotentType;
}
public String getEmployeeName() {
return employeeName;
}
public void setEmployeeName(String employeeName) {
this.employeeName = employeeName;
}
}
Configuration 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.devMode" value="true"/>
<package name="FileUploadStruts" extends="struts-default">
<action name="index">
<result>/index.jsp</result>
</action>
<action name="submitForm" class="com.fileupload.action.FileUploadAction">
<result name="success">/result.jsp</result>
</action>
</package>
</struts>
View CreateProduct.jsp
<%--
Document : index
Created on : Nov 26, 2017, 12:50:38 PM
Author : owner
--%>
<%#page contentType="text/html" pageEncoding="UTF-8"%>
<%# taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>File upload example</title>
</head>
<body>
<h1>Fill the form below</h1>
<s:form action="submitForm" enctype="multipart/form-data" name="employeeform">
<s:textfield name="employeeName"/>
<s:file name="image"/>
<s:submit value="Submit"/>
</s:form>
</body>
</html>
Of,course,your file upload operation can working When you using Model
driven interface but you made a few mistake:
public class FileUploadModel {
private String employeeName;
private File image;
private String imageFileName;
// YourCode was wrong : private String imageFileCotentType;
private String imageFileContentType;
(get set)...
And then,you need to add a piece of code to your code for upload like
this:
#Namespace("/")
#ParentPackage("struts-default")
public class FileUploadAction extends ActionSupport implements ModelDriven<FileUploadModel> {
private static final long serialVersionUID = 1L;
FileUploadModel fileModel = new FileUploadModel();
#Override
public FileUploadModel getModel() {
return fileModel;
}
#Action(value = "submitForm", results = {
#Result(name = "success", location = "/result.jsp") })
public String submitForm() {
HttpServletRequest request = ServletActionContext.getRequest();
String tomcatPath = ServletActionContext.getServletContext().getRealPath("/");
String projectName = request.getContextPath();
projectName = projectName.substring(1);
String filePath = tomcatPath.substring(0, tomcatPath.indexOf(projectName)) + "uploadFile";
File dest = new File(filePath, fileModel.getImageFileName());
try {
FileUtils.copyFile(fileModel.getImage(), dest);
} catch (IOException e) {
e.printStackTrace();
}
return "success";
}
}
if you implements the function based on my answer,please reply to
me,smile.

There is no Action mapped for namespace /controller and action name

I am trying to learn Struts2, I have used a view page that hits action , the action class is using a bean where getter setter methods are written and the action is also using a dao where the connection is written.I want to mention that I am using jboss v5.0 and eclipse, I have added all the jar files.
Now , when I am trying to run this application the welcome jsp page is hitting properly then on clicking submit button the below error is showing:
There is no Action mapped for namespace /controller and action name
I am placing my code and directory structure. I have tried the using namespace="/"
<result name="SUCCESS">/success.jsp</result>, still its is not working
passing
+JAX-WS Web Services
+Deployment Descriptor:Passing
-Java Resources
-src
-controller
-TestAction.java
-TestAction
-execute(HttpServletRequest request , HttpServletResponse response) : String
-model
-TestBean.java
-TestBean
-age
-ocation
-name
-getAge() :String
-getName() :String
-getLocation() :String
-setAge(String) : void
-setName(String) : void
-getlocation(String) : void
-UserDao.java
- UserDao
-Logincheck() :Connection
registration.jsp
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" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>Passing</display-name>
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>registration.jsp</welcome-file>
</welcome-file-list>
</web-app>
struts.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="default" extends="sturts-default">
<action name="TestAction" class="controller.TestAction">
<result name="SUCCESS">/success.jsp</result>
</action>
</package>
</struts>
success.jsp
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<center> Welcome, Data successfully inserted</center>
</body>
</html>
registration.jsp
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<%# taglib uri="/struts-tags" prefix="s"/%>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<s:form action="TestAction" method="post" >
<s:textfield name="Name" label="Name"/>
<s:textfield name="Age" label="Age"/>
<s:textfield name="Location" label="Location"/>
<s:submit label="Submit"></s:submit>
</s:form>
</body>
</html>
TestAction.java
package controller;
import java.sql.Connection;
import java.sql.PreparedStatement;
import com.opensymphony.xwork2.ActionSupport;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import model.TestBean;
import model.UserDao;
import org.apache.struts2.ServletActionContext;
public class TestAction extends ActionSupport{
public String execute(HttpServletRequest request , HttpServletResponse response) throws Exception
{
String Name = request.getParameter("Name");
String Age = request.getParameter("Age");
String Location = request.getParameter("Location");
TestBean bean = new TestBean();
bean.setName(Name);
bean.setAge(Age);
bean.setLocation(Location);
UserDao obj = new UserDao();
Connection x= obj.Logincheck();
if(x!=null)
{
PreparedStatement ps= x.prepareStatement("insert into Registration values(?,?,?)");
ps.setString(1, bean.getName());
ps.setString(2, bean.getAge());
ps.setString(3, bean.getLocation());
int i = ps.executeUpdate();
System.out.println("The value of i =" +i);
if(i>0)
{
return SUCCESS;
}
}
return null;
}
}
TestBean.java
package model;
public class TestBean {
String name;
String age;
String location;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
}
UserDao.java
package model;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
public class UserDao {
public Connection Logincheck()
{
Connection con=null;
try
{
try
{
Class.forName("oracle.jdbc.driver.OracleDriver");
}
catch(ClassNotFoundException e)
{
e.printStackTrace();
}
con= DriverManager.getConnection("jdbc:oracle:thin:#localhost:1521:XE", "username", "password");
if(con!=null)
{
return con;
}
}
catch(Exception e)
{
e.printStackTrace();
}
return null;
}
}
that's all.
This error
There is no Action mapped for namespace /controller and action name
generally means Struts can't find the action specified in a namespace specified (/controller in this case). BTW in your case you've not specified /controller anywhere and the action name is missing in the error message, so this error could be probably generated by the bunch of other errors you have in your action / JSP / configuration.
you also have two typos, preventing anything to work:
sturts-default instead of struts-default:
<package name="default" extends="struts-default">
"SUCCESS" instead of "success", that is the result mapped to the constant SUCCESS that you are returning from the Action method.
<result name="success">/success.jsp</result>
If using Struts version newer than or equals to 2.1.3, you need the new filter, StrutsPrepareAndExecuteFilter instead of the deprecated FilterDispatcher;
The action method must be a public String something() with no parameters. This:
public String execute(HttpServletRequest request , HttpServletResponse response) throws Exception
is simply wrong, and should be:
public String execute(){}
Here
String Name = request.getParameter("Name");
String Age = request.getParameter("Age");
String Location = request.getParameter("Location");
TestBean bean = new TestBean();
bean.setName(Name);
bean.setAge(Age);
bean.setLocation(Location);
you are reinventing the wheel really badly. Attributes must be private, at class level, with getters and setters, and they'll be populated automatically, with no need to access the request. In your case:
private TestBean bean;
/* GETTER AND SETTER */
public String execute(){
System.out.println(bean.getName());
// ...
}
Unrelated, but Java naming conventions use lower-case names for local variables and instance properties.
In JSP page, you need to access the getter with a starting lowercase character:
<s:textfield name="Name" label="Name"/>
must be
<s:textfield name="name" label="Name"/>
and so the other fields. Also if you point to an object like TestBean, you need to do like this:
<s:textfield name="bean.name" label="Name"/>
This are the main problems... BTW consider start coding after having read a book, or some good tutorial. Starting in the dark like this is not the right way, IMHO.
Following are points which you should notice,
If you are using TestBean class as data carrier, you have to implement ModelDriven Interface.
TestAction.java should present in "Controller" package.
If you want HttpServletRequest and HttpServletResponse in your execute() method, then the simplest way you can get that is to implement ServletRequestAware and ServletResponseAware interfaces and implement respective methods.
And most important if your success.jsp is in Web Content folder, then you dont need to specify
<result name="SUCCESS">/success.jsp</result>
Just make it like
<result name="SUCCESS">success.jsp</result>
And if you have any folder suppose, "Folder1" in Web Content, Then specify like
<result name="SUCCESS">Folder1/success.jsp</result>

How to refresh the meta tags in h:head?

In jsf2 when I have PROJECT_STAGE = Production my h:head part is not refreshed. When I change it to Development, then everything works fine. How to force the head part for being refreshed?
The h:head is in template.xhtml.
template.xhtml:
<h:head>
<meta name="description" content="#{metaBean.metaDescription}" />
<meta name="keywords" content="#{metaBean.metaKeywords}" />
</h:head>
web.xml
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<!-- <param-value>Development</param-value>-->
<param-value>Production</param-value>
</context-param>
<context-param>
<param-name>javax.faces.FACELETS_REFRESH_PERIOD</param-name>
<param-value>0</param-value>
</context-param>
...Or How to make dynamic meta description in other way?
Thank you
You can use meta filter like this
public class HtmlMetaFilter implements Filter {
private List<String> metaNames = null;
private List<String> metaValues = null;
private int metaSize = 0;
#Override
public void destroy() {
// logger.info("html meta filter destroyed.");
}
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse res = (HttpServletResponse)response;
for(int i = 0; i < metaSize; i++) {
res.setHeader(metaNames.get(i), metaValues.get(i));
}
chain.doFilter(request, res);
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
metaNames = Configuration.getInstance().getList("//configuration/web-app/html-meta/name");
metaValues = Configuration.getInstance().getList("//configuration/web-app/html-meta/value");
if(metaNames != null && metaValues != null) {
metaSize = Math.min(metaNames.size(), metaValues.size());
}
// logger.info("html meta filter initialized.");
}
}
If you want to change it dynamically, then you need to set the different data in init method from your bean file.
I've found answer on this post: title in h:head rendered before render response phase?
It's enough to use event preRenderView and prepare necessary values in it.

JSF Login with HttpServletRequest

i found a solution in stackoverflow how to code a login in JSF using HttpServletRequest.
First things first, the login.xhtml:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<title>Login</title>
</h:head>
<h:body>
<h3>Login here</h3>
<h:form id="loginForm">
<h:outputLabel for="username" value="Username:" />
<h:inputText value="#{loginService.userName}" id="username" requried="true" />
<br/>
<h:outputLabel for="password" value="Password:" />
<h:inputSecret value="#{loginService.password}" id="password" requried="true" />
<br/>
<h:commandButton id="button" value="Login" action="#{loginService.doLogin}" />
<br/>
<h:commandLink action="#{navigationService.redirectToIndex}" value="Home" />
<br/>
<h:messages />
<br/>
</h:form>
</h:body>
The loginService:
#Named
#SessionScoped
public class LoginService implements Serializable {
private String userName = "";
private String password = "";
#Inject
private NavigationService navigationService = null;
#Inject
private String originalURL = "";
/**
*
*/
#PostConstruct
public void init() {
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
this.originalURL = (String) externalContext.getRequestMap().get(RequestDispatcher.FORWARD_REQUEST_URI);
if(this.originalURL == null) {
this.originalURL = externalContext.getRequestContextPath() + navigationService.toIndex();
} else {
String originalQuery = (String) externalContext.getRequestMap().get(RequestDispatcher.FORWARD_QUERY_STRING);
if(originalQuery != null) {
this.originalURL += "?" + originalQuery;
}
}
}
/**
*
* #return
* #throws IOException
*/
public void doLogin() throws IOException {
FacesContext context = FacesContext.getCurrentInstance();
ExternalContext externalContext = context.getExternalContext();
HttpServletRequest request = (HttpServletRequest)externalContext.getRequest();
try {
request.login(this.userName, this.password);
User user = dao.findUserByUserName(userName);
externalContext.getSessionMap().put("user", user);
externalContext.redirect(this.originalURL);
} catch(ServletException e) {
context.addMessage(null, new FacesMessage("Unknown login"));
} catch (NoSuchUserException e) {
context.addMessage(null, new FacesMessage(e.getMessage()));
}
}
/**
*
* #return
* #throws IOException
*/
public void doLogout() throws IOException {
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
externalContext.invalidateSession();
externalContext.redirect(externalContext.getRequestContextPath() + navigationService.toLogin());
}
// Getters and Setters
}
The only thing i still need to know is now:
Where can i define for which pages login is needed?
A suggested solution is: putting all the pages requiring logging under one place (folder, ex: "private_section"), and the pages that don't need it (public access) are to be put wherever in the project context except under the folder "private_section". Then you can use a simple filter to control accessing to the private region (to our folder), and through this pattern (first annotation) you can specify the region to be controlled :
// imports
#WebFilter("/private_section/*")
public class LoggingFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest)request;
HttpServletResponse res = (HttpServletResponse)response;
UserBean user = (UserBean) req.getSession().getAttribute("user");
if (user != null && user.isLoggedIn()){
chain.doFilter(request,response);
}
else res.sendRedirect(req.getContextPath()+"/index.xhtml");
}
// other overriden methods

JSF 2 Captcha using <h:graphicImage rendering twice for Servlet generated image value working only for Chrome

I have an issue in my application using where I have a Captcha component built as a JSF Custom Tag:
in my JavaEE 6 webapp I use:
JSF 2.1 + Jboss Richfaces 4.2.3 + EJB 3.1 + JPA 2.0 + PrettyFaces 3.3.3
I have a JSF2 custom tag that is:
<tag>
<tag-name>captcha</tag-name>
<source>tags/captcha.xhtml</source>
</tag>
in my XHTML page called accountEdit.xhtml I have the captcha being displayed:
<ui:fragment rendered="#{customerMB.screenComponent.pageName eq 'create'}">
<div class="form_row">
<label class="contact"><strong>#{msg.captcha}:</strong>
</label>
<atl:captcha></atl:captcha>
</div>
</ui:fragment>
in captcha.xhtml:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich">
<table border="0">
<tr>
<td>
<h:graphicImage id="capImg" value="#{facesContext.externalContext.requestContextPath}/../captcha.jpg" />
</td>
<td><a4j:commandButton id="resetCaptcha" value="#{msg.changeImage}" immediate="true" action="#{userMB.resetCaptcha}" >
<a4j:ajax render="capImg" execute="#this" />
</a4j:commandButton></td>
</tr>
<tr>
<td><h:inputText value="#{userMB.captchaComponent.captchaInputText}" /></td>
</tr>
</table>
</ui:composition>
in my web.xml I have configured a CaptchaServlet that handles the request for generating a captcha during runtime:
<servlet>
<servlet-name>CaptchaServlet</servlet-name>
<servlet-class>com.myapp.web.common.servlet.CaptchaServlet</servlet-class>
<init-param>
<description>passing height</description>
<param-name>height</param-name>
<param-value>30</param-value>
</init-param>
<init-param>
<description>passing width</description>
<param-name>width</param-name>
<param-value>120</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CaptchaServlet</servlet-name>
<url-pattern>/captcha.jpg</url-pattern>
</servlet-mapping>
My CaptchaServlet implementation:
public class CaptchaServlet extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = 6105436133454099605L;
private int height = 0;
private int width = 0;
public static final String CAPTCHA_KEY = "captcha_key_name";
#Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
height = Integer
.parseInt(getServletConfig().getInitParameter("height"));
width = Integer.parseInt(getServletConfig().getInitParameter("width"));
}
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse response)
throws IOException, ServletException {
// Expire response
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Max-Age", 0);
BufferedImage image = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
Graphics2D graphics2D = image.createGraphics();
Hashtable<TextAttribute, Object> map = new Hashtable<TextAttribute, Object>();
Random r = new Random();
String token = Long.toString(Math.abs(r.nextLong()), 36);
String ch = token.substring(0, 6);
Color c = new Color(0.6662f, 0.4569f, 0.3232f);
GradientPaint gp = new GradientPaint(30, 30, c, 15, 25, Color.white,
true);
graphics2D.setPaint(gp);
Font font = new Font("Verdana", Font.CENTER_BASELINE, 26);
graphics2D.setFont(font);
graphics2D.drawString(ch, 2, 20);
graphics2D.dispose();
HttpSession session = req.getSession(true);
session.setAttribute(CAPTCHA_KEY, ch);
OutputStream outputStream = response.getOutputStream();
ImageIO.write(image, "jpeg", outputStream);
outputStream.close();
}
}
When I run this app on Glassfish 3.1.1
when the Servlet's doGet() method is called while rendering
for the HttpServlet doGet() method that renders:
<h:graphicImage id="capImg" value="#{facesContext.externalContext.requestContextPath}/../captcha.jpg" />
doGet() renders only once for Google Chrome, thus rendering correctly.
For Firefox and IE doGet() renders twice updating the Captcha Key but not updating the painted Captcha Image on the page.
If anyone might know what could be a fix for this and why it has this behavior for Chrome different from other browsers please let me.
Thanks in advance!
The browser is caching the response. Your attempt to avoid this is incomplete and incorrect:
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Max-Age", 0);
Please refer How to control web page caching, across all browsers? for the proper set:
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
response.setDateHeader("Expires", 0); // Proxies.
Further, to make it more robust, add a query string with the current timestamp in millis to the image URL. Here's an example provided that you've a java.util.Date instance as managed bean with the name now:
<h:graphicImage id="capImg" value="#{request.contextPath}/../captcha.jpg?#{now.time}" />
(please note that I also simplified the way to get the request context path, I only don't understand how it's useful if you go to domain root by ../ anyway)
I found a solution for this, is not the optimal solution but it works, here it goes:
captcha.xhtml
<table border="0">
<tr>
<td>
<h:graphicImage url="#{request.contextPath}/../jcaptcha"/>
</td>
<td>
<input type='text' name='j_captcha_response' value='' />
</td>
</tr>
</table>
CaptchaServlet doGet method:
protected void doGet(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException {
byte[] captchaChallengeAsJpeg = null;
// the output stream to render the captcha image as jpeg into
ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
try {
// get the session id that will identify the generated captcha.
//the same id must be used to validate the response, the session id is a good candidate!
String captchaId = httpServletRequest.getSession().getId();
// call the ImageCaptchaService getChallenge method
BufferedImage challenge =
CaptchaServiceSingleton.getImageChallengeForID(captchaId,
httpServletRequest.getLocale());
// a jpeg encoder
JPEGImageEncoder jpegEncoder =
JPEGCodec.createJPEGEncoder(jpegOutputStream);
jpegEncoder.encode(challenge);
} catch (IllegalArgumentException e) {
httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
} catch (CaptchaServiceException e) {
httpServletResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
return;
}
captchaChallengeAsJpeg = jpegOutputStream.toByteArray();
// flush it in the response
httpServletResponse.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
httpServletResponse.setHeader("Pragma", "no-cache");
httpServletResponse.setDateHeader("Expires", 0);
httpServletResponse.setContentType("image/jpeg");
ServletOutputStream responseOutputStream =
httpServletResponse.getOutputStream();
responseOutputStream.write(captchaChallengeAsJpeg);
responseOutputStream.flush();
responseOutputStream.close();
}
created CaptchaServiceRequestSingleton.java
package com.myapp.web.common.listener;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Locale;
import com.octo.captcha.service.image.DefaultManageableImageCaptchaService;
import com.octo.captcha.service.image.ImageCaptchaService;
public class CaptchaServiceSingleton {
private static ImageCaptchaService instance = new DefaultManageableImageCaptchaService();
private static final int MAX_CACHE_SIZE = 200;
private static HashMap<String, BufferedImage> captchaImgCache = new HashMap<String, BufferedImage>();
public static ImageCaptchaService getInstance(){
return instance;
}
public static BufferedImage getImageChallengeForID(String id, Locale locale) {
if (captchaImgCache.containsKey(id)) {
return captchaImgCache.get(id);
} else {
BufferedImage bImage = instance.getImageChallengeForID(id, locale);
// if limit reached reset captcha cache
if (captchaImgCache.size() > MAX_CACHE_SIZE) {
captchaImgCache = new HashMap<String, BufferedImage>();
}
captchaImgCache.put(id, bImage);
return bImage;
}
}
public static void resetImageChallengeForID(String id) {
if (captchaImgCache.containsKey(id)) {
captchaImgCache.remove(id);
}
}
}
when clicking on "Create Account" button Captcha is reset:
CustomerMB.openCreateCustomerAccount():
public String openCreateCustomerAccount() {
customerAccountEditVO = new CustomerAccountVO();
screenComponent.setPageName(NameConstants.CREATE);
getUserMB().resetCaptcha();
return null;
}
in UserMB.resetCaptcha():
public String resetCaptcha() {
CaptchaServiceSingleton.resetImageChallengeForID(JSFUtil.getRequest().getRequestedSessionId());
return null;
}
Perhaps it's not the perfect solution but at least it's working for all Browsers.

Resources