001: // Copyright 2004, 2005 The Apache Software Foundation
002: //
003: // Licensed under the Apache License, Version 2.0 (the "License");
004: // you may not use this file except in compliance with the License.
005: // You may obtain a copy of the License at
006: //
007: // http://www.apache.org/licenses/LICENSE-2.0
008: //
009: // Unless required by applicable law or agreed to in writing, software
010: // distributed under the License is distributed on an "AS IS" BASIS,
011: // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: // See the License for the specific language governing permissions and
013: // limitations under the License.
014:
015: package org.apache.hivemind.util;
016:
017: import java.beans.BeanInfo;
018: import java.beans.Introspector;
019: import java.util.HashMap;
020: import java.util.List;
021: import java.util.Map;
022:
023: import org.apache.hivemind.ApplicationRuntimeException;
024: import org.apache.hivemind.HiveMind;
025:
026: /**
027: * A collection of static methods used to perform property-level access on arbitrary objects.
028: *
029: * @author Howard Lewis Ship
030: */
031: public class PropertyUtils {
032: private static final Map _classAdaptors = new HashMap();
033:
034: // Prevent instantiation
035: private PropertyUtils() {
036: }
037:
038: /**
039: * Updates the property of the target object.
040: *
041: * @param target
042: * the object to update
043: * @param propertyName
044: * the name of the property to be updated
045: * @param value
046: * the value to be stored into the target object property
047: */
048: public static void write(Object target, String propertyName,
049: Object value) {
050: ClassAdaptor a = getAdaptor(target);
051:
052: a.write(target, propertyName, value);
053: }
054:
055: /**
056: * An improved version of {@link #write(Object, String, Object)} where the value starts as a
057: * string and is converted to the correct property type before being assigned.
058: *
059: * @since 1.1
060: */
061: public static void smartWrite(Object target, String propertyName,
062: String value) {
063: ClassAdaptor a = getAdaptor(target);
064:
065: a.smartWrite(target, propertyName, value);
066: }
067:
068: /**
069: * Initializes the properties of an object from a string. The string is a comma-seperated
070: * sequence of property names and values. Property names are seperated from values be an equals
071: * sign. Spaces before and after the property names are trimmed.
072: * For boolean properties, the equals sign and value may be omitted (a value of true is
073: * assumed), or the property name may be prefixed with an exclamation point to indicated false
074: * value. Example: <code>validate,maxLength=10,displayName=User Id</code>.
075: *
076: * @param target
077: * the object to be configured
078: * @param initializer
079: * the string encoding the properties and values to be configured in the target
080: * object
081: * @since 1.1
082: */
083:
084: public static void configureProperties(Object target,
085: String initializer) {
086: ClassAdaptor a = getAdaptor(target);
087:
088: a.configureProperties(target, initializer);
089: }
090:
091: /**
092: * Returns true of the instance contains a writable property of the given type.
093: *
094: * @param target
095: * the object to inspect
096: * @param propertyName
097: * the name of the property to check
098: */
099:
100: public static boolean isWritable(Object target, String propertyName) {
101: return getAdaptor(target).isWritable(propertyName);
102: }
103:
104: public static boolean isReadable(Object target, String propertyName) {
105: return getAdaptor(target).isReadable(propertyName);
106: }
107:
108: /**
109: * Updates the property of the target object.
110: *
111: * @param target
112: * the object to update
113: * @param propertyName
114: * the name of a property toread
115: */
116:
117: public static Object read(Object target, String propertyName) {
118: ClassAdaptor a = getAdaptor(target);
119:
120: return a.read(target, propertyName);
121: }
122:
123: /**
124: * Returns the type of the named property.
125: *
126: * @param target
127: * the object to examine
128: * @param propertyName
129: * the name of the property to check
130: */
131: public static Class getPropertyType(Object target,
132: String propertyName) {
133: ClassAdaptor a = getAdaptor(target);
134:
135: return a.getPropertyType(target, propertyName);
136: }
137:
138: /**
139: * Returns the {@link PropertyAdaptor} for the given target object and property name.
140: *
141: * @throws ApplicationRuntimeException
142: * if the property does not exist.
143: */
144: public static PropertyAdaptor getPropertyAdaptor(Object target,
145: String propertyName) {
146: ClassAdaptor a = getAdaptor(target);
147:
148: return a.getPropertyAdaptor(target, propertyName);
149: }
150:
151: /**
152: * Returns an unordered List of the names of all readable properties of the target.
153: */
154: public static List getReadableProperties(Object target) {
155: return getAdaptor(target).getReadableProperties();
156: }
157:
158: /**
159: * Returns an unordered List of the names of all writable properties of the target.
160: */
161: public static List getWriteableProperties(Object target) {
162: return getAdaptor(target).getWriteableProperties();
163: }
164:
165: private static ClassAdaptor getAdaptor(Object target) {
166: if (target == null)
167: throw new ApplicationRuntimeException(UtilMessages
168: .nullObject());
169:
170: Class targetClass = target.getClass();
171:
172: synchronized (HiveMind.INTROSPECTOR_MUTEX) {
173: ClassAdaptor result = (ClassAdaptor) _classAdaptors
174: .get(targetClass);
175:
176: if (result == null) {
177: result = buildClassAdaptor(target, targetClass);
178: _classAdaptors.put(targetClass, result);
179: }
180:
181: return result;
182: }
183: }
184:
185: private static ClassAdaptor buildClassAdaptor(Object target,
186: Class targetClass) {
187: try {
188: BeanInfo info = Introspector.getBeanInfo(targetClass);
189:
190: return new ClassAdaptor(info.getPropertyDescriptors());
191: } catch (Exception ex) {
192: throw new ApplicationRuntimeException(UtilMessages
193: .unableToIntrospect(targetClass, ex), target, null,
194: ex);
195: }
196: }
197:
198: /**
199: * Clears all cached information. Invokes {@link Introspector#flushCaches()}.
200: */
201: public static void clearCache() {
202: synchronized (HiveMind.INTROSPECTOR_MUTEX) {
203: _classAdaptors.clear();
204: Introspector.flushCaches();
205: }
206: }
207:
208: }
|