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.Collection;
29 import java.util.List;
30
31 import de.bea.domingo.DDocument;
32
33 /***
34 * Class defining and performing a direct mapping of a single attribute between
35 * a document and a business object.
36 *
37 * The following types are supported:
38 * <ul>
39 * <li>java.lang.String</li>
40 * <li>java.lang.Integer and <code>int</code></li>
41 * <li>java.lang.Double and <code>double</code></li>
42 * <li>java.util.Calendar</li>
43 * </ul>
44 *
45 * <p>Other types must be mapped e.g. with a {@link CustomMapper}.</p>
46 *
47 * @author <a href="mailto:kriede@users.sourceforge.net">Kurt Riede</a>
48 */
49 public final class DirectMapper extends BaseDMapper {
50
51 /*** Notes item name in the Notes document. */
52 private String itemName;
53
54 /*** Name of getter method of instance class. */
55 private String getName;
56
57 /*** Name of setter method of instance class. */
58 private String setName;
59
60 /***
61 * Value class, can be {@link java.lang.Number}, {@link java.lang.String}
62 * or {@link java.lang.Calendar}.
63 */
64 private Class clazz;
65
66 /***
67 * Constructor. Creates a direct mapper where the Notes item name is equal
68 * to the <tt>itemName</tt> attribute and the names of the get/set methods
69 * in the business class are equal to <tt>"get" + itemName</tt> and
70 * <tt>"set" + itemName</tt>.
71 *
72 * @param itemName name of Notes item
73 * @param clazz the value type
74 * @throws MethodNotFoundException if the getter or setter method was not found for the attribute name
75 */
76 public DirectMapper(final String itemName, final Class clazz) throws MethodNotFoundException {
77 this(itemName, itemName, clazz);
78 }
79
80 /***
81 * Constructor. Creates a direct mapper where the Notes item name is equal
82 * to the <tt>itemName</tt> attribute and the names of the get/set methods
83 * in the business class are equal to <tt>"get" + attributeName</tt> and
84 * <tt>"set" + attributeName</tt>. Also the prefix <tt>"is</tt>" is allowed
85 * in case of methods returning boolean values.
86 *
87 * @param itemName name of Notes item
88 * @param attributeName name of Java attribute
89 * @param clazz the value type
90 * @throws MethodNotFoundException if the getter or setter method was not found for the attribute name
91 */
92 public DirectMapper(final String itemName, final String attributeName, final Class clazz) throws MethodNotFoundException {
93 this(itemName, getGetterName(clazz, attributeName), getSetterName(clazz, attributeName), clazz);
94 }
95
96 /***
97 * Returns the name of the setter method of a class for a given attribute
98 * name or throws an exception if no getter method exists.
99 *
100 * @param clazz the class to check
101 * @param attributeName the attribute name
102 * @return the name of the getter method
103 * @throws MethodNotFoundException if the getter or setter method was not
104 * found for the attribute name
105 */
106 private static String getSetterName(final Class clazz, final String attributeName)
107 throws MethodNotFoundException {
108 return "set" + attributeName;
109 }
110
111 /***
112 * Returns the name of the getter method of a class for a given attribute
113 * name or throws an exception if no getter method exists.
114 *
115 * @param clazz the class to check
116 * @param attributeName the attribute name
117 * @return the name of the getter method
118 * @throws MethodNotFoundException if the getter or setter method was not
119 * found for the attribute name
120 */
121 private static String getGetterName(final Class clazz, final String attributeName) throws MethodNotFoundException {
122 if (clazz.equals(Boolean.TYPE)) {
123 return "is" + attributeName;
124 } else {
125 return "get" + attributeName;
126 }
127 }
128
129 /***
130 * Constructor. Creates a direct mapper where the Notes item name is equal
131 * to the <tt>itemName</tt> attribute and the names of the get/set methods
132 * in the business class are equal to <tt>getName</tt> and
133 * <tt>setName</tt>.
134 *
135 * @param itemName name of Notes item
136 * @param getName name of get-method
137 * @param setName name of set-method
138 * @param clazz the value type
139 */
140 public DirectMapper(final String itemName, final String getName, final String setName, final Class clazz) {
141 this.itemName = itemName;
142 this.getName = getName;
143 this.setName = setName;
144 this.clazz = clazz;
145 }
146
147 /***
148 * Performs the direct mapping from a document to a business object.
149 *
150 * @param document the Notes document
151 * @param object the business object
152 * @throws MappingException if an error occurred during mapping
153 */
154 public void map(final DDocument document, final Object object) throws MappingException {
155 List itemValueList = document.getItemValue(itemName);
156 if (itemValueList != null && itemValueList.size() > 0) {
157 Object value = itemValueList;
158 if (!Collection.class.isAssignableFrom(clazz)) {
159 if (itemValueList.size() > 0) {
160 value = itemValueList.get(0);
161 } else {
162 return;
163 }
164 }
165 if (Boolean.class.equals(clazz) || Boolean.TYPE.equals(clazz)) {
166 value = getBoolean(value.toString());
167 }
168 Class[] parameterTypes = { clazz };
169 if (setName != null) {
170 String className = object.getClass().getName();
171 try {
172 Method method = new MethodFinder(object.getClass()).findMethod(setName, parameterTypes);
173 Object[] args = { value };
174 method.invoke(object, args);
175 } catch (Exception e) {
176 throw new MappingException("Cannot map item " + itemName + " to " + className + "." + setName, e);
177 }
178 }
179 }
180 }
181
182 /***
183 * Performs the direct mapping from a business object to a document.
184 *
185 * Allowed objects are of type <code>String</code>,
186 * <code>Calendar</code>, <code>Integer</code>, <code>Double</code>
187 * or <code>List</code>, where if the object is a <code>List</code>, all
188 * values in the list must be of one of the other types.
189 *
190 * @param object the business object
191 * @param document the Notes document
192 * @throws MappingException if an error occurred during mapping
193 */
194 public void map(final Object object, final DDocument document) throws MappingException {
195 if (getName != null) {
196 final Object value = getValue(object, getName);
197 if (value == null) {
198 document.replaceItemValue(itemName, "");
199 } else if (String.class.equals(clazz)) {
200 document.replaceItemValue(itemName, value.toString());
201 } else if (Boolean.class.equals(clazz) || Boolean.TYPE.equals(clazz)) {
202 document.replaceItemValue(itemName, getBooleanValue(value));
203 } else if (value instanceof Calendar && Calendar.class.isAssignableFrom(clazz)) {
204 document.replaceItemValue(itemName, (Calendar) value);
205 } else if (value instanceof Double && Number.class.isAssignableFrom(clazz) || Double.TYPE.equals(clazz)) {
206 document.replaceItemValue(itemName, (Double) value);
207 } else if (value instanceof Integer && Number.class.isAssignableFrom(clazz) || Integer.TYPE.equals(clazz)) {
208 document.replaceItemValue(itemName, (Integer) value);
209 } else if (value instanceof List) {
210
211 document.replaceItemValue(itemName, (List) value);
212 } else if (value instanceof Collection) {
213
214 List list = new ArrayList();
215 list.addAll((Collection) value);
216 document.replaceItemValue(itemName, list);
217 } else {
218 throw new MappingException("Invalid datatype for method " + getName + ": " + value.getClass().getName()
219 + " is not assignable of class " + clazz.getName());
220 }
221 }
222 }
223
224 /***
225 * Converts a value to a string representing a boolean value as stored in
226 * Lotus Notes.
227 *
228 * @param value the value
229 * @return the string representing <code>true</code> or <code>false</code>
230 */
231 private String getBooleanValue(final Object value) {
232 if (value instanceof Boolean) {
233 return ((Boolean) value).equals(Boolean.TRUE) ? "1" : "0";
234 } else if (value instanceof Number) {
235 return ((Number) value).doubleValue() != 0 ? "1" : "0";
236 }
237 return value != null ? "1" : "0";
238 }
239
240 /***
241 * Converts a string to a boolean value; only the string <code>"1"</code>
242 * results to <code>true</code>.
243 *
244 * @param value any string
245 * @return <code>true</code> if the string is <code>"1"</code>, else <code>false</code>
246 */
247 private Boolean getBoolean(final String value) {
248 return Boolean.valueOf(value != null && value.equals("1"));
249 }
250 }