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