001/* 002 * Copyright 2002-2008 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.util.LinkedHashMap; 020import java.util.Map; 021 022import org.springframework.util.Assert; 023 024/** 025 * Abstract support class for RequestAttributes implementations, 026 * offering a request completion mechanism for request-specific destruction 027 * callbacks and for updating accessed session attributes. 028 * 029 * @author Juergen Hoeller 030 * @since 2.0 031 * @see #requestCompleted() 032 */ 033public abstract class AbstractRequestAttributes implements RequestAttributes { 034 035 /** Map from attribute name String to destruction callback Runnable */ 036 protected final Map<String, Runnable> requestDestructionCallbacks = new LinkedHashMap<String, Runnable>(8); 037 038 private volatile boolean requestActive = true; 039 040 041 /** 042 * Signal that the request has been completed. 043 * <p>Executes all request destruction callbacks and updates the 044 * session attributes that have been accessed during request processing. 045 */ 046 public void requestCompleted() { 047 executeRequestDestructionCallbacks(); 048 updateAccessedSessionAttributes(); 049 this.requestActive = false; 050 } 051 052 /** 053 * Determine whether the original request is still active. 054 * @see #requestCompleted() 055 */ 056 protected final boolean isRequestActive() { 057 return this.requestActive; 058 } 059 060 /** 061 * Register the given callback as to be executed after request completion. 062 * @param name the name of the attribute to register the callback for 063 * @param callback the callback to be executed for destruction 064 */ 065 protected final void registerRequestDestructionCallback(String name, Runnable callback) { 066 Assert.notNull(name, "Name must not be null"); 067 Assert.notNull(callback, "Callback must not be null"); 068 synchronized (this.requestDestructionCallbacks) { 069 this.requestDestructionCallbacks.put(name, callback); 070 } 071 } 072 073 /** 074 * Remove the request destruction callback for the specified attribute, if any. 075 * @param name the name of the attribute to remove the callback for 076 */ 077 protected final void removeRequestDestructionCallback(String name) { 078 Assert.notNull(name, "Name must not be null"); 079 synchronized (this.requestDestructionCallbacks) { 080 this.requestDestructionCallbacks.remove(name); 081 } 082 } 083 084 /** 085 * Execute all callbacks that have been registered for execution 086 * after request completion. 087 */ 088 private void executeRequestDestructionCallbacks() { 089 synchronized (this.requestDestructionCallbacks) { 090 for (Runnable runnable : this.requestDestructionCallbacks.values()) { 091 runnable.run(); 092 } 093 this.requestDestructionCallbacks.clear(); 094 } 095 } 096 097 /** 098 * Update all session attributes that have been accessed during request processing, 099 * to expose their potentially updated state to the underlying session manager. 100 */ 101 protected abstract void updateAccessedSessionAttributes(); 102 103}