Skip to content

Commit

Permalink
[MNG-8150] Backport TransferListener improvements for Maven 3.9.x (#1576
Browse files Browse the repository at this point in the history
)

Backporting #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
  • Loading branch information
pshevche committed Jun 11, 2024
1 parent 02927b7 commit 083716d
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@
*/
public class ConsoleMavenTransferListener extends AbstractMavenTransferListener {

private final Map<TransferResource, Long> transfers =
Collections.synchronizedMap(new LinkedHashMap<TransferResource, Long>());
private final Map<TransferResourceIdentifier, TransferResourceAndSize> transfers =
Collections.synchronizedMap(new LinkedHashMap<TransferResourceIdentifier, TransferResourceAndSize>());

private final boolean printResourceNames;
private int lastLength;
Expand All @@ -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<Map.Entry<TransferResource, Long>> entries =
transfers.entrySet().iterator();
Iterator<TransferResourceAndSize> entries = transfers.values().iterator();
while (entries.hasNext()) {
Map.Entry<TransferResource, Long> 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(" | ");
}
Expand Down Expand Up @@ -131,15 +132,15 @@ 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);
}

@Override
public void transferFailed(TransferEvent event) {
transfers.remove(event.getResource());
transfers.remove(new TransferResourceIdentifier(event.getResource()));
overridePreviousTransfer(event);

super.transferFailed(event);
Expand All @@ -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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -129,7 +128,7 @@ private void demux(List<Exchange> 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);
}
});
}
Expand All @@ -150,47 +149,47 @@ private void put(TransferEvent event, boolean last) {
}
}

private final ConcurrentHashMap<File, Boolean> ongoing = new ConcurrentHashMap<>();
private final ConcurrentHashMap<TransferResourceIdentifier, Boolean> 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);
}

@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);
}

@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);
}

@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());
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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

Expand All @@ -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();
}
}

0 comments on commit 083716d

Please sign in to comment.