Page 4 of 7

Re: Partial AJAX calls don't handle container session timeou

Posted: 26 Jan 2012, 22:20
by smithh032772
Okay. This is the last thing on my to-do list for the JSF/Primefaces web app that I'm developing. I've done some research and reading of topics on this forum and stackoverflow.com. I'm keeping my eyes and ears open for this topic, because I want a working solution which handles session timeouts, invalidate session, and login. Personally, I don't like Java EE j_security_check. I want a Primefaces form as login page, programmatic security/login (starting/opening a session), users and user groups (in DB/DAO), java EE 6 security, allowing certain user groups access to certain modules and/or menu options, xhtml pages, etc...

Re: Partial AJAX calls don't handle container session timeou

Posted: 26 Jan 2012, 23:31
by tandraschko
The only solution that i know, is to write an own ExceptionHandler. It's really easy and you can also for example redirect to an ErrorPage etc. within an AJAX request.

Re: Partial AJAX calls don't handle container session timeou

Posted: 26 Jan 2012, 23:47
by smithh032772
Okay, thanks. I know this topic is discussing AJAX calls, but I will need to address non-AJAX calls too. majority of calls in JSF app i'm developing are AJAX, but there are some non-AJAX, too.

Re: Partial AJAX calls don't handle container session timeou

Posted: 26 Jan 2012, 23:48
by tandraschko
Doesn't matter :) ExceptionHandler is for all requests - not only for AJAX.

Re: Partial AJAX calls don't handle container session timeou

Posted: 27 Jan 2012, 00:04
by smithh032772
Okay, I added NullRestoreViewViewHandler and ViewExpiredExceptionExceptionHandler (package = com.sun.faces) that I found, which was provided by one of guys on website where mojarra is downloaded, but I didn't like how it behaved with the web app, so all I have, at the present is the following in web.xml, but web app not in production yet, so I'm not testing or seeing this exception occur much or xhtml page displayed.

Code: Select all

    <error-page>
        <exception-type>javax.faces.application.ViewExpiredException</exception-type>
        <location>/viewExpired.xhtml</location>
    </error-page>

Re: Partial AJAX calls don't handle container session timeou

Posted: 27 Jan 2012, 00:07
by tandraschko
First off all, create your own ExceptionHandler for your app.
Here is a good post in Oleg's blog: http://ovaraksin.blogspot.com/2010/10/g ... ecked.html

AFAIK the web.xml entry will not work for AJAX request but please share it after your tests.

Also it is easy to test a view expiration.
Just configure server side state saving, open a page, restart your servlet container, do a post on this -> View Expired should occur.

Re: Partial AJAX calls don't handle container session timeou

Posted: 27 Jan 2012, 02:14
by smithh032772
Okay. I think I saw Oleg's blog before, and will use it as a reference. Thanks.

I tested the ViewExpiredException per your last response here in this topic, and the following is the result:

1. Glassfish returned the following to web client (internet browser):

Code: Select all

HTTP Status 500 -

type Exception report

message

descriptionThe server encountered an internal error () that prevented it from fulfilling this request.

exception

javax.servlet.ServletException: null source
root cause

java.lang.IllegalArgumentException: null source
note The full stack traces of the exception and its root causes are available in the GlassFish Server Open Source Edition 3.1.1 logs.

GlassFish Server Open Source Edition 3.1.1
Glassfish server log had the following:

Code: Select all

WARNING: StandardWrapperValve[Faces Servlet]: PWC1406: Servlet.service() for servlet Faces Servlet threw exception
java.lang.IllegalArgumentException: null source
	at java.util.EventObject.<init>(EventObject.java:38)
	at javax.faces.event.SystemEvent.<init>(SystemEvent.java:71)
	at javax.faces.event.ComponentSystemEvent.<init>(ComponentSystemEvent.java:73)
	at javax.faces.event.PostRestoreStateEvent.<init>(PostRestoreStateEvent.java:73)
	at com.sun.faces.lifecycle.RestoreViewPhase.deliverPostRestoreStateEvent(RestoreViewPhase.java:271)
	at com.sun.faces.lifecycle.RestoreViewPhase.execute(RestoreViewPhase.java:257)
	at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
	at com.sun.faces.lifecycle.RestoreViewPhase.doPhase(RestoreViewPhase.java:116)
	at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
	at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)
	at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1539)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
	at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
	at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
	at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:98)
	at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:91)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:162)
	at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:330)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
	at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:174)
	at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:828)
	at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:725)
	at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1019)
	at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:225)
	at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
	at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
	at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
	at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
	at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
	at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
	at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
	at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
	at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
	at java.lang.Thread.run(Thread.java:662)

Re: Partial AJAX calls don't handle container session timeou

Posted: 27 Jan 2012, 12:34
by kwintesencja
Hi smithh032772,

I have implemented this in a couple of projects and will summarize it, here is the files/code you will need:

1 - ViewExpiredExceptionExceptionHandlerFactory: https://bitbucket.org/rmpestano/wikifac ... ctory.java

2 - ViewExpiredExceptionExceptionHandler: https://bitbucket.org/rmpestano/wikifac ... ndler.java

3 - declare the exception handler factory in faces-config:https://bitbucket.org/rmpestano/wikifac ... config.xml

4 - hook the ajax calls with this javascript (place it in a template):

Code: Select all

   <script type="text/javascript">
                 jQuery('body').bind('ajaxError', function(event,xhr){
                 if(xhr.status == 666) {
                       alert('Sessao expirada - Entre novamente no sistema.'); 
                       window.location.replace(xhr.getResponseHeader('redirect'));
                       
                 }
                 });   
           
            </script>
i hope it helps.

Re: Partial AJAX calls don't handle container session timeou

Posted: 27 Jan 2012, 13:56
by cagatay.civici
Here is my example I've just applied to showcase to handle session timeouts and viewexpired exceptions;

ShowcaseExceptionHandlerFactory

Code: Select all

package org.primefaces.examples.application;

import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerFactory;

public class ShowcaseExceptionHandlerFactory extends ExceptionHandlerFactory {

    private ExceptionHandlerFactory base;
    
    public ShowcaseExceptionHandlerFactory(ExceptionHandlerFactory base) {
        this.base = base;
    }
    
    @Override
    public ExceptionHandler getExceptionHandler() {
        return new ShowcaseExceptionHandler(base.getExceptionHandler());
    }
    
}
ShowcaseExceptionHandler

Code: Select all

package org.primefaces.examples.application;

import java.util.Iterator;
import javax.faces.FacesException;
import javax.faces.application.NavigationHandler;
import javax.faces.application.ViewExpiredException;
import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerWrapper;
import javax.faces.context.FacesContext;
import javax.faces.event.ExceptionQueuedEvent;
import javax.faces.event.ExceptionQueuedEventContext;

public class ShowcaseExceptionHandler extends ExceptionHandlerWrapper {

    private ExceptionHandler wrapped;

    public ShowcaseExceptionHandler(ExceptionHandler wrapped) {
        this.wrapped = wrapped;
    }

    @Override
    public ExceptionHandler getWrapped() {
        return this.wrapped;
    }

    @Override
    public void handle() throws FacesException {
        Iterable<ExceptionQueuedEvent> events = this.wrapped.getUnhandledExceptionQueuedEvents();
        for(Iterator<ExceptionQueuedEvent> it = events.iterator(); it.hasNext();) {
            ExceptionQueuedEvent event = it.next();
            ExceptionQueuedEventContext eqec = event.getContext();
            
            if(eqec.getException() instanceof ViewExpiredException) {
                FacesContext context = eqec.getContext();
                NavigationHandler navHandler = context.getApplication().getNavigationHandler();
 
                try {
                    navHandler.handleNavigation(context, null, "home?faces-redirect=true&expired=true");
                }
                finally {
                    it.remove();
                }
            }
        }

        this.wrapped.handle();;
    }
}
faces-config.xml

Code: Select all

    <factory>
        <exception-handler-factory>org.primefaces.examples.application.ShowcaseExceptionHandlerFactory</exception-handler-factory>
    </factory>
UI

User is redirected to home page when session timeouts or view expires so following dialog popups at home.xhtml;

Code: Select all

<p:confirmDialog header="Oooops!!!" severity="alert" 
                         visible="#{not empty param['expired']}" 
                         message="View has expired." widgetVar="confirmDlg">
            <p:commandButton type="button" value="Whatever" onclick="confirmDlg.hide()" />
        </p:confirmDialog>
Image

Re: Partial AJAX calls don't handle container session timeou

Posted: 27 Jan 2012, 14:23
by ltune
Don`t know if it has been mentioned before, but an elegant solution with phase-listener exists since 2006 -> [1].
Basically you check in phaseListener if in your sessionBean user is logged in.

Code: Select all

	@Override
	public void beforePhase(PhaseEvent event) {
		FacesContext fc = event.getFacesContext();
		[...]  // null check for fc, loggin status of your sessionBean, etc..
		//user not logged in:
		NavigationHandler nh = fc.getApplication().getNavigationHandler();
		nh.handleNavigation(fc, null, "login"); // assuming you have "login" as Naviagtion-case in faces-config
}
Had to mention this, because its good to see, when code works for so many years ;)

[1] http://mowyourlawn.com/blog/?p=6