001 /* 002 * Copyright 2005-2007 The Kuali Foundation 003 * 004 * 005 * Licensed under the Educational Community License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.opensource.org/licenses/ecl2.php 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.kuali.rice.core.resourceloader; 018 019 import java.util.ArrayList; 020 import java.util.List; 021 022 /** 023 * Utility class that binds/unbinds the context ClassLoader of the current Thread 024 * using a ThreadLocal. 025 * This class supports re-entrancy by maintaining a stack of context classloaders. 026 * NOTE: maybe implement stricter checks, by matching some contextual object or original 027 * classloader on bind to the unbind so that they are always matched (within a given context) 028 * 029 * @author Kuali Rice Team (rice.collab@kuali.org) 030 */ 031 public final class ContextClassLoaderBinder { 032 033 /** 034 * Stack of previous context classloaders that should be 035 * restored on unbind 036 */ 037 private static final ThreadLocal<List<ClassLoader>> STACK = new ThreadLocal<List<ClassLoader>>() { 038 protected List<ClassLoader> initialValue() { 039 return new ArrayList<ClassLoader>(5); 040 } 041 }; 042 043 private static List<ClassLoader> getStack() { 044 return STACK.get(); 045 } 046 047 public static void bind(ClassLoader cl) { 048 List<ClassLoader> stack = getStack(); 049 Thread current = Thread.currentThread(); 050 //log.debug("[bind] Switching CCL from " + current.getContextClassLoader() + " to " + cl); 051 // push the current context classloader on the stack 052 stack.add(current.getContextClassLoader()); 053 current.setContextClassLoader(cl); 054 } 055 056 public static void unbind() { 057 List<ClassLoader> stack = getStack(); 058 if (stack.size() == 0) { 059 throw new IllegalStateException("No context classloader to unbind!"); 060 } 061 // pop the last context classloader off the stack 062 ClassLoader lastClassLoader = stack.get(stack.size() - 1); 063 //log.debug("[unbind] Switching CCL from " + Thread.currentThread().getContextClassLoader() + " to " + lastClassLoader); 064 stack.remove(stack.size() - 1); 065 Thread.currentThread().setContextClassLoader(lastClassLoader); 066 } 067 }