/********************************************************************************** * $URL: https://source.sakaiproject.org/svn/kernel/trunk/kernel-impl/src/main/java/org/sakaiproject/thread_local/impl/ThreadLocalComponent.java $ * $Id: ThreadLocalComponent.java 105077 2012-02-24 22:54:29Z ottenhoff@longsight.com $ *********************************************************************************** * * Copyright (c) 2005, 2006, 2007, 2008 Sakai Foundation * * Licensed under the Educational Community 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.opensource.org/licenses/ECL-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.sakaiproject.thread_local.impl; import java.util.HashMap; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.sakaiproject.thread_local.api.ThreadBound; import org.sakaiproject.thread_local.api.ThreadLocalManager; /** * <p> * ThreadLocalComponent provides the standard implementation of the Sakai Framework ThreadLocalManager. * </p> * <p> * See the {@link org.sakaiproject.api.kernel.thread_local.ThreadLocalManager}interface for details. * </p> */ public class ThreadLocalComponent implements ThreadLocalManager { /** Our log (commons). */ private static Log M_log = LogFactory.getLog(ThreadLocalComponent.class); /** * <p> * ThreadBindings is a thread local map of keys to objects, holding the things bound to each thread. * </p> */ protected class ThreadBindings extends ThreadLocal { public Object initialValue() { return new HashMap(); } public Map getBindings() { return (Map) get(); } } /** The bindings for each thread. */ protected ThreadBindings m_bindings = new ThreadBindings(); /********************************************************************************************************************************************************************************************************************************************************** * Dependencies and their setter methods *********************************************************************************************************************************************************************************************************************************************************/ /********************************************************************************************************************************************************************************************************************************************************** * Init and Destroy *********************************************************************************************************************************************************************************************************************************************************/ /** * Final initialization, once all dependencies are set. */ public void init() { M_log.info("init()"); } /** * Final cleanup. */ public void destroy() { M_log.info("destroy()"); } /********************************************************************************************************************************************************************************************************************************************************** * Work interface methods: org.sakaiproject.api.kernel.thread_local.ThreadLocalManager *********************************************************************************************************************************************************************************************************************************************************/ /** * {@inheritDoc} */ public void set(String name, Object value) { // find the map that might already exist Map bindings = m_bindings.getBindings(); if (bindings == null) { M_log.warn("setInThread: no bindings!"); return; } Object existing = bindings.get(name); if (existing instanceof ThreadBound) { if (!existing.equals(value)) { unbind((ThreadBound) existing); } } // remove if nulling if (value == null) { bindings.remove(name); } // otherwise bind the object else { bindings.put(name, value); } } /** * @param bound */ private void unbind(ThreadBound bound) { try { bound.unbind(); M_log.debug("Unbound from ThreadLocal " + bound); } catch (Exception t) { M_log.error("Failed to unbind Object " + bound, t); } } /** * {@inheritDoc} */ public void clear() { Map bindings = m_bindings.getBindings(); if (bindings == null) { M_log.warn("clear: no bindings!"); return; } // unbind all objects that need it Object[] oa = bindings.values().toArray(); // make the code re-entrant for ( Object o : oa ) { if ( o instanceof ThreadBound ) { unbind((ThreadBound)o); } } // clear the bindings map associated with this thread bindings.clear(); } /** * {@inheritDoc} */ public Object get(String name) { Map bindings = m_bindings.getBindings(); if (bindings == null) { M_log.warn("get: no bindings!"); return null; } return bindings.get(name); } }