View Javadoc
1   /*
2    * Copyright 2012 Olivier Godineau
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5    * use this file except in compliance with the License. You may obtain a copy of
6    * the License at http://www.apache.org/licenses/LICENSE-2.0
7    * 
8    * Unless required by applicable law or agreed to in writing, software
9    * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11   * License for the specific language governing permissions and limitations under
12   * the License.
13   */
14  package olg.csv.bean.impl;
15  
16  import java.lang.reflect.InvocationTargetException;
17  import java.lang.reflect.Method;
18  import java.util.List;
19  
20  import olg.csv.bean.PropertyException;
21  import olg.csv.bean.filter.AbstractStringFilter;
22  import olg.csv.bean.formatter.Formatter;
23  
24  /**
25   * In writing Bean, allows to represent a field of an object as a String. This
26   * class seems to be the same as {@link Formatter} class. But its motivation is
27   * different : We want to product a string which represents a characteristic of
28   * an object not the object itself.
29   * 
30   * @author Olivier Godineau
31   * 
32   */
33  public abstract class PropertyFormatter { // NOPMD by olivier on 05/01/12 00:36
34  	/**
35  	 * Name of the property on which to apply the conversion.
36  	 */
37  	protected String name;
38  
39  	/**
40  	 * Returns a string representation of the property.
41  	 * <p>
42  	 * Throws a PropertyException when errors occurs during the formatting.
43  	 * </p>
44  	 * 
45  	 * @param object
46  	 *            Object from which product a string representation of its
47  	 *            property
48  	 * @return the string representation.
49  	 * 
50  	 */
51  	public abstract String toString(Object object);
52  
53  	/**
54  	 * Returns the name of the property.
55  	 * 
56  	 * @return the property name.
57  	 */
58  	public String getName() {
59  		return name;
60  	}
61  
62  	/**
63  	 * Return the full name of the property. In case property is itself a
64  	 * property of a field, must indicate the field name followed by the
65  	 * property name like "field.property".
66  	 * 
67  	 * @return the full name.
68  	 */
69  	public String getFullName() {
70  		return name;
71  	}
72  
73  	/**
74  	 * Returns a PropertyFormatter which concates strings the given
75  	 * propertyformatters returns.
76  	 * 
77  	 * @param formatters
78  	 *            list of PropertyFormatter to concate. Must be not
79  	 *            <code>null</code> and not empty.
80  	 * @param filtre
81  	 *            it's possible to filtre the string rendered by the given
82  	 *            propertyFormatters before to be returned
83  	 * @return a new instance of PropertyFormatter
84  	 */
85  	public static PropertyFormatter getConcatePropertyReader(List<PropertyFormatter> formatters,
86  			AbstractStringFilter filtre) {
87  		if (formatters == null || formatters.isEmpty()) {
88  			throw new IllegalArgumentException("PropertyFormatter#getConcatePropertyReader  "
89  					+ "propertiyFormatters argument must be not null and not empty");
90  		}
91  
92  		return new ConcatePropertyReader(formatters, filtre);
93  
94  	}
95  
96  	@Override
97  	public int hashCode() {
98  		final int prime = 31;
99  		int result = 1;
100 		result = prime * result + (getFullName() == null ? 0 : getFullName().hashCode());
101 		return result;
102 	}
103 	@Override
104 	public boolean equals(Object obj) {
105 		if (this == obj) {
106 			return true;
107 		}
108 		if (obj == null) {
109 			return false;
110 		}
111 		if (getClass() != obj.getClass()) {
112 			return false;
113 		}
114 		PropertyFormatter other = (PropertyFormatter) obj;
115 		if (getFullName() == null) {
116 			if (other.getFullName() != null) {
117 				return false;
118 			}
119 		} else if (!getFullName().equals(other.getFullName())) {
120 			return false;
121 		}
122 		return true;
123 	}
124 
125 	/**
126 	 * Returns a PropertyFormatter which extracts as a string a characteristic
127 	 * of a field.
128 	 * 
129 	 * @param getter
130 	 *            the method to extract the field from its object. Must be not
131 	 *            <code>null</code>.
132 	 * @param name
133 	 *            the field name
134 	 * @param propertyFormatter
135 	 *            the formatter to apply to the field, not to the owner object.
136 	 *            May be obtained from getPropertyReader or get
137 	 *            delegatePropertyReader methods.Must be not <code>null</code>.
138 	 * @return a new instance of PropertyFormatter
139 	 */
140 	public static PropertyFormatter getDelegatePropertyReader(Method getter, String name,
141 			PropertyFormatter propertyFormatter) {
142 
143 		if (getter == null) {
144 			throw new IllegalArgumentException(
145 					"PropertyFormatter#getDelegatePropertyReader  getter argument must ne not null");
146 		}
147 		if (propertyFormatter == null) {
148 			throw new IllegalArgumentException(
149 					"PropertyFormatter#getDelegatePropertyReader  propertyFormatter argument must be not null");
150 		}
151 
152 		return new DelegatePropertyReader(getter, name, propertyFormatter);
153 
154 	}
155 
156 	/**
157 	 * Returns a basic PropertyFormatter.
158 	 * 
159 	 * @param getter
160 	 *            the method to extract the field from the object. Must not be
161 	 *            <code>null</code>.
162 	 * @param name
163 	 *            the property name
164 	 * @param formatter
165 	 *            this formatter allows to transform the field into a string. if
166 	 *            the given argument is <code>null</code> a default formatter is
167 	 *            define which use the toString method of the field.
168 	 * @param filtre
169 	 *            it's possible to filtre the string rendered by the formatter
170 	 *            before to be returned
171 	 * @param <T>
172 	 *            the type of the property
173 	 * @return a new instance of PropertyFormatter
174 	 */
175 	public static <T> PropertyFormatter getPropertyReader(Method getter, String name, Formatter<T> formatter,
176 			AbstractStringFilter filtre) {
177 		if (getter == null) {
178 			throw new IllegalArgumentException("PropertyFormatter#getPropertyReader getter argument must be not null");
179 		}
180 
181 		return new PropertyReader(getter, name, (formatter == null ? new Formatter<T>() : formatter), filtre);
182 	}
183 
184 	/**
185 	 * 
186 	 * Allows to concate severals characteristics of an object into a single
187 	 * string.
188 	 * 
189 	 */
190 	private static final class ConcatePropertyReader extends PropertyFormatter {
191 
192 		/**
193 		 * 
194 		 * @param properties
195 		 *            The list of PropertyFormatter used to concate their
196 		 *            results.
197 		 * @param filtre
198 		 *            The filtre used to filter the concated strings.
199 		 */
200 		ConcatePropertyReader(List<PropertyFormatter> properties, AbstractStringFilter filtre) {
201 			super();
202 			this.properties = properties;
203 			this.filtre = filtre;
204 		}
205 
206 		/**
207 		 * The list of PropertyFormatter used to concate their results.
208 		 */
209 		private final List<PropertyFormatter> properties;
210 
211 		/**
212 		 * The filtre used to filter the concated strings.
213 		 */
214 		private final AbstractStringFilter filtre;
215 		@Override
216 		public String toString(Object object) {
217 			String retour = null;
218 			if (object != null) {
219 
220 				StringBuffer buf = new StringBuffer();
221 				for (PropertyFormatter property : properties) {
222 					String toBuf = property.toString(object);
223 					buf.append(toBuf == null ? "" : toBuf);
224 				}
225 				retour = (filtre == null ? buf.toString() : filtre.filtre(buf.toString()));
226 			}
227 			return retour;
228 		}
229 
230 		/**
231 		 * {@inheritDoc} Throws UnsupportedOperationException.
232 		 */
233 		@Override
234 		public String getName() {
235 			throw new UnsupportedOperationException();
236 		}
237 
238 		@Override
239 		public String getFullName() {
240 			StringBuilder builder = new StringBuilder();
241 
242 			for (PropertyFormatter property : properties) {
243 				builder.append(property.getFullName()).append(";");
244 			}
245 			return builder.toString();
246 		}
247 
248 	}
249 
250 	/**
251 	 * 
252 	 * PropertyFormatter to use to represent a characterstic of a field as a
253 	 * string.
254 	 * 
255 	 */
256 	private static final class DelegatePropertyReader extends PropertyFormatter {
257 
258 		/**
259 		 * 
260 		 * 
261 		 * @param getter
262 		 *            the method to invoke to get the property value.
263 		 * @param name
264 		 *            the property name.
265 		 * @param propertyFormatter
266 		 *            the formatter. format the property value as a string.
267 		 */
268 		DelegatePropertyReader(Method getter, String name, PropertyFormatter propertyFormatter) {
269 			super();
270 			this.getter = getter;
271 			this.name = name;
272 			this.propertyFormatter = propertyFormatter;
273 
274 		}
275 
276 		@Override
277 		public String getFullName() {
278 
279 			return name + "." + propertyFormatter.getFullName();
280 		}
281 
282 		@Override
283 		public String getName() {
284 
285 			return propertyFormatter.getName();
286 		}
287 
288 		/**
289 		 * The method to extract the field.
290 		 */
291 		private final Method getter;
292 		/**
293 		 * The propertyFormatter used to represents the field.
294 		 */
295 		private final PropertyFormatter propertyFormatter;
296 		@Override
297 		public String toString(Object object) {
298 			String retour = null;
299 			if (object != null) {
300 
301 				try {
302 					Object property = getter.invoke(object, (Object[]) null);
303 					retour = propertyFormatter.toString(property);
304 				} catch (IllegalArgumentException e) {
305 					throw new PropertyException("Error on method invocation  " + getter.getName(), e); // NOPMD
306 																										// by
307 																										// olivier
308 																										// on
309 																										// 01/02/12
310 																										// 00:34
311 				} catch (IllegalAccessException e) {
312 					throw new PropertyException("Error on method invocation  " + getter.getName(), e);
313 				} catch (InvocationTargetException e) {
314 					throw new PropertyException("Error on method invocation  " + getter.getName(), // NOPMD
315 																									// by
316 																									// olivier
317 																									// on
318 																									// 28/01/12
319 																									// 14:05
320 							e.getTargetException());
321 				}
322 			}
323 			return retour;
324 		}
325 
326 	}
327 
328 	/**
329 	 * 
330 	 * Basic PropertyFormatter. Allow to represent a field as a string.
331 	 * 
332 	 */
333 	private static final class PropertyReader extends PropertyFormatter {
334 
335 		/**
336 		 * 
337 		 * @param name
338 		 *            the name of the field
339 		 * @param getter
340 		 *            the method to use to extract field of the object
341 		 * @param formatter
342 		 *            the formatter to use to transform the field into a string
343 		 * @param filtre
344 		 *            it's possible to use a filter after the field has bean
345 		 *            formatted
346 		 */
347 
348 		PropertyReader(Method getter, String name, @SuppressWarnings("rawtypes") Formatter formatter,
349 				AbstractStringFilter filtre) {
350 			super();
351 			this.name = name;
352 			this.getter = getter;
353 			this.formatter = formatter;
354 			this.filtre = filtre;
355 
356 		}
357 
358 		/**
359 		 * the method to use to extract property of the object.
360 		 */
361 		private final Method getter;
362 
363 		/**
364 		 * the formatter to use to transform the field into a string.
365 		 */
366 		@SuppressWarnings("rawtypes")
367 		private final Formatter formatter;
368 		/**
369 		 * The filter to use to filter the string the formatter returns.
370 		 */
371 		private final AbstractStringFilter filtre;
372 
373 		@SuppressWarnings("unchecked")
374 		@Override
375 		public String toString(Object object) {
376 			String retour = null;
377 			if (object != null) {
378 				try {
379 					Object property = getter.invoke(object, (Object[]) null);
380 					String rendered = formatter.toString(property);
381 					retour = (filtre == null ? rendered : filtre.filtre(rendered));
382 
383 				} catch (IllegalArgumentException e) {
384 					throw new PropertyException("Error on method invocation  " + getter.getName(), e);
385 				} catch (IllegalAccessException e) {
386 					throw new PropertyException("Error on method invocation  " + getter.getName(), e);
387 				} catch (InvocationTargetException e) {
388 					throw new PropertyException("Error on method invocation  " + getter.getName(), // NOPMD
389 																									// by
390 																									// olivier
391 																									// on
392 																									// 28/01/12
393 																									// 14:05
394 							e.getTargetException());
395 				}
396 			}
397 			return retour;
398 		}
399 
400 	}
401 
402 }