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