PageRenderTime 52ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/projects/springframework-3.0.5/projects/org.springframework.aop/src/main/java/org/springframework/aop/framework/AdvisedSupport.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 607 lines | 347 code | 81 blank | 179 comment | 50 complexity | 5b2d1b17756ebd9f43aeaef3731c0ce5 MD5 | raw file
  1. /*
  2. * Copyright 2002-2010 the original author or authors.
  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. package org.springframework.aop.framework;
  17. import java.io.IOException;
  18. import java.io.ObjectInputStream;
  19. import java.lang.reflect.Method;
  20. import java.util.ArrayList;
  21. import java.util.Arrays;
  22. import java.util.Collection;
  23. import java.util.LinkedList;
  24. import java.util.List;
  25. import java.util.Map;
  26. import java.util.concurrent.ConcurrentHashMap;
  27. import org.aopalliance.aop.Advice;
  28. import org.springframework.aop.Advisor;
  29. import org.springframework.aop.DynamicIntroductionAdvice;
  30. import org.springframework.aop.IntroductionAdvisor;
  31. import org.springframework.aop.IntroductionInfo;
  32. import org.springframework.aop.TargetSource;
  33. import org.springframework.aop.support.DefaultIntroductionAdvisor;
  34. import org.springframework.aop.support.DefaultPointcutAdvisor;
  35. import org.springframework.aop.target.EmptyTargetSource;
  36. import org.springframework.aop.target.SingletonTargetSource;
  37. import org.springframework.util.Assert;
  38. import org.springframework.util.ClassUtils;
  39. import org.springframework.util.CollectionUtils;
  40. /**
  41. * Base class for AOP proxy configuration managers.
  42. * These are not themselves AOP proxies, but subclasses of this class are
  43. * normally factories from which AOP proxy instances are obtained directly.
  44. *
  45. * <p>This class frees subclasses of the housekeeping of Advices
  46. * and Advisors, but doesn't actually implement proxy creation
  47. * methods, which are provided by subclasses.
  48. *
  49. * <p>This class is serializable; subclasses need not be.
  50. * This class is used to hold snapshots of proxies.
  51. *
  52. * @author Rod Johnson
  53. * @author Juergen Hoeller
  54. * @see org.springframework.aop.framework.AopProxy
  55. */
  56. @SuppressWarnings("unchecked")
  57. public class AdvisedSupport extends ProxyConfig implements Advised {
  58. /** use serialVersionUID from Spring 2.0 for interoperability */
  59. private static final long serialVersionUID = 2651364800145442165L;
  60. /**
  61. * Canonical TargetSource when there's no target, and behavior is
  62. * supplied by the advisors.
  63. */
  64. public static final TargetSource EMPTY_TARGET_SOURCE = EmptyTargetSource.INSTANCE;
  65. /** Package-protected to allow direct access for efficiency */
  66. TargetSource targetSource = EMPTY_TARGET_SOURCE;
  67. /** Whether the Advisors are already filtered for the specific target class */
  68. private boolean preFiltered = false;
  69. /** The AdvisorChainFactory to use */
  70. AdvisorChainFactory advisorChainFactory = new DefaultAdvisorChainFactory();
  71. /** Cache with Method as key and advisor chain List as value */
  72. private transient Map<MethodCacheKey, List<Object>> methodCache;
  73. /**
  74. * Interfaces to be implemented by the proxy. Held in List to keep the order
  75. * of registration, to create JDK proxy with specified order of interfaces.
  76. */
  77. private List<Class> interfaces = new ArrayList<Class>();
  78. /**
  79. * List of Advisors. If an Advice is added, it will be wrapped
  80. * in an Advisor before being added to this List.
  81. */
  82. private List<Advisor> advisors = new LinkedList<Advisor>();
  83. /**
  84. * Array updated on changes to the advisors list, which is easier
  85. * to manipulate internally.
  86. */
  87. private Advisor[] advisorArray = new Advisor[0];
  88. /**
  89. * No-arg constructor for use as a JavaBean.
  90. */
  91. public AdvisedSupport() {
  92. initMethodCache();
  93. }
  94. /**
  95. * Create a AdvisedSupport instance with the given parameters.
  96. * @param interfaces the proxied interfaces
  97. */
  98. public AdvisedSupport(Class[] interfaces) {
  99. this();
  100. setInterfaces(interfaces);
  101. }
  102. /**
  103. * Initialize the method cache.
  104. */
  105. private void initMethodCache() {
  106. this.methodCache = new ConcurrentHashMap<MethodCacheKey, List<Object>>(32);
  107. }
  108. /**
  109. * Set the given object as target.
  110. * Will create a SingletonTargetSource for the object.
  111. * @see #setTargetSource
  112. * @see org.springframework.aop.target.SingletonTargetSource
  113. */
  114. public void setTarget(Object target) {
  115. setTargetSource(new SingletonTargetSource(target));
  116. }
  117. public void setTargetSource(TargetSource targetSource) {
  118. this.targetSource = (targetSource != null ? targetSource : EMPTY_TARGET_SOURCE);
  119. }
  120. public TargetSource getTargetSource() {
  121. return this.targetSource;
  122. }
  123. /**
  124. * Set a target class to be proxied, indicating that the proxy
  125. * should be castable to the given class.
  126. * <p>Internally, an {@link org.springframework.aop.target.EmptyTargetSource}
  127. * for the given target class will be used. The kind of proxy needed
  128. * will be determined on actual creation of the proxy.
  129. * <p>This is a replacement for setting a "targetSource" or "target",
  130. * for the case where we want a proxy based on a target class
  131. * (which can be an interface or a concrete class) without having
  132. * a fully capable TargetSource available.
  133. * @see #setTargetSource
  134. * @see #setTarget
  135. */
  136. public void setTargetClass(Class targetClass) {
  137. this.targetSource = EmptyTargetSource.forClass(targetClass);
  138. }
  139. public Class<?> getTargetClass() {
  140. return this.targetSource.getTargetClass();
  141. }
  142. public void setPreFiltered(boolean preFiltered) {
  143. this.preFiltered = preFiltered;
  144. }
  145. public boolean isPreFiltered() {
  146. return this.preFiltered;
  147. }
  148. /**
  149. * Set the advisor chain factory to use.
  150. * <p>Default is a {@link DefaultAdvisorChainFactory}.
  151. */
  152. public void setAdvisorChainFactory(AdvisorChainFactory advisorChainFactory) {
  153. Assert.notNull(advisorChainFactory, "AdvisorChainFactory must not be null");
  154. this.advisorChainFactory = advisorChainFactory;
  155. }
  156. /**
  157. * Return the advisor chain factory to use (never <code>null</code>).
  158. */
  159. public AdvisorChainFactory getAdvisorChainFactory() {
  160. return this.advisorChainFactory;
  161. }
  162. /**
  163. * Set the interfaces to be proxied.
  164. */
  165. public void setInterfaces(Class[] interfaces) {
  166. Assert.notNull(interfaces, "Interfaces must not be null");
  167. this.interfaces.clear();
  168. for (Class ifc : interfaces) {
  169. addInterface(ifc);
  170. }
  171. }
  172. /**
  173. * Add a new proxied interface.
  174. * @param intf the additional interface to proxy
  175. */
  176. public void addInterface(Class intf) {
  177. Assert.notNull(intf, "Interface must not be null");
  178. if (!intf.isInterface()) {
  179. throw new IllegalArgumentException("[" + intf.getName() + "] is not an interface");
  180. }
  181. if (!this.interfaces.contains(intf)) {
  182. this.interfaces.add(intf);
  183. adviceChanged();
  184. }
  185. }
  186. /**
  187. * Remove a proxied interface.
  188. * <p>Does nothing if the given interface isn't proxied.
  189. * @param intf the interface to remove from the proxy
  190. * @return <code>true</code> if the interface was removed; <code>false</code>
  191. * if the interface was not found and hence could not be removed
  192. */
  193. public boolean removeInterface(Class intf) {
  194. return this.interfaces.remove(intf);
  195. }
  196. public Class[] getProxiedInterfaces() {
  197. return this.interfaces.toArray(new Class[this.interfaces.size()]);
  198. }
  199. public boolean isInterfaceProxied(Class intf) {
  200. for (Class proxyIntf : this.interfaces) {
  201. if (intf.isAssignableFrom(proxyIntf)) {
  202. return true;
  203. }
  204. }
  205. return false;
  206. }
  207. public final Advisor[] getAdvisors() {
  208. return this.advisorArray;
  209. }
  210. public void addAdvisor(Advisor advisor) {
  211. int pos = this.advisors.size();
  212. addAdvisor(pos, advisor);
  213. }
  214. public void addAdvisor(int pos, Advisor advisor) throws AopConfigException {
  215. if (advisor instanceof IntroductionAdvisor) {
  216. validateIntroductionAdvisor((IntroductionAdvisor) advisor);
  217. }
  218. addAdvisorInternal(pos, advisor);
  219. }
  220. public boolean removeAdvisor(Advisor advisor) {
  221. int index = indexOf(advisor);
  222. if (index == -1) {
  223. return false;
  224. }
  225. else {
  226. removeAdvisor(index);
  227. return true;
  228. }
  229. }
  230. public void removeAdvisor(int index) throws AopConfigException {
  231. if (isFrozen()) {
  232. throw new AopConfigException("Cannot remove Advisor: Configuration is frozen.");
  233. }
  234. if (index < 0 || index > this.advisors.size() - 1) {
  235. throw new AopConfigException("Advisor index " + index + " is out of bounds: " +
  236. "This configuration only has " + this.advisors.size() + " advisors.");
  237. }
  238. Advisor advisor = this.advisors.get(index);
  239. if (advisor instanceof IntroductionAdvisor) {
  240. IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
  241. // We need to remove introduction interfaces.
  242. for (int j = 0; j < ia.getInterfaces().length; j++) {
  243. removeInterface(ia.getInterfaces()[j]);
  244. }
  245. }
  246. this.advisors.remove(index);
  247. updateAdvisorArray();
  248. adviceChanged();
  249. }
  250. public int indexOf(Advisor advisor) {
  251. Assert.notNull(advisor, "Advisor must not be null");
  252. return this.advisors.indexOf(advisor);
  253. }
  254. public boolean replaceAdvisor(Advisor a, Advisor b) throws AopConfigException {
  255. Assert.notNull(a, "Advisor a must not be null");
  256. Assert.notNull(b, "Advisor b must not be null");
  257. int index = indexOf(a);
  258. if (index == -1) {
  259. return false;
  260. }
  261. removeAdvisor(index);
  262. addAdvisor(index, b);
  263. return true;
  264. }
  265. /**
  266. * Add all of the given advisors to this proxy configuration.
  267. * @param advisors the advisors to register
  268. * @deprecated as of Spring 3.0, in favor of {@link #addAdvisors}
  269. */
  270. @Deprecated
  271. public void addAllAdvisors(Advisor[] advisors) {
  272. addAdvisors(Arrays.asList(advisors));
  273. }
  274. /**
  275. * Add all of the given advisors to this proxy configuration.
  276. * @param advisors the advisors to register
  277. */
  278. public void addAdvisors(Advisor... advisors) {
  279. addAdvisors(Arrays.asList(advisors));
  280. }
  281. /**
  282. * Add all of the given advisors to this proxy configuration.
  283. * @param advisors the advisors to register
  284. */
  285. public void addAdvisors(Collection<Advisor> advisors) {
  286. if (isFrozen()) {
  287. throw new AopConfigException("Cannot add advisor: Configuration is frozen.");
  288. }
  289. if (!CollectionUtils.isEmpty(advisors)) {
  290. for (Advisor advisor : advisors) {
  291. if (advisor instanceof IntroductionAdvisor) {
  292. validateIntroductionAdvisor((IntroductionAdvisor) advisor);
  293. }
  294. Assert.notNull(advisor, "Advisor must not be null");
  295. this.advisors.add(advisor);
  296. }
  297. updateAdvisorArray();
  298. adviceChanged();
  299. }
  300. }
  301. private void validateIntroductionAdvisor(IntroductionAdvisor advisor) {
  302. advisor.validateInterfaces();
  303. // If the advisor passed validation, we can make the change.
  304. Class[] ifcs = advisor.getInterfaces();
  305. for (Class ifc : ifcs) {
  306. addInterface(ifc);
  307. }
  308. }
  309. private void addAdvisorInternal(int pos, Advisor advisor) throws AopConfigException {
  310. Assert.notNull(advisor, "Advisor must not be null");
  311. if (isFrozen()) {
  312. throw new AopConfigException("Cannot add advisor: Configuration is frozen.");
  313. }
  314. if (pos > this.advisors.size()) {
  315. throw new IllegalArgumentException(
  316. "Illegal position " + pos + " in advisor list with size " + this.advisors.size());
  317. }
  318. this.advisors.add(pos, advisor);
  319. updateAdvisorArray();
  320. adviceChanged();
  321. }
  322. /**
  323. * Bring the array up to date with the list.
  324. */
  325. protected final void updateAdvisorArray() {
  326. this.advisorArray = this.advisors.toArray(new Advisor[this.advisors.size()]);
  327. }
  328. /**
  329. * Allows uncontrolled access to the {@link List} of {@link Advisor Advisors}.
  330. * <p>Use with care, and remember to {@link #updateAdvisorArray() refresh the advisor array}
  331. * and {@link #adviceChanged() fire advice changed events} when making any modifications.
  332. */
  333. protected final List<Advisor> getAdvisorsInternal() {
  334. return this.advisors;
  335. }
  336. public void addAdvice(Advice advice) throws AopConfigException {
  337. int pos = this.advisors.size();
  338. addAdvice(pos, advice);
  339. }
  340. /**
  341. * Cannot add introductions this way unless the advice implements IntroductionInfo.
  342. */
  343. public void addAdvice(int pos, Advice advice) throws AopConfigException {
  344. Assert.notNull(advice, "Advice must not be null");
  345. if (advice instanceof IntroductionInfo) {
  346. // We don't need an IntroductionAdvisor for this kind of introduction:
  347. // It's fully self-describing.
  348. addAdvisor(pos, new DefaultIntroductionAdvisor(advice, (IntroductionInfo) advice));
  349. }
  350. else if (advice instanceof DynamicIntroductionAdvice) {
  351. // We need an IntroductionAdvisor for this kind of introduction.
  352. throw new AopConfigException("DynamicIntroductionAdvice may only be added as part of IntroductionAdvisor");
  353. }
  354. else {
  355. addAdvisor(pos, new DefaultPointcutAdvisor(advice));
  356. }
  357. }
  358. public boolean removeAdvice(Advice advice) throws AopConfigException {
  359. int index = indexOf(advice);
  360. if (index == -1) {
  361. return false;
  362. }
  363. else {
  364. removeAdvisor(index);
  365. return true;
  366. }
  367. }
  368. public int indexOf(Advice advice) {
  369. Assert.notNull(advice, "Advice must not be null");
  370. for (int i = 0; i < this.advisors.size(); i++) {
  371. Advisor advisor = this.advisors.get(i);
  372. if (advisor.getAdvice() == advice) {
  373. return i;
  374. }
  375. }
  376. return -1;
  377. }
  378. /**
  379. * Is the given advice included in any advisor within this proxy configuration?
  380. * @param advice the advice to check inclusion of
  381. * @return whether this advice instance is included
  382. */
  383. public boolean adviceIncluded(Advice advice) {
  384. if (advice != null) {
  385. for (Advisor advisor : this.advisors) {
  386. if (advisor.getAdvice() == advice) {
  387. return true;
  388. }
  389. }
  390. }
  391. return false;
  392. }
  393. /**
  394. * Count advices of the given class.
  395. * @param adviceClass the advice class to check
  396. * @return the count of the interceptors of this class or subclasses
  397. */
  398. public int countAdvicesOfType(Class adviceClass) {
  399. int count = 0;
  400. if (adviceClass != null) {
  401. for (Advisor advisor : this.advisors) {
  402. if (adviceClass.isInstance(advisor.getAdvice())) {
  403. count++;
  404. }
  405. }
  406. }
  407. return count;
  408. }
  409. /**
  410. * Determine a list of {@link org.aopalliance.intercept.MethodInterceptor} objects
  411. * for the given method, based on this configuration.
  412. * @param method the proxied method
  413. * @param targetClass the target class
  414. * @return List of MethodInterceptors (may also include InterceptorAndDynamicMethodMatchers)
  415. */
  416. public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class targetClass) {
  417. MethodCacheKey cacheKey = new MethodCacheKey(method);
  418. List<Object> cached = this.methodCache.get(cacheKey);
  419. if (cached == null) {
  420. cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
  421. this, method, targetClass);
  422. this.methodCache.put(cacheKey, cached);
  423. }
  424. return cached;
  425. }
  426. /**
  427. * Invoked when advice has changed.
  428. */
  429. protected void adviceChanged() {
  430. this.methodCache.clear();
  431. }
  432. /**
  433. * Call this method on a new instance created by the no-arg constructor
  434. * to create an independent copy of the configuration from the given object.
  435. * @param other the AdvisedSupport object to copy configuration from
  436. */
  437. protected void copyConfigurationFrom(AdvisedSupport other) {
  438. copyConfigurationFrom(other, other.targetSource, new ArrayList<Advisor>(other.advisors));
  439. }
  440. /**
  441. * Copy the AOP configuration from the given AdvisedSupport object,
  442. * but allow substitution of a fresh TargetSource and a given interceptor chain.
  443. * @param other the AdvisedSupport object to take proxy configuration from
  444. * @param targetSource the new TargetSource
  445. * @param advisors the Advisors for the chain
  446. */
  447. protected void copyConfigurationFrom(AdvisedSupport other, TargetSource targetSource, List<Advisor> advisors) {
  448. copyFrom(other);
  449. this.targetSource = targetSource;
  450. this.advisorChainFactory = other.advisorChainFactory;
  451. this.interfaces = new ArrayList<Class>(other.interfaces);
  452. for (Advisor advisor : advisors) {
  453. if (advisor instanceof IntroductionAdvisor) {
  454. validateIntroductionAdvisor((IntroductionAdvisor) advisor);
  455. }
  456. Assert.notNull(advisor, "Advisor must not be null");
  457. this.advisors.add(advisor);
  458. }
  459. updateAdvisorArray();
  460. adviceChanged();
  461. }
  462. /**
  463. * Build a configuration-only copy of this AdvisedSupport,
  464. * replacing the TargetSource
  465. */
  466. AdvisedSupport getConfigurationOnlyCopy() {
  467. AdvisedSupport copy = new AdvisedSupport();
  468. copy.copyFrom(this);
  469. copy.targetSource = EmptyTargetSource.forClass(getTargetClass(), getTargetSource().isStatic());
  470. copy.advisorChainFactory = this.advisorChainFactory;
  471. copy.interfaces = this.interfaces;
  472. copy.advisors = this.advisors;
  473. copy.updateAdvisorArray();
  474. return copy;
  475. }
  476. //---------------------------------------------------------------------
  477. // Serialization support
  478. //---------------------------------------------------------------------
  479. private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
  480. // Rely on default serialization; just initialize state after deserialization.
  481. ois.defaultReadObject();
  482. // Initialize transient fields.
  483. initMethodCache();
  484. }
  485. public String toProxyConfigString() {
  486. return toString();
  487. }
  488. /**
  489. * For debugging/diagnostic use.
  490. */
  491. @Override
  492. public String toString() {
  493. StringBuilder sb = new StringBuilder(getClass().getName());
  494. sb.append(": ").append(this.interfaces.size()).append(" interfaces ");
  495. sb.append(ClassUtils.classNamesToString(this.interfaces)).append("; ");
  496. sb.append(this.advisors.size()).append(" advisors ");
  497. sb.append(this.advisors).append("; ");
  498. sb.append("targetSource [").append(this.targetSource).append("]; ");
  499. sb.append(super.toString());
  500. return sb.toString();
  501. }
  502. /**
  503. * Simple wrapper class around a Method. Used as the key when
  504. * caching methods, for efficient equals and hashCode comparisons.
  505. */
  506. private static class MethodCacheKey {
  507. private final Method method;
  508. private final int hashCode;
  509. public MethodCacheKey(Method method) {
  510. this.method = method;
  511. this.hashCode = method.hashCode();
  512. }
  513. @Override
  514. public boolean equals(Object other) {
  515. if (other == this) {
  516. return true;
  517. }
  518. MethodCacheKey otherKey = (MethodCacheKey) other;
  519. return (this.method == otherKey.method);
  520. }
  521. @Override
  522. public int hashCode() {
  523. return this.hashCode;
  524. }
  525. }
  526. }