001/*
002 * Copyright 2002-2017 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 org.springframework.beans.factory.ObjectFactory;
020import org.springframework.beans.factory.config.Scope;
021
022/**
023 * Abstract {@link Scope} implementation that reads from a particular scope
024 * in the current thread-bound {@link RequestAttributes} object.
025 *
026 * <p>Subclasses simply need to implement {@link #getScope()} to instruct
027 * this class which {@link RequestAttributes} scope to read attributes from.
028 *
029 * <p>Subclasses may wish to override the {@link #get} and {@link #remove}
030 * methods to add synchronization around the call back into this super class.
031 *
032 * @author Rod Johnson
033 * @author Juergen Hoeller
034 * @author Rob Harrop
035 * @since 2.0
036 */
037public abstract class AbstractRequestAttributesScope implements Scope {
038
039        @Override
040        public Object get(String name, ObjectFactory<?> objectFactory) {
041                RequestAttributes attributes = RequestContextHolder.currentRequestAttributes();
042                Object scopedObject = attributes.getAttribute(name, getScope());
043                if (scopedObject == null) {
044                        scopedObject = objectFactory.getObject();
045                        attributes.setAttribute(name, scopedObject, getScope());
046                        // Retrieve object again, registering it for implicit session attribute updates.
047                        // As a bonus, we also allow for potential decoration at the getAttribute level.
048                        Object retrievedObject = attributes.getAttribute(name, getScope());
049                        if (retrievedObject != null) {
050                                // Only proceed with retrieved object if still present (the expected case).
051                                // If it disappeared concurrently, we return our locally created instance.
052                                scopedObject = retrievedObject;
053                        }
054                }
055                return scopedObject;
056        }
057
058        @Override
059        public Object remove(String name) {
060                RequestAttributes attributes = RequestContextHolder.currentRequestAttributes();
061                Object scopedObject = attributes.getAttribute(name, getScope());
062                if (scopedObject != null) {
063                        attributes.removeAttribute(name, getScope());
064                        return scopedObject;
065                }
066                else {
067                        return null;
068                }
069        }
070
071        @Override
072        public void registerDestructionCallback(String name, Runnable callback) {
073                RequestAttributes attributes = RequestContextHolder.currentRequestAttributes();
074                attributes.registerDestructionCallback(name, callback, getScope());
075        }
076
077        @Override
078        public Object resolveContextualObject(String key) {
079                RequestAttributes attributes = RequestContextHolder.currentRequestAttributes();
080                return attributes.resolveReference(key);
081        }
082
083
084        /**
085         * Template method that determines the actual target scope.
086         * @return the target scope, in the form of an appropriate
087         * {@link RequestAttributes} constant
088         * @see RequestAttributes#SCOPE_REQUEST
089         * @see RequestAttributes#SCOPE_SESSION
090         * @see RequestAttributes#SCOPE_GLOBAL_SESSION
091         */
092        protected abstract int getScope();
093
094}