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