001    package org.trails.descriptor;
002    
003    import java.util.ArrayList;
004    import java.util.Collections;
005    import java.util.Comparator;
006    import java.util.HashMap;
007    import java.util.List;
008    import java.util.Map;
009    
010    import ognl.OgnlException;
011    
012    /**
013     * This class builds and caches IClassDescriptors.  Descriptors are build during the init
014     * method which is called by Spring during application startup
015     *
016     * @author cnelson
017     * @see IClassDescriptor
018     */
019    public class TrailsDescriptorService implements DescriptorService
020    {
021            protected List<Class> types;
022            protected Map<Class, IClassDescriptor> descriptors = new HashMap<Class, IClassDescriptor>();
023            private List<DescriptorDecorator> decorators = new ArrayList<DescriptorDecorator>();
024            private DescriptorFactory descriptorFactory;
025    
026            /**
027             * For each class in types, a descriptor is built by the DescriptorFactory.  Next it is decorated
028             * by each DescriptorDecorator in turn.  Finally it is cached.
029             *
030             * @throws OgnlException
031             * @see DescriptorFactory
032             * @see DescriptorDecorator
033             */
034            public void init() throws OgnlException
035            {
036                    descriptors.clear();
037                    for (Class type : types)
038                    {
039                            IClassDescriptor descriptor = getDescriptorFactory().buildClassDescriptor(type);
040                            descriptor = applyDecorators(descriptor);
041                            descriptors.put(type, descriptor);
042                    }
043                    // second pass to find children and set up descriptor parents
044                    for (IClassDescriptor iClassDescriptor : descriptors.values())
045                    {
046                            findChildren(iClassDescriptor);
047                    }
048            }
049    
050            public List<IClassDescriptor> getAllDescriptors()
051            {
052                    List<IClassDescriptor> allDescriptors = new ArrayList<IClassDescriptor>(descriptors.values());
053                    Collections.sort(allDescriptors, new Comparator<IClassDescriptor>()
054                    {
055                            public int compare(IClassDescriptor o1, IClassDescriptor o2)
056                            {
057                                    return o1.getDisplayName().compareTo(o2.getDisplayName());
058                            }
059                    });
060                    return allDescriptors;
061            }
062    
063            /* (non-Javadoc)
064                     * @see org.trails.descriptor.IDescriptorFactory#buildClassDescriptor(java.lang.Class)
065                     */
066            public IClassDescriptor getClassDescriptor(Class type)
067            {
068                    if (type.getName().contains("CGLIB"))
069                    {
070                            return descriptors.get(type.getSuperclass());
071                    } else
072                    {
073                            return descriptors.get(type);
074                    }
075            }
076    
077            protected void findChildren(IClassDescriptor iClassDescriptor)
078            {
079                    for (IPropertyDescriptor propertyDescriptor : iClassDescriptor.getPropertyDescriptors())
080                    {
081                            if (propertyDescriptor.isCollection())
082                            {
083                                    if (((CollectionDescriptor) propertyDescriptor).isChildRelationship())
084                                    {
085                                            IClassDescriptor collectionClassDescriptor = getClassDescriptor(((CollectionDescriptor) propertyDescriptor).getElementType());
086                                            collectionClassDescriptor.setChild(true);
087                                    }
088                                    if (((CollectionDescriptor) propertyDescriptor).getInverseProperty() != null)
089                                    {
090                                            iClassDescriptor.setHasCyclicRelationships(true);
091                                    }
092                            }
093                    }
094            }
095    
096            /**
097             * Have the decorators decorate this descriptor  todo what are decorators for and/or why would I want to call this
098             * menthod?
099             *
100             * @param descriptor
101             * @return The resulting descriptor after all decorators are applied
102             */
103            protected IClassDescriptor applyDecorators(IClassDescriptor descriptor)
104            {
105                    IClassDescriptor currDescriptor = descriptor;
106                    for (DescriptorDecorator decorator : getDecorators())
107                    {
108                            currDescriptor = decorator.decorate(currDescriptor);
109                    }
110                    return currDescriptor;
111            }
112    
113            /**
114             * In the Trails default configuration this will be set
115             * to all classes in the Hibernate config
116             *
117             * @return
118             */
119            public List getTypes()
120            {
121                    return types;
122            }
123    
124            /**
125             * @param types all the classes this service should describe
126             */
127            public void setTypes(List<Class> types)
128            {
129                    this.types = types;
130            }
131    
132            /**
133             * In the default Trails configuration this will contain a HibernateDescriptorDecorator
134             * and an AnnotationDecorator
135             *
136             * @return
137             * @see org.trails.hibernate.HibernateDescriptorDecorator
138             * @see org.trails.descriptor.annotation.AnnotationDecorator
139             */
140            public List<DescriptorDecorator> getDecorators()
141            {
142                    return decorators;
143            }
144    
145            public void setDecorators(List<DescriptorDecorator> decorators)
146            {
147                    this.decorators = decorators;
148            }
149    
150            /**
151             * In default Trails this will be a ReflectionDescriptorFactory
152             *
153             * @return
154             * @see ReflectionDescriptorFactory
155             */
156            public DescriptorFactory getDescriptorFactory()
157            {
158                    return descriptorFactory;
159            }
160    
161            public void setDescriptorFactory(DescriptorFactory descriptorFactory)
162            {
163                    this.descriptorFactory = descriptorFactory;
164            }
165    }