001: /*
002: * Copyright 2007 The Kuali Foundation.
003: *
004: * Licensed under the Educational Community License, Version 1.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.opensource.org/licenses/ecl1.php
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.kuali.module.labor.util;
017:
018: import java.math.BigDecimal;
019: import java.sql.Date;
020: import java.sql.Timestamp;
021: import java.util.ArrayList;
022: import java.util.Arrays;
023: import java.util.LinkedHashMap;
024: import java.util.List;
025: import java.util.Map;
026: import java.util.Properties;
027:
028: import org.apache.commons.beanutils.DynaClass;
029: import org.apache.commons.beanutils.DynaProperty;
030: import org.apache.commons.beanutils.PropertyUtils;
031: import org.apache.commons.beanutils.WrapDynaClass;
032: import org.apache.commons.lang.ObjectUtils;
033: import org.apache.commons.lang.StringUtils;
034: import org.kuali.core.bo.PersistableBusinessObjectBase;
035: import org.kuali.core.util.KualiDecimal;
036:
037: /**
038: * This class provides a set of facilities that can be used to manipulate objects, for example, object population
039: */
040: public class ObjectUtil {
041: private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger
042: .getLogger(ObjectUtil.class);
043:
044: /**
045: * Populate the given fields of the target object with the corresponding field values of source object
046: *
047: * @param targetObject the target object
048: * @param sourceObject the source object
049: * @param keyFields the given fields of the target object that need to be popluated
050: */
051: public static void buildObject(Object targetObject,
052: Object sourceObject, List<String> keyFields) {
053: if (sourceObject.getClass().isArray()) {
054: buildObject(targetObject, sourceObject, keyFields);
055: return;
056: }
057:
058: for (String propertyName : keyFields) {
059: if (PropertyUtils.isReadable(sourceObject, propertyName)
060: && PropertyUtils.isWriteable(targetObject,
061: propertyName)) {
062: try {
063: Object propertyValue = PropertyUtils.getProperty(
064: sourceObject, propertyName);
065: PropertyUtils.setProperty(targetObject,
066: propertyName, propertyValue);
067: } catch (Exception e) {
068: LOG.debug(e);
069: }
070: }
071: }
072: }
073:
074: /**
075: * Populate the given fields of the target object with the values of an array
076: *
077: * @param targetObject the target object
078: * @param sourceObject the given array
079: * @param keyFields the given fields of the target object that need to be popluated
080: */
081: public static void buildObject(Object targetObject,
082: Object[] sourceObject, List<String> keyFields) {
083: int indexOfArray = 0;
084: for (String propertyName : keyFields) {
085: if (PropertyUtils.isWriteable(targetObject, propertyName)
086: && indexOfArray < sourceObject.length) {
087: try {
088: Object value = sourceObject[indexOfArray];
089: String propertyValue = value != null ? value
090: .toString() : "";
091:
092: String type = PropertyUtils.getPropertyType(
093: targetObject, propertyName).getSimpleName();
094: Object realPropertyValue = valueOf(type,
095: propertyValue);
096:
097: if (realPropertyValue != null
098: && !StringUtils.isEmpty(realPropertyValue
099: .toString())) {
100: PropertyUtils.setProperty(targetObject,
101: propertyName, realPropertyValue);
102: } else {
103: PropertyUtils.setProperty(targetObject,
104: propertyName, null);
105: }
106: } catch (Exception e) {
107: LOG.debug(e);
108: }
109: }
110: indexOfArray++;
111: }
112: }
113:
114: /**
115: * Get an object of the given type holding the property value of the specified String.
116: *
117: * @param type the given type of the returning object
118: * @param propertyValue the property value of the specified string
119: * @return an object of the given type holding the property value of the specified String
120: */
121: public static Object valueOf(String type, String propertyValue) {
122: Object realPropertyValue = null;
123:
124: if (type.equals("Integer")) {
125: realPropertyValue = isInteger(propertyValue) ? Integer
126: .valueOf(propertyValue) : null;
127: } else if (type.equals("Boolean")) {
128: realPropertyValue = Boolean.valueOf(propertyValue);
129: } else if (type.equals("KualiDecimal")) {
130: realPropertyValue = isDecimal(propertyValue) ? new KualiDecimal(
131: propertyValue)
132: : null;
133: } else if (type.equals("Date")) {
134: realPropertyValue = formatDate(propertyValue);
135: } else if (type.equals("BigDecimal")) {
136: realPropertyValue = isDecimal(propertyValue) ? new BigDecimal(
137: propertyValue)
138: : null;
139: } else if (type.equals("Timestamp")) {
140: realPropertyValue = formatTimeStamp(propertyValue);
141: } else {
142: realPropertyValue = propertyValue;
143: }
144: return realPropertyValue;
145: }
146:
147: /**
148: * determine if the given string can be converted into an Integer
149: *
150: * @param value the value of the specified string
151: * @return true if the string can be converted into an Integer; otherwise, return false
152: */
153: public static boolean isInteger(String value) {
154: String pattern = "^(\\+|-)?\\d+$";
155: return value != null && value.matches(pattern);
156: }
157:
158: /**
159: * determine if the given string can be converted into a decimal
160: *
161: * @param value the value of the specified string
162: * @return true if the string can be converted into a decimal; otherwise, return false
163: */
164: public static boolean isDecimal(String value) {
165: String pattern = "^(((\\+|-)?\\d+(\\.\\d*)?)|((\\+|-)?(\\d*\\.)?\\d+))$";
166: return value != null && value.matches(pattern);
167: }
168:
169: public static Date formatDate(String value) {
170: Date formattedDate = null;
171:
172: try {
173: formattedDate = Date.valueOf(value);
174: } catch (Exception e) {
175: return formattedDate;
176: }
177: return formattedDate;
178: }
179:
180: public static Timestamp formatTimeStamp(String value) {
181: Timestamp formattedTimestamp = null;
182:
183: String pattern = "^(\\d{1,4}-\\d{1,2}-\\d{1,2} \\d{1,2}:\\d{1,2}:\\d{1,2}(\\.\\d{1,9})?)$";
184: boolean isTimestamp = value != null && value.matches(pattern);
185:
186: try {
187: if (isTimestamp) {
188: formattedTimestamp = Timestamp.valueOf(value);
189: } else {
190: formattedTimestamp = new Timestamp(formatDate(value)
191: .getTime());
192: }
193: } catch (Exception e) {
194: return formattedTimestamp;
195: }
196: return formattedTimestamp;
197: }
198:
199: /**
200: * Populate the target object with the source object
201: *
202: * @param targetObject the target object
203: * @param sourceObject the source object
204: */
205: public static void buildObject(Object targetObject,
206: Object sourceObject) {
207: DynaClass dynaClass = WrapDynaClass
208: .createDynaClass(targetObject.getClass());
209: DynaProperty[] properties = dynaClass.getDynaProperties();
210:
211: for (DynaProperty property : properties) {
212: String propertyName = property.getName();
213: if (PersistableBusinessObjectBase.class
214: .isAssignableFrom(property.getClass())) {
215: continue;
216: }
217:
218: if (PropertyUtils.isReadable(sourceObject, propertyName)
219: && PropertyUtils.isWriteable(targetObject,
220: propertyName)) {
221: try {
222: Object propertyValue = PropertyUtils.getProperty(
223: sourceObject, propertyName);
224: PropertyUtils.setProperty(targetObject,
225: propertyName, propertyValue);
226: } catch (Exception e) {
227: LOG.debug(e + propertyName);
228: }
229: }
230: }
231: }
232:
233: /**
234: * Determine if they have the same values in the specified fields
235: *
236: * @param targetObject the target object
237: * @param sourceObject the source object
238: * @param keyFields the specified fields
239: * @return true if the two objects have the same values in the specified fields; otherwise, false
240: */
241: public static boolean compareObject(Object targetObject,
242: Object sourceObject, List<String> keyFields) {
243: if (targetObject == sourceObject) {
244: return true;
245: }
246:
247: if (targetObject == null || sourceObject == null) {
248: return false;
249: }
250:
251: for (String propertyName : keyFields) {
252: try {
253: Object propertyValueOfSource = PropertyUtils
254: .getProperty(sourceObject, propertyName);
255: Object propertyValueOfTarget = PropertyUtils
256: .getProperty(targetObject, propertyName);
257:
258: if (!ObjectUtils.equals(propertyValueOfSource,
259: propertyValueOfTarget)) {
260: return false;
261: }
262: } catch (Exception e) {
263: LOG.info(e);
264: return false;
265: }
266: }
267: return true;
268: }
269:
270: /**
271: * This method builds a map of business object with its specified property names and corresponding values
272: *
273: * @param businessObject the given business object
274: * @param the specified fields that need to be included in the return map
275: * @return the map of business object with its property names and values
276: */
277: public static Map<String, Object> buildPropertyMap(Object object,
278: List<String> keyFields) {
279: DynaClass dynaClass = WrapDynaClass.createDynaClass(object
280: .getClass());
281: DynaProperty[] properties = dynaClass.getDynaProperties();
282: Map<String, Object> propertyMap = new LinkedHashMap<String, Object>();
283:
284: for (DynaProperty property : properties) {
285: String propertyName = property.getName();
286:
287: if (PropertyUtils.isReadable(object, propertyName)
288: && keyFields.contains(propertyName)) {
289: try {
290: Object propertyValue = PropertyUtils.getProperty(
291: object, propertyName);
292:
293: if (propertyValue != null
294: && !StringUtils.isEmpty(propertyValue
295: .toString())) {
296: propertyMap.put(propertyName, propertyValue);
297: }
298: } catch (Exception e) {
299: LOG.info(e);
300: }
301: }
302: }
303: return propertyMap;
304: }
305:
306: /**
307: * Tokenize the input line with the given deliminator and populate the given object with values of the tokens
308: *
309: * @param targetObject the target object
310: * @param line the input line
311: * @param delim the deminator that separates the fields in the given line
312: * @param keyFields the specified fields
313: */
314: public static void convertLineToBusinessObject(Object targetObject,
315: String line, String delim, List<String> keyFields) {
316: String[] tokens = StringUtils.split(line, delim);
317: ObjectUtil.buildObject(targetObject, tokens, keyFields);
318: }
319:
320: /**
321: * Tokenize the input line with the given deliminator and populate the given object with values of the tokens
322: *
323: * @param targetObject the target object
324: * @param line the input line
325: * @param delim the deminator that separates the fields in the given line
326: * @param keyFields the specified fields
327: */
328: public static void convertLineToBusinessObject(Object targetObject,
329: String line, String delim, String fieldNames) {
330: List<String> tokens = split(line, delim);
331: List<String> keyFields = Arrays.asList(StringUtils.split(
332: fieldNames, delim));
333: ObjectUtil.buildObject(targetObject, tokens.toArray(),
334: keyFields);
335: }
336:
337: /**
338: * Tokenize the input line with the given deliminator and populate the given object with values of the tokens
339: *
340: * @param targetObject the target object
341: * @param line the input line
342: * @param delim the deminator that separates the fields in the given line
343: * @param keyFields the specified fields
344: */
345: public static List<String> split(String line, String delim) {
346: List<String> tokens = new ArrayList<String>();
347:
348: int currentPosition = 0;
349: for (int step = 0; step < line.length(); step++) {
350: int previousPosition = currentPosition;
351: currentPosition = StringUtils.indexOf(line, delim,
352: currentPosition);
353: currentPosition = currentPosition == -1 ? line.length() - 1
354: : currentPosition;
355:
356: String sub = line.substring(previousPosition,
357: currentPosition);
358: tokens.add(sub); // don't trim the string
359:
360: currentPosition += delim.length();
361: if (currentPosition >= line.length()) {
362: break;
363: }
364: }
365: return tokens;
366: }
367:
368: /**
369: * Tokenize the input line with the given deliminator and populate the given object with values of the tokens
370: *
371: * @param targetObject the target object
372: * @param line the input line
373: * @param delim the deminator that separates the fields in the given line
374: * @param keyFields the specified fields
375: */
376: public static void convertLineToBusinessObject(Object targetObject,
377: String line, int[] fieldLength, List<String> keyFields) {
378: String[] tokens = new String[fieldLength.length];
379:
380: int currentPosition = 0;
381: for (int i = 0; i < fieldLength.length; i++) {
382: currentPosition = i <= 0 ? 0 : fieldLength[i - 1]
383: + currentPosition;
384: tokens[i] = StringUtils.mid(line, currentPosition,
385: fieldLength[i]).trim();
386: }
387: ObjectUtil.buildObject(targetObject, tokens, keyFields);
388: }
389:
390: /**
391: * Populate a business object with the given properities and information
392: *
393: * @param businessOjbject the business object to be populated
394: * @param properties the given properties
395: * @param propertyKey the property keys in the properties
396: * @param fieldNames the names of the fields to be populated
397: * @param deliminator the deliminator that separates the values to be used in a string
398: */
399: public static void populateBusinessObject(Object businessOjbject,
400: Properties properties, String propertyKey,
401: String fieldNames, String deliminator) {
402: String data = properties.getProperty(propertyKey);
403: ObjectUtil.convertLineToBusinessObject(businessOjbject, data,
404: deliminator, fieldNames);
405: }
406:
407: /**
408: * Populate a business object with the given properities and information
409: *
410: * @param businessOjbject the business object to be populated
411: * @param properties the given properties
412: * @param propertyKey the property keys in the properties
413: * @param fieldNames the names of the fields to be populated
414: * @param deliminator the deliminator that separates the values to be used in a string
415: */
416: public static void populateBusinessObject(Object businessOjbject,
417: Properties properties, String propertyKey,
418: int[] fieldLength, List<String> keyFields) {
419: String data = properties.getProperty(propertyKey);
420: ObjectUtil.convertLineToBusinessObject(businessOjbject, data,
421: fieldLength, keyFields);
422: }
423:
424: /**
425: * determine if the source object has a field with null as its value
426: *
427: * @param sourceObject the source object
428: */
429: public static boolean hasNullValueField(Object sourceObject) {
430: DynaClass dynaClass = WrapDynaClass
431: .createDynaClass(sourceObject.getClass());
432: DynaProperty[] properties = dynaClass.getDynaProperties();
433:
434: for (DynaProperty property : properties) {
435: String propertyName = property.getName();
436:
437: if (PropertyUtils.isReadable(sourceObject, propertyName)) {
438: try {
439: Object propertyValue = PropertyUtils.getProperty(
440: sourceObject, propertyName);
441: if (propertyValue == null) {
442: return true;
443: }
444: } catch (Exception e) {
445: LOG.info(e);
446: return false;
447: }
448: }
449: }
450: return false;
451: }
452: }
|