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.util.Locale;
22  
23  import org.apache.maven.api.services.MessageBuilder;
24  
25  /**
26   * Formats file size with the associated <a href="https://en.wikipedia.org/wiki/Metric_prefix">SI</a> prefix
27   * (GB, MB, kB) and using the patterns <code>#0.0</code> for numbers between 1 and 10
28   * and <code>###0</code> for numbers between 10 and 1000+ by default.
29   *
30   * @see <a href="https://en.wikipedia.org/wiki/Metric_prefix">https://en.wikipedia.org/wiki/Metric_prefix</a>
31   * @see <a href="https://en.wikipedia.org/wiki/Binary_prefix">https://en.wikipedia.org/wiki/Binary_prefix</a>
32   * @see <a
33   *      href="https://en.wikipedia.org/wiki/Octet_%28computing%29">https://en.wikipedia.org/wiki/Octet_(computing)</a>
34   */
35  public class FileSizeFormat {
36      public enum ScaleUnit {
37          BYTE {
38              @Override
39              public long bytes() {
40                  return 1L;
41              }
42  
43              @Override
44              public String symbol() {
45                  return "B";
46              }
47          },
48          KILOBYTE {
49              @Override
50              public long bytes() {
51                  return 1000L;
52              }
53  
54              @Override
55              public String symbol() {
56                  return "kB";
57              }
58          },
59          MEGABYTE {
60              @Override
61              public long bytes() {
62                  return KILOBYTE.bytes() * KILOBYTE.bytes();
63              }
64  
65              @Override
66              public String symbol() {
67                  return "MB";
68              }
69          },
70          GIGABYTE {
71              @Override
72              public long bytes() {
73                  return MEGABYTE.bytes() * KILOBYTE.bytes();
74              }
75              ;
76  
77              @Override
78              public String symbol() {
79                  return "GB";
80              }
81          };
82  
83          public abstract long bytes();
84  
85          public abstract String symbol();
86  
87          public static ScaleUnit getScaleUnit(long size) {
88              if (size < 0L) {
89                  throw new IllegalArgumentException("file size cannot be negative: " + size);
90              }
91  
92              if (size >= GIGABYTE.bytes()) {
93                  return GIGABYTE;
94              } else if (size >= MEGABYTE.bytes()) {
95                  return MEGABYTE;
96              } else if (size >= KILOBYTE.bytes()) {
97                  return KILOBYTE;
98              } else {
99                  return BYTE;
100             }
101         }
102     }
103 
104     public FileSizeFormat(Locale locale) {}
105 
106     public String format(long size) {
107         return format(size, null);
108     }
109 
110     public String format(long size, ScaleUnit unit) {
111         return format(size, unit, false);
112     }
113 
114     public String format(long size, ScaleUnit unit, boolean omitSymbol) {
115         StringBuilder sb = new StringBuilder();
116         format(sb, size, unit, omitSymbol);
117         return sb.toString();
118     }
119 
120     public void format(StringBuilder builder, long size) {
121         format(builder, size, null, false);
122     }
123 
124     public void format(StringBuilder builder, long size, ScaleUnit unit) {
125         format(builder, size, unit, false);
126     }
127 
128     @SuppressWarnings("checkstyle:magicnumber")
129     private void format(StringBuilder builder, long size, ScaleUnit unit, boolean omitSymbol) {
130         if (size < 0L) {
131             throw new IllegalArgumentException("file size cannot be negative: " + size);
132         }
133         if (unit == null) {
134             unit = ScaleUnit.getScaleUnit(size);
135         }
136 
137         double scaledSize = (double) size / unit.bytes();
138 
139         if (unit == ScaleUnit.BYTE) {
140             builder.append(size);
141         } else if (scaledSize < 0.05d || scaledSize >= 10.0d) {
142             builder.append(Math.round(scaledSize));
143         } else {
144             builder.append(Math.round(scaledSize * 10d) / 10d);
145         }
146 
147         if (!omitSymbol) {
148             builder.append(" ").append(unit.symbol());
149         }
150     }
151 
152     public void format(MessageBuilder builder, long size) {
153         format(builder, size, null, false);
154     }
155 
156     public void format(MessageBuilder builder, long size, ScaleUnit unit) {
157         format(builder, size, unit, false);
158     }
159 
160     @SuppressWarnings("checkstyle:magicnumber")
161     private void format(MessageBuilder builder, long size, ScaleUnit unit, boolean omitSymbol) {
162         if (size < 0L) {
163             throw new IllegalArgumentException("file size cannot be negative: " + size);
164         }
165         if (unit == null) {
166             unit = ScaleUnit.getScaleUnit(size);
167         }
168 
169         double scaledSize = (double) size / unit.bytes();
170 
171         if (unit == ScaleUnit.BYTE) {
172             builder.append(Long.toString(size));
173         } else if (scaledSize < 0.05d || scaledSize >= 10.0d) {
174             builder.append(Long.toString(Math.round(scaledSize)));
175         } else {
176             builder.append(Double.toString(Math.round(scaledSize * 10d) / 10d));
177         }
178 
179         if (!omitSymbol) {
180             builder.append(" ").append(unit.symbol());
181         }
182     }
183 
184     public String formatProgress(long progressedSize, long size) {
185         StringBuilder sb = new StringBuilder();
186         formatProgress(sb, progressedSize, size);
187         return sb.toString();
188     }
189 
190     public void formatProgress(StringBuilder builder, long progressedSize, long size) {
191         if (progressedSize < 0L) {
192             throw new IllegalArgumentException("progressed file size cannot be negative: " + size);
193         }
194         if (size >= 0 && progressedSize > size) {
195             throw new IllegalArgumentException(
196                     "progressed file size cannot be greater than size: " + progressedSize + " > " + size);
197         }
198 
199         if (size >= 0L && progressedSize != size) {
200             ScaleUnit unit = ScaleUnit.getScaleUnit(size);
201             format(builder, progressedSize, unit, true);
202             builder.append("/");
203             format(builder, size, unit, false);
204         } else {
205             ScaleUnit unit = ScaleUnit.getScaleUnit(progressedSize);
206 
207             format(builder, progressedSize, unit, false);
208         }
209     }
210 }