Hello,

On Wed, 2006-07-26 at 15:54 +0200, tetaslap tetaslap wrote:
> Hi, 
>     I'm currently working on a web-application wich use MyFace,
> Tomahawk, Spring, Hibernate, AcegiSecurity and Birt.
> I would like to prevent the user from submiting a form several times. 
> Which is the best practice for that ? 
> I read about filters, but I got no idea how to user it.
i looked also for a solution but did not find one.

So i wrote an EpochPhaseListener that uses the jsf_sequence that i found
in myfaces. This listener checks if the sequence is higher than in the
last request, and otherwise directly invokes jsfContext.renderResponse.

You have to register the listener in the faces-config.xml, just add the
following below the application element:

<lifecycle>
   <phase-listener>com.freiheit.ark.control.EpochPhaseListener</phase-listener>
</lifecycle>

See the code below, but be aware that's it's not yet really tested... ;)

public final class EpochPhaseListener implements PhaseListener {
    
    private static final String JSF_SEQUENCE_OLD = "jsf_sequence_old";
    private static final long serialVersionUID = 2L;
    private static final Log LOG = LogFactory.getLog( EpochPhaseListener.class 
);

    /* (non-Javadoc)
     * @see 
javax.faces.event.PhaseListener#afterPhase(javax.faces.event.PhaseEvent)
     */
    public void afterPhase( PhaseEvent e ) {
    }

    /* (non-Javadoc)
     * @see 
javax.faces.event.PhaseListener#beforePhase(javax.faces.event.PhaseEvent)
     */
    public void beforePhase( PhaseEvent e ) {
        
        /* get the current epoch from the request
         */
        final Map params = 
e.getFacesContext().getExternalContext().getRequestParameterMap();
        Integer epoch = null;
        if ( params != null ) {
            final Object epochObj = params.get( RendererUtils.SEQUENCE_PARAM );
            if ( epochObj != null ) {
                if ( LOG.isDebugEnabled() )
                    LOG.debug( "Have jsf sequence from request with value " + 
epochObj );
                try {
                    epoch = Integer.valueOf( (String)epochObj );
                } catch ( Exception ex ) {
                    LOG.warn( "Could not read epoch from value " + epochObj, ex 
);
                }
            }
        }
        
        final Object session = 
e.getFacesContext().getExternalContext().getSession( false );
        /* if we have no epoch from the form, we read it from the session
         */
        if ( epoch == null ) {
            if ( session instanceof HttpSession ) {
                epoch = (Integer) ((HttpSession)session).getAttribute( 
JSF_SEQUENCE_OLD );
            }
        }
        
        if ( epoch != null && session instanceof HttpSession ) {
            final HttpSession httpSession = (HttpSession)session;
            if ( LOG.isDebugEnabled() )
                LOG.debug( "Have jsf sequence from session with value " + 
httpSession.getAttribute( RendererUtils.SEQUENCE_PARAM ) );
            final Integer epochOld = (Integer) httpSession.getAttribute( 
JSF_SEQUENCE_OLD );
            if ( epochOld != null ) {
                /* if the current epoch is not higher than the old one,
                 * we do not want to invoke the application, but render
                 * directly the response.
                 */
                if ( epoch <= epochOld ) {
                    LOG.info( "Got invalid request, ommitting application 
invocation." );
                    e.getFacesContext().renderResponse();
                }
            }
            
            if ( epochOld == null || epochOld < epoch ) {
                httpSession.setAttribute( JSF_SEQUENCE_OLD, epoch );
            }
        }
    }

    /* (non-Javadoc)
     * @see javax.faces.event.PhaseListener#getPhaseId()
     */
    public PhaseId getPhaseId() {
        return PhaseId.RESTORE_VIEW;
    }

}


I hope that is what you looked for,
cheers,
Martin



Attachment: signature.asc
Description: This is a digitally signed message part

Reply via email to