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...
1 parent bf833e3 commit 04b011051d0e970a323d9a5fb3d20be0ba44fcc7 @BalusC BalusC committed Jul 23, 2014
@@ -421,6 +421,16 @@ public static String normalizeViewId(String path) {
}
/**
+ * 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)}.
* @param viewId The view ID to return the metadata attribute for.
@@ -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;
@@ -262,6 +263,13 @@ else if (path.endsWith(mapping)) {
}
/**
+ * @see Faces#getMetadataAttributes()
+ */
+ public static Map<String, Object> getMetadataAttributes(FacesContext context) {
+ return context.getViewRoot().getAttributes();
+ }
+
+ /**
* @see Faces#getMetadataAttribute(String, String)
*/
@SuppressWarnings("unchecked")
@@ -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,63 +695,24 @@ 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)
*/
public static void responseSendError(FacesContext context, int status, String message) throws IOException {
@@ -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.