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