View Javadoc
1   package org.apache.maven.cli.transfer;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.PrintStream;
23  import java.text.DecimalFormat;
24  import java.text.DecimalFormatSymbols;
25  import java.util.Locale;
26  
27  import org.apache.commons.lang3.Validate;
28  import org.eclipse.aether.transfer.AbstractTransferListener;
29  import org.eclipse.aether.transfer.TransferCancelledException;
30  import org.eclipse.aether.transfer.TransferEvent;
31  import org.eclipse.aether.transfer.TransferResource;
32  
33  /**
34   * AbstractMavenTransferListener
35   */
36  public abstract class AbstractMavenTransferListener
37      extends AbstractTransferListener
38  {
39  
40      // CHECKSTYLE_OFF: LineLength
41      /**
42       * Formats file size with the associated <a href="https://en.wikipedia.org/wiki/Metric_prefix">SI</a> prefix
43       * (GB, MB, kB) and using the patterns <code>#0.0</code> for numbers between 1 and 10
44       * and <code>###0</code> for numbers between 10 and 1000+ by default.
45       *
46       * @see <a href="https://en.wikipedia.org/wiki/Metric_prefix">https://en.wikipedia.org/wiki/Metric_prefix</a>
47       * @see <a href="https://en.wikipedia.org/wiki/Binary_prefix">https://en.wikipedia.org/wiki/Binary_prefix</a>
48       * @see <a
49       *      href="https://en.wikipedia.org/wiki/Octet_%28computing%29">https://en.wikipedia.org/wiki/Octet_(computing)</a>
50       */
51      // CHECKSTYLE_ON: LineLength
52      // TODO Move me to Maven Shared Utils
53      static class FileSizeFormat
54      {
55          enum ScaleUnit
56          {
57              BYTE
58              {
59                  @Override
60                  public long bytes()
61                  {
62                      return 1L;
63                  }
64  
65                  @Override
66                  public String symbol()
67                  {
68                      return "B";
69                  }
70              },
71              KILOBYTE
72              {
73                  @Override
74                  public long bytes()
75                  {
76                      return 1000L;
77                  }
78  
79                  @Override
80                  public String symbol()
81                  {
82                      return "kB";
83                  }
84              },
85              MEGABYTE
86              {
87                  @Override
88                  public long bytes()
89                  {
90                      return KILOBYTE.bytes() * KILOBYTE.bytes();
91                  }
92  
93                  @Override
94                  public String symbol()
95                  {
96                      return "MB";
97                  }
98              },
99              GIGABYTE
100             {
101                 @Override
102                 public long bytes()
103                 {
104                     return MEGABYTE.bytes() * KILOBYTE.bytes();
105                 };
106 
107                 @Override
108                 public String symbol()
109                 {
110                     return "GB";
111                 }
112             };
113 
114             public abstract long bytes();
115             public abstract String symbol();
116 
117             public static ScaleUnit getScaleUnit( long size )
118             {
119                 Validate.isTrue( size >= 0L, "file size cannot be negative: %s", size );
120 
121                 if ( size >= GIGABYTE.bytes() )
122                 {
123                     return GIGABYTE;
124                 }
125                 else if ( size >= MEGABYTE.bytes() )
126                 {
127                     return MEGABYTE;
128                 }
129                 else if ( size >= KILOBYTE.bytes() )
130                 {
131                     return KILOBYTE;
132                 }
133                 else
134                 {
135                     return BYTE;
136                 }
137             }
138         }
139 
140         private DecimalFormat smallFormat;
141         private DecimalFormat largeFormat;
142 
143         FileSizeFormat( Locale locale )
144         {
145             smallFormat = new DecimalFormat( "#0.0", new DecimalFormatSymbols( locale ) );
146             largeFormat = new DecimalFormat( "###0", new DecimalFormatSymbols( locale ) );
147         }
148 
149         public String format( long size )
150         {
151             return format( size, null );
152         }
153 
154         public String format( long size, ScaleUnit unit )
155         {
156             return format( size, unit, false );
157         }
158 
159         @SuppressWarnings( "checkstyle:magicnumber" )
160         public String format( long size, ScaleUnit unit, boolean omitSymbol )
161         {
162             Validate.isTrue( size >= 0L, "file size cannot be negative: %s", size );
163 
164             if ( unit == null )
165             {
166                 unit = ScaleUnit.getScaleUnit( size );
167             }
168 
169             double scaledSize = (double) size / unit.bytes();
170             String scaledSymbol = " " + unit.symbol();
171 
172             if ( omitSymbol )
173             {
174                 scaledSymbol = "";
175             }
176 
177             if ( unit == ScaleUnit.BYTE )
178             {
179                 return largeFormat.format( size ) + scaledSymbol;
180             }
181 
182             if ( scaledSize < 0.05 || scaledSize >= 10.0 )
183             {
184                 return largeFormat.format( scaledSize ) + scaledSymbol;
185             }
186             else
187             {
188                 return smallFormat.format( scaledSize ) + scaledSymbol;
189             }
190         }
191 
192         public String formatProgress( long progressedSize, long size )
193         {
194             Validate.isTrue( progressedSize >= 0L, "progressed file size cannot be negative: %s", progressedSize );
195             Validate.isTrue( size >= 0L && progressedSize <= size || size < 0L,
196                 "progressed file size cannot be greater than size: %s > %s", progressedSize, size );
197 
198             if ( size >= 0L && progressedSize != size )
199             {
200                 ScaleUnit unit = ScaleUnit.getScaleUnit( size );
201                 String formattedProgressedSize = format( progressedSize, unit, true );
202                 String formattedSize = format( size, unit );
203 
204                 return formattedProgressedSize + "/" + formattedSize;
205             }
206             else
207             {
208                 return format( progressedSize );
209             }
210         }
211     }
212 
213     protected PrintStream out;
214 
215     protected AbstractMavenTransferListener( PrintStream out )
216     {
217         this.out = out;
218     }
219 
220     @Override
221     public void transferInitiated( TransferEvent event )
222     {
223         String action = event.getRequestType() == TransferEvent.RequestType.PUT ? "Uploading" : "Downloading";
224         String direction = event.getRequestType() == TransferEvent.RequestType.PUT ? "to" : "from";
225 
226         TransferResource resource = event.getResource();
227         StringBuilder message = new StringBuilder();
228         message.append( action ).append( ' ' ).append( direction ).append( ' ' ).append( resource.getRepositoryId() );
229         message.append( ": " );
230         message.append( resource.getRepositoryUrl() ).append( resource.getResourceName() );
231 
232         out.println( message.toString() );
233     }
234 
235     @Override
236     public void transferCorrupted( TransferEvent event )
237         throws TransferCancelledException
238     {
239         TransferResource resource = event.getResource();
240         // TODO This needs to be colorized
241         out.println( "[WARNING] " + event.getException().getMessage() + " from " + resource.getRepositoryId() + " for "
242             + resource.getRepositoryUrl() + resource.getResourceName() );
243     }
244 
245     @Override
246     public void transferSucceeded( TransferEvent event )
247     {
248         String action = ( event.getRequestType() == TransferEvent.RequestType.PUT ? "Uploaded" : "Downloaded" );
249         String direction = event.getRequestType() == TransferEvent.RequestType.PUT ? "to" : "from";
250 
251         TransferResource resource = event.getResource();
252         long contentLength = event.getTransferredBytes();
253         FileSizeFormat format = new FileSizeFormat( Locale.ENGLISH );
254 
255         StringBuilder message = new StringBuilder();
256         message.append( action ).append( ' ' ).append( direction ).append( ' ' ).append( resource.getRepositoryId() );
257         message.append( ": " );
258         message.append( resource.getRepositoryUrl() ).append( resource.getResourceName() );
259         message.append( " (" ).append( format.format( contentLength ) );
260 
261         long duration = System.currentTimeMillis() - resource.getTransferStartTime();
262         if ( duration > 0L )
263         {
264             double bytesPerSecond = contentLength / ( duration / 1000.0 );
265             message.append( " at " ).append( format.format( (long) bytesPerSecond ) ).append( "/s" );
266         }
267 
268         message.append( ')' );
269         out.println( message.toString() );
270     }
271 
272 }