1 package org.weda.property.impl; 2 3 import java.beans.IntrospectionException; 4 import java.util.ArrayList; 5 import java.util.HashMap; 6 import java.util.List; 7 import java.util.Map; 8 import org.weda.property.PropertyGetOperationListener; 9 import org.weda.property.PropertyOperation; 10 import org.weda.property.PropertyOperationException; 11 import org.weda.property.PropertyValueException; 12 import org.weda.property.PropertyValue; 13 14 /** 15 * 16 * @author Mikhail Titov 17 */ 18 public class PropertyValueImpl implements PropertyValue { 19 private List<PropertyOperation[]> propertyGetters = 20 new ArrayList<PropertyOperation[]>(); 21 private List<PropertyOperation[]> propertySetters = 22 new ArrayList<PropertyOperation[]>(); 23 private Map<String, Integer> getterIds = new HashMap<String, Integer>(); 24 private Map<String, Integer> setterIds = new HashMap<String, Integer>(); 25 private Map<Integer, String> getterStrIds = new HashMap<Integer, String>(); 26 private Map<Integer, String> setterStrIds = new HashMap<Integer, String>(); 27 private Map<PropertyOperation, PropertyOperation> operations = 28 new HashMap<PropertyOperation, PropertyOperation>(); 29 30 public Object getValue(Object baseObject, Integer propertyPathId) 31 throws PropertyValueException 32 { 33 Object res=baseObject; 34 try{ 35 PropertyOperation[] getters = propertyGetters.get(propertyPathId); 36 for (PropertyOperation getter: getters){ 37 res = getter.invoke(res, null); 38 if (res==null) 39 return null; 40 } 41 }catch(PropertyOperationException e){ 42 throw new PropertyValueException( 43 String.format("Can't get value for property path (%s)" 44 , getterStrIds.get(propertyPathId)) 45 , e); 46 } 47 return res; 48 } 49 50 public void setValue( 51 Object baseObject, Integer propertyPathId, Object value) 52 throws PropertyValueException 53 { 54 Object res=baseObject; 55 try{ 56 PropertyOperation[] getters = propertySetters.get(propertyPathId); 57 for (int i=0; i<getters.length-1; ++i){ 58 res = getters[i].invoke(res, null); 59 if (res==null) 60 throw new PropertyValueException( 61 "Null property value at position "+(i+1), null); 62 } 63 getters[getters.length-1].invoke(res, value); 64 }catch(Exception e){ 65 throw new PropertyValueException( 66 String.format("Can't set value for property path (%s)" 67 , getterStrIds.get(propertyPathId)) 68 , e); 69 } 70 } 71 72 protected PropertyOperation[] createGetters( 73 Class baseClass, String propertyPath, boolean lastSetter) 74 throws PropertyValueException 75 { 76 String[] names=propertyPath.split("\\."); 77 PropertyOperation[] getters = new PropertyOperation[names.length]; 78 int i=0; 79 try{ 80 for (String name: names){ 81 boolean isGetter = !(i==names.length-1 && lastSetter); 82 PropertyOperation operation = 83 createPropertyOperation(baseClass, name, isGetter); 84 getters[i++]=operation; 85 baseClass = operation.getMethod().getReturnType(); 86 } 87 }catch(PropertyValueException e){ 88 throw new PropertyValueException( 89 String.format( 90 "Can't compile property path (%s). ", propertyPath) 91 , e); 92 } 93 return getters; 94 } 95 96 private PropertyOperation createPropertyOperation( 97 Class propOwnerClass, String propertyName, boolean isGetter) 98 throws PropertyValueException 99 { 100 PropertyOperation operation = null; 101 try{ 102 if (!isGetter) 103 operation = 104 new PropertySetOperation(propOwnerClass, propertyName); 105 else 106 operation = 107 new PropertyGetOperation(propOwnerClass, propertyName); 108 if (operation.getMethod()==null){ 109 throw new PropertyValueException( 110 String.format( 111 "Can't compile (%1$s) operation for property (%2$s) " + 112 "of class (%3$s). Property (%2$s) is %4$s only" 113 , isGetter?"GET":"SET", propertyName 114 , propOwnerClass.getName(), isGetter?"read":"write") 115 , null); 116 } 117 PropertyOperation cachedOperation = operations.get(operation); 118 if (cachedOperation==null){ 119 operations.put(operation, operation); 120 cachedOperation = operation; 121 } 122 return cachedOperation; 123 }catch(IntrospectionException e){ 124 throw new PropertyValueException( 125 String.format( 126 "Can't compile (%s) operation for property (%s) " + 127 "of class (%s)" 128 , isGetter?"GET":"SET", propertyName 129 , propOwnerClass.getName()) 130 , e); 131 } 132 } 133 134 protected String formStrId(Class baseClass, String propertyPath){ 135 return baseClass.getName()+"#"+propertyPath; 136 } 137 138 public synchronized Integer compileGetter( 139 Class baseClass, String propertyPath) 140 throws PropertyValueException 141 { 142 String strId = formStrId(baseClass, propertyPath); 143 Integer id=getterIds.get(strId); 144 if (id==null){ 145 PropertyOperation[] getters = 146 createGetters(baseClass, propertyPath, false); 147 propertyGetters.add(getters); 148 id=propertyGetters.size()-1; 149 getterIds.put(strId, id); 150 getterStrIds.put(id, strId); 151 } 152 return id; 153 } 154 155 public synchronized Integer compileSetter( 156 Class baseClass, String propertyPath) 157 throws PropertyValueException 158 { 159 String strId = formStrId(baseClass, propertyPath); 160 Integer id = setterIds.get(strId); 161 if (id == null){ 162 PropertyOperation[] getters = 163 createGetters(baseClass, propertyPath, true); 164 propertySetters.add(getters); 165 id=propertySetters.size()-1; 166 setterIds.put(strId, id); 167 setterStrIds.put(id, strId); 168 } 169 return id; 170 } 171 172 public synchronized void addGetOperationListener( 173 Class objectClass, String propertyName 174 , PropertyGetOperationListener listener) 175 throws PropertyValueException 176 { 177 PropertyOperation operation = 178 createPropertyOperation(objectClass, propertyName, true); 179 operation.addListener(listener); 180 } 181 182 public synchronized void removeGetListener( 183 PropertyGetOperationListener listener) 184 { 185 for (PropertyOperation operation: operations.values()) 186 operation.removeListener(listener); 187 } 188 }