KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > core > ControlFlowFactory


1 /*
2  * Copyright 2002-2006 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
17 package org.springframework.core;
18
19 import java.io.PrintWriter JavaDoc;
20 import java.io.StringWriter JavaDoc;
21
22 import org.springframework.util.Assert;
23
24 /**
25  * Static factory to conceal automatic choice of Java 1.4 or 1.3 ControlFlow
26  * implementation class.
27  *
28  * <p>We want to use the more efficient Java 1.4 StackTraceElement if we can,
29  * but we don't want to impose a runtime dependency on JDK 1.4.
30  *
31  * @author Rod Johnson
32  * @author Juergen Hoeller
33  * @since 02.02.2004
34  */

35 public abstract class ControlFlowFactory {
36
37     /**
38      * Returns an appropriate {@link ControlFlow} instance.
39      * @return an appropriate {@link ControlFlow} instance
40      */

41     public static ControlFlow createControlFlow() {
42         return JdkVersion.isAtLeastJava14() ?
43                 (ControlFlow) new Jdk14ControlFlow() :
44                 (ControlFlow) new Jdk13ControlFlow();
45     }
46
47
48     /**
49      * Utilities for cflow-style pointcuts. Note that such pointcuts are
50      * 5-10 times more expensive to evaluate than other pointcuts, as they require
51      * analysis of the stack trace (through constructing a new throwable).
52      * However, they are useful in some cases.
53      * <p>This implementation uses the StackTraceElement class introduced in Java 1.4.
54      * @see java.lang.StackTraceElement
55      */

56     static class Jdk14ControlFlow implements ControlFlow {
57
58         private StackTraceElement JavaDoc[] stack;
59
60         public Jdk14ControlFlow() {
61             this.stack = new Throwable JavaDoc().getStackTrace();
62         }
63
64         /**
65          * Searches for class name match in a StackTraceElement.
66          */

67         public boolean under(Class JavaDoc clazz) {
68             Assert.notNull(clazz, "Class must not be null");
69             String JavaDoc className = clazz.getName();
70             for (int i = 0; i < stack.length; i++) {
71                 if (this.stack[i].getClassName().equals(className)) {
72                     return true;
73                 }
74             }
75             return false;
76         }
77
78         /**
79          * Searches for class name match plus method name match
80          * in a StackTraceElement.
81          */

82         public boolean under(Class JavaDoc clazz, String JavaDoc methodName) {
83             Assert.notNull(clazz, "Class must not be null");
84             Assert.notNull(methodName, "Method name must not be null");
85             String JavaDoc className = clazz.getName();
86             for (int i = 0; i < this.stack.length; i++) {
87                 if (this.stack[i].getClassName().equals(className) &&
88                         this.stack[i].getMethodName().equals(methodName)) {
89                     return true;
90                 }
91             }
92             return false;
93         }
94
95         /**
96          * Leave it up to the caller to decide what matches.
97          * Caller must understand stack trace format, so there's less abstraction.
98          */

99         public boolean underToken(String JavaDoc token) {
100             if (token == null) {
101                 return false;
102             }
103             StringWriter JavaDoc sw = new StringWriter JavaDoc();
104             new Throwable JavaDoc().printStackTrace(new PrintWriter JavaDoc(sw));
105             String JavaDoc stackTrace = sw.toString();
106             return stackTrace.indexOf(token) != -1;
107         }
108
109         public String JavaDoc toString() {
110             StringBuffer JavaDoc sb = new StringBuffer JavaDoc("Jdk14ControlFlow: ");
111             for (int i = 0; i < this.stack.length; i++) {
112                 if (i > 0) {
113                     sb.append("\n\t@");
114                 }
115                 sb.append(this.stack[i]);
116             }
117             return sb.toString();
118         }
119     }
120
121
122     /**
123      * Java 1.3 version of utilities for cflow-style pointcuts. We can't
124      * rely on the Java 1.4 StackTraceElement class.
125      * <p>Note that such pointcuts are 10-15 times more expensive to evaluate under
126      * JDK 1.3 than other pointcuts, as they require analysis of the stack trace
127      * (through constructing a new throwable). However, they are useful in some cases.
128      */

129     static class Jdk13ControlFlow implements ControlFlow {
130
131         private final String JavaDoc stackTrace;
132
133         private final int stackTraceLength;
134
135         public Jdk13ControlFlow() {
136             StringWriter JavaDoc sw = new StringWriter JavaDoc();
137             new Throwable JavaDoc().printStackTrace(new PrintWriter JavaDoc(sw));
138             this.stackTrace = sw.toString();
139             this.stackTraceLength = this.stackTrace.length();
140         }
141
142         /**
143          * Searches for class name match in the stringified stacktrace.
144          */

145         public boolean under(Class JavaDoc clazz) {
146             Assert.notNull(clazz, "Class must not be null");
147             return this.stackTrace.indexOf(clazz.getName()) != -1;
148         }
149
150         /**
151          * Searches for class name + "." + method name match in the stringified
152          * stacktrace. Checks the character right after the method name for '('
153          * or whitespace, to only match the exact method name (and not a method
154          * with a longer name that happens to start with the same characters).
155          * <p>The whitespace check has been introduced for compatibility with
156          * GNU ClassPath, as of Spring 1.2.7. Sun JDKs (and JDKs with licensed
157          * Sun core libraries) always append '(' right after the method name.
158          */

159         public boolean under(Class JavaDoc clazz, String JavaDoc methodName) {
160             Assert.notNull(clazz, "Class must not be null");
161             Assert.notNull(methodName, "Method name must not be null");
162             String JavaDoc searchPattern = clazz.getName() + "." + methodName;
163             int patternLength = searchPattern.length();
164             int index = 0;
165             do {
166                 index = this.stackTrace.indexOf(searchPattern, index);
167                 if (index != -1) {
168                     int endIndex = index + patternLength;
169                     if (endIndex == this.stackTraceLength) {
170                         return true;
171                     }
172                     char afterPattern = this.stackTrace.charAt(endIndex);
173                     if (afterPattern == '(' || Character.isWhitespace(afterPattern)) {
174                         return true;
175                     }
176                     index = endIndex;
177                 }
178             }
179             while (index != -1);
180             return false;
181         }
182
183         /**
184          * Leave it up to the caller to decide what matches.
185          * Caller must understand stack trace format, so there's less abstraction.
186          */

187         public boolean underToken(String JavaDoc token) {
188             return (token != null && this.stackTrace.indexOf(token) != -1);
189         }
190     }
191
192 }
193
Popular Tags