1 package org.codehaus.mojo.wagon.shared;
2
3 import static java.lang.String.format;
4 import static java.lang.System.currentTimeMillis;
5 import static org.apache.commons.io.FileUtils.touch;
6 import static org.apache.commons.lang3.StringUtils.leftPad;
7 import static org.kuali.common.util.FormatUtils.getCount;
8 import static org.kuali.common.util.FormatUtils.getRate;
9 import static org.kuali.common.util.FormatUtils.getSize;
10 import static org.kuali.common.util.FormatUtils.getTime;
11 import static org.kuali.common.util.base.Exceptions.illegalState;
12 import static org.kuali.common.util.log.Loggers.newLogger;
13
14 import java.io.File;
15 import java.text.NumberFormat;
16
17 import javax.validation.constraints.Min;
18
19 import org.apache.maven.wagon.Wagon;
20 import org.kuali.common.core.build.ValidatingBuilder;
21 import org.kuali.common.core.validate.annotation.IdiotProofImmutable;
22 import org.kuali.common.util.Counter;
23 import org.kuali.common.util.LongCounter;
24 import org.kuali.common.util.execute.Executable;
25 import org.kuali.common.util.inform.Inform;
26 import org.kuali.common.util.inform.PercentCompleteInformer;
27 import org.slf4j.Logger;
28
29 @IdiotProofImmutable
30 public final class WagonDownloadExecutable implements Executable {
31
32 private static final Logger logger = newLogger();
33
34 private final String remoteFile;
35 private final File destination;
36 private final Wagon wagon;
37 private final Counter counter;
38 private final LongCounter bytesCounter;
39 @Min(0)
40 private final int total;
41 @Min(0)
42 private final long start;
43 private final NumberFormat numberFormatter;
44 private final NumberFormat rateFormatter;
45 private final PercentCompleteInformer informer;
46
47 @Override
48 public void execute() {
49 try {
50 touch(destination);
51 wagon.get(remoteFile, destination);
52 counter.increment();
53 if (useInformer()) {
54 inform();
55 } else {
56 stats();
57 }
58 } catch (Exception e) {
59 throw illegalState(e);
60 }
61 }
62
63 private void inform() {
64 synchronized (informer) {
65 informer.incrementProgress();
66 if (informer.getProgress() % informer.getTotal() == 0) {
67 Inform inform = informer.getInform();
68 String msg = String.format(" - [%s of %s]%s%s", informer.getProgress(), total, inform.getCompleteToken(), inform.getStartToken());
69 inform.getPrintStream().print(msg);
70 }
71 }
72 }
73
74 private boolean useInformer() {
75 return "warn".equalsIgnoreCase(System.getProperty("org.slf4j.simpleLogger.log.org.kuali.maven.wagon"));
76 }
77
78 private void stats() {
79 bytesCounter.increment(destination.length());
80 int count = counter.getValue();
81 long elapsed = currentTimeMillis() - start;
82 String rate = getRate(elapsed, bytesCounter.getValue(), rateFormatter);
83
84 int filesRemaining = total - count;
85
86
87 String amount = lpad(getSize(bytesCounter.getValue(), numberFormatter), 6);
88 Object[] args = { lpad(getCount(count), 6), lpad(getCount(total), 6), lpad(getCount(filesRemaining), 6), ltime(elapsed), lpad(rate, 8), amount };
89 logger.info(format("%s of %s - remaining %s [elapsed:%s rate:%s downloaded:%s]", args));
90 }
91
92 private String ltime(long millis) {
93 return leftPad(getTime(millis, numberFormatter), 5, " ");
94 }
95
96 private String lpad(Object object, int size) {
97 return leftPad(object.toString(), size, " ");
98 }
99
100 private WagonDownloadExecutable(Builder builder) {
101 this.remoteFile = builder.remoteFile;
102 this.destination = builder.destination;
103 this.wagon = builder.wagon;
104 this.counter = builder.counter;
105 this.total = builder.total;
106 this.start = builder.start;
107 this.bytesCounter = builder.bytesCounter;
108 this.numberFormatter = builder.numberFormatter;
109 this.rateFormatter = builder.rateFormatter;
110 this.informer = builder.informer;
111 }
112
113 public static Builder builder() {
114 return new Builder();
115 }
116
117 public static class Builder extends ValidatingBuilder<WagonDownloadExecutable> {
118
119 private String remoteFile;
120 private File destination;
121 private Wagon wagon;
122 private Counter counter;
123 private int total;
124 private long start;
125 private LongCounter bytesCounter;
126 private NumberFormat numberFormatter = getDefaultNumberFormatter();
127 private NumberFormat rateFormatter = getDefaultRateFormatter();
128 private PercentCompleteInformer informer;
129
130 public Builder withInformer(PercentCompleteInformer informer) {
131 this.informer = informer;
132 return this;
133 }
134
135 public Builder withRateFormatter(NumberFormat rateFormatter) {
136 this.rateFormatter = rateFormatter;
137 return this;
138 }
139
140 public Builder withNumberFormatter(NumberFormat numberFormatter) {
141 this.numberFormatter = numberFormatter;
142 return this;
143 }
144
145 public Builder withBytesCounter(LongCounter bytesCounter) {
146 this.bytesCounter = bytesCounter;
147 return this;
148 }
149
150 public Builder withStart(long start) {
151 this.start = start;
152 return this;
153 }
154
155 public Builder withTotal(int total) {
156 this.total = total;
157 return this;
158 }
159
160 public Builder withCounter(Counter counter) {
161 this.counter = counter;
162 return this;
163 }
164
165 public Builder withRemoteFile(String remoteFile) {
166 this.remoteFile = remoteFile;
167 return this;
168 }
169
170 public Builder withDestination(File destination) {
171 this.destination = destination;
172 return this;
173 }
174
175 public Builder withWagon(Wagon wagon) {
176 this.wagon = wagon;
177 return this;
178 }
179
180 @Override
181 public WagonDownloadExecutable build() {
182 return validate(new WagonDownloadExecutable(this));
183 }
184
185 private NumberFormat getDefaultNumberFormatter() {
186 NumberFormat nf = NumberFormat.getInstance();
187 nf.setMaximumFractionDigits(1);
188 nf.setMinimumFractionDigits(1);
189 return nf;
190 }
191
192 private NumberFormat getDefaultRateFormatter() {
193 NumberFormat nf = NumberFormat.getInstance();
194 nf.setMaximumFractionDigits(0);
195 return nf;
196 }
197
198 }
199
200 public String getRemoteFile() {
201 return remoteFile;
202 }
203
204 public File getDestination() {
205 return destination;
206 }
207
208 public Wagon getWagon() {
209 return wagon;
210 }
211
212 public Counter getCounter() {
213 return counter;
214 }
215
216 public int getTotal() {
217 return total;
218 }
219
220 public long getStart() {
221 return start;
222 }
223
224 public PercentCompleteInformer getInformer() {
225 return informer;
226 }
227
228 public LongCounter getBytesCounter() {
229 return bytesCounter;
230 }
231
232 }