1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package dev.aherscu.qa.s3.publisher.maven.plugin.util;
18
19 import java.io.*;
20 import java.text.*;
21 import java.util.*;
22
23 import org.apache.commons.codec.binary.*;
24 import org.apache.commons.codec.digest.*;
25 import org.apache.maven.plugin.logging.*;
26
27 import com.amazonaws.*;
28 import com.amazonaws.services.s3.*;
29 import com.amazonaws.services.s3.model.*;
30
31 import dev.aherscu.qa.s3.publisher.maven.plugin.config.*;
32
33 public class S3Uploader {
34
35 private final AmazonS3Client client;
36 private final Log log;
37 private final String bucketName;
38 private final File inputDirectory;
39 private final List<ManagedFileContentEncoder> contentEncoders;
40 private final boolean refreshExpiredObjects;
41 private final SimpleDateFormat httpDateFormat;
42
43 public S3Uploader(final AmazonS3Client client, final Log log,
44 final List<ManagedFileContentEncoder> contentEncoders,
45 final String bucketName,
46 final File inputDirectory, final File tmpDirectory,
47 final boolean refreshExpiredObjects) {
48 this.client = client;
49 this.log = log;
50 this.bucketName = bucketName;
51 this.inputDirectory = inputDirectory;
52 this.contentEncoders = contentEncoders;
53 this.refreshExpiredObjects = refreshExpiredObjects;
54 httpDateFormat =
55 new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
56 httpDateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
57 }
58
59 private static String calculateETag(final File file) throws Exception {
60 return Hex.encodeHexString(DigestUtils.md5(new FileInputStream(file)));
61 }
62
63 private static boolean isLocalFileSameAsRemote(final File localFile,
64 final ObjectMetadata remoteFileMetadata) throws Exception {
65 return remoteFileMetadata != null &&
66 remoteFileMetadata.getETag().equals(calculateETag(localFile));
67 }
68
69 private static boolean isMetadataExpired() {
70
71 return true;
72 }
73
74 private static String transformFileNameSlashesToS3(final String fileName) {
75 return fileName.replace('\\', '/');
76 }
77
78 public void uploadManagedFile(final ManagedFile managedFile)
79 throws Exception {
80 final File encodedFile = encodeManagedFile(managedFile);
81 final String remoteFileName = getRemoteFileName(managedFile);
82 final ObjectMetadata remoteMetadata =
83 retrieveObjectMetadata(remoteFileName);
84 final ObjectMetadataBuilder objectMetadataBuilder =
85 new ObjectMetadataBuilder(managedFile, encodedFile);
86 final ObjectMetadata objectMetadata =
87 objectMetadataBuilder.buildMetadata();
88
89 if (!isLocalFileSameAsRemote(encodedFile, remoteMetadata)) {
90 log.debug("uploading file " + managedFile.getFilename() + " to "
91 + bucketName);
92 client.putObject(bucketName, remoteFileName,
93 new FileInputStream(encodedFile), objectMetadata);
94 setObjectAcl(managedFile, remoteFileName);
95 } else {
96 if (refreshExpiredObjects && isMetadataExpired()) {
97 log.debug("refreshing metadata for file "
98 + managedFile.getFilename());
99 client.copyObject(
100 buildCopyObjectRequest(remoteFileName, objectMetadata));
101 setObjectAcl(managedFile, remoteFileName);
102 } else {
103 log.debug("the object " + remoteFileName + " stored at "
104 + bucketName + " does not require update");
105 }
106 }
107 }
108
109 private CopyObjectRequest buildCopyObjectRequest(
110 final String remoteFileName,
111 final ObjectMetadata objectMetadata) {
112 return new CopyObjectRequest(bucketName, remoteFileName, bucketName,
113 remoteFileName)
114 .withNewObjectMetadata(objectMetadata);
115 }
116
117 private File encodeManagedFile(final ManagedFile managedFile)
118 throws Exception {
119 File encodedFile = null;
120 for (final ManagedFileContentEncoder contentEncoder : contentEncoders) {
121 if (contentEncoder.isContentEncodingSupported(
122 managedFile.getMetadata().getContentEncoding())) {
123 log.debug("contentEncoding file " + managedFile.getFilename());
124 encodedFile = contentEncoder.encode(managedFile);
125 }
126 }
127 return encodedFile;
128 }
129
130 private String getRemoteFileName(final ManagedFile managedFile) {
131 final File file = new File(managedFile.getFilename());
132 return transformFileNameSlashesToS3(removeBasePath(file));
133 }
134
135 private void logObjectMetadata(final ObjectMetadata objectMetadata) {
136 log.debug(" ETag: " + objectMetadata.getETag());
137 log.debug(" ContentType: " + objectMetadata.getContentType());
138 log.debug(" CacheControl: " + objectMetadata.getCacheControl());
139 log.debug(" ContentEncoding: " + objectMetadata.getContentEncoding());
140 log.debug(" ContentLength: " + objectMetadata.getContentLength());
141 log.debug(" Expires: "
142 + (objectMetadata.getHttpExpiresDate() == null ? "unknown"
143 : httpDateFormat.format(objectMetadata.getHttpExpiresDate())));
144 log.debug(" LastModified: " + objectMetadata.getLastModified());
145 }
146
147 private String removeBasePath(final File file) {
148 return file.getPath().substring(inputDirectory.getPath().length() + 1);
149 }
150
151 private ObjectMetadata retrieveObjectMetadata(final String remoteFileName) {
152 log.debug("retrieving metadata for " + remoteFileName);
153 ObjectMetadata objectMetadata = null;
154 try {
155 objectMetadata =
156 client.getObjectMetadata(bucketName, remoteFileName);
157 logObjectMetadata(objectMetadata);
158 } catch (final AmazonServiceException e) {
159 log.debug(e);
160 }
161 return objectMetadata;
162 }
163
164 private void setObjectAcl(final ManagedFile managedFile,
165 final String remoteFileName) {
166 final CannedAccessControlList acl = CannedAccessControlList
167 .valueOf(managedFile.getMetadata().getCannedAcl());
168 client.setObjectAcl(bucketName, remoteFileName, acl);
169 }
170 }