001: /*
002: * Copyright 2002-2007 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: * http://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:
017: package org.springframework.aop.support;
018:
019: import java.io.Serializable;
020:
021: import org.aopalliance.aop.Advice;
022:
023: import org.springframework.aop.Pointcut;
024: import org.springframework.core.JdkVersion;
025: import org.springframework.util.ObjectUtils;
026:
027: /**
028: * Convenient class for regexp method pointcuts that hold an Advice,
029: * making them an {@link org.springframework.aop.Advisor}.
030: *
031: * <p>Configure this class using the "pattern" and "patterns"
032: * pass-through properties. These are analogous to the pattern
033: * and patterns properties of {@link AbstractRegexpMethodPointcut}.
034: *
035: * <p>Can delegate to any {@link AbstractRegexpMethodPointcut} subclass,
036: * like {@link Perl5RegexpMethodPointcut} or {@link JdkRegexpMethodPointcut}.
037: * To choose a specific one, either override the {@link #createPointcut}
038: * method or set the "perl5" flag accordingly.
039: *
040: * <p>By default, {@link JdkRegexpMethodPointcut} will be used on JDK 1.4+,
041: * falling back to {@link Perl5RegexpMethodPointcut} on JDK 1.3 (requiring
042: * Jakarta ORO on the classpath). The use of Perl5RegexpMethodPointcut
043: * can be enforced through specifying the "perl5" property.
044: *
045: * @author Rod Johnson
046: * @author Juergen Hoeller
047: * @see #setPattern
048: * @see #setPatterns
049: * @see #setPerl5
050: * @see #createPointcut
051: * @see Perl5RegexpMethodPointcut
052: * @see JdkRegexpMethodPointcut
053: */
054: public class RegexpMethodPointcutAdvisor extends
055: AbstractGenericPointcutAdvisor {
056:
057: private String[] patterns;
058:
059: private boolean perl5 = false;
060:
061: private AbstractRegexpMethodPointcut pointcut;
062:
063: private final Object pointcutMonitor = new SerializableMonitor();
064:
065: /**
066: * Create an empty RegexpMethodPointcutAdvisor.
067: * @see #setPattern
068: * @see #setPatterns
069: * @see #setPerl5
070: * @see #setAdvice
071: */
072: public RegexpMethodPointcutAdvisor() {
073: }
074:
075: /**
076: * Create a RegexpMethodPointcutAdvisor for the given advice.
077: * The pattern still needs to be specified afterwards.
078: * @param advice the advice to use
079: * @see #setPattern
080: * @see #setPatterns
081: * @see #setPerl5
082: */
083: public RegexpMethodPointcutAdvisor(Advice advice) {
084: setAdvice(advice);
085: }
086:
087: /**
088: * Create a RegexpMethodPointcutAdvisor for the given advice.
089: * @param pattern the pattern to use
090: * @param advice the advice to use
091: * @see #setPerl5
092: */
093: public RegexpMethodPointcutAdvisor(String pattern, Advice advice) {
094: setPattern(pattern);
095: setAdvice(advice);
096: }
097:
098: /**
099: * Create a RegexpMethodPointcutAdvisor for the given advice.
100: * @param patterns the patterns to use
101: * @param advice the advice to use
102: * @see #setPerl5
103: */
104: public RegexpMethodPointcutAdvisor(String[] patterns, Advice advice) {
105: setPatterns(patterns);
106: setAdvice(advice);
107: }
108:
109: /**
110: * Set the regular expression defining methods to match.
111: * <p>Use either this method or {@link #setPatterns}, not both.
112: * @see #setPatterns
113: */
114: public void setPattern(String pattern) {
115: setPatterns(new String[] { pattern });
116: }
117:
118: /**
119: * Set the regular expressions defining methods to match.
120: * To be passed through to the pointcut implementation.
121: * <p>Matching will be the union of all these; if any of the
122: * patterns matches, the pointcut matches.
123: * @see AbstractRegexpMethodPointcut#setPatterns
124: */
125: public void setPatterns(String[] patterns) {
126: this .patterns = patterns;
127: }
128:
129: /**
130: * Set whether to enforce Perl5 regexp syntax. Default is "false".
131: * <p>Turn this flag on to use {@link Perl5RegexpMethodPointcut}
132: * (delegating to Jakarta ORO). Else, {@link JdkRegexpMethodPointcut} will
133: * be used on JDK 1.4+, falling back to Perl5RegexpMethodPointcut on JDK 1.3.
134: * <p>Alternatively, override the {@link #createPointcut} method.
135: * @see #createPointcut
136: * @see Perl5RegexpMethodPointcut
137: * @see JdkRegexpMethodPointcut
138: */
139: public void setPerl5(boolean perl5) {
140: this .perl5 = perl5;
141: }
142:
143: /**
144: * Initialize the singleton Pointcut held within this Advisor.
145: */
146: public Pointcut getPointcut() {
147: synchronized (this .pointcutMonitor) {
148: if (this .pointcut == null) {
149: this .pointcut = createPointcut();
150: this .pointcut.setPatterns(this .patterns);
151: }
152: return pointcut;
153: }
154: }
155:
156: /**
157: * Create the actual pointcut: By default, a {@link Perl5RegexpMethodPointcut}
158: * will be created if Perl5 syntax is enforced or when running on JDK 1.3.
159: * Else, a {@link JdkRegexpMethodPointcut} (JDK 1.4+) will be used.
160: * @return the Pointcut instance (never <code>null</code>)
161: * @see #setPerl5
162: * @see Perl5RegexpMethodPointcut
163: * @see JdkRegexpMethodPointcut
164: */
165: protected AbstractRegexpMethodPointcut createPointcut() {
166: if (this .perl5
167: || JdkVersion.getMajorJavaVersion() < JdkVersion.JAVA_14) {
168: // needs Jakarta ORO on the classpath
169: return Perl5RegexpPointcutFactory
170: .createPerl5RegexpPointcut();
171: } else {
172: // needs to run on JDK >= 1.4
173: return new JdkRegexpMethodPointcut();
174: }
175: }
176:
177: public String toString() {
178: return getClass().getName() + ": advice [" + getAdvice()
179: + "], pointcut patterns "
180: + ObjectUtils.nullSafeToString(this .patterns);
181: }
182:
183: /**
184: * Inner factory class used to just introduce an ORO dependency
185: * when actually creating a Perl5 regexp pointcut.
186: */
187: private static class Perl5RegexpPointcutFactory {
188:
189: public static AbstractRegexpMethodPointcut createPerl5RegexpPointcut() {
190: return new Perl5RegexpMethodPointcut();
191: }
192: }
193:
194: /**
195: * Empty class used for a serializable monitor object.
196: */
197: private static class SerializableMonitor implements Serializable {
198: }
199:
200: }
|