/**
* 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<>();
}
}