Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@
import org.openrewrite.maven.MavenDownloadingException;
import org.openrewrite.maven.MavenExecutionContextView;
import org.openrewrite.maven.cache.InMemoryMavenPomCache;
import org.openrewrite.maven.cache.MavenMetadataCacheEntry;
import org.openrewrite.maven.cache.MavenPomCache;
import org.openrewrite.maven.tree.GroupArtifactVersion;
import org.openrewrite.maven.tree.MavenMetadata;
import org.openrewrite.maven.tree.MavenRepository;
import org.openrewrite.maven.tree.Pom;
import org.openrewrite.maven.tree.ResolvedDependency;
Expand Down Expand Up @@ -141,13 +141,13 @@ public void putResolvedDependencyPom(ResolvedGroupArtifactVersion dependency, Re
}

@Override
public @Nullable Optional<MavenMetadata> getMavenMetadata(URI repo, GroupArtifactVersion gav) {
public @Nullable MavenMetadataCacheEntry getMavenMetadata(URI repo, GroupArtifactVersion gav) {
assertNotFailureAccess(gav.getGroupId(), gav.getArtifactId());
return delegate.getMavenMetadata(repo, gav);
}

@Override
public void putMavenMetadata(URI repo, GroupArtifactVersion gav, @Nullable MavenMetadata metadata) {
public void putMavenMetadata(URI repo, GroupArtifactVersion gav, MavenMetadataCacheEntry metadata) {
assertNotFailureAccess(gav.getGroupId(), gav.getArtifactId());
delegate.putMavenMetadata(repo, gav, metadata);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,20 +49,22 @@ public void putResolvedDependencyPom(ResolvedGroupArtifactVersion dependency, Re
}

@Override
public @Nullable Optional<MavenMetadata> getMavenMetadata(URI repo, GroupArtifactVersion gav) {
Optional<MavenMetadata> l1m = l1.getMavenMetadata(repo, gav);
public @Nullable MavenMetadataCacheEntry getMavenMetadata(URI repo, GroupArtifactVersion gav) {
MavenMetadataCacheEntry l1m = l1.getMavenMetadata(repo, gav);
if(l1m != null) {
return l1m;
}
Optional<MavenMetadata> l2m = l2.getMavenMetadata(repo, gav);
if(l2m != null && l2m.isPresent()) {
l1.putMavenMetadata(repo, gav, l2m.get());
MavenMetadataCacheEntry l2m = l2.getMavenMetadata(repo, gav);
// Promote only a still-fresh hit into l1; an expired l2 entry (validators only) is left for
// the downloader to revalidate, so l1 isn't seeded with a stale value.
if(l2m != null && l2m.getMetadata() != null && !l2m.isExpired()) {
l1.putMavenMetadata(repo, gav, l2m);
}
return l2m;
}

@Override
public void putMavenMetadata(URI repo, GroupArtifactVersion gav, MavenMetadata metadata) {
public void putMavenMetadata(URI repo, GroupArtifactVersion gav, MavenMetadataCacheEntry metadata) {
l1.putMavenMetadata(repo, gav, metadata);
l2.putMavenMetadata(repo, gav, metadata);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public static class MetadataKey {
}

private final Cache<ResolvedGroupArtifactVersion, Optional<Pom>> pomCache;
private final Cache<MetadataKey, Optional<MavenMetadata>> mavenMetadataCache;
private final Cache<MetadataKey, MavenMetadataCacheEntry> mavenMetadataCache;
private final Cache<MavenRepository, Optional<MavenRepository>> repositoryCache;
private final Cache<ResolvedGroupArtifactVersion, ResolvedPom> dependencyCache;

Expand All @@ -61,7 +61,7 @@ public InMemoryMavenPomCache() {

public InMemoryMavenPomCache(String cacheNickname,
Cache<ResolvedGroupArtifactVersion, Optional<Pom>> pomCache,
Cache<MetadataKey, Optional<MavenMetadata>> mavenMetadataCache,
Cache<MetadataKey, MavenMetadataCacheEntry> mavenMetadataCache,
Cache<MavenRepository, Optional<MavenRepository>> repositoryCache,
Cache<ResolvedGroupArtifactVersion, ResolvedPom> dependencyCache) {

Expand All @@ -72,7 +72,7 @@ public InMemoryMavenPomCache(String cacheNickname,
}

public InMemoryMavenPomCache(Cache<ResolvedGroupArtifactVersion, Optional<Pom>> pomCache,
Cache<MetadataKey, Optional<MavenMetadata>> mavenMetadataCache,
Cache<MetadataKey, MavenMetadataCacheEntry> mavenMetadataCache,
Cache<MavenRepository, Optional<MavenRepository>> repositoryCache,
Cache<ResolvedGroupArtifactVersion, ResolvedPom> dependencyCache) {
this("default", pomCache, mavenMetadataCache, repositoryCache, dependencyCache);
Expand All @@ -89,13 +89,14 @@ public void putResolvedDependencyPom(ResolvedGroupArtifactVersion dependency, Re
}

@Override
public @Nullable Optional<MavenMetadata> getMavenMetadata(URI repo, GroupArtifactVersion gav) {
public @Nullable MavenMetadataCacheEntry getMavenMetadata(URI repo, GroupArtifactVersion gav) {
// No freshness policy here: entries are always served as stored (never expired).
return mavenMetadataCache.getIfPresent(new MetadataKey(repo, gav));
}

@Override
public void putMavenMetadata(URI repo, GroupArtifactVersion gav, @Nullable MavenMetadata metadata) {
mavenMetadataCache.put(new MetadataKey(repo, gav), Optional.ofNullable(metadata));
public void putMavenMetadata(URI repo, GroupArtifactVersion gav, MavenMetadataCacheEntry metadata) {
mavenMetadataCache.put(new MetadataKey(repo, gav), metadata);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright 2026 the original author or authors.
* <p>
* 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
* <p>
* https://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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 org.openrewrite.maven.cache;

import lombok.Value;
import lombok.With;
import org.jspecify.annotations.Nullable;
import org.openrewrite.maven.tree.MavenMetadata;

/**
* A cached {@link MavenMetadata} value together with the HTTP validators (ETag / Last-Modified)
* returned by the origin when it was downloaded. This is the single payload a {@link MavenPomCache}
* exchanges for {@code maven-metadata.xml}: it is handed back from
* {@link MavenPomCache#getMavenMetadata} and accepted by {@link MavenPomCache#putMavenMetadata}.
* <p>
* Carrying the validators on every read lets the downloader, when an entry's freshness window has
* elapsed ({@link #expired}), revalidate it with a conditional GET ({@code If-None-Match} /
* {@code If-Modified-Since}) rather than re-downloading and re-parsing the body. On a {@code 304 Not
* Modified} the cached {@link #metadata} is reused as-is.
*/
@Value
public class MavenMetadataCacheEntry {

/**
* The cached metadata value. {@code null} represents a previously cached negative result (a
* download that failed with a client-side error), distinct from a cache miss, which is signalled
* by {@link MavenPomCache#getMavenMetadata} returning {@code null} for the whole entry.
*/
@Nullable
MavenMetadata metadata;

/**
* The {@code ETag} response header captured when the metadata was downloaded, replayed as
* {@code If-None-Match}. {@code null} if the origin did not provide one.
*/
@Nullable
String etag;

/**
* The {@code Last-Modified} response header (raw HTTP-date string) captured when the metadata was
* downloaded, replayed verbatim as {@code If-Modified-Since}. {@code null} if the origin did not
* provide one.
*/
@Nullable
String lastModified;

/**
* The cache's freshness verdict, populated when the entry is read back. {@code true} means the
* entry's freshness window has elapsed and the caller should revalidate it with a conditional GET
* rather than serving {@link #metadata} directly. It is always {@code false} on the write path
* (see {@link #fresh}); caches that expire entries recompute it on read from their own retention
* policy, e.g. via {@link #withExpired(boolean)}.
*/
@With
boolean expired;

/**
* Create an entry for storing a just-fetched value and its validators. The entry is not
* {@linkplain #expired}; a cache decides expiry when the entry is later read back.
*/
public static MavenMetadataCacheEntry fresh(@Nullable MavenMetadata metadata, @Nullable String etag, @Nullable String lastModified) {
return new MavenMetadataCacheEntry(metadata, etag, lastModified, false);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,24 @@ public interface MavenPomCache {

void putResolvedDependencyPom(ResolvedGroupArtifactVersion dependency, ResolvedPom resolved);

/**
* Look up a cached {@code maven-metadata.xml} entry. A {@code null} return is a cache miss. A
* non-null {@link MavenMetadataCacheEntry} carries the value (or a negative result, when its
* {@link MavenMetadataCacheEntry#getMetadata() metadata} is {@code null}) together with any HTTP
* validators; if the entry's freshness window has elapsed the cache marks it
* {@link MavenMetadataCacheEntry#isExpired() expired}, signalling the caller to revalidate it
* with a conditional GET rather than serving it directly.
*/
@Nullable
Optional<MavenMetadata> getMavenMetadata(URI repo, GroupArtifactVersion gav);

void putMavenMetadata(URI repo, GroupArtifactVersion gav, @Nullable MavenMetadata metadata);
MavenMetadataCacheEntry getMavenMetadata(URI repo, GroupArtifactVersion gav);

/**
* Store a {@code maven-metadata.xml} entry, including any HTTP validators (ETag / Last-Modified)
* the origin returned, so that a later expiry can be revalidated cheaply via a conditional GET.
* The entry is supplied {@linkplain MavenMetadataCacheEntry#fresh fresh}; the cache owns when it
* subsequently considers the entry expired.
*/
void putMavenMetadata(URI repo, GroupArtifactVersion gav, MavenMetadataCacheEntry metadata);

@Nullable
Optional<Pom> getPom(ResolvedGroupArtifactVersion gav) throws MavenDownloadingException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,13 +132,13 @@ public void putResolvedDependencyPom(ResolvedGroupArtifactVersion dependency, Re
}

@Override
public @Nullable Optional<MavenMetadata> getMavenMetadata(URI repo, GroupArtifactVersion gav) {
public @Nullable MavenMetadataCacheEntry getMavenMetadata(URI repo, GroupArtifactVersion gav) {
//The Maven metadata is not something that should be stored long term, as it will change over time.
return null;
}

@Override
public void putMavenMetadata(URI repo, GroupArtifactVersion gav, @Nullable MavenMetadata metadata) {
public void putMavenMetadata(URI repo, GroupArtifactVersion gav, MavenMetadataCacheEntry metadata) {
//The Maven metadata is not something that should be stored long term, as it will change over time.
}

Expand Down
Loading