View Javadoc

1   package org.weda.property.impl;
2   
3   import java.beans.IntrospectionException;
4   import java.beans.Introspector;
5   import java.lang.annotation.Annotation;
6   import java.lang.reflect.Method;
7   import java.util.ArrayList;
8   import java.util.Collections;
9   import java.util.HashMap;
10  import java.util.List;
11  import java.util.Map;
12  import org.weda.converter.ValueTypeConverter;
13  import org.weda.enhance.InjectHivemindObject;
14  import org.weda.property.Constraint;
15  import org.weda.property.ConstraintException;
16  import org.weda.property.ConstraintsRegistry;
17  import org.weda.property.PropertyDescriptorException;
18  import org.weda.property.annotations.Constraints;
19  import org.weda.property.annotations.Description;
20  import org.weda.property.ObjectDescriptorRegistry;
21  import org.weda.property.PropertyDescriptor;
22  import org.weda.property.annotations.ConstraintId;
23  
24  /**Цель: возвращать название свойства заданного класса
25   * в результате возвращается значение атрибута name аннотации description или 
26   * название свойства если нет аннотации
27   *
28   * @author tim
29   */
30  //TODO: Привести к модели: контракт - реализация
31  public class ObjectDescriptor {
32      private Class objectClass;
33      
34      @InjectHivemindObject private ObjectDescriptorRegistry objDescRegistry;
35      @InjectHivemindObject private ConstraintsRegistry constraintsRegistry;
36      
37      private Map<String, PropertyDescriptorImpl> properties = 
38              new HashMap<String, PropertyDescriptorImpl>();
39      private Map<String, PropertyDescriptor> additionalPropertiesInfo =
40              new HashMap<String, PropertyDescriptor>();
41      private Map<String, java.beans.PropertyDescriptor> beanDescriptorCache;
42      
43      public void init() throws ObjectDescriptorException {
44          try {
45              for (PropertyDescriptor descriptor
46                      : additionalPropertiesInfo.values())
47              {                
48                  PropertyDescriptorImpl desc = 
49                          (PropertyDescriptorImpl)descriptor;
50                  desc.setObjectClass(objectClass);
51                  desc.init();
52              }
53          } catch (PropertyDescriptorException ex) {
54              throw new ObjectDescriptorException(
55                  String.format(
56                      "Can't initialize object descriptor for target class (%s)"
57                      , objectClass.getName()));
58          }
59      }
60      
61      public Class getObjectClass() {
62          return objectClass;
63      }
64      
65      public void setObjectClass(Class value) {
66          this.objectClass = value;
67      }
68      
69      public void addAdditionalPropertyInfo(PropertyDescriptor property){
70          additionalPropertiesInfo.put(property.getName(), property);
71      }
72      
73      public PropertyDescriptor getPropertyDescriptor(String propertyName)
74          throws ObjectDescriptorException 
75      {
76          PropertyDescriptorImpl propertyDescriptor = 
77                  properties.get(propertyName);
78          if (propertyDescriptor==null){
79              try{
80                  java.beans.PropertyDescriptor d = 
81                          getJavaBeansPropertyDescriptor(propertyName);
82                  propertyDescriptor = new PropertyDescriptorImpl();
83                  propertyDescriptor.setName(propertyName);
84                  propertyDescriptor.setObjectClass(getObjectClass());
85                  propertyDescriptor.setPropertyClass(d.getPropertyType());
86                  processAnnotaions(propertyDescriptor, d);
87                  if (d.getPropertyType().isEnum())
88                      addEnumConstraint(propertyDescriptor);
89                  if (additionalPropertiesInfo.containsKey(propertyName)){
90                      PropertyDescriptor pinfo = 
91                              additionalPropertiesInfo.get(propertyName);
92                      propertyDescriptor.setDisplayName(pinfo.getDisplayName());
93                  }
94                  propertyDescriptor.init();
95                  properties.put(propertyName, propertyDescriptor);
96              }catch(Exception e){
97                  throw new ObjectDescriptorException(
98                      String.format(
99                          "Can't get property descriptor for property (%s) " +
100                             "of class (%s)"
101                         , propertyName, objectClass.getName())
102                     , e);
103             }
104         }
105         return propertyDescriptor;
106     }
107     
108     private void addEnumConstraint(PropertyDescriptorImpl desc) 
109         throws ConstraintException
110     {
111         Object[] constants = desc.getPropertyClass().getEnumConstants();
112         StaticSetConstraint constraint = new StaticSetConstraint();
113         constraint.setValuesAliased(true);
114         for (Object obj: constants){
115             Enum cons = (Enum)obj;
116             constraint.addSetValue(new SetValueImpl(cons, cons.name()));
117         }
118         constraint.init();
119         desc.addConstraint(constraint);
120     }
121     
122     private void processAnnotaions(
123             PropertyDescriptorImpl desc
124             , java.beans.PropertyDescriptor javaDesc)
125         throws Exception
126     {
127         //lookup for Description annotation
128         Description descriptionAnn = null;
129         Constraints constraintsAnn = null;
130         Method[] methods = 
131                 new Method[]{
132                     javaDesc.getReadMethod(), javaDesc.getWriteMethod()};
133         for (Method method: methods){
134             if (method!=null){
135                 if (method.isAnnotationPresent(Description.class))
136                     descriptionAnn = method.getAnnotation(Description.class);
137                 if (method.isAnnotationPresent(Constraints.class))
138                     constraintsAnn = method.getAnnotation(Constraints.class);
139             }
140         }
141         processDescriptionAnnotaion(desc, descriptionAnn);
142         processConstraintsAnnotations(desc, constraintsAnn);
143     }
144     
145     private void processDescriptionAnnotaion(
146             PropertyDescriptorImpl propertyDescriptor
147             , Description descriptionAnn)
148     {
149         if (descriptionAnn!=null){
150             propertyDescriptor.setDisplayName(
151                     returnNullIfEmpty(descriptionAnn.displayName()));
152             propertyDescriptor.setPattern(
153                     returnNullIfEmpty(descriptionAnn.pattern()));
154             propertyDescriptor.setMimeType(
155                     returnNullIfEmpty(descriptionAnn.mimeType()));
156         }
157     }
158     
159     private void processConstraintsAnnotations(
160             PropertyDescriptorImpl desc
161             , Constraints constraintsAnn)
162         throws Exception
163     {
164         if (constraintsAnn != null){
165             ConstraintId[] ids = constraintsAnn.value();
166             if (ids != null)
167                 for (ConstraintId id: ids)
168                     desc.addConstraint(
169                         constraintsRegistry.getConstraint(id.value()));
170         }
171     }
172     
173     
174     /**Метод возвращает имена свойств которые можно читать и устананавливать.
175      */
176     public List<String> getReadWriteProperties() 
177         throws ObjectDescriptorException
178     {
179         try{
180             List<String> names = new ArrayList<String>();
181             if (beanDescriptorCache==null)
182                 cacheJavaBeansPropertyDescriptors();
183             for (java.beans.PropertyDescriptor desc
184                     : beanDescriptorCache.values())
185             {
186                 if (desc.getWriteMethod()!=null && desc.getReadMethod()!=null)
187                     names.add(desc.getName());
188             }
189             return names;
190         }catch(Exception e){
191             throw new ObjectDescriptorException(
192                 String.format(
193                     "Can't create list of writable properties for class (%s)"
194                     , objectClass.getName()));
195         }        
196     }
197 
198     public void setRegistry(ObjectDescriptorRegistry registry) {
199         //this.objDescRegistry = registry;
200     }
201     
202     private java.beans.PropertyDescriptor getJavaBeansPropertyDescriptor(
203                 String propertyName)
204             throws ObjectDescriptorException
205     {
206         try{
207             if (beanDescriptorCache==null)
208                 cacheJavaBeansPropertyDescriptors();
209             java.beans.PropertyDescriptor desc = 
210                     beanDescriptorCache.get(propertyName);
211             if (desc==null)
212                     throw new ObjectDescriptorException(
213                         String.format(
214                             "Property name (%s) does not exist in class (%s)"
215                             , propertyName, objectClass.getName()));
216             return desc;
217         }catch(IntrospectionException e){
218             throw new ObjectDescriptorException(
219                     String.format(
220                         "Can't extract java beans property descriptors. " +
221                         "Object class (%d), property name(%s)"
222                         , objectClass.getName(), propertyName)
223                     , e);
224         }
225     }
226     
227     private void cacheJavaBeansPropertyDescriptors() 
228         throws IntrospectionException
229     {
230         java.beans.PropertyDescriptor[] descs = 
231                 Introspector.getBeanInfo(objectClass).getPropertyDescriptors();
232         beanDescriptorCache=
233                 new HashMap<String, java.beans.PropertyDescriptor>();
234         for (java.beans.PropertyDescriptor desc: descs)
235             beanDescriptorCache.put(desc.getName(), desc);
236     }
237     
238     private String returnNullIfEmpty(String value){
239         if (value==null || value.length()==0)
240             return null;
241         else
242             return value;
243     }
244 
245     public void setConverter(ValueTypeConverter converter) {
246         //this.converter = converter;
247     }
248 
249 }