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

liquibase.analytics.configuration.LiquibaseRemoteAnalyticsConfiguration Maven / Gradle / Ivy

The newest version!
package liquibase.analytics.configuration;

import liquibase.Scope;
import liquibase.configuration.ConfiguredValue;
import liquibase.logging.Logger;
import liquibase.util.Cache;
import lombok.Data;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.SafeConstructor;

import java.io.InputStream;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;

/**
 * LiquibaseRemoteAnalyticsConfiguration is responsible for fetching and providing
 * remote analytics configurations used by Liquibase.
 *
 * This class uses a {@link Cache} to store the remote analytics configuration, which is
 * loaded from a specified URL endpoint.
 */
@Data
public class LiquibaseRemoteAnalyticsConfiguration implements AnalyticsConfiguration {

    /**
     * Cache holding the {@link RemoteAnalyticsConfiguration} object. It ensures the
     * configuration is fetched only once and reused across the application.
     *
     * The configuration is loaded from the URL specified by {@link AnalyticsArgs#CONFIG_ENDPOINT_URL}.
     */
    private final static Cache remoteAnalyticsConfiguration = new Cache<>(() -> {
        /**
         * It is important to obtain the URL here outside of the newly created thread. {@link Scope} stores its stuff
         * in a ThreadLocal, so if you tried to get the value inside the thread, the value could be different.
         */
        Logger log = Scope.getCurrentScope().getLog(AnalyticsConfiguration.class);
        Level logLevel = AnalyticsArgs.LOG_LEVEL.getCurrentValue();
        String url = AnalyticsArgs.CONFIG_ENDPOINT_URL.getCurrentValue();
        AtomicReference remoteAnalyticsConfiguration = new AtomicReference<>();
        try {
            URLConnection urlConnection = new URL(url).openConnection();
            urlConnection.setConnectTimeout(AnalyticsArgs.CONFIG_ENDPOINT_TIMEOUT_MILLIS.getCurrentValue());
            urlConnection.setReadTimeout(AnalyticsArgs.CONFIG_ENDPOINT_TIMEOUT_MILLIS.getCurrentValue());
            InputStream input = urlConnection.getInputStream();
            Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));
            Map loaded = yaml.load(input);
            remoteAnalyticsConfiguration.set(RemoteAnalyticsConfiguration.fromYaml(loaded));
        } catch (SocketTimeoutException e) {
            log.log(logLevel, "Timed out while attempting to load analytics configuration from " + url, null);
        } catch (Exception e) {
            log.log(logLevel, "Failed to load analytics configuration from " + url, e);
        }
        return remoteAnalyticsConfiguration.get();
    }, false, AnalyticsArgs.CONFIG_CACHE_TIMEOUT_MILLIS.getCurrentValue());

    @Override
    public int getPriority() {
        return 0;
    }

    /**
     * Retrieves the timeout value in milliseconds from the remote configuration.
     *
     * @return the timeout in milliseconds
     * @throws Exception if there is an issue fetching the configuration
     */
    public int getTimeoutMillis() throws Exception {
        ConfiguredValue userTimeoutMillis = AnalyticsArgs.TIMEOUT_MILLIS.getCurrentConfiguredValue();
        if (userTimeoutMillis.found()) {
            return userTimeoutMillis.getValue();
        } else {
            return remoteAnalyticsConfiguration.get().getTimeoutMs();
        }
    }

    /**
     * Retrieves the destination URL for analytics from the remote configuration.
     *
     * @return the destination URL as a String
     * @throws Exception if there is an issue fetching the configuration
     */
    public String getDestinationUrl() throws Exception {
        return remoteAnalyticsConfiguration.get().getEndpointData();
    }

    /**
     * Determines if OSS analytics are enabled by reading the remote configuration.
     *
     * @return true if OSS analytics are enabled, false otherwise
     * @throws Exception if there is an issue fetching the configuration
     */
    @Override
    public boolean isOssAnalyticsEnabled() throws Exception {
        return Optional.ofNullable(remoteAnalyticsConfiguration.get())
                .map(RemoteAnalyticsConfiguration::isSendOss)
                .orElse(false);
    }

    /**
     * Determines if Pro analytics are enabled by reading the remote configuration.
     *
     * @return true if Pro analytics are enabled, false otherwise
     * @throws Exception if there is an issue fetching the configuration
     */
    @Override
    public boolean isProAnalyticsEnabled() throws Exception {
        return Optional.ofNullable(remoteAnalyticsConfiguration.get())
                .map(RemoteAnalyticsConfiguration::isSendPro)
                .orElse(false);
    }

    /**
     * Retrieves the write key used for analytics reporting from the remote configuration.
     *
     * @return the write key as a String
     * @throws Exception if there is an issue fetching the configuration
     */
    public String getWriteKey() throws Exception {
        return remoteAnalyticsConfiguration.get().getWriteKey();
    }

    /**
     * Retrieves the list of extension names included in the remote configuration.
     *
     * @return a list of extension names
     * @throws Exception if there is an issue fetching the configuration
     */
    public List getExtensionNames() throws Exception {
        return remoteAnalyticsConfiguration.get().getExtensions();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy