/*
 * Copyright 1999-2018 Alibaba Group Holding Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.alibaba.csp.sentinel.slots.block;

/**
 * Abstract exception indicating blocked by Sentinel due to flow control,
 * circuit breaking or system protection triggered.
 *
 * @author youji.zj
 */
public abstract class BlockException extends Exception {

    public static final String BLOCK_EXCEPTION_FLAG = "SentinelBlockException";
    /**
     * <p>this constant RuntimeException has no stack trace, just has a message
     * {@link #BLOCK_EXCEPTION_FLAG} that marks its name.
     * </p>
     * <p>
     * Use {@link #isBlockException(Throwable)} to check whether one Exception
     * Sentinel Blocked Exception.
     * </p>
     */
    public static RuntimeException THROW_OUT_EXCEPTION = new RuntimeException(BLOCK_EXCEPTION_FLAG);

    public static StackTraceElement[] sentinelStackTrace = new StackTraceElement[] {
        new StackTraceElement(BlockException.class.getName(), "block", "BlockException", 0)
    };

    static {
        THROW_OUT_EXCEPTION.setStackTrace(sentinelStackTrace);
    }

    protected AbstractRule rule;
    private String ruleLimitApp;

    public BlockException(String ruleLimitApp) {
        super();
        this.ruleLimitApp = ruleLimitApp;
    }

    public BlockException(String ruleLimitApp, AbstractRule rule) {
        super();
        this.ruleLimitApp = ruleLimitApp;
        this.rule = rule;
    }

    public BlockException(String message, Throwable cause) {
        super(message, cause);
    }

    public BlockException(String ruleLimitApp, String message) {
        super(message);
        this.ruleLimitApp = ruleLimitApp;
    }

    public BlockException(String ruleLimitApp, String message, AbstractRule rule) {
        super(message);
        this.ruleLimitApp = ruleLimitApp;
        this.rule = rule;
    }

    @Override
    public Throwable fillInStackTrace() {
        return this;
    }

    public String getRuleLimitApp() {
        return ruleLimitApp;
    }

    public void setRuleLimitApp(String ruleLimitApp) {
        this.ruleLimitApp = ruleLimitApp;
    }

    /**
     * Check whether the exception is sentinel blocked exception. One exception is sentinel blocked
     * exception only when:
     * <ul>
     * <li>the exception or its (sub-)cause is {@link BlockException}, or</li>
     * <li>the exception's message is or any of its sub-cause's message equals to {@link #BLOCK_EXCEPTION_FLAG}</li>
     * </ul>
     *
     * @param t the exception.
     * @return return true if the exception marks sentinel blocked exception.
     */
    public static boolean isBlockException(Throwable t) {
        if (null == t) {
            return false;
        }

        int counter = 0;
        Throwable cause = t;
        while (cause != null && counter++ < 50) {
            if ((cause instanceof BlockException) || (BLOCK_EXCEPTION_FLAG.equals(cause.getMessage()))) {
                return true;
            }
            cause = cause.getCause();
        }

        return false;
    }

    public AbstractRule getRule() {
        return rule;
    }
}

@@ -871,16 +871,69 @@
 tion %7B%0A%0A
+    private static final int MAX_SEARCH_DEPTH = 10;%0A%0A
     publ
@@ -1004,16 +1004,105 @@
 ption%22;%0A
+    public static final String BLOCK_EXCEPTION_MSG_PREFIX = %22SentinelBlockException: %22;%0A%0A
     /**%0A
@@ -2790,24 +2790,253 @@
 %0A    %7D%0A%0A
+    public RuntimeException toRuntimeException() %7B%0A        RuntimeException t = new RuntimeException(BLOCK_EXCEPTION_MSG_PREFIX + getClass().getSimpleName());%0A        t.setStackTrace(sentinelStackTrace);%0A        return t;%0A    %7D%0A%0A
     /**%0A
      * C
@@ -3023,24 +3023,24 @@
  %7D%0A%0A    /**%0A
-
      * Check
@@ -3281,19 +3281,16 @@
 message 
-is 
 or any o
@@ -3319,17 +3319,22 @@
 age 
-equals to
+is prefixed by
  %7B@l
@@ -3724,10 +3724,24 @@
 + %3C 
-50
+MAX_SEARCH_DEPTH
 ) %7B%0A
@@ -3755,17 +3755,16 @@
      if 
-(
 (cause i
@@ -3793,59 +3793,149 @@
 on) 
-%7C%7C (BLOCK_EXCEPTION_FLAG.equals(cause.getMessage())
+%7B%0A                return true;%0A            %7D%0A            if (cause.getMessage() != null && cause.getMessage().startsWith(BLOCK_EXCEPTION_FLAG
 )) %7B

Add RuntimeException converting method in BlockException and polish logic for validation