From 71b92d76055630678336989a05db71550e39ebc1 Mon Sep 17 00:00:00 2001 From: Victor Rubezhny Date: Tue, 25 Jul 2023 15:28:30 +0200 Subject: [PATCH] Maven Central search results should be cached #263 Fixes: #263 --- .../RemoteCentralRepositorySearcher.java | 120 +++++++++++++----- .../participants/RemoteCentralRepoTest.java | 9 +- 2 files changed, 90 insertions(+), 39 deletions(-) diff --git a/lemminx-maven/src/main/java/org/eclipse/lemminx/extensions/maven/searcher/RemoteCentralRepositorySearcher.java b/lemminx-maven/src/main/java/org/eclipse/lemminx/extensions/maven/searcher/RemoteCentralRepositorySearcher.java index 632f9ff3..62637177 100644 --- a/lemminx-maven/src/main/java/org/eclipse/lemminx/extensions/maven/searcher/RemoteCentralRepositorySearcher.java +++ b/lemminx-maven/src/main/java/org/eclipse/lemminx/extensions/maven/searcher/RemoteCentralRepositorySearcher.java @@ -10,7 +10,6 @@ import java.io.UnsupportedEncodingException; import java.net.URLEncoder; - import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -18,6 +17,9 @@ import java.util.List; import java.util.Set; import java.util.TreeSet; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; @@ -29,6 +31,8 @@ import org.eclipse.aether.repository.RemoteRepository; import org.eclipse.lemminx.extensions.maven.MavenLemminxExtension; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; import com.google.gson.JsonObject; import com.google.gson.JsonParser; @@ -56,8 +60,35 @@ public class RemoteCentralRepositorySearcher { public static boolean disableCentralSearch = Boolean .parseBoolean(System.getProperty(RemoteCentralRepositorySearcher.class.getName() + ".disableCentralSearch")); + public static int cacheExpirationTimeoutMinutes = Integer + .parseInt(System.getProperty(RemoteCentralRepositorySearcher.class.getName() + ".cacheExpirationTimeoutMinutes", "-1"), 10); + private OkHttpClient client = new OkHttpClient(); + private static class CacheManager { + private static long DEFAULT_EXPIRATION_TIMEOUT = 30; + + private Cache cache; + private long cacheExpirationTimeout = DEFAULT_EXPIRATION_TIMEOUT; + + public CacheManager(long expirationTimeoutMinutes) { + cacheExpirationTimeout = expirationTimeoutMinutes != -1 ? + expirationTimeoutMinutes : DEFAULT_EXPIRATION_TIMEOUT; + cache = CacheBuilder.newBuilder() + .expireAfterWrite(cacheExpirationTimeout, TimeUnit.MINUTES) + .build(); + } + + V get(K key, Callable loader) { + try { + return cache.get(key, loader); + } catch (ExecutionException e) { + LOGGER.log(Level.SEVERE, "Maven Central Repo search failed: " + e.getMessage(), e); + } + return null; + } + } + public RemoteCentralRepositorySearcher(MavenLemminxExtension lemminxMavenPlugin) { } @@ -68,11 +99,11 @@ public Collection getArtifacts(Dependency artifactToSearch) { return disableCentralSearch ? Collections.emptySet() : internalGetArtifacts(artifactToSearch, PACKAGING_TYPE_JAR); } - public Set getArtifactVersions(Dependency artifactToSearch) { + public Collection getArtifactVersions(Dependency artifactToSearch) { return disableCentralSearch ? Collections.emptySet() : internalGetArtifactVersions(artifactToSearch, PACKAGING_TYPE_JAR); } - public Set getGroupIds(Dependency artifactToSearch) { + public Collection getGroupIds(Dependency artifactToSearch) { return disableCentralSearch ? Collections.emptySet() : internalGetGroupIds(artifactToSearch, PACKAGING_TYPE_JAR); } @@ -80,62 +111,83 @@ public Collection getPluginArtifacts(Dependency artifactToSearch) { return disableCentralSearch ? Collections.emptySet() : internalGetArtifacts(artifactToSearch, PACKAGING_TYPE_MAVEN_PLUGIN); } - public Set getPluginArtifactVersions(Dependency artifactToSearch) { + public Collection getPluginArtifactVersions(Dependency artifactToSearch) { return disableCentralSearch ? Collections.emptySet() : internalGetArtifactVersions(artifactToSearch, PACKAGING_TYPE_MAVEN_PLUGIN); } - public Set getPluginGroupIds(Dependency artifactToSearch) { + public Collection getPluginGroupIds(Dependency artifactToSearch) { return disableCentralSearch ? Collections.emptySet() : internalGetGroupIds(artifactToSearch, PACKAGING_TYPE_MAVEN_PLUGIN); } + private static CacheManager> artifactsCache = new CacheManager<>(cacheExpirationTimeoutMinutes); private Collection internalGetArtifacts(Dependency artifactToSearch, String packaging) { Request request = createArtifactIdsRequesty(artifactToSearch, packaging); - JsonObject responseBody = getResponseBody(request, artifactToSearch); - if (responseBody == null || responseBody.get("numFound").getAsInt() <= 0 ) { - return Collections.emptyList(); - } + return artifactsCache.get(request, new Callable>() { + @Override + public Collection call() throws Exception { + JsonObject responseBody = getResponseBody(request, artifactToSearch); + if (responseBody == null || responseBody.get("numFound").getAsInt() <= 0 ) { + return Collections.emptyList(); + } - List artifactInfos = new ArrayList<>(); - responseBody.get("docs").getAsJsonArray().forEach(d -> { - artifactInfos.add(toArtifactInfo(d.getAsJsonObject())); + List artifactInfos = new ArrayList<>(); + responseBody.get("docs").getAsJsonArray().forEach(d -> { + artifactInfos.add(toArtifactInfo(d.getAsJsonObject())); + }); + + return artifactInfos; + } }); - return artifactInfos; } - - private Set internalGetArtifactVersions(Dependency artifactToSearch, String packaging) { + + private static CacheManager> artifactVersionsCache = new CacheManager<>(cacheExpirationTimeoutMinutes); + private Collection internalGetArtifactVersions(Dependency artifactToSearch, String packaging) { if (isEmpty(artifactToSearch.getArtifactId())) { return Collections.emptySet(); } Request request = createArtifactVersionsRequest(artifactToSearch, packaging); - JsonObject responseBody = getResponseBody(request, artifactToSearch); - if (responseBody == null || responseBody.get("numFound").getAsInt() <= 0 ) { - return Collections.emptySet(); - } - - Set artifactVersions = new HashSet(); - responseBody.get("docs").getAsJsonArray().forEach(d -> { - artifactVersions.add(new DefaultArtifactVersion(d.getAsJsonObject().get(VERSION).getAsString())); + return artifactVersionsCache.get(request, new Callable>() { + @Override + public Collection call() throws Exception { + JsonObject responseBody = getResponseBody(request, artifactToSearch); + if (responseBody == null || responseBody.get("numFound").getAsInt() <= 0 ) { + return Collections.emptySet(); + } + + Set artifactVersions = new HashSet(); + responseBody.get("docs").getAsJsonArray().forEach(d -> { + artifactVersions.add(new DefaultArtifactVersion(d.getAsJsonObject().get(VERSION).getAsString())); + }); + + return artifactVersions; + } }); - return artifactVersions; } - private Set internalGetGroupIds(Dependency artifactToSearch, String packaging) { + private static CacheManager> groupIdsCache = new CacheManager<>(cacheExpirationTimeoutMinutes); + private Collection internalGetGroupIds(Dependency artifactToSearch, String packaging) { if (isEmpty(artifactToSearch.getGroupId())) { return Collections.emptySet(); } Request request = createGroupIdsRequest(artifactToSearch, packaging); - JsonObject responseBody = getResponseBody(request, artifactToSearch); - if (responseBody == null || responseBody.get("numFound").getAsInt() <= 0 ) { - return Collections.emptySet(); - } - - Set artifactGroupIds = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); - responseBody.get("docs").getAsJsonArray().forEach(d -> { - artifactGroupIds.add(d.getAsJsonObject().get(GROUP_ID).getAsString()); + return groupIdsCache.get(request, new Callable>() { + @Override + public Collection call() throws Exception { + JsonObject responseBody = getResponseBody(request, artifactToSearch); + if (responseBody == null || responseBody.get("numFound").getAsInt() <= 0 ) { + return Collections.emptySet(); + } + + Collection artifactGroupIds = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); + responseBody.get("docs").getAsJsonArray().forEach(d -> { + artifactGroupIds.add(d.getAsJsonObject().get(GROUP_ID).getAsString()); + }); + + return artifactGroupIds; + } }); - return artifactGroupIds; } private static Request createGroupIdsRequest(Dependency artifactToSearch, String packaging) { diff --git a/lemminx-maven/src/test/java/org/eclipse/lemminx/extensions/maven/participants/RemoteCentralRepoTest.java b/lemminx-maven/src/test/java/org/eclipse/lemminx/extensions/maven/participants/RemoteCentralRepoTest.java index c127b3da..ddbbca8a 100644 --- a/lemminx-maven/src/test/java/org/eclipse/lemminx/extensions/maven/participants/RemoteCentralRepoTest.java +++ b/lemminx-maven/src/test/java/org/eclipse/lemminx/extensions/maven/participants/RemoteCentralRepoTest.java @@ -13,7 +13,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.Collection; -import java.util.Set; import org.apache.maven.artifact.versioning.ArtifactVersion; import org.apache.maven.model.Dependency; @@ -78,7 +77,7 @@ void testGetArtifactVersionss() { dep.setVersion(V); System.out.println("\nDep: " + dep.toString()); - Set artifactVersions = repoSearcher.getArtifactVersions(dep); + Collection artifactVersions = repoSearcher.getArtifactVersions(dep); assertNotNull(artifactVersions); assertFalse(artifactVersions.isEmpty()); @@ -95,7 +94,7 @@ void testGetGroupIdss() { dep.setGroupId(G); System.out.println("\nDep: " + dep.toString()); - Set artifactGroups = repoSearcher.getGroupIds(dep); + Collection artifactGroups = repoSearcher.getGroupIds(dep); assertNotNull(artifactGroups); assertFalse(artifactGroups.isEmpty()); @@ -164,7 +163,7 @@ void testGetPluginArtifactVersionss() { System.out.println("\nDep: " + dep.toString()); - Set artifactVersions = repoSearcher.getPluginArtifactVersions(dep); + Collection artifactVersions = repoSearcher.getPluginArtifactVersions(dep); assertNotNull(artifactVersions); assertFalse(artifactVersions.isEmpty()); @@ -180,7 +179,7 @@ void testGetPluginGroupIdss() { dep.setGroupId(G); System.out.println("\nDep: " + dep.toString()); - Set artifactGroups = repoSearcher.getPluginGroupIds(dep); + Collection artifactGroups = repoSearcher.getPluginGroupIds(dep); assertNotNull(artifactGroups); assertFalse(artifactGroups.isEmpty());