001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.kernel.cache;
016    
017    import com.liferay.portal.kernel.transaction.TransactionAttribute;
018    import com.liferay.portal.kernel.transaction.TransactionLifecycleListener;
019    import com.liferay.portal.kernel.transaction.TransactionStatus;
020    import com.liferay.portal.kernel.util.InitialThreadLocal;
021    
022    import java.io.Serializable;
023    
024    import java.util.EnumMap;
025    import java.util.HashMap;
026    import java.util.Map;
027    
028    /**
029     * @author Shuyang Zhou
030     */
031    public class ThreadLocalCacheManager {
032    
033            public static final TransactionLifecycleListener
034                    TRANSACTION_LIFECYCLE_LISTENER = new TransactionLifecycleListener() {
035    
036                    @Override
037                    public void committed(
038                            TransactionAttribute transactionAttribute,
039                            TransactionStatus transactionStatus) {
040    
041                            if (!transactionAttribute.isReadOnly()) {
042                                    enable(Lifecycle.REQUEST);
043                            }
044                    }
045    
046                    @Override
047                    public void created(
048                            TransactionAttribute transactionAttribute,
049                            TransactionStatus transactionStatus) {
050    
051                            if (!transactionAttribute.isReadOnly()) {
052                                    disable(Lifecycle.REQUEST);
053                            }
054                    }
055    
056                    @Override
057                    public void rollbacked(
058                            TransactionAttribute transactionAttribute,
059                            TransactionStatus transactionStatus, Throwable throwable) {
060    
061                            if (!transactionAttribute.isReadOnly()) {
062                                    enable(Lifecycle.REQUEST);
063                            }
064                    }
065            };
066    
067            public static void clearAll(Lifecycle lifecycle) {
068                    Map<Lifecycle, Map<Serializable, ThreadLocalCache<?>>>
069                            threadLocalCacheMaps = _threadLocalCacheMaps.get();
070    
071                    Map<Serializable, ThreadLocalCache<?>> threadLocalCacheMap =
072                            threadLocalCacheMaps.get(lifecycle);
073    
074                    if (threadLocalCacheMap != null) {
075                            threadLocalCacheMap.clear();
076                    }
077            }
078    
079            public static void destroy() {
080                    _threadLocalCacheMaps.remove();
081            }
082    
083            public static void disable(Lifecycle lifecycle) {
084                    Map<Lifecycle, Boolean> threadLocalCacheDisabledFlags =
085                            _threadLocalCacheDisabledFlags.get();
086    
087                    threadLocalCacheDisabledFlags.put(lifecycle, Boolean.TRUE);
088    
089                    clearAll(lifecycle);
090            }
091    
092            public static void enable(Lifecycle lifecycle) {
093                    Map<Lifecycle, Boolean> threadLocalCacheDisabledFlags =
094                            _threadLocalCacheDisabledFlags.get();
095    
096                    threadLocalCacheDisabledFlags.remove(lifecycle);
097            }
098    
099            public static <T> ThreadLocalCache<T> getThreadLocalCache(
100                    Lifecycle lifecycle, Serializable name) {
101    
102                    Map<Lifecycle, Boolean> threadLocalCacheDisabledFlags =
103                            _threadLocalCacheDisabledFlags.get();
104    
105                    if (threadLocalCacheDisabledFlags.get(lifecycle) == Boolean.TRUE) {
106                            return (ThreadLocalCache<T>)_emptyThreadLocalCache;
107                    }
108    
109                    Map<Lifecycle, Map<Serializable, ThreadLocalCache<?>>>
110                            threadLocalCacheMaps = _threadLocalCacheMaps.get();
111    
112                    Map<Serializable, ThreadLocalCache<?>> threadLocalCacheMap =
113                            threadLocalCacheMaps.get(lifecycle);
114    
115                    if (threadLocalCacheMap == null) {
116                            threadLocalCacheMap = new HashMap<>();
117    
118                            threadLocalCacheMaps.put(lifecycle, threadLocalCacheMap);
119                    }
120    
121                    ThreadLocalCache<?> threadLocalCache = threadLocalCacheMap.get(name);
122    
123                    if (threadLocalCache == null) {
124                            threadLocalCache = new ThreadLocalCache<>(name, lifecycle);
125    
126                            threadLocalCacheMap.put(name, threadLocalCache);
127                    }
128    
129                    return (ThreadLocalCache<T>)threadLocalCache;
130            }
131    
132            private static final EmptyThreadLocalCahce<?> _emptyThreadLocalCache =
133                    new EmptyThreadLocalCahce<>();
134            private static final ThreadLocal
135                    <Map<Lifecycle, Boolean>>
136                            _threadLocalCacheDisabledFlags = new InitialThreadLocal
137                                    <Map<Lifecycle, Boolean>>(
138                                            ThreadLocalCacheManager.class +
139                                                    "._threadLocalCacheDisabledFlags",
140                                            new EnumMap<Lifecycle, Boolean>(Lifecycle.class));
141            private static final ThreadLocal
142                    <Map<Lifecycle, Map<Serializable, ThreadLocalCache<?>>>>
143                            _threadLocalCacheMaps = new InitialThreadLocal
144                                    <Map<Lifecycle, Map<Serializable, ThreadLocalCache<?>>>>(
145                                            ThreadLocalCacheManager.class + "._threadLocalCacheMaps",
146                                            new EnumMap
147                                                    <Lifecycle, Map<Serializable, ThreadLocalCache<?>>>(
148                                                            Lifecycle.class));
149    
150            private static class EmptyThreadLocalCahce<T> extends ThreadLocalCache<T> {
151    
152                    public EmptyThreadLocalCahce() {
153                            super(null, null);
154                    }
155    
156                    @Override
157                    public T get(String key) {
158                            return null;
159                    }
160    
161                    @Override
162                    public void put(String key, T obj) {
163                    }
164    
165                    @Override
166                    public void remove(String key) {
167                    }
168    
169                    @Override
170                    public void removeAll() {
171                    }
172    
173                    @Override
174                    public String toString() {
175                            return EmptyThreadLocalCahce.class.getName();
176                    }
177    
178            }
179    
180    }