Search code examples
jsf-2java-ee-6prettyfaces

PrettyFaces, Filter, and url-pattern issue


I'm working on a Java EE (which I'm fairly new to) web application (JSF, JPA, EJB), and am in the process of incorporating PrettyFaces for human readable/bookmarkable URLs. I've been using a Filter for 2 reasons.

  1. to make sure a user is logged in.
  2. to wrap the call to filterChain.doFilter(...) in a transaction so JPA lazy loading works when generating views (for example, I can just set a Department object in the backing bean, and use #{backingBean.department.employees} to get the associated list of employees in the .xhmtl file).

Before incorporating PrettyFaces, I was using a url-pattern (in web.xml) of *.xhmtl (although the filter doesn't really need to run for the login page) for the Filter. With PrettyFaces, trying to specify a url-pattern for Filters seems to be a bit of a problem, mainly due to the lack of flexibility of the url-pattern rules (lack of support for regular expressions). Is there another way of accomplishing what I need with-out using Filters (and without having to duplicate code)?

Also, I know I can add a static portion to the beginning of the URL (like, /dept/#{deptName}/... and then use a Filter with a url-pattern of /dept/*, but I was hoping to just start with something like /#{deptName}/... (and using a url-pattern of /* runs the filter on everything, including images, javascript, css, etc.)

Basically, the filter has a transaction injected...

@Resource UserTransaction tx;

And does something like this.

public void doFilter(ServletRequest request, ServletResponse response,
        FilterChain chain) throws IOException, ServletException {       
    HttpServletRequest httpReq = (HttpServletRequest) request; 
    HttpServletResponse httpRes = (HttpServletResponse) response;

    HttpSession session = httpReq.getSession();
    User currentUser = (User)session.getAttribute("userInSession");

    if (currentUser == null) {
        httpRes.sendRedirect("...")    //redirect to LoginServlet
    } else {        
    try {
        tx.begin();
        chain.doFilter(httpReq, httpRes);
    }
    catch (Exception e) { } 
    finally {
        try {
             tx.commit();
        }
        catch (Exception e) { }
    }
}

I have a managed bean that is like this...

@ManagedBean
@RequestScoped
@URLMapping(
  id="uutSerialNumber",
  pattern="/#{uutSerialNumberController.programId}/uut/#{uutSerialNumberController.uutId}",
  viewId="/uutSerialNumber.xhtml"
)
public class UutSerialNumberController {
  @EJB private ProgramServiceBean programServiceBean;
  @EJB private UutServiceBean uutServiceBean;

  private Integer programId;
  private Integer uutId;

  private Program program;
  private Uut uut;

  @URLAction
  public String loadData() {
    program = programServiceBean.findByProgramId(programId);
    uut = uutServiceBean.findUutByUutId(uutId);
    return null;
  }

  //other stuff, setters/getters
}

In the view uutSerialNumber.xhmtl, I do something like this (which requires lazy-loading, unless I want to go to the trouble of manually pre-fetching collections in my uutServiceBean.findUutByUutId())...

<ul>
<c:forEach var="serialNumber item="#{uut.serialNumbers}>
   <li>#{serialNumber.description}</li>
</c:forEach>
</ul>

Solution

  • Turns out I didn't have PrettyFaces configured correctly (doh!). It was a little confusing because in the PrettyFaces Reference Guide, it says that you don't need to edit web.xml if using Servlet 3.0 (which I am). But, doing the following solved my problem.

    <!-- PrettyFaces Filter -->
    <filter>
      <filter-name>Pretty Filter</filter-name>
      <filter-class>com.ocpsoft.pretty.PrettyFilter</filter-class>
    </filter>
    <!-- My own view Filter -->
    <filter>
      <filter-name>View Filter</filter-name>
      <filter-class>com.jasoni.ViewFilter</filter-class>
    </filter>
    <!-- mappings -->
    <filter-mapping>
      <filter-name>Pretty Filter</filter-name>
      <url-pattern>/*</url-pattern>
      <dispatcher>FORWARD</dispatcher>
      <dispatcher>REQUEST</dispatcher>
      <dispatcher>ERROR</dispatcher>
    </filter-mapping>
    <filter-mapping>
      <filter-name>View Filter</filter-name>
      <url-pattern>*.xhtml</url-pattern>
      <dispatcher>FORWARD</dispatcher>
      <dispatcher>REQUEST</dispatcher>
      <dispatcher>ERROR</dispatcher>
    </filter-mapping>
    

    With this, I'm able to run a filter on my views and use a Transaction View Pattern (similar to the one mentioned in Pro JPA 2, except using a Filter instead of a Serlvet, so lazy loading works with JPA), and also check that the user has a session going.