001/* 002 * Copyright 2002-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.context.request; 018 019import java.lang.reflect.Method; 020import java.util.Map; 021 022import javax.faces.context.ExternalContext; 023import javax.faces.context.FacesContext; 024 025import org.apache.commons.logging.Log; 026import org.apache.commons.logging.LogFactory; 027 028import org.springframework.util.Assert; 029import org.springframework.util.ReflectionUtils; 030import org.springframework.util.StringUtils; 031import org.springframework.web.util.WebUtils; 032 033/** 034 * {@link RequestAttributes} adapter for a JSF {@link javax.faces.context.FacesContext}. 035 * Used as default in a JSF environment, wrapping the current FacesContext. 036 * 037 * <p><b>NOTE:</b> In contrast to {@link ServletRequestAttributes}, this variant does 038 * <i>not</i> support destruction callbacks for scoped attributes, neither for the 039 * request scope nor for the session scope. If you rely on such implicit destruction 040 * callbacks, consider defining a Spring {@link RequestContextListener} in your 041 * {@code web.xml}. 042 * 043 * <p>Requires JSF 2.0 or higher, as of Spring 4.0. 044 * 045 * @author Juergen Hoeller 046 * @since 2.5.2 047 * @see javax.faces.context.FacesContext#getExternalContext() 048 * @see javax.faces.context.ExternalContext#getRequestMap() 049 * @see javax.faces.context.ExternalContext#getSessionMap() 050 * @see RequestContextHolder#currentRequestAttributes() 051 */ 052public class FacesRequestAttributes implements RequestAttributes { 053 054 /** 055 * We'll create a lot of these objects, so we don't want a new logger every time. 056 */ 057 private static final Log logger = LogFactory.getLog(FacesRequestAttributes.class); 058 059 private final FacesContext facesContext; 060 061 062 /** 063 * Create a new FacesRequestAttributes adapter for the given FacesContext. 064 * @param facesContext the current FacesContext 065 * @see javax.faces.context.FacesContext#getCurrentInstance() 066 */ 067 public FacesRequestAttributes(FacesContext facesContext) { 068 Assert.notNull(facesContext, "FacesContext must not be null"); 069 this.facesContext = facesContext; 070 } 071 072 073 /** 074 * Return the JSF FacesContext that this adapter operates on. 075 */ 076 protected final FacesContext getFacesContext() { 077 return this.facesContext; 078 } 079 080 /** 081 * Return the JSF ExternalContext that this adapter operates on. 082 * @see javax.faces.context.FacesContext#getExternalContext() 083 */ 084 protected final ExternalContext getExternalContext() { 085 return getFacesContext().getExternalContext(); 086 } 087 088 /** 089 * Return the JSF attribute Map for the specified scope. 090 * @param scope constant indicating request or session scope 091 * @return the Map representation of the attributes in the specified scope 092 * @see #SCOPE_REQUEST 093 * @see #SCOPE_SESSION 094 */ 095 protected Map<String, Object> getAttributeMap(int scope) { 096 if (scope == SCOPE_REQUEST) { 097 return getExternalContext().getRequestMap(); 098 } 099 else { 100 return getExternalContext().getSessionMap(); 101 } 102 } 103 104 105 @Override 106 public Object getAttribute(String name, int scope) { 107 return getAttributeMap(scope).get(name); 108 } 109 110 @Override 111 public void setAttribute(String name, Object value, int scope) { 112 getAttributeMap(scope).put(name, value); 113 } 114 115 @Override 116 public void removeAttribute(String name, int scope) { 117 getAttributeMap(scope).remove(name); 118 } 119 120 @Override 121 public String[] getAttributeNames(int scope) { 122 return StringUtils.toStringArray(getAttributeMap(scope).keySet()); 123 } 124 125 @Override 126 public void registerDestructionCallback(String name, Runnable callback, int scope) { 127 if (logger.isWarnEnabled()) { 128 logger.warn("Could not register destruction callback [" + callback + "] for attribute '" + name + 129 "' because FacesRequestAttributes does not support such callbacks"); 130 } 131 } 132 133 @Override 134 public Object resolveReference(String key) { 135 if (REFERENCE_REQUEST.equals(key)) { 136 return getExternalContext().getRequest(); 137 } 138 else if (REFERENCE_SESSION.equals(key)) { 139 return getExternalContext().getSession(true); 140 } 141 else if ("application".equals(key)) { 142 return getExternalContext().getContext(); 143 } 144 else if ("requestScope".equals(key)) { 145 return getExternalContext().getRequestMap(); 146 } 147 else if ("sessionScope".equals(key)) { 148 return getExternalContext().getSessionMap(); 149 } 150 else if ("applicationScope".equals(key)) { 151 return getExternalContext().getApplicationMap(); 152 } 153 else if ("facesContext".equals(key)) { 154 return getFacesContext(); 155 } 156 else if ("cookie".equals(key)) { 157 return getExternalContext().getRequestCookieMap(); 158 } 159 else if ("header".equals(key)) { 160 return getExternalContext().getRequestHeaderMap(); 161 } 162 else if ("headerValues".equals(key)) { 163 return getExternalContext().getRequestHeaderValuesMap(); 164 } 165 else if ("param".equals(key)) { 166 return getExternalContext().getRequestParameterMap(); 167 } 168 else if ("paramValues".equals(key)) { 169 return getExternalContext().getRequestParameterValuesMap(); 170 } 171 else if ("initParam".equals(key)) { 172 return getExternalContext().getInitParameterMap(); 173 } 174 else if ("view".equals(key)) { 175 return getFacesContext().getViewRoot(); 176 } 177 else if ("viewScope".equals(key)) { 178 return getFacesContext().getViewRoot().getViewMap(); 179 } 180 else if ("flash".equals(key)) { 181 return getExternalContext().getFlash(); 182 } 183 else if ("resource".equals(key)) { 184 return getFacesContext().getApplication().getResourceHandler(); 185 } 186 else { 187 return null; 188 } 189 } 190 191 @Override 192 public String getSessionId() { 193 Object session = getExternalContext().getSession(true); 194 try { 195 // HttpSession has a getId() method. 196 Method getIdMethod = session.getClass().getMethod("getId"); 197 return String.valueOf(ReflectionUtils.invokeMethod(getIdMethod, session)); 198 } 199 catch (NoSuchMethodException ex) { 200 throw new IllegalStateException("Session object [" + session + "] does not have a getId() method"); 201 } 202 } 203 204 @Override 205 public Object getSessionMutex() { 206 // Enforce presence of a session first to allow listeners to create the mutex attribute 207 ExternalContext externalContext = getExternalContext(); 208 Object session = externalContext.getSession(true); 209 Object mutex = externalContext.getSessionMap().get(WebUtils.SESSION_MUTEX_ATTRIBUTE); 210 if (mutex == null) { 211 mutex = (session != null ? session : externalContext); 212 } 213 return mutex; 214 } 215 216}