001/** 002 * Logback: the reliable, generic, fast and flexible logging framework. 003 * Copyright (C) 1999-2015, QOS.ch. All rights reserved. 004 * 005 * This program and the accompanying materials are dual-licensed under 006 * either the terms of the Eclipse Public License v1.0 as published by 007 * the Eclipse Foundation 008 * 009 * or (per the licensee's choosing) 010 * 011 * under the terms of the GNU Lesser General Public License version 2.1 012 * as published by the Free Software Foundation. 013 */ 014package ch.qos.logback.core.joran.spi; 015 016import ch.qos.logback.core.spi.ContextAwareBase; 017 018import java.io.File; 019import java.net.URL; 020import java.net.URLDecoder; 021import java.util.ArrayList; 022import java.util.List; 023 024import static ch.qos.logback.core.CoreConstants.PROPERTIES_FILE_EXTENSION; 025 026/** 027 * @author Ceki Gülcü 028 */ 029public class ConfigurationWatchList extends ContextAwareBase { 030 031 URL mainURL; 032 List<File> fileWatchList = new ArrayList<File>(); 033 List<Long> lastModifiedList = new ArrayList<Long>(); 034 035 public ConfigurationWatchList buildClone() { 036 ConfigurationWatchList out = new ConfigurationWatchList(); 037 out.mainURL = this.mainURL; 038 out.fileWatchList = new ArrayList<File>(this.fileWatchList); 039 out.lastModifiedList = new ArrayList<Long>(this.lastModifiedList); 040 return out; 041 } 042 043 public void clear() { 044 this.mainURL = null; 045 lastModifiedList.clear(); 046 fileWatchList.clear(); 047 } 048 049 /** 050 * The mainURL for the configuration file. Null values are allowed. 051 * 052 * @param mainURL 053 */ 054 public void setMainURL(URL mainURL) { 055 // main url can be null 056 this.mainURL = mainURL; 057 if (mainURL != null) 058 addAsFileToWatch(mainURL); 059 } 060 061 public boolean watchPredicateFulfilled() { 062 if(hasMainURLAndNonEmptyFileList()) { 063 return true; 064 } 065 066 return fileWatchListContainsProperties(); 067 068 } 069 070 private boolean hasMainURLAndNonEmptyFileList() { 071 return mainURL != null && !fileWatchList.isEmpty(); 072 } 073 074 private boolean fileWatchListContainsProperties() { 075 return fileWatchList.stream().anyMatch(file -> file.getName().endsWith(PROPERTIES_FILE_EXTENSION)); 076 077 } 078 079 private void addAsFileToWatch(URL url) { 080 File file = convertToFile(url); 081 if (file != null) { 082 fileWatchList.add(file); 083 lastModifiedList.add(file.lastModified()); 084 } 085 } 086 087 /** 088 * Add the url but only if it is file://. 089 * @param url should be a file 090 */ 091 092 public void addToWatchList(URL url) { 093 addAsFileToWatch(url); 094 } 095 096 public URL getMainURL() { 097 return mainURL; 098 } 099 100 public List<File> getCopyOfFileWatchList() { 101 return new ArrayList<File>(fileWatchList); 102 } 103 104 public File changeDetected() { 105 int len = fileWatchList.size(); 106 107 for (int i = 0; i < len; i++) { 108 long lastModified = lastModifiedList.get(i); 109 File file = fileWatchList.get(i); 110 long actualModificationDate = file.lastModified(); 111 112 if (lastModified != actualModificationDate) { 113 // update modification date in case this instance is reused 114 lastModifiedList.set(i, actualModificationDate); 115 return file; 116 } 117 } 118 return null; 119 } 120 121 @SuppressWarnings("deprecation") 122 File convertToFile(URL url) { 123 String protocol = url.getProtocol(); 124 if ("file".equals(protocol)) { 125 return new File(URLDecoder.decode(url.getFile())); 126 } else { 127 addInfo("URL [" + url + "] is not of type file"); 128 return null; 129 } 130 } 131 132 /** 133 * Returns true if there are watchable files, false otherwise. 134 * @return true if there are watchable files, false otherwise. 135 * @since 1.5.8 136 */ 137 public boolean hasAtLeastOneWatchableFile() { 138 return !fileWatchList.isEmpty(); 139 } 140}