1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package de.bea.domingo.map;
24
25 import java.lang.reflect.Method;
26 import java.util.ArrayList;
27 import java.util.Calendar;
28 import java.util.Iterator;
29 import java.util.List;
30
31 import de.bea.domingo.DDateRange;
32 import de.bea.domingo.DDocument;
33 import de.bea.domingo.DNotesRuntimeException;
34
35 /***
36 * Abstract base class for domingo mappers providing useful methods to access
37 * Notes. Converts
38 * {@link de.bea.domingo.DNotesRuntimeException DNotesRuntimeException}s into
39 * {@link de.bea.domingo.map.MappingException MappingException}s.
40 *
41 * @author <a href="mailto:kriede@users.sourceforge.net">Kurt Riede</a>
42 */
43 public abstract class BaseDMapper implements Mapper {
44
45 /*** Notes default date/time. */
46 private static final Calendar NOTES_DEFAULT_DATE_TIME = Calendar.getInstance();
47
48 /*** Year of Notes default date. */
49 private static final int NOTES_DEFAULT_YEAR = 1899;
50
51 /*** Day of Notes default date. */
52 private static final int NOTES_DEFAULT_DAY = 30;
53
54 /*** Hour of Notes default date. */
55 private static final int NOTES_DEFAULT_HOUR = 12;
56
57 static {
58 NOTES_DEFAULT_DATE_TIME.set(NOTES_DEFAULT_YEAR, Calendar.DECEMBER, NOTES_DEFAULT_DAY, NOTES_DEFAULT_HOUR, 0, 0);
59 NOTES_DEFAULT_DATE_TIME.set(Calendar.MILLISECOND, 0);
60 }
61
62 /***
63 * Constructor.
64 */
65 public BaseDMapper() {
66 }
67
68 /***
69 * Replaces the value of an item with a String.
70 *
71 * @param document document to replace item in
72 * @param itemName name of item to replace
73 * @param value the value to map
74 * @throws MappingException if the value cannot be mapped to the item
75 */
76 protected final void replaceItemValue(final DDocument document, final String itemName, final String value)
77 throws MappingException {
78 try {
79 document.replaceItemValue(itemName, value);
80 } catch (DNotesRuntimeException e) {
81 throw new MappingException("Cannot map String value '" + value + "' to item " + itemName, e);
82 }
83 }
84
85 /***
86 * Replaces the value of an item with a Calendar.
87 *
88 * @param document document to replace item in
89 * @param itemName name of item to replace
90 * @param value the value to map
91 * @throws MappingException if the value cannot be mapped to the item
92 */
93 protected final void replaceItemValue(final DDocument document, final String itemName, final Calendar value)
94 throws MappingException {
95 try {
96 document.replaceItemValue(itemName, value);
97 } catch (DNotesRuntimeException e) {
98 throw new MappingException("Cannot map Calendar value '" + value + "' to item " + itemName, e);
99 }
100 }
101
102 /***
103 * Replaces the value of an item with an int.
104 *
105 * @param document document to replace item in
106 * @param itemName name of item to replace
107 * @param value the value to map
108 * @throws MappingException if the value cannot be mapped to the item
109 */
110 protected final void replaceItemValue(final DDocument document, final String itemName, final int value)
111 throws MappingException {
112 try {
113 document.replaceItemValue(itemName, value);
114 } catch (DNotesRuntimeException e) {
115 throw new MappingException("Cannot map int value '" + value + "' to item " + itemName, e);
116 }
117 }
118
119 /***
120 * Replaces the value of an item with an Integer.
121 *
122 * @param document document to replace item in
123 * @param itemName name of item to replace
124 * @param value the value to map
125 * @throws MappingException if the value cannot be mapped to the item
126 */
127 protected final void replaceItemValue(final DDocument document, final String itemName, final Integer value)
128 throws MappingException {
129 try {
130 document.replaceItemValue(itemName, value);
131 } catch (DNotesRuntimeException e) {
132 throw new MappingException("Cannot map Integer value '" + value + "' to item " + itemName, e);
133 }
134 }
135
136 /***
137 * Replaces the value of an item with a double.
138 *
139 * @param document document to replace item in
140 * @param itemName name of item to replace
141 * @param value the value to map
142 * @throws MappingException if the value cannot be mapped to the item
143 */
144 protected final void replaceItemValue(final DDocument document, final String itemName, final double value)
145 throws MappingException {
146 try {
147 document.replaceItemValue(itemName, value);
148 } catch (DNotesRuntimeException e) {
149 throw new MappingException("Cannot map double value '" + value + "' to item " + itemName, e);
150 }
151 }
152
153 /***
154 * Replaces the value of an item with a Double.
155 *
156 * @param document document to replace item in
157 * @param itemName name of item to replace
158 * @param value the value to map
159 * @throws MappingException if the value cannot be mapped to the item
160 */
161 protected final void replaceItemValue(final DDocument document, final String itemName, final Double value)
162 throws MappingException {
163 try {
164 document.replaceItemValue(itemName, value);
165 } catch (DNotesRuntimeException e) {
166 throw new MappingException("Cannot map Double value '" + value + "' to item " + itemName, e);
167 }
168 }
169
170 /***
171 * Replaces the value of an item with a List.
172 *
173 * @param document document to replace item in
174 * @param itemName name of item to replace
175 * @param value the value to map
176 * @throws MappingException if the value cannot be mapped to the item
177 */
178 protected final void replaceItemValue(final DDocument document, final String itemName, final List value)
179 throws MappingException {
180 try {
181 document.replaceItemValue(itemName, cleanList(value));
182 } catch (DNotesRuntimeException e) {
183 throw new MappingException("Cannot map value '" + value + "' to item " + itemName, e);
184 }
185 }
186
187 /***
188 * Reads the date value of an item.
189 *
190 * @param document the domingo document to read from
191 * @param itemName the name of the item to read from
192 * @return value of item as Calendar
193 * @throws MappingException if the value cannot be read
194 */
195 protected final Calendar getValueDate(final DDocument document, final String itemName) throws MappingException {
196 try {
197 return document.getItemValueDate(itemName);
198 } catch (DNotesRuntimeException e) {
199 throw new MappingException("Cannot read Calendar value from item " + itemName, e);
200 }
201 }
202
203 /***
204 * Reads the DDateRange value of an item.
205 *
206 * @param document the domingo document to read from
207 * @param itemName the name of the item to read from
208 * @return value of item as DDateRange
209 * @throws MappingException if the value cannot be read
210 */
211 protected final DDateRange getValueDateRange(final DDocument document, final String itemName) throws MappingException {
212 try {
213 return document.getItemValueDateRange(itemName);
214 } catch (DNotesRuntimeException e) {
215 throw new MappingException("Cannot read Calendar value from item " + itemName, e);
216 }
217 }
218
219 /***
220 * Reads the String value of an item.
221 *
222 * @param document the domingo document to read from
223 * @param itemName the name of the item to read from
224 * @return value of item as String
225 * @throws MappingException if the value cannot be read
226 */
227 protected final String getValueString(final DDocument document, final String itemName) throws MappingException {
228 try {
229 return document.getItemValueString(itemName);
230 } catch (DNotesRuntimeException e) {
231 throw new MappingException("Cannot read String value from item " + itemName, e);
232 }
233 }
234
235 /***
236 * Reads the Double value of an item.
237 *
238 * @param document the domingo document to read from
239 * @param itemName the name of the item to read from
240 * @return value of item as Double
241 * @throws MappingException if the value cannot be read
242 */
243 protected final Double getValueDouble(final DDocument document, final String itemName) throws MappingException {
244 try {
245 return document.getItemValueDouble(itemName);
246 } catch (DNotesRuntimeException e) {
247 throw new MappingException("Cannot read Double value from item " + itemName, e);
248 }
249 }
250
251 /***
252 * Reads the Integer value of an item.
253 *
254 * @param document the domingo document to read from
255 * @param itemName the name of the item to read from
256 * @return value of item as Integer
257 * @throws MappingException if the value cannot be read
258 */
259 protected final Integer getValueInteger(final DDocument document, final String itemName) throws MappingException {
260 try {
261 return document.getItemValueInteger(itemName);
262 } catch (DNotesRuntimeException e) {
263 throw new MappingException("Cannot read Integer value from item " + itemName, e);
264 }
265 }
266
267 /***
268 * Reads the date value of an item.
269 *
270 * @param document the domingo document to read from
271 * @param itemName the name of the item to read from
272 * @return value of item as Calendar
273 * @throws MappingException if the value cannot be read
274 */
275 protected final List getValue(final DDocument document, final String itemName) throws MappingException {
276 try {
277 return document.getItemValue(itemName);
278 } catch (DNotesRuntimeException e) {
279 throw new MappingException("Cannot read value list from item " + itemName, e);
280 }
281 }
282
283 /***
284 * Checks and repairs the values in a list. If there are <tt>null</tt>
285 * values in the list they are replaced with a default value with the same
286 * datatype as the first value that is not <tt>null</tt>. If all values
287 * are <tt>null</tt>, all values are replaced with empty strings. The
288 * returned list is a new list; the original list is left unchanged.
289 *
290 * @param value list of values
291 */
292 private List cleanList(final List list) {
293 Object firstValueNotNull = getFirstValueNotNull(list);
294 Object defaultValue = getDefaultValue(firstValueNotNull);
295 return replaceNull(list, defaultValue);
296 }
297
298 /***
299 * Returns the default value matching the type of a given value.
300 *
301 * @param value a value
302 * @return default value with same type or best matching type
303 */
304 private Object getDefaultValue(final Object value) {
305 if (value instanceof Number) {
306 return new Integer(0);
307 } else if (value instanceof Calendar) {
308 return NOTES_DEFAULT_DATE_TIME;
309 }
310 return "";
311 }
312
313 /***
314 * Returns the first value in a list that is not <tt>null</tt>.
315 *
316 * @param list list of values
317 * @return first value that is not <tt>null</tt>
318 */
319 private Object getFirstValueNotNull(final List list) {
320 Object value = null;
321 Iterator iterator = list.iterator();
322 while (iterator.hasNext() && value == null) {
323 value = iterator.next();
324 }
325 return value;
326 }
327
328 /***
329 * Returns a calendar if the given object is a calendar or
330 * it is a list and the first element in the list is a calendar.
331 *
332 * @param calendarOrList a {@link Calendar} or a {@link List}
333 * @return {@link Calendar} or <code>null</code>
334 */
335 protected final Calendar getCalendar(final Object calendarOrList) {
336 if (calendarOrList instanceof Calendar) {
337 return (Calendar) calendarOrList;
338 }
339 if (calendarOrList instanceof List && ((List) calendarOrList).size() > 0) {
340 return (Calendar) ((List) calendarOrList).get(0);
341 }
342 return null;
343 }
344
345 /***
346 * Replaces all <tt>null</tt> values in a list with a given default value.
347 *
348 * @param list the list to replace in
349 * @param defaultValue the default value for <tt>null</tt> values
350 */
351 private List replaceNull(final List list, final Object defaultValue) {
352 List result = new ArrayList();
353 Iterator iterator = list.iterator();
354 while (iterator.hasNext()) {
355 Object value = iterator.next();
356 result.add(value == null ? defaultValue : value);
357 }
358 return result;
359 }
360
361 /***
362 * Returns the value of an attribute given by its getter method from given
363 * object.
364 *
365 * @param object the object
366 * @param getName the name of the getter method
367 * @return the value
368 * @throws MappingException if the given attribute cannot be accessed
369 */
370 protected final Object getValue(final Object object, final String getName) throws MappingException {
371 Class[] parameterTypes = {};
372 try {
373 Method method = object.getClass().getMethod(getName, parameterTypes);
374 return method.invoke(object, BaseMapper.EMPTY_ARGS);
375 } catch (Exception e) {
376 throw new MappingException("Cannot access method " + getName, e);
377 }
378 }
379
380 /***
381 * Sets a value of an attribute given by its setter method in a given
382 * object.
383 *
384 * @param object the object
385 * @param setName the name of the setter method
386 * @param value the value to set
387 * @param clazz class name of attribute
388 * @throws MappingException if the given attribute cannot be accessed
389 */
390 protected final void setValue(final Object object, final String setName, final Object value, final Class clazz)
391 throws MappingException {
392 final Class[] parameterTypes = { clazz };
393 final Object arg0;
394 if (value == null) {
395 return;
396 } else if (value instanceof Number && (clazz == Integer.class || clazz == Integer.TYPE)) {
397 arg0 = new Integer(((Double) value).intValue());
398 } else {
399 arg0 = value;
400 }
401
402 final Object[] args = { arg0 };
403 final Method method;
404 try {
405 method = object.getClass().getMethod(setName, parameterTypes);
406 } catch (Exception e) {
407 throw new MappingException("not found: " + object.getClass().getName() + "." + setName + "(" + clazz + ")", e);
408 }
409 try {
410 method.invoke(object, args);
411 } catch (Exception e) {
412 throw new MappingException("error calling " + object.getClass().getName() + "." + setName + "(" + clazz + ")", e);
413 }
414 }
415
416 /***
417 * Checks if a class contains a method with the specified name and no
418 * arguments.
419 *
420 * @param clazz the class to check
421 * @param name a method name
422 * @return <code>true</code> if the method exists, else <code>false</code>
423 */
424 protected static final boolean hasMethod(final Class clazz, final String name) {
425 try {
426 return clazz.getMethod(name, BaseMapper.EMPTY_PARAMS) != null;
427 } catch (SecurityException e) {
428
429 return false;
430 } catch (NoSuchMethodException e) {
431
432 return false;
433 }
434 }
435
436 }