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 }