Open Source Repository

Home /jodd/jodd-3.3.2 | Repository Home



jodd/util/ClassLoaderLocal.java
// Copyright (c) 2003-2012, Jodd Team (jodd.org). All Rights Reserved.

package jodd.util;

import java.util.Map;
import java.util.WeakHashMap;

/**
 * This class provides classloader-local variables.
 <p>
 * It is designed to look very much like <code>ThreadLocal</code>.
 */
public class ClassLoaderLocal<T> {

  private final Map<ClassLoader, T> weakMap = new WeakHashMap<ClassLoader, T>();
  private T value;
  private boolean initialized;

  /**
   * Returns the current classloader "initial value" for this classloader-local variable.
   * This method will be invoked the first time it is accessed the get() method, unless
   * the thread previously invoked the set(T) method, in which case the initialValue method
   * will not be invoked for the classloader. Normally, this method is invoked at most once
   * per classloader, but it may be invoked again in case of subsequent invocations of remove()
   * followed by get().
   <p>
   * This implementation simply returns null; if the programmer desires classloader-local variables to
   * have an initial value other than null, ClassLoaderLocal must be subclassed, and this method overridden.
   * Typically, an anonymous inner class will be used.
   */
  protected T initialValue() {
    return null;
  }

  /**
   * Returns the value in the current classloader copy of this variable.
   * If the variable has no value for the current classloader, it is first initialized to the value returned
   * by an invocation of the initialValue() method.
   */
  public synchronized T get() {
    ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();

    if (contextClassLoader != null) {
      T value = weakMap.get(contextClassLoader);

      if ((value == null&& !weakMap.containsKey(contextClassLoader)) {
        value = initialValue();
        weakMap.put(contextClassLoader, value);
      }

      return value;
    }

    if (initialized == false) {
      value = initialValue();
      initialized = true;
    }

    return value;
  }

  /**
   * Sets the current classloaders's copy of this variable to the specified value.
   * Most subclasses will have no need to override this method, relying solely on the initialValue()
   * method to set the values of classloader-locals.
   */
  public synchronized void set(T value) {

    ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();

    if (contextClassLoader != null) {
      weakMap.put(contextClassLoader, value);
      return;
    }

    this.value = value;
    this.initialized = true;
  }

  /**
   * Removes the current classloader's value for this variable.
   */
  public synchronized void remove() {
    ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
    weakMap.remove(contextClassLoader);
  }

}