001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.maven.resolver.examples.util; 020 021import java.io.PrintStream; 022import java.text.DecimalFormat; 023import java.text.DecimalFormatSymbols; 024import java.time.Duration; 025import java.time.Instant; 026import java.util.Locale; 027import java.util.Map; 028import java.util.concurrent.ConcurrentHashMap; 029 030import org.eclipse.aether.transfer.AbstractTransferListener; 031import org.eclipse.aether.transfer.MetadataNotFoundException; 032import org.eclipse.aether.transfer.TransferEvent; 033import org.eclipse.aether.transfer.TransferResource; 034 035import static java.util.Objects.requireNonNull; 036 037/** 038 * A simplistic transfer listener that logs uploads/downloads to the console. 039 */ 040public class ConsoleTransferListener extends AbstractTransferListener { 041 042 private final PrintStream out; 043 044 private final Map<TransferResource, Long> downloads = new ConcurrentHashMap<>(); 045 046 private int lastLength; 047 048 public ConsoleTransferListener() { 049 this(null); 050 } 051 052 public ConsoleTransferListener(PrintStream out) { 053 this.out = (out != null) ? out : System.out; 054 } 055 056 @Override 057 public void transferInitiated(TransferEvent event) { 058 requireNonNull(event, "event cannot be null"); 059 String message = event.getRequestType() == TransferEvent.RequestType.PUT ? "Uploading" : "Downloading"; 060 061 out.println(message + ": " + event.getResource().getRepositoryUrl() 062 + event.getResource().getResourceName()); 063 } 064 065 @Override 066 public void transferProgressed(TransferEvent event) { 067 requireNonNull(event, "event cannot be null"); 068 TransferResource resource = event.getResource(); 069 downloads.put(resource, event.getTransferredBytes()); 070 071 StringBuilder buffer = new StringBuilder(64); 072 073 for (Map.Entry<TransferResource, Long> entry : downloads.entrySet()) { 074 long total = entry.getKey().getContentLength(); 075 long complete = entry.getValue(); 076 077 buffer.append(getStatus(complete, total)).append(" "); 078 } 079 080 int pad = lastLength - buffer.length(); 081 lastLength = buffer.length(); 082 pad(buffer, pad); 083 buffer.append('\r'); 084 085 out.print(buffer); 086 } 087 088 private String getStatus(long complete, long total) { 089 if (total >= 1024) { 090 return toKB(complete) + "/" + toKB(total) + " KB "; 091 } else if (total >= 0) { 092 return complete + "/" + total + " B "; 093 } else if (complete >= 1024) { 094 return toKB(complete) + " KB "; 095 } else { 096 return complete + " B "; 097 } 098 } 099 100 private void pad(StringBuilder buffer, int spaces) { 101 String block = " "; 102 while (spaces > 0) { 103 int n = Math.min(spaces, block.length()); 104 buffer.append(block, 0, n); 105 spaces -= n; 106 } 107 } 108 109 @Override 110 public void transferSucceeded(TransferEvent event) { 111 requireNonNull(event, "event cannot be null"); 112 transferCompleted(event); 113 114 TransferResource resource = event.getResource(); 115 long contentLength = event.getTransferredBytes(); 116 if (contentLength >= 0) { 117 String type = (event.getRequestType() == TransferEvent.RequestType.PUT ? "Uploaded" : "Downloaded"); 118 String len = contentLength >= 1024 ? toKB(contentLength) + " KB" : contentLength + " B"; 119 120 String throughput = ""; 121 Duration duration = Duration.between(resource.getStartTime(), Instant.now()); 122 if (duration.toMillis() > 0) { 123 long bytes = contentLength - resource.getResumeOffset(); 124 DecimalFormat format = new DecimalFormat("0.0", new DecimalFormatSymbols(Locale.ENGLISH)); 125 double kbPerSec = (bytes / 1024.0) / duration.toSeconds(); 126 throughput = " at " + format.format(kbPerSec) + " KB/sec"; 127 } 128 129 out.println(type + ": " + resource.getRepositoryUrl() + resource.getResourceName() + " (" + len + throughput 130 + ")"); 131 } 132 } 133 134 @Override 135 public void transferFailed(TransferEvent event) { 136 requireNonNull(event, "event cannot be null"); 137 transferCompleted(event); 138 139 if (!(event.getException() instanceof MetadataNotFoundException)) { 140 event.getException().printStackTrace(out); 141 } 142 } 143 144 private void transferCompleted(TransferEvent event) { 145 requireNonNull(event, "event cannot be null"); 146 downloads.remove(event.getResource()); 147 148 StringBuilder buffer = new StringBuilder(64); 149 pad(buffer, lastLength); 150 buffer.append('\r'); 151 out.print(buffer); 152 } 153 154 public void transferCorrupted(TransferEvent event) { 155 requireNonNull(event, "event cannot be null"); 156 event.getException().printStackTrace(out); 157 } 158 159 protected long toKB(long bytes) { 160 return (bytes + 1023) / 1024; 161 } 162}