Permalink
Browse files

Added Faces#getMetadataAttributes() for the current view and added

Servlets#facesRedirect() enabling users to perform a JSF ajax redirect
from inside a filter or another servlet.
  • Loading branch information...
BalusC committed Jul 23, 2014
1 parent bf833e3 commit 04b011051d0e970a323d9a5fb3d20be0ba44fcc7
@@ -420,6 +420,16 @@ public static String normalizeViewId(String path) {
return FacesLocal.getMetadataAttributes(getContext(), viewId);
}
/**
* Returns the metadata attribute map of the current view, or an empty map if there is no view metadata.
* @return The metadata attribute map of the current view, or an empty map if there is no view metadata.
* @see UIViewRoot#getAttributes()
* @since 2.0
*/
public static Map<String, Object> getMetadataAttributes() {
return FacesLocal.getMetadataAttributes(getContext());
}
/**
* Returns the metadata attribute of the given view ID associated with the given name.
* Note: this is not the same as the view scope, for that use {@link #getViewAttribute(String)}.
@@ -961,10 +971,13 @@ public static void setResponseStatus(int status) {
}
/**
* Sends a temporary (302) redirect to the given URL. If the given URL does not start with <code>http://</code>,
* Sends a temporary (302) redirect to the given URL. If the given URL does <b>not</b> start with <code>http://</code>,
* <code>https://</code> or <code>/</code>, then the request context path will be prepended, otherwise it will be
* the unmodified redirect URL. So, when redirecting to another page in the same web application, always specify the
* full path from the context root on (which in turn does not need to start with <code>/</code>).
* <pre>
* Faces.redirect("other.xhtml");
* </pre>
* <p>
* You can use {@link String#format(String, Object...)} placeholder <code>%s</code> in the redirect URL to represent
* placeholders for any request parameter values which needs to be URL-encoded. Here's a concrete example:
@@ -986,10 +999,13 @@ public static void redirect(String url, String... paramValues) throws IOExceptio
}
/**
* Sends a permanent (301) redirect to the given URL. If the given URL does not start with <code>http://</code>,
* Sends a permanent (301) redirect to the given URL. If the given URL does <b>not</b> start with <code>http://</code>,
* <code>https://</code> or <code>/</code>, then the request context path will be prepended, otherwise it will be
* the unmodified redirect URL. So, when redirecting to another page in the same web application, always specify the
* full path from the context root on (which in turn does not need to start with <code>/</code>).
* <pre>
* Faces.redirectPermanent("other.xhtml");
* </pre>
* <p>
* You can use {@link String#format(String, Object...)} placeholder <code>%s</code> in the redirect URL to represent
* placeholders for any request parameter values which needs to be URL-encoded. Here's a concrete example:
@@ -13,6 +13,7 @@
package org.omnifaces.util;
import static javax.servlet.http.HttpServletResponse.SC_MOVED_PERMANENTLY;
import static org.omnifaces.util.Servlets.prepareRedirectURL;
import static org.omnifaces.util.Utils.encodeURL;
import java.io.ByteArrayInputStream;
@@ -261,6 +262,13 @@ else if (path.endsWith(mapping)) {
: Collections.<String, Object>emptyMap();
}
/**
* @see Faces#getMetadataAttributes()
*/
public static Map<String, Object> getMetadataAttributes(FacesContext context) {
return context.getViewRoot().getAttributes();
}
/**
* @see Faces#getMetadataAttribute(String, String)
*/
@@ -274,7 +282,7 @@ else if (path.endsWith(mapping)) {
*/
@SuppressWarnings("unchecked")
public static <T> T getMetadataAttribute(FacesContext context, String name) {
return (T) context.getViewRoot().getAttributes().get(name);
return (T) getMetadataAttributes(context).get(name);
}
/**
@@ -687,62 +695,23 @@ public static void setResponseStatus(FacesContext context, int status) {
* @see Faces#redirect(String, String...)
*/
public static void redirect(FacesContext context, String url, String... paramValues) throws IOException {
String normalizedURL = normalizeRedirectURL(context, url);
Object[] params = encodeURLParams(paramValues);
String redirectURL = (params.length == 0) ? normalizedURL : String.format(normalizedURL, params);
ExternalContext externalContext = context.getExternalContext();
externalContext.getFlash().setRedirect(true);
externalContext.redirect(redirectURL);
externalContext.redirect(prepareRedirectURL(getRequest(context), url, paramValues));
}
/**
* @see Faces#redirectPermanent(String, String...)
*/
public static void redirectPermanent(FacesContext context, String url, String... paramValues) {
String normalizedURL = normalizeRedirectURL(context, url);
Object[] params = encodeURLParams(paramValues);
String redirectURL = (params.length == 0) ? normalizedURL : String.format(normalizedURL, params);
ExternalContext externalContext = context.getExternalContext();
externalContext.getFlash().setRedirect(true);
externalContext.setResponseStatus(SC_MOVED_PERMANENTLY);
externalContext.setResponseHeader("Location", redirectURL);
externalContext.setResponseHeader("Location", prepareRedirectURL(getRequest(context), url, paramValues));
externalContext.setResponseHeader("Connection", "close");
context.responseComplete();
}
/**
* Helper method to normalize the given URL for a redirect. If the given URL does not start with
* <code>http://</code>, <code>https://</code> or <code>/</code>, then the request context path will be prepended,
* otherwise it will be unmodified.
*/
private static String normalizeRedirectURL(FacesContext context, String url) {
if (!url.startsWith("http://") && !url.startsWith("https://") && !url.startsWith("/")) {
url = getRequestContextPath(context) + "/" + url;
}
return url;
}
/**
* Helper method to encode the given URL parameters using UTF-8.
*/
private static Object[] encodeURLParams(String... params) {
if (params == null) {
return new Object[0];
}
else {
Object[] encodedParams = new Object[params.length];
for (int i = 0; i < params.length; i++) {
encodedParams[i] = encodeURL(params[i]);
}
return encodedParams;
}
}
/**
* @see Faces#responseSendError(int, String)
*/
@@ -16,9 +16,12 @@
import static org.omnifaces.util.Utils.decodeURL;
import static org.omnifaces.util.Utils.encodeURL;
import static org.omnifaces.util.Utils.isEmpty;
import static org.omnifaces.util.Utils.startsWithOneOf;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
@@ -30,6 +33,8 @@
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.omnifaces.filter.CacheControlFilter;
/**
* Collection of utility methods for the Servlet API in general.
*
@@ -220,6 +225,55 @@ public static String getForwardRequestURIWithQueryString(HttpServletRequest requ
return parameterMap;
}
// HttpServletResponse --------------------------------------------------------------------------------------------
/**
* Sends a temporary (302) faces redirect to the given URL. This does exactly the same as
* {@link Faces#redirect(String, String...)}. The major advantage over calling
* {@link HttpServletResponse#sendRedirect(String)} is that this method also recognizes JSF ajax requests which
* requires a special XML response in order to successfully perform the redirect. This enables you to perform a
* fullworthy "JSF redirect" from inside a servlet filter or even a plain vanilla servlet.
* <p>
* If the given URL does <b>not</b> start with <code>http://</code>, <code>https://</code> or <code>/</code>, then
* the request context path will be prepended, otherwise it will be the unmodified redirect URL. So, when
* redirecting to another page in the same web application, always specify the full path from the context root on
* (which in turn does not need to start with <code>/</code>).
* <pre>
* Servlets.facesRedirect(request, response, "some.xhtml");
* </pre>
* <p>
* You can use {@link String#format(String, Object...)} placeholder <code>%s</code> in the redirect URL to represent
* placeholders for any request parameter values which needs to be URL-encoded. Here's a concrete example:
* <pre>
* Servlets.facesRedirect(request, response, "some.xhtml?foo=%s&bar=%s", foo, bar);
* </pre>
* @param request The involved HTTP servlet request.
* @param response The involved HTTP servlet response.
* @param url The URL to redirect the current response to.
* @param paramValues The request parameter values which you'd like to put URL-encoded in the given URL.
* @throws IOException Whenever something fails at I/O level. The caller should preferably not catch it, but just
* redeclare it in the action method. The servletcontainer will handle it.
* @since 2.0
*/
public static void facesRedirect
(HttpServletRequest request, HttpServletResponse response, String url, String ... paramValues)
throws IOException
{
String redirectURL = prepareRedirectURL(request, url, paramValues);
String facesRequestHeader = request.getHeader("Faces-Request");
if ("partial/ajax".equals(facesRequestHeader) || "partial/process".equals(facesRequestHeader)) {
response.setContentType("text/xml");
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
CacheControlFilter.setNoCacheHeaders(response);
response.getWriter().append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
.printf("<partial-response><redirect url=\"%s\"></redirect></partial-response>", redirectURL);
}
else {
response.sendRedirect(redirectURL);
}
}
// Cookies --------------------------------------------------------------------------------------------------------
/**
@@ -367,4 +421,27 @@ public static void removeResponseCookie(HttpServletRequest request, HttpServletR
return (T) context.getAttribute(name);
}
// Helpers --------------------------------------------------------------------------------------------------------
/**
* Helper method to prepare redirect URL. Package-private so that {@link FacesLocal} can also use it.
*/
static String prepareRedirectURL(HttpServletRequest request, String url, String... paramValues) {
if (!startsWithOneOf(url, "http://", "https://", "/")) {
url = request.getContextPath() + "/" + url;
}
if (isEmpty(paramValues)) {
return url;
}
Object[] encodedParams = new Object[paramValues.length];
for (int i = 0; i < paramValues.length; i++) {
encodedParams[i] = encodeURL(paramValues[i]);
}
return String.format(url, encodedParams);
}
}

0 comments on commit 04b0110

Please sign in to comment.