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 }