KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > hivemind > lib > util > StrategyRegistryImpl


1 // Copyright 2004, 2005 The Apache Software Foundation
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15 package org.apache.hivemind.lib.util;
16
17 import java.util.HashMap JavaDoc;
18 import java.util.Iterator JavaDoc;
19 import java.util.LinkedList JavaDoc;
20 import java.util.Map JavaDoc;
21 import java.util.WeakHashMap JavaDoc;
22
23 import org.apache.hivemind.service.ClassFabUtils;
24 import org.apache.hivemind.util.Defense;
25
26 /**
27  * Thread-safe implementation of {@link org.apache.hivemind.lib.util.StrategyRegistry}.
28  *
29  * @author Howard Lewis Ship
30  * @since 1.1
31  */

32
33 public class StrategyRegistryImpl implements StrategyRegistry
34 {
35     /**
36      * A Map of adaptor objects, keyed on registration Class.
37      */

38
39     private Map JavaDoc _registrations = new HashMap JavaDoc();
40
41     /**
42      * A Map of adaptor objects, keyed on subject Class.
43      */

44
45     private Map JavaDoc _cache = new WeakHashMap JavaDoc();
46
47     public synchronized void register(Class JavaDoc registrationClass, Object JavaDoc adaptor)
48     {
49         Defense.notNull(registrationClass, "registrationClass");
50         Defense.notNull(adaptor, "adaptor");
51
52         if (_registrations.containsKey(registrationClass))
53             throw new IllegalArgumentException JavaDoc(UtilMessages
54                     .duplicateRegistration(registrationClass));
55
56         _registrations.put(registrationClass, adaptor);
57
58         // Can't tell what is and isn't valid in the cache.
59
// Also, normally all registrations occur before any adaptors
60
// are searched for, so this is not a big deal.
61

62         _cache.clear();
63     }
64
65     public synchronized Object JavaDoc getStrategy(Class JavaDoc subjectClass)
66     {
67         Defense.notNull(subjectClass, "subjectClass");
68
69         Object JavaDoc result = _cache.get(subjectClass);
70
71         if (result != null)
72             return result;
73
74         result = searchForAdaptor(subjectClass);
75
76         // Record the result in the cache
77

78         _cache.put(subjectClass, result);
79
80         return result;
81     }
82
83     /**
84      * Searches the registration Map for a match, based on inheritance.
85      * <p>
86      * Searches class inheritance first, then interfaces (in a rather vague order). Really should
87      * match the order from the JVM spec.
88      * <p>
89      * There's a degenerate case where we may check the same interface more than once:
90      * <ul>
91      * <li>Two interfaces, I1 and I2
92      * <li>Two classes, C1 and C2
93      * <li>I2 extends I1
94      * <li>C2 extends C1
95      * <li>C1 implements I1
96      * <li>C2 implements I2
97      * <li>The search will be: C2, C1, I2, I1, I1
98      * <li>I1 is searched twice, because C1 implements it, and I2 extends it
99      * <li>There are other such cases, but none of them cause infinite loops and most are rare (we
100      * could guard against it, but its relatively expensive).
101      * <li>Multiple checks only occur if we don't find a registration
102      * </ul>
103      * <p>
104      * This method is only called from a synchronized block, so it is implicitly synchronized.
105      */

106
107     private Object JavaDoc searchForAdaptor(Class JavaDoc subjectClass)
108     {
109         LinkedList JavaDoc queue = null;
110         Object JavaDoc result = null;
111
112         // Step one: work up through the class inheritance.
113

114         Class JavaDoc searchClass = subjectClass;
115
116         // Primitive types have null, not Object, as their parent
117
// class.
118

119         while (searchClass != Object JavaDoc.class && searchClass != null)
120         {
121             result = _registrations.get(searchClass);
122             if (result != null)
123                 return result;
124
125             // Not an exact match. If the search class
126
// implements any interfaces, add them to the queue.
127

128             Class JavaDoc[] interfaces = searchClass.getInterfaces();
129             int length = interfaces.length;
130
131             if (queue == null && length > 0)
132                 queue = new LinkedList JavaDoc();
133
134             for (int i = 0; i < length; i++)
135                 queue.addLast(interfaces[i]);
136
137             // Advance up to the next superclass
138

139             searchClass = getSuperclass(searchClass);
140
141         }
142
143         // Ok, the easy part failed, lets start searching
144
// interfaces.
145

146         if (queue != null)
147         {
148             while (!queue.isEmpty())
149             {
150                 searchClass = (Class JavaDoc) queue.removeFirst();
151
152                 result = _registrations.get(searchClass);
153                 if (result != null)
154                     return result;
155
156                 // Interfaces can extend other interfaces; add them
157
// to the queue.
158

159                 Class JavaDoc[] interfaces = searchClass.getInterfaces();
160                 int length = interfaces.length;
161
162                 for (int i = 0; i < length; i++)
163                     queue.addLast(interfaces[i]);
164             }
165         }
166
167         // Not a match on interface; our last gasp is to check
168
// for a registration for java.lang.Object
169

170         result = _registrations.get(Object JavaDoc.class);
171         if (result != null)
172             return result;
173
174         // No match? That's rare ... and an error.
175

176         throw new IllegalArgumentException JavaDoc(UtilMessages.strategyNotFound(subjectClass));
177     }
178
179     /**
180      * Returns the superclass of the given class, with a single tweak: If the search class is an
181      * array class, and the component type is an object class (but not Object), then the simple
182      * Object array class is returned. This reflects the fact that an array of any class may be
183      * assignable to <code>Object[]</code>, even though the superclass of an array is always
184      * simply <code>Object</code>.
185      */

186
187     private Class JavaDoc getSuperclass(Class JavaDoc searchClass)
188     {
189         if (searchClass.isArray())
190         {
191             Class JavaDoc componentType = searchClass.getComponentType();
192
193             if (!componentType.isPrimitive() && componentType != Object JavaDoc.class)
194                 return Object JavaDoc[].class;
195         }
196
197         return searchClass.getSuperclass();
198     }
199
200     public synchronized String JavaDoc toString()
201     {
202         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
203         buffer.append("AdaptorRegistry[");
204
205         Iterator JavaDoc i = _registrations.entrySet().iterator();
206         boolean showSep = false;
207
208         while (i.hasNext())
209         {
210             if (showSep)
211                 buffer.append(' ');
212
213             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) i.next();
214
215             Class JavaDoc registeredClass = (Class JavaDoc) entry.getKey();
216
217             buffer.append(ClassFabUtils.getJavaClassName(registeredClass));
218             buffer.append("=");
219             buffer.append(entry.getValue());
220
221             showSep = true;
222         }
223
224         buffer.append("]");
225
226         return buffer.toString();
227     }
228 }
Popular Tags