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 {
033 private static final Map _classAdaptors = new HashMap();
034
035 // Prevent instantiation
036 private PropertyUtils()
037 {
038 }
039
040 /**
041 * Updates the property of the target object.
042 *
043 * @param target
044 * the object to update
045 * @param propertyName
046 * the name of the property to be updated
047 * @param value
048 * the value to be stored into the target object property
049 */
050 public static void write(Object target, String propertyName, Object value)
051 {
052 ClassAdaptor a = getAdaptor(target);
053
054 a.write(target, propertyName, value);
055 }
056
057 /**
058 * An improved version of {@link #write(Object, String, Object)} where the value starts as a
059 * string and is converted to the correct property type before being assigned.
060 *
061 * @since 1.1
062 */
063 public static void smartWrite(Object target, String propertyName, String value)
064 {
065 ClassAdaptor a = getAdaptor(target);
066
067 a.smartWrite(target, propertyName, value);
068 }
069
070 /**
071 * Initializes the properties of an object from a string. The string is a comma-seperated
072 * sequence of property names and values. Property names are seperated from values be an equals
073 * sign. Spaces before and after the property names are trimmed.
074 * For boolean properties, the equals sign and value may be omitted (a value of true is
075 * assumed), or the property name may be prefixed with an exclamation point to indicated false
076 * value. Example: <code>validate,maxLength=10,displayName=User Id</code>.
077 *
078 * @param target
079 * the object to be configured
080 * @param initializer
081 * the string encoding the properties and values to be configured in the target
082 * object
083 * @since 1.1
084 */
085
086 public static void configureProperties(Object target, String initializer)
087 {
088 ClassAdaptor a = getAdaptor(target);
089
090 a.configureProperties(target, initializer);
091 }
092
093 /**
094 * Returns true of the instance contains a writable property of the given type.
095 *
096 * @param target
097 * the object to inspect
098 * @param propertyName
099 * the name of the property to check
100 */
101
102 public static boolean isWritable(Object target, String propertyName)
103 {
104 return getAdaptor(target).isWritable(propertyName);
105 }
106
107 public static boolean isReadable(Object target, String propertyName)
108 {
109 return getAdaptor(target).isReadable(propertyName);
110 }
111
112 /**
113 * Updates the property of the target object.
114 *
115 * @param target
116 * the object to update
117 * @param propertyName
118 * the name of a property toread
119 */
120
121 public static Object read(Object target, String propertyName)
122 {
123 ClassAdaptor a = getAdaptor(target);
124
125 return a.read(target, propertyName);
126 }
127
128 /**
129 * Returns the type of the named property.
130 *
131 * @param target
132 * the object to examine
133 * @param propertyName
134 * the name of the property to check
135 */
136 public static Class getPropertyType(Object target, String propertyName)
137 {
138 ClassAdaptor a = getAdaptor(target);
139
140 return a.getPropertyType(target, propertyName);
141 }
142
143 /**
144 * Returns the {@link PropertyAdaptor} for the given target object and property name.
145 *
146 * @throws ApplicationRuntimeException
147 * if the property does not exist.
148 */
149 public static PropertyAdaptor getPropertyAdaptor(Object target, String propertyName)
150 {
151 ClassAdaptor a = getAdaptor(target);
152
153 return a.getPropertyAdaptor(target, propertyName);
154 }
155
156 /**
157 * Returns an unordered List of the names of all readable properties of the target.
158 */
159 public static List getReadableProperties(Object target)
160 {
161 return getAdaptor(target).getReadableProperties();
162 }
163
164 /**
165 * Returns an unordered List of the names of all writable properties of the target.
166 */
167 public static List getWriteableProperties(Object target)
168 {
169 return getAdaptor(target).getWriteableProperties();
170 }
171
172 private static ClassAdaptor getAdaptor(Object target)
173 {
174 if (target == null)
175 throw new ApplicationRuntimeException(UtilMessages.nullObject());
176
177 Class targetClass = target.getClass();
178
179 synchronized (HiveMind.INTROSPECTOR_MUTEX)
180 {
181 ClassAdaptor result = (ClassAdaptor) _classAdaptors.get(targetClass);
182
183 if (result == null)
184 {
185 result = buildClassAdaptor(target, targetClass);
186 _classAdaptors.put(targetClass, result);
187 }
188
189 return result;
190 }
191 }
192
193 private static ClassAdaptor buildClassAdaptor(Object target, Class targetClass)
194 {
195 try
196 {
197 BeanInfo info = Introspector.getBeanInfo(targetClass);
198
199 return new ClassAdaptor(info.getPropertyDescriptors());
200 }
201 catch (Exception ex)
202 {
203 throw new ApplicationRuntimeException(UtilMessages.unableToIntrospect(targetClass, ex),
204 target, null, ex);
205 }
206 }
207
208 /**
209 * Clears all cached information. Invokes {@link Introspector#flushCaches()}.
210 */
211 public static void clearCache()
212 {
213 synchronized (HiveMind.INTROSPECTOR_MUTEX)
214 {
215 _classAdaptors.clear();
216 Introspector.flushCaches();
217 }
218 }
219
220 }