001/*
002 * Copyright 2002-2019 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.cache.interceptor;
018
019import org.springframework.cache.Cache;
020import org.springframework.lang.Nullable;
021import org.springframework.util.function.SingletonSupplier;
022
023/**
024 * A base component for invoking {@link Cache} operations and using a
025 * configurable {@link CacheErrorHandler} when an exception occurs.
026 *
027 * @author Stephane Nicoll
028 * @author Juergen Hoeller
029 * @since 4.1
030 * @see org.springframework.cache.interceptor.CacheErrorHandler
031 */
032public abstract class AbstractCacheInvoker {
033
034        protected SingletonSupplier<CacheErrorHandler> errorHandler;
035
036
037        protected AbstractCacheInvoker() {
038                this.errorHandler = SingletonSupplier.of(SimpleCacheErrorHandler::new);
039        }
040
041        protected AbstractCacheInvoker(CacheErrorHandler errorHandler) {
042                this.errorHandler = SingletonSupplier.of(errorHandler);
043        }
044
045
046        /**
047         * Set the {@link CacheErrorHandler} instance to use to handle errors
048         * thrown by the cache provider. By default, a {@link SimpleCacheErrorHandler}
049         * is used who throws any exception as is.
050         */
051        public void setErrorHandler(CacheErrorHandler errorHandler) {
052                this.errorHandler = SingletonSupplier.of(errorHandler);
053        }
054
055        /**
056         * Return the {@link CacheErrorHandler} to use.
057         */
058        public CacheErrorHandler getErrorHandler() {
059                return this.errorHandler.obtain();
060        }
061
062
063        /**
064         * Execute {@link Cache#get(Object)} on the specified {@link Cache} and
065         * invoke the error handler if an exception occurs. Return {@code null}
066         * if the handler does not throw any exception, which simulates a cache
067         * miss in case of error.
068         * @see Cache#get(Object)
069         */
070        @Nullable
071        protected Cache.ValueWrapper doGet(Cache cache, Object key) {
072                try {
073                        return cache.get(key);
074                }
075                catch (RuntimeException ex) {
076                        getErrorHandler().handleCacheGetError(ex, cache, key);
077                        return null;  // If the exception is handled, return a cache miss
078                }
079        }
080
081        /**
082         * Execute {@link Cache#put(Object, Object)} on the specified {@link Cache}
083         * and invoke the error handler if an exception occurs.
084         */
085        protected void doPut(Cache cache, Object key, @Nullable Object result) {
086                try {
087                        cache.put(key, result);
088                }
089                catch (RuntimeException ex) {
090                        getErrorHandler().handleCachePutError(ex, cache, key, result);
091                }
092        }
093
094        /**
095         * Execute {@link Cache#evict(Object)}/{@link Cache#evictIfPresent(Object)} on the
096         * specified {@link Cache} and invoke the error handler if an exception occurs.
097         */
098        protected void doEvict(Cache cache, Object key, boolean immediate) {
099                try {
100                        if (immediate) {
101                                cache.evictIfPresent(key);
102                        }
103                        else {
104                                cache.evict(key);
105                        }
106                }
107                catch (RuntimeException ex) {
108                        getErrorHandler().handleCacheEvictError(ex, cache, key);
109                }
110        }
111
112        /**
113         * Execute {@link Cache#clear()} on the specified {@link Cache} and
114         * invoke the error handler if an exception occurs.
115         */
116        protected void doClear(Cache cache, boolean immediate) {
117                try {
118                        if (immediate) {
119                                cache.invalidate();
120                        }
121                        else {
122                                cache.clear();
123                        }
124                }
125                catch (RuntimeException ex) {
126                        getErrorHandler().handleCacheClearError(ex, cache);
127                }
128        }
129
130}