How to set parameters for a JSF PhaseListener to intercept and act accordingly?

1k Views Asked by At

I'm trying to add parameters for a PhaseListener to intercept after an action method is executed and redirected to another page - what is the best way to do this?

  • explicit redirect call and wrap the additional parameters with PrettyFacesWrappedRequest?
  • using flash scope on both ends (caller bean and phase listener afterPhase)?
1

There are 1 best solutions below

0
On

Which version of JSF are you using?. With JSF 2.0, 2.1 or 2.2 you can use CDI beans and use interceptors for change the return of your method.

I don't believe that changing JSF Lifecycle becauase of yor Business Logic is a good idea.

You may use interceptors. For example

index.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://xmlns.jcp.org/jsf/html">
<h:head>
  <title>Facelet Title</title>
</h:head>
<h:body>
  <h:form>
    <h:inputText id="txtNro" value="#{testCDI.value}"></h:inputText>
    <h:commandButton value="Send" action="#{testCDI.doSomething()}" />
  </h:form>
</h:body>
</html>

Then your CDI Interceptor Intercept FacesContext and HttpServletRequest (you can use any of them):

@RedirectInterceptor
@Interceptor
public class MyInterceptor {

    @Inject
    HttpServletRequest req;

     @AroundInvoke
    public Object intercept(InvocationContext context) throws Exception {        
        Logger.getLogger("CdiInterceptor").log(Logger.Level.INFO, "REQUEST  "+req);    
        req.setAttribute("irA", "index.xhtml");
        Logger.getLogger("CdiInterceptor").log(Logger.Level.INFO, "FACES CONT "+FacesContext.getCurrentInstance());    
        for(Map.Entry<String, Object> ent : context.getContextData().entrySet()){
            Logger.getLogger("CdiInterceptor").log(Logger.Level.INFO, ent.getKey()+ " --- "+ent.getValue());    
        }
        Logger.getLogger("CdiInterceptor").log(Logger.Level.INFO, " Init logger");
        Object value = context.proceed();

        Logger.getLogger("CdiInterceptor").log(Logger.Level.INFO, " Value : "+value);
        Logger.getLogger("CdiInterceptor").log(Logger.Level.INFO, req.getAttribute("irA"));
            return req.getAttribute("irA");
    }
}

And finally you use "HttpServletRequest" in your CDI controller for analyze HTTP servlet request, and even you can use'it for put request Attributes.

@Named(value = "testCDI")
@RequestScoped
public class CdiInterceptor implements Serializable{

    @Inject HttpServletRequest req;

    private int value;

    @RedirectInterceptor
    public String doSomething(){
        if(value%3 ==0){ 
            req.setAttribute("irA", "index.xhtml");
        }else if(value%3==1){
            req.setAttribute("irA", "page1.xhtml");
        }else{
            req.setAttribute("irA", "page2.xhtml");
        }            
        return null;
    }

In that way you can achieve redirection to another JSF Page, based on HTTP Servlet request.

You may remember enable CDI Interceptors in beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans 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/beans_1_1.xsd"
       bean-discovery-mode="annotated">
    <interceptors>
        <class>cdi.test.MyInterceptor</class>
    </interceptors>
</beans>

UPDATE Interceptors are used for Cross-Cutting concerns, so you use it when you have to apply it to more than one method. If every method has your own logic in your interception, you may use Decorators.