From 2ef2639f7833c8a8efeed276a00e52493e7ac40a Mon Sep 17 00:00:00 2001 From: "Buerenheide, Christian" Date: Tue, 19 Dec 2017 19:49:54 +0100 Subject: [PATCH] Issue #78 Fixed thread-safety for DependencyLockProvider, IvyRecommendationProvider, PropertyFileRecommendationProvider --- .../provider/DependencyLockProvider.groovy | 32 ++++++++++++------- .../provider/IvyRecommendationProvider.groovy | 26 +++++++++------ .../PropertyFileRecommendationProvider.java | 23 +++++++++---- 3 files changed, 53 insertions(+), 28 deletions(-) diff --git a/src/main/groovy/netflix/nebula/dependency/recommender/provider/DependencyLockProvider.groovy b/src/main/groovy/netflix/nebula/dependency/recommender/provider/DependencyLockProvider.groovy index 1692cc8..b31a54e 100644 --- a/src/main/groovy/netflix/nebula/dependency/recommender/provider/DependencyLockProvider.groovy +++ b/src/main/groovy/netflix/nebula/dependency/recommender/provider/DependencyLockProvider.groovy @@ -4,7 +4,7 @@ import groovy.json.JsonSlurper import org.gradle.api.Project class DependencyLockProvider extends FileBasedRecommendationProvider { - Map recommendations + volatile Map recommendations DependencyLockProvider() {} @@ -14,20 +14,28 @@ class DependencyLockProvider extends FileBasedRecommendationProvider { @Override String getVersion(String org, String name) throws Exception { - if (!recommendations) { - input.withCloseable { - final locks = new JsonSlurper().parse(it) - final isDependencyLock4Format = locks.every { - it.value.every { - it.value instanceof Map + + Map tmpResult = recommendations + + if (tmpResult == null) { + synchronized (this) { + tmpResult = recommendations + if (tmpResult == null) { + input.withCloseable { + final locks = new JsonSlurper().parse(it) + final isDependencyLock4Format = locks.every { + it.value.every { + it.value instanceof Map + } + } + tmpResult = (isDependencyLock4Format ? locks.collectEntries { it.value } : locks).collectEntries { + [(it.key): it.value.locked] + } } - } - - recommendations = (isDependencyLock4Format ? locks.collectEntries { it.value } : locks).collectEntries { - [(it.key): it.value.locked] + recommendations = tmpResult } } } - recommendations[org + ':' + name] + tmpResult[org + ':' + name] } } diff --git a/src/main/groovy/netflix/nebula/dependency/recommender/provider/IvyRecommendationProvider.groovy b/src/main/groovy/netflix/nebula/dependency/recommender/provider/IvyRecommendationProvider.groovy index c95e644..e5126e4 100644 --- a/src/main/groovy/netflix/nebula/dependency/recommender/provider/IvyRecommendationProvider.groovy +++ b/src/main/groovy/netflix/nebula/dependency/recommender/provider/IvyRecommendationProvider.groovy @@ -3,25 +3,33 @@ package netflix.nebula.dependency.recommender.provider import org.gradle.api.Project class IvyRecommendationProvider extends FileBasedRecommendationProvider { - Map versionsByCoord + volatile Map versionsByCoord IvyRecommendationProvider(Project p) { super(p) } @Override String getVersion(String org, String name) throws Exception { - if (versionsByCoord == null) { - versionsByCoord = [:] - getInput().withCloseable { - def ivy = new XmlSlurper().parse(it) - ivy.dependencies.dependency.each { d -> - versionsByCoord.put("${d.@org.text()}:${d.@name.text()}".toString(), "${d.@rev.text()}") + + Map tmpResult = versionsByCoord + + if (tmpResult == null) { + synchronized (this) { + tmpResult = versionsByCoord + if (tmpResult == null) { + tmpResult = [:] + getInput().withCloseable { + def ivy = new XmlSlurper().parse(it) + ivy.dependencies.dependency.each { d -> + tmpResult.put("${d.@org.text()}:${d.@name.text()}".toString(), "${d.@rev.text()}") + } + } + versionsByCoord = tmpResult } } } - return versionsByCoord["$org:$name".toString()] + return tmpResult["$org:$name".toString()] } - @SuppressWarnings("unchecked") @Override public InputStreamProvider setModule(Object dependencyNotation) { if (dependencyNotation == null) diff --git a/src/main/groovy/netflix/nebula/dependency/recommender/provider/PropertyFileRecommendationProvider.java b/src/main/groovy/netflix/nebula/dependency/recommender/provider/PropertyFileRecommendationProvider.java index 171a707..553d818 100644 --- a/src/main/groovy/netflix/nebula/dependency/recommender/provider/PropertyFileRecommendationProvider.java +++ b/src/main/groovy/netflix/nebula/dependency/recommender/provider/PropertyFileRecommendationProvider.java @@ -7,7 +7,8 @@ import java.util.Properties; public class PropertyFileRecommendationProvider extends FileBasedRecommendationProvider { - private Properties recommendations; + + private volatile Properties recommendations; private FuzzyVersionResolver fuzzyResolver = new FuzzyVersionResolver() { @Override @@ -31,12 +32,20 @@ public PropertyFileRecommendationProvider(Project project) { @Override public String getVersion(String org, String name) throws Exception { - if(recommendations == null) { - recommendations = new Properties(); - try (InputStream inputStream = inputProvider.getInputStream()) { - recommendations.load( - new EolCommentFilteringReader( - new ColonFilteringReader(new InputStreamReader(inputStream)))); + + Properties tmpResult = recommendations; + + if(tmpResult == null) { + synchronized (this) { + if (tmpResult == null) { + tmpResult = new Properties(); + try (InputStream inputStream = inputProvider.getInputStream()) { + tmpResult.load( + new EolCommentFilteringReader( + new ColonFilteringReader(new InputStreamReader(inputStream)))); + } + recommendations = tmpResult; + } } } return fuzzyResolver.versionOf(org + "/" + name);