001/*
002 * Copyright 2002-2013 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;
020
021import org.springframework.aop.ClassFilter;
022import org.springframework.util.Assert;
023import org.springframework.util.ObjectUtils;
024
025/**
026 * Static utility methods for composing {@link ClassFilter ClassFilters}.
027 *
028 * @author Rod Johnson
029 * @author Rob Harrop
030 * @author Juergen Hoeller
031 * @since 11.11.2003
032 * @see MethodMatchers
033 * @see Pointcuts
034 */
035public abstract class ClassFilters {
036
037        /**
038         * Match all classes that <i>either</i> (or both) of the given ClassFilters matches.
039         * @param cf1 the first ClassFilter
040         * @param cf2 the second ClassFilter
041         * @return a distinct ClassFilter that matches all classes that either
042         * of the given ClassFilter matches
043         */
044        public static ClassFilter union(ClassFilter cf1, ClassFilter cf2) {
045                Assert.notNull(cf1, "First ClassFilter must not be null");
046                Assert.notNull(cf2, "Second ClassFilter must not be null");
047                return new UnionClassFilter(new ClassFilter[] {cf1, cf2});
048        }
049
050        /**
051         * Match all classes that <i>either</i> (or all) of the given ClassFilters matches.
052         * @param classFilters the ClassFilters to match
053         * @return a distinct ClassFilter that matches all classes that either
054         * of the given ClassFilter matches
055         */
056        public static ClassFilter union(ClassFilter[] classFilters) {
057                Assert.notEmpty(classFilters, "ClassFilter array must not be empty");
058                return new UnionClassFilter(classFilters);
059        }
060
061        /**
062         * Match all classes that <i>both</i> of the given ClassFilters match.
063         * @param cf1 the first ClassFilter
064         * @param cf2 the second ClassFilter
065         * @return a distinct ClassFilter that matches all classes that both
066         * of the given ClassFilter match
067         */
068        public static ClassFilter intersection(ClassFilter cf1, ClassFilter cf2) {
069                Assert.notNull(cf1, "First ClassFilter must not be null");
070                Assert.notNull(cf2, "Second ClassFilter must not be null");
071                return new IntersectionClassFilter(new ClassFilter[] {cf1, cf2});
072        }
073
074        /**
075         * Match all classes that <i>all</i> of the given ClassFilters match.
076         * @param classFilters the ClassFilters to match
077         * @return a distinct ClassFilter that matches all classes that both
078         * of the given ClassFilter match
079         */
080        public static ClassFilter intersection(ClassFilter[] classFilters) {
081                Assert.notEmpty(classFilters, "ClassFilter array must not be empty");
082                return new IntersectionClassFilter(classFilters);
083        }
084
085
086        /**
087         * ClassFilter implementation for a union of the given ClassFilters.
088         */
089        @SuppressWarnings("serial")
090        private static class UnionClassFilter implements ClassFilter, Serializable {
091
092                private ClassFilter[] filters;
093
094                public UnionClassFilter(ClassFilter[] filters) {
095                        this.filters = filters;
096                }
097
098                @Override
099                public boolean matches(Class<?> clazz) {
100                        for (ClassFilter filter : this.filters) {
101                                if (filter.matches(clazz)) {
102                                        return true;
103                                }
104                        }
105                        return false;
106                }
107
108                @Override
109                public boolean equals(Object other) {
110                        return (this == other || (other instanceof UnionClassFilter &&
111                                        ObjectUtils.nullSafeEquals(this.filters, ((UnionClassFilter) other).filters)));
112                }
113
114                @Override
115                public int hashCode() {
116                        return ObjectUtils.nullSafeHashCode(this.filters);
117                }
118        }
119
120
121        /**
122         * ClassFilter implementation for an intersection of the given ClassFilters.
123         */
124        @SuppressWarnings("serial")
125        private static class IntersectionClassFilter implements ClassFilter, Serializable {
126
127                private ClassFilter[] filters;
128
129                public IntersectionClassFilter(ClassFilter[] filters) {
130                        this.filters = filters;
131                }
132
133                @Override
134                public boolean matches(Class<?> clazz) {
135                        for (ClassFilter filter : this.filters) {
136                                if (!filter.matches(clazz)) {
137                                        return false;
138                                }
139                        }
140                        return true;
141                }
142
143                @Override
144                public boolean equals(Object other) {
145                        return (this == other || (other instanceof IntersectionClassFilter &&
146                                        ObjectUtils.nullSafeEquals(this.filters, ((IntersectionClassFilter) other).filters)));
147                }
148
149                @Override
150                public int hashCode() {
151                        return ObjectUtils.nullSafeHashCode(this.filters);
152                }
153        }
154
155}