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.core;
018:
019: import java.io.PrintWriter;
020: import java.io.StringWriter;
021:
022: import org.springframework.util.Assert;
023:
024: /**
025: * Static factory to conceal the automatic choice of the ControlFlow
026: * implementation class.
027: *
028: * <p>This implementation always uses the efficient Java 1.4 StackTraceElement
029: * mechanism for analyzing control flows.
030: *
031: * @author Rod Johnson
032: * @author Juergen Hoeller
033: * @since 02.02.2004
034: */
035: public abstract class ControlFlowFactory {
036:
037: /**
038: * Return an appropriate {@link ControlFlow} instance.
039: */
040: public static ControlFlow createControlFlow() {
041: return new Jdk14ControlFlow();
042: }
043:
044: /**
045: * Utilities for cflow-style pointcuts. Note that such pointcuts are
046: * 5-10 times more expensive to evaluate than other pointcuts, as they require
047: * analysis of the stack trace (through constructing a new throwable).
048: * However, they are useful in some cases.
049: * <p>This implementation uses the StackTraceElement class introduced in Java 1.4.
050: * @see java.lang.StackTraceElement
051: */
052: static class Jdk14ControlFlow implements ControlFlow {
053:
054: private StackTraceElement[] stack;
055:
056: public Jdk14ControlFlow() {
057: this .stack = new Throwable().getStackTrace();
058: }
059:
060: /**
061: * Searches for class name match in a StackTraceElement.
062: */
063: public boolean under(Class clazz) {
064: Assert.notNull(clazz, "Class must not be null");
065: String className = clazz.getName();
066: for (int i = 0; i < stack.length; i++) {
067: if (this .stack[i].getClassName().equals(className)) {
068: return true;
069: }
070: }
071: return false;
072: }
073:
074: /**
075: * Searches for class name match plus method name match
076: * in a StackTraceElement.
077: */
078: public boolean under(Class clazz, String methodName) {
079: Assert.notNull(clazz, "Class must not be null");
080: Assert.notNull(methodName, "Method name must not be null");
081: String className = clazz.getName();
082: for (int i = 0; i < this .stack.length; i++) {
083: if (this .stack[i].getClassName().equals(className)
084: && this .stack[i].getMethodName().equals(
085: methodName)) {
086: return true;
087: }
088: }
089: return false;
090: }
091:
092: /**
093: * Leave it up to the caller to decide what matches.
094: * Caller must understand stack trace format, so there's less abstraction.
095: */
096: public boolean underToken(String token) {
097: if (token == null) {
098: return false;
099: }
100: StringWriter sw = new StringWriter();
101: new Throwable().printStackTrace(new PrintWriter(sw));
102: String stackTrace = sw.toString();
103: return stackTrace.indexOf(token) != -1;
104: }
105:
106: public String toString() {
107: StringBuffer sb = new StringBuffer("Jdk14ControlFlow: ");
108: for (int i = 0; i < this .stack.length; i++) {
109: if (i > 0) {
110: sb.append("\n\t@");
111: }
112: sb.append(this.stack[i]);
113: }
114: return sb.toString();
115: }
116: }
117:
118: }
|