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 */ 016package org.ini4j.spi; 017 018import java.beans.Introspector; 019import java.beans.PropertyChangeListener; 020import java.beans.PropertyChangeSupport; 021import java.beans.PropertyVetoException; 022import java.beans.VetoableChangeListener; 023import java.beans.VetoableChangeSupport; 024 025import java.lang.reflect.Array; 026import java.lang.reflect.InvocationHandler; 027import java.lang.reflect.Method; 028 029public 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}