View Javadoc
1   /**
2    * Copyright 2005-2014 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.core.api.util;
17  
18  import java.util.ArrayList;
19  import java.util.List;
20  import java.util.concurrent.Callable;
21  
22  /**
23   * Utility class that binds/unbinds the context ClassLoader of the current Thread
24   * using a ThreadLocal.
25   * NOTE: {@link #doInContextClassLoader(ClassLoader, java.util.concurrent.Callable)} is the only safe way to use this class,
26   * do not use deprecated {@link #bind(ClassLoader)} or {@link #unbind()} methods.
27   * 
28   * @author Kuali Rice Team (rice.collab@kuali.org)
29   */
30  public final class ContextClassLoaderBinder {
31  	
32  	/**
33       * Stack of previous context classloaders that should be
34       * restored on unbind
35       * @deprecated since 2.1, use #doInContextClassLoader. storing references to classloaders is an incredibly bad idea!
36       */
37      private static final ThreadLocal<List<ClassLoader>> STACK = new ThreadLocal<List<ClassLoader>>() {
38          protected List<ClassLoader> initialValue() {
39              return new ArrayList<ClassLoader>(5);
40          }
41      };
42  
43      /**
44       * @deprecated use #doInContextClassLoader
45       */
46      private static List<ClassLoader> getStack() {
47          return STACK.get();
48      }
49  
50      /**
51       * @deprecated use #doInContextClassLoader
52       */
53      public static void bind(ClassLoader cl) {
54          List<ClassLoader> stack = getStack();
55          Thread current = Thread.currentThread();
56          //log.debug("[bind] Switching CCL from " + current.getContextClassLoader() + " to " + cl);
57          // push the current context classloader on the stack
58          stack.add(current.getContextClassLoader());
59          current.setContextClassLoader(cl);
60      }
61  
62      /**
63       * @deprecated use #doInContextClassLoader
64       */
65      public static void unbind() {
66          List<ClassLoader> stack = getStack();
67          if (stack.size() == 0) {
68              throw new IllegalStateException("No context classloader to unbind!");
69          }
70          // pop the last context classloader off the stack
71          ClassLoader lastClassLoader = stack.get(stack.size() - 1);
72          //log.debug("[unbind] Switching CCL from " + Thread.currentThread().getContextClassLoader() + " to " + lastClassLoader);
73          stack.remove(stack.size() - 1);
74          Thread.currentThread().setContextClassLoader(lastClassLoader);
75      }
76  
77      /**
78       * Execute a runnable under a given context classloader
79       * @param cl the classloader to set as the thread context classloader
80       * @param callable the callable
81       */
82      public static <T> T doInContextClassLoader(ClassLoader cl, Callable<T> callable) throws Exception {
83          Thread current = Thread.currentThread();
84          ClassLoader prev = current.getContextClassLoader();
85          try {
86              current.setContextClassLoader(cl);
87              return callable.call();
88          } finally {
89              current.setContextClassLoader(prev);
90          }
91      }
92  }