9.2 Returning a Non-JSF View Response
In most cases,
links and submit
buttons in a screen generated by a
JSF view trigger a request back to the same view, so that user input
can be processed by the same view as we discussed earlier. There are
exceptions, though. Links may point directly to any type of resource,
e.g., a regular JSP or HTML page. It's also possible
that the response to a JSF view request must be generated by some
other resource type than a JSF view.
9.2.1 Linking Non-JSF Resources
You've already seen an
example of a link to a
different resource than the JSF view that rendered the screen
containing the view, namely the link to the first preferences view in
the menu area view. The logout link is another example, and in links
to a regular JSP page instead of a JSF view:
[<h:outputLink value="../../logout.jsp">
<h:outputText value="Logout" />
</h:outputLink>]
The logout.jsp page is located in the top
directory for the application, so that accessing this page
doesn't trigger the authentication constraint
declared for all resources in the expense
directory; it wouldn't make sense to have to login
if the session has timed out just to be able to logout. I therefore
specify the path as a relative path to the file located two
directories up from the file with the link. An alternative is to use
a JSF EL expression that adds the context path for the application to
a context-relative path so that it makes sense to the browser:
[<h:outputLink
value="#{facesContext.externalContext.request.contextPath}/logout.jsp">
<h:outputText value="Logout" />
</h:outputLink>]
The JSF EL expression evaluates to the application context path,
e.g., /jsfbook if you use the default for the
sample application, so the HTML link's
href attribute is rendered with the value
/jsfbook/logout.jsp. It would, of course, be
better if the link renderer added the context-path automatically for
a context-relative path, but it slipped through the cracks for the
JSF 1.0 specification. Hopefully it will be corrected in a future
release.
The logout JSP page simply invalidates (terminates) the session and
redirects to the index page with links to all book examples:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<% session.invalidate( ); %>
<c:redirect url="/index.html"/>
9.2.2 Processing JSF Input and Generating a Non-JSF Response
If user input must be processed before
the response is rendered
using some other type of resource than a JSF view, you can do so in a
JSF action method or an action event listener. When the input is
processed, render the response any way you like, and just tell JSF
that a response has already been sent to prevent it from trying to
generate a response from the view.
Let's say that you have a JSF view containing links
to external resources, such as referral links to Amazon.com. When the
user clicks a link, you want to log this fact before you redirect to
the book details page on Amazon.com—maybe to make sure their
click-count is accurate. The link may be represented by a
<h:commandLink> action element, like this:
<h:form>
<h:commandLink action="#{logger.logJSFBookClick}">
<h:outputText value="JavaServer Faces, Hans Bergsten (O'Reilly)" />
</h:commandLink>
</h:form>
The <h:commandLink> action element must be
nested within an <h:form> element, and it
generates an HTML link element with a JavaScript event handler that
submits the form when the link is clicked. What's
most important in this example is that it's bound to
an action method that may look like this:
public String logJSFBookClick( ) {
// Whatever is needed to log the event
...
FacesContext context = FacesContext.getCurrentInstance( );
ExternalContext ec = context.getExternalContext( );
try {
ec.redirect("http://www.amazon.com/exec/obidos/ASIN/0596005393");
}
catch (IOException ioe) {
return "failure";
}
context.responseComplete( );
return "success";
}
The action method first does whatever it needs to do to log the fact
that the link was clicked. It then generates a redirect response by
obtaining the ExternalContext and calling its
redirect() method. This is just one example of a
possible non-JSF response. The method could generate a regular
response by setting response headers and writing the body directly,
or it could get hold of a RequestDispatcher and
forward to a servlet or a JSP page. What really matters is that after
the method has generated the response, it must call the
FacesContext responseComplete(
) method. After processing all events for a phase, the JSF
implementation checks to see if anyone has called this method, and if
so, it ends the processing of the request without generating a
response.
|