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 }