1
2
3
4
5
6
7
8
9
10
11
12
13
14 package ch.qos.logback.core.joran.spi;
15
16 import ch.qos.logback.core.spi.ContextAwareBase;
17 import ch.qos.logback.core.util.MD5Util;
18
19 import java.io.File;
20 import java.net.HttpURLConnection;
21 import java.net.URL;
22 import java.net.URLDecoder;
23 import java.security.NoSuchAlgorithmException;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.List;
27 import java.util.stream.Collectors;
28
29 import static ch.qos.logback.core.CoreConstants.PROPERTIES_FILE_EXTENSION;
30
31
32
33
34
35
36 public class ConfigurationWatchList extends ContextAwareBase {
37
38 public static final String HTTPS_PROTOCOL_STR = "https";
39 public static final String HTTP_PROTOCOL_STR = "http";
40 public static final String FILE_PROTOCOL_STR = "file";
41
42 static final String[] WATCHABLE_PROTOCOLS = new String[] { FILE_PROTOCOL_STR, HTTPS_PROTOCOL_STR, HTTP_PROTOCOL_STR };
43
44 static final byte[] BUF_ZERO = new byte[] { 0 };
45
46 URL topURL;
47 List<File> fileWatchList = new ArrayList<>();
48 List<URL> urlWatchList = new ArrayList<>();
49 List<byte[]> lastHashList = new ArrayList<>();
50
51 List<Long> lastModifiedList = new ArrayList<>();
52
53 public ConfigurationWatchList buildClone() {
54 ConfigurationWatchList out = new ConfigurationWatchList();
55 out.topURL = this.topURL;
56 out.fileWatchList = new ArrayList<File>(this.fileWatchList);
57 out.lastModifiedList = new ArrayList<Long>(this.lastModifiedList);
58 out.lastHashList = new ArrayList<>(this.lastHashList);
59 return out;
60 }
61
62 public void clear() {
63 this.topURL = null;
64 this.lastModifiedList.clear();
65 this.fileWatchList.clear();
66 this.urlWatchList.clear();
67 this.lastHashList.clear();
68 }
69
70
71
72
73
74
75 public void setTopURL(URL topURL) {
76
77 this.topURL = topURL;
78 if (topURL != null)
79 addAsFileToWatch(topURL);
80 }
81
82 public boolean watchPredicateFulfilled() {
83 if (hasMainURLAndNonEmptyFileList()) {
84 return true;
85 }
86
87 if(urlListContainsProperties()) {
88 return true;
89 }
90
91 return fileWatchListContainsProperties();
92
93 }
94
95 private boolean urlListContainsProperties() {
96 return urlWatchList.stream().anyMatch(url -> url.toString().endsWith(PROPERTIES_FILE_EXTENSION));
97 }
98
99 private boolean hasMainURLAndNonEmptyFileList() {
100 return topURL != null && !fileWatchList.isEmpty();
101 }
102
103 private boolean fileWatchListContainsProperties() {
104 return fileWatchList.stream().anyMatch(file -> file.getName().endsWith(PROPERTIES_FILE_EXTENSION));
105
106 }
107
108 private void addAsFileToWatch(URL url) {
109 File file = convertToFile(url);
110 if (file != null) {
111 fileWatchList.add(file);
112 lastModifiedList.add(file.lastModified());
113 }
114 }
115
116
117 private boolean isHTTP_Or_HTTPS(URL url) {
118 String protocolStr = url.getProtocol();
119 return isHTTP_Or_HTTPS(protocolStr);
120 }
121
122 private boolean isHTTP_Or_HTTPS(String protocolStr) {
123 return (protocolStr.equals(HTTP_PROTOCOL_STR) || protocolStr.equals(HTTPS_PROTOCOL_STR));
124 }
125
126 private void addAsHTTP_or_HTTPS_URLToWatch(URL url) {
127 if(isHTTP_Or_HTTPS(url)) {
128 urlWatchList.add(url);
129 lastHashList.add(BUF_ZERO);
130 }
131 }
132
133
134
135
136
137 public void addToWatchList(URL url) {
138
139 String protocolStr = url.getProtocol();
140 if (protocolStr.equals(FILE_PROTOCOL_STR)) {
141 addAsFileToWatch(url);
142 } else if (isHTTP_Or_HTTPS(protocolStr)) {
143 addAsHTTP_or_HTTPS_URLToWatch(url);
144 }
145 }
146
147 public URL getTopURL() {
148 return topURL;
149 }
150
151 public List<File> getCopyOfFileWatchList() {
152 return new ArrayList<File>(fileWatchList);
153 }
154
155
156 public boolean emptyWatchLists() {
157 if(fileWatchList != null && !fileWatchList.isEmpty()) {
158 return false;
159 }
160
161 if(urlWatchList != null && !urlWatchList.isEmpty()) {
162 return false;
163 }
164 return true;
165 }
166
167
168
169
170
171
172 public File changeDetected() {
173 return changeDetectedInFile();
174 }
175
176
177
178
179
180 public File changeDetectedInFile() {
181 int len = fileWatchList.size();
182
183 for (int i = 0; i < len; i++) {
184 long lastModified = lastModifiedList.get(i);
185 File file = fileWatchList.get(i);
186 long actualModificationDate = file.lastModified();
187
188 if (lastModified != actualModificationDate) {
189
190 lastModifiedList.set(i, actualModificationDate);
191 return file;
192 }
193 }
194 return null;
195 }
196
197 public URL changeDetectedInURL() {
198 int len = urlWatchList.size();
199
200 for (int i = 0; i < len; i++) {
201 byte[] lastHash = this.lastHashList.get(i);
202 URL url = urlWatchList.get(i);
203
204 HttpUtil httpGetUtil = new HttpUtil(HttpUtil.RequestMethod.GET, url);
205 HttpURLConnection getConnection = httpGetUtil.connectTextTxt();
206 String response = httpGetUtil.readResponse(getConnection);
207
208 byte[] hash = computeHash(response);
209 if (lastHash == BUF_ZERO) {
210 this.lastHashList.set(i, hash);
211 return null;
212 }
213
214 if (Arrays.equals(lastHash, hash)) {
215 return null;
216 } else {
217 this.lastHashList.set(i, hash);
218 return url;
219 }
220 }
221 return null;
222 }
223
224 private byte[] computeHash(String response) {
225 if (response == null || response.trim().length() == 0) {
226 return null;
227 }
228
229 try {
230 MD5Util md5Util = new MD5Util();
231 byte[] hashBytes = md5Util.md5Hash(response);
232 return hashBytes;
233 } catch (NoSuchAlgorithmException e) {
234 addError("missing MD5 algorithm", e);
235 return null;
236 }
237 }
238
239 @SuppressWarnings("deprecation")
240 File convertToFile(URL url) {
241 String protocol = url.getProtocol();
242 if ("file".equals(protocol)) {
243 return new File(URLDecoder.decode(url.getFile()));
244 } else {
245 addInfo("URL [" + url + "] is not of type file");
246 return null;
247 }
248 }
249
250
251
252
253
254
255 public boolean hasAtLeastOneWatchableFile() {
256 return !fileWatchList.isEmpty();
257 }
258
259
260
261
262
263
264
265
266 static public boolean isWatchableProtocol(URL url) {
267 if (url == null) {
268 return false;
269 }
270 String protocolStr = url.getProtocol();
271 return isWatchableProtocol(protocolStr);
272 }
273
274
275
276
277
278
279
280
281 static public boolean isWatchableProtocol(String protocolStr) {
282 return Arrays.stream(WATCHABLE_PROTOCOLS).anyMatch(protocol -> protocol.equalsIgnoreCase(protocolStr));
283 }
284
285
286
287
288
289
290 public String getUrlWatchListAsStr() {
291 String urlWatchListStr = urlWatchList.stream().map(URL::toString).collect(Collectors.joining(", "));
292 return urlWatchListStr;
293 }
294
295
296
297
298
299
300 public String getFileWatchListAsStr() {
301 return fileWatchList.stream().map(File::getPath).collect(Collectors.joining(", "));
302 }
303
304 }