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    }