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.spring.hibernate;
016    
017    import com.liferay.portal.kernel.util.CentralizedThreadLocal;
018    import com.liferay.portal.kernel.util.InitialThreadLocal;
019    import com.liferay.portal.kernel.util.ReflectionUtil;
020    
021    import java.lang.reflect.Field;
022    import java.lang.reflect.Modifier;
023    
024    import java.util.HashMap;
025    import java.util.Map;
026    
027    import org.springframework.core.NamedThreadLocal;
028    import org.springframework.transaction.support.ResourceHolder;
029    import org.springframework.transaction.support.TransactionSynchronizationManager;
030    
031    /**
032     * @author Shuyang Zhou
033     */
034    public class SpringHibernateThreadLocalUtil {
035    
036            public static <T> T getResource(Object key) {
037                    Map<Object, Object> resources = _resourcesThreadLocal.get();
038    
039                    if (resources == null) {
040                            return null;
041                    }
042    
043                    Object resource = resources.get(key);
044    
045                    if (resource instanceof ResourceHolder) {
046                            ResourceHolder resourceHolder = (ResourceHolder)resource;
047    
048                            if (resourceHolder.isVoid()) {
049                                    resources.remove(key);
050    
051                                    if (resources.isEmpty()) {
052                                            _resourcesThreadLocal.remove();
053                                    }
054    
055                                    return null;
056                            }
057                    }
058    
059                    return (T)resource;
060            }
061    
062            public static <T> T setResource(Object key, Object resource) {
063                    Map<Object, Object> resources = _resourcesThreadLocal.get();
064    
065                    Object oldResource = null;
066    
067                    if (resource == null) {
068                            if (resources == null) {
069                                    return null;
070                            }
071    
072                            oldResource = resources.remove(key);
073    
074                            if (resources.isEmpty()) {
075                                    _resourcesThreadLocal.remove();
076                            }
077                    }
078                    else {
079                            if (resources == null) {
080                                    resources = new HashMap<Object, Object>();
081    
082                                    _resourcesThreadLocal.set(resources);
083                            }
084    
085                            oldResource = resources.put(key, resource);
086                    }
087    
088                    if (oldResource instanceof ResourceHolder) {
089                            ResourceHolder resourceHolder = (ResourceHolder)oldResource;
090    
091                            if (resourceHolder.isVoid()) {
092                                    oldResource = null;
093                            }
094                    }
095    
096                    return (T)oldResource;
097            }
098    
099            private static final ThreadLocal<Map<Object, Object>> _resourcesThreadLocal;
100    
101            static {
102                    try {
103                            Field nameField = ReflectionUtil.getDeclaredField(
104                                    NamedThreadLocal.class, "name");
105    
106                            ThreadLocal<?> resourcesThreadLocal = null;
107    
108                            for (Field field : ReflectionUtil.getDeclaredFields(
109                                            TransactionSynchronizationManager.class)) {
110    
111                                    if (Modifier.isStatic(field.getModifiers()) &&
112                                            ThreadLocal.class.isAssignableFrom(field.getType())) {
113    
114                                            ThreadLocal<Object> threadLocal =
115                                                    (ThreadLocal<Object>)field.get(null);
116    
117                                            Object value = threadLocal.get();
118    
119                                            if (threadLocal instanceof NamedThreadLocal) {
120                                                    threadLocal = new InitialThreadLocal<Object>(
121                                                            (String)nameField.get(threadLocal), null);
122                                            }
123                                            else {
124                                                    threadLocal = new CentralizedThreadLocal<Object>(false);
125                                            }
126    
127                                            if (value != null) {
128                                                    threadLocal.set(value);
129                                            }
130    
131                                            field.set(null, threadLocal);
132    
133                                            String name = field.getName();
134    
135                                            if (name.equals("resources")) {
136                                                    resourcesThreadLocal = threadLocal;
137                                            }
138                                    }
139                            }
140    
141                            if (resourcesThreadLocal == null) {
142                                    throw new ExceptionInInitializerError(
143                                            "Unable to locate \"resources\" thread local field from " +
144                                                    TransactionSynchronizationManager.class);
145                            }
146    
147                            _resourcesThreadLocal =
148                                    (ThreadLocal<Map<Object, Object>>)resourcesThreadLocal;
149                    }
150                    catch (Exception e) {
151                            throw new ExceptionInInitializerError(e);
152                    }
153            }
154    
155    }