/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.portal.kernel.cache.thread.local; import com.liferay.portal.kernel.transaction.NewTransactionLifecycleListener; import com.liferay.portal.kernel.transaction.TransactionAttribute; import com.liferay.portal.kernel.transaction.TransactionLifecycleListener; import com.liferay.portal.kernel.transaction.TransactionStatus; import com.liferay.portal.kernel.util.InitialThreadLocal; import java.io.Serializable; import java.util.HashMap; import java.util.Map; /** * @author Shuyang Zhou */ public class ThreadLocalCacheManager { public static final TransactionLifecycleListener TRANSACTION_LIFECYCLE_LISTENER = new NewTransactionLifecycleListener() { @Override protected void doCommitted( TransactionAttribute transactionAttribute, TransactionStatus transactionStatus) { if (!transactionAttribute.isReadOnly()) { enable(Lifecycle.REQUEST); } } @Override protected void doCreated( TransactionAttribute transactionAttribute, TransactionStatus transactionStatus) { if (!transactionAttribute.isReadOnly()) { disable(Lifecycle.REQUEST); } } @Override protected void doRollbacked( TransactionAttribute transactionAttribute, TransactionStatus transactionStatus, Throwable throwable) { if (!transactionAttribute.isReadOnly()) { enable(Lifecycle.REQUEST); } } }; public static void clearAll(Lifecycle lifecycle) { ThreadLocalCaches threadLocalCaches = _getThreadLocalCaches(lifecycle); if (threadLocalCaches != null) { Map<Object, ThreadLocalCache<?>> threadLocalCacheMaps = threadLocalCaches._threadLocalCacheMap; threadLocalCacheMaps.clear(); } } public static void destroy() { _requestThreadLocalCaches.remove(); _eternalThreadLocalCaches.remove(); } public static void disable(Lifecycle lifecycle) { ThreadLocalCaches threadLocalCaches = _getThreadLocalCaches(lifecycle); if (threadLocalCaches != null) { threadLocalCaches._disabled = true; Map<Object, ThreadLocalCache<?>> threadLocalCacheMaps = threadLocalCaches._threadLocalCacheMap; threadLocalCacheMaps.clear(); } } public static void enable(Lifecycle lifecycle) { ThreadLocalCaches threadLocalCaches = _getThreadLocalCaches(lifecycle); if (threadLocalCaches != null) { threadLocalCaches._disabled = false; } } public static <T> ThreadLocalCache<T> getThreadLocalCache( Lifecycle lifecycle, Object name) { ThreadLocalCaches threadLocalCaches = _getThreadLocalCaches(lifecycle); if ((threadLocalCaches == null) || threadLocalCaches._disabled) { return (ThreadLocalCache<T>)_emptyThreadLocalCache; } Map<Object, ThreadLocalCache<?>> threadLocalCacheMap = threadLocalCaches._threadLocalCacheMap; ThreadLocalCache<?> threadLocalCache = threadLocalCacheMap.get(name); if (threadLocalCache == null) { threadLocalCache = new ThreadLocalCache<>(name, lifecycle); threadLocalCacheMap.put(name, threadLocalCache); } return (ThreadLocalCache<T>)threadLocalCache; } public static <T> ThreadLocalCache<T> getThreadLocalCache( Lifecycle lifecycle, Serializable name) { return getThreadLocalCache(lifecycle, (Object)name); } private static ThreadLocalCaches _getThreadLocalCaches( Lifecycle lifecycle) { if (lifecycle == Lifecycle.REQUEST) { return _requestThreadLocalCaches.get(); } if (lifecycle == Lifecycle.ETERNAL) { return _eternalThreadLocalCaches.get(); } return null; } private static final EmptyThreadLocalCahce<?> _emptyThreadLocalCache = new EmptyThreadLocalCahce<>(); private static final ThreadLocal<ThreadLocalCaches> _eternalThreadLocalCaches = new InitialThreadLocal<ThreadLocalCaches>( ThreadLocalCacheManager.class + "._eternalThreadLocalCaches", () -> null) { @Override protected ThreadLocalCaches initialValue() { return new ThreadLocalCaches(); } }; private static final ThreadLocal<ThreadLocalCaches> _requestThreadLocalCaches = new InitialThreadLocal<ThreadLocalCaches>( ThreadLocalCacheManager.class + "._requestThreadLocalCaches", () -> null) { @Override protected ThreadLocalCaches initialValue() { return new ThreadLocalCaches(); } }; private static class EmptyThreadLocalCahce<T> extends ThreadLocalCache<T> { @Override public T get(String key) { return null; } @Override public void put(String key, T obj) { } @Override public void remove(String key) { } @Override public void removeAll() { } @Override public String toString() { return EmptyThreadLocalCahce.class.getName(); } private EmptyThreadLocalCahce() { super(null, null); } } private static class ThreadLocalCaches { private boolean _disabled; private final Map<Object, ThreadLocalCache<?>> _threadLocalCacheMap = new HashMap<>(); } }