001 package org.tynamo.descriptor.annotation;
002
003 import ognl.Ognl;
004 import org.apache.commons.lang.exception.ExceptionUtils;
005 import org.slf4j.Logger;
006 import org.slf4j.LoggerFactory;
007 import org.tynamo.descriptor.*;
008
009 import java.beans.Introspector;
010 import java.beans.PropertyDescriptor;
011 import java.lang.annotation.Annotation;
012 import java.lang.reflect.Field;
013 import java.lang.reflect.Method;
014 import java.util.ArrayList;
015 import java.util.Collections;
016 import java.util.List;
017
018 /**
019 * This class uses the annotations on a given class or property to modify its
020 * descriptor
021 *
022 * @author Chris Nelson
023 */
024 public class AnnotationDecorator implements DescriptorDecorator
025 {
026
027 private static final Logger LOGGER = LoggerFactory.getLogger(AnnotationDecorator.class);
028
029 public TynamoClassDescriptor decorate(TynamoClassDescriptor descriptor)
030 {
031
032 Annotation[] classAnnotations = descriptor.getType().getAnnotations();
033 TynamoClassDescriptor decoratedDescriptor = (TynamoClassDescriptor) decorateFromAnnotations(descriptor, classAnnotations);
034
035 decoratedDescriptor.setPropertyDescriptors(decoratePropertyDescriptors(descriptor));
036 sortDescriptors(decoratedDescriptor.getPropertyDescriptors());
037
038 decoratedDescriptor.setMethodDescriptors(decorateMethodDescriptors(descriptor));
039
040 return decoratedDescriptor;
041 }
042
043 private List<TynamoPropertyDescriptor> decoratePropertyDescriptors(TynamoClassDescriptor descriptor)
044 {
045 List<TynamoPropertyDescriptor> decoratedPropertyDescriptors = new ArrayList<TynamoPropertyDescriptor>();
046 for (TynamoPropertyDescriptor propertyDescriptor : descriptor.getPropertyDescriptors())
047 {
048 TynamoPropertyDescriptor clonedDescriptor = decoratePropertyDescriptor(propertyDescriptor);
049 // recursively decorate components
050 if (clonedDescriptor.isEmbedded())
051 {
052 clonedDescriptor = (EmbeddedDescriptor) decorate((EmbeddedDescriptor) clonedDescriptor);
053 }
054 decoratedPropertyDescriptors.add(clonedDescriptor);
055 }
056 return decoratedPropertyDescriptors;
057 }
058
059 private List<IMethodDescriptor> decorateMethodDescriptors(TynamoClassDescriptor descriptor)
060 {
061 List<IMethodDescriptor> decoratedMethodDescriptors = new ArrayList<IMethodDescriptor>();
062 for (IMethodDescriptor methodDescriptor : descriptor.getMethodDescriptors())
063 {
064 IMethodDescriptor clonedDescriptor = decorateMethodDescriptor(methodDescriptor);
065 decoratedMethodDescriptors.add(clonedDescriptor);
066 }
067 return decoratedMethodDescriptors;
068 }
069
070 protected TynamoPropertyDescriptor decoratePropertyDescriptor(TynamoPropertyDescriptor propertyDescriptor)
071 {
072 TynamoPropertyDescriptor clonedDescriptor = (TynamoPropertyDescriptor) propertyDescriptor.clone();
073 try
074 {
075 Field propertyField = clonedDescriptor.getBeanType().getDeclaredField(propertyDescriptor.getName());
076 clonedDescriptor = (TynamoPropertyDescriptor) decorateFromAnnotations(clonedDescriptor, propertyField.getAnnotations());
077
078 } catch (Exception ex)
079 {
080 // don't care
081 }
082 try
083 {
084 PropertyDescriptor beanPropDescriptor = (PropertyDescriptor) Ognl.getValue("propertyDescriptors.{? name == '" + propertyDescriptor.getName() + "'}[0]",
085 Introspector.getBeanInfo(clonedDescriptor.getBeanType()));
086
087 Method readMethod = beanPropDescriptor.getReadMethod();
088 clonedDescriptor = (TynamoPropertyDescriptor) decorateFromAnnotations(clonedDescriptor, readMethod.getAnnotations());
089 }
090 catch (Exception ex)
091 {
092 //System.out.println(propertyDescriptor.getName());
093 //ex.printStackTrace();
094 // don't care
095 }
096 return clonedDescriptor;
097 }
098
099 protected IMethodDescriptor decorateMethodDescriptor(IMethodDescriptor methodDescriptor)
100 {
101 try
102 {
103
104 return (IMethodDescriptor) decorateFromAnnotations(methodDescriptor, methodDescriptor.getMethod().getAnnotations());
105
106 } catch (NoSuchMethodException nsme)
107 {
108 LOGGER.warn(ExceptionUtils.getRootCauseMessage(nsme));
109 }
110 return methodDescriptor;
111 }
112
113 /**
114 * Rearrange the property descriptors by their index
115 *
116 * @param propertyDescriptors
117 */
118 private void sortDescriptors(List<TynamoPropertyDescriptor> propertyDescriptors)
119 {
120 for (TynamoPropertyDescriptor propertyDescriptor : Collections.unmodifiableList(propertyDescriptors))
121 {
122 if (propertyDescriptor.getIndex() != TynamoPropertyDescriptor.UNDEFINED_INDEX)
123 {
124 Collections.swap(propertyDescriptors, propertyDescriptor.getIndex(),
125 propertyDescriptors.indexOf(propertyDescriptor));
126 }
127 }
128 }
129
130 private Descriptor decorateFromAnnotations(Descriptor descriptor, Annotation[] annotations)
131 {
132 Descriptor clonedDescriptor = (Descriptor) descriptor.clone();
133 for (Annotation annotation : annotations)
134 {
135 // If the annotation type itself has a DescriptorAnnotation, it's one of ours
136 DescriptorAnnotation handlerAnnotation =
137 annotation.annotationType().getAnnotation(DescriptorAnnotation.class);
138 if (handlerAnnotation != null)
139 {
140 try
141 {
142 DescriptorAnnotationHandler handler = handlerAnnotation.value().newInstance();
143 clonedDescriptor = handler.decorateFromAnnotation(annotation, clonedDescriptor);
144 }
145 catch (Exception ex)
146 {
147 LOGGER.warn(ExceptionUtils.getRootCauseMessage(ex));
148 }
149 }
150 }
151 return clonedDescriptor;
152 }
153
154 }