views:

83

answers:

3

I am sorry if my question does not make any sense. So here is what I have: 2 pages, A.jsf and B.jsf. When I press a button in A.jsf, the code set the value of an object and redirect to B.jsf. Contain of B.jsf will depend on which object I set in A.jsf (which depend on which button I click). Therefore, I dont want to allow the user to type this on the web browser

http://myhost:myport/myproject/B.jsf

and get directly to B.jsf. So, no GET request to B.jsf, only POST. And if I see GET request to B.jsf, I redirect to A.jsf. I feel like the solution is inside web.xml.
btw, I am using Netbean 6.8 and java EE 6

EDIT Here is the solution. Thanks to BalusC
MyFilter.java

package org.xdrawings.filter;

public class MyFilter implements Filter{

    private FilterConfig filterConfig = null;

    public void destroy(){}

    public void init(FilterConfig filterConfig){
        this.filterConfig = filterConfig;
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException{
        HttpServletRequest req = (HttpServletRequest)request;
        HttpServletResponse res = (HttpServletResponse) response;
        if("GET".equals(req.getMethod()) && "/B.jsf".equals(req.getServletPath())){
            res.sendRedirect("A.jsf");
        }else {
            chain.doFilter(request, response);
        }
    }
}

then in my web.xml

<filter>
    <filter-name>My Filter</filter-name>
    <filter-class>org.xdrawings.filter.MyFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>My Filter</filter-name>
    <url-pattern>*.jsf</url-pattern>
</filter-mapping>

All credits go to BalusC

+1  A: 

Is there something wrong with making B.jsf check for the value set in A.jsf, and issue a redirect if it's not present?

Borealid
well, I give your idea some thought but I am still not there yet. I can use `jQuery` `$(document).ready(function(){...}`, to detect when the page first load, but then the object is in my `managed bean`, correct me if I am wrong, but I dont think you can access it from jQuery. Any idea to fix that?
Harry Pham
A: 

This one shows you how to redirect:

http://stackoverflow.com/questions/973732/redirect-from-jsf/973908#973908

Leniel Macaferi
+4  A: 

Yes, as you guessed, this can be controlled from in the web.xml. You need to declare a security-constraint on an url-pattern of /b.jsf with http-method of GET, along with an empty auth-constraint.

<security-constraint>
    <display-name>Prevent GET requests on the b.jsf file</display-name>
    <web-resource-collection>
        <web-resource-name>The b.jsf file</web-resource-name>
        <url-pattern>/b.jsf</url-pattern>
        <http-method>GET</http-method>
    </web-resource-collection>
    <auth-constraint />
</security-constraint>

This however shows a HTTP 403 error. This doesn't (and can't) redirect to a.jsf (at least, not without supplying a custom 403 error page with the necessary checks, but that's plain ugly). If the redirect is mandatory, other solutions are available:

  1. In the constructor of the request scoped bean associated with b.jsf check for postback by ResponseStateManager#isPostback() and then redirect accordingly using ExternalContext#redirect().

    FacesContext context = FacesContext.getCurrentInstance();
    if (!context.getRenderKit().getResponseStateManager().isPostback(context)) {
        context.getExternalContext().redirect("a.jsf");
    }
    

    If you're already on JSF 2.0, you can also use the convenience method FacesContext#isPostback() instead, which is less typing.

  2. Or as a more high-level approach, create a Filter which does exactly the task. The requested page and the HTTP method can be obtained by HttpServletRequest#getServletPath() and getMethod() respectively and the redirect can be done using HttpServletResponse#sendRedirect().

    HttpServletRequest req = (HttpServletRequest) request;
    HttpServletResponse res = (HttpServletResponse) response;
    if ("GET".equals(req.getMethod()) && "/b.jsf".equals(req.getServletPath())) {
       res.sendRedirect("a.jsf");
    } else {
       chain.doFilter(request, response);
    }
    

    This can be more easily extended for future methods and pages which you can configure as under each init-param of the Filter in web.xml.

BalusC
It amazes me how much you know about Web development. Your first method work great. However, I kind of want to learn the second method as well, since I always heard about people creating Filter but not sure what it is about. So it seem like you are creating a custom `Filter` here, and tell the project to use that filter via `web.xml`, correct? Let me try it out and I get back to you. Thank you very much man
Harry Pham
I implement your second method, but I have couple questions, can u look at my updated post to see my implementation.
Harry Pham
The filter could be mapped on an `<url-pattern>` of `/*`, or more specific `*.jsf`, or even more specific the `/b.jsf` (and then remove the unnecessary check in the `if` block). The `<init-param>` is optional. If you define any, it'll be available by [`FilterConfig#getInitParameter()`](http://download.oracle.com/javaee/5/api/javax/servlet/FilterConfig.html#getInitParameter%28java.lang.String%29) inside `init()` method which you can then assign as instance variable and use it further in `doFilter()` logic. E.g. a commaseparated string of pagenames and so on.
BalusC
See also [Java EE 5 tutorial chapter 4 - Filtering requests and responses](http://download-llnw.oracle.com/javaee/5/tutorial/doc/bnagb.html).
BalusC
Thank you. I successfully got it. But I think `res.sendRedirect("/a.jsf");` is actually `res.sendRedirect("a.jsf");`
Harry Pham
Right, I fixed it. You're welcome.
BalusC