/**
* 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.spring.hibernate;
import com.liferay.portal.kernel.util.CentralizedThreadLocal;
import com.liferay.portal.kernel.util.InitialThreadLocal;
import com.liferay.portal.kernel.util.ReflectionUtil;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;
import org.springframework.core.NamedThreadLocal;
import org.springframework.transaction.support.ResourceHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager;
/**
* @author Shuyang Zhou
*/
public class SpringHibernateThreadLocalUtil {
public static <T> T getResource(Object key) {
Map<Object, Object> resources = _resourcesThreadLocal.get();
if (resources == null) {
return null;
}
Object resource = resources.get(key);
if (resource instanceof ResourceHolder) {
ResourceHolder resourceHolder = (ResourceHolder)resource;
if (resourceHolder.isVoid()) {
resources.remove(key);
if (resources.isEmpty()) {
_resourcesThreadLocal.remove();
}
return null;
}
}
return (T)resource;
}
public static <T> T setResource(Object key, Object resource) {
Map<Object, Object> resources = _resourcesThreadLocal.get();
Object oldResource = null;
if (resource == null) {
if (resources == null) {
return null;
}
oldResource = resources.remove(key);
if (resources.isEmpty()) {
_resourcesThreadLocal.remove();
}
}
else {
if (resources == null) {
resources = new HashMap<>();
_resourcesThreadLocal.set(resources);
}
oldResource = resources.put(key, resource);
}
if (oldResource instanceof ResourceHolder) {
ResourceHolder resourceHolder = (ResourceHolder)oldResource;
if (resourceHolder.isVoid()) {
oldResource = null;
}
}
return (T)oldResource;
}
private static final ThreadLocal<Map<Object, Object>> _resourcesThreadLocal;
static {
try {
Field nameField = ReflectionUtil.getDeclaredField(
NamedThreadLocal.class, "name");
ThreadLocal<?> resourcesThreadLocal = null;
for (Field field : ReflectionUtil.getDeclaredFields(
TransactionSynchronizationManager.class)) {
if (Modifier.isStatic(field.getModifiers()) &&
ThreadLocal.class.isAssignableFrom(field.getType())) {
ThreadLocal<Object> threadLocal =
(ThreadLocal<Object>)field.get(null);
Object value = threadLocal.get();
if (threadLocal instanceof NamedThreadLocal) {
threadLocal = new InitialThreadLocal<>(
(String)nameField.get(threadLocal), () -> null);
}
else {
threadLocal = new CentralizedThreadLocal<>(false);
}
if (value != null) {
threadLocal.set(value);
}
field.set(null, threadLocal);
String name = field.getName();
if (name.equals("resources")) {
resourcesThreadLocal = threadLocal;
}
}
}
if (resourcesThreadLocal == null) {
throw new ExceptionInInitializerError(
"Unable to locate \"resources\" thread local field from " +
TransactionSynchronizationManager.class);
}
_resourcesThreadLocal =
(ThreadLocal<Map<Object, Object>>)resourcesThreadLocal;
}
catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
}