001: /*
002: The contents of this file are subject to the Common Public Attribution License
003: Version 1.0 (the "License"); you may not use this file except in compliance with
004: the License. You may obtain a copy of the License at
005: http://www.projity.com/license . The License is based on the Mozilla Public
006: License Version 1.1 but Sections 14 and 15 have been added to cover use of
007: software over a computer network and provide for limited attribution for the
008: Original Developer. In addition, Exhibit A has been modified to be consistent
009: with Exhibit B.
010:
011: Software distributed under the License is distributed on an "AS IS" basis,
012: WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
013: specific language governing rights and limitations under the License. The
014: Original Code is OpenProj. The Original Developer is the Initial Developer and
015: is Projity, Inc. All portions of the code written by Projity are Copyright (c)
016: 2006, 2007. All Rights Reserved. Contributors Projity, Inc.
017:
018: Alternatively, the contents of this file may be used under the terms of the
019: Projity End-User License Agreeement (the Projity License), in which case the
020: provisions of the Projity License are applicable instead of those above. If you
021: wish to allow use of your version of this file only under the terms of the
022: Projity License and not to allow others to use your version of this file under
023: the CPAL, indicate your decision by deleting the provisions above and replace
024: them with the notice and other provisions required by the Projity License. If
025: you do not delete the provisions above, a recipient may use your version of this
026: file under either the CPAL or the Projity License.
027:
028: [NOTE: The text of this license may differ slightly from the text of the notices
029: in Exhibits A and B of the license at http://www.projity.com/license. You should
030: use the latest text at http://www.projity.com/license for your modifications.
031: You may not remove this license text from the source files.]
032:
033: Attribution Information: Attribution Copyright Notice: Copyright © 2006, 2007
034: Projity, Inc. Attribution Phrase (not exceeding 10 words): Powered by OpenProj,
035: an open source solution from Projity. Attribution URL: http://www.projity.com
036: Graphic Image as provided in the Covered Code as file: openproj_logo.png with
037: alternatives listed on http://www.projity.com/logo
038:
039: Display of Attribution Information is required in Larger Works which are defined
040: in the CPAL as a work which combines Covered Code or portions thereof with code
041: not governed by the terms of the CPAL. However, in addition to the other notice
042: obligations, all copies of the Covered Code in Executable and Source Code form
043: distributed must, as a form of attribution of the original author, include on
044: each user interface screen the "OpenProj" logo visible to all users. The
045: OpenProj logo should be located horizontally aligned with the menu bar and left
046: justified on the top left of the screen adjacent to the File menu. The logo
047: must be at least 100 x 25 pixels. When users click on the "OpenProj" logo it
048: must direct them back to http://www.projity.com.
049: */
050: package com.projity.util;
051:
052: import java.lang.reflect.InvocationTargetException;
053: import java.lang.reflect.Method;
054: import java.util.Comparator;
055: import java.util.Date;
056: import java.util.HashMap;
057:
058: import org.apache.commons.beanutils.PropertyUtils;
059: import org.apache.commons.collections.comparators.ComparableComparator;
060:
061: import com.projity.datatype.Duration;
062: import com.projity.datatype.Money;
063: import com.projity.datatype.Rate;
064: import com.projity.datatype.TimeUnit;
065: import com.projity.datatype.Work;
066: import com.projity.field.Field;
067:
068: /**
069: * Utility functions for manipulating primitive types
070: */
071: public class ClassUtils {
072:
073: public static final Long defaultLong = new Long(0L);
074: public static final Double defaultDouble = new Double(0.0);
075: public static final Integer defaultInteger = new Integer(0);
076: public static final Float defaultFloat = new Float(0.0);
077: public static final Boolean defaultBoolean = new Boolean(false);
078: public static final String defaultString = new String();
079: public static final Rate defaultRate = new Rate(1.0D);
080: public static final Rate defaultUnitlessRate = new Rate(1,
081: TimeUnit.NON_TEMPORAL);
082:
083: /**
084: * Given a type, return its default value. If type is unknown, a new one is constructed
085: * @param clazz
086: * @return
087: */
088: public static Object getDefaultValueForType(Class clazz) {
089: if (clazz == String.class)
090: return defaultString;
091: else if (clazz == Double.class || clazz == Double.TYPE)
092: return defaultDouble;
093: else if (clazz == Integer.class || clazz == Integer.TYPE)
094: return defaultInteger;
095: else if (clazz == Long.class || clazz == Long.TYPE)
096: return defaultLong;
097: else if (clazz == Float.class || clazz == Float.TYPE)
098: return defaultFloat;
099: else if (clazz == Boolean.class)
100: return defaultBoolean;
101: else if (clazz == Rate.class)
102: return defaultRate;
103: else {
104: try {
105: System.out.println("making default for class" + clazz);
106: return clazz.newInstance();
107: } catch (InstantiationException e) {
108: e.printStackTrace();
109: } catch (IllegalAccessException e) {
110: e.printStackTrace();
111: }
112: return null;
113: }
114: }
115:
116: public static boolean isDefaultValue(Object value) {
117: return (value == defaultLong || value == defaultDouble
118: || value == defaultInteger || value == defaultFloat
119: || value == defaultString || value == Duration.ZERO
120: || value == defaultRate || value == DateTime
121: .getZeroDate());
122: }
123:
124: public static final Long LONG_MULTIPLE_VALUES = new Long(0L);
125: public static final Double DOUBLE_MULTIPLE_VALUES = new Double(0.0);
126: public static final Integer INTEGER_MULTIPLE_VALUES = new Integer(0);
127: public static final Float FLOAT_MULTIPLE_VALUES = new Float(0.0);
128: public static final Boolean BOOLEAN_MULTIPLE_VALUES = new Boolean(
129: false);
130: public static final String STRING_MULTIPLE_VALUES = new String();
131: public static final Double PERCENT_MULTIPLE_VALUES = new Double(
132: -9876543.21); // a never used value used as flag to indicate multiple values
133: public static final Rate RATE_MULTIPLE_VALUES = new Rate();
134:
135: /**
136: * Given a type, return a value that signifies that there are multiple values. This can occur in a dialog which works on multile objects at once. If type is unknown, a new one is constructed
137: * @param clazz
138: * @return
139: */
140: public static Object getMultipleValueForType(Class clazz) {
141: if (clazz == String.class)
142: return STRING_MULTIPLE_VALUES;
143: else if (clazz == Double.class || clazz == Double.TYPE)
144: return DOUBLE_MULTIPLE_VALUES;
145: else if (clazz == Integer.class || clazz == Integer.TYPE)
146: return INTEGER_MULTIPLE_VALUES;
147: else if (clazz == Long.class || clazz == Long.TYPE)
148: return LONG_MULTIPLE_VALUES;
149: else if (clazz == Float.class || clazz == Float.TYPE)
150: return FLOAT_MULTIPLE_VALUES;
151: else if (clazz == Boolean.class)
152: return BOOLEAN_MULTIPLE_VALUES;
153: else if (clazz == Rate.class)
154: return RATE_MULTIPLE_VALUES;
155: else {
156: try {
157: return clazz.newInstance();
158: } catch (InstantiationException e) {
159: } catch (IllegalAccessException e) {
160: }
161: return null;
162: }
163: }
164:
165: public static boolean isMultipleValue(Object value) {
166: if (value == null)
167: return false;
168: return (value == LONG_MULTIPLE_VALUES
169: || value == DOUBLE_MULTIPLE_VALUES
170: || value == INTEGER_MULTIPLE_VALUES
171: || value == FLOAT_MULTIPLE_VALUES
172: || value == STRING_MULTIPLE_VALUES
173: || value.equals(PERCENT_MULTIPLE_VALUES)
174: || value == RATE_MULTIPLE_VALUES
175: || value == Duration.ZERO || value == DateTime
176: .getZeroDate());
177: }
178:
179: /**
180: * Get the corresponding object class from a primitive class
181: * @param clazz primitive class
182: * @return Object class.
183: * @throws ClassCastException if class is unknown primitive
184: */
185: public static Class primitiveToObjectClass(Class clazz) {
186: // return MethodUtils.toNonPrimitiveClass(clazz);
187: if (clazz == Boolean.TYPE)
188: return Boolean.class;
189: else if (clazz == Character.TYPE)
190: return Character.class;
191: else if (clazz == Byte.TYPE)
192: return Byte.class;
193: else if (clazz == Short.TYPE)
194: return Short.class;
195: else if (clazz == Integer.TYPE)
196: return Integer.class;
197: else if (clazz == Long.TYPE)
198: return Long.class;
199: else if (clazz == Float.TYPE)
200: return Float.class;
201: else if (clazz == Double.TYPE)
202: return Double.class;
203: throw new ClassCastException("Cannot convert class" + clazz
204: + " to an object class");
205: }
206:
207: /**
208: * Convert a Double to an Object of a given class
209: * @param value Double value to convert
210: * @param clazz Class the class to convert to
211: * @return new object of the given class
212: * @throws IllegalArgumentException if the value is not convertible to the class
213: */
214: public static Object doubleToObject(Double value, Class clazz) {
215: if (clazz == Boolean.class)
216: return new Boolean(value.doubleValue() != 0.0);
217: else if (clazz == Byte.class)
218: return new Byte(value.byteValue());
219: else if (clazz == Short.class)
220: return new Short(value.shortValue());
221: else if (clazz == Integer.class)
222: return new Integer(value.intValue());
223: else if (clazz == Long.class)
224: return new Long(value.longValue());
225: else if (clazz == Float.class)
226: return new Float(value.floatValue());
227: else if (clazz == Double.class)
228: return value;
229: else if (clazz == Money.class)
230: return Money.getInstance(value.doubleValue());
231: else if (clazz == Duration.class)
232: return Duration.getInstanceFromDouble(value);
233: else if (clazz == Work.class)
234: return Work.getWorkInstanceFromDouble(value);
235:
236: throw new IllegalArgumentException("Class " + clazz
237: + " cannot be converted from a Double");
238: }
239:
240: public static java.lang.reflect.Field staticFieldFromFullName(
241: String nameAndField) {
242: int lastDot = nameAndField.lastIndexOf(".");
243: String className = nameAndField.substring(0, lastDot);
244: String fieldName = nameAndField.substring(lastDot + 1);
245: try {
246: return ClassUtils.forName(className).getDeclaredField(
247: fieldName);
248: } catch (SecurityException e) {
249: // TODO Auto-generated catch block
250: e.printStackTrace();
251: } catch (NoSuchFieldException e) {
252: // TODO Auto-generated catch block
253: e.printStackTrace();
254: } catch (ClassNotFoundException e) {
255: // TODO Auto-generated catch block
256: e.printStackTrace();
257: }
258: return null;
259: }
260:
261: public static Method staticVoidMethodFromFullName(
262: String nameAndField) {
263: return staticMethodFromFullName(nameAndField, null);
264: }
265:
266: public static Method staticMethodFromFullName(String nameAndField,
267: Class[] args) {
268: int lastDot = nameAndField.lastIndexOf(".");
269: String className = nameAndField.substring(0, lastDot);
270: String methodName = nameAndField.substring(lastDot + 1);
271: try {
272: return ClassUtils.forName(className).getDeclaredMethod(
273: methodName, args);
274: } catch (SecurityException e) {
275: // TODO Auto-generated catch block
276: e.printStackTrace();
277: } catch (ClassNotFoundException e) {
278: // TODO Auto-generated catch block
279: e.printStackTrace();
280: } catch (NoSuchMethodException e) {
281: // TODO Auto-generated catch block
282: e.printStackTrace();
283: }
284: return null;
285: }
286:
287: /**
288: * Set the array size of the custom field this applies to
289: * @param boundsField
290: */
291: public static void setStaticField(String field, int value) {
292: try {
293: staticFieldFromFullName(field).setInt(null, value);
294: } catch (IllegalArgumentException e) {
295: // TODO Auto-generated catch block
296: e.printStackTrace();
297: } catch (IllegalAccessException e) {
298: // TODO Auto-generated catch block
299: e.printStackTrace();
300: }
301: }
302:
303: public static void setStaticField(String field, String value) {
304: try {
305: staticFieldFromFullName(field).set(null, value);
306: } catch (IllegalArgumentException e) {
307: // TODO Auto-generated catch block
308: e.printStackTrace();
309: } catch (IllegalAccessException e) {
310: // TODO Auto-generated catch block
311: e.printStackTrace();
312: }
313: }
314:
315: /**
316: * Safe Class.forName. See http://radio.weblogs.com/0112098/stories/2003/02/12/classfornameIsEvil.html
317: * @param className
318: * @return
319: * @throws ClassNotFoundException
320: */
321: public static Class forName(String className)
322: throws ClassNotFoundException {
323: Class theClass = null;
324: try {
325: theClass = Class.forName(className, true, Thread
326: .currentThread().getContextClassLoader());
327: } catch (ClassNotFoundException e) {
328: theClass = Class.forName(className);
329: }
330: return theClass;
331: }
332:
333: public static boolean setSimpleProperty(Object bean, String name,
334: Object value) {
335: try {
336: PropertyUtils.setSimpleProperty(bean, name, value);
337: return true;
338: } catch (IllegalAccessException e) {
339: // TODO Auto-generated catch block
340: e.printStackTrace();
341: } catch (InvocationTargetException e) {
342: // TODO Auto-generated catch block
343: e.printStackTrace();
344: } catch (NoSuchMethodException e) {
345: // TODO Auto-generated catch block
346: e.printStackTrace();
347: }
348: return false;
349: }
350:
351: private static Class[] getterParams = new Class[] {};
352:
353: public static boolean isObjectReadOnly(Object object) {
354: if (object == null)
355: return false;
356: Boolean value = null;
357: try {
358: Method m = object.getClass().getMethod("isReadOnly",
359: getterParams);
360: if (m != null)
361: value = (Boolean) m.invoke(object, null);
362: } catch (IllegalArgumentException e) {
363: } catch (IllegalAccessException e) {
364: } catch (InvocationTargetException e) {
365: } catch (NoSuchMethodException e) {
366: }
367: return value != null && value.booleanValue();
368:
369: }
370:
371: private static Class[] fieldGetterParams = new Class[] { Field.class };
372:
373: public static boolean isObjectFieldReadOnly(Object object,
374: Field field) {
375: if (object == null)
376: return false;
377: Boolean value = null;
378: try {
379: Method m = object.getClass().getMethod("isReadOnly",
380: fieldGetterParams);
381: if (m != null)
382: value = (Boolean) m.invoke(object,
383: new Object[] { field });
384: } catch (IllegalArgumentException e) {
385: } catch (IllegalAccessException e) {
386: } catch (InvocationTargetException e) {
387: } catch (NoSuchMethodException e) {
388: }
389: return value != null && value.booleanValue();
390:
391: }
392:
393: private static HashMap<Class, Comparator> comparatorMap = null;
394: private static final Comparator defaultTextComparator = new Comparator() {
395: public int compare(Object o1, Object o2) {
396: return ("" + o1).compareTo("" + o2);
397: }
398: };
399:
400: public static Comparator getComparator(Class clazz) {
401: if (comparatorMap == null) {
402: comparatorMap = new HashMap<Class, Comparator>();
403: comparatorMap.put(String.class, new Comparator() {
404: public int compare(Object o1, Object o2) {
405: if (o1 == null)
406: return (o2 == null ? 0 : -1);
407: else if (o2 == null)
408: return 1;
409: return ((String) o1).compareTo((String) o2);
410: }
411: });
412: comparatorMap.put(Date.class, new Comparator() {
413: public int compare(Object o1, Object o2) {
414: if (o1 == null)
415: return (o2 == null ? 0 : -1);
416: else if (o2 == null)
417: return 1;
418: return ((Date) o1).compareTo((Date) o2);
419: }
420: });
421: comparatorMap.put(Integer.class, new Comparator() {
422: public int compare(Object o1, Object o2) {
423: if (o1 == null)
424: return (o2 == null ? 0 : -1);
425: else if (o2 == null)
426: return 1;
427: return ((Integer) o1).compareTo((Integer) o2);
428: }
429: });
430: comparatorMap.put(Long.class, new Comparator() {
431: public int compare(Object o1, Object o2) {
432: if (o1 == null)
433: return (o2 == null ? 0 : -1);
434: else if (o2 == null)
435: return 1;
436: return ((Long) o1).compareTo((Long) o2);
437: }
438: });
439: comparatorMap.put(Short.class, new Comparator() {
440: public int compare(Object o1, Object o2) {
441: if (o1 == null)
442: return (o2 == null ? 0 : -1);
443: else if (o2 == null)
444: return 1;
445: return ((Short) o1).compareTo((Short) o2);
446: }
447: });
448: comparatorMap.put(Float.class, new Comparator() {
449: public int compare(Object o1, Object o2) {
450: if (o1 == null)
451: return (o2 == null ? 0 : -1);
452: else if (o2 == null)
453: return 1;
454: return ((Float) o1).compareTo((Float) o2);
455: }
456: });
457: comparatorMap.put(Double.class, new Comparator() {
458: public int compare(Object o1, Object o2) {
459: if (o1 == null)
460: return (o2 == null ? 0 : -1);
461: else if (o2 == null)
462: return 1;
463: return ((Double) o1).compareTo((Double) o2);
464: }
465: });
466: comparatorMap.put(Byte.class, new Comparator() {
467: public int compare(Object o1, Object o2) {
468: if (o1 == null)
469: return (o2 == null ? 0 : -1);
470: else if (o2 == null)
471: return 1;
472: return ((Byte) o1).compareTo((Byte) o2);
473: }
474: });
475: comparatorMap.put(Boolean.class, new Comparator() {
476: public int compare(Object o1, Object o2) {
477: if (o1 == null)
478: return (o2 == null ? 0 : -1);
479: else if (o2 == null)
480: return 1;
481: return ((Boolean) o1).compareTo((Boolean) o2);
482: }
483: });
484: comparatorMap.put(Money.class, new Comparator() {
485: public int compare(Object o1, Object o2) {
486: if (o1 == null)
487: return (o2 == null ? 0 : -1);
488: else if (o2 == null)
489: return 1;
490: return ((Money) o1).compareTo((Money) o2);
491: }
492: });
493: comparatorMap.put(Duration.class, new Comparator() {
494: public int compare(Object o1, Object o2) {
495: if (o1 == null)
496: return (o2 == null ? 0 : -1);
497: else if (o2 == null)
498: return 1;
499: return ((Duration) o1).compareTo(o2);
500: }
501: });
502: comparatorMap.put(Work.class, new Comparator() {
503: public int compare(Object o1, Object o2) {
504: if (o1 == null)
505: return (o2 == null ? 0 : -1);
506: else if (o2 == null)
507: return 1;
508: return ((Work) o1).compareTo(o2);
509: }
510: });
511: comparatorMap.put(Rate.class, new Comparator() {
512: public int compare(Object o1, Object o2) {
513: if (o1 == null)
514: return (o2 == null ? 0 : -1);
515: else if (o2 == null)
516: return 1;
517: return ((Rate) o1).compareTo(o2);
518: }
519: });
520: }
521: Comparator result = comparatorMap.get(clazz);
522: if (result == null) { // in case none found, try comparing if the class is comparable
523: if (Comparable.class.isAssignableFrom(clazz))
524: return ComparableComparator.getInstance();
525: else
526: return defaultTextComparator;
527: }
528: return comparatorMap.get(clazz);
529:
530: }
531:
532: }
|