All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.dbflute.hook.CallbackContext Maven / Gradle / Ivy

There is a newer version: 1.2.8
Show newest version
/*
 * Copyright 2014-2021 the original author or authors.
 *
 * 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 org.dbflute.hook;

import java.util.function.BiFunction;
import java.util.function.Consumer;

import org.dbflute.bhv.core.BehaviorCommandHook;
import org.dbflute.bhv.core.BehaviorCommandMeta;
import org.dbflute.util.DfTypeUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * The context of callback in DBFlute deep logic.
 * @author jflute
 */
public class CallbackContext {

    // ===================================================================================
    //                                                                          Definition
    //                                                                          ==========
    /** The logger instance for this class. (NotNull) */
    private static final Logger _log = LoggerFactory.getLogger(CallbackContext.class);

    // ===================================================================================
    //                                                                        Thread Local
    //                                                                        ============
    // -----------------------------------------------------
    //                                         Thread Object
    //                                         -------------
    /** The default thread-local for this. */
    protected static final ThreadLocal _defaultThreadLocal = new ThreadLocal();

    /** The default holder for callback context, using thread local. (NotNull) */
    protected static final CallbackContextHolder _defaultHolder = new CallbackContextHolder() {

        public CallbackContext provide() {
            return _defaultThreadLocal.get();
        }

        public void save(CallbackContext context) {
            _defaultThreadLocal.set(context);
        }
    };

    /** The holder for callback context, might be changed. (NotNull: null setting is not allowed) */
    protected static CallbackContextHolder _holder = _defaultHolder; // as default

    /** Is this static world locked? e.g. you should unlock it to set your own provider. */
    protected static boolean _locked = true; // at first locked

    /**
     * The holder of for callback context. 
* Basically for asynchronous of web framework e.g. Play2. */ public static interface CallbackContextHolder { /** * Provide callback context.
* You should return same instance in same request. * @return The instance of callback context. (NullAllowed: when no context, but should exist in real handling) */ CallbackContext provide(); /** * Hold callback context and save it in holder. * @param callbackContext The callback context set by static setter. (NullAllowed: if null, context is removed) */ void save(CallbackContext callbackContext); } // ----------------------------------------------------- // Basic Handling // -------------- /** * Get callback context on thread. * @return The context of callback. (NullAllowed) */ public static CallbackContext getCallbackContextOnThread() { return getActiveHolder().provide(); } /** * Set callback context on thread.
* You can use setting methods per interface instead of this method. * @param callbackContext The context of callback. (NotNull) */ public static void setCallbackContextOnThread(CallbackContext callbackContext) { if (callbackContext == null) { String msg = "The argument 'callbackContext' must not be null."; throw new IllegalArgumentException(msg); } getActiveHolder().save(callbackContext); } /** * Is existing callback context on thread?
* You can use determination methods per interface instead of this method. * @return The determination, true or false. */ public static boolean isExistCallbackContextOnThread() { return getActiveHolder().provide() != null; } /** * Clear callback context on thread.
* Basically you should call other clear methods per interfaces, * because this clear method clears all interfaces. */ public static void clearCallbackContextOnThread() { getActiveHolder().save(null); } /** * Get the active holder for callback context. * @return The holder instance to handle callback context. (NotNull) */ protected static CallbackContextHolder getActiveHolder() { return _holder; } // ----------------------------------------------------- // Management // ---------- /** * Use the surrogate holder for callback context. (automatically locked after setting)
* You should call this in application initialization if it needs. * @param holder The holder instance. (NullAllowed: if null, use default holder) */ public static void useSurrogateHolder(CallbackContextHolder holder) { assertNotLocked(); if (_log.isInfoEnabled()) { _log.info("...Setting surrogate holder for callback context: " + holder); } if (holder != null) { _holder = holder; } else { _holder = _defaultHolder; } _locked = true; } /** * Is this static world locked? * @return The determination, true or false. */ public static boolean isLocked() { return _locked; } /** * Lock this static world, e.g. not to set the holder of thread-local. */ public static void lock() { if (_log.isInfoEnabled()) { _log.info("...Locking the static world of the callback context!"); } _locked = true; } /** * Unlock this static world, e.g. to set the holder of thread-local. */ public static void unlock() { if (_log.isInfoEnabled()) { _log.info("...Unlocking the static world of the callback context!"); } _locked = false; } /** * Assert this is not locked. */ protected static void assertNotLocked() { if (!isLocked()) { return; } String msg = "The callback context is locked! Don't access at this timing!"; throw new IllegalStateException(msg); } // ----------------------------------------------------- // BehaviorCommandHook // ------------------- /** * Set the hook interface of behavior commands. (inheriting existing hooks as default)
* This hook interface is called-back before executing behavior commands and finally.
* The hook methods may be called by nested process so pay attention to it.
* And don't forget to terminate the last hook in finally scope. *
     * CallbackContext.setBehaviorCommandHook(new BehaviorCommandHook() {
     *     public void hookBefore(BehaviorCommandMeta meta) {
     *         // You can implement your favorite callback here.
     *     }
     *     public void hookFinally(BehaviorCommandMeta meta, RuntimeException cause) {
     *         // You can implement your favorite callback here.
     *     }
     * });
     * try {
     *     ...(DB access)
     * } finally {
     *     CallbackContext.terminateLastBehaviorCommandHookOnThread();
     * }
     * 
* @param behaviorCommandHook The hook interface of behavior commands. (NullAllowed: completely clear, Inheritable) */ public static void setBehaviorCommandHookOnThread(BehaviorCommandHook behaviorCommandHook) { final CallbackContext context = getOrCreateContext(); context.setBehaviorCommandHook(behaviorCommandHook); } /** * Is existing the hook interface of behavior commands on thread? * @return The determination, true or false. */ public static boolean isExistBehaviorCommandHookOnThread() { // memorable code: wants to rename to exists...() return isExistCallbackContextOnThread() && getCallbackContextOnThread().getBehaviorCommandHook() != null; } /** * Terminate the last hook interface of behavior commands from callback context on thread.
* If the callback context does not have other interfaces, the context is removed from thread. */ public static void terminateLastBehaviorCommandHookOnThread() { endCallback(context -> context.terminateLastBehaviorCommandHook()); } /** * * (removes all existing hooks completely so use terminateLast...() basically)
*
* Clear the hook interface of behavior commands from callback context on thread.
* If the callback context does not have other interfaces, the context is removed from thread. */ public static void clearBehaviorCommandHookOnThread() { endCallback(context -> context.setBehaviorCommandHook(null)); } // ----------------------------------------------------- // SqlFireHook // ----------- /** * Set the hook interface of SQL fires. (inheriting existing hooks as default)
* This hook interface is called back before firing SQL and finally.
* The hook methods may be called by nested process so pay attention to it.
* And don't forget to terminate the last hook in finally scope. *
     * context.setSqlFireHook(new SqlFireHook() {
     *     public void hookBefore(BehaviorCommandMeta meta, SqlFireReadyInfo fireReadyInfo) {
     *         // You can implement your favorite callback here.
     *     }
     *     public void hookFinally(BehaviorCommandMeta meta, SqlFireResultInfo fireResultInfo) {
     *         // You can implement your favorite callback here.
     *     }
     * });
     * try {
     *     ...(DB access)
     * } finally {
     *     CallbackContext.terminateLastSqlFireHookOnThread();
     * }
     * 
* @param sqlFireHook The hook interface of SQL fires. (NullAllowed: completely clear, Inheritable) */ public static void setSqlFireHookOnThread(SqlFireHook sqlFireHook) { final CallbackContext context = getOrCreateContext(); context.setSqlFireHook(sqlFireHook); } /** * Is existing the hook interface of behavior commands on thread? * @return The determination, true or false. */ public static boolean isExistSqlFireHookOnThread() { return isExistCallbackContextOnThread() && getCallbackContextOnThread().getSqlFireHook() != null; } /** * Terminate the last hook interface of SQL fires from callback context on thread.
* If the callback context does not have other interfaces, the context is removed from thread. */ public static void terminateLastSqlFireHookOnThread() { endCallback(context -> context.terminateLastSqlFireHook()); } /** * * (removes all existing hooks completely so use terminateLast...() basically)
*
* Clear the hook interface of behavior commands from callback context on thread.
* If the callback context does not have other interfaces, the context is removed from thread. */ public static void clearSqlFireHookOnThread() { endCallback(context -> context.setSqlFireHook(null)); } // ----------------------------------------------------- // SqlLogHandler // ------------- /** * Set the handler of SQL log. (inheriting existing handlers as default)
* This handler is called back before executing the SQL.
* The handler methods may be called by nested process so pay attention to it.
* And don't forget to terminate the last handler in finally scope. *
     * context.setSqlLogHandler(new SqlLogHandler() {
     *     public void handle(SqlLogInfo info) {
     *         // You can get your SQL string here.
     *     }
     * });
     * try {
     *     ...(DB access)
     * } finally {
     *     CallbackContext.terminateLastSqlLogHandlerOnThread();
     * }
     * 
* @param sqlLogHandler The handler of SQL log. (NullAllowed: completely clear, Inheritable) */ public static void setSqlLogHandlerOnThread(SqlLogHandler sqlLogHandler) { final CallbackContext context = getOrCreateContext(); context.setSqlLogHandler(sqlLogHandler); } /** * Is existing the handler of SQL log on thread? * @return The determination, true or false. */ public static boolean isExistSqlLogHandlerOnThread() { return isExistCallbackContextOnThread() && getCallbackContextOnThread().getSqlLogHandler() != null; } /** * Terminate the last handler interface of SQL logs from callback context on thread.
* If the callback context does not have other interfaces, the context is removed from thread. */ public static void terminateLastSqlLogHandlerOnThread() { endCallback(context -> context.terminateLastSqlLogHandler()); } /** * * (removes all existing handlers completely so use terminateLast...() basically)
*
* Clear the handler of SQL log from callback context on thread.
* If the callback context does not have other interfaces, the context is removed from thread. */ public static void clearSqlLogHandlerOnThread() { endCallback(context -> context.setSqlLogHandler(null)); } // ----------------------------------------------------- // SqlResultHandler // ---------------- /** * Set the handler of SQL result. (inheriting existing handlers as default)
* This handler is called back before executing the SQL.
* The handler methods may be called by nested process so pay attention to it.
* And don't forget to terminate the last handler in finally scope. *
     * context.setSqlResultHandler(new SqlResultHandler() {
     *     public void handle(SqlResultInfo info) {
     *         // You can get your SQL result information here.
     *     }
     * });
     * try {
     *     ...(DB access)
     * } finally {
     *     CallbackContext.terminateLastSqlResultHandlerOnThread();
     * }
     * 
* @param sqlResultHandler The handler of SQL result. (NullAllowed: completely clear, Inheritable) */ public static void setSqlResultHandlerOnThread(SqlResultHandler sqlResultHandler) { final CallbackContext context = getOrCreateContext(); context.setSqlResultHandler(sqlResultHandler); } /** * Is existing the handler of SQL result on thread? * @return The determination, true or false. */ public static boolean isExistSqlResultHandlerOnThread() { return isExistCallbackContextOnThread() && getCallbackContextOnThread().getSqlResultHandler() != null; } /** * Terminate the last handler interface of SQL results from callback context on thread.
* If the callback context does not have other interfaces, the context is removed from thread. */ public static void terminateLastSqlResultHandlerOnThread() { endCallback(context -> context.terminateLastSqlResultHandler()); } /** * * (removes all existing handlers completely so use terminateLast...() basically)
*
* Clear the handler of SQL result from callback context on thread.
* If the callback context does not have other interfaces, the context is removed from thread. */ public static void clearSqlResultHandlerOnThread() { endCallback(context -> context.setSqlResultHandler(null)); } // ----------------------------------------------------- // SqlStringFilter // --------------- /** * Set the filter of SQL string. (inheriting existing filters as default)
* This handler is called back before executing the SQL.
* The filter methods may be called by nested process so pay attention to it.
* And don't forget to terminate the last filter in finally scope. *
     * context.setSqlStringFilter(new SqlStringFilter() {
     *     public String filter(String executedSql) {
     *         // You can filter your executed SQL string here.
     *     }
     * });
     * try {
     *     ...(DB access)
     * } finally {
     *     CallbackContext.terminateLastSqlStringFilterOnThread();
     * }
     * 
* @param sqlStringFilter The filter of SQL string. (NullAllowed: completely clear, Inheritable) */ public static void setSqlStringFilterOnThread(SqlStringFilter sqlStringFilter) { final CallbackContext context = getOrCreateContext(); context.setSqlStringFilter(sqlStringFilter); } /** * Is existing the handler of SQL result on thread? * @return The determination, true or false. */ public static boolean isExistSqlStringFilterOnThread() { return isExistCallbackContextOnThread() && getCallbackContextOnThread().getSqlStringFilter() != null; } /** * Terminate the last filter interface of SQL strings from callback context on thread.
* If the callback context does not have other interfaces, the context is removed from thread. */ public static void terminateLastSqlStringFilterOnThread() { endCallback(context -> context.terminateLastSqlStringFilter()); } /** * * (removes all existing filters completely so use terminateLast...() basically)
*
* Clear the filter of SQL string from callback context on thread.
* If the callback context does not have other interfaces, the context is removed from thread. */ public static void clearSqlStringFilterOnThread() { endCallback(context -> context.setSqlStringFilter(null)); } // ----------------------------------------------------- // Assist Helper // ------------- protected static CallbackContext getOrCreateContext() { if (isExistCallbackContextOnThread()) { return getCallbackContextOnThread(); } else { final CallbackContext context = new CallbackContext(); setCallbackContextOnThread(context); return context; } } protected static void endCallback(Consumer oneArgLambda) { if (isExistCallbackContextOnThread()) { final CallbackContext context = getCallbackContextOnThread(); oneArgLambda.accept(context); clearContextIfNoInterface(context); } } protected static void clearContextIfNoInterface(final CallbackContext context) { if (!context.hasAnyInterface()) { clearCallbackContextOnThread(); } } // =================================================================================== // Attribute // ========= protected BehaviorCommandHook _behaviorCommandHook; protected SqlFireHook _sqlFireHook; protected SqlLogHandler _sqlLogHandler; protected SqlResultHandler _sqlResultHandler; protected SqlStringFilter _sqlStringFilter; // =================================================================================== // Determination // ============= public boolean hasAnyInterface() { return _behaviorCommandHook != null || _sqlFireHook != null // hook || _sqlLogHandler != null || _sqlResultHandler != null // handler || _sqlStringFilter != null; // filter } // =================================================================================== // Registration // ============ // ----------------------------------------------------- // BehaviorCommandHook // ------------------- /** * Set the hook interface of behavior commands. (inheriting existing hooks as default)
* This hook interface is called back before executing behavior commands and finally.
* The hook methods may be called by nested process so pay attention to it. *
     * context.setBehaviorCommandHook(new BehaviorCommandHook() {
     *     public void hookBefore(BehaviorCommandMeta meta) {
     *         // You can implement your favorite callback here.
     *     }
     *     public void hookFinally(BehaviorCommandMeta meta, RuntimeException cause) {
     *         // You can implement your favorite callback here.
     *     }
     * });
     * 
* @param behaviorCommandHook The hook interface of behavior commands. (NullAllowed: completely clear, Inheritable) */ public void setBehaviorCommandHook(BehaviorCommandHook behaviorCommandHook) { if (_behaviorCommandHook != null && behaviorCommandHook != null && behaviorCommandHook.inheritsExistingHook()) { _behaviorCommandHook = newInheritableBehaviorCommandHook(_behaviorCommandHook, behaviorCommandHook); } else { _behaviorCommandHook = behaviorCommandHook; } } /** * Terminate the last behavior command hook.
* If the only one hook is registered, completely remove the instance from variable. */ public void terminateLastBehaviorCommandHook() { if (_behaviorCommandHook instanceof InheritableBehaviorCommandHook) { _behaviorCommandHook = ((InheritableBehaviorCommandHook) _behaviorCommandHook).getOriginally(); } else { _behaviorCommandHook = null; } } // ----------------------------------------------------- // SqlFireHook // ----------- /** * Set the hook interface of SQL fires. (inheriting existing hooks as default)
* This hook interface is called back before firing SQL and finally.
* The hook methods may be called by nested process so pay attention to it. *
     * context.setSqlFireHook(new SqlFireHook() {
     *     public void hookBefore(BehaviorCommandMeta meta, SqlFireReadyInfo fireReadyInfo) {
     *         // You can implement your favorite callback here.
     *     }
     *     public void hookFinally(BehaviorCommandMeta meta, SqlFireResultInfo fireResultInfo) {
     *         // You can implement your favorite callback here.
     *     }
     * });
     * 
* @param sqlFireHook The hook interface of SQL fires. (NullAllowed: completely clear, Inheritable) */ public void setSqlFireHook(SqlFireHook sqlFireHook) { if (_sqlFireHook != null && sqlFireHook != null && sqlFireHook.inheritsExistingHook()) { _sqlFireHook = newInheritableSqlFireHook(_sqlFireHook, sqlFireHook); } else { _sqlFireHook = sqlFireHook; } } /** * Terminate the last SQL fire hook.
* If the only one hook is registered, completely remove the instance from variable. */ public void terminateLastSqlFireHook() { if (_sqlFireHook instanceof InheritableSqlFireHook) { _sqlFireHook = ((InheritableSqlFireHook) _sqlFireHook).getOriginally(); } else { _sqlFireHook = null; } } // ----------------------------------------------------- // SqlLogHandler // ------------- /** * Set the handler of SQL log. (inheriting existing hooks as default)
* This handler is called back before executing the SQL. *
     * context.setSqlLogHandler(new SqlLogHandler() {
     *     public void handle(String executedSql, String displaySql
     *                      , Object[] args, Class<?>[] argTypes) {
     *         // You can get your SQL string here.
     *     }
     * });
     * 
* @param sqlLogHandler The handler of SQL log. (NullAllowed: completely clear, Inheritable) */ public void setSqlLogHandler(SqlLogHandler sqlLogHandler) { if (_sqlLogHandler != null && sqlLogHandler != null && sqlLogHandler.inheritsExistingHandler()) { _sqlLogHandler = newInheritableSqlLogHandler(_sqlLogHandler, sqlLogHandler); } else { _sqlLogHandler = sqlLogHandler; } } /** * Terminate the last SQL log handler.
* If the only one handler is registered, completely remove the instance from variable. */ public void terminateLastSqlLogHandler() { if (_sqlLogHandler instanceof InheritableSqlLogHandler) { _sqlLogHandler = ((InheritableSqlLogHandler) _sqlLogHandler).getOriginally(); } else { _sqlLogHandler = null; } } // ----------------------------------------------------- // SqlResultHandler // ---------------- /** * Set the handler of SQL result. (inheriting existing hooks as default)
* This handler is called back before executing the SQL. *
     * context.setSqlResultHandler(new SqlResultHandler() {
     *     public void handle(SqlResultInfo info) {
     *         // You can get your SQL result information here.
     *     }
     * });
     * 
* @param sqlResultHandler The handler of SQL result. (NullAllowed: completely clear, Inheritable) */ public void setSqlResultHandler(SqlResultHandler sqlResultHandler) { if (_sqlResultHandler != null && sqlResultHandler != null && sqlResultHandler.inheritsExistingHandler()) { _sqlResultHandler = newInheritableSqlResultHandler(_sqlResultHandler, sqlResultHandler); } else { _sqlResultHandler = sqlResultHandler; } } /** * Terminate the last SQL log handler.
* If the only one handler is registered, completely remove the instance from variable. */ public void terminateLastSqlResultHandler() { if (_sqlResultHandler instanceof InheritableSqlResultHandler) { _sqlResultHandler = ((InheritableSqlResultHandler) _sqlResultHandler).getOriginally(); } else { _sqlResultHandler = null; } } // ----------------------------------------------------- // SqlStringFilter // --------------- /** * Set the filter of SQL string. (inheriting existing hooks as default)
* This filter is called back before executing the SQL. *
     * context.setSqlStringFilter(new SqlStringFilter() {
     *     public String filterSelectCB(BehaviorCommandMeta meta, String executedSql) {
     *         // You can filter your SQL string here.
     *     }
     *     ...
     * });
     * 
* @param sqlStringFilter The filter of SQL string. (NullAllowed: completely clear, Inheritable) */ public void setSqlStringFilter(SqlStringFilter sqlStringFilter) { if (_sqlStringFilter != null && sqlStringFilter != null && sqlStringFilter.inheritsExistingFilter()) { _sqlStringFilter = newInheritableSqlStringFilter(_sqlStringFilter, sqlStringFilter); } else { _sqlStringFilter = sqlStringFilter; } } /** * Terminate the last SQL string filter.
* If the only one filter is registered, completely remove the instance from variable. */ public void terminateLastSqlStringFilter() { if (_sqlStringFilter instanceof InheritableSqlStringFilter) { _sqlStringFilter = ((InheritableSqlStringFilter) _sqlStringFilter).getOriginally(); } else { _sqlStringFilter = null; } } // =================================================================================== // Inheritable // =========== // ----------------------------------------------------- // BehaviorCommandHook // ------------------- protected InheritableBehaviorCommandHook newInheritableBehaviorCommandHook(BehaviorCommandHook originally, BehaviorCommandHook yourHook) { return new InheritableBehaviorCommandHook(originally, yourHook); } protected static class InheritableBehaviorCommandHook implements BehaviorCommandHook, InheritableCallback { protected final BehaviorCommandHook _originally; // may be inheritable, not null protected final BehaviorCommandHook _yourHook; // is not inheritable, always real hook, not null public InheritableBehaviorCommandHook(BehaviorCommandHook originally, BehaviorCommandHook yourHook) { _originally = originally; _yourHook = yourHook; } public void hookBefore(BehaviorCommandMeta meta) { _originally.hookBefore(meta); _yourHook.hookBefore(meta); // your is inside } public void hookFinally(BehaviorCommandMeta meta, RuntimeException cause) { _yourHook.hookFinally(meta, cause); // your is inside _originally.hookFinally(meta, cause); } public BehaviorCommandHook getOriginally() { return _originally; } public BehaviorCommandHook getYourHook() { return _yourHook; } } // ----------------------------------------------------- // SqlFireHook // ----------- protected InheritableSqlFireHook newInheritableSqlFireHook(SqlFireHook originally, SqlFireHook yourHook) { return new InheritableSqlFireHook(originally, yourHook); } protected static class InheritableSqlFireHook implements SqlFireHook, InheritableCallback { protected final SqlFireHook _originally; // may be inheritable, not null protected final SqlFireHook _yourHook; // is not inheritable, always real hook, not null public InheritableSqlFireHook(SqlFireHook originally, SqlFireHook yourHook) { _originally = originally; _yourHook = yourHook; } public void hookBefore(BehaviorCommandMeta meta, SqlFireReadyInfo fireReadyInfo) { _originally.hookBefore(meta, fireReadyInfo); _yourHook.hookBefore(meta, fireReadyInfo); // your is inside } public void hookFinally(BehaviorCommandMeta meta, SqlFireResultInfo fireResultInfo) { _yourHook.hookFinally(meta, fireResultInfo); // your is inside _originally.hookFinally(meta, fireResultInfo); } public SqlFireHook getOriginally() { return _originally; } public SqlFireHook getYourHook() { return _yourHook; } } // ----------------------------------------------------- // SqlLogHandler // ------------- protected InheritableSqlLogHandler newInheritableSqlLogHandler(SqlLogHandler originally, SqlLogHandler yourHandler) { return new InheritableSqlLogHandler(originally, yourHandler); } protected static class InheritableSqlLogHandler implements SqlLogHandler, InheritableCallback { protected final SqlLogHandler _originally; // may be inheritable, not null protected final SqlLogHandler _yourHandler; // is not inheritable, always real handler, not null public InheritableSqlLogHandler(SqlLogHandler originally, SqlLogHandler yourHandler) { _originally = originally; _yourHandler = yourHandler; } public void handle(SqlLogInfo info) { _originally.handle(info); _yourHandler.handle(info); } public SqlLogHandler getOriginally() { return _originally; } public SqlLogHandler getYourHandler() { return _yourHandler; } } // ----------------------------------------------------- // SqlResultHandler // ---------------- protected InheritableSqlResultHandler newInheritableSqlResultHandler(SqlResultHandler originally, SqlResultHandler yourHandler) { return new InheritableSqlResultHandler(originally, yourHandler); } protected static class InheritableSqlResultHandler implements SqlResultHandler, InheritableCallback { protected final SqlResultHandler _originally; // may be inheritable, not null protected final SqlResultHandler _yourHandler; // is not inheritable, always real handler, not null public InheritableSqlResultHandler(SqlResultHandler originally, SqlResultHandler yourHandler) { _originally = originally; _yourHandler = yourHandler; } public void handle(SqlResultInfo info) { _originally.handle(info); _yourHandler.handle(info); } @Override public SqlResultHandler getOriginally() { return _originally; } public SqlResultHandler getYourHandler() { return _yourHandler; } } // ----------------------------------------------------- // SqlStringFilter // --------------- protected InheritableSqlStringFilter newInheritableSqlStringFilter(SqlStringFilter originally, SqlStringFilter yourFilter) { return new InheritableSqlStringFilter(originally, yourFilter); } protected static class InheritableSqlStringFilter implements SqlStringFilter, InheritableCallback { protected final SqlStringFilter _originally; // might be null e.g. when first one protected final SqlStringFilter _yourFilter; // is not inheritable, always real filter, not null public InheritableSqlStringFilter(SqlStringFilter originally, SqlStringFilter yourFilter) { _originally = originally; _yourFilter = yourFilter; } @Override public String filterSelectCB(BehaviorCommandMeta meta, String executedSql) { return doFilter(executedSql, (filter, sql) -> filter.filterSelectCB(meta, sql)); } @Override public String filterEntityUpdate(BehaviorCommandMeta meta, String executedSql) { return doFilter(executedSql, (filter, sql) -> filter.filterEntityUpdate(meta, sql)); } @Override public String filterQueryUpdate(BehaviorCommandMeta meta, String executedSql) { return doFilter(executedSql, (filter, sql) -> filter.filterQueryUpdate(meta, sql)); } @Override public String filterOutsideSql(BehaviorCommandMeta meta, String executedSql) { return doFilter(executedSql, (filter, sql) -> filter.filterOutsideSql(meta, sql)); } @Override public String filterProcedure(BehaviorCommandMeta meta, String executedSql) { return doFilter(executedSql, (filter, sql) -> filter.filterProcedure(meta, sql)); } protected String doFilter(String executedSql, BiFunction call) { final String originallyFiltered = actuallyFilter(_originally, executedSql, call); return actuallyFilter(_yourFilter, originallyFiltered, call); } protected String actuallyFilter(SqlStringFilter filter, String executedSql, BiFunction call) { final String filtered = call.apply(filter, executedSql); return filtered != null ? filtered : executedSql; } @Override public SqlStringFilter getOriginally() { return _originally; } public SqlStringFilter getYourFilter() { return _yourFilter; } } // ----------------------------------------------------- // Small Helper // ------------ protected static interface InheritableCallback { default int countManagedHook() { // contains myself final CALL originally = getOriginally(); final int nestHookCount; if (originally instanceof InheritableBehaviorCommandHook) { // e.g. three or more hooks registered nestHookCount = ((InheritableBehaviorCommandHook) originally).countManagedHook(); } else { // termination nestHookCount = 1; // add nested one (the 1 is for originally that is real hook) } return nestHookCount + 1; // add myself (the 1 is for yourHook) } CALL getOriginally(); } // =================================================================================== // Basic Override // ============== @Override public String toString() { final String title = DfTypeUtil.toClassTitle(this); final StringBuilder sb = new StringBuilder(); sb.append(title); sb.append(":{behaviorCommandHook=").append(_behaviorCommandHook); sb.append(", sqlFireHook=").append(_sqlFireHook); sb.append(", sqlLogHandler=").append(_sqlLogHandler); sb.append(", sqlResultHandler=").append(_sqlResultHandler); sb.append(", sqlStringFilter=").append(_sqlStringFilter); sb.append("}"); return sb.toString(); } // =================================================================================== // Accessor // ======== // ----------------------------------------------------- // BehaviorCommandHook // ------------------- public BehaviorCommandHook getBehaviorCommandHook() { return _behaviorCommandHook; } // ----------------------------------------------------- // SqlFireHook // ----------- public SqlFireHook getSqlFireHook() { return _sqlFireHook; } // ----------------------------------------------------- // SqlLogHandler // ------------- public SqlLogHandler getSqlLogHandler() { return _sqlLogHandler; } // ----------------------------------------------------- // SqlResultHandler // ---------------- public SqlResultHandler getSqlResultHandler() { return _sqlResultHandler; } // ----------------------------------------------------- // SqlStringFilter // --------------- public SqlStringFilter getSqlStringFilter() { return _sqlStringFilter; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy