View Javadoc

1   /*
2    * This file is part of Domingo
3    * an Open Source Java-API to Lotus Notes/Domino
4    * hosted at http://domingo.sourceforge.net
5    *
6    * Copyright (c) 2003-2007 Beck et al. projects GmbH Munich, Germany (http://www.bea.de)
7    *
8    * This library is free software; you can redistribute it and/or
9    * modify it under the terms of the GNU Lesser General Public
10   * License as published by the Free Software Foundation; either
11   * version 2.1 of the License, or (at your option) any later version.
12   *
13   * This library is distributed in the hope that it will be useful,
14   * but WITHOUT ANY WARRANTY; without even the implied warranty of
15   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   * Lesser General Public License for more details.
17   *
18   * You should have received a copy of the GNU Lesser General Public
19   * License along with this library; if not, write to the Free Software
20   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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             // TODO handle exception
429             return false;
430         } catch (NoSuchMethodException e) {
431             // TODO handle exception
432             return false;
433         }
434     }
435 
436 }