Java tutorial
/* * Copyright 2015 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 com.gradleware.tooling.toolingutils.distribution; import com.google.common.base.Charsets; import com.google.common.base.Function; import com.google.common.base.Optional; import com.google.common.base.Predicate; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableList; import com.google.common.io.CharSource; import com.google.common.io.Files; import com.google.common.io.Resources; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; import org.gradle.util.GradleVersion; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; /** * Provides information about the Gradle versions available from services.gradle.org. The version information can optionally be cached on the local file system. * * @author Etienne Studer */ public final class PublishedGradleVersions { // end-point that provides full version information private static final String VERSIONS_URL = "https://services.gradle.org/versions/all"; // the minimum Gradle version considered private static final String MINIMUM_SUPPORTED_GRADLE_VERSION = "1.0"; // JSON keys private static final String VERSION = "version"; private static final String SNAPSHOT = "snapshot"; private static final String ACTIVE_RC = "activeRc"; private static final String RC_FOR = "rcFor"; private static final String BROKEN = "broken"; // the file to cache the downloaded version information private static final File CACHE_FILE = new File(System.getProperty("user.home"), ".tooling/gradle/versions.json"); private static final Logger LOG = LoggerFactory.getLogger(PublishedGradleVersions.class); private final List<Map<String, String>> versions; private PublishedGradleVersions(List<Map<String, String>> versions) { this.versions = ImmutableList.copyOf(versions); } /** * Returns all final Gradle versions plus the latest active release candidate, if available. * * @return the matching versions */ public List<GradleVersion> getVersions() { return FluentIterable.from(this.versions).filter(new Predicate<Map<String, String>>() { @Override public boolean apply(Map<String, String> input) { return (Boolean.valueOf(input.get(ACTIVE_RC)) || input.get(RC_FOR).equals("")) && !Boolean.valueOf(input.get(BROKEN)) && !Boolean.valueOf(input.get(SNAPSHOT)); } }).transform(new Function<Map<String, String>, GradleVersion>() { @Override public GradleVersion apply(Map<String, String> input) { return GradleVersion.version(input.get(VERSION)); } }).filter(new Predicate<GradleVersion>() { @Override public boolean apply(GradleVersion input) { return input.compareTo(GradleVersion.version(MINIMUM_SUPPORTED_GRADLE_VERSION)) >= 0; } }).toList(); } /** * Creates a new instance based on the version information available on services.gradle.org. If caching is enabled, the version information is only retrieved remotely if the * version information is not cached or if the cached data has expired. * * @param enableCaching if {@code true} the version information is retrieved from the cache if available and if not outdated * @return the new instance */ public static PublishedGradleVersions create(boolean enableCaching) { if (enableCaching) { // allow to read from and write to cache file if (CACHE_FILE.isFile()) { // if cache file exists, try to make use of it Optional<String> cachedVersions = readCacheVersionsFile(); if (CACHE_FILE.lastModified() > System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1)) { // cache file is current and its version information can be used LOG.info( "Gradle version information cache file is not out-of-date. No remote download required."); if (cachedVersions.isPresent()) { // local cache file is valid, use it return create(cachedVersions.get()); } else { // local cache file is not valid, download latest version information LOG.error( "Cannot read found Gradle version information cache file. Remote download required."); String json = downloadVersionInformation(); storeCacheVersionFile(json); return create(json); } } else { // cache file is out-of-date, download latest version information, but fall back to cached version in case of download problems LOG.info("Gradle version information cache file is out-of-date. Remote download required."); String json; try { json = downloadVersionInformation(); } catch (RuntimeException e) { if (cachedVersions.isPresent()) { // download failed, but local cache file is valid, use it return create(cachedVersions.get()); } else { // download failed and local cache file is invalid, too throw new RuntimeException( "Cannot collect Gradle version information remotely nor locally.", e); } } storeCacheVersionFile(json); return create(json); } } else { // if no previous cache file exists, download and cache the version information LOG.info("Gradle version information cache file is not available. Remote download required."); String json = downloadVersionInformation(); storeCacheVersionFile(json); return create(json); } } else { // read versions from Gradle services end-point each time (do not cache downloaded version information) String json = downloadVersionInformation(); return create(json); } } private static String downloadVersionInformation() { try { return Resources.asCharSource(createURL(VERSIONS_URL), Charsets.UTF_8).read(); } catch (IOException e) { LOG.error("Cannot download published Gradle versions.", e); throw new RuntimeException("Cannot download published Gradle versions.", e); // throw an exception if version information cannot be downloaded since we need this information } } private static void storeCacheVersionFile(String json) { //noinspection ResultOfMethodCallIgnored CACHE_FILE.getParentFile().mkdirs(); try { CharSource.wrap(json).copyTo(Files.asCharSink(CACHE_FILE, Charsets.UTF_8)); } catch (IOException e) { LOG.error("Cannot write Gradle version information cache file.", e); // do not throw an exception if cache file cannot be written to be more robust against file system problems } } private static Optional<String> readCacheVersionsFile() { try { return Optional.of(Files.toString(CACHE_FILE, Charsets.UTF_8)); } catch (IOException e) { LOG.error("Cannot read found Gradle version information cache file.", e); // do not throw an exception if cache file cannot be read to be more robust against file system problems return Optional.absent(); } } /** * Creates a new instance based on the provided version information. * * @param json the json string containing the version information * @return the new instance */ public static PublishedGradleVersions create(String json) { // convert versions from JSON String to JSON Map Gson gson = new GsonBuilder().create(); TypeToken<List<Map<String, String>>> typeToken = new TypeToken<List<Map<String, String>>>() { }; List<Map<String, String>> versions = gson.fromJson(json, typeToken.getType()); // create instance return new PublishedGradleVersions(versions); } private static URL createURL(String url) { try { return new URL(url); } catch (MalformedURLException e) { throw new IllegalArgumentException("Invalid URL: " + url, e); } } }