1 | /* |
2 | * Copyright 2006-2007 the original author or authors. |
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.springframework.batch.item; |
18 | |
19 | import java.io.Serializable; |
20 | import java.util.HashMap; |
21 | import java.util.Iterator; |
22 | import java.util.Map; |
23 | import java.util.Properties; |
24 | import java.util.Set; |
25 | import java.util.Map.Entry; |
26 | |
27 | import org.springframework.util.Assert; |
28 | |
29 | /** |
30 | * Object representing a context for an {@link ItemStream}. It is a thin |
31 | * wrapper for a map that allows optionally for type safety on reads. It also |
32 | * allows for dirty checking by setting a 'dirty' flag whenever any put is |
33 | * called. |
34 | * |
35 | * @author Lucas Ward |
36 | * @author Douglas Kaminsky |
37 | */ |
38 | public class ExecutionContext implements Serializable { |
39 | |
40 | private boolean dirty = false; |
41 | |
42 | private final Map map; |
43 | |
44 | /** |
45 | * Default constructor. Initializes a new execution context with an empty |
46 | * internal map. |
47 | */ |
48 | public ExecutionContext() { |
49 | map = new HashMap(); |
50 | } |
51 | |
52 | /** |
53 | * Initializes a new execution context with the contents of another map. |
54 | * |
55 | * @param map Initial contents of context. |
56 | */ |
57 | public ExecutionContext(Map map) { |
58 | this.map = map; |
59 | } |
60 | |
61 | /** |
62 | * @param executionContext |
63 | */ |
64 | public ExecutionContext(ExecutionContext executionContext) { |
65 | this(); |
66 | if (executionContext==null) { |
67 | return; |
68 | } |
69 | for (Iterator iterator = executionContext.entrySet().iterator(); iterator.hasNext();) { |
70 | Entry entry = (Entry) iterator.next(); |
71 | this.map.put(entry.getKey(), entry.getValue()); |
72 | } |
73 | } |
74 | |
75 | /** |
76 | * Adds a String value to the context. |
77 | * |
78 | * @param key Key to add to context |
79 | * @param value Value to associate with key |
80 | */ |
81 | |
82 | public void putString(String key, String value) { |
83 | |
84 | put(key, value); |
85 | } |
86 | |
87 | /** |
88 | * Adds a Long value to the context. |
89 | * |
90 | * @param key Key to add to context |
91 | * @param value Value to associate with key |
92 | */ |
93 | public void putLong(String key, long value) { |
94 | |
95 | put(key, new Long(value)); |
96 | } |
97 | |
98 | /** |
99 | * Add a Double value to the context. |
100 | * |
101 | * @param key Key to add to context |
102 | * @param value Value to associate with key |
103 | */ |
104 | public void putDouble(String key, double value) { |
105 | |
106 | put(key, new Double(value)); |
107 | } |
108 | |
109 | /** |
110 | * Add an Object value to the context (must be Serializable). |
111 | * |
112 | * @param key Key to add to context |
113 | * @param value Value to associate with key |
114 | */ |
115 | public void put(String key, Object value) { |
116 | if (value != null) { |
117 | Assert.isInstanceOf(Serializable.class, value, "Value: [ " + value + "must be serializable."); |
118 | } |
119 | dirty = true; |
120 | map.put(key, value); |
121 | } |
122 | |
123 | /** |
124 | * Indicates if context has been changed with a "put" operation since the |
125 | * dirty flag was last cleared. Note that the last time the flag was cleared |
126 | * might correspond to creation of the context. |
127 | * |
128 | * @return True if "put" operation has occurred since flag was last cleared |
129 | */ |
130 | public boolean isDirty() { |
131 | return dirty; |
132 | } |
133 | |
134 | /** |
135 | * Typesafe Getter for the String represented by the provided key. |
136 | * |
137 | * @param key The key to get a value for |
138 | * @return The <code>String</code> value |
139 | */ |
140 | public String getString(String key) { |
141 | |
142 | return (String) readAndValidate(key, String.class); |
143 | } |
144 | |
145 | /** |
146 | * Typesafe Getter for the String represented by the provided key with |
147 | * default value to return if key is not represented. |
148 | * |
149 | * @param key The key to get a value for |
150 | * @param defaultString Default to return if key is not represented |
151 | * @return The <code>String</code> value if key is repreesnted, specified |
152 | * default otherwise |
153 | */ |
154 | public String getString(String key, String defaultString) { |
155 | if (!map.containsKey(key)) { |
156 | return defaultString; |
157 | } |
158 | |
159 | return (String) readAndValidate(key, String.class); |
160 | } |
161 | |
162 | /** |
163 | * Typesafe Getter for the Long represented by the provided key. |
164 | * |
165 | * @param key The key to get a value for |
166 | * @return The <code>Long</code> value |
167 | */ |
168 | public long getLong(String key) { |
169 | |
170 | return ((Long) readAndValidate(key, Long.class)).longValue(); |
171 | } |
172 | |
173 | /** |
174 | * Typesafe Getter for the Long represented by the provided key with default |
175 | * value to return if key is not represented. |
176 | * |
177 | * @param key The key to get a value for |
178 | * @param defaultLong Default to return if key is not represented |
179 | * @return The <code>long</code> value if key is represented, specified |
180 | * default otherwise |
181 | */ |
182 | public long getLong(String key, long defaultLong) { |
183 | if (!map.containsKey(key)) { |
184 | return defaultLong; |
185 | } |
186 | |
187 | return ((Long) readAndValidate(key, Long.class)).longValue(); |
188 | } |
189 | |
190 | /** |
191 | * Typesafe Getter for the Double represented by the provided key. |
192 | * |
193 | * @param key The key to get a value for |
194 | * @return The <code>Double</code> value |
195 | */ |
196 | public double getDouble(String key) { |
197 | return ((Double) readAndValidate(key, Double.class)).doubleValue(); |
198 | } |
199 | |
200 | /** |
201 | * Typesafe Getter for the Double represented by the provided key with |
202 | * default value to return if key is not represented. |
203 | * |
204 | * @param key The key to get a value for |
205 | * @param defaultDouble Default to return if key is not represented |
206 | * @return The <code>double</code> value if key is represented, specified |
207 | * default otherwise |
208 | */ |
209 | public double getDouble(String key, double defaultDouble) { |
210 | if (!map.containsKey(key)) { |
211 | return defaultDouble; |
212 | } |
213 | |
214 | return ((Double) readAndValidate(key, Double.class)).doubleValue(); |
215 | } |
216 | |
217 | /** |
218 | * Getter for the value represented by the provided key. |
219 | * |
220 | * @param key The key to get a value for |
221 | * @return The value represented by the given key |
222 | */ |
223 | public Object get(String key) { |
224 | |
225 | return map.get(key); |
226 | } |
227 | |
228 | /** |
229 | * Utility method that attempts to take a value represented by a given key |
230 | * and validate it as a member of the specified type. |
231 | * |
232 | * @param key The key to validate a value for |
233 | * @param type Class against which value should be validated |
234 | * @return Value typed to the specified <code>Class</code> |
235 | */ |
236 | private Object readAndValidate(String key, Class type) { |
237 | |
238 | Object value = map.get(key); |
239 | |
240 | if (!type.isInstance(value)) { |
241 | throw new ClassCastException("Value for key=[" + key + "] is not of type: [" + type + "], it is [" |
242 | + (value == null ? null : "(" + value.getClass() + ")" + value) + "]"); |
243 | } |
244 | |
245 | return value; |
246 | } |
247 | |
248 | /** |
249 | * Indicates whether or not the context is empty. |
250 | * |
251 | * @return True if the context has no entries, false otherwise. |
252 | * @see java.util.Map#isEmpty() |
253 | */ |
254 | public boolean isEmpty() { |
255 | return map.isEmpty(); |
256 | } |
257 | |
258 | /** |
259 | * Clears the dirty flag. |
260 | */ |
261 | public void clearDirtyFlag() { |
262 | dirty = false; |
263 | } |
264 | |
265 | /** |
266 | * Returns the entry set containing the contents of this context. |
267 | * |
268 | * @return A set representing the contents of the context |
269 | * @see java.util.Map#entrySet() |
270 | */ |
271 | public Set entrySet() { |
272 | return map.entrySet(); |
273 | } |
274 | |
275 | /** |
276 | * Indicates whether or not a key is represented in this context. |
277 | * |
278 | * @param key Key to check existence for |
279 | * @return True if key is represented in context, false otherwise |
280 | * @see java.util.Map#containsKey(Object) |
281 | */ |
282 | public boolean containsKey(String key) { |
283 | return map.containsKey(key); |
284 | } |
285 | |
286 | /** |
287 | * Indicates whether or not a value is represented in this context. |
288 | * |
289 | * @param value Value to check existence for |
290 | * @return True if value is represented in context, false otherwise |
291 | * @see java.util.Map#containsValue(Object) |
292 | */ |
293 | public boolean containsValue(Object value) { |
294 | return map.containsValue(value); |
295 | } |
296 | |
297 | /** |
298 | * Returns a <code>Properties</code> object containing <code>String</code> |
299 | * versions of the contents of the context. |
300 | * |
301 | * @return Contents of context as a {@link java.util.Properties} |
302 | * |
303 | * @deprecated to be removed with no replacement in 2.0. Should not be part |
304 | * of public API (test purposes only) |
305 | */ |
306 | public Properties getProperties() { |
307 | Properties props = new Properties(); |
308 | for (Iterator it = map.entrySet().iterator(); it.hasNext();) { |
309 | Entry entry = (Entry) it.next(); |
310 | props.setProperty(entry.getKey().toString(), entry.getValue().toString()); |
311 | } |
312 | |
313 | return props; |
314 | } |
315 | |
316 | /* |
317 | * (non-Javadoc) |
318 | * @see java.lang.Object#equals(java.lang.Object) |
319 | */ |
320 | public boolean equals(Object obj) { |
321 | if (obj instanceof ExecutionContext == false) { |
322 | return false; |
323 | } |
324 | if (this == obj) { |
325 | return true; |
326 | } |
327 | ExecutionContext rhs = (ExecutionContext) obj; |
328 | return this.entrySet().equals(rhs.entrySet()); |
329 | } |
330 | |
331 | /* |
332 | * (non-Javadoc) |
333 | * @see java.lang.Object#hashCode() |
334 | */ |
335 | public int hashCode() { |
336 | return map.hashCode(); |
337 | } |
338 | |
339 | /* |
340 | * (non-Javadoc) |
341 | * @see java.lang.Object#toString() |
342 | */ |
343 | public String toString() { |
344 | return map.toString(); |
345 | } |
346 | |
347 | /** |
348 | * Returns number of entries in the context |
349 | * |
350 | * @return Number of entries in the context |
351 | * @see java.util.Map#size() |
352 | */ |
353 | public int size() { |
354 | return map.size(); |
355 | } |
356 | |
357 | } |