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 }