1 /*
2 * Copyright 1999-2001,2004 The Apache Software Foundation.
3 *
4 * Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
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
17 package org.apache.commons.workflow.base;
18
19
20 import java.util.Collection;
21 import java.util.HashMap;
22 import java.util.Iterator;
23 import java.util.Map;
24 import java.util.Set;
25 import org.apache.commons.jxpath.JXPathIntrospector;
26 import org.apache.commons.jxpath.MapDynamicPropertyHandler;
27 import org.apache.commons.workflow.Scope;
28 import org.apache.commons.workflow.ScopeListener;
29 import org.apache.commons.workflow.util.ScopeSupport;
30
31
32 /**
33 * <strong>BaseScope</strong> is a basic <code>Scope</code> implementation
34 * that maintains its bean collection in an in-memory HashMap. This can
35 * also serve as a convenient base class for more sophisticated
36 * <code>Scope</code> implementations.
37 *
38 * <p><strong>WARNING</strong> - No synchronization is performed within this
39 * class. If it is used in a multiple thread environment, callers must
40 * take suitable precations.</p>
41 *
42 * @version $Revision: 155475 $ $Date: 2005-02-26 13:31:11 +0000 (Sat, 26 Feb 2005) $
43 * @author Craig R. McClanahan
44 */
45
46 public class BaseScope implements Scope {
47
48
49 // -------------------------------------------------- Static Initialization
50
51
52 /**
53 * Register ourselves with JXPathIntrospector as an instance of a
54 * dynamic class (in JXPath terminology).
55 */
56 static {
57 JXPathIntrospector.registerDynamicClass
58 (BaseScope.class, MapDynamicPropertyHandler.class);
59 }
60
61
62 // ----------------------------------------------------- Instance Variables
63
64
65 /**
66 * The HashMap that contains our registered keys and beans.
67 */
68 protected HashMap map = new HashMap();
69
70
71 /**
72 * The event listener support object for this <code>Scope</code>.
73 */
74 protected ScopeSupport support = new ScopeSupport(this);
75
76
77 // ------------------------------------------------------------ Map Methods
78
79
80 /**
81 * Remove all beans from this Map and call <code>scopeCleared() on
82 * all registered <code>ScopeListeners</code>.
83 */
84 public void clear() {
85
86 map.clear();
87 support.fireScopeCleared();
88
89 }
90
91
92 /**
93 * Return <code>true</code> if this map contains the specified key.
94 *
95 * @param key Key to be looked up
96 */
97 public boolean containsKey(Object key) {
98
99 return (map.containsKey(key));
100
101 }
102
103
104 /**
105 * Return <code>true</code> if this map contains the specified value.
106 *
107 * @param value Value to be looked up
108 */
109 public boolean containsValue(Object value) {
110
111 return (map.containsValue(value));
112
113 }
114
115
116 /**
117 * Return a set view of the mappings contained in this map.
118 */
119 public Set entrySet() {
120
121 return (map.entrySet());
122
123 }
124
125
126 /**
127 * Compare the specified object with this map for equality.
128 *
129 * @param object Object to be compared
130 */
131 public boolean equals(Object object) {
132
133 return (map.equals(object));
134
135 }
136
137
138 /**
139 * Return the value to which this map maps the specified key.
140 *
141 * @param key Key to be looked up
142 */
143 public Object get(Object key) {
144
145 return (get((String) key));
146
147 }
148
149
150 /**
151 * Return the value to which this map maps the specified key.
152 *
153 * @param key Key to be looked up
154 */
155 public Object get(String key) {
156
157 return (map.get(key));
158
159 }
160
161
162 /**
163 * Return the hash code value for this map.
164 */
165 public int hashCode() {
166
167 return (map.hashCode());
168
169 }
170
171
172 /**
173 * Return <code>true</code> if this map is empty.
174 */
175 public boolean isEmpty() {
176
177 return (map.isEmpty());
178
179 }
180
181
182 /**
183 * Return a set view of the keys contained in this map.
184 */
185 public Set keySet() {
186
187 return (map.keySet());
188
189 }
190
191
192 /**
193 * Add or replace the bean associated with the specified key.
194 *
195 * @param key Key with which the new value should be associated
196 * (cannot be null)
197 * @param bean Bean to be associated with this key (cannot be null)
198 */
199 public Object put(Object key, Object bean) {
200
201 return (put((String) key, bean));
202
203 }
204
205
206 /**
207 * Add the specified bean, associated with the specified key, to this
208 * scope and replace any previous bean associated with this key. If
209 * the bean was added, call <code>beanAdded()</code> on all registered
210 * listeners after the add is done. If an old bean was replaced,
211 * call <code>beanReplaced()</code> (passing the old value in the event)
212 * on all registered <code>ScopeListeners</code> after the removal
213 * is done. If a bean was replaced, the old value is also returned;
214 * otherwise <code>null</code> is returned.
215 *
216 * @param key Key with which the new value should be associated
217 * (cannot be null)
218 * @param bean Bean to be associated with this key (cannot be null)
219 *
220 * @exception IllegalArgumentException if <code>key</code> or
221 * <code>bean</code> is null
222 */
223 public Object put(String key, Object bean) {
224
225 if (key == null)
226 throw new IllegalArgumentException("Key cannot be null");
227 if (bean == null)
228 throw new IllegalArgumentException("Value cannot be null");
229
230 Object old = get(key);
231 if (map.containsKey(key)) {
232 map.put(key, bean);
233 support.fireBeanReplaced(key, old);
234 } else {
235 map.put(key, bean);
236 support.fireBeanAdded(key, bean);
237 }
238 return (old);
239
240 }
241
242
243 /**
244 * Copy all of the mappings from the specified map into this map,
245 * firing appropriate <code>beanAdded()</code> and
246 * <code>beanReplaced()</code> events along the way.
247 *
248 * @param in Map whose contents are to be added
249 */
250 public void putAll(Map in) {
251
252 Iterator keys = in.keySet().iterator();
253 while (keys.hasNext()) {
254 Object key = keys.next();
255 put(key, in.get(key));
256 }
257
258 }
259
260
261 /**
262 * Remove the bean associated with the specified key (if any), and return
263 * the old value if removed.
264 *
265 * @param key Key of the bean to remove (cannot be null)
266 */
267 public Object remove(Object key) {
268
269 return (remove((String) key));
270
271 }
272
273
274
275 /**
276 * Remove the bean associated with the specified key (if any). If such
277 * a bean is found and removed, call <code>beanRemoved()</code> on all
278 * registered <code>ScopeListeners</code> after the removal is done.
279 * Return the old value (if any); otherwise return <code>null</code>.
280 *
281 * @param key Key of the bean to remove (cannot be null)
282 *
283 * @exception IllegalArgumentException if <code>key</code> is null
284 */
285 public Object remove(String key) {
286
287 if (map.containsKey(key)) {
288 Object old = map.remove(key);
289 support.fireBeanRemoved(key, old);
290 return (old);
291 }
292 return (null);
293
294 }
295
296
297 /**
298 * Return the number of key-value mappings in this map.
299 */
300 public int size() {
301
302 return (map.size());
303
304 }
305
306
307 /**
308 * Return a Collection view of the values contained in this map.
309 */
310 public Collection values() {
311
312 return (map.values());
313
314 }
315
316
317 // ------------------------------------------------- Event Listener Methods
318
319
320 /**
321 * Add a listener that is notified each time beans are added,
322 * replaced, or removed in this scope.
323 *
324 * @param listener The ScopeListener to be added
325 */
326 public void addScopeListener(ScopeListener listener) {
327
328 support.addScopeListener(listener);
329
330 }
331
332
333 /**
334 * Remove a listener that is notified each time beans are added,
335 * replaced, or removed in this scope.
336 *
337 * @param listener The ScopeListener to be removed
338 */
339 public void removeScopeListener(ScopeListener listener) {
340
341 support.removeScopeListener(listener);
342
343 }
344
345
346 }