001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.commons.compress.compressors.brotli;
020
021/**
022 * Utility code for the Brotli compression format.
023 * @ThreadSafe
024 * @since 1.14
025 */
026public class BrotliUtils {
027
028    enum CachedAvailability {
029        DONT_CACHE, CACHED_AVAILABLE, CACHED_UNAVAILABLE
030    }
031
032    private static volatile CachedAvailability cachedBrotliAvailability;
033
034    static {
035        cachedBrotliAvailability = CachedAvailability.DONT_CACHE;
036        try {
037            Class.forName("org.osgi.framework.BundleEvent");
038        } catch (final Exception ex) { // NOSONAR
039            setCacheBrotliAvailablity(true);
040        }
041    }
042
043    /** Private constructor to prevent instantiation of this utility class. */
044    private BrotliUtils() {
045    }
046
047
048    /**
049     * Are the classes required to support Brotli compression available?
050     * @return true if the classes required to support Brotli compression are available
051     */
052    public static boolean isBrotliCompressionAvailable() {
053        final CachedAvailability cachedResult = cachedBrotliAvailability;
054        if (cachedResult != CachedAvailability.DONT_CACHE) {
055            return cachedResult == CachedAvailability.CACHED_AVAILABLE;
056        }
057        return internalIsBrotliCompressionAvailable();
058    }
059
060    private static boolean internalIsBrotliCompressionAvailable() {
061        try {
062            Class.forName("org.brotli.dec.BrotliInputStream");
063            return true;
064        } catch (NoClassDefFoundError | Exception error) { // NOSONAR
065            return false;
066        }
067    }
068
069    /**
070     * Whether to cache the result of the Brotli for Java check.
071     *
072     * <p>This defaults to {@code false} in an OSGi environment and {@code true} otherwise.</p>
073     * @param doCache whether to cache the result
074     */
075    public static void setCacheBrotliAvailablity(final boolean doCache) {
076        if (!doCache) {
077            cachedBrotliAvailability = CachedAvailability.DONT_CACHE;
078        } else if (cachedBrotliAvailability == CachedAvailability.DONT_CACHE) {
079            final boolean hasBrotli = internalIsBrotliCompressionAvailable();
080            cachedBrotliAvailability = hasBrotli ? CachedAvailability.CACHED_AVAILABLE
081                : CachedAvailability.CACHED_UNAVAILABLE;
082        }
083    }
084
085    // only exists to support unit tests
086    static CachedAvailability getCachedBrotliAvailability() {
087        return cachedBrotliAvailability;
088    }
089}