I am working with JSF 2.0, tomcat 7.0, mojarra 2.0.3 and primefaces.
The problem is that I implemented unsuccessfully javax.servlet.Filter class to redirect to the login page if a user tries to enter a page without having logged in, but I am also using FileUpload to upload files to server, which I think is what is me and trigger conflict with the doFilter method, the server throws me the following exception:
javax.servlet.ServletException
javax.faces.webapp.FacesServlet.service (FacesServlet.java: 321)
org.primefaces.webapp.filter.FileUploadFilter.doFilter (FileUploadFilter.java: 98)
org.apache.tomcat.websocket.server.WsFilter.doFilter (WsFilter.java: 52)
I configured the web.xml file as follows:
<!--this may be the cause of the error--!>
<filter>
<filter-name>PrimeFaces FileUpload Filter</filter-name>
<filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>PrimeFaces FileUpload Filter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
</filter-mapping>
<filter>
<filter-name>Login</filter-name>
<filter-class>controller.BeanFiltersession</filter-class>
</filter>
<filter-mapping>
<filter-name>Login</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
after that delete the class that implemented Filter and erased the lines in the web.xml file, but the error still persists
any idea how to fix it?
the problem is not the FileUpload problem is between primefaces, I think the problem is that as I indicated one filter to validate sessions using HttpSession and HttpServletRequest, upon login sends me this exception, it is clear that delete the class that implemented Filter, probe the FileUpload and works without problems, but I think the changes I made in that class were recorded at api.jar servlet-api having Tomcat 7.0 my code is as follows:
package validators;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
public class SessionValidator {
public static HttpSession getSesion(){
return (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(false);
}
public static HttpServletRequest getRequest(){
return (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
}
public static String getUser(){
HttpSession sesion= (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(false);
return sesion.getAttribute("usuario").toString();
}
public static String getNivel(){
HttpSession sesion=getSesion();
if(sesion !=null){
return sesion.getAttribute("nivel").toString();
}else{
return null;
}
}
}
The SessionValidator class called when I login in my code is this:
package controller;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.servlet.http.HttpSession;
import org.primefaces.context.RequestContext;
import validators.SessionValidator;
import model.csConexion;
import model.csSesion;
#ManagedBean
#SessionScoped
public class BeanSesion implements Serializable{
private static final long serialVersionUID = 1L;
private csSesion sesion;
private csConexion con;
HttpSession session;
private String usuario;
private String nivel;
public BeanSesion(){
sesion=new csSesion();
con=new csConexion();
}
public String getUsuario(){
return SessionValidator.getUser();
}
public void setUsuario(String usuario){
this.usuario=usuario;
}
public String getNivel(){
if(SessionValidator.getSesion().getAttribute("usuario")!=null){
return SessionValidator.getNivel();
}else{
return "";
}
}
public void setNivel(String nivel){
this.nivel=nivel;
}
public csSesion getSesion(){
return sesion;
}
public void setSesion(csSesion sesion){
this.sesion=sesion;
}
public String iniciarsesion(ActionEvent e){
RequestContext context= RequestContext.getCurrentInstance();
FacesContext fcontext= FacesContext.getCurrentInstance();
FacesMessage message=null;
boolean ok=false;
ResultSet rs;
try {
if(con.conectar()==true){
String sql="select*from usuario where usuario=? and contrasenia=?";
PreparedStatement comando= con.getConexion().prepareStatement(sql);
comando.setString(1,sesion.getUsuario());
comando.setString(2,sesion.getContrasenia());
rs=comando.executeQuery();
if(rs.next()){
nivel= rs.getString("nivel");
usuario= rs.getString("usuario");
ok=true;
session= SessionValidator.getSesion();
session.setAttribute("usuario", usuario);
session.setAttribute("nivel", nivel);
message= new FacesMessage(FacesMessage.SEVERITY_INFO,"¡Bienvenido!",sesion.getUsuario());
try {
if(nivel.equals("master")){
fcontext.getExternalContext().redirect("admin/admin.xhtml");
}else if(nivel.equals(null)){
fcontext.getExternalContext().redirect("index.xhtml");
}
} catch (Exception e2) {
e2.printStackTrace();
message= new FacesMessage(FacesMessage.SEVERITY_WARN,"Error","Error");
}
}else{
ok=false;
message= new FacesMessage(FacesMessage.SEVERITY_ERROR,"Error","Usuario o contraseña inválidos");
}
FacesContext.getCurrentInstance().addMessage(null,message);
context.addCallbackParam("Ok", ok);
}
} catch (Exception ex) {
ex.printStackTrace();
ok=false;
}
finally{
System.out.println(nivel);
con.desconectar();
}
return nivel;
}
}
and this is the exception send Tomcat:
excepción
javax.servlet.ServletException: null source
javax.faces.webapp.FacesServlet.service(FacesServlet.java:321)
org.primefaces.webapp.filter.FileUploadFilter.doFilter(FileUploadFilter.java:98)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
causa raíz
java.lang.IllegalArgumentException: null source
java.util.EventObject.<init>(Unknown Source)
javax.faces.event.SystemEvent.<init>(SystemEvent.java:67)
javax.faces.event.ComponentSystemEvent.<init>(ComponentSystemEvent.java:69)
javax.faces.event.PostRestoreStateEvent.<init>(PostRestoreStateEvent.java:69)
com.sun.faces.lifecycle.RestoreViewPhase.deliverPostRestoreStateEvent(RestoreViewPhase.java:256)
com.sun.faces.lifecycle.RestoreViewPhase.execute(RestoreViewPhase.java:245)
com.sun.faces.lifecycle.Phase.doPhase(Phase.java:97)
com.sun.faces.lifecycle.RestoreViewPhase.doPhase(RestoreViewPhase.java:107)
com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:114)
javax.faces.webapp.FacesServlet.service(FacesServlet.java:308)
org.primefaces.webapp.filter.FileUploadFilter.doFilter(FileUploadFilter.java:98)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
Related
I am using the following stack :
PrimeFaces 5.3.1
MyFaces 2.2.8
OpenWebBeans 1.6.2
OmniFaces 1.10
DeltaSpike 1.5.1
Tomcat 8.0.28
AFAI understand, only MyFaces and OmniFaces are important there.
I have a bug when an ajax request is performed by a client whose session is expired and when the access to the page is controlled by a <security-constraint> in the webapp web.xml.
In that case, OmniPartialViewContext#startDocument perform a "transparent redirect", to provide a better explanation (see https://github.com/omnifaces/omnifaces/blob/master/src/main/java/org/omnifaces/context/OmniPartialViewContext.java#L275 ) (this function is unchanged from version 1.10 to current 1.11).
#Override
public void startDocument() throws IOException {
wrapped.startDocument();
String loginURL = WebXml.INSTANCE.getFormLoginPage();
if (loginURL != null) {
FacesContext facesContext = FacesContext.getCurrentInstance();
String loginViewId = normalizeViewId(facesContext, loginURL);
if (loginViewId.equals(getViewId(facesContext))) {
String originalURL = getRequestAttribute(facesContext, "javax.servlet.forward.request_uri");
if (originalURL != null) {
redirect(originalURL);
}
}
}
}
This is a problem because, higher in the stack, org.apache.myfaces.context.servlet.PartialViewContextImpl.processPartialRendering does lines 466 and following :
{
String currentEncoding = writer.getCharacterEncoding();
writer.writePreamble("<?xml version=\"1.0\" encoding=\""+
(currentEncoding == null ? "UTF-8" : currentEncoding) +"\"?>");
writer.startDocument();
writer.writeAttribute("id", viewRoot.getContainerClientId(_facesContext),"id");
So, an exception like the following is raised when trying to write the id, because no element is currently opened.
16-Nov-2015 16:36:35.980 SEVERE [http-apr-8444-exec-10] org.omnifaces.exceptionhandler.FullAjaxExceptionHandler.logException FullAjaxExceptionHandler: An exception occurred during rendering JSF ajax response. Error page '/error.xhtml' will be shown.
java.lang.IllegalStateException: Must be called before the start element is closed (attribute 'id')
at org.apache.myfaces.shared.renderkit.html.HtmlResponseWriterImpl.writeAttribute(HtmlResponseWriterImpl.java:816)
at javax.faces.context.ResponseWriterWrapper.writeAttribute(ResponseWriterWrapper.java:109)
at org.apache.myfaces.context.PartialResponseWriterImpl.writeAttribute(PartialResponseWriterImpl.java:407)
at javax.faces.context.ResponseWriterWrapper.writeAttribute(ResponseWriterWrapper.java:109)
at javax.faces.context.ResponseWriterWrapper.writeAttribute(ResponseWriterWrapper.java:109)
at org.apache.myfaces.context.servlet.PartialViewContextImpl.processPartialRendering(PartialViewContextImpl.java:473)
at org.apache.myfaces.context.servlet.PartialViewContextImpl.processPartial(PartialViewContextImpl.java:415)
at org.primefaces.context.PrimePartialViewContext.processPartial(PrimePartialViewContext.java:60)
at javax.faces.context.PartialViewContextWrapper.processPartial(PartialViewContextWrapper.java:85)
at javax.faces.component.UIViewRoot.encodeChildren(UIViewRoot.java:516)
at javax.faces.component.UIComponentBase.encodeAll(UIComponentBase.java:541)
at org.apache.myfaces.view.facelets.FaceletViewDeclarationLanguage.renderView(FaceletViewDeclarationLanguage.java:1891)
at org.apache.myfaces.application.ViewHandlerImpl.renderView(ViewHandlerImpl.java:313)
at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:58)
at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:58)
at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:58)
at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:58)
at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:58)
at org.apache.myfaces.lifecycle.RenderResponseExecutor.execute(RenderResponseExecutor.java:116)
at org.apache.myfaces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:267)
at org.apache.deltaspike.jsf.impl.listener.request.DeltaSpikeLifecycleWrapper.render(DeltaSpikeLifecycleWrapper.java:111)
at javax.faces.lifecycle.LifecycleWrapper.render(LifecycleWrapper.java:31)
at org.apache.deltaspike.jsf.impl.listener.request.JsfClientWindowAwareLifecycleWrapper.render(JsfClientWindowAwareLifecycleWrapper.java:160)
at org.apache.deltaspike.jsf.impl.listener.request.DeltaSpikeLifecycleWrapper.render(DeltaSpikeLifecycleWrapper.java:111)
at javax.faces.lifecycle.LifecycleWrapper.render(LifecycleWrapper.java:31)
at org.apache.deltaspike.jsf.impl.listener.request.JsfClientWindowAwareLifecycleWrapper.render(JsfClientWindowAwareLifecycleWrapper.java:160)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:200)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.logging.log4j.web.Log4jServletFilter.doFilter(Log4jServletFilter.java:71)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:720)
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:466)
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:391)
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:318)
at org.apache.catalina.authenticator.FormAuthenticator.forwardToLoginPage(FormAuthenticator.java:384)
at org.apache.catalina.authenticator.FormAuthenticator.authenticate(FormAuthenticator.java:229)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:577)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
at org.apache.catalina.authenticator.SingleSignOn.invoke(SingleSignOn.java:291)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:673)
at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2503)
at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2492)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
How can I correct that (appart from dropping OmniFaces, which is really cool, and that I would really like to keep. :-) ) ?
Eventually, I am using the following solution, which can be seen as a work around, as patching MyFaces or OmniFaces is out of my reach...
I am adding my own PartialViewContext at the top of the processing chain. This way, I can perform a clean redirect on an ajax request when I can see it is trying to get the login page.
To do so, one has to :
implement a PartialViewContextFactory
implement a PartialViewContext
declare the PartialViewContextFactory in the faces-config.xml file
So, in my webapp faces-config.xml, I put :
<factory>
<partial-view-context-factory>fr.senat.context.SenatPartialViewContextFactory</partial-view-context-factory>
</factory>
My PartialViewContextFactory is dead simple :
package fr.senat.context;
import javax.faces.context.FacesContext;
import javax.faces.context.PartialViewContext;
import javax.faces.context.PartialViewContextFactory;
import lombok.Getter;
/**
*
* #author lpenet
*/
public class SenatPartialViewContextFactory extends PartialViewContextFactory {
#Getter
private final PartialViewContextFactory wrapped;
public SenatPartialViewContextFactory(PartialViewContextFactory wrapped) {
this.wrapped = wrapped;
}
#Override
public PartialViewContext getPartialViewContext(FacesContext context) {
return new SenatPartialViewContext(wrapped.getPartialViewContext(context));
}
}
and the PartialViewContext is quite simple too :
package fr.senat.context;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.context.PartialResponseWriter;
import javax.faces.context.PartialViewContext;
import javax.faces.context.PartialViewContextWrapper;
import javax.faces.event.PhaseId;
import javax.servlet.http.HttpServletRequest;
import lombok.Getter;
import org.apache.myfaces.context.servlet.PartialViewContextImpl;
import org.omnifaces.config.WebXml;
import static org.omnifaces.util.FacesLocal.getRequestAttribute;
import static org.omnifaces.util.FacesLocal.getViewId;
import static org.omnifaces.util.FacesLocal.normalizeViewId;
/**
*
* #author lpenet
*/
public class SenatPartialViewContext extends PartialViewContextWrapper {
#Getter
private final PartialViewContext wrapped;
public SenatPartialViewContext(PartialViewContext wrapped) {
this.wrapped = wrapped;
}
private void processPartialRendering() throws IOException
{
FacesContext facesContext = FacesContext.getCurrentInstance();
UIViewRoot viewRoot = facesContext.getViewRoot();
String loginURL = WebXml.INSTANCE.getFormLoginPage();
if (loginURL != null) {
String loginViewId = normalizeViewId(facesContext, loginURL);
if (loginViewId.equals(getViewId(facesContext))) {
String originalURL = getRequestAttribute(facesContext, "javax.servlet.forward.request_uri");
if (originalURL != null) {
PartialResponseWriter writer = facesContext.getPartialViewContext().getPartialResponseWriter();
writer.startDocument();
HttpServletRequest request = (HttpServletRequest) facesContext.getExternalContext().getRequest();
writer.redirect(request.getContextPath() + loginURL);
writer.endDocument();
return;
}
}
}
wrapped.processPartial(PhaseId.RENDER_RESPONSE);
}
#Override
public void processPartial(PhaseId phaseId)
{
if (phaseId == PhaseId.RENDER_RESPONSE)
{
try {
processPartialRendering();
}
catch (IOException ex)
{
Logger log = Logger.getLogger(PartialViewContextImpl.class.getName());
if (log.isLoggable(Level.SEVERE))
{
log.log(Level.SEVERE, "", ex);
}
}
} else {
wrapped.processPartial(phaseId);
}
}
}
I am trying to navigate to error page if an exception occurred. For that I have defined:
<error-page>
<error-code>500</error-code>
<location>/error.jspx</location>
</error-page>
in the web.xml. Also I have tried to do this by Servlet:
<servlet>
<servlet-name>ErrorHandler</servlet-name>
<servlet-class>web.servlet.ErrorHandler</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ErrorHandler</servlet-name>
<url-pattern>/errorhandler</url-pattern>
</servlet-mapping>
<error-page>
<error-code>500</error-code>
<location>/errorhandler</location>
</error-page>
But neither it is navigating to the error.jspx nor the ErrorHandler Servlet get called.
To test the error handling I have tried to throw new Exception("Test"); from both of the constructor of managed bean and also from actionListener. But it is printing the exception in console but the redirection is not happening.
I have also tried with: <exception-type>java.lang.Exception</exception-type> instead of <error-code>500</error-code>, but no luck. How can I invoke the Servlet or navigate to the page whenever any exception is occurred from anywhere like the constructor or some action/actionListener?
I do not know if this will serve you.
I have a handler for any error defined as follows.
In "faces-config.xml"
<factory>
<exception-handler-factory>
com.mypackage.global.DatExceptionHandlerFactory
</exception-handler-factory>
</factory>
And two classes
import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerFactory;
public class DatExceptionHandlerFactory extends ExceptionHandlerFactory {
private ExceptionHandlerFactory parent;
// this injection handles jsf
public DatExceptionHandlerFactory(ExceptionHandlerFactory parent) {
this.parent = parent;
}
//create your own ExceptionHandler
#Override
public ExceptionHandler getExceptionHandler() {
ExceptionHandler result =
new DatExceptionHandler(parent.getExceptionHandler());
return result;
}
}
Second class
import java.util.Iterator;
import javax.faces.FacesException;
import javax.faces.application.NavigationHandler;
import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerWrapper;
import javax.faces.context.FacesContext;
import javax.faces.context.Flash;
import javax.faces.event.ExceptionQueuedEvent;
import javax.faces.event.ExceptionQueuedEventContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class DatExceptionHandler extends ExceptionHandlerWrapper {
private static Log log = LogFactory.getLog(DatExceptionHandler.class);
private ExceptionHandler wrapped;
public String error = "n";
public String getError() {
return error;
}
public void setError(String error) {
this.error = error;
}
public DatExceptionHandler(ExceptionHandler wrapped) {
this.wrapped = wrapped;
}
#Override
public ExceptionHandler getWrapped() {
return wrapped;
}
#Override
public void handle() throws FacesException {
Iterator iterator = getUnhandledExceptionQueuedEvents().iterator();
while (iterator.hasNext()) {
ExceptionQueuedEvent event = (ExceptionQueuedEvent) iterator.next();
ExceptionQueuedEventContext context = (ExceptionQueuedEventContext)event.getSource();
Throwable throwable = context.getException();
FacesContext fc = FacesContext.getCurrentInstance();
try {
Flash flash = fc.getExternalContext().getFlash();
// Put the exception in the flash scope to be displayed in the error
// page if necessary ...
flash.put("errorDetails", throwable.getMessage());
System.out.println("the error is put in the flash: " + throwable.getMessage());
NavigationHandler navigationHandler = fc.getApplication().getNavigationHandler();
navigationHandler.handleNavigation(fc, null, "components/errorHandler.xhtml?faces-redirect=true");
fc.renderResponse();
} finally {
iterator.remove();
}
}
// Let the parent handle the rest
getWrapped().handle();
}
}
And errorHandler.xhtml to show error
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<link type="text/css" rel="stylesheet" href="#request.contextPath}/css/default.css" />
<title>#{bundle['guessNumber.error_page.title']}</title>
</h:head>
<h:body>
<div class="highlighted errorMessage">
<h:outputText escape="false"
value="#{bundle['guessNumber.error_page.content']}"/>
</div>
<br/><br/>
<div class="errorDetails">
Error details: <br/>
#{flash.keep.errorDetails}
</div>
</h:body>
</html>
I've been trying to follow this answer primarily but I always get redirected to my login.xhtml (except for when i log in from the login page) because this...
AppManager am = (AppManager) req.getSession().getAttribute("appManager");
Is always null.
I've been trying to print out user info on the login screen and no matter how i get there all fields(username, password, loggedIn...) are always null, even if i type the adress straight from the admin page (that's where you get when you log in).
How do I make it so that the session is saved, not whiped everytime i type in the adress manually/leave the page?
AppManager:
import java.io.Serializable;
import javax.ejb.EJB;
import javax.enterprise.context.SessionScoped;
import javax.faces.bean.ManagedBean;
import javax.faces.context.FacesContext;
import jobapp.controller.Controller;
#ManagedBean(name="appManager")
#SessionScoped
public class AppManager implements Serializable {
private static final long serialVersionUID = 16247164405L;
#EJB
private Controller controller;
private String username;
private String password;
private boolean loggedIn;
private Exception failure;
...
/**
*
* #param e an exception to handle.
*/
private void handleException(Exception e) {
e.printStackTrace(System.err);
failure = e;
FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
}
/**
* The login method.
* calls the controllers login method.
*
*/
public void login(){
try{
failure = null;
loggedIn = controller.login(username, password);
}catch (Exception e){
handleException(e);
}
}
/**
* The logout method.
* Sets the user's info to null
* and stops the conversation.
*/
public void logout(){
username = null;
password = null;
loggedIn = false;
FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
}
...
Filter:
#WebFilter("/faces/admin.xhtml")
public class LoginFilter implements Filter {
...
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
HttpServletRequest req = (HttpServletRequest) request;
//TODO fix "am" nullpointer
AppManager am = (AppManager) req.getSession().getAttribute("appManager");
if (am != null && am.isLoggedIn()) {
// User is logged in, so just continue request.
chain.doFilter(request, response);
} else {
// User is not logged in, so redirect to login.
HttpServletResponse res = (HttpServletResponse) response;
res.sendRedirect(req.getContextPath() + "/faces/login.xhtml");
}
}
#SessionScoped is from javax.enterprise.context.SessionScoped
This one works in combination with CDI #Named only. As you're using JSF #ManagedBean, you should be using the scope annotations from javax.faces.bean package instead.
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
#ManagedBean
#SessionScoped
public class AppManager implements Serializable {
Without a valid scope, a JSF managed bean would behave like #RequestScoped which effectively means that it's constructed again and again on every request.
I have a form with a p:fileUpload, and when I submit the form, all methods are not fired
This is my xhtml :
<h:form enctype="multipart/form-data">
<p:messages id="messages" showDetail="true"/>
<p:fileUpload value="#{uploadBean.file}" mode="simple" id="fileUploadId"/>
<p:commandButton value="Envoyer ce fichier" process="#form" update="messages fileUploadId" actionListener="#{uploadBean.upload}"/>
</h:form>
my bean :
public void setFile(final UploadedFile file)
{
System.out.println("Dans le setFile");
this.file = file;
}
public void upload()
{
System.out.println("Dans le upload");
System.out.println("Fichier : " + file.getFileName());
FacesContext.getCurrentInstance().addMessage(null, msg);
}
my web.xml :
<filter>
<filter-name>PrimeFaces FileUpload Filter</filter-name>
<filter-class>
org.primefaces.webapp.filter.FileUploadFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>PrimeFaces FileUpload Filter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
</filter-mapping>
In the trace, I have just :
Infos: Dans le upload
Grave: Réception de «java.lang.NullPointerException» lors de l’invocation du listener d’action «#{uploadBean.upload}» du composant «j_idt11»
Grave: java.lang.NullPointerException
The method setFile() is not call...
Thanks
edit :
All the code of my bean :
import java.io.Serializable;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import org.primefaces.event.FileUploadEvent;
import org.primefaces.model.UploadedFile;
#ManagedBean
#ViewScoped
public class UploadBean implements Serializable
{
/**
*
*/
private static final long serialVersionUID = 556636819990963651L;
private UploadedFile file;
public UploadedFile getFile()
{
System.out.println("Dans le getFile");
return file;
}
public void setFile(final UploadedFile file)
{
System.out.println("Dans le setFile");
this.file = file;
}
public void upload()
{
System.out.println("Dans le upload");
// System.out.println("Fichier : " + file.getFileName());
FacesMessage msg;
if (file == null)
{
msg = new FacesMessage(FacesMessage.SEVERITY_WARN, "Raté ! ", "Le fichier vaut null.");
System.out.println("la variable file : null");
}
else
{
msg = new FacesMessage("Ouép ! ", file.getFileName() + " is uploaded.");
System.out.println("Le nom du fichier uploader est : " + file.getFileName());
}
FacesContext.getCurrentInstance().addMessage(null, msg);
}
}
From what you provided, I think you have done correctly so far. However, there are still 2 things you need to take care of:
You need to download common-io & common-fileupload and import the .jar file into your Library folder.
You also need to make sure that there are no other filters in web.xml or any classes that are annotated with #WebFilter which may read the HttpServletRequest#getInputStream() before PrimeFaces's filter, because it can be read only once.
You are using prettyfaces too? Then try it (set dispatcher):
<filter-mapping>
<filter-name>PrimeFaces FileUpload Filter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
I had a similar issue, the form was not submitted and the setters methods were never called, add
<f:ajax event="change"/>
inside the component what u want to submit. also
"immediate=true"
on the component itself. Thought might be helpful to others..
I would like to upload images onto a folder inside the server.
For some reason i cant. I don't understand why my filter is not being triggered.And why the file does not get uploaded. Could someone have a look at my code and help me find the reason why the files don't get uploaded?
I will paste all i did till now so you can help me find the mistake:
1.Added commons-fileupload-1.2.1.jar and commons-io-1.4.jar to the lib folder(Automatically get added to the classpath)
2.Created an xml that wil make the tag library available(This is placed inside WEB-INF folder)
<?xml version="1.0" encoding="UTF-8"?>
<facelet-taglib version="2.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-facelettaglibrary_2_0.xsd">
<namespace>http://corejsf.com</namespace>
<tag>
<tag-name>upload</tag-name>
<component>
<component-type>javax.faces.Input</component-type>
<renderer-type>com.corejsf.Upload</renderer-type>
</component>
</tag>
</facelet-taglib>
3.Create a package for the implementation of the tag and place in a new package called com.corejsf;
Here is the source:
package com.corejsf;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import javax.el.ValueExpression;
import javax.faces.FacesException;
import javax.faces.component.EditableValueHolder;
import javax.faces.component.UIComponent;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.FacesRenderer;
import javax.faces.render.Renderer;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.fileupload.FileItem;
#FacesRenderer(componentFamily="javax.faces.Input",
rendererType="com.corejsf.Upload")
public class UploadRenderer extends Renderer {
public void encodeBegin(FacesContext context, UIComponent component)
throws IOException {
if (!component.isRendered()) return;
ResponseWriter writer = context.getResponseWriter();
String clientId = component.getClientId(context);
writer.startElement("input", component);
writer.writeAttribute("type", "file", "type");
writer.writeAttribute("name", clientId, "clientId");
writer.endElement("input");
writer.flush();
}
public void decode(FacesContext context, UIComponent component) {
ExternalContext external = context.getExternalContext();
HttpServletRequest request = (HttpServletRequest) external.getRequest();
String clientId = component.getClientId(context);
FileItem item = (FileItem) request.getAttribute(clientId);
Object newValue;
ValueExpression valueExpr = component.getValueExpression("value");
if (valueExpr != null) {
Class<?> valueType = valueExpr.getType(context.getELContext());
if (valueType == byte[].class) {
newValue = item.get();
}
else if (valueType == InputStream.class) {
try {
newValue = item.getInputStream();
} catch (IOException ex) {
throw new FacesException(ex);
}
}
else {
String encoding = request.getCharacterEncoding();
if (encoding != null)
try {
newValue = item.getString(encoding);
} catch (UnsupportedEncodingException ex) {
newValue = item.getString();
}
else
newValue = item.getString();
}
((EditableValueHolder) component).setSubmittedValue(newValue);
((EditableValueHolder) component).setValid(true);
}
Object target = component.getAttributes().get("target");
if (target != null) {
File file;
if (target instanceof File)
file = (File) target;
else {
ServletContext servletContext
= (ServletContext) external.getContext();
String realPath = servletContext.getRealPath(target.toString());
file = new File(realPath);
}
try { // ugh--write is declared with "throws Exception"
item.write(file);
} catch (Exception ex) {
throw new FacesException(ex);
}
}
}
}
4.Then I added a servlet filter, to distinguish to intercept the requests and placed it in the same package as the custom tag implementation
This is its source:
package com.corejsf;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
public class UploadFilter implements Filter {
private int sizeThreshold = -1;
private String repositoryPath;
public void init(FilterConfig config) throws ServletException {
repositoryPath = config.getInitParameter(
"com.corejsf.UploadFilter.repositoryPath");
try {
String paramValue = config.getInitParameter(
"com.corejsf.UploadFilter.sizeThreshold");
if (paramValue != null)
sizeThreshold = Integer.parseInt(paramValue);
}
catch (NumberFormatException ex) {
ServletException servletEx = new ServletException();
servletEx.initCause(ex);
throw servletEx;
}
}
public void destroy() {
}
public void doFilter(ServletRequest request,
ServletResponse response, FilterChain chain)
throws IOException, ServletException {
if (!(request instanceof HttpServletRequest)) {
chain.doFilter(request, response);
return;
}
HttpServletRequest httpRequest = (HttpServletRequest) request;
boolean isMultipartContent
= ServletFileUpload.isMultipartContent(httpRequest);
if (!isMultipartContent) {
chain.doFilter(request, response);
return;
}
DiskFileItemFactory factory = new DiskFileItemFactory();
if (sizeThreshold >= 0)
factory.setSizeThreshold(sizeThreshold);
if (repositoryPath != null)
factory.setRepository(new File(repositoryPath));
ServletFileUpload upload = new ServletFileUpload(factory);
try {
#SuppressWarnings("unchecked") List<FileItem> items
= (List<FileItem>) upload.parseRequest(httpRequest);
final Map<String, String[]> map = new HashMap<String, String[]>();
for (FileItem item : items) {
String str = item.getString();
if (item.isFormField())
map.put(item.getFieldName(), new String[] { str });
else
httpRequest.setAttribute(item.getFieldName(), item);
}
chain.doFilter(new
HttpServletRequestWrapper(httpRequest) {
public Map<String, String[]> getParameterMap() {
return map;
}
// busywork follows ... should have been part of the wrapper
public String[] getParameterValues(String name) {
Map<String, String[]> map = getParameterMap();
return (String[]) map.get(name);
}
public String getParameter(String name) {
String[] params = getParameterValues(name);
if (params == null) return null;
return params[0];
}
public Enumeration<String> getParameterNames() {
Map<String, String[]> map = getParameterMap();
return Collections.enumeration(map.keySet());
}
}, response);
} catch (FileUploadException ex) {
ServletException servletEx = new ServletException();
servletEx.initCause(ex);
throw servletEx;
}
}
}
5.Then I registered the filter in the web.xml. (I wanted to use an annotation but I didn’t know how, does someon know how can I do that with an annotation?)
Also added the corejsf.taglib.xml
<!-- NEEDED FOR FILE UPLOAD -->
<filter>
<filter-name>Upload Filter</filter-name>
<filter-class>com.corejsf.UploadFilter</filter-class>
<init-param>
<param-name>sizeThreshold</param-name>
<param-value>1024</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Upload Filter</filter-name>
<url-pattern>/faces/upload/*</url-pattern>
</filter-mapping>
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<context-param>
<param-name>facelets.LIBRARIES</param-name>
<param-value>/WEB-INF/corejsf.taglib.xml</param-value>
</context-param>
6.On my WebContent folder I created a subfolder called upload(Destination of the uploaded files)
7.Inside a jsf page I use the tag for upload and submit and also use a managed bean method to create the file names:
<html 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:corejsf="http://corejsf.com">
....
<h:form enctype="multipart/form-data">
<corejsf:upload target="upload/#{placeAddController.prepareUniqueIdentifier}" />
....
<h:commandButton value="Dalje" style=" font-weight: bold; font-size:150%; action="/submittedImage" />
...
</h:form>
And the java managedbean:
#ManagedBean
#RequestScoped
public class PlaceAddControler {
…
public String prepareUniqueIdentifier() {
return UUID.randomUUID().toString()+"png";
}
-All seems ok, but something is missing or wrong.
What do you think, why is not uploading?
The filter is apparently not been invoked. Put debug breakpoints on the doFilter() method or add Logger statements or poor man's System.out.println() statements to learn what code exactly get executed and what not and what variables exactly are been set.
The filter will only be invoked when the request URL matches the filter's <url-pattern>. It needs to match the URL pattern of the request URL as you see in the browser address bar of the JSF page with the upload form. As you have configured the URL pattern, /faces/upload/*, it will only be invoked when the request URL look like something this
http://localhost:8080/contextname/faces/upload/form.xhtml
As to the question how to annotate the filter, use #WebFilter.
#WebFilter(urlPatterns={"/faces/upload/*"})
public class UploadFilter implements Filter {
// ...
}
Unrelated to the problem, there are some flaws in the code (yes, I know, the majority is not yours, I just want to warn you):
This filter does not support request parameters with multiple values like foo=val1&foo=val2&foo=val3 as you can get when multi-select or multi-checkbox are been used in the forms. Only the last selected/checked value ends up in the parameter map this way. I'd recommend to fix the filter code accordingly.
Storing uploaded files in webcontent folder is not useful if you want a permanent storage. Whenever you redeploy the webapp WAR/EAR file, then the originally expanded webapp folder will be entirely deleted, including the files which were been added during webapp's runtime. The webserver don't retain the changes in the freshly expanded webapp folder. If you want a more permanent storage, you should be storing the files outside the webapp folder, preferably on an absolute path. E.g. /var/webapp/upload.
See also:
JSF FileUpload Directory