1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package java.beans;
19
20import java.lang.reflect.Method;
21import java.lang.reflect.Modifier;
22import org.apache.harmony.beans.internal.nls.Messages;
23
24public class IndexedPropertyDescriptor extends PropertyDescriptor {
25    private Method indexedGetter;
26
27    private Method indexedSetter;
28
29    public IndexedPropertyDescriptor(String propertyName, Class<?> beanClass,
30            String getterName, String setterName, String indexedGetterName,
31            String indexedSetterName) throws IntrospectionException {
32        super(propertyName, beanClass, getterName, setterName);
33
34        // RI behaves like this
35        if (indexedGetterName == null && indexedSetterName == null &&
36                (getterName != null || setterName != null)) {
37            throw new IntrospectionException(Messages.getString("beans.50"));
38        }
39        setIndexedReadMethod(beanClass, indexedGetterName);
40        setIndexedWriteMethod(beanClass, indexedSetterName);
41    }
42
43    public IndexedPropertyDescriptor(String propertyName, Method getter, Method setter,
44            Method indexedGetter, Method indexedSetter) throws IntrospectionException {
45        super(propertyName, getter, setter);
46
47        // we need this in order to be compatible with RI
48        if (indexedGetter == null && indexedSetter == null &&
49                (getter != null || setter != null)) {
50            throw new IntrospectionException(Messages.getString("beans.50"));
51        }
52        setIndexedReadMethod(indexedGetter);
53        setIndexedWriteMethod(indexedSetter);
54    }
55
56    public IndexedPropertyDescriptor(String propertyName, Class<?> beanClass)
57            throws IntrospectionException {
58        super(propertyName, beanClass, null, null);
59        String getterName;
60        String setterName;
61        String indexedGetterName;
62        String indexedSetterName;
63
64        // array getter
65        getterName = createDefaultMethodName(propertyName, "get"); //$NON-NLS-1$
66        if (hasMethod(beanClass, getterName)) {
67            setReadMethod(beanClass, getterName);
68        }
69        // array setter
70        setterName = createDefaultMethodName(propertyName, "set"); //$NON-NLS-1$
71        if (hasMethod(beanClass, setterName)) {
72            setWriteMethod(beanClass, setterName);
73        }
74        // indexed getter
75        indexedGetterName = createDefaultMethodName(propertyName, "get"); //$NON-NLS-1$
76        if (hasMethod(beanClass, indexedGetterName)) {
77            setIndexedReadMethod(beanClass, indexedGetterName);
78        }
79        // indexed setter
80        indexedSetterName = createDefaultMethodName(propertyName, "set"); //$NON-NLS-1$
81        if (hasMethod(beanClass, indexedSetterName)) {
82            setIndexedWriteMethod(beanClass, indexedSetterName);
83        }
84        // RI seems to behave a bit differently
85        if (indexedGetter == null && indexedSetter == null &&
86                getReadMethod() == null && getWriteMethod() == null) {
87            throw new IntrospectionException(
88                    Messages.getString("beans.01", propertyName)); //$NON-NLS-1$
89        }
90        if (indexedGetter == null && indexedSetter == null) {
91            // not an indexed property indeed
92            throw new IntrospectionException(Messages.getString("beans.50"));
93        }
94    }
95
96    public void setIndexedReadMethod(Method indexedGetter) throws IntrospectionException {
97        if (indexedGetter != null) {
98            int modifiers = indexedGetter.getModifiers();
99            Class<?>[] parameterTypes;
100            Class<?> returnType;
101            Class<?> indexedPropertyType;
102
103            if (!Modifier.isPublic(modifiers)) {
104                throw new IntrospectionException(Messages.getString("beans.21")); //$NON-NLS-1$
105            }
106            parameterTypes = indexedGetter.getParameterTypes();
107            if (parameterTypes.length != 1) {
108                throw new IntrospectionException(Messages.getString("beans.22")); //$NON-NLS-1$
109            }
110            if (!parameterTypes[0].equals(int.class)) {
111                throw new IntrospectionException(Messages.getString("beans.23")); //$NON-NLS-1$
112            }
113            returnType = indexedGetter.getReturnType();
114            indexedPropertyType = getIndexedPropertyType();
115            if ((indexedPropertyType != null) && !returnType.equals(indexedPropertyType)) {
116                throw new IntrospectionException(Messages.getString("beans.24")); //$NON-NLS-1$
117            }
118        }
119        this.indexedGetter = indexedGetter;
120    }
121
122    public void setIndexedWriteMethod(Method indexedSetter) throws IntrospectionException {
123        if (indexedSetter != null) {
124            int modifiers = indexedSetter.getModifiers();
125            Class<?>[] parameterTypes;
126            Class<?> firstParameterType;
127            Class<?> secondParameterType;
128            Class<?> propType;
129
130            if (!Modifier.isPublic(modifiers)) {
131                throw new IntrospectionException(Messages.getString("beans.25")); //$NON-NLS-1$
132            }
133            parameterTypes = indexedSetter.getParameterTypes();
134            if (parameterTypes.length != 2) {
135                throw new IntrospectionException(Messages.getString("beans.26")); //$NON-NLS-1$
136            }
137            firstParameterType = parameterTypes[0];
138            if (!firstParameterType.equals(int.class)) {
139                throw new IntrospectionException(Messages.getString("beans.27")); //$NON-NLS-1$
140            }
141            secondParameterType = parameterTypes[1];
142            propType = getIndexedPropertyType();
143            if (propType != null && !secondParameterType.equals(propType)) {
144                throw new IntrospectionException(Messages.getString("beans.28")); //$NON-NLS-1$
145            }
146        }
147        this.indexedSetter = indexedSetter;
148    }
149
150    public Method getIndexedWriteMethod() {
151        return indexedSetter;
152    }
153
154    public Method getIndexedReadMethod() {
155        return indexedGetter;
156    }
157
158    @Override
159    public boolean equals(Object obj) {
160        boolean result = super.equals(obj);
161
162        if (result) {
163            IndexedPropertyDescriptor pd = (IndexedPropertyDescriptor) obj;
164
165            if (indexedGetter != null) {
166                result = indexedGetter.equals(pd.getIndexedReadMethod());
167            } else if (result && indexedGetter == null) {
168                result = pd.getIndexedReadMethod() == null;
169            }
170
171            if (result) {
172                if (indexedSetter != null) {
173                    result = indexedSetter.equals(pd.getIndexedWriteMethod());
174                } else if (indexedSetter == null) {
175                    result = pd.getIndexedWriteMethod() == null;
176                }
177            }
178        }
179
180        return result;
181    }
182
183    public Class<?> getIndexedPropertyType() {
184        Class<?> result = null;
185
186        if (indexedGetter != null) {
187            result = indexedGetter.getReturnType();
188        } else if (indexedSetter != null) {
189            Class<?>[] parameterTypes = indexedSetter.getParameterTypes();
190
191            result = parameterTypes[1];
192        }
193        return result;
194    }
195
196    private void setIndexedReadMethod(Class<?> beanClass, String indexedGetterName) {
197        Method[] getters = findMethods(beanClass, indexedGetterName);
198        boolean result = false;
199
200        for (Method element : getters) {
201            try {
202                setIndexedReadMethod(element);
203                result = true;
204            } catch (IntrospectionException ie) {}
205
206            if (result) {
207                break;
208            }
209        }
210    }
211
212    private void setIndexedWriteMethod(Class<?> beanClass, String indexedSetterName) {
213        Method[] setters = findMethods(beanClass, indexedSetterName);
214        boolean result = false;
215
216        for (Method element : setters) {
217            try {
218                setIndexedWriteMethod(element);
219                result = true;
220            } catch (IntrospectionException ie) {}
221
222            if (result) {
223                break;
224            }
225        }
226    }
227}
228