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

com.amazonaws.util.VersionInfoUtils Maven / Gradle / Ivy

Go to download

The AWS SDK for Java - Core module holds the classes that are used by the individual service clients to interact with Amazon Web Services. Users need to depend on aws-java-sdk artifact for accessing individual client classes.

There is a newer version: 1.12.778
Show newest version
/*
 * Copyright 2010-2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *  http://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file 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.amazonaws.util;

import static com.amazonaws.util.IOUtils.closeQuietly;

import com.amazonaws.annotation.ThreadSafe;
import com.amazonaws.internal.config.InternalConfig;
import java.io.InputStream;
import java.net.URL;
import java.util.Properties;
import java.util.jar.JarInputStream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Utility class for accessing AWS SDK versioning information.
 */
@ThreadSafe
public class VersionInfoUtils {
    /** The AWS SDK version info file with SDK versioning info */
    static final String VERSION_INFO_FILE = "/com/amazonaws/sdk/versionInfo.properties";

    private static final String DISABLE_DEPRECATION_ANNOUNCEMENT_ENV_VAR =
        "AWS_JAVA_V1_DISABLE_DEPRECATION_ANNOUNCEMENT";
    private static final String DISABLE_DEPRECATION_ANNOUNCEMENT_SYS_PROP =
        "aws.java.v1.disableDeprecationAnnouncement";

    private static final String PRINT_LOCATION_ENV_VAR = "AWS_JAVA_V1_PRINT_LOCATION";
    private static final String PRINT_LOCATION_SYS_PROP = "aws.java.v1.printLocation";

    /** SDK version info */
    private static volatile String version;

    /** SDK platform info */
    private static volatile String platform;

    /** User Agent info */
    private static volatile String userAgent;

    /** Shared logger for any issues while loading version information */
    private static final Log log = LogFactory.getLog(VersionInfoUtils.class);

    private static final String UNKNOWN = "unknown";

    static {
        printDeprecationAnnouncement();
        printSdkLocation();
    }

    private static void printDeprecationAnnouncement() {
        String disableAnnouncementEnvVar = System.getenv(DISABLE_DEPRECATION_ANNOUNCEMENT_ENV_VAR);
        String disableAnnouncementSysProp = System.getProperty(DISABLE_DEPRECATION_ANNOUNCEMENT_SYS_PROP);
        boolean printDeprecationAnnouncement = !isTrue(disableAnnouncementEnvVar) && !isTrue(disableAnnouncementSysProp);

        if (printDeprecationAnnouncement) {
            StringBuilder message = new StringBuilder(
                "The AWS SDK for Java 1.x entered maintenance mode starting July 31, 2024 and will reach end of support "
                + "on December 31, 2025. For more information, see "
                + "https://aws.amazon.com/blogs/developer/the-aws-sdk-for-java-1-x-is-in-maintenance-mode-effective-july-31-2024/\n"
                + "You can print where on the file system the AWS SDK for Java 1.x core runtime is located by setting "
                + "the " + PRINT_LOCATION_ENV_VAR + " environment variable or " + PRINT_LOCATION_SYS_PROP + " system "
                + "property to 'true'.\n"
                + "This message can be disabled by setting the " + DISABLE_DEPRECATION_ANNOUNCEMENT_ENV_VAR
                + " environment variable or " + DISABLE_DEPRECATION_ANNOUNCEMENT_SYS_PROP + " system property to 'true'."
                + "\n"
                + "The AWS SDK for Java 1.x is being used here:");

            for (StackTraceElement element : Thread.currentThread().getStackTrace()) {
                message.append("\n").append("at ").append(element);
            }

            log.warn(message);
        }
    }

    private static void printSdkLocation() {
        String printJarEnvVar = System.getenv(PRINT_LOCATION_ENV_VAR);
        String printJarSysProp = System.getProperty(PRINT_LOCATION_SYS_PROP);
        boolean printJar = isTrue(printJarEnvVar) || isTrue(printJarSysProp);

        if (printJar) {
            try {
                URL jarLocation = VersionInfoUtils.class.getProtectionDomain().getCodeSource().getLocation();
                String message =
                    "The AWS SDK for Java 1.x core runtime is located at " + jarLocation + "\n"
                    + "This message was generated because the " + PRINT_LOCATION_ENV_VAR + " environment variable or "
                    + PRINT_LOCATION_SYS_PROP + " system property were set to 'true'.";
                log.info(message);
            } catch (SecurityException e) {
                String message =
                    "The AWS SDK for Java 1.x core runtime location could not be printed, because a "
                    + "security manager did not allow it.";
                log.error(message, e);
            }
        }
    }

    /**
     * Returns the current version for the AWS SDK in which this class is
     * running. Version information is obtained from from the
     * versionInfo.properties file which the AWS Java SDK build process
     * generates.
     *
     * @return The current version for the AWS SDK, if known, otherwise
     *         returns a string indicating that the version information is
     *         not available.
     */
    public static String getVersion() {
        if (version == null) {
            synchronized(VersionInfoUtils.class) {
                if (version == null)
                    initializeVersion();
            }
        }
        return version;
    }

    /**
     * Returns the current platform for the AWS SDK in which this class is
     * running. Version information is obtained from from the
     * versionInfo.properties file which the AWS Java SDK build process
     * generates.
     *
     * @return The current platform for the AWS SDK, if known, otherwise
     *         returns a string indicating that the platform information is
     *         not available.
     */
    public static String getPlatform() {
        if (platform == null) {
            synchronized(VersionInfoUtils.class) {
                if (platform == null)
                    initializeVersion();
            }
        }
        return platform;
    }

     /**
     * @return Returns the User Agent string to be used when communicating with
	 * the AWS services.  The User Agent encapsulates SDK, Java, OS and
	 * region information.
     */
    public static String getUserAgent() {
        if (userAgent == null) {
            synchronized(VersionInfoUtils.class) {
                if (userAgent == null)
                    initializeUserAgent();
            }
        }
        return userAgent;
    }

   /**
     * Loads the versionInfo.properties file from the AWS Java SDK and
     * stores the information so that the file doesn't have to be read the
     * next time the data is needed.
     */
    private static void initializeVersion() {
        InputStream inputStream = ClassLoaderHelper.getResourceAsStream(
                VERSION_INFO_FILE, true, VersionInfoUtils.class);
        Properties versionInfoProperties = new Properties();
        try {
            if (inputStream == null)
                throw new Exception(VERSION_INFO_FILE + " not found on classpath");

            versionInfoProperties.load(inputStream);
            version = versionInfoProperties.getProperty("version");
            platform = versionInfoProperties.getProperty("platform");
        } catch (Exception e) {
            log.info("Unable to load version information for the running SDK: " + e.getMessage());
            version = "unknown-version";
            platform = "java";
        } finally {
            closeQuietly(inputStream, log);
        }
    }

    /**
     * Initializes the user agent string by loading a template from
     * {@code InternalConfig} and filling in the detected version/platform
     * info.
     */
    private static void initializeUserAgent() {
        userAgent = userAgent();
    }

    static String userAgent() {

        String ua = InternalConfig.Factory.getInternalConfig()
                .getUserAgentTemplate();

        if (ua == null) {
            return "aws-sdk-java";
        }

        ua = ua
            .replace("{platform}",  StringUtils.lowerCase(getPlatform()))
            .replace("{version}", getVersion())
            .replace("{os.name}", replaceSpaces(System.getProperty("os.name")))
            .replace("{os.version}", replaceSpaces(System.getProperty("os.version")))
            .replace("{java.vm.name}", replaceSpaces(System.getProperty("java.vm.name")))
            .replace("{java.vm.version}", replaceSpaces(System.getProperty("java.vm.version")))
            .replace("{java.version}", replaceSpaces(System.getProperty("java.version")))
            .replace("{java.vendor}", replaceSpaces(System.getProperty("java.vendor")))
	    ;

        if (ua.contains("{additional.languages}")) {
            ua = ua.replace("{additional.languages}", getAdditionalJvmLanguages());
        }


        String language = System.getProperty("user.language");
        String region = System.getProperty("user.region");

        String languageAndRegion = "";
        if (language != null && region != null) {
            languageAndRegion =
                    " " + replaceSpaces(language) + "_" + replaceSpaces(region);
        }
        ua = ua.replace("{language.and.region}", languageAndRegion);

        return ua;
    }

    /**
     * Replace any spaces in the input with underscores.
     *
     * @param input the input
     * @return the input with spaces replaced by underscores
     */
    private static String replaceSpaces(final String input) {
        return input == null ? UNKNOWN : input.replace(' ', '_');
    }

    private static String getAdditionalJvmLanguages() {
        StringBuilder versions = new StringBuilder();
        concat(versions, scalaVersion(), " ");
        concat(versions, clojureVersion(), " ");
        concat(versions, groovyVersion(), " ");
        concat(versions, jythonVersion(), " ");
        concat(versions, jrubyVersion(), " ");
        concat(versions, kotlinVersion(), " ");
        return versions.toString();
    }

    private static String scalaVersion() {
        return languageVersion("scala", "scala.util.Properties", "versionNumberString", true);
    }

    private static String clojureVersion() {
        return languageVersion("clojure", "clojure.core$clojure_version", "invokeStatic", true);
    }

    private static String groovyVersion() {
        return languageVersion("groovy", "groovy.lang.GroovySystem", "getVersion", true);
    }

    private static String jythonVersion() {
        return languageVersion("jython", "org.python.Version", "PY_VERSION", false);
    }

    private static String jrubyVersion() {
        return languageVersion("jruby", "org.jruby.runtime.Constants", "VERSION", false);
    }

    /**
     * Attempt to determine if Kotlin is on the classpath and if so what version is in use.
     * Can do this by either using the KotlinVersion class that was introduced in 1.1 or
     * via looking at the JAR's manifest versions for earlier versions.
     *
     * @return Kotlin version if any, else empty string
     */
    private static String kotlinVersion() {
        String version = kotlinVersionByClass();
        return version.equals("") ? kotlinVersionByJar() : version;
    }

    private static String kotlinVersionByClass() {
        StringBuilder kotlinVersion = new StringBuilder("");
        try {
            Class versionClass = Class.forName("kotlin.KotlinVersion");
            kotlinVersion.append("kotlin");
            String version = versionClass.getField("CURRENT").get(null).toString();
            concat(kotlinVersion, version, "/");
        } catch (ClassNotFoundException e) {
            //ignore
        } catch (Exception e) {
            if (log.isTraceEnabled()){
                log.trace("Exception attempting to get Kotlin version.", e);
            }

        }
        return kotlinVersion.toString();
    }

    private static String kotlinVersionByJar() {
        StringBuilder kotlinVersion = new StringBuilder("");
        JarInputStream kotlinJar = null;
        try {
            Class kotlinUnit = Class.forName("kotlin.Unit");
            kotlinVersion.append("kotlin");
            kotlinJar = new JarInputStream(kotlinUnit.getProtectionDomain().getCodeSource().getLocation().openStream());
            String version = kotlinJar.getManifest().getMainAttributes().getValue("Implementation-Version");
            concat(kotlinVersion, version, "/");
        } catch (ClassNotFoundException e) {
            //Ignore
        } catch (Exception e) {
            if (log.isTraceEnabled()) {
                log.trace("Exception attempting to get Kotlin version.", e);
            }
        } finally {
            closeQuietly(kotlinJar, log);
        }
        return kotlinVersion.toString();
    }

    /**
     * Attempt to determine if this language exists on the classpath and what it's version is
     * @param language the name of the language
     * @param className a class of that lanauge that exposes runtime version information
     * @param methodOrFieldName the static field or method name that holds the version number
     * @param isMethod whether the above is a field or method
     * @return the version number or empty string if the language does not exist on the classpath
     */
    private static String languageVersion(String language, String className, String methodOrFieldName, boolean isMethod) {
        StringBuilder sb = new StringBuilder();
        try {
            Class clz = Class.forName(className);
            sb.append(language);
            String version = isMethod ? (String) clz.getMethod(methodOrFieldName).invoke(null) : (String) clz.getField(methodOrFieldName).get(null);
            concat(sb, version, "/");
        } catch (ClassNotFoundException e) {
            //Ignore
        } catch (Exception e) {
            if (log.isTraceEnabled()){
                log.trace("Exception attempting to get " + language + " version.", e);
            }
        }
        return sb.toString();
    }

    private static void concat(StringBuilder prefix, String suffix, String separator) {
        if (suffix != null && !suffix.isEmpty()) {
            prefix.append(separator).append(suffix);
        }
    }

    private static boolean isTrue(String string) {
        return Boolean.parseBoolean(string);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy