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.PropertyEditor; 018 import java.beans.PropertyEditorManager; 019 import java.lang.reflect.Constructor; 020 import java.lang.reflect.Method; 021 022 import org.apache.hivemind.ApplicationRuntimeException; 023 024 /** 025 * Used to manage dynamic access to a property of a specific class. 026 * 027 * @author Howard Lewis Ship 028 */ 029 public class PropertyAdaptor 030 { 031 private String _propertyName; 032 033 private Class _propertyType; 034 035 private Method _readMethod; 036 037 private Method _writeMethod; 038 039 PropertyAdaptor(String propertyName, Class propertyType, Method readMethod, Method writeMethod) 040 { 041 _propertyName = propertyName; 042 _propertyType = propertyType; 043 _readMethod = readMethod; 044 _writeMethod = writeMethod; 045 } 046 047 /** 048 * Returns the name of the method used to read the property, or null if the property is not 049 * readable. 050 */ 051 public String getReadMethodName() 052 { 053 return _readMethod == null ? null : _readMethod.getName(); 054 } 055 056 /** 057 * Returns the name of the method used to write the property, or null if the property is not 058 * writable. 059 */ 060 public String getWriteMethodName() 061 { 062 return _writeMethod == null ? null : _writeMethod.getName(); 063 } 064 065 public String getPropertyName() 066 { 067 return _propertyName; 068 } 069 070 public Class getPropertyType() 071 { 072 return _propertyType; 073 } 074 075 /** 076 * Updates the property of the target object. 077 * 078 * @param target 079 * the object to update 080 * @param value 081 * the value to be stored into the target object property 082 */ 083 public void write(Object target, Object value) 084 { 085 if (_writeMethod == null) 086 throw new ApplicationRuntimeException(UtilMessages.noPropertyWriter( 087 _propertyName, 088 target), target, null, null); 089 090 try 091 { 092 _writeMethod.invoke(target, new Object[] 093 { value }); 094 095 } 096 catch (Exception ex) 097 { 098 throw new ApplicationRuntimeException(UtilMessages.writeFailure( 099 _propertyName, 100 target, 101 ex), target, null, ex); 102 } 103 } 104 105 public void smartWrite(Object target, String value) 106 { 107 Object convertedValue = convertValueForAssignment(target, value); 108 109 write(target, convertedValue); 110 } 111 112 /** @since 1.1 */ 113 private Object convertValueForAssignment(Object target, String value) 114 { 115 if (value == null || _propertyType.isInstance(value)) 116 return value; 117 118 PropertyEditor e = PropertyEditorManager.findEditor(_propertyType); 119 120 if (e == null) 121 { 122 Object convertedValue = instantiateViaStringConstructor(target, value); 123 124 if (convertedValue != null) 125 return convertedValue; 126 127 throw new ApplicationRuntimeException(UtilMessages.noPropertyEditor( 128 _propertyName, 129 target.getClass())); 130 } 131 132 try 133 { 134 e.setAsText(value); 135 136 return e.getValue(); 137 } 138 catch (Exception ex) 139 { 140 throw new ApplicationRuntimeException(UtilMessages.unableToConvert( 141 value, 142 _propertyType, 143 _propertyName, 144 target, 145 ex), null, ex); 146 } 147 } 148 149 /** 150 * Checks to see if this adaptor's property type has a public constructor that takes a single 151 * String argument. 152 */ 153 154 private Object instantiateViaStringConstructor(Object target, String value) 155 { 156 try 157 { 158 Constructor c = _propertyType.getConstructor(new Class[] 159 { String.class }); 160 161 return c.newInstance(new Object[] 162 { value }); 163 } 164 catch (Exception ex) 165 { 166 return null; 167 } 168 } 169 170 /** 171 * Returns true if there's a write method for the property. 172 */ 173 public boolean isWritable() 174 { 175 return _writeMethod != null; 176 } 177 178 /** 179 * Reads the property of the target object. 180 * 181 * @param target 182 * the object to read a property from 183 */ 184 public Object read(Object target) 185 { 186 if (_readMethod == null) 187 throw new ApplicationRuntimeException(UtilMessages.noReader(_propertyName, target), 188 target, null, null); 189 190 try 191 { 192 return _readMethod.invoke(target, (Object []) null); 193 194 } 195 catch (Exception ex) 196 { 197 throw new ApplicationRuntimeException(UtilMessages.readFailure( 198 _propertyName, 199 target, 200 ex), target, null, ex); 201 } 202 } 203 204 /** 205 * Returns true if there's a read method for the property. 206 */ 207 208 public boolean isReadable() 209 { 210 return _readMethod != null; 211 } 212 213 }