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.HashMap;
28  import java.util.Iterator;
29  import java.util.List;
30  import java.util.Map;
31  
32  import de.bea.domingo.DDocument;
33  
34  /***
35   * Class defining and performing a mapping of Lists of business objects from and
36   * to a document.
37   *
38   * @author <a href="mailto:kriede@users.sourceforge.net">Kurt Riede</a>
39   */
40  public abstract class ListMapper extends BaseDMapper {
41  
42      /*** Notes item name in the Notes document. */
43      private String mItemName;
44  
45      /*** Name of getter method of list attribute. */
46      private String mGetName;
47  
48      /*** Set of list item attributes. */
49      private List mAttributes = new ArrayList();
50  
51      /***
52       * Constructor. Creates a direct mapper where the Notes item name is equal
53       * to the <tt>itemName</tt> attribute and the names of the get/set methods
54       * in the business class are equal to <tt>"get" + itemName</tt> and
55       * <tt>"set" + itemName</tt>.
56       *
57       * @param itemName name of Notes item
58       */
59      public ListMapper(final String itemName) {
60          this(itemName, "get" + itemName);
61      }
62  
63      /***
64       * Constructor. Creates a direct mapper where the Notes item name is equal
65       * to the <tt>itemName</tt> attribute and the names of the get/set methods
66       * in the business class are equal to <tt>getName</tt> and
67       * <tt>setName</tt>.
68       *
69       * @param itemName name of Notes item
70       * @param getName name of get-method
71       */
72      public ListMapper(final String itemName, final String getName) {
73          this.mItemName = itemName;
74          this.mGetName = getName;
75      }
76  
77      /***
78       * Adds a mapper where the Notes item name is equal to the <tt>itemName</tt>
79       * attribute and the names of the get/set methods in the business class are
80       * equal to <tt>"get" + itemName</tt> and <tt>"set" + itemName</tt>.
81       *
82       * @param itemName name of Notes item
83       * @param clazz the value type
84       */
85      protected final void add(final String itemName, final Class clazz) {
86          add(itemName, itemName, clazz);
87      }
88  
89      /***
90       * Adds a mapper where the Notes item name is equal to the <tt>itemName</tt>
91       * attribute and the names of the get/set methods in the business class are
92       * equal to <tt>"get" + attributeName</tt> and
93       * <tt>"set" + attributeName</tt>.
94       *
95       * @param itemName name of Notes item
96       * @param attributeName name of Java attribute
97       * @param clazz the value type
98       */
99      protected final void add(final String itemName, final String attributeName, final Class clazz) {
100         add(itemName, "get" + attributeName, "set" + attributeName, clazz);
101     }
102 
103     /***
104      * Adds a mapper where the Notes item name is equal to the <tt>itemName</tt>
105      * attribute and the names of the get/set methods in the business class are
106      * equal to <tt>getName</tt> and <tt>setName</tt>.
107      *
108      * @param itemName name of Notes item
109      * @param getName name of get-method
110      * @param setName name of set-method
111      * @param clazz the value type
112      */
113     protected final void add(final String itemName, final String getName, final String setName, final Class clazz) {
114         mAttributes.add(new Attribute(itemName, getName, setName, clazz));
115     }
116 
117     private static final class Attribute {
118 
119         private final String mItemName;
120 
121         private final String mGetName;
122 
123         private final String mSetName;
124 
125         private final Class mClazz;
126 
127         private Attribute(final String itemName, final String getName, final String setName, final Class clazz) {
128             this.mItemName = itemName;
129             this.mGetName = getName;
130             this.mSetName = setName;
131             this.mClazz = clazz;
132         }
133     }
134 
135     /***
136      * {@inheritDoc}
137      * @see de.bea.domingo.map.Mapper#map(de.bea.domingo.DDocument,
138      *      java.lang.Object)
139      */
140     public final void map(final DDocument document, final Object object) throws MappingException {
141         // read value lists from document
142         final Map values = new HashMap(mAttributes.size());
143         int minSize = Integer.MAX_VALUE;
144         int maxSize = 0;
145         final Iterator i2 = mAttributes.iterator();
146         while (i2.hasNext()) {
147             final Attribute attribute = (Attribute) i2.next();
148             final List itemValue = document.getItemValue(attribute.mItemName);
149             minSize = itemValue.size() < minSize ? itemValue.size() : minSize;
150             maxSize = itemValue.size() > maxSize ? itemValue.size() : maxSize;
151             values.put(attribute, itemValue);
152         }
153         if (minSize != maxSize) {
154             System.out.println("not all items have the same number of values");
155         }
156         for (int k = 0; k < minSize; k++) {
157             Object item = createItem(object);
158             final Iterator i3 = mAttributes.iterator();
159             while (i3.hasNext()) {
160                 final Attribute attribute = (Attribute) i3.next();
161                 setValue(item, attribute.mSetName, ((List) values.get(attribute)).get(k), attribute.mClazz);
162             }
163         }
164     }
165 
166     /***
167      * Creates a new instance of a list item. Must be implemented by concrete
168      * list mappers.
169      *
170      * @param object parent object
171      * @return new instance of list item
172      */
173     protected abstract Object createItem(final Object object);
174 
175     /***
176      * {@inheritDoc}
177      * @see de.bea.domingo.map.Mapper#map(java.lang.Object,
178      *      de.bea.domingo.DDocument)
179      */
180     public final void map(final Object object, final DDocument document) throws MappingException {
181         List items = getList(object);
182         int size = items.size();
183         // create value lists for all attributes
184         Map values = new HashMap(mAttributes.size());
185         Iterator i = mAttributes.iterator();
186         while (i.hasNext()) {
187             Attribute attribute = (Attribute) i.next();
188             values.put(attribute, new ArrayList(size));
189         }
190         // fill value lists
191         Iterator iterator = items.iterator();
192         while (iterator.hasNext()) {
193             Object item = iterator.next();
194             Iterator i3 = mAttributes.iterator();
195             while (i3.hasNext()) {
196                 Attribute attribute = (Attribute) i3.next();
197                 List list = (List) values.get(attribute);
198                 list.add(getValue(item, attribute.mGetName));
199             }
200         }
201         // write value lists to document
202         Iterator i2 = mAttributes.iterator();
203         while (i2.hasNext()) {
204             Attribute attribute = (Attribute) i2.next();
205             replaceItemValue(document, attribute.mItemName, (List) values.get(attribute));
206         }
207     }
208 
209     /***
210      * Returns the list attribute defined by the getter method as defined in the
211      * constructor.
212      *
213      * @return the list
214      * @throws MappingException if the list attribute cannot be read from the
215      *             given object
216      */
217     private List getList(final Object object) throws MappingException {
218         Class[] parameterTypes = {};
219         try {
220             Method method = object.getClass().getMethod(mGetName, parameterTypes);
221             Object[] args = {};
222             return (List) method.invoke(object, args);
223         } catch (Exception e) {
224             throw new MappingException("Cannot get list attribute " + mItemName, e);
225         }
226     }
227 }