From 083716de8b744dfa8869d976bc225f5d73a4f744 Mon Sep 17 00:00:00 2001 From: Pavlo Shevchenko Date: Tue, 11 Jun 2024 20:49:57 +0000 Subject: [PATCH] [MNG-8150] Backport TransferListener improvements for Maven 3.9.x (#1576) Backporting https://github.com/apache/maven/pull/1575 to Maven 3.9.x. - [x] I hereby declare this contribution to be licenced under the [Apache License Version 2.0, January 2004](http://www.apache.org/licenses/LICENSE-2.0) --- https://issues.apache.org/jira/browse/MNG-8150 --- .../ConsoleMavenTransferListener.java | 34 ++++++--- .../cli/transfer/SimplexTransferListener.java | 17 ++--- .../transfer/TransferResourceIdentifier.java | 74 +++++++++++++++++++ .../transfer/SimplexTransferListenerTest.java | 37 +++++++++- 4 files changed, 139 insertions(+), 23 deletions(-) create mode 100644 maven-embedder/src/main/java/org/apache/maven/cli/transfer/TransferResourceIdentifier.java diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/transfer/ConsoleMavenTransferListener.java b/maven-embedder/src/main/java/org/apache/maven/cli/transfer/ConsoleMavenTransferListener.java index e867762ca18..0b453306bfc 100644 --- a/maven-embedder/src/main/java/org/apache/maven/cli/transfer/ConsoleMavenTransferListener.java +++ b/maven-embedder/src/main/java/org/apache/maven/cli/transfer/ConsoleMavenTransferListener.java @@ -36,8 +36,8 @@ */ public class ConsoleMavenTransferListener extends AbstractMavenTransferListener { - private final Map transfers = - Collections.synchronizedMap(new LinkedHashMap()); + private final Map transfers = + Collections.synchronizedMap(new LinkedHashMap()); private final boolean printResourceNames; private int lastLength; @@ -64,19 +64,20 @@ public void transferCorrupted(TransferEvent event) throws TransferCancelledExcep @Override public void transferProgressed(TransferEvent event) throws TransferCancelledException { TransferResource resource = event.getResource(); - transfers.put(resource, event.getTransferredBytes()); + transfers.put( + new TransferResourceIdentifier(resource), + new TransferResourceAndSize(resource, event.getTransferredBytes())); StringBuilder buffer = new StringBuilder(128); buffer.append("Progress (").append(transfers.size()).append("): "); synchronized (transfers) { - Iterator> entries = - transfers.entrySet().iterator(); + Iterator entries = transfers.values().iterator(); while (entries.hasNext()) { - Map.Entry entry = entries.next(); - long total = entry.getKey().getContentLength(); - Long complete = entry.getValue(); - buffer.append(getStatus(entry.getKey().getResourceName(), complete, total)); + TransferResourceAndSize entry = entries.next(); + long total = entry.resource.getContentLength(); + Long complete = entry.transferredBytes; + buffer.append(getStatus(entry.resource.getResourceName(), complete, total)); if (entries.hasNext()) { buffer.append(" | "); } @@ -131,7 +132,7 @@ private void pad(StringBuilder buffer, int spaces) { @Override public void transferSucceeded(TransferEvent event) { - transfers.remove(event.getResource()); + transfers.remove(new TransferResourceIdentifier(event.getResource())); overridePreviousTransfer(event); super.transferSucceeded(event); @@ -139,7 +140,7 @@ public void transferSucceeded(TransferEvent event) { @Override public void transferFailed(TransferEvent event) { - transfers.remove(event.getResource()); + transfers.remove(new TransferResourceIdentifier(event.getResource())); overridePreviousTransfer(event); super.transferFailed(event); @@ -155,4 +156,15 @@ private void overridePreviousTransfer(TransferEvent event) { lastLength = 0; } } + + private final class TransferResourceAndSize { + + private final TransferResource resource; + private final long transferredBytes; + + private TransferResourceAndSize(TransferResource resource, long transferredBytes) { + this.resource = resource; + this.transferredBytes = transferredBytes; + } + } } diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/transfer/SimplexTransferListener.java b/maven-embedder/src/main/java/org/apache/maven/cli/transfer/SimplexTransferListener.java index c556e16b70a..39c0c304c90 100644 --- a/maven-embedder/src/main/java/org/apache/maven/cli/transfer/SimplexTransferListener.java +++ b/maven-embedder/src/main/java/org/apache/maven/cli/transfer/SimplexTransferListener.java @@ -18,7 +18,6 @@ */ package org.apache.maven.cli.transfer; -import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ArrayBlockingQueue; @@ -129,7 +128,7 @@ private void demux(List exchanges) { LOGGER.warn("Invalid TransferEvent.EventType={}; ignoring it", type); } } catch (TransferCancelledException e) { - ongoing.put(transferEvent.getResource().getFile(), Boolean.FALSE); + ongoing.put(new TransferResourceIdentifier(transferEvent.getResource()), Boolean.FALSE); } }); } @@ -150,17 +149,17 @@ private void put(TransferEvent event, boolean last) { } } - private final ConcurrentHashMap ongoing = new ConcurrentHashMap<>(); + private final ConcurrentHashMap ongoing = new ConcurrentHashMap<>(); @Override public void transferInitiated(TransferEvent event) { - ongoing.putIfAbsent(event.getResource().getFile(), Boolean.TRUE); + ongoing.putIfAbsent(new TransferResourceIdentifier(event.getResource()), Boolean.TRUE); put(event, false); } @Override public void transferStarted(TransferEvent event) throws TransferCancelledException { - if (ongoing.get(event.getResource().getFile()) == Boolean.FALSE) { + if (ongoing.get(new TransferResourceIdentifier(event.getResource())) == Boolean.FALSE) { throw new TransferCancelledException(); } put(event, false); @@ -168,7 +167,7 @@ public void transferStarted(TransferEvent event) throws TransferCancelledExcepti @Override public void transferProgressed(TransferEvent event) throws TransferCancelledException { - if (ongoing.get(event.getResource().getFile()) == Boolean.FALSE) { + if (ongoing.get(new TransferResourceIdentifier(event.getResource())) == Boolean.FALSE) { throw new TransferCancelledException(); } put(event, false); @@ -176,7 +175,7 @@ public void transferProgressed(TransferEvent event) throws TransferCancelledExce @Override public void transferCorrupted(TransferEvent event) throws TransferCancelledException { - if (ongoing.get(event.getResource().getFile()) == Boolean.FALSE) { + if (ongoing.get(new TransferResourceIdentifier(event.getResource())) == Boolean.FALSE) { throw new TransferCancelledException(); } put(event, false); @@ -184,13 +183,13 @@ public void transferCorrupted(TransferEvent event) throws TransferCancelledExcep @Override public void transferSucceeded(TransferEvent event) { - ongoing.remove(event.getResource().getFile()); + ongoing.remove(new TransferResourceIdentifier(event.getResource())); put(event, ongoing.isEmpty()); } @Override public void transferFailed(TransferEvent event) { - ongoing.remove(event.getResource().getFile()); + ongoing.remove(new TransferResourceIdentifier(event.getResource())); put(event, ongoing.isEmpty()); } diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/transfer/TransferResourceIdentifier.java b/maven-embedder/src/main/java/org/apache/maven/cli/transfer/TransferResourceIdentifier.java new file mode 100644 index 00000000000..e58996c2d1a --- /dev/null +++ b/maven-embedder/src/main/java/org/apache/maven/cli/transfer/TransferResourceIdentifier.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.maven.cli.transfer; + +import java.io.File; +import java.util.Objects; + +import org.eclipse.aether.transfer.TransferResource; +import org.eclipse.sisu.Nullable; + +/** + * Immutable identifier of a {@link TransferResource}. + * The {@link TransferResource} is not immutable and does not implement {@code Objects#equals} and {@code Objects#hashCode} methods, + * making it not very suitable for usage in collections. + */ +final class TransferResourceIdentifier { + + private final String repositoryId; + private final String repositoryUrl; + private final String resourceName; + + @Nullable + private final File file; + + private TransferResourceIdentifier( + String repositoryId, String repositoryUrl, String resourceName, @Nullable File file) { + this.repositoryId = repositoryId; + this.repositoryUrl = repositoryUrl; + this.resourceName = resourceName; + this.file = file; + } + + TransferResourceIdentifier(TransferResource resource) { + this(resource.getRepositoryId(), resource.getRepositoryUrl(), resource.getResourceName(), resource.getFile()); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + + if (obj == null || obj.getClass() != this.getClass()) { + return false; + } + + TransferResourceIdentifier that = (TransferResourceIdentifier) obj; + return Objects.equals(this.repositoryId, that.repositoryId) + && Objects.equals(this.repositoryUrl, that.repositoryUrl) + && Objects.equals(this.resourceName, that.resourceName) + && Objects.equals(this.file, that.file); + } + + @Override + public int hashCode() { + return Objects.hash(repositoryId, repositoryUrl, resourceName, file); + } +} diff --git a/maven-embedder/src/test/java/org/apache/maven/cli/transfer/SimplexTransferListenerTest.java b/maven-embedder/src/test/java/org/apache/maven/cli/transfer/SimplexTransferListenerTest.java index 382c6092de0..541b2b50c95 100644 --- a/maven-embedder/src/test/java/org/apache/maven/cli/transfer/SimplexTransferListenerTest.java +++ b/maven-embedder/src/test/java/org/apache/maven/cli/transfer/SimplexTransferListenerTest.java @@ -21,11 +21,13 @@ import java.io.File; import org.eclipse.aether.DefaultRepositorySystemSession; +import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.transfer.TransferCancelledException; import org.eclipse.aether.transfer.TransferEvent; import org.eclipse.aether.transfer.TransferListener; import org.eclipse.aether.transfer.TransferResource; import org.junit.Test; +import org.mockito.Mockito; import static org.junit.Assert.fail; @@ -67,9 +69,7 @@ public void transferFailed(TransferEvent event) {} DefaultRepositorySystemSession session = new DefaultRepositorySystemSession(); // for technical reasons we cannot throw here, even if delegate does cancel transfer - listener.transferInitiated(new TransferEvent.Builder(session, resource) - .setType(TransferEvent.EventType.INITIATED) - .build()); + listener.transferInitiated(event(session, resource, TransferEvent.EventType.INITIATED)); Thread.sleep(500); // to make sure queue is processed, cancellation applied @@ -83,4 +83,35 @@ public void transferFailed(TransferEvent event) {} // good } } + + @Test + public void handlesAbsentTransferSource() throws InterruptedException, TransferCancelledException { + TransferResource resource = new TransferResource(null, null, "http://maven.org/test/test-resource", null, null); + + RepositorySystemSession session = Mockito.mock(RepositorySystemSession.class); + TransferListener delegate = Mockito.mock(TransferListener.class); + SimplexTransferListener listener = new SimplexTransferListener(delegate); + + TransferEvent transferInitiatedEvent = event(session, resource, TransferEvent.EventType.INITIATED); + TransferEvent transferStartedEvent = event(session, resource, TransferEvent.EventType.STARTED); + TransferEvent transferProgressedEvent = event(session, resource, TransferEvent.EventType.PROGRESSED); + TransferEvent transferSucceededEvent = event(session, resource, TransferEvent.EventType.SUCCEEDED); + + listener.transferInitiated(transferInitiatedEvent); + listener.transferStarted(transferStartedEvent); + listener.transferProgressed(transferProgressedEvent); + listener.transferSucceeded(transferSucceededEvent); + + Thread.sleep(500); // to make sure queue is processed, cancellation applied + + Mockito.verify(delegate).transferInitiated(transferInitiatedEvent); + Mockito.verify(delegate).transferStarted(transferStartedEvent); + Mockito.verify(delegate).transferProgressed(transferProgressedEvent); + Mockito.verify(delegate).transferSucceeded(transferSucceededEvent); + } + + private static TransferEvent event( + RepositorySystemSession session, TransferResource resource, TransferEvent.EventType type) { + return new TransferEvent.Builder(session, resource).setType(type).build(); + } }