001/* 002 * Copyright 2012-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.boot.devtools.settings; 018 019import java.net.URL; 020import java.util.ArrayList; 021import java.util.Enumeration; 022import java.util.LinkedHashMap; 023import java.util.List; 024import java.util.Map; 025import java.util.regex.Pattern; 026 027import org.apache.commons.logging.Log; 028 029import org.springframework.boot.devtools.logger.DevToolsLogFactory; 030import org.springframework.core.io.UrlResource; 031import org.springframework.core.io.support.PropertiesLoaderUtils; 032 033/** 034 * DevTools settings loaded from {@literal /META-INF/spring-devtools.properties} files. 035 * 036 * @author Phillip Webb 037 * @since 1.3.0 038 */ 039public class DevToolsSettings { 040 041 /** 042 * The location to look for settings properties. Can be present in multiple JAR files. 043 */ 044 public static final String SETTINGS_RESOURCE_LOCATION = "META-INF/spring-devtools.properties"; 045 046 private static final Log logger = DevToolsLogFactory.getLog(DevToolsSettings.class); 047 048 private static DevToolsSettings settings; 049 050 private final List<Pattern> restartIncludePatterns = new ArrayList<>(); 051 052 private final List<Pattern> restartExcludePatterns = new ArrayList<>(); 053 054 DevToolsSettings() { 055 } 056 057 void add(Map<?, ?> properties) { 058 Map<String, Pattern> includes = getPatterns(properties, "restart.include."); 059 this.restartIncludePatterns.addAll(includes.values()); 060 Map<String, Pattern> excludes = getPatterns(properties, "restart.exclude."); 061 this.restartExcludePatterns.addAll(excludes.values()); 062 } 063 064 private Map<String, Pattern> getPatterns(Map<?, ?> properties, String prefix) { 065 Map<String, Pattern> patterns = new LinkedHashMap<>(); 066 properties.forEach((key, value) -> { 067 String name = String.valueOf(key); 068 if (name.startsWith(prefix)) { 069 Pattern pattern = Pattern.compile((String) value); 070 patterns.put(name, pattern); 071 } 072 }); 073 return patterns; 074 } 075 076 public boolean isRestartInclude(URL url) { 077 return isMatch(url.toString(), this.restartIncludePatterns); 078 } 079 080 public boolean isRestartExclude(URL url) { 081 return isMatch(url.toString(), this.restartExcludePatterns); 082 } 083 084 private boolean isMatch(String url, List<Pattern> patterns) { 085 for (Pattern pattern : patterns) { 086 if (pattern.matcher(url).find()) { 087 return true; 088 } 089 } 090 return false; 091 } 092 093 public static DevToolsSettings get() { 094 if (settings == null) { 095 settings = load(); 096 } 097 return settings; 098 } 099 100 static DevToolsSettings load() { 101 return load(SETTINGS_RESOURCE_LOCATION); 102 } 103 104 static DevToolsSettings load(String location) { 105 try { 106 DevToolsSettings settings = new DevToolsSettings(); 107 Enumeration<URL> urls = Thread.currentThread().getContextClassLoader() 108 .getResources(location); 109 while (urls.hasMoreElements()) { 110 settings.add(PropertiesLoaderUtils 111 .loadProperties(new UrlResource(urls.nextElement()))); 112 } 113 if (logger.isDebugEnabled()) { 114 logger.debug("Included patterns for restart : " 115 + settings.restartIncludePatterns); 116 logger.debug("Excluded patterns for restart : " 117 + settings.restartExcludePatterns); 118 } 119 return settings; 120 } 121 catch (Exception ex) { 122 throw new IllegalStateException("Unable to load devtools settings from " 123 + "location [" + location + "]", ex); 124 } 125 } 126 127}