View Javadoc

1   /*
2    * Copyright 2005,2009 Ivan SZKIBA
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.ini4j.spi;
17  
18  import java.beans.Introspector;
19  import java.beans.PropertyChangeListener;
20  import java.beans.PropertyChangeSupport;
21  import java.beans.PropertyVetoException;
22  import java.beans.VetoableChangeListener;
23  import java.beans.VetoableChangeSupport;
24  
25  import java.lang.reflect.Array;
26  import java.lang.reflect.InvocationHandler;
27  import java.lang.reflect.Method;
28  
29  public abstract class AbstractBeanInvocationHandler implements InvocationHandler
30  {
31      private static final String PROPERTY_CHANGE_LISTENER = "PropertyChangeListener";
32      private static final String VETOABLE_CHANGE_LISTENER = "VetoableChangeListener";
33      private static final String ADD_PREFIX = "add";
34      private static final String READ_PREFIX = "get";
35      private static final String REMOVE_PREFIX = "remove";
36      private static final String READ_BOOLEAN_PREFIX = "is";
37      private static final String WRITE_PREFIX = "set";
38      private static final String HAS_PREFIX = "has";
39  
40      private static enum Prefix
41      {
42          READ(READ_PREFIX),
43          READ_BOOLEAN(READ_BOOLEAN_PREFIX),
44          WRITE(WRITE_PREFIX),
45          ADD_CHANGE(ADD_PREFIX + PROPERTY_CHANGE_LISTENER),
46          ADD_VETO(ADD_PREFIX + VETOABLE_CHANGE_LISTENER),
47          REMOVE_CHANGE(REMOVE_PREFIX + PROPERTY_CHANGE_LISTENER),
48          REMOVE_VETO(REMOVE_PREFIX + VETOABLE_CHANGE_LISTENER),
49          HAS(HAS_PREFIX);
50          private int _len;
51          private String _value;
52  
53          private Prefix(String value)
54          {
55              _value = value;
56              _len = value.length();
57          }
58  
59          public static Prefix parse(String str)
60          {
61              Prefix ret = null;
62  
63              for (Prefix p : values())
64              {
65                  if (str.startsWith(p.getValue()))
66                  {
67                      ret = p;
68  
69                      break;
70                  }
71              }
72  
73              return ret;
74          }
75  
76          public String getTail(String input)
77          {
78              return Introspector.decapitalize(input.substring(_len));
79          }
80  
81          public String getValue()
82          {
83              return _value;
84          }
85      }
86  
87      private PropertyChangeSupport _pcSupport;
88      private Object _proxy;
89      private VetoableChangeSupport _vcSupport;
90  
91      @Override public Object invoke(Object proxy, Method method, Object[] args) throws PropertyVetoException
92      {
93          Object ret = null;
94          Prefix prefix = Prefix.parse(method.getName());
95  
96          if (prefix != null)
97          {
98              String tail = prefix.getTail(method.getName());
99  
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 }