Java tutorial
/** * Copyright 2013 Netflix, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package halfpipe.properties; import static com.netflix.config.sources.URLConfigurationSource.*; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.*; import java.util.Map.Entry; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.FileConfiguration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.netflix.config.PollResult; import com.netflix.config.PolledConfigurationSource; /** * A polled configuration source based on a set of URLs. For each poll, * it always returns the complete union of properties defined in all files. If one property * is defined in more than one URL, the value in file later on the list will override * the value in the previous one. The content of the URL should conform to the properties file format. * */ public class UrlPropertiesSource implements PolledConfigurationSource { private static final Logger logger = LoggerFactory.getLogger(UrlPropertiesSource.class); private final URL[] configUrls; /** * Create an instance with a list URLs to be used. * * @param urls list of URLs to be used */ public UrlPropertiesSource(String... urls) { configUrls = createUrls(urls); } private static URL[] createUrls(String... urlStrings) { if (urlStrings == null || urlStrings.length == 0) { throw new IllegalArgumentException("urlStrings is null or empty"); } URL[] urls = new URL[urlStrings.length]; try { for (int i = 0; i < urls.length; i++) { urls[i] = new URL(urlStrings[i]); } } catch (Throwable e) { throw new RuntimeException(e); } return urls; } /** * Create an instance with a list URLs to be used. * * @param urls list of URLs to be used */ public UrlPropertiesSource(URL... urls) { configUrls = urls; } /** * Create the instance for the default list of URLs, which is composed by the following order * * <ul> * <li>A configuration file (default name to be <code>config.properties</code>, see {@link #DEFAULT_CONFIG_FILE_NAME}) on the classpath * <li>A list of URLs defined by system property {@value #CONFIG_URL} with values separated by comma <code>","</code>. * </ul> */ public UrlPropertiesSource() { List<URL> urlList = new ArrayList<URL>(); URL configFromClasspath = getConfigFileFromClasspath(); if (configFromClasspath != null) { urlList.add(configFromClasspath); } String[] fileNames = getDefaultFileSources(); if (fileNames.length != 0) { urlList.addAll(Arrays.asList(createUrls(fileNames))); } if (urlList.size() == 0) { configUrls = new URL[0]; logger.warn("No URLs will be polled as dynamic configuration sources."); logger.info("To enable URLs as dynamic configuration sources, define System property " + CONFIG_URL + " or make " + DEFAULT_CONFIG_FILE_FROM_CLASSPATH + " available on classpath."); } else { configUrls = urlList.toArray(new URL[urlList.size()]); logger.info("URLs to be used as dynamic configuration source: " + urlList); } } private URL getConfigFileFromClasspath() { URL url = null; // attempt to load from the context classpath ClassLoader loader = Thread.currentThread().getContextClassLoader(); if (loader != null) { url = loader.getResource(DEFAULT_CONFIG_FILE_FROM_CLASSPATH); } if (url == null) { // attempt to load from the system classpath url = ClassLoader.getSystemResource(DEFAULT_CONFIG_FILE_FROM_CLASSPATH); } if (url == null) { // attempt to load from the system classpath url = UrlPropertiesSource.class.getResource(DEFAULT_CONFIG_FILE_FROM_CLASSPATH); } return url; } public List<URL> getConfigUrls() { return Collections.unmodifiableList(Arrays.asList(configUrls)); } private static final String[] getDefaultFileSources() { String name = System.getProperty(CONFIG_URL); String[] fileNames; if (name != null) { fileNames = name.split(","); } else { fileNames = new String[0]; } return fileNames; } /** * Retrieve the content of the property files. For each poll, it always * returns the complete union of properties defined in all URLs. If one * property is defined in content of more than one URL, the value in file later on the * list will override the value in the previous one. * * @param initial this parameter is ignored by the implementation * @param checkPoint this parameter is ignored by the implementation * @throws IOException IOException occurred in file operation */ @Override public PollResult poll(boolean initial, Object checkPoint) throws IOException { if (configUrls == null || configUrls.length == 0) { return PollResult.createFull(null); } Map<String, Object> map = new HashMap<String, Object>(); for (URL url : configUrls) { String urlString = url.toString().toLowerCase(); if (urlString.endsWith(".yaml") || urlString.endsWith(".yml")) { try { loadConfig(map, new YamlProperties(url)); } catch (ConfigurationException e) { throw new IOException("Error loading YamlProperties file " + url, e); } } else { loadConfig(map, url); } } return PollResult.createFull(map); } private void loadConfig(Map<String, Object> map, URL url) throws IOException { Properties props = new Properties(); InputStream fin = url.openStream(); props.load(fin); fin.close(); for (Entry<Object, Object> entry : props.entrySet()) { map.put((String) entry.getKey(), entry.getValue()); } } private void loadConfig(Map<String, Object> map, FileConfiguration config) throws ConfigurationException { config.load(); Iterator<String> keys = config.getKeys(); while (keys.hasNext()) { String key = keys.next(); map.put(key, config.getProperty(key)); } } @Override public String toString() { return "FileConfigurationSource [fileUrls=" + Arrays.toString(configUrls) + "]"; } }