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) 2006 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.core.aop;
18  
19  import java.lang.reflect.Proxy;
20  
21  import org.slf4j.Logger;
22  import org.slf4j.LoggerFactory;
23  import org.springframework.aop.TargetSource;
24  import org.springframework.aop.framework.adapter.AdvisorAdapterRegistry;
25  import org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry;
26  import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
27  import org.springframework.aop.support.AopUtils;
28  import org.springframework.beans.factory.BeanFactory;
29  import org.springframework.beans.factory.InitializingBean;
30  import org.springframework.beans.factory.config.BeanDefinition;
31  import org.springframework.beans.factory.support.DefaultListableBeanFactory;
32  import org.springframework.util.Assert;
33  
34  import ch.elca.el4j.services.monitoring.notification.CoreNotificationHelper;
35  import ch.elca.el4j.util.codingsupport.AopHelper;
36  
37  /**
38   * Intelligent autoproxy creator for advisors. Will not create a new proxy for a
39   * given bean if this bean is already a proxy bean. All class members (plus
40   * getter and setter for them) do just take place in this class, because class
41   * {@link AbstractAutoProxyCreator} hides them.
42   *
43   * @svnLink $Revision: 4204 $;$Date: 2010-11-02 11:44:37 +0100 (Di, 02. Nov 2010) $;$Author: swisswheel $;$URL: https://el4j.svn.sourceforge.net/svnroot/el4j/branches/el4j_3_1/el4j/framework/modules/core/src/main/java/ch/elca/el4j/core/aop/IntelligentAdvisorAutoProxyCreator.java $
44   *
45   * @author Martin Zeltner (MZE)
46   */
47  public class IntelligentAdvisorAutoProxyCreator extends DefaultAdvisorAutoProxyCreator implements InitializingBean {
48  	/**
49  	 * Serial version UID.
50  	 */
51  	private static final long serialVersionUID = 8582646215764283797L;
52  
53  	/**
54  	 * Private logger.
55  	 */
56  	private static final Logger s_logger = LoggerFactory.getLogger(IntelligentAdvisorAutoProxyCreator.class);
57  	
58  	/**
59  	 * COPYIED FROM SUPERCLASS!
60  	 *
61  	 * Names of common interceptors. We must use bean name rather than object
62  	 * references to handle prototype advisors/interceptors.
63  	 * Default is the empty array: no common interceptors.
64  	 */
65  	private String[] m_interceptorNames = new String[0];
66  	
67  	/**
68  	 * COPYIED FROM SUPERCLASS!
69  	 *
70  	 * Default is global AdvisorAdapterRegistry.
71  	 */
72  	private AdvisorAdapterRegistry m_advisorAdapterRegistry
73  		= GlobalAdvisorAdapterRegistry.getInstance();
74  
75  	/**
76  	 * COPYIED FROM SUPERCLASS!
77  	 *
78  	 * Default is "true"; else, bean-specific interceptors will get applied first.
79  	 */
80  	private boolean m_applyCommonInterceptorsFirst = true;
81  	
82  	/**
83  	 * If <code>true</code> (default) the use of advisor name prefix is mandatory.
84  	 * @see #setUsePrefix(boolean)
85  	 */
86  	private boolean forceUseOfAdvisorNamePrefix = true;
87  
88  	/**
89  	 * Will not create a new proxy for a given bean if this bean is already
90  	 * a proxy bean.
91  	 *
92  	 * {@inheritDoc}
93  	 */
94  	@SuppressWarnings("unchecked")
95  	@Override
96  	protected Object createProxy(Class beanClass, String beanName,
97  		Object[] specificInterceptors, TargetSource targetSource) {
98  		
99  		Object proxy = ProxyEnricher.enrichProxy(beanClass, beanName,
100 			specificInterceptors, targetSource, getInterceptorNames(),
101 			getBeanFactory(), getAdvisorAdapterRegistry(),
102 			isApplyCommonInterceptorsFirst());
103 		
104 		// If no proxy could be enriched create a new one.
105 		if (proxy == null) {
106 			proxy = super.createProxy(beanClass, beanName,
107 				specificInterceptors, targetSource);
108 		}
109 		return proxy;
110 	}
111 
112 	/**
113 	 * Here we additionally de-proxy beans (to avoid that certain applications of interceptors fail).
114 	 * 
115 	 * {@inheritDoc}
116 	 */
117 	@SuppressWarnings("unchecked")
118 	@Override	
119 	protected Object[] getAdvicesAndAdvisorsForBean(Class beanClass, String beanName, TargetSource targetSource) {
120 		Class deproxiedBeanClass = deproxyBeanClass(beanClass, beanName, getBeanFactory());
121 		return super.getAdvicesAndAdvisorsForBean(deproxiedBeanClass, beanName, targetSource);
122 	}
123 
124 	/**
125 	 * Finds out if the given class is a generated one of a proxy. If yes, the original class will be returned.
126 	 * 
127 	 * @param beanClass Is the class of the bean.
128 	 * @param beanName Is the name opf the bean.
129 	 * @param beanFactory Is the beanFactory (to be able to keep this method static).
130 	 * @return Returns the original class if it is a proxy class. Else the given class will be returned.
131 	 */
132 	@SuppressWarnings("unchecked")
133 	protected static Class deproxyBeanClass(Class beanClass, String beanName, BeanFactory beanFactory) {
134 		Class deproxiedBeanClass = beanClass;
135 		if (AopUtils.isCglibProxyClass(beanClass)) {
136 			deproxiedBeanClass = AopHelper.getClassOfCglibProxyClass(beanClass);
137 		} else if (Proxy.isProxyClass(beanClass) && (beanFactory instanceof DefaultListableBeanFactory)) {
138 			DefaultListableBeanFactory factory = (DefaultListableBeanFactory) beanFactory;
139 			BeanDefinition beanDefinition = factory.getBeanDefinition(beanName);
140 			if (!beanDefinition.isAbstract()) {
141 				String beanClassName = beanDefinition.getBeanClassName();
142 				try {
143 					// replace the beanClass (if it works - otherwise keep "old" beanClass)
144 					deproxiedBeanClass = beanClass.getClassLoader().loadClass(beanClassName);
145 				} catch (ClassNotFoundException e) {
146 					s_logger.debug("error deproxying beanClass:" + beanClass, e);
147 				} // ignore error in loading class, just return null
148 			}
149 		}
150 		return deproxiedBeanClass;
151 	}
152 
153 	/**
154 	 * @return Returns the interceptorNames.
155 	 */
156 	protected String[] getInterceptorNames() {
157 		return m_interceptorNames;
158 	}
159 
160 	/**
161 	 * COPYIED FROM SUPERCLASS!
162 	 * 
163 	 * Added to have access to the interceptor names.
164 	 *
165 	 * {@inheritDoc}
166 	 */
167 	@Override
168 	public void setInterceptorNames(String[] interceptorNames) {
169 		m_interceptorNames = interceptorNames;
170 		super.setInterceptorNames(interceptorNames);
171 	}
172 
173 	/**
174 	 * @return Returns the advisorAdapterRegistry.
175 	 */
176 	protected AdvisorAdapterRegistry getAdvisorAdapterRegistry() {
177 		return m_advisorAdapterRegistry;
178 	}
179 
180 	/**
181 	 * COPYIED FROM SUPERCLASS!
182 	 * 
183 	 * Added to have access to the interceptor names.
184 	 *
185 	 * {@inheritDoc}
186 	 */
187 	@Override
188 	public void setAdvisorAdapterRegistry(
189 		AdvisorAdapterRegistry advisorAdapterRegistry) {
190 		m_advisorAdapterRegistry = advisorAdapterRegistry;
191 		super.setAdvisorAdapterRegistry(advisorAdapterRegistry);
192 	}
193 	
194 	/**
195 	 * @return Returns the applyCommonInterceptorsFirst.
196 	 */
197 	protected boolean isApplyCommonInterceptorsFirst() {
198 		return m_applyCommonInterceptorsFirst;
199 	}
200 
201 	/**
202 	 * COPYIED FROM SUPERCLASS!
203 	 *
204 	 * Set whether the common interceptors should be applied before
205 	 * bean-specific ones. Default is "true"; else, bean-specific interceptors
206 	 * will get applied first.
207 	 *
208 	 * @param applyCommonInterceptorsFirst See method description.
209 	 */
210 	@Override
211 	public void setApplyCommonInterceptorsFirst(
212 		boolean applyCommonInterceptorsFirst) {
213 		m_applyCommonInterceptorsFirst = applyCommonInterceptorsFirst;
214 		super.setApplyCommonInterceptorsFirst(applyCommonInterceptorsFirst);
215 	}
216 
217 	/**
218 	 * @return Returns the forceUseOfAdvisorNamePrefix.
219 	 */
220 	public boolean isForceUseOfAdvisorNamePrefix() {
221 		return forceUseOfAdvisorNamePrefix;
222 	}
223 
224 	/**
225 	 * @param forceUseOfAdvisorNamePrefix Is the forceUseOfAdvisorNamePrefix to set.
226 	 */
227 	public void setForceUseOfAdvisorNamePrefix(boolean forceUseOfAdvisorNamePrefix) {
228 		this.forceUseOfAdvisorNamePrefix = forceUseOfAdvisorNamePrefix;
229 	}
230 	
231 	/**
232 	 * {@inheritDoc}
233 	 */
234 	@Override
235 	public void afterPropertiesSet() throws Exception {
236 		Assert.isTrue(!isForceUseOfAdvisorNamePrefix() || isUsePrefix(),
237 			"Property 'forceUseOfAdvisorNamePrefix' is set to true, so property 'usePrefix' must be true too. "
238 			+ "This was made to eliminate duplicated used advisors, so interceptors are not applied twice or "
239 			+ "even more on one bean.");
240 	}
241 }