1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.report.projectinfo.avatars;
20
21 import javax.inject.Named;
22
23 import java.io.File;
24 import java.io.FileNotFoundException;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.io.OutputStream;
28 import java.net.URI;
29 import java.net.URISyntaxException;
30 import java.net.URL;
31 import java.nio.file.Files;
32 import java.nio.file.Path;
33 import java.nio.file.Paths;
34 import java.security.MessageDigest;
35 import java.security.NoSuchAlgorithmException;
36 import java.util.Locale;
37
38 import org.codehaus.plexus.util.IOUtil;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42
43
44
45
46
47 @Named("gravatar")
48 class GravatarProvider implements AvatarsProvider {
49
50 private static final Logger LOGGER = LoggerFactory.getLogger(GravatarProvider.class);
51
52 private static final String AVATAR_SIZE = "s=60";
53
54 private static final String AVATAR_DIRECTORY = "avatars";
55
56 private static final String AVATAR_DEFAULT_FILE_NAME = "00000000000000000000000000000000.jpg";
57
58 private String baseUrl = "https://www.gravatar.com/avatar/";
59
60 private Path outputDirectory;
61
62 @Override
63 public void setBaseUrl(String baseUrl) {
64 this.baseUrl = baseUrl.endsWith("/") ? baseUrl : baseUrl + "/";
65 }
66
67 @Override
68 public void setOutputDirectory(File outputDirectory) {
69 this.outputDirectory = outputDirectory.toPath();
70 }
71
72 public String getAvatarUrl(String email) {
73 return getAvatarUrl(email, "blank");
74 }
75
76 private String getAvatarUrl(String email, String defaultAvatar) {
77 if (email == null || email.isEmpty()) {
78 return getSpacerGravatarUrl();
79 }
80
81 try {
82 email = email.trim().toLowerCase(Locale.ROOT);
83 MessageDigest md = MessageDigest.getInstance("MD5");
84 md.update(email.getBytes());
85 byte[] byteData = md.digest();
86 StringBuilder sb = new StringBuilder();
87 final int lowerEightBitsOnly = 0xff;
88 for (byte aByteData : byteData) {
89 sb.append(Integer.toString((aByteData & lowerEightBitsOnly) + 0x100, 16)
90 .substring(1));
91 }
92 return baseUrl + sb + ".jpg?d=" + defaultAvatar + "&" + AVATAR_SIZE;
93 } catch (NoSuchAlgorithmException e) {
94 LOGGER.warn("Error while getting MD5 hash, use default image: {}", e.getMessage());
95 return getSpacerGravatarUrl();
96 }
97 }
98
99 @Override
100 public String getLocalAvatarPath(String email) throws IOException {
101
102 String avatarUrl = getAvatarUrl(email, "404");
103 try {
104 URL url = new URI(avatarUrl).toURL();
105 Path name = Paths.get(url.getPath()).getFileName();
106 if (AVATAR_DEFAULT_FILE_NAME.equals(name.toString())) {
107 copyDefault();
108 } else {
109 copyUrl(url, outputDirectory.resolve(AVATAR_DIRECTORY).resolve(name));
110 }
111 return AVATAR_DIRECTORY + "/" + name;
112 } catch (URISyntaxException | IOException e) {
113 if (e instanceof FileNotFoundException) {
114 LOGGER.debug(
115 "Error while getting external avatar url for: {}, use default image: {}:{}",
116 email,
117 e.getClass().getName(),
118 e.getMessage());
119 } else {
120 LOGGER.warn(
121 "Error while getting external avatar url for: {}, use default image: {}:{}",
122 email,
123 e.getClass().getName(),
124 e.getMessage());
125 }
126 copyDefault();
127 return AVATAR_DIRECTORY + "/" + AVATAR_DEFAULT_FILE_NAME;
128 }
129 }
130
131 private String getSpacerGravatarUrl() {
132 return baseUrl + AVATAR_DEFAULT_FILE_NAME + "?d=blank&f=y&" + AVATAR_SIZE;
133 }
134
135 private void copyUrl(URL url, Path outputPath) throws IOException {
136 if (!Files.exists(outputPath)) {
137 Files.createDirectories(outputPath.getParent());
138 try (InputStream in = url.openStream();
139 OutputStream out = Files.newOutputStream(outputPath)) {
140 LOGGER.debug("Copying URL {} to {}", url, outputPath);
141 IOUtil.copy(in, out);
142 }
143 }
144 }
145
146 private void copyDefault() throws IOException {
147 Path outputPath = outputDirectory.resolve(AVATAR_DIRECTORY).resolve(AVATAR_DEFAULT_FILE_NAME);
148 if (!Files.exists(outputPath)) {
149 Files.createDirectories(outputPath.getParent());
150 try (InputStream in = getClass().getResourceAsStream("default-avatar.jpg");
151 OutputStream out = Files.newOutputStream(outputPath)) {
152 IOUtil.copy(in, out);
153 }
154 }
155 }
156 }