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