View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.cli.transfer;
20  
21  import java.io.PrintStream;
22  import java.util.Collections;
23  import java.util.Iterator;
24  import java.util.LinkedHashMap;
25  import java.util.Locale;
26  import java.util.Map;
27  
28  import org.eclipse.aether.transfer.TransferCancelledException;
29  import org.eclipse.aether.transfer.TransferEvent;
30  import org.eclipse.aether.transfer.TransferResource;
31  
32  /**
33   * Console download progress meter.
34   * <p>
35   * This listener is not thread-safe and should be wrapped in the {@link SimplexTransferListener} in a multi-threaded scenario.
36   */
37  @Deprecated
38  public class ConsoleMavenTransferListener extends AbstractMavenTransferListener {
39  
40      private final Map<TransferResourceIdentifier, TransferResourceAndSize> transfers =
41              Collections.synchronizedMap(new LinkedHashMap<TransferResourceIdentifier, TransferResourceAndSize>());
42  
43      private final boolean printResourceNames;
44      private int lastLength;
45  
46      public ConsoleMavenTransferListener(PrintStream out, boolean printResourceNames) {
47          super(out);
48          this.printResourceNames = printResourceNames;
49      }
50  
51      @Override
52      public void transferInitiated(TransferEvent event) {
53          overridePreviousTransfer(event);
54  
55          super.transferInitiated(event);
56      }
57  
58      @Override
59      public void transferCorrupted(TransferEvent event) throws TransferCancelledException {
60          overridePreviousTransfer(event);
61  
62          super.transferCorrupted(event);
63      }
64  
65      @Override
66      public void transferProgressed(TransferEvent event) throws TransferCancelledException {
67          TransferResource resource = event.getResource();
68          transfers.put(
69                  new TransferResourceIdentifier(resource),
70                  new TransferResourceAndSize(resource, event.getTransferredBytes()));
71  
72          StringBuilder buffer = new StringBuilder(128);
73          buffer.append("Progress (").append(transfers.size()).append("): ");
74  
75          synchronized (transfers) {
76              Iterator<TransferResourceAndSize> entries = transfers.values().iterator();
77              while (entries.hasNext()) {
78                  TransferResourceAndSize entry = entries.next();
79                  long total = entry.resource.getContentLength();
80                  long complete = entry.transferredBytes;
81                  buffer.append(getStatus(entry.resource.getResourceName(), complete, total));
82                  if (entries.hasNext()) {
83                      buffer.append(" | ");
84                  }
85              }
86          }
87  
88          int pad = lastLength - buffer.length();
89          lastLength = buffer.length();
90          pad(buffer, pad);
91          buffer.append('\r');
92          out.print(buffer);
93          out.flush();
94      }
95  
96      private String getStatus(String resourceName, long complete, long total) {
97          FileSizeFormat format = new FileSizeFormat(Locale.ENGLISH);
98          StringBuilder status = new StringBuilder();
99  
100         if (printResourceNames) {
101             status.append(resourceName(resourceName));
102             status.append(" (");
103         }
104 
105         status.append(format.formatProgress(complete, total));
106 
107         if (printResourceNames) {
108             status.append(")");
109         }
110 
111         return status.toString();
112     }
113 
114     private String resourceName(String resourceName) {
115         if (resourceName == null || resourceName.trim().isEmpty()) {
116             return "";
117         }
118         final int pos = resourceName.lastIndexOf("/");
119         if (pos == -1 || pos == resourceName.length() - 1) {
120             return "";
121         }
122         return resourceName.substring(pos + 1);
123     }
124 
125     private void pad(StringBuilder buffer, int spaces) {
126         String block = "                                        ";
127         while (spaces > 0) {
128             int n = Math.min(spaces, block.length());
129             buffer.append(block, 0, n);
130             spaces -= n;
131         }
132     }
133 
134     @Override
135     public void transferSucceeded(TransferEvent event) {
136         transfers.remove(new TransferResourceIdentifier(event.getResource()));
137         overridePreviousTransfer(event);
138 
139         super.transferSucceeded(event);
140     }
141 
142     @Override
143     public void transferFailed(TransferEvent event) {
144         transfers.remove(new TransferResourceIdentifier(event.getResource()));
145         overridePreviousTransfer(event);
146 
147         super.transferFailed(event);
148     }
149 
150     private void overridePreviousTransfer(TransferEvent event) {
151         if (lastLength > 0) {
152             StringBuilder buffer = new StringBuilder(128);
153             pad(buffer, lastLength);
154             buffer.append('\r');
155             out.print(buffer);
156             out.flush();
157             lastLength = 0;
158         }
159     }
160 
161     private final class TransferResourceAndSize {
162 
163         private final TransferResource resource;
164         private final long transferredBytes;
165 
166         private TransferResourceAndSize(TransferResource resource, long transferredBytes) {
167             this.resource = resource;
168             this.transferredBytes = transferredBytes;
169         }
170     }
171 }