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
18 package ch.elca.el4j.util.metadata;
19
20 import java.lang.reflect.Method;
21 import java.util.List;
22
23 import org.aopalliance.aop.Advice;
24 import org.aopalliance.intercept.MethodInterceptor;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
27 import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;
28 import org.springframework.beans.factory.InitializingBean;
29 import org.springframework.util.Assert;
30
31 import ch.elca.el4j.services.monitoring.notification.CoreNotificationHelper;
32 import ch.elca.el4j.util.metadata.annotations.Annotations;
33
34 /**
35 * This class simplifies the metadata programming.
36 *
37 * <p>
38 * One way to set up AOP in Spring is to define a DefaultAdvisorAutoProxyCreator
39 * bean which will create AOP proxies for all Advisors that are defined in the
40 * same BeanFactory. These advisors are the starting points for Attributes. For
41 * each attribute, at least 4 beans have to be defined:
42 * <dl>
43 * <dt>Advisor:</dt>
44 * <dd>Base interface holding AOP advice (action to take at a joinpoint).</dd>
45 * <dt>Advice:</dt>
46 * <dd>A possible advice is for example a MethodInterceptor which intercepts
47 * runtime events that occur within a base program. There is a link from
48 * the Advisor to the Advice.</dd>
49 * <dt>Source:</dt>
50 * <dd>Sources the attributes. There is a link from the Advice to the Source
51 * telling the Advice which attribute sources it has to consider.</dd>
52 * <dt>Attributes:</dt>
53 * <dd>The attributes implementation to use. There is a link from Source to
54 * Attributes to define where it has to take the attributes from.</dd>
55 * </dl>
56 * </p>
57 *
58 * <p>
59 * This class simplifies the creation of attributes. By using it, only two beans
60 * have to be defined:
61 * <dl>
62 * <dt>GenericMetaDataAdvisor:</dt>
63 * <dd>This bean is an advisor implementing the matches(Method, Class) method.
64 * This advisor also creates a DefaultGenericAttributeSource in case no
65 * one is defined in the configuration file. The attributes to which the
66 * Advice will react also have to be defined in the configuration
67 * file.</dd>
68 * <dt>Advice:</dt>
69 * <dd>An advice which will be invoked by this Advisor has to be injected via
70 * the configuration file.</dd>
71 * </dl>
72 *
73 * @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/GenericMetaDataAdvisor.java $
74 *
75 * @author Raphael Boog (RBO)
76 * @author Martin Zeltner (MZE)
77 */
78 public class GenericMetaDataAdvisor extends StaticMethodMatcherPointcutAdvisor
79 implements InitializingBean {
80 /**
81 * Private logger.
82 */
83 private static Logger s_logger
84 = LoggerFactory.getLogger(GenericMetaDataAdvisor.class);
85
86 /**
87 * The metadata source to lookup metadata.
88 */
89 private GenericMetaDataSource m_metaDataSource;
90
91 /**
92 * Are the metadata types where the interceptor will be applied.
93 */
94 private List<Class> m_interceptingMetaData;
95
96 /**
97 * Default constructor.
98 */
99 public GenericMetaDataAdvisor() { }
100
101 /**
102 * Constructor which sets the advice being received as parameter.
103 *
104 * @param advice The advice to set.
105 */
106 public GenericMetaDataAdvisor(Advice advice) {
107 setAdvice(advice);
108 }
109
110 /**
111 * @return Returns the interceptingMetaData.
112 */
113 public List<Class> getInterceptingMetaData() {
114 return m_interceptingMetaData;
115 }
116
117 /**
118 * @param interceptingMetaData Is the interceptingMetaData to set.
119 */
120 public void setInterceptingMetaData(List<Class> interceptingMetaData) {
121 m_interceptingMetaData = interceptingMetaData;
122 }
123
124 /**
125 * @return Returns the metaDataSource.
126 */
127 public GenericMetaDataSource getMetaDataSource() {
128 return m_metaDataSource;
129 }
130
131 /**
132 * @param metaDataSource Is the metaDataSource to set.
133 */
134 public void setMetaDataSource(GenericMetaDataSource metaDataSource) {
135 m_metaDataSource = metaDataSource;
136 }
137
138 /**
139 * A convenience getter method for the method interceptor.
140 *
141 * @return The methodInterceptor
142 */
143 public MethodInterceptor getMethodInterceptor() {
144 Advice advice = getAdvice();
145 Assert.isInstanceOf(MethodInterceptor.class, advice,
146 "Only method interception supported.");
147 return (MethodInterceptor) advice;
148 }
149
150 /**
151 * A convenience setter method for the method Interceptor.
152 *
153 * @param methodInterceptor
154 * The methodInterceptor to set.
155 */
156 public void setMethodInterceptor(MethodInterceptor methodInterceptor) {
157 setAdvice(methodInterceptor);
158 }
159
160 /**
161 * Perform static checking. If this returns false, no runtime check will be
162 * made.
163 *
164 * @param method
165 * the candidate method
166 * @param targetClass
167 * target class (may be null, in which case the candidate class
168 * must be taken to be the method's declaring class)
169 * @return whether or not this method matches statically
170 */
171 public boolean matches(Method method, Class targetClass) {
172 return getMetaDataSource().getMetaData(method, targetClass) != null;
173 }
174
175 /**
176 * {@inheritDoc}
177 */
178 public void afterPropertiesSet() throws Exception {
179
180 // Check whether an Advice has been defined.
181 CoreNotificationHelper.notifyIfEssentialPropertyIsEmpty(
182 getAdvice(), "advice", this);
183
184 // In case no MetaDataSource was defined, we create it on our own.
185 if (getMetaDataSource() == null) {
186 s_logger.debug("No specific metadata source set. Using default.");
187 setMetaDataSource(new DefaultGenericMetaDataSource());
188 }
189
190 // Set the metadata which 'invoke' the Advice
191 if (getMetaDataSource().getInterceptingMetaData() == null) {
192 s_logger.debug("No intercepting metadata set on metadata source. "
193 + "Using intercepting metadata from advisor.");
194 getMetaDataSource().setInterceptingMetaData(
195 getInterceptingMetaData());
196 }
197
198 // In case no metadata implementation is defined, we take the
199 // Annotation implementation. In order to provide splitting metadata
200 // on multiple source file we interposed the MetaDataCollector.
201 if (getMetaDataSource().getMetaDataDelegator() == null) {
202 MetaDataCollector collector = new MetaDataCollector();
203 collector.setMetaDataDelegator(new Annotations());
204 getMetaDataSource().setMetaDataDelegator(collector);
205 }
206
207 // In case the Advice implements MetaDataSourceAware, we set
208 // its MetaDataeSource
209 if (getAdvice() instanceof MetaDataSourceAware) {
210 ((MetaDataSourceAware) getAdvice())
211 .setMetaDataSource(getMetaDataSource());
212 }
213 }
214
215 }