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, 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    }