001/*
002 * Copyright 2002-2019 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.aop.support;
018
019import java.io.Serializable;
020import java.util.LinkedHashSet;
021import java.util.Set;
022
023import org.aopalliance.aop.Advice;
024
025import org.springframework.aop.ClassFilter;
026import org.springframework.aop.DynamicIntroductionAdvice;
027import org.springframework.aop.IntroductionAdvisor;
028import org.springframework.aop.IntroductionInfo;
029import org.springframework.core.Ordered;
030import org.springframework.lang.Nullable;
031import org.springframework.util.Assert;
032import org.springframework.util.ClassUtils;
033
034/**
035 * Simple {@link org.springframework.aop.IntroductionAdvisor} implementation
036 * that by default applies to any class.
037 *
038 * @author Rod Johnson
039 * @author Juergen Hoeller
040 * @since 11.11.2003
041 */
042@SuppressWarnings("serial")
043public class DefaultIntroductionAdvisor implements IntroductionAdvisor, ClassFilter, Ordered, Serializable {
044
045        private final Advice advice;
046
047        private final Set<Class<?>> interfaces = new LinkedHashSet<>();
048
049        private int order = Ordered.LOWEST_PRECEDENCE;
050
051
052        /**
053         * Create a DefaultIntroductionAdvisor for the given advice.
054         * @param advice the Advice to apply (may implement the
055         * {@link org.springframework.aop.IntroductionInfo} interface)
056         * @see #addInterface
057         */
058        public DefaultIntroductionAdvisor(Advice advice) {
059                this(advice, (advice instanceof IntroductionInfo ? (IntroductionInfo) advice : null));
060        }
061
062        /**
063         * Create a DefaultIntroductionAdvisor for the given advice.
064         * @param advice the Advice to apply
065         * @param introductionInfo the IntroductionInfo that describes
066         * the interface to introduce (may be {@code null})
067         */
068        public DefaultIntroductionAdvisor(Advice advice, @Nullable IntroductionInfo introductionInfo) {
069                Assert.notNull(advice, "Advice must not be null");
070                this.advice = advice;
071                if (introductionInfo != null) {
072                        Class<?>[] introducedInterfaces = introductionInfo.getInterfaces();
073                        if (introducedInterfaces.length == 0) {
074                                throw new IllegalArgumentException("IntroductionAdviceSupport implements no interfaces");
075                        }
076                        for (Class<?> ifc : introducedInterfaces) {
077                                addInterface(ifc);
078                        }
079                }
080        }
081
082        /**
083         * Create a DefaultIntroductionAdvisor for the given advice.
084         * @param advice the Advice to apply
085         * @param ifc the interface to introduce
086         */
087        public DefaultIntroductionAdvisor(DynamicIntroductionAdvice advice, Class<?> ifc) {
088                Assert.notNull(advice, "Advice must not be null");
089                this.advice = advice;
090                addInterface(ifc);
091        }
092
093
094        /**
095         * Add the specified interface to the list of interfaces to introduce.
096         * @param ifc the interface to introduce
097         */
098        public void addInterface(Class<?> ifc) {
099                Assert.notNull(ifc, "Interface must not be null");
100                if (!ifc.isInterface()) {
101                        throw new IllegalArgumentException("Specified class [" + ifc.getName() + "] must be an interface");
102                }
103                this.interfaces.add(ifc);
104        }
105
106        @Override
107        public Class<?>[] getInterfaces() {
108                return ClassUtils.toClassArray(this.interfaces);
109        }
110
111        @Override
112        public void validateInterfaces() throws IllegalArgumentException {
113                for (Class<?> ifc : this.interfaces) {
114                        if (this.advice instanceof DynamicIntroductionAdvice &&
115                                        !((DynamicIntroductionAdvice) this.advice).implementsInterface(ifc)) {
116                                throw new IllegalArgumentException("DynamicIntroductionAdvice [" + this.advice + "] " +
117                                                "does not implement interface [" + ifc.getName() + "] specified for introduction");
118                        }
119                }
120        }
121
122        public void setOrder(int order) {
123                this.order = order;
124        }
125
126        @Override
127        public int getOrder() {
128                return this.order;
129        }
130
131        @Override
132        public Advice getAdvice() {
133                return this.advice;
134        }
135
136        @Override
137        public boolean isPerInstance() {
138                return true;
139        }
140
141        @Override
142        public ClassFilter getClassFilter() {
143                return this;
144        }
145
146        @Override
147        public boolean matches(Class<?> clazz) {
148                return true;
149        }
150
151
152        @Override
153        public boolean equals(@Nullable Object other) {
154                if (this == other) {
155                        return true;
156                }
157                if (!(other instanceof DefaultIntroductionAdvisor)) {
158                        return false;
159                }
160                DefaultIntroductionAdvisor otherAdvisor = (DefaultIntroductionAdvisor) other;
161                return (this.advice.equals(otherAdvisor.advice) && this.interfaces.equals(otherAdvisor.interfaces));
162        }
163
164        @Override
165        public int hashCode() {
166                return this.advice.hashCode() * 13 + this.interfaces.hashCode();
167        }
168
169        @Override
170        public String toString() {
171                return getClass().getName() + ": advice [" + this.advice + "]; interfaces " +
172                                ClassUtils.classNamesToString(this.interfaces);
173        }
174
175}