001 package org.apache.ojb.broker.core;
002
003 /* Copyright 2003-2005 The Apache Software Foundation
004 *
005 * Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
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
018 import java.util.Collection;
019 import java.util.HashMap;
020 import java.util.HashSet;
021 import java.util.Iterator;
022 import java.util.WeakHashMap;
023
024 import org.apache.ojb.broker.PBFactoryException;
025 import org.apache.ojb.broker.PBKey;
026 import org.apache.ojb.broker.PersistenceBrokerException;
027 import org.apache.ojb.broker.PersistenceBrokerInternal;
028
029 /**
030 * Helper class that tracks correspondence between PersistenceBroker instances
031 * and threads. The main task that this class solves is: to get current
032 * PersistenceBroker for the given thread. For internal use only.
033 *
034 * @author Oleg Nitz
035 * @version $Id: PersistenceBrokerThreadMapping.java,v 1.1 2007-08-24 22:17:35 ewestfal Exp $
036 */
037 public class PersistenceBrokerThreadMapping
038 {
039 /**
040 * A Collection of all HashMaps added to the <CODE>ThreadLocal currentBrokerMap</CODE> that are still -alive-.
041 * If all the PersistenceBrokers are always correctly closed, the Collection should remain empty.
042 * The Collection is iterated trough when calling the <CODE>shutdown()</CODE> method and all the maps that are
043 * still alive will be cleared.
044 */
045 private static Collection loadedHMs = new HashSet();
046
047 /**
048 * The hashmap that maps PBKeys to current brokers for the thread
049 */
050 private static ThreadLocal currentBrokerMap = new ThreadLocal();
051
052 /**
053 * Mark a PersistenceBroker as preferred choice for current Thread
054 *
055 * @param key The PBKey the broker is associated to
056 * @param broker The PersistenceBroker to mark as current
057 */
058 public static void setCurrentPersistenceBroker(PBKey key, PersistenceBrokerInternal broker)
059 throws PBFactoryException
060 {
061 HashMap map = (HashMap) currentBrokerMap.get();
062 WeakHashMap set = null;
063 if(map == null)
064 {
065 map = new HashMap();
066 currentBrokerMap.set(map);
067
068 loadedHMs.add(map);
069 }
070 else
071 {
072 set = (WeakHashMap) map.get(key);
073 }
074
075 if(set == null)
076 {
077 // We emulate weak HashSet using WeakHashMap
078 set = new WeakHashMap();
079 map.put(key, set);
080 }
081 set.put(broker, null);
082 }
083
084 /**
085 * Unmark a PersistenceBroker as preferred choice for current Thread
086 *
087 * @param key The PBKey the broker is associated to
088 * @param broker The PersistenceBroker to unmark
089 */
090 public static void unsetCurrentPersistenceBroker(PBKey key, PersistenceBrokerInternal broker)
091 throws PBFactoryException
092 {
093 HashMap map = (HashMap) currentBrokerMap.get();
094 WeakHashMap set = null;
095 if(map != null)
096 {
097 set = (WeakHashMap) map.get(key);
098 if(set != null)
099 {
100 set.remove(broker);
101 if(set.isEmpty())
102 {
103 map.remove(key);
104 }
105 }
106 if(map.isEmpty())
107 {
108 currentBrokerMap.set(null);
109 loadedHMs.remove(map);
110 }
111 }
112 }
113
114 /**
115 * Return the current open {@link org.apache.ojb.broker.PersistenceBroker}
116 * instance for the given {@link org.apache.ojb.broker.PBKey}, if any.
117 *
118 * @param key
119 * @return null if no open {@link org.apache.ojb.broker.PersistenceBroker} found.
120 */
121 public static PersistenceBrokerInternal currentPersistenceBroker(PBKey key)
122 throws PBFactoryException, PersistenceBrokerException
123 {
124 HashMap map = (HashMap) currentBrokerMap.get();
125 WeakHashMap set;
126 PersistenceBrokerInternal broker = null;
127
128 if(map == null)
129 {
130 return null;
131 }
132
133 set = (WeakHashMap) map.get(key);
134 if(set == null)
135 {
136 return null;
137 }
138
139 // seek for an open broker, preferably in transaction
140 for(Iterator it = set.keySet().iterator(); it.hasNext();)
141 {
142 PersistenceBrokerInternal tmp = (PersistenceBrokerInternal) it.next();
143 if(tmp == null || tmp.isClosed())
144 {
145 it.remove();
146 continue;
147 }
148 broker = tmp;
149 if(tmp.isInTransaction())
150 {
151 break; // the best choice found
152 }
153 }
154 return broker;
155 }
156
157 /**
158 * Clean up static fields and any registered ThreadLocal contents to grant a clean
159 * shutdown/reload of OJB within re/hot-deployable applications.
160 */
161 public static void shutdown()
162 {
163 for(Iterator it = loadedHMs.iterator(); it.hasNext();)
164 {
165 ((HashMap) it.next()).clear();
166 }
167 loadedHMs.clear();
168 loadedHMs = null;
169 currentBrokerMap = null;
170 }
171 }