View Javadoc

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 }