1

I have a problem where an action in my h:commandLink is not firing. I reviewed BalusC's very useful post on what the cause might be, and I was able to trace it to number 11:

Be sure that no Filter or Servlet in the same request-response chain has blocked the request for the FacesServlet somehow.

There is a filter that seems to be causing the problem - I found this by removing the filter and trying again. I unfortunately did not write the filter, and more unfortunately I have very little knowledge about them. So I am wondering if there is a good way to have this filter not apply to the h:commandLink action firing? I see the doFilter() method gets passed the following parameters:

ServletRequest request
ServletResponse response
FilterChain chain 

So my first instinct is to see if there is something I can use in one of those parameters that will tell me this is a click from my h:commandLink. If so, I would have all of the code in the doFilter() method get bypassed. Not sure if that is even possible, or a good way to do this, but that is the first thing that comes to mind.

But I would also like to ask here if there is a decent way to handle this? Or does this indicate some sort of problem with the filter itself I might need to look at fixing? Any info like that would be useful.

BTW, I know I can probably use an actionListener to fire the method in my bean, however, this is bad design as I understand it, so I would like to avoid this.

Community
  • 1
  • 1
mkohanek
  • 69
  • 1
  • 10
  • 3
    This is a very rare cause and indicates a possible serious bug or misconfiguration in the filter in question. Which filter is it? A 3rd party one or an inhouse one? Can you tell its fully qualified class name? Can you tell/ask what its job is? – BalusC Mar 22 '13 at 00:57
  • The filter in question was written in house by a peer. His explanation is as follows: "it's there to redirect long urls into matching short urls and forward those short urls to the real long urls". When I removed the filter, to hit the page I had to go to the longer url, something like /status/app/page.xhtml. With the filter in place, this url becomes /status/page/ - so it sounds like I have some debugging to do, I guess it is about time I learn about filters anyway - I will update the thread once I have better information or a solution – mkohanek Mar 22 '13 at 12:26
  • 1
    Sounds like as if he tried to reinvent what's already invented by [PrettyFaces](http://ocpsoft.org/prettyfaces/) in a way which is fully compatible with JSF2. You might want to consider to use it instead to have a more robust implementation instead of wasting time to reinvent the wheel while having insufficient knowledge of the matters. – BalusC Mar 22 '13 at 13:25
  • My debugging seems to indicate that when the `h:commandLink` is clicked, the filter sees this as a request from a "long URL". And when this happens, the chain gets interrupted with a redirect using a generated "short URL": `httpResponse.setHeader("Location", shortRedirectUrl);` So I will ask today if he considered PrettyFaces, and check into implementing this myself if that is acceptable to my stakeholders - thanks for the information! – mkohanek Mar 22 '13 at 14:10

1 Answers1

0

I said I would update this once I had my solution worked out. So the answer to my original question is that it is possible. But the ways to do it are not very good design.

Warning - this first option is very hacky and I do not recommend you do it - just adding for the sake of completeness. One way to do this, would be to give your h:commandLink an ID, something like "skipFilter". Then in the filter, check for this ID. You can check for this in #HttpServletRequest.getParameterNames(). Then add logic to skip the filter if you see the request is coming from this ID.

The other option, is to just use ajax. Then in the filter add logic to check if the request is ajax, and bypass the filter if so: if("partial/ajax".equalsIgnoreCase(#HttpServletRequest.getHeader("Faces-Request")))

Slightly less hacky.

But this what was already being done in my project's filter, so I wasn't adding it myself.

The other option is of course as BalusC recommended, to correct or replace the filter. This is not an option in my case, so I have to work within the constraints of my filter. So I just use ajax. I have my h:commandLink:

<h:commandLink action="#{orderInvoiceBean.navToPdfAction}" value="-EXTRA INVOICE LINK- #{invoice.customerTrxId}" >   
   <f:setPropertyActionListener target="#{orderInvoiceBean.orderInvoiceNative}" value="#{invoice}"/>
   <f:ajax/>  
</h:commandLink>

This way, the orderInvoiceNative property gets set first, then the ajax action occurs, and can access that value as needed.

However, I had one further issue as well. I need to display a binary response - not text. And of course, ajax does not exactly allow for this. But I was constrained to use ajax. So what to do?

Well, I have my ajax action trigger a nav rule, that simply navigates to the following page:

<!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://java.sun.com/jsf/html">
   <h:body binding="#{orderInvoiceBean.orderInvoicePdf}"/>
</html>

Through this page action, a new request is created, so now I can return a binary file in the response. So the result is, you stay on the page on which you clicked the link, and you get a file download dialog - this does not navigate to a blank white page before sending the binary file response as I first feared it would - you stay on the original page, and the url in your browser does not change, even though you invoked a nav rule go to a new page.

Hope this is useful to someone.

mkohanek
  • 69
  • 1
  • 10