/*
 * Copyright 2015-2017 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.lastaflute.core.smartdeploy;

import org.lastaflute.di.core.smart.hot.HotdeployUtil;

/**
 * @author jflute
 * @since 0.7.9 (2016/01/13 Wednesday)
 */
public abstract class ManagedHotdeploy {

    // ===================================================================================
    //                                                                           Attribute
    //                                                                           =========
    protected static volatile int hotdeployCount;

    // ===================================================================================
    //                                                                  HotDeploy Resource
    //                                                                  ==================
    public static ClassLoader getLaContainerClassLoader() {
        return HotdeployUtil.getLaContainerClassLoader();
    }

    public static ClassLoader getThreadContextClassLoader() {
        return HotdeployUtil.getThreadContextClassLoader();
    }

    // ===================================================================================
    //                                                                       Determination
    //                                                                       =============
    public static boolean isHotdeploy() {
        return HotdeployUtil.isHotdeploy();
    }

    public static boolean isLaContainerHotdeploy() {
        return HotdeployUtil.isLaContainerHotdeploy();
    }

    public static boolean isThreadContextHotdeploy() {
        return HotdeployUtil.isThreadContextHotdeploy();
    }

    // ===================================================================================
    //                                                                          Start/Stop
    //                                                                          ==========
    public static synchronized ClassLoader start() {
        if (isHotdeploy()) {
            final ClassLoader originalLoader = getThreadContextClassLoader();
            if (isAnotherThreadHotdeploy()) { // e.g. job started
                inheritAnotherThreadClassLoader(); // to use same loader
            } else { // normally here
                if (!isThreadContextHotdeploy()) {
                    HotdeployUtil.start();
                }
            }
            ++hotdeployCount;
            return originalLoader;
        } else {
            return null;
        }
    }

    protected static boolean isAnotherThreadHotdeploy() {
        return isLaContainerHotdeploy() && !isThreadContextHotdeploy();
    }

    protected static void inheritAnotherThreadClassLoader() {
        HotdeployUtil.setThreadContextClassLoader(getLaContainerClassLoader());
    }

    public static synchronized void stop(ClassLoader originalLoader) {
        if (isHotdeploy()) {
            --hotdeployCount;
            if (hotdeployCount <= 0) { // nobody is hot (stop or keep hot), also minus just in case
                HotdeployUtil.stop(); // with restoring thread class loader
                hotdeployCount = 0; // if minus
            } else {
                HotdeployUtil.setThreadContextClassLoader(originalLoader);
            }
        }
    }

    // ===================================================================================
    //                                                                         Deserialize
    //                                                                         ===========
    public static Object deserializeInternal(byte[] bytes) throws Exception {
        return HotdeployUtil.deserializeInternal(bytes);
    }

    // ===================================================================================
    //                                                                            Accessor
    //                                                                            ========
    public static synchronized int getHotdeployCount() {
        return hotdeployCount;
    }
}

@@ -2900,103 +2900,738 @@
     
-if (!isThreadContextH
+// _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/%0A                // remove this if-statement to avoid context class-loader being null by jflute (2017/12/17) %0A                // if stop() without start(), context class-loader becomes null%0A                // if hot-deploy process makes new thread, the thread inherits%0A                // h
 ot
+-
 deploy
-()) %7B%0A                    H
+ class-loader as context class-loader%0A                // so this if-statement causes stop() without start()%0A                // (though hot-deploy class-loader may wrap h
 ot
+-
 deploy
-Util.start();%0A                %7D
+ class-loader, but no problem?)%0A                // _/_/_/_/_/_/_/_/_/_/%0A                //if (!isThreadContextHotdeploy()) %7B%0A                HotdeployUtil.start();
 %0A   

remove this if-statement to avoid context class-loader being null