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 =
117                                    new HashMap<Serializable, ThreadLocalCache<?>>();
118    
119                            threadLocalCacheMaps.put(lifecycle, threadLocalCacheMap);
120                    }
121    
122                    ThreadLocalCache<?> threadLocalCache = threadLocalCacheMap.get(name);
123    
124                    if (threadLocalCache == null) {
125                            threadLocalCache = new ThreadLocalCache<T>(name, lifecycle);
126    
127                            threadLocalCacheMap.put(name, threadLocalCache);
128                    }
129    
130                    return (ThreadLocalCache<T>)threadLocalCache;
131            }
132    
133            private static final EmptyThreadLocalCahce<?> _emptyThreadLocalCache =
134                    new EmptyThreadLocalCahce<Object>();
135            private static final ThreadLocal
136                    <Map<Lifecycle, Boolean>>
137                            _threadLocalCacheDisabledFlags = new InitialThreadLocal
138                                    <Map<Lifecycle, Boolean>>(
139                                            ThreadLocalCacheManager.class +
140                                                    "._threadLocalCacheDisabledFlags",
141                                            new EnumMap<Lifecycle, Boolean>(Lifecycle.class));
142            private static final ThreadLocal
143                    <Map<Lifecycle, Map<Serializable, ThreadLocalCache<?>>>>
144                            _threadLocalCacheMaps = new InitialThreadLocal
145                                    <Map<Lifecycle, Map<Serializable, ThreadLocalCache<?>>>>(
146                                            ThreadLocalCacheManager.class + "._threadLocalCacheMaps",
147                                            new EnumMap
148                                                    <Lifecycle, Map<Serializable, ThreadLocalCache<?>>>(
149                                                            Lifecycle.class));
150    
151            private static class EmptyThreadLocalCahce<T> extends ThreadLocalCache<T> {
152    
153                    public EmptyThreadLocalCahce() {
154                            super(null, null);
155                    }
156    
157                    @Override
158                    public T get(String key) {
159                            return null;
160                    }
161    
162                    @Override
163                    public void put(String key, T obj) {
164                    }
165    
166                    @Override
167                    public void remove(String key) {
168                    }
169    
170                    @Override
171                    public void removeAll() {
172                    }
173    
174                    @Override
175                    public String toString() {
176                            return EmptyThreadLocalCahce.class.getName();
177                    }
178    
179            }
180    
181    }