All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.shiro.util.ThreadContext Maven / Gradle / Ivy

There is a newer version: 3.9
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.shiro.util;

import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;


/**
 * A ThreadContext provides a means of binding and unbinding objects to the
 * current thread based on key/value pairs.
 * 

*

An internal {@link java.util.HashMap} is used to maintain the key/value pairs * for each thread.

*

*

If the desired behavior is to ensure that bound data is not shared across * threads in a pooled or reusable threaded environment, the application (or more likely a framework) must * bind and remove any necessary values at the beginning and end of stack * execution, respectively (i.e. individually explicitly or all via the clear method).

* * @see #remove() * @since 0.1 */ public abstract class ThreadContext { /** * Private internal log instance. */ private static final Logger log = LoggerFactory.getLogger(ThreadContext.class); public static final String SECURITY_MANAGER_KEY = ThreadContext.class.getName() + "_SECURITY_MANAGER_KEY"; public static final String SUBJECT_KEY = ThreadContext.class.getName() + "_SUBJECT_KEY"; private static final ThreadLocal> resources = new InheritableThreadLocalMap>(); /** * Default no-argument constructor. */ protected ThreadContext() { } /** * Returns the ThreadLocal Map. This Map is used internally to bind objects * to the current thread by storing each object under a unique key. * * @return the map of bound resources */ public static Map getResources() { return resources != null ? new HashMap(resources.get()) : null; } /** * Allows a caller to explicitly set the entire resource map. This operation overwrites everything that existed * previously in the ThreadContext - if you need to retain what was on the thread prior to calling this method, * call the {@link #getResources()} method, which will give you the existing state. * * @param newResources the resources to replace the existing {@link #getResources() resources}. * @since 1.0 */ public static void setResources(Map newResources) { if (CollectionUtils.isEmpty(newResources)) { return; } resources.get().clear(); resources.get().putAll(newResources); } /** * Returns the value bound in the {@code ThreadContext} under the specified {@code key}, or {@code null} if there * is no value for that {@code key}. * * @param key the map key to use to lookup the value * @return the value bound in the {@code ThreadContext} under the specified {@code key}, or {@code null} if there * is no value for that {@code key}. * @since 1.0 */ private static Object getValue(Object key) { return resources.get().get(key); } /** * Returns the object for the specified key that is bound to * the current thread. * * @param key the key that identifies the value to return * @return the object keyed by key or null if * no value exists for the specified key */ public static Object get(Object key) { if (log.isTraceEnabled()) { String msg = "get() - in thread [" + Thread.currentThread().getName() + "]"; log.trace(msg); } Object value = getValue(key); if ((value != null) && log.isTraceEnabled()) { String msg = "Retrieved value of type [" + value.getClass().getName() + "] for key [" + key + "] " + "bound to thread [" + Thread.currentThread().getName() + "]"; log.trace(msg); } return value; } /** * Binds value for the given key to the current thread. *

*

A null value has the same effect as if remove was called for the given * key, i.e.: *

*

     * if ( value == null ) {
     *     remove( key );
     * }
* * @param key The key with which to identify the value. * @param value The value to bind to the thread. * @throws IllegalArgumentException if the key argument is null. */ public static void put(Object key, Object value) { if (key == null) { throw new IllegalArgumentException("key cannot be null"); } if (value == null) { remove(key); return; } resources.get().put(key, value); if (log.isTraceEnabled()) { String msg = "Bound value of type [" + value.getClass().getName() + "] for key [" + key + "] to thread " + "[" + Thread.currentThread().getName() + "]"; log.trace(msg); } } /** * Unbinds the value for the given key from the current * thread. * * @param key The key identifying the value bound to the current thread. * @return the object unbound or null if there was nothing bound * under the specified key name. */ public static Object remove(Object key) { Object value = resources.get().remove(key); if ((value != null) && log.isTraceEnabled()) { String msg = "Removed value of type [" + value.getClass().getName() + "] for key [" + key + "]" + "from thread [" + Thread.currentThread().getName() + "]"; log.trace(msg); } return value; } /** * {@link ThreadLocal#remove Remove}s the underlying {@link ThreadLocal ThreadLocal} from the thread. *

* This method is meant to be the final 'clean up' operation that is called at the end of thread execution to * prevent thread corruption in pooled thread environments. * * @since 1.0 */ public static void remove() { resources.remove(); } /** * Convenience method that simplifies retrieval of the application's SecurityManager instance from the current * thread. If there is no SecurityManager bound to the thread (probably because framework code did not bind it * to the thread), this method returns null. *

* It is merely a convenient wrapper for the following: *

* return (SecurityManager)get( SECURITY_MANAGER_KEY ); *

* This method only returns the bound value if it exists - it does not remove it * from the thread. To remove it, one must call {@link #unbindSecurityManager() unbindSecurityManager()} instead. * * @return the Subject object bound to the thread, or null if there isn't one bound. * @since 0.9 */ public static SecurityManager getSecurityManager() { return (SecurityManager) get(SECURITY_MANAGER_KEY); } /** * Convenience method that simplifies binding the application's SecurityManager instance to the ThreadContext. *

*

The method's existence is to help reduce casting in code and to simplify remembering of * ThreadContext key names. The implementation is simple in that, if the SecurityManager is not null, * it binds it to the thread, i.e.: *

*

     * if (securityManager != null) {
     *     put( SECURITY_MANAGER_KEY, securityManager);
     * }
* * @param securityManager the application's SecurityManager instance to bind to the thread. If the argument is * null, nothing will be done. * @since 0.9 */ public static void bind(SecurityManager securityManager) { if (securityManager != null) { put(SECURITY_MANAGER_KEY, securityManager); } } /** * Convenience method that simplifies removal of the application's SecurityManager instance from the thread. *

* The implementation just helps reduce casting and remembering of the ThreadContext key name, i.e it is * merely a conveient wrapper for the following: *

* return (SecurityManager)remove( SECURITY_MANAGER_KEY ); *

* If you wish to just retrieve the object from the thread without removing it (so it can be retrieved later * during thread execution), use the {@link #getSecurityManager() getSecurityManager()} method instead. * * @return the application's SecurityManager instance previously bound to the thread, or null if there * was none bound. * @since 0.9 */ public static SecurityManager unbindSecurityManager() { return (SecurityManager) remove(SECURITY_MANAGER_KEY); } /** * Convenience method that simplifies retrieval of a thread-bound Subject. If there is no * Subject bound to the thread, this method returns null. It is merely a convenient wrapper * for the following: *

* return (Subject)get( SUBJECT_KEY ); *

* This method only returns the bound value if it exists - it does not remove it * from the thread. To remove it, one must call {@link #unbindSubject() unbindSubject()} instead. * * @return the Subject object bound to the thread, or null if there isn't one bound. * @since 0.2 */ public static Subject getSubject() { return (Subject) get(SUBJECT_KEY); } /** * Convenience method that simplifies binding a Subject to the ThreadContext. *

*

The method's existence is to help reduce casting in your own code and to simplify remembering of * ThreadContext key names. The implementation is simple in that, if the Subject is not null, * it binds it to the thread, i.e.: *

*

     * if (subject != null) {
     *     put( SUBJECT_KEY, subject );
     * }
* * @param subject the Subject object to bind to the thread. If the argument is null, nothing will be done. * @since 0.2 */ public static void bind(Subject subject) { if (subject != null) { put(SUBJECT_KEY, subject); } } /** * Convenience method that simplifies removal of a thread-local Subject from the thread. *

* The implementation just helps reduce casting and remembering of the ThreadContext key name, i.e it is * merely a conveient wrapper for the following: *

* return (Subject)remove( SUBJECT_KEY ); *

* If you wish to just retrieve the object from the thread without removing it (so it can be retrieved later during * thread execution), you should use the {@link #getSubject() getSubject()} method for that purpose. * * @return the Subject object previously bound to the thread, or null if there was none bound. * @since 0.2 */ public static Subject unbindSubject() { return (Subject) remove(SUBJECT_KEY); } private static final class InheritableThreadLocalMap> extends InheritableThreadLocal> { protected Map initialValue() { return new HashMap(); } /** * This implementation was added to address a * * user-reported issue. * @param parentValue the parent value, a HashMap as defined in the {@link #initialValue()} method. * @return the HashMap to be used by any parent-spawned child threads (a clone of the parent HashMap). */ @SuppressWarnings({"unchecked"}) protected Map childValue(Map parentValue) { if (parentValue != null) { return (Map) ((HashMap) parentValue).clone(); } else { return null; } } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy