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

com.microsoft.applicationinsights.internal.shutdown.SDKShutdownActivity Maven / Gradle / Ivy

/*
 * ApplicationInsights-Java
 * Copyright (c) Microsoft Corporation
 * All rights reserved.
 *
 * MIT License
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this
 * software and associated documentation files (the ""Software""), to deal in the Software
 * without restriction, including without limitation the rights to use, copy, modify, merge,
 * publish, distribute, sublicense, and/or sell copies of the Software, and to permit
 * persons to whom the Software is furnished to do so, subject to the following conditions:
 * The above copyright notice and this permission notice shall be included in all copies or
 * substantial portions of the Software.
 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
 * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

package com.microsoft.applicationinsights.internal.shutdown;

import java.util.ArrayList;
import java.util.concurrent.TimeUnit;

import com.microsoft.applicationinsights.channel.TelemetryChannel;
import com.microsoft.applicationinsights.internal.logger.InternalLogger;
import com.microsoft.applicationinsights.internal.util.ChannelFetcher;

/**
 * The class is responsible for all shutdown activities done in the SDK.
 *
 * Created by gupele on 2/2/2015.
 */
public enum SDKShutdownActivity {
    INSTANCE;

    /**
     * An helper class that does the cleanup
     *
     * The following are a MUST and should be kept under any future change:
     * 1. The class should not throw an exception
     * 2. The class 'run' method should exit as soon as possible
     */
    private static class SDKShutdownThread extends Thread {
        private boolean stopped = false;

        private final ArrayList fetchers = new ArrayList();
        private final ArrayList stoppables = new ArrayList();

        public synchronized void register(ChannelFetcher fetcher) {
            fetchers.add(fetcher);
        }

        public synchronized void register(Stoppable stoppable) {
            stoppables.add(stoppable);
        }

        public SDKShutdownThread() {
        }

        @Override
        public synchronized void run() {
            if (stopped) {
                // For making sure the JVM exists ASAP.
                return;
            }

            try {
                stopChannels();
                stopStoppables();
            } finally {
                // As the last step, the SDK gracefully closes the Internal Logger
                stopInternalLogger();
            }

            stopped = true;
        }

        /**
         * Make sure no exception is thrown!
         */
        private void stopInternalLogger() {
            try {
                InternalLogger.INSTANCE.stop();
            } catch (Throwable t) {
            }
        }

        /**
         * Make sure no exception is thrown!
         */
        private void stopChannels() {
            for (ChannelFetcher fetcher : fetchers) {
                try {
                    TelemetryChannel channelToStop = fetcher.fetch();
                    if (channelToStop != null) {
                        channelToStop.stop(1L, TimeUnit.SECONDS);
                    }
                } catch (Throwable t) {
                    InternalLogger.INSTANCE.error("Failed to stop channel: '%s'", t.getMessage());
                }
            }
        }
        /**
         * Make sure no exception is thrown!
         */
        private void stopStoppables() {
            for (Stoppable stoppable : stoppables) {
                try {
                    stoppable.stop(1L, TimeUnit.SECONDS);
                } catch (Throwable t) {
                    InternalLogger.INSTANCE.error("Failed to stop stoppable class '%s': '%s'", stoppable.getClass().getName(), t.getMessage());
                }
            }
        }
    }

    private static volatile SDKShutdownThread shutdownThread;

    public void register(ChannelFetcher fetcher) {
        getShutdownThread().register(fetcher);
    }

    public void register(Stoppable stoppable) {
        getShutdownThread().register(stoppable);
    }

    private SDKShutdownThread getShutdownThread() {
        if (shutdownThread == null) {
            synchronized (this) {
                if (shutdownThread == null) {
                    try {
                        shutdownThread = new SDKShutdownThread();
                        Runtime.getRuntime().addShutdownHook(shutdownThread);
                    } catch (Exception e) {
                    }
                }
            }
        }

        return shutdownThread;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy