/* * Copyright 2017 OmniFaces * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. */ package org.omnifaces.util; import static java.util.Arrays.asList; import static java.util.Collections.unmodifiableList; import static java.util.logging.Level.FINE; import static javax.servlet.http.HttpServletResponse.SC_MOVED_PERMANENTLY; import static org.omnifaces.util.Reflection.instance; import static org.omnifaces.util.Reflection.toClassOrNull; import static org.omnifaces.util.Servlets.formatContentDispositionHeader; import static org.omnifaces.util.Servlets.prepareRedirectURL; import static org.omnifaces.util.Servlets.toQueryString; import static org.omnifaces.util.Utils.coalesce; import static org.omnifaces.util.Utils.encodeURL; import static org.omnifaces.util.Utils.isAnyEmpty; import static org.omnifaces.util.Utils.isEmpty; import static org.omnifaces.util.Utils.isOneOf; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.Array; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.MissingResourceException; import java.util.ResourceBundle; import java.util.Set; import java.util.logging.Logger; import javax.el.ELContext; import javax.el.ELResolver; import javax.el.ValueExpression; import javax.faces.FacesException; import javax.faces.FactoryFinder; import javax.faces.application.Application; import javax.faces.application.ProjectStage; import javax.faces.application.ViewHandler; import javax.faces.component.UIViewParameter; import javax.faces.component.UIViewRoot; import javax.faces.context.ExternalContext; import javax.faces.context.FacesContext; import javax.faces.context.Flash; import javax.faces.context.PartialViewContext; import javax.faces.convert.Converter; import javax.faces.event.PhaseId; import javax.faces.lifecycle.Lifecycle; import javax.faces.render.RenderKit; import javax.faces.render.RenderKitFactory; import javax.faces.validator.Validator; import javax.faces.view.ViewDeclarationLanguage; import javax.faces.view.ViewMetadata; import javax.faces.view.facelets.FaceletContext; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import javax.servlet.http.Part; import org.omnifaces.component.ParamHolder; import org.omnifaces.config.FacesConfigXml; /** * <p> * Collection of utility methods for the JSF API that are mainly shortcuts for obtaining stuff from the provided * {@link FacesContext} argument. In effect, it 'flattens' the hierarchy of nested objects. * <p> * The difference with {@link Faces} is that no one method of {@link FacesLocal} obtains the {@link FacesContext} from * the current thread by {@link FacesContext#getCurrentInstance()}. This job is up to the caller. This is more efficient * in situations where multiple utility methods needs to be called at the same time. Invoking * {@link FacesContext#getCurrentInstance()} is at its own an extremely cheap operation, however as it's to be obtained * as a {@link ThreadLocal} variable, it's during the call still blocking all other running threads for some nanoseconds * or so. * <p> * Note that methods which are <strong>directly</strong> available on {@link FacesContext} instance itself, such as * {@link FacesContext#getExternalContext()}, {@link FacesContext#getViewRoot()}, * {@link FacesContext#isValidationFailed()}, etc are not delegated by the this utility class, because it would design * technically not make any sense to delegate a single-depth method call like follows: * <pre> * ExternalContext externalContext = FacesLocal.getExternalContext(facesContext); * </pre> * <p> * instead of just calling it directly like follows: * <pre> * ExternalContext externalContext = facesContext.getExternalContext(); * </pre> * * <h3>Usage</h3> * <p> * Some examples (for the full list, check the API documentation): * <pre> * FacesContext context = Faces.getContext(); * User user = FacesLocal.getSessionAttribute(context, "user"); * Item item = FacesLocal.evaluateExpressionGet(context, "#{item}"); * String cookieValue = FacesLocal.getRequestCookie(context, "cookieName"); * List<Locale> supportedLocales = FacesLocal.getSupportedLocales(context); * FacesLocal.invalidateSession(context); * FacesLocal.redirect(context, "login.xhtml"); * </pre> * * @author Arjan Tijms * @author Bauke Scholtz * @since 1.6 * @see Servlets */ public final class FacesLocal { // Constants ------------------------------------------------------------------------------------------------------ private static final Logger logger = Logger.getLogger(FacesLocal.class.getName()); private static final String DEFAULT_MIME_TYPE = "application/octet-stream"; private static final int DEFAULT_SENDFILE_BUFFER_SIZE = 10240; private static final String ERROR_NO_VIEW = "There is no view."; private static final String[] FACELET_CONTEXT_KEYS = { FaceletContext.FACELET_CONTEXT_KEY, // Compiletime constant, may fail when compiled against EE6 and run on EE7. "com.sun.faces.facelets.FACELET_CONTEXT", // JSF 2.0/2.1. "javax.faces.FACELET_CONTEXT" // JSF 2.2. }; // Constructors --------------------------------------------------------------------------------------------------- private FacesLocal() { // Hide constructor. } // JSF general ---------------------------------------------------------------------------------------------------- /** * @see Faces#getServerInfo() */ public static String getServerInfo(FacesContext context) { return getServletContext(context).getServerInfo(); } /** * @see Faces#getProjectStage() */ public static ProjectStage getProjectStage(FacesContext context) { return context.getApplication().getProjectStage(); } /** * @see Faces#isDevelopment() */ public static boolean isDevelopment(FacesContext context) { return getProjectStage(context) == ProjectStage.Development; } /** * @see Faces#isSystemTest() */ public static boolean isSystemTest(FacesContext context) { return getProjectStage(context) == ProjectStage.SystemTest; } /** * @see Faces#isProduction() */ public static boolean isProduction(FacesContext context) { return getProjectStage(context) == ProjectStage.Production; } /** * @see Faces#getMapping() */ public static String getMapping(FacesContext context) { ExternalContext externalContext = context.getExternalContext(); if (externalContext.getRequestPathInfo() == null) { String path = externalContext.getRequestServletPath(); return path.substring(path.lastIndexOf('.')); } else { return externalContext.getRequestServletPath(); } } /** * @see Faces#isPrefixMapping() */ public static boolean isPrefixMapping(FacesContext context) { return Faces.isPrefixMapping(getMapping(context)); } /** * @see Faces#evaluateExpressionGet(String) */ @SuppressWarnings("unchecked") public static <T> T evaluateExpressionGet(FacesContext context, String expression) { if (isEmpty(expression)) { return null; } return (T) context.getApplication().evaluateExpressionGet(context, expression, Object.class); } /** * @see Faces#evaluateExpressionSet(String, Object) */ public static void evaluateExpressionSet(FacesContext context, String expression, Object value) { ELContext elContext = context.getELContext(); ValueExpression valueExpression = context.getApplication().getExpressionFactory() .createValueExpression(elContext, expression, Object.class); valueExpression.setValue(elContext, value); } /** * @see Faces#resolveExpressionGet(Object, String) */ @SuppressWarnings("unchecked") public static <T> T resolveExpressionGet(FacesContext context, Object base, String property) { ELResolver elResolver = context.getApplication().getELResolver(); return (T) elResolver.getValue(context.getELContext(), base, property); } /** * @see Faces#resolveExpressionSet(Object, String, Object) */ public static void resolveExpressionSet(FacesContext context, Object base, String property, Object value) { ELResolver elResolver = context.getApplication().getELResolver(); elResolver.setValue(context.getELContext(), base, property, value); } /** * @see Faces#getContextAttribute(String) */ @SuppressWarnings("unchecked") public static <T> T getContextAttribute(FacesContext context, String name) { return (T) context.getAttributes().get(name); } /** * @see Faces#setContextAttribute(String, Object) */ public static void setContextAttribute(FacesContext context, String name, Object value) { context.getAttributes().put(name, value); } /** * @see Faces#createConverter(Object) */ public static Converter createConverter(FacesContext context, Object identifier) { if (identifier instanceof String) { return createConverter(context, (String) identifier); } else if (identifier instanceof Class) { return createConverter(context, (Class<?>) identifier); } else if (identifier instanceof Converter) { return (Converter) identifier; } else { return null; } } /** * @see Faces#createConverter(String) */ public static Converter createConverter(FacesContext context, String identifier) { Converter converter = context.getApplication().createConverter(identifier); if (converter == null) { converter = createConverter(context, toClassOrNull(identifier)); } return converter; } /** * @see Faces#createConverter(Class) */ public static Converter createConverter(FacesContext context, Class<?> identifier) { if (Converter.class.isAssignableFrom(identifier)) { return (Converter) instance(identifier); } else { return context.getApplication().createConverter(identifier); } } /** * @see Faces#createValidator(Object) */ public static Validator createValidator(FacesContext context, Object identifier) { if (identifier instanceof String) { return createValidator(context, (String) identifier); } else if (identifier instanceof Class) { return createValidator(context, (Class<?>) identifier); } else if (identifier instanceof Validator) { return (Validator) identifier; } else { return null; } } /** * @see Faces#createValidator(String) */ public static Validator createValidator(FacesContext context, String identifier) { Validator validator = context.getApplication().createValidator(identifier); if (validator == null) { validator = createValidator(context, toClassOrNull(identifier)); } return validator; } /** * @see Faces#createValidator(Class) */ @SuppressWarnings("all") public static Validator createValidator(FacesContext context, Class<?> identifier) { if (Validator.class.isAssignableFrom(identifier)) { return (Validator) instance(identifier); } else { return null; } } /** * @see Faces#getLifecycle() */ public static Lifecycle getLifecycle(FacesContext context) { return Servlets.getFacesLifecycle(getServletContext(context)); } // JSF views ------------------------------------------------------------------------------------------------------ /** * @see Faces#setViewRoot(String) */ public static void setViewRoot(FacesContext context, String viewId) { context.setViewRoot(context.getApplication().getViewHandler().createView(context, viewId)); } /** * @see Faces#getViewId() */ public static String getViewId(FacesContext context) { UIViewRoot viewRoot = context.getViewRoot(); return (viewRoot != null) ? viewRoot.getViewId() : null; } /** * @see Faces#getViewIdWithParameters() */ public static String getViewIdWithParameters(FacesContext context) { String viewId = coalesce(getViewId(context), ""); String viewParameters = toQueryString(getViewParameterMap(context)); return (viewParameters == null) ? viewId : (viewId + "?" + viewParameters); } /** * @see Faces#getViewName() */ public static String getViewName(FacesContext context) { String viewId = getViewId(context); return (viewId != null) ? viewId.substring(viewId.lastIndexOf('/') + 1).split("\\.")[0] : null; } /** * @see Faces#getViewDeclarationLanguage() */ public static ViewDeclarationLanguage getViewDeclarationLanguage(FacesContext context) { return context.getApplication().getViewHandler().getViewDeclarationLanguage(context, context.getViewRoot().getViewId()); } /** * @see Faces#getRenderKit() */ public static RenderKit getRenderKit(FacesContext context) { UIViewRoot view = context.getViewRoot(); String renderKitId = (view != null) ? view.getRenderKitId() : context.getApplication().getViewHandler().calculateRenderKitId(context); return ((RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY)).getRenderKit(context, renderKitId); } /** * @see Faces#normalizeViewId(String) */ public static String normalizeViewId(FacesContext context, String path) { String mapping = getMapping(context); if (Faces.isPrefixMapping(mapping)) { if (path.startsWith(mapping)) { return path.substring(mapping.length()); } } else if (path.endsWith(mapping)) { return path.substring(0, path.lastIndexOf('.')) + Utils.coalesce( getInitParameter(context, ViewHandler.FACELETS_SUFFIX_PARAM_NAME), ViewHandler.DEFAULT_FACELETS_SUFFIX); } return path; } /** * @see Faces#getViewParameters() */ public static Collection<UIViewParameter> getViewParameters(FacesContext context) { UIViewRoot viewRoot = context.getViewRoot(); return (viewRoot != null) ? ViewMetadata.getViewParameters(viewRoot) : Collections.<UIViewParameter>emptyList(); } /** * @see Faces#getViewParameterMap() */ public static Map<String, List<String>> getViewParameterMap(FacesContext context) { Collection<UIViewParameter> viewParameters = getViewParameters(context); if (viewParameters.isEmpty()) { return new LinkedHashMap<>(0); } Map<String, List<String>> parameterMap = new LinkedHashMap<>(viewParameters.size()); for (UIViewParameter viewParameter : viewParameters) { String value = viewParameter.getStringValue(context); if (value != null) { // <f:viewParam> doesn't support multiple values anyway, so having multiple <f:viewParam> on the // same request parameter shouldn't end up in repeated parameters in action URL. parameterMap.put(viewParameter.getName(), asList(value)); } } return parameterMap; } /** * @see Faces#getMetadataAttributes(String) */ public static Map<String, Object> getMetadataAttributes(FacesContext context, String viewId) { ViewHandler viewHandler = context.getApplication().getViewHandler(); ViewDeclarationLanguage vdl = viewHandler.getViewDeclarationLanguage(context, viewId); ViewMetadata metadata = vdl.getViewMetadata(context, viewId); return (metadata != null) ? metadata.createMetadataView(context).getAttributes() : Collections.<String, Object>emptyMap(); } /** * @see Faces#getMetadataAttributes() */ public static Map<String, Object> getMetadataAttributes(FacesContext context) { return context.getViewRoot().getAttributes(); } /** * @see Faces#getMetadataAttribute(String, String) */ @SuppressWarnings("unchecked") public static <T> T getMetadataAttribute(FacesContext context, String viewId, String name) { return (T) getMetadataAttributes(context, viewId).get(name); } /** * @see Faces#getMetadataAttribute(String) */ @SuppressWarnings("unchecked") public static <T> T getMetadataAttribute(FacesContext context, String name) { return (T) getMetadataAttributes(context).get(name); } /** * @see Faces#getLocale() */ public static Locale getLocale(FacesContext context) { Locale locale = null; UIViewRoot viewRoot = context.getViewRoot(); // Prefer the locale set in the view. if (viewRoot != null) { locale = viewRoot.getLocale(); } // Then the client preferred locale. if (locale == null) { Locale clientLocale = context.getExternalContext().getRequestLocale(); if (getSupportedLocales(context).contains(clientLocale)) { locale = clientLocale; } } // Then the JSF default locale. if (locale == null) { locale = context.getApplication().getDefaultLocale(); } // Finally the system default locale. if (locale == null) { locale = Locale.getDefault(); } return locale; } /** * @see Faces#getDefaultLocale() */ public static Locale getDefaultLocale(FacesContext context) { return context.getApplication().getDefaultLocale(); } /** * @see Faces#getSupportedLocales() */ public static List<Locale> getSupportedLocales(FacesContext context) { Application application = context.getApplication(); List<Locale> supportedLocales = new ArrayList<>(); Locale defaultLocale = application.getDefaultLocale(); if (defaultLocale != null) { supportedLocales.add(defaultLocale); } for (Iterator<Locale> iter = application.getSupportedLocales(); iter.hasNext();) { Locale supportedLocale = iter.next(); if (!supportedLocale.equals(defaultLocale)) { supportedLocales.add(supportedLocale); } } return supportedLocales; } /** * @see Faces#setLocale(Locale) */ public static void setLocale(FacesContext context, Locale locale) { UIViewRoot viewRoot = context.getViewRoot(); if (viewRoot == null) { throw new IllegalStateException(ERROR_NO_VIEW); } viewRoot.setLocale(locale); } /** * @see Faces#getMessageBundle() */ public static ResourceBundle getMessageBundle(FacesContext context) { String messageBundle = context.getApplication().getMessageBundle(); if (messageBundle == null) { return null; } return ResourceBundle.getBundle(messageBundle, getLocale(context)); } /** * @see Faces#getResourceBundle(String) */ public static ResourceBundle getResourceBundle(FacesContext context, String var) { return context.getApplication().getResourceBundle(context, var); } /** * @see Faces#getResourceBundles() */ public static Map<String, ResourceBundle> getResourceBundles(FacesContext context) { Map<String, String> resourceBundles = FacesConfigXml.INSTANCE.getResourceBundles(); Map<String, ResourceBundle> map = new HashMap<>(resourceBundles.size()); for (String var : resourceBundles.keySet()) { map.put(var, getResourceBundle(context, var)); } return map; } /** * @see Faces#getBundleString(String) */ public static String getBundleString(FacesContext context, String key) { for (ResourceBundle bundle : getResourceBundles(context).values()) { try { return bundle.getString(key); } catch (MissingResourceException ignore) { logger.log(FINE, "Ignoring thrown exception; there is a fallback anyway.", ignore); continue; } } return "???" + key + "???"; } /** * @see Faces#navigate(String) */ public static void navigate(FacesContext context, String outcome) { context.getApplication().getNavigationHandler().handleNavigation(context, null, outcome); } /** * @see Faces#getBookmarkableURL(Map, boolean) */ public static String getBookmarkableURL (FacesContext context, Map<String, List<String>> params, boolean includeViewParams) { String viewId = getViewId(context); if (viewId == null) { throw new IllegalStateException(ERROR_NO_VIEW); } return getBookmarkableURL(context, viewId, params, includeViewParams); } /** * @see Faces#getBookmarkableURL(String, Map, boolean) */ public static String getBookmarkableURL (FacesContext context, String viewId, Map<String, List<String>> params, boolean includeViewParams) { Map<String, List<String>> map = new HashMap<>(); if (params != null) { for (Entry<String, List<String>> param : params.entrySet()) { for (String value : param.getValue()) { addParamToMapIfNecessary(map, param.getKey(), value); } } } return context.getApplication().getViewHandler().getBookmarkableURL(context, viewId, map, includeViewParams); } /** * @see Faces#getBookmarkableURL(Collection, boolean) */ public static String getBookmarkableURL (FacesContext context, Collection<? extends ParamHolder> params, boolean includeViewParams) { String viewId = getViewId(context); if (viewId == null) { throw new IllegalStateException(ERROR_NO_VIEW); } return getBookmarkableURL(context, viewId, params, includeViewParams); } /** * @see Faces#getBookmarkableURL(String, Collection, boolean) */ public static String getBookmarkableURL (FacesContext context, String viewId, Collection<? extends ParamHolder> params, boolean includeViewParams) { Map<String, List<String>> map = new HashMap<>(); if (params != null) { for (ParamHolder param : params) { addParamToMapIfNecessary(map, param.getName(), param.getValue()); } } return context.getApplication().getViewHandler().getBookmarkableURL(context, viewId, map, includeViewParams); } private static void addParamToMapIfNecessary(Map<String, List<String>> map, String name, Object value) { if (isAnyEmpty(name, value)) { return; } List<String> values = map.get(name); if (values == null) { values = new ArrayList<>(1); map.put(name, values); } values.add(value.toString()); } // Facelets ------------------------------------------------------------------------------------------------------- /** * @see Faces#getFaceletContext() */ public static FaceletContext getFaceletContext(FacesContext context) { Map<Object, Object> contextAttributes = context.getAttributes(); for (String key : FACELET_CONTEXT_KEYS) { FaceletContext faceletContext = (FaceletContext) contextAttributes.get(key); if (faceletContext != null) { return faceletContext; } } throw new IllegalStateException(ERROR_NO_VIEW); } /** * @see Faces#getFaceletAttribute(String) */ @SuppressWarnings("unchecked") public static <T> T getFaceletAttribute(FacesContext context, String name) { return (T) getFaceletContext(context).getAttribute(name); } /** * @see Faces#setFaceletAttribute(String, Object) */ public static void setFaceletAttribute(FacesContext context, String name, Object value) { getFaceletContext(context).setAttribute(name, value); } // HTTP request --------------------------------------------------------------------------------------------------- /** * @see Faces#getRequest() */ public static HttpServletRequest getRequest(FacesContext context) { return (HttpServletRequest) context.getExternalContext().getRequest(); } /** * @see Faces#isAjaxRequest() */ public static boolean isAjaxRequest(FacesContext context) { return context.getPartialViewContext().isAjaxRequest(); } /** * @see Faces#isAjaxRequestWithPartialRendering() */ public static boolean isAjaxRequestWithPartialRendering(FacesContext context) { PartialViewContext pvc = context.getPartialViewContext(); return pvc.isAjaxRequest() && !pvc.isRenderAll(); } /** * @see Faces#isPostback() */ public static boolean isPostback(FacesContext context) { return "POST".equalsIgnoreCase(getRequest(context).getMethod()) && context.isPostback(); } /** * @see Faces#getRequestParameterMap() */ public static Map<String, String> getRequestParameterMap(FacesContext context) { return context.getExternalContext().getRequestParameterMap(); } /** * @see Faces#getRequestParameter(String) */ public static String getRequestParameter(FacesContext context, String name) { return getRequestParameterMap(context).get(name); } /** * @see Faces#getRequestParameter(String, Class) */ @SuppressWarnings("unchecked") public static <T> T getRequestParameter(FacesContext context, String name, Class<T> type) { String value = getRequestParameter(context, name); if (value == null) { return null; } Converter converter = createConverter(context, type); if (converter == null) { return (T) value; } return (T) converter.getAsObject(context, context.getViewRoot(), value); } /** * @see Faces#getRequestParameterValuesMap() */ public static Map<String, String[]> getRequestParameterValuesMap(FacesContext context) { return context.getExternalContext().getRequestParameterValuesMap(); } /** * @see Faces#getRequestParameterValues(String) */ public static String[] getRequestParameterValues(FacesContext context, String name) { return getRequestParameterValuesMap(context).get(name); } /** * @see Faces#getRequestParameterValues(String, Class) */ @SuppressWarnings("unchecked") public static <T> T[] getRequestParameterValues(FacesContext context, String name, Class<T> type) { String[] values = getRequestParameterValues(context, name); if (values == null) { return null; } Converter converter = createConverter(context, type); if (converter == null) { return (T[]) values; } Object convertedValues = Array.newInstance(type, values.length); for (int i = 0; i < values.length; i++) { Array.set(convertedValues, i, converter.getAsObject(context, context.getViewRoot(), values[i])); } return (T[]) convertedValues; } /** * @see Faces#getRequestParts() */ public static Collection<Part> getRequestParts(FacesContext context) { try { return getRequest(context).getParts(); } catch (IOException | ServletException e) { throw new FacesException(e); } } /** * @see Faces#getRequestPart(String) */ public static Part getRequestPart(FacesContext context, String name) { try { return getRequest(context).getPart(name); } catch (ServletException | IOException e) { throw new FacesException(e); } } /** * @see Faces#getRequestParts(String) */ public static Collection<Part> getRequestParts(FacesContext context, String name) { try { List<Part> parts = new ArrayList<>(); for (Part part : getRequest(context).getParts()) { if (name.equals(part.getName())) { parts.add(part); } } return unmodifiableList(parts); } catch (ServletException | IOException e) { throw new FacesException(e); } } /** * @see Faces#getRequestHeaderMap() */ public static Map<String, String> getRequestHeaderMap(FacesContext context) { return context.getExternalContext().getRequestHeaderMap(); } /** * @see Faces#getRequestHeader(String) */ public static String getRequestHeader(FacesContext context, String name) { return getRequestHeaderMap(context).get(name); } /** * @see Faces#getRequestHeaderValuesMap() */ public static Map<String, String[]> getRequestHeaderValuesMap(FacesContext context) { return context.getExternalContext().getRequestHeaderValuesMap(); } /** * @see Faces#getRequestHeaderValues(String) */ public static String[] getRequestHeaderValues(FacesContext context, String name) { return getRequestHeaderValuesMap(context).get(name); } /** * @see Faces#getRequestContextPath() */ public static String getRequestContextPath(FacesContext context) { return context.getExternalContext().getRequestContextPath(); } /** * @see Faces#getRequestServletPath() */ public static String getRequestServletPath(FacesContext context) { return context.getExternalContext().getRequestServletPath(); } /** * @see Faces#getRequestPathInfo() */ public static String getRequestPathInfo(FacesContext context) { return Servlets.getRequestPathInfo(getRequest(context)); } /** * @see Faces#getRequestHostname() */ public static String getRequestHostname(FacesContext context) { return Servlets.getRequestHostname(getRequest(context)); } /** * @see Faces#getRequestBaseURL() */ public static String getRequestBaseURL(FacesContext context) { return Servlets.getRequestBaseURL(getRequest(context)); } /** * @see Faces#getRequestDomainURL() */ public static String getRequestDomainURL(FacesContext context) { return Servlets.getRequestDomainURL(getRequest(context)); } /** * @see Faces#getRequestURL() */ public static String getRequestURL(FacesContext context) { return Servlets.getRequestURL(getRequest(context)); } /** * @see Faces#getRequestURI() */ public static String getRequestURI(FacesContext context) { return Servlets.getRequestURI(getRequest(context)); } /** * @see Faces#getRequestQueryString() */ public static String getRequestQueryString(FacesContext context) { return Servlets.getRequestQueryString(getRequest(context)); } /** * @see Faces#getRequestQueryStringMap() */ public static Map<String, List<String>> getRequestQueryStringMap(FacesContext context) { return Servlets.getRequestQueryStringMap(getRequest(context)); } /** * @see Faces#getRequestURLWithQueryString() */ public static String getRequestURLWithQueryString(FacesContext context) { return Servlets.getRequestURLWithQueryString(getRequest(context)); } /** * @see Faces#getRequestURIWithQueryString() */ public static String getRequestURIWithQueryString(FacesContext context) { return Servlets.getRequestURIWithQueryString(getRequest(context)); } /** * @see Faces#getForwardRequestURI() * @deprecated Since 2.4. This is abstracted away by {@link #getRequestURI(FacesContext)}. Use it instead. * JSF has as to retrieving request URI no business of knowing if the request is forwarded/rewritten or not. */ @Deprecated // TODO: Remove in OmniFaces 3.0. public static String getForwardRequestURI(FacesContext context) { return Servlets.getForwardRequestURI(getRequest(context)); } /** * @see Faces#getForwardRequestQueryString() * @deprecated Since 2.4. This is abstracted away by {@link #getRequestQueryString(FacesContext)}. Use it instead. * JSF has as to retrieving request URI no business of knowing if the request is forwarded/rewritten or not. */ @Deprecated // TODO: Remove in OmniFaces 3.0. public static String getForwardRequestQueryString(FacesContext context) { return Servlets.getForwardRequestQueryString(getRequest(context)); } /** * @see Faces#getForwardRequestURIWithQueryString() * @deprecated Since 2.4. This is abstracted away by {@link #getRequestURIWithQueryString(FacesContext)}. Use it instead. * JSF has as to retrieving request URI no business of knowing if the request is forwarded/rewritten or not. */ @Deprecated // TODO: Remove in OmniFaces 3.0. public static String getForwardRequestURIWithQueryString(FacesContext context) { return Servlets.getForwardRequestURIWithQueryString(getRequest(context)); } /** * @see Faces#getRemoteAddr() */ public static String getRemoteAddr(FacesContext context) { return Servlets.getRemoteAddr(getRequest(context)); } // HTTP response -------------------------------------------------------------------------------------------------- /** * @see Faces#getResponse() */ public static HttpServletResponse getResponse(FacesContext context) { return (HttpServletResponse) context.getExternalContext().getResponse(); } /** * @see Faces#getResponseBufferSize() */ public static int getResponseBufferSize(FacesContext context) { return context.getExternalContext().getResponseBufferSize(); } /** * @see Faces#getResponseCharacterEncoding() */ public static String getResponseCharacterEncoding(FacesContext context) { return context.getExternalContext().getResponseCharacterEncoding(); } /** * @see Faces#setResponseStatus(int) */ public static void setResponseStatus(FacesContext context, int status) { context.getExternalContext().setResponseStatus(status); } /** * @see Faces#redirect(String, String...) */ public static void redirect(FacesContext context, String url, String... paramValues) throws IOException { ExternalContext externalContext = context.getExternalContext(); externalContext.getFlash().setRedirect(true); // MyFaces also requires this for a redirect in current request (which is incorrect). externalContext.redirect(prepareRedirectURL(getRequest(context), url, paramValues)); } /** * @see Faces#redirectPermanent(String, String...) */ public static void redirectPermanent(FacesContext context, String url, String... paramValues) { ExternalContext externalContext = context.getExternalContext(); externalContext.getFlash().setRedirect(true); // MyFaces also requires this for a redirect in current request (which is incorrect). externalContext.setResponseStatus(SC_MOVED_PERMANENTLY); externalContext.setResponseHeader("Location", prepareRedirectURL(getRequest(context), url, paramValues)); externalContext.setResponseHeader("Connection", "close"); context.responseComplete(); } /** * @see Faces#refresh() */ public static void refresh(FacesContext context) throws IOException { redirect(context, getRequestURI(context)); } /** * @see Faces#refreshWithQueryString() */ public static void refreshWithQueryString(FacesContext context) throws IOException { redirect(context, getRequestURIWithQueryString(context)); } /** * @see Faces#responseSendError(int, String) */ public static void responseSendError(FacesContext context, int status, String message) throws IOException { context.getExternalContext().responseSendError(status, message); context.responseComplete(); // Below is a workaround for disappearing FacesContext in WildFly/Undertow. It disappears because Undertow // immediately performs a forward to error page instead of waiting until servlet's service is finished. When // the error page is a JSF page as well, then it implicitly invokes FacesServlet once again, which in turn // creates another FacesContext which overrides the current FacesContext in the same thread! So, when the // FacesContext which is created during the forward is released, it leaves the current FacesContext as null, // causing NPE over all place which is relying on FacesContext#getCurrentInstance(). // This is already fixed in WildFly 8.2 / Undertow 1.1.0 as per https://issues.jboss.org/browse/UNDERTOW-322. if (!Faces.hasContext()) { Faces.setContext(context); } } /** * @see Faces#addResponseHeader(String, String) */ public static void addResponseHeader(FacesContext context, String name, String value) { context.getExternalContext().addResponseHeader(name, value); } /** * @see Faces#isResponseCommitted() */ public static boolean isResponseCommitted(FacesContext context) { return context.getExternalContext().isResponseCommitted(); } /** * @see Faces#responseReset() */ public static void responseReset(FacesContext context) { context.getExternalContext().responseReset(); } /** * @see Faces#isRenderResponse() */ public static boolean isRenderResponse(FacesContext context) { return context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE; } // FORM based authentication -------------------------------------------------------------------------------------- /** * @see Faces#login(String, String) */ public static void login(FacesContext context, String username, String password) throws ServletException { getRequest(context).login(username, password); } /** * @see Faces#authenticate() */ public static boolean authenticate(FacesContext context) throws ServletException, IOException { return getRequest(context).authenticate(getResponse(context)); } /** * @see Faces#logout() */ public static void logout(FacesContext context) throws ServletException { getRequest(context).logout(); } /** * @see Faces#getRemoteUser() */ public static String getRemoteUser(FacesContext context) { return context.getExternalContext().getRemoteUser(); } /** * @see Faces#isUserInRole(String) */ public static boolean isUserInRole(FacesContext context, String role) { return context.getExternalContext().isUserInRole(role); } // HTTP cookies --------------------------------------------------------------------------------------------------- /** * @see Faces#getRequestCookie(String) */ public static String getRequestCookie(FacesContext context, String name) { Cookie cookie = (Cookie) context.getExternalContext().getRequestCookieMap().get(name); return (cookie != null) ? Utils.decodeURL(cookie.getValue()) : null; } /** * @see Faces#addResponseCookie(String, String, int) */ public static void addResponseCookie(FacesContext context, String name, String value, int maxAge) { addResponseCookie(context, name, value, getRequestHostname(context), null, maxAge); } /** * @see Faces#addResponseCookie(String, String, String, int) */ public static void addResponseCookie(FacesContext context, String name, String value, String path, int maxAge) { addResponseCookie(context, name, value, getRequestHostname(context), path, maxAge); } /** * @see Faces#addResponseCookie(String, String, String, String, int) */ public static void addResponseCookie(FacesContext context, String name, String value, String domain, String path, int maxAge) { ExternalContext externalContext = context.getExternalContext(); Map<String, Object> properties = new HashMap<>(); if (!isOneOf(domain, null, "localhost")) { // Chrome doesn't like domain:"localhost" on cookies. properties.put("domain", domain); } if (path != null) { properties.put("path", path); } properties.put("maxAge", maxAge); properties.put("httpOnly", true); properties.put("secure", ((HttpServletRequest) externalContext.getRequest()).isSecure()); externalContext.addResponseCookie(name, encodeURL(value), properties); } /** * @see Faces#removeResponseCookie(String, String) */ public static void removeResponseCookie(FacesContext context, String name, String path) { addResponseCookie(context, name, null, path, 0); } // HTTP session --------------------------------------------------------------------------------------------------- /** * @see Faces#getSession() */ public static HttpSession getSession(FacesContext context) { return getSession(context, true); } /** * @see Faces#getSession(boolean) */ public static HttpSession getSession(FacesContext context, boolean create) { return (HttpSession) context.getExternalContext().getSession(create); } /** * @see Faces#getSessionId() */ public static String getSessionId(FacesContext context) { HttpSession session = getSession(context, false); return (session != null) ? session.getId() : null; } /** * @see Faces#invalidateSession() */ public static void invalidateSession(FacesContext context) { context.getExternalContext().invalidateSession(); } /** * @see Faces#hasSession() */ public static boolean hasSession(FacesContext context) { return getSession(context, false) != null; } /** * @see Faces#isSessionNew() */ public static boolean isSessionNew(FacesContext context) { HttpSession session = getSession(context, false); return (session != null && session.isNew()); } /** * @see Faces#getSessionCreationTime() */ public static long getSessionCreationTime(FacesContext context) { return getSession(context).getCreationTime(); } /** * @see Faces#getSessionLastAccessedTime() */ public static long getSessionLastAccessedTime(FacesContext context) { return getSession(context).getLastAccessedTime(); } /** * @see Faces#getSessionMaxInactiveInterval() */ public static int getSessionMaxInactiveInterval(FacesContext context) { // Note that JSF 2.1 has this method on ExternalContext. We don't use it in order to be JSF 2.0 compatible. return getSession(context).getMaxInactiveInterval(); } /** * @see Faces#setSessionMaxInactiveInterval(int) */ public static void setSessionMaxInactiveInterval(FacesContext context, int seconds) { // Note that JSF 2.1 has this method on ExternalContext. We don't use it in order to be JSF 2.0 compatible. getSession(context).setMaxInactiveInterval(seconds); } /** * @see Faces#hasSessionTimedOut() */ public static boolean hasSessionTimedOut(FacesContext context) { HttpServletRequest request = getRequest(context); return request.getRequestedSessionId() != null && !request.isRequestedSessionIdValid(); } // Servlet context ------------------------------------------------------------------------------------------------ /** * @see Faces#getServletContext() */ public static ServletContext getServletContext(FacesContext context) { return (ServletContext) context.getExternalContext().getContext(); } /** * @see Faces#getInitParameterMap() */ @SuppressWarnings("unchecked") public static Map<String, String> getInitParameterMap(FacesContext context) { return context.getExternalContext().getInitParameterMap(); } /** * @see Faces#getInitParameter(String) */ public static String getInitParameter(FacesContext context, String name) { return context.getExternalContext().getInitParameter(name); } /** * @see Faces#getMimeType(String) */ public static String getMimeType(FacesContext context, String name) { String mimeType = context.getExternalContext().getMimeType(name); if (mimeType == null) { mimeType = DEFAULT_MIME_TYPE; } return mimeType; } /** * @see Faces#getResource(String) */ public static URL getResource(FacesContext context, String path) throws MalformedURLException { return context.getExternalContext().getResource(path); } /** * @see Faces#getResourceAsStream(String) */ public static InputStream getResourceAsStream(FacesContext context, String path) { return context.getExternalContext().getResourceAsStream(path); } /** * @see Faces#getResourcePaths(String) */ public static Set<String> getResourcePaths(FacesContext context, String path) { return context.getExternalContext().getResourcePaths(path); } /** * @see Faces#getRealPath(String) */ public static String getRealPath(FacesContext context, String webContentPath) { return context.getExternalContext().getRealPath(webContentPath); } // Request scope -------------------------------------------------------------------------------------------------- /** * @see Faces#getRequestMap() */ public static Map<String, Object> getRequestMap(FacesContext context) { return context.getExternalContext().getRequestMap(); } /** * @see Faces#getRequestAttribute(String) */ @SuppressWarnings("unchecked") public static <T> T getRequestAttribute(FacesContext context, String name) { return (T) getRequestMap(context).get(name); } /** * @see Faces#setRequestAttribute(String, Object) */ public static void setRequestAttribute(FacesContext context, String name, Object value) { getRequestMap(context).put(name, value); } /** * @see Faces#removeRequestAttribute(String) */ @SuppressWarnings("unchecked") public static <T> T removeRequestAttribute(FacesContext context, String name) { return (T) getRequestMap(context).remove(name); } // Flash scope ---------------------------------------------------------------------------------------------------- /** * @see Faces#getFlash() */ public static Flash getFlash(FacesContext context) { return context.getExternalContext().getFlash(); } /** * @see Faces#getFlashAttribute(String) */ @SuppressWarnings("unchecked") public static <T> T getFlashAttribute(FacesContext context, String name) { return (T) getFlash(context).get(name); } /** * @see Faces#setFlashAttribute(String, Object) */ public static void setFlashAttribute(FacesContext context, String name, Object value) { getFlash(context).put(name, value); } /** * @see Faces#removeFlashAttribute(String) */ @SuppressWarnings("unchecked") public static <T> T removeFlashAttribute(FacesContext context, String name) { return (T) getFlash(context).remove(name); } // View scope ----------------------------------------------------------------------------------------------------- /** * @see Faces#getViewMap() */ public static Map<String, Object> getViewMap(FacesContext context) { return context.getViewRoot().getViewMap(); } /** * @see Faces#getViewAttribute(String) */ @SuppressWarnings("unchecked") public static <T> T getViewAttribute(FacesContext context, String name) { return (T) getViewMap(context).get(name); } /** * @see Faces#setViewAttribute(String, Object) */ public static void setViewAttribute(FacesContext context, String name, Object value) { getViewMap(context).put(name, value); } /** * @see Faces#removeViewAttribute(String) */ @SuppressWarnings("unchecked") public static <T> T removeViewAttribute(FacesContext context, String name) { return (T) getViewMap(context).remove(name); } // Session scope -------------------------------------------------------------------------------------------------- /** * @see Faces#getSessionMap() */ public static Map<String, Object> getSessionMap(FacesContext context) { return context.getExternalContext().getSessionMap(); } /** * @see Faces#getSessionAttribute(String) */ @SuppressWarnings("unchecked") public static <T> T getSessionAttribute(FacesContext context, String name) { return (T) getSessionMap(context).get(name); } /** * @see Faces#setSessionAttribute(String, Object) */ public static void setSessionAttribute(FacesContext context, String name, Object value) { getSessionMap(context).put(name, value); } /** * @see Faces#removeSessionAttribute(String) */ @SuppressWarnings("unchecked") public static <T> T removeSessionAttribute(FacesContext context, String name) { return (T) getSessionMap(context).remove(name); } // Application scope ---------------------------------------------------------------------------------------------- /** * @see Faces#getApplicationMap() */ public static Map<String, Object> getApplicationMap(FacesContext context) { return context.getExternalContext().getApplicationMap(); } /** * @see Faces#getApplicationAttribute(String) */ @SuppressWarnings("unchecked") public static <T> T getApplicationAttribute(FacesContext context, String name) { return (T) getApplicationMap(context).get(name); } /** * @see Faces#setApplicationAttribute(String, Object) */ public static void setApplicationAttribute(FacesContext context, String name, Object value) { getApplicationMap(context).put(name, value); } /** * @see Faces#removeApplicationAttribute(String) */ @SuppressWarnings("unchecked") public static <T> T removeApplicationAttribute(FacesContext context, String name) { return (T) getApplicationMap(context).remove(name); } // File download -------------------------------------------------------------------------------------------------- /** * @see Faces#sendFile(File, boolean) */ public static void sendFile(FacesContext context, File file, boolean attachment) throws IOException { sendFile(context, new FileInputStream(file), file.getName(), file.length(), attachment); } /** * @see Faces#sendFile(byte[], String, boolean) */ public static void sendFile(FacesContext context, byte[] content, String filename, boolean attachment) throws IOException { sendFile(context, new ByteArrayInputStream(content), filename, content.length, attachment); } /** * @see Faces#sendFile(InputStream, String, boolean) */ public static void sendFile(FacesContext context, InputStream content, String filename, boolean attachment) throws IOException { sendFile(context, content, filename, -1, attachment); } /** * @see Faces#sendFile(String, boolean, org.omnifaces.util.Callback.Output) */ public static void sendFile(FacesContext context, String filename, boolean attachment, Callback.Output outputCallback) throws IOException { ExternalContext externalContext = context.getExternalContext(); // Prepare the response and set the necessary headers. externalContext.setResponseBufferSize(DEFAULT_SENDFILE_BUFFER_SIZE); externalContext.setResponseContentType(getMimeType(context, filename)); externalContext.setResponseHeader("Content-Disposition", formatContentDispositionHeader(filename, attachment)); // Not exactly mandatory, but this fixes at least a MSIE quirk: http://support.microsoft.com/kb/316431 if (((HttpServletRequest) externalContext.getRequest()).isSecure()) { externalContext.setResponseHeader("Cache-Control", "public"); externalContext.setResponseHeader("Pragma", "public"); } try (OutputStream output = externalContext.getResponseOutputStream()) { outputCallback.writeTo(output); } context.responseComplete(); } /** * Internal global method to send the given input stream to the response. * @param input The file content as input stream. * @param filename The file name which should appear in content disposition header. * @param contentLength The content length, or -1 if it is unknown. * @param attachment Whether the file should be provided as attachment, or just inline. * @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. */ private static void sendFile (final FacesContext context, final InputStream input, String filename, final long contentLength, boolean attachment) throws IOException { sendFile(context, filename, attachment, new Callback.Output() { @Override public void writeTo(OutputStream output) throws IOException { ExternalContext externalContext = context.getExternalContext(); // If content length is known, set it. Note that setResponseContentLength() cannot be used as it takes only int. if (contentLength != -1) { externalContext.setResponseHeader("Content-Length", String.valueOf(contentLength)); } long size = Utils.stream(input, output); // This may be on time for files smaller than the default buffer size, but is otherwise ignored anyway. if (contentLength == -1 && !externalContext.isResponseCommitted()) { externalContext.setResponseHeader("Content-Length", String.valueOf(size)); } } }); } }