1 package org.kuali.common.devops.jenkins.upgrade;
2
3 import static com.amazonaws.services.s3.Headers.CONTENT_TYPE;
4 import static com.google.common.base.Stopwatch.createStarted;
5 import static com.google.common.collect.Lists.newArrayList;
6 import static com.google.common.collect.Maps.newHashMap;
7 import static java.lang.String.format;
8 import static org.kuali.common.core.collect.Lists.shuffledCopy;
9 import static org.kuali.common.devops.archive.sweep.Functions.hostnameToKey;
10 import static org.kuali.common.devops.jenkins.upgrade.Jenkins.jenkinsContentType;
11 import static org.kuali.common.util.Encodings.UTF8;
12 import static org.kuali.common.util.log.Loggers.newLogger;
13
14 import java.io.File;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.concurrent.Callable;
18
19 import org.kuali.common.aws.s3.S3Service;
20 import org.kuali.common.aws.s3.model.ObjectMetadata;
21 import org.kuali.common.aws.s3.model.PutFileRequest;
22 import org.kuali.common.core.base.TimedInterval;
23 import org.kuali.common.core.build.ValidatingBuilder;
24 import org.kuali.common.core.io.BasicFile;
25 import org.kuali.common.core.validate.annotation.IdiotProofImmutable;
26 import org.kuali.common.util.inform.PercentCompleteInformer;
27 import org.slf4j.Logger;
28
29 import com.google.common.base.Function;
30 import com.google.common.base.Optional;
31 import com.google.common.base.Stopwatch;
32 import com.google.common.collect.ImmutableList;
33
34 @IdiotProofImmutable
35 public final class BasicFileUploadCallable implements Callable<List<TimedInterval>> {
36
37 private static final Logger logger = newLogger();
38
39 private final S3Service s3;
40 private final ImmutableList<BasicFile> files;
41 private final String hostname;
42 private final String bucket;
43 private final PercentCompleteInformer informer;
44 private final Function<BasicFile, Double> weigher;
45
46 private final Function<BasicFile, Optional<String>> contentType = jenkinsContentType();
47
48 @Override
49 public List<TimedInterval> call() {
50 String prefix = hostnameToKey().apply(hostname);
51 List<TimedInterval> timings = newArrayList();
52 List<BasicFile> shuffled = shuffledCopy(files);
53 for (BasicFile file : shuffled) {
54 Stopwatch sw = createStarted();
55 String s3Key = prefix + file.getPath();
56 try {
57 PutFileRequest request = getPutFileRequest(file, s3Key);
58 s3.putFile(request);
59 } catch (Exception e) {
60 logger.info(format("error -> %s", e));
61 }
62 TimedInterval timing = TimedInterval.build(sw);
63 timings.add(timing);
64 long progress = weigher.apply(file).longValue();
65 informer.incrementProgress(progress);
66 }
67 return timings;
68 }
69
70 private PutFileRequest getPutFileRequest(BasicFile file, String s3Key) {
71 PutFileRequest.Builder builder = PutFileRequest.builder().withBucket(bucket).withEncoding(UTF8).withFile(new File(file.getPath())).withKey(s3Key);
72 Optional<String> contentType = this.contentType.apply(file);
73 if (contentType.isPresent()) {
74 Map<String, Object> raw = newHashMap();
75 raw.put(CONTENT_TYPE, contentType.get());
76 ObjectMetadata meta = ObjectMetadata.builder().withRawMetadata(raw).build();
77 builder.withMetadata(meta);
78 }
79 return builder.build();
80 }
81
82 private BasicFileUploadCallable(Builder builder) {
83 this.s3 = builder.s3;
84 this.files = ImmutableList.copyOf(builder.files);
85 this.hostname = builder.hostname;
86 this.bucket = builder.bucket;
87 this.informer = builder.informer;
88 this.weigher = builder.weigher;
89 }
90
91 public static Builder builder() {
92 return new Builder();
93 }
94
95 public static class Builder extends ValidatingBuilder<BasicFileUploadCallable> {
96
97 private S3Service s3;
98 private List<BasicFile> files;
99 private String hostname;
100 private String bucket;
101 private PercentCompleteInformer informer;
102 private Function<BasicFile, Double> weigher;
103
104 public Builder withWeigher(Function<BasicFile, Double> weigher) {
105 this.weigher = weigher;
106 return this;
107 }
108
109 public Builder withS3(S3Service s3) {
110 this.s3 = s3;
111 return this;
112 }
113
114 public Builder withFiles(List<BasicFile> files) {
115 this.files = files;
116 return this;
117 }
118
119 public Builder withHostname(String hostname) {
120 this.hostname = hostname;
121 return this;
122 }
123
124 public Builder withBucket(String bucket) {
125 this.bucket = bucket;
126 return this;
127 }
128
129 public Builder withInformer(PercentCompleteInformer informer) {
130 this.informer = informer;
131 return this;
132 }
133
134 @Override
135 public BasicFileUploadCallable build() {
136 return validate(new BasicFileUploadCallable(this));
137 }
138 }
139
140 public S3Service getS3() {
141 return s3;
142 }
143
144 public List<BasicFile> getFiles() {
145 return files;
146 }
147
148 public String getHostname() {
149 return hostname;
150 }
151
152 public String getBucket() {
153 return bucket;
154 }
155
156 public PercentCompleteInformer getInformer() {
157 return informer;
158 }
159
160 public Function<BasicFile, Double> getWeigher() {
161 return weigher;
162 }
163
164 }