001 package org.codehaus.mojo.wagon.shared; 002 003 import static java.lang.String.format; 004 import static java.lang.System.currentTimeMillis; 005 import static org.apache.commons.io.FileUtils.touch; 006 import static org.apache.commons.lang3.StringUtils.leftPad; 007 import static org.kuali.common.util.FormatUtils.getCount; 008 import static org.kuali.common.util.FormatUtils.getRate; 009 import static org.kuali.common.util.FormatUtils.getSize; 010 import static org.kuali.common.util.FormatUtils.getTime; 011 import static org.kuali.common.util.base.Exceptions.illegalState; 012 import static org.kuali.common.util.log.Loggers.newLogger; 013 014 import java.io.File; 015 import java.text.NumberFormat; 016 017 import javax.validation.constraints.Min; 018 019 import org.apache.maven.wagon.Wagon; 020 import org.kuali.common.core.build.ValidatingBuilder; 021 import org.kuali.common.core.validate.annotation.IdiotProofImmutable; 022 import org.kuali.common.util.Counter; 023 import org.kuali.common.util.LongCounter; 024 import org.kuali.common.util.execute.Executable; 025 import org.kuali.common.util.inform.Inform; 026 import org.kuali.common.util.inform.PercentCompleteInformer; 027 import org.slf4j.Logger; 028 029 @IdiotProofImmutable 030 public final class WagonDownloadExecutable implements Executable { 031 032 private static final Logger logger = newLogger(); 033 034 private final String remoteFile; 035 private final File destination; 036 private final Wagon wagon; 037 private final Counter counter; 038 private final LongCounter bytesCounter; 039 @Min(0) 040 private final int total; 041 @Min(0) 042 private final long start; 043 private final NumberFormat numberFormatter; 044 private final NumberFormat rateFormatter; 045 private final PercentCompleteInformer informer; 046 047 @Override 048 public void execute() { 049 try { 050 touch(destination); 051 wagon.get(remoteFile, destination); 052 counter.increment(); 053 if (useInformer()) { 054 inform(); 055 } else { 056 stats(); 057 } 058 } catch (Exception e) { 059 throw illegalState(e); 060 } 061 } 062 063 private void inform() { 064 synchronized (informer) { 065 informer.incrementProgress(); 066 if (informer.getProgress() % informer.getTotal() == 0) { 067 Inform inform = informer.getInform(); 068 String msg = String.format(" - [%s of %s]%s%s", informer.getProgress(), total, inform.getCompleteToken(), inform.getStartToken()); 069 inform.getPrintStream().print(msg); 070 } 071 } 072 } 073 074 private boolean useInformer() { 075 return "warn".equalsIgnoreCase(System.getProperty("org.slf4j.simpleLogger.log.org.kuali.maven.wagon")); 076 } 077 078 private void stats() { 079 bytesCounter.increment(destination.length()); 080 int count = counter.getValue(); 081 long elapsed = currentTimeMillis() - start; 082 String rate = getRate(elapsed, bytesCounter.getValue(), rateFormatter); 083 // long millisPerFile = elapsed / count; 084 int filesRemaining = total - count; 085 // long timeRemaining = millisPerFile * filesRemaining; 086 // int percent = new Double((count / (total * 1D)) * 100).intValue(); 087 String amount = lpad(getSize(bytesCounter.getValue(), numberFormatter), 6); 088 Object[] args = { lpad(getCount(count), 6), lpad(getCount(total), 6), lpad(getCount(filesRemaining), 6), ltime(elapsed), lpad(rate, 8), amount }; 089 logger.info(format("%s of %s - remaining %s [elapsed:%s rate:%s downloaded:%s]", args)); 090 } 091 092 private String ltime(long millis) { 093 return leftPad(getTime(millis, numberFormatter), 5, " "); 094 } 095 096 private String lpad(Object object, int size) { 097 return leftPad(object.toString(), size, " "); 098 } 099 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 }