/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.gradle.plugins.dependency.checker.internal;
import com.liferay.gradle.plugins.dependency.checker.DependencyCheckerException;
import com.liferay.gradle.util.Validator;
import groovy.json.JsonSlurper;
import groovy.time.Duration;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Date;
import java.util.List;
import java.util.Map;
import net.jodah.expiringmap.ExpiringMap;
import org.gradle.api.logging.Logger;
/**
* @author Andrea Di Giorgi
*/
public class MaxAgeDependencyCheckerImpl extends BaseDependencyCheckerImpl {
public MaxAgeDependencyCheckerImpl(Logger logger) {
_logger = logger;
}
@Override
public void check(String group, String name, String version)
throws Exception {
VersionInfo latestVersionInfo = _getVersionInfo(group, name, null);
if (latestVersionInfo.equals(VersionInfo.MISSING)) {
if (_logger.isWarnEnabled()) {
_logger.warn(
"Unable to get information about the latest version of " +
"'{}:{}'",
group, name);
}
return;
}
Date latestDate = new Date(latestVersionInfo.timestamp);
if (latestVersionInfo.version.equals(version)) {
if (_logger.isInfoEnabled()) {
_logger.info(
"Dependency '{}:{}:{}', published {}, is the latest one " +
"available",
group, name, version, latestDate);
}
return;
}
VersionInfo currentVersionInfo = _getVersionInfo(group, name, version);
if (currentVersionInfo.equals(VersionInfo.MISSING)) {
if (_logger.isInfoEnabled()) {
_logger.info(
"Unable to get information about '{}:{}:{}'", group, name,
version);
}
return;
}
Date currentDate = new Date(currentVersionInfo.timestamp);
if (latestVersionInfo.timestamp <=
(currentVersionInfo.timestamp +
_maxAge.toMilliseconds())) {
if (_logger.isWarnEnabled()) {
_logger.warn(
"Dependency '{}:{}:{}', published {}, is older than the " +
"latest one available ('{}:{}:{}', published {}), " +
"but not yet expired",
group, name, version, currentDate, group, name,
latestVersionInfo.version, latestDate);
}
return;
}
StringBuilder sb = new StringBuilder();
sb.append("Dependency '");
sb.append(group);
sb.append(':');
sb.append(name);
sb.append(':');
sb.append(version);
sb.append("', published ");
sb.append(currentDate);
sb.append(", is more than ");
sb.append(_maxAge);
sb.append(" older than the latest one available ('");
sb.append(group);
sb.append(':');
sb.append(name);
sb.append(':');
sb.append(latestVersionInfo.version);
sb.append("', published ");
sb.append(latestDate);
sb.append("), and it is expired");
if (isThrowError()) {
throw new DependencyCheckerException(sb.toString());
}
if (_logger.isWarnEnabled()) {
_logger.warn(sb.toString());
}
}
public Duration getMaxAge() {
return _maxAge;
}
public void setMaxAge(Duration maxAge) {
_maxAge = maxAge;
}
private VersionInfo _getVersionInfo(
String group, String name, String version)
throws MalformedURLException {
URL url = _getVersionInfoURL(group, name, version);
VersionInfo versionInfo = _versionInfos.get(url);
if (versionInfo != null) {
if (_logger.isDebugEnabled()) {
_logger.debug("Cache hit for {}: {}", url, versionInfo);
}
return versionInfo;
}
JsonSlurper jsonSlurper = new JsonSlurper();
Map<String, Object> map = (Map<String, Object>)jsonSlurper.parse(url);
Map<String, Object> responseMap = (Map<String, Object>)map.get(
"response");
List<Map<String, Object>> docsList =
(List<Map<String, Object>>)responseMap.get("docs");
if (docsList.isEmpty()) {
versionInfo = VersionInfo.MISSING;
}
else {
Map<String, Object> docMap = docsList.get(0);
long timestamp = (Long)docMap.get("timestamp");
if (Validator.isNull(version)) {
version = (String)docMap.get("latestVersion");
}
versionInfo = new VersionInfo(timestamp, version);
}
_versionInfos.put(url, versionInfo);
if (_logger.isDebugEnabled()) {
_logger.debug("Cache miss for {}: {}", url, versionInfo);
}
return versionInfo;
}
private URL _getVersionInfoURL(String group, String name, String version)
throws MalformedURLException {
StringBuilder sb = new StringBuilder();
sb.append("https://search.maven.org/solrsearch/select?q=g:\"");
sb.append(group);
sb.append("\"+AND+a:\"");
sb.append(name);
if (Validator.isNotNull(version)) {
sb.append("\"+AND+v:\"");
sb.append(version);
}
sb.append("\"&wt=json");
return new URL(sb.toString());
}
private static final ExpiringMap<URL, VersionInfo> _versionInfos =
ExpiringMap.create();
private final Logger _logger;
private Duration _maxAge;
private static class VersionInfo {
public static final VersionInfo MISSING = new VersionInfo(0, "");
public VersionInfo(long timestamp, String version) {
this.timestamp = timestamp;
this.version = version;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof VersionInfo)) {
return false;
}
VersionInfo versionInfo = (VersionInfo)obj;
if ((timestamp == versionInfo.timestamp) &&
version.equals(versionInfo.version)) {
return true;
}
return false;
}
@Override
public int hashCode() {
String s = toString();
return s.hashCode();
}
@Override
public String toString() {
if (equals(MISSING)) {
return "MISSING";
}
StringBuilder sb = new StringBuilder();
sb.append("timestamp=");
sb.append(timestamp);
sb.append(", version=");
sb.append(version);
return sb.toString();
}
public final long timestamp;
public final String version;
}
}