View Javadoc

1   /*
2    * Copyright (c) 2010 Carman Consulting, Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.metastopheles;
18  
19  import java.beans.BeanInfo;
20  import java.beans.IntrospectionException;
21  import java.beans.Introspector;
22  import java.beans.MethodDescriptor;
23  import java.beans.PropertyDescriptor;
24  import java.lang.reflect.Method;
25  import java.util.HashMap;
26  import java.util.HashSet;
27  import java.util.LinkedList;
28  import java.util.List;
29  import java.util.Map;
30  import java.util.Set;
31  import java.util.UUID;
32  import java.util.WeakHashMap;
33  import java.util.concurrent.ConcurrentMap;
34  
35  /**
36   * @author James Carman
37   * @since 1.0
38   */
39  public class BeanMetaDataFactory
40  {
41  //**********************************************************************************************************************
42  // Fields
43  //**********************************************************************************************************************
44  
45      private static final Map<String,BeanMetaDataFactory> factoryRegistry = new HashMap<String,BeanMetaDataFactory>();
46      private final Map<Class, BeanMetaData> metaDataMap = new WeakHashMap<Class, BeanMetaData>();
47  
48      private List<MetaDataDecorator<BeanMetaData>> beanMetaDataDecorators = new LinkedList<MetaDataDecorator<BeanMetaData>>();
49      private List<MetaDataDecorator<MethodMetaData>> methodMetaDataDecorators = new LinkedList<MetaDataDecorator<MethodMetaData>>();
50      private List<MetaDataDecorator<PropertyMetaData>> propertyMetaDataDecorators = new LinkedList<MetaDataDecorator<PropertyMetaData>>();
51      private final String id = UUID.randomUUID().toString();
52  
53  //**********************************************************************************************************************
54  // Static Methods
55  //**********************************************************************************************************************
56  
57      static BeanMetaDataFactory get(String id)
58      {
59          return factoryRegistry.get(id);
60      }
61  
62  //**********************************************************************************************************************
63  // Constructors
64  //**********************************************************************************************************************
65  
66      public BeanMetaDataFactory()
67      {
68          factoryRegistry.put(id, this);
69      }
70  
71  //**********************************************************************************************************************
72  // Getter/Setter Methods
73  //**********************************************************************************************************************
74  
75      public List<MetaDataDecorator<BeanMetaData>> getBeanMetaDataDecorators()
76      {
77          return beanMetaDataDecorators;
78      }
79  
80      public void setBeanMetaDataDecorators(List<MetaDataDecorator<BeanMetaData>> beanMetaDataDecorators)
81      {
82          this.beanMetaDataDecorators = beanMetaDataDecorators;
83      }
84  
85      public List<MetaDataDecorator<MethodMetaData>> getMethodMetaDataDecorators()
86      {
87          return methodMetaDataDecorators;
88      }
89  
90      public void setMethodMetaDataDecorators(List<MetaDataDecorator<MethodMetaData>> methodMetaDataDecorators)
91      {
92          this.methodMetaDataDecorators = methodMetaDataDecorators;
93      }
94  
95      public List<MetaDataDecorator<PropertyMetaData>> getPropertyMetaDataDecorators()
96      {
97          return propertyMetaDataDecorators;
98      }
99  
100     public void setPropertyMetaDataDecorators(List<MetaDataDecorator<PropertyMetaData>> propertyMetaDataDecorators)
101     {
102         this.propertyMetaDataDecorators = propertyMetaDataDecorators;
103     }
104 
105 //**********************************************************************************************************************
106 // Other Methods
107 //**********************************************************************************************************************
108 
109     public synchronized void clear()
110     {
111         metaDataMap.clear();
112     }
113 
114     public synchronized BeanMetaData getBeanMetaData(Class beanClass)
115     {
116         if (metaDataMap.containsKey(beanClass))
117         {
118             return metaDataMap.get(beanClass);
119         }
120         else
121         {
122             try
123             {
124                 BeanInfo beanInfo = Introspector.getBeanInfo(beanClass);
125                 BeanMetaData beanMetaData = new BeanMetaData(id, beanInfo.getBeanDescriptor());
126                 for (MetaDataDecorator<BeanMetaData> decorator : beanMetaDataDecorators)
127                 {
128                     decorator.decorate(beanMetaData);
129                 }
130                 final Set<Method> visitedMethods = new HashSet<Method>();
131                 for (PropertyDescriptor descriptor : beanInfo.getPropertyDescriptors())
132                 {
133                     visitedMethods.add(descriptor.getReadMethod());
134                     visitedMethods.add(descriptor.getWriteMethod());
135                     if (!"class".equals(descriptor.getName()))
136                     {
137                         final PropertyMetaData propertyMetaData = new PropertyMetaData(beanMetaData, descriptor);
138                         beanMetaData.addPropertyMetaData(propertyMetaData);
139                         for (MetaDataDecorator<PropertyMetaData> decorator : propertyMetaDataDecorators)
140                         {
141                             decorator.decorate(propertyMetaData);
142                         }
143                     }
144                 }
145                 for (MethodDescriptor descriptor : beanInfo.getMethodDescriptors())
146                 {
147                     if (!visitedMethods.contains(descriptor.getMethod()) && !Object.class.equals(descriptor.getMethod().getDeclaringClass()))
148                     {
149                         final MethodMetaData methodMetaData = new MethodMetaData(beanMetaData, descriptor);
150                         beanMetaData.addMethodMetaData(methodMetaData);
151                         for (MetaDataDecorator<MethodMetaData> decorator : methodMetaDataDecorators)
152                         {
153                             decorator.decorate(methodMetaData);
154                         }
155                     }
156                 }
157                 metaDataMap.put(beanClass, beanMetaData);
158                 return beanMetaData;
159             }
160             catch (IntrospectionException e)
161             {
162                 throw new RuntimeException("Unable to lookup bean information for bean class " + beanClass.getName() + ".", e);
163             }
164         }
165     }
166 }