001 /*
002 * Copyright 2005,2009 Ivan SZKIBA
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.ini4j.spi;
017
018 import java.beans.Introspector;
019 import java.beans.PropertyChangeListener;
020 import java.beans.PropertyChangeSupport;
021 import java.beans.PropertyVetoException;
022 import java.beans.VetoableChangeListener;
023 import java.beans.VetoableChangeSupport;
024
025 import java.lang.reflect.Array;
026 import java.lang.reflect.InvocationHandler;
027 import java.lang.reflect.Method;
028
029 public abstract class AbstractBeanInvocationHandler implements InvocationHandler
030 {
031 private static final String PROPERTY_CHANGE_LISTENER = "PropertyChangeListener";
032 private static final String VETOABLE_CHANGE_LISTENER = "VetoableChangeListener";
033 private static final String ADD_PREFIX = "add";
034 private static final String READ_PREFIX = "get";
035 private static final String REMOVE_PREFIX = "remove";
036 private static final String READ_BOOLEAN_PREFIX = "is";
037 private static final String WRITE_PREFIX = "set";
038 private static final String HAS_PREFIX = "has";
039
040 private static enum Prefix
041 {
042 READ(READ_PREFIX),
043 READ_BOOLEAN(READ_BOOLEAN_PREFIX),
044 WRITE(WRITE_PREFIX),
045 ADD_CHANGE(ADD_PREFIX + PROPERTY_CHANGE_LISTENER),
046 ADD_VETO(ADD_PREFIX + VETOABLE_CHANGE_LISTENER),
047 REMOVE_CHANGE(REMOVE_PREFIX + PROPERTY_CHANGE_LISTENER),
048 REMOVE_VETO(REMOVE_PREFIX + VETOABLE_CHANGE_LISTENER),
049 HAS(HAS_PREFIX);
050 private int _len;
051 private String _value;
052
053 private Prefix(String value)
054 {
055 _value = value;
056 _len = value.length();
057 }
058
059 public static Prefix parse(String str)
060 {
061 Prefix ret = null;
062
063 for (Prefix p : values())
064 {
065 if (str.startsWith(p.getValue()))
066 {
067 ret = p;
068
069 break;
070 }
071 }
072
073 return ret;
074 }
075
076 public String getTail(String input)
077 {
078 return Introspector.decapitalize(input.substring(_len));
079 }
080
081 public String getValue()
082 {
083 return _value;
084 }
085 }
086
087 private PropertyChangeSupport _pcSupport;
088 private Object _proxy;
089 private VetoableChangeSupport _vcSupport;
090
091 @Override public Object invoke(Object proxy, Method method, Object[] args) throws PropertyVetoException
092 {
093 Object ret = null;
094 Prefix prefix = Prefix.parse(method.getName());
095
096 if (prefix != null)
097 {
098 String tail = prefix.getTail(method.getName());
099
100 updateProxy(proxy);
101 switch (prefix)
102 {
103
104 case READ:
105 ret = getProperty(prefix.getTail(method.getName()), method.getReturnType());
106 break;
107
108 case READ_BOOLEAN:
109 ret = getProperty(prefix.getTail(method.getName()), method.getReturnType());
110 break;
111
112 case WRITE:
113 setProperty(tail, args[0], method.getParameterTypes()[0]);
114 break;
115
116 case HAS:
117 ret = Boolean.valueOf(hasProperty(prefix.getTail(method.getName())));
118 break;
119
120 case ADD_CHANGE:
121 addPropertyChangeListener((String) args[0], (PropertyChangeListener) args[1]);
122 break;
123
124 case ADD_VETO:
125 addVetoableChangeListener((String) args[0], (VetoableChangeListener) args[1]);
126 break;
127
128 case REMOVE_CHANGE:
129 removePropertyChangeListener((String) args[0], (PropertyChangeListener) args[1]);
130 break;
131
132 case REMOVE_VETO:
133 removeVetoableChangeListener((String) args[0], (VetoableChangeListener) args[1]);
134 break;
135
136 default:
137 break;
138 }
139 }
140
141 return ret;
142 }
143
144 protected abstract Object getPropertySpi(String property, Class<?> clazz);
145
146 protected abstract void setPropertySpi(String property, Object value, Class<?> clazz);
147
148 protected abstract boolean hasPropertySpi(String property);
149
150 protected synchronized Object getProperty(String property, Class<?> clazz)
151 {
152 Object o;
153
154 try
155 {
156 o = getPropertySpi(property, clazz);
157 if (o == null)
158 {
159 o = zero(clazz);
160 }
161 else if (clazz.isArray() && (o instanceof String[]) && !clazz.equals(String[].class))
162 {
163 String[] str = (String[]) o;
164
165 o = Array.newInstance(clazz.getComponentType(), str.length);
166 for (int i = 0; i < str.length; i++)
167 {
168 Array.set(o, i, parse(str[i], clazz.getComponentType()));
169 }
170 }
171 else if ((o instanceof String) && !clazz.equals(String.class))
172 {
173 o = parse((String) o, clazz);
174 }
175 }
176 catch (Exception x)
177 {
178 o = zero(clazz);
179 }
180
181 return o;
182 }
183
184 protected synchronized void setProperty(String property, Object value, Class<?> clazz) throws PropertyVetoException
185 {
186 boolean pc = (_pcSupport != null) && _pcSupport.hasListeners(property);
187 boolean vc = (_vcSupport != null) && _vcSupport.hasListeners(property);
188 Object oldVal = null;
189 Object newVal = ((value != null) && clazz.equals(String.class) && !(value instanceof String)) ? value.toString() : value;
190
191 if (pc || vc)
192 {
193 oldVal = getProperty(property, clazz);
194 }
195
196 if (vc)
197 {
198 fireVetoableChange(property, oldVal, value);
199 }
200
201 setPropertySpi(property, newVal, clazz);
202 if (pc)
203 {
204 firePropertyChange(property, oldVal, value);
205 }
206 }
207
208 protected synchronized Object getProxy()
209 {
210 return _proxy;
211 }
212
213 protected synchronized void addPropertyChangeListener(String property, PropertyChangeListener listener)
214 {
215 if (_pcSupport == null)
216 {
217 _pcSupport = new PropertyChangeSupport(_proxy);
218 }
219
220 _pcSupport.addPropertyChangeListener(property, listener);
221 }
222
223 protected synchronized void addVetoableChangeListener(String property, VetoableChangeListener listener)
224 {
225 if (_vcSupport == null)
226 {
227 _vcSupport = new VetoableChangeSupport(_proxy);
228 }
229
230 _vcSupport.addVetoableChangeListener(property, listener);
231 }
232
233 protected synchronized void firePropertyChange(String property, Object oldValue, Object newValue)
234 {
235 if (_pcSupport != null)
236 {
237 _pcSupport.firePropertyChange(property, oldValue, newValue);
238 }
239 }
240
241 protected synchronized void fireVetoableChange(String property, Object oldValue, Object newValue) throws PropertyVetoException
242 {
243 if (_vcSupport != null)
244 {
245 _vcSupport.fireVetoableChange(property, oldValue, newValue);
246 }
247 }
248
249 protected synchronized boolean hasProperty(String property)
250 {
251 boolean ret;
252
253 try
254 {
255 ret = hasPropertySpi(property);
256 }
257 catch (Exception x)
258 {
259 ret = false;
260 }
261
262 return ret;
263 }
264
265 protected Object parse(String value, Class clazz) throws IllegalArgumentException
266 {
267 return BeanTool.getInstance().parse(value, clazz);
268 }
269
270 protected synchronized void removePropertyChangeListener(String property, PropertyChangeListener listener)
271 {
272 if (_pcSupport != null)
273 {
274 _pcSupport.removePropertyChangeListener(property, listener);
275 }
276 }
277
278 protected synchronized void removeVetoableChangeListener(String property, VetoableChangeListener listener)
279 {
280 if (_vcSupport != null)
281 {
282 _vcSupport.removeVetoableChangeListener(property, listener);
283 }
284 }
285
286 protected Object zero(Class clazz)
287 {
288 return BeanTool.getInstance().zero(clazz);
289 }
290
291 private synchronized void updateProxy(Object value)
292 {
293 if (_proxy == null)
294 {
295 _proxy = value;
296 }
297 }
298 }