Java tutorial
/* * Copyright 2002-2011 the original author or authors. * * 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.springframework.web.servlet.support; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.util.CollectionUtils; import org.springframework.util.MultiValueMap; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import org.springframework.web.servlet.FlashMap; import org.springframework.web.servlet.FlashMapManager; import org.springframework.web.util.UrlPathHelper; /** * A default {@link FlashMapManager} implementation that stores {@link FlashMap} * instances in the HTTP session. * * @author Rossen Stoyanchev * @since 3.1 */ public class DefaultFlashMapManager implements FlashMapManager { private static final String FLASH_MAPS_SESSION_ATTRIBUTE = DefaultFlashMapManager.class.getName() + ".FLASH_MAPS"; private static final Log logger = LogFactory.getLog(DefaultFlashMapManager.class); private int flashTimeout = 180; private final UrlPathHelper urlPathHelper = new UrlPathHelper(); /** * Set the amount of time in seconds after a {@link FlashMap} is saved * (at request completion) and before it expires. * <p>The default value is 180 seconds. */ public void setFlashMapTimeout(int flashTimeout) { this.flashTimeout = flashTimeout; } /** * {@inheritDoc} * <p>An HTTP session is never created by this method. */ public void requestStarted(HttpServletRequest request) { if (request.getAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE) != null) { return; } FlashMap inputFlashMap = lookupFlashMap(request); if (inputFlashMap != null) { request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap)); } FlashMap outputFlashMap = new FlashMap(this.hashCode()); request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, outputFlashMap); removeExpiredFlashMaps(request); } /** * Find the "input" FlashMap for the current request target by matching it * to the target request information of all stored FlashMap instances. * @return a FlashMap instance or {@code null} */ private FlashMap lookupFlashMap(HttpServletRequest request) { List<FlashMap> allFlashMaps = retrieveFlashMaps(request, false); if (CollectionUtils.isEmpty(allFlashMaps)) { return null; } if (logger.isDebugEnabled()) { logger.debug("Retrieved FlashMap(s): " + allFlashMaps); } List<FlashMap> result = new ArrayList<FlashMap>(); for (FlashMap flashMap : allFlashMaps) { if (isFlashMapForRequest(flashMap, request)) { result.add(flashMap); } } if (!result.isEmpty()) { Collections.sort(result); if (logger.isDebugEnabled()) { logger.debug("Found matching FlashMap(s): " + result); } FlashMap match = result.remove(0); allFlashMaps.remove(match); return match; } return null; } /** * Whether the given FlashMap matches the current request. * The default implementation uses the target request path and query params * saved in the FlashMap. */ protected boolean isFlashMapForRequest(FlashMap flashMap, HttpServletRequest request) { if (flashMap.getTargetRequestPath() != null) { String requestUri = this.urlPathHelper.getOriginatingRequestUri(request); if (!requestUri.equals(flashMap.getTargetRequestPath()) && !requestUri.equals(flashMap.getTargetRequestPath() + "/")) { return false; } } MultiValueMap<String, String> targetParams = flashMap.getTargetRequestParams(); for (String paramName : targetParams.keySet()) { for (String targetValue : targetParams.get(paramName)) { if (!ObjectUtils.containsElement(request.getParameterValues(paramName), targetValue)) { return false; } } } return true; } /** * Retrieve all FlashMap instances from the current HTTP session. * If {@code allowCreate} is "true" and no flash maps exist yet, a new list * is created and stored as a session attribute. * @param request the current request * @param allowCreate whether to create the session if necessary * @return a List to add FlashMap instances to or {@code null} * assuming {@code allowCreate} is "false". */ @SuppressWarnings("unchecked") protected List<FlashMap> retrieveFlashMaps(HttpServletRequest request, boolean allowCreate) { HttpSession session = request.getSession(allowCreate); if (session == null) { return null; } List<FlashMap> allFlashMaps = (List<FlashMap>) session.getAttribute(FLASH_MAPS_SESSION_ATTRIBUTE); if (allFlashMaps == null && allowCreate) { synchronized (this) { allFlashMaps = (List<FlashMap>) session.getAttribute(FLASH_MAPS_SESSION_ATTRIBUTE); if (allFlashMaps == null) { allFlashMaps = new CopyOnWriteArrayList<FlashMap>(); session.setAttribute(FLASH_MAPS_SESSION_ATTRIBUTE, allFlashMaps); } } } return allFlashMaps; } /** * Iterate all flash maps and remove expired ones. */ private void removeExpiredFlashMaps(HttpServletRequest request) { List<FlashMap> allMaps = retrieveFlashMaps(request, false); if (CollectionUtils.isEmpty(allMaps)) { return; } List<FlashMap> expiredMaps = new ArrayList<FlashMap>(); for (FlashMap flashMap : allMaps) { if (flashMap.isExpired()) { if (logger.isDebugEnabled()) { logger.debug("Removing expired FlashMap: " + flashMap); } expiredMaps.add(flashMap); } } if (!expiredMaps.isEmpty()) { allMaps.removeAll(expiredMaps); } } /** * {@inheritDoc} * <p>An HTTP session is never created if the "output" FlashMap is empty. */ public void requestCompleted(HttpServletRequest request) { FlashMap flashMap = (FlashMap) request.getAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE); if (flashMap == null) { throw new IllegalStateException("requestCompleted called but \"output\" FlashMap was never created"); } if (!flashMap.isEmpty() && flashMap.isCreatedBy(this.hashCode())) { if (logger.isDebugEnabled()) { logger.debug("Saving FlashMap=" + flashMap); } onSaveFlashMap(flashMap, request); retrieveFlashMaps(request, true).add(flashMap); } } /** * Update a FlashMap before it is stored in the HTTP Session. * <p>The default implementation starts the expiration period and ensures the * target request path is decoded and normalized if it is relative. * @param flashMap the flash map to be saved * @param request the current request */ protected void onSaveFlashMap(FlashMap flashMap, HttpServletRequest request) { String targetPath = flashMap.getTargetRequestPath(); flashMap.setTargetRequestPath(decodeAndNormalizePath(targetPath, request)); flashMap.startExpirationPeriod(this.flashTimeout); } private String decodeAndNormalizePath(String path, HttpServletRequest request) { if (path != null) { path = this.urlPathHelper.decodeRequestString(request, path); if (path.charAt(0) != '/') { String requestUri = this.urlPathHelper.getRequestUri(request); path = requestUri.substring(0, requestUri.lastIndexOf('/') + 1) + path; path = StringUtils.cleanPath(path); } } return path; } }