001    package org.tynamo.descriptor.factories;
002    
003    import org.apache.commons.beanutils.BeanUtils;
004    import org.apache.commons.logging.Log;
005    import org.apache.commons.logging.LogFactory;
006    import org.tynamo.descriptor.TynamoClassDescriptor;
007    import org.tynamo.descriptor.TynamoClassDescriptorImpl;
008    import org.tynamo.descriptor.decorators.DescriptorDecorator;
009    
010    import java.beans.BeanInfo;
011    import java.beans.Introspector;
012    import java.lang.reflect.InvocationTargetException;
013    import java.util.List;
014    
015    /**
016     * Generate descriptors using reflection on the underlying class.
017     * ReflectionDescriptorFactory.buildClassDescriptor() is the only public method
018     * here.
019     */
020    public class ReflectionDescriptorFactory implements DescriptorFactory
021    {
022    
023            protected static final Log LOG = LogFactory.getLog(ReflectionDescriptorFactory.class);
024    
025            private final MethodDescriptorFactory methodDescriptorFactory;
026            private final PropertyDescriptorFactory propertyDescriptorFactory;
027            private final List<DescriptorDecorator> decorators;
028    
029            /**
030             * @param decorators                            In the default Tynamo configuration this will contain a HibernateDescriptorDecorator and an TynamoDecorator
031             * @param methodDescriptorFactory
032             * @param propertyDescriptorFactory
033             */
034            public ReflectionDescriptorFactory(final List<DescriptorDecorator> decorators, MethodDescriptorFactory methodDescriptorFactory, PropertyDescriptorFactory propertyDescriptorFactory)
035            {
036                    this.decorators = decorators;
037                    this.methodDescriptorFactory = methodDescriptorFactory;
038                    this.propertyDescriptorFactory = propertyDescriptorFactory;
039            }
040    
041            /**
042             * Given a type, build a class descriptor
043             *
044             * @param type The type to build for
045             * @return a completed class descriptor
046             */
047            public TynamoClassDescriptor buildClassDescriptor(Class type)
048            {
049                    try
050                    {
051                            TynamoClassDescriptor descriptor = new TynamoClassDescriptorImpl(type);
052                            BeanInfo beanInfo = Introspector.getBeanInfo(type);
053    
054                            BeanUtils.copyProperties(descriptor, beanInfo.getBeanDescriptor());
055                            descriptor.setPropertyDescriptors(propertyDescriptorFactory.buildPropertyDescriptors(type, beanInfo));
056                            descriptor.setMethodDescriptors(methodDescriptorFactory.buildMethodDescriptors(type, beanInfo));
057    
058                            descriptor = applyDecorators(descriptor);
059    
060                            return descriptor;
061    
062                    } catch (IllegalAccessException e)
063                    {
064                            LOG.error(e.getMessage());
065                            e.printStackTrace();
066                    } catch (InvocationTargetException e)
067                    {
068                            LOG.error(e.getMessage());
069                            e.printStackTrace();
070                    } catch (Exception e)
071                    {
072                            LOG.error(e.toString());
073                            e.printStackTrace();
074                    }
075                    return null;
076            }
077    
078            /**
079             * Have the decorators decorate this descriptor
080             *
081             * @param descriptor
082             * @param decorators
083             * @return The resulting descriptor after all decorators are applied
084             */
085            private TynamoClassDescriptor applyDecorators(final TynamoClassDescriptor descriptor)
086            {
087                    TynamoClassDescriptor decoratedDescriptor = descriptor;
088    
089                    for (DescriptorDecorator decorator : decorators)
090                    {
091                            decoratedDescriptor = decorator.decorate(decoratedDescriptor);
092                    }
093    
094                    return decoratedDescriptor;
095            }
096    }