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.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<>(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}