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}