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  
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 }