View Javadoc

1   /*
2    * EL4J, the Extension Library for the J2EE, adds incremental enhancements to
3    * the spring framework, http://el4j.sf.net
4    * Copyright (C) 2005 by ELCA Informatique SA, Av. de la Harpe 22-24,
5    * 1000 Lausanne, Switzerland, http://www.elca.ch
6    *
7    * EL4J is published under the GNU Lesser General Public License (LGPL)
8    * Version 2.1. See http://www.gnu.org/licenses/
9    *
10   * This program is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13   * GNU Lesser General Public License for more details.
14   *
15   * For alternative licensing, please contact info@elca.ch
16   */
17  package ch.elca.el4j.util.metadata;
18  
19  import java.lang.reflect.Field;
20  import java.lang.reflect.Method;
21  import java.util.ArrayList;
22  import java.util.Collection;
23  import java.util.LinkedHashSet;
24  import java.util.List;
25  import java.util.Set;
26  
27  import org.springframework.beans.factory.InitializingBean;
28  
29  import ch.elca.el4j.services.monitoring.notification.CoreNotificationHelper;
30  
31  /**
32   * <p>
33   * Depending to the used kind of metadata, it can be defined on a field, on a
34   * method, on a class, and on a package. The used kinds of metadata are the
35   * <b>Commons Attributes</b> and the <b>Java 5 Annotations</b>. Both can handle
36   * metadata defined on a field, on a method, and on a class.
37   * </p>
38   *
39   * <p>
40   * This class collects metadata from different classes. The examples below
41   * show you how the metadata is collected.
42   * </p>
43   *
44   * <pre>
45   * public interface X {
46   *     public int getValue();
47   * }
48   *
49   * public interface Y {
50   *     public int getValue();
51   * }
52   *
53   * public class A implements X {
54   *     public int getValue() {...}
55   * }
56   *
57   * public class B extends A implements Y {
58   *     public int getValue() {...}
59   * }
60   *
61   * public class C extends B {
62   *     public int getValue() {...}
63   * }
64   * </pre>
65   *
66   * <p>
67   * If metadata for method <code>getValue()</code> of Class <code>C</code> is
68   * requested, the result will be a collection of metadata from class
69   * <code>C</code> and interfaces <code>Y</code> and <code>X</code>. Metadata
70   * defined in class <code>A</code> and <code>B</code> will be omitted.
71   * </p>
72   *
73   * <p>
74   * The same behavior can be found with metadata on class level. The collection
75   * of metadata will also only contain metadata defined on class <code>C</code>
76   * and interfaces <code>Y</code> and <code>X</code>.
77   * </p>
78   *
79   * <p>
80   * <b>Always the most specific implementation and all interfaces will be
81   * inspected.</b>
82   * </p>
83   *
84   * @svnLink $Revision: 4091 $;$Date: 2010-01-15 12:21:07 +0100 (Fr, 15. Jan 2010) $;$Author: jonasha $;$URL: https://el4j.svn.sourceforge.net/svnroot/el4j/branches/el4j_3_1/el4j/framework/modules/core/src/main/java/ch/elca/el4j/util/metadata/MetaDataCollector.java $
85   *
86   * @author Martin Zeltner (MZE)
87   */
88  public class MetaDataCollector implements Attributes, InitializingBean {
89  	/**
90  	 * Inner object to fetch metadata.
91  	 */
92  	private Attributes m_metaDataDelegator;
93  
94  	/**
95  	 * @return Returns the metaDataDelegator.
96  	 */
97  	public Attributes getMetaDataDelegator() {
98  		return m_metaDataDelegator;
99  	}
100 
101 	/**
102 	 * @param metaDataDelegator Is the metaDataDelegator to set.
103 	 */
104 	public void setMetaDataDelegator(Attributes metaDataDelegator) {
105 		m_metaDataDelegator = metaDataDelegator;
106 	}
107 
108 	/**
109 	 * {@inheritDoc}
110 	 */
111 	@SuppressWarnings("unchecked")
112 	public Collection getAttributes(Class targetClass) {
113 		Set attributeSet = new LinkedHashSet();
114 		List<Class> interfaceList
115 			= getAllInterfaces(new ArrayList<Class>(), targetClass);
116 		Attributes metaDataDelegator = getMetaDataDelegator();
117 
118 		attributeSet.addAll(metaDataDelegator.getAttributes(targetClass));
119 		for (Class iface : interfaceList) {
120 			attributeSet.addAll(metaDataDelegator.getAttributes(iface));
121 		}
122 		
123 		return attributeSet;
124 	}
125 
126 	/**
127 	 * {@inheritDoc}
128 	 */
129 	@SuppressWarnings("unchecked")
130 	public Collection getAttributes(Class targetClass, Class filter) {
131 		Set attributeSet = new LinkedHashSet();
132 		List<Class> interfaceList
133 			= getAllInterfaces(new ArrayList<Class>(), targetClass);
134 		Attributes metaDataDelegator = getMetaDataDelegator();
135 
136 		attributeSet.addAll(
137 			metaDataDelegator.getAttributes(targetClass, filter));
138 		for (Class iface : interfaceList) {
139 			attributeSet.addAll(
140 				metaDataDelegator.getAttributes(iface, filter));
141 		}
142 
143 		return attributeSet;
144 	}
145 
146 	/**
147 	 * {@inheritDoc}
148 	 */
149 	@SuppressWarnings("unchecked")
150 	public Collection getAttributes(Method targetMethod) {
151 		Set attributeSet = new LinkedHashSet();
152 		List<Class> interfaceList = getAllInterfaces(
153 			new ArrayList<Class>(), targetMethod.getDeclaringClass());
154 		Attributes metaDataDelegator = getMetaDataDelegator();
155 
156 		attributeSet.addAll(metaDataDelegator.getAttributes(targetMethod));
157 		for (Class iface : interfaceList) {
158 			try {
159 				Method m = iface.getDeclaredMethod(targetMethod.getName(),
160 						targetMethod.getParameterTypes());
161 				attributeSet.addAll(metaDataDelegator.getAttributes(m));
162 			// Checkstyle: EmptyBlock off
163 			} catch (NoSuchMethodException e) {
164 				// Do nothing. Method does not exist in current interface.
165 			}
166 			// Checkstyle: EmptyBlock off
167 		}
168 
169 		return attributeSet;
170 	}
171 
172 	/**
173 	 * {@inheritDoc}
174 	 */
175 	@SuppressWarnings("unchecked")
176 	public Collection getAttributes(Method targetMethod, Class filter) {
177 		Set attributeSet = new LinkedHashSet();
178 		List<Class> interfaceList = getAllInterfaces(
179 			new ArrayList<Class>(), targetMethod.getDeclaringClass());
180 		Attributes metaDataDelegator = getMetaDataDelegator();
181 
182 		attributeSet.addAll(
183 			metaDataDelegator.getAttributes(targetMethod, filter));
184 		for (Class iface : interfaceList) {
185 			try {
186 				Method m = iface.getDeclaredMethod(targetMethod.getName(),
187 						targetMethod.getParameterTypes());
188 				attributeSet.addAll(
189 					metaDataDelegator.getAttributes(m, filter));
190 			} catch (NoSuchMethodException e) {
191 				// Do nothing. Method does not exist in current interface.
192 			}
193 		}
194 
195 		return attributeSet;
196 	}
197 
198 	/**
199 	 * Method to get all interfaces, that are implemented by the
200 	 * given class and all its super classes.
201 	 *
202 	 * @param list
203 	 *            Is the list with all interfaces.
204 	 * @param clazz
205 	 *            Is the class, that must be analyzed.
206 	 * @return Returns the list with all interfaces.
207 	 */
208 	private List<Class> getAllInterfaces(List<Class> list, Class clazz) {
209 		if (clazz != null && clazz != Object.class) {
210 			Class[] classes = clazz.getInterfaces();
211 			for (Class c : classes) {
212 				list.add(c);
213 			}
214 			getAllInterfaces(list, clazz.getSuperclass());
215 		}
216 		return list;
217 	}
218 
219 	/**
220 	 * Directly calls the metadata delegator.
221 	 *
222 	 * {@inheritDoc}
223 	 */
224 	public Collection getAttributes(Field targetField) {
225 		return getMetaDataDelegator().getAttributes(targetField);
226 	}
227 
228 	/**
229 	 * Directly calls the metadata delegator.
230 	 *
231 	 * {@inheritDoc}
232 	 */
233 	public Collection getAttributes(Field targetField, Class filter) {
234 		return getMetaDataDelegator().getAttributes(targetField, filter);
235 	}
236 
237 	/**
238 	 * {@inheritDoc}
239 	 */
240 	public void afterPropertiesSet() throws Exception {
241 		if (getMetaDataDelegator() == null) {
242 			CoreNotificationHelper.notifyLackingEssentialProperty(
243 				"metaDataDelegator", this);
244 		}
245 	}
246 }