001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- 002 * 003 * Copyright © 2017–2019 microBean. 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 014 * implied. See the License for the specific language governing 015 * permissions and limitations under the License. 016 */ 017package org.microbean.configuration.spi; 018 019import java.io.Serializable; 020 021import java.util.Collections; 022import java.util.Map; 023import java.util.Properties; 024import java.util.Set; 025 026import java.util.function.Function; 027 028import org.microbean.configuration.api.ConfigurationValue; 029 030/** 031 * An {@link AbstractResourceLoadingConfiguration} that {@linkplain 032 * #getValue(Resource, Map, String) gets configuration property 033 * values} from {@link Properties} resources. 034 * 035 * @author <a href="https://about.me/lairdnelson" 036 * target="_parent">Laird Nelson</a> 037 * 038 * @see #getValue(Resource, Map, String) 039 */ 040public class PropertiesConfiguration extends AbstractResourceLoadingConfiguration<Properties> implements Ranked, Serializable { 041 042 043 /* 044 * Static fields. 045 */ 046 047 048 /** 049 * The version of this class for {@linkplain Serializable 050 * serialization purposes}. 051 */ 052 private static final long serialVersionUID = 1L; 053 054 055 /* 056 * Constructors. 057 */ 058 059 060 /** 061 * Creates a new {@link PropertiesConfiguration}. 062 * 063 * @param resourceLoader a {@link Function} that accepts a {@link 064 * Map} of requested configuration coordinates and returns a {@link 065 * Resource} that can {@linkplain Resource#get() supply} a {@link 066 * Properties} object to serve as a source of configuration values 067 * for use by the {@link #getValue(Resource, Map, String)} method; 068 * may be {@code null} in which case all invocations of the {@link 069 * #getValue(Map, String)} method will return {@code null} 070 * 071 * @see #getValue(Resource, Map, String) 072 * 073 * @see Resource 074 */ 075 public PropertiesConfiguration(final Function<? super Map<? extends String, ? extends String>, ? extends Resource<? extends Properties>> resourceLoader) { 076 super(resourceLoader); 077 } 078 079 080 /* 081 * Instance methods. 082 */ 083 084 085 /** 086 * {@inheritDoc} 087 * 088 * <p>This implementation gets a {@link Properties} object 089 * {@linkplain Resource#get() from the supplied 090 * <code>Resource</code>} and uses it, plus the {@linkplain 091 * Resource#getCoordinates() configuration coordinates supplied by 092 * the supplied <code>Resource</code>}, to construct and return a 093 * suitable {@link ConfigurationValue}.</p> 094 * 095 * @param propertiesResource a {@link Resource} that can {@linkplain 096 * Resource#get() supply} a {@link Properties} object to serve as 097 * the ultimate source of configuration values for the requested 098 * coordinates; must not be {@code null} 099 * 100 * @param requestedCoordinates for convenience, the same {@link Map} 101 * supplied to the {@link #getValue(Map, String)} method is supplied 102 * here representing the configuration coordinates for which a value 103 * is requested; note that these may very well be different from 104 * {@linkplain Resource#getCoordinates() the configuration 105 * coordinates actually pertaining to the resource}; most 106 * implementations will not need to reference this parameter 107 * 108 * @param name the name of the configuration property for which a 109 * value is to be sought; must not be {@code null} 110 * 111 * @return a suitable {@link ConfigurationValue} or {@code null} 112 * 113 * @exception NullPointerException if {@code resource} or {@code 114 * name} is {@code null} 115 * 116 * @see #getValue(Map, String) 117 * 118 * @see Resource 119 */ 120 @Override 121 protected ConfigurationValue getValue(final Resource<? extends Properties> propertiesResource, final Map<String, String> requestedCoordinates, final String name) { 122 final ConfigurationValue returnValue; 123 final Properties properties; 124 if (propertiesResource == null) { 125 properties = null; 126 returnValue = null; 127 } else { 128 properties = propertiesResource.get(); 129 if (properties == null) { 130 returnValue = null; 131 } else { 132 returnValue = new ConfigurationValue(this, propertiesResource.getCoordinates(), name, properties.getProperty(name), false); 133 } 134 } 135 return returnValue; 136 } 137 138 @Override 139 public Set<String> getNames(final Resource<? extends Properties> propertiesResource) { 140 final Set<String> returnValue; 141 if (propertiesResource == null) { 142 returnValue = Collections.emptySet(); 143 } else { 144 final Properties properties = propertiesResource.get(); 145 if (properties != null) { 146 returnValue = Collections.emptySet(); 147 } else { 148 returnValue = properties.stringPropertyNames(); 149 } 150 } 151 return returnValue; 152 } 153 154 @Override 155 protected int getRank(final Resource<? extends Properties> resource) { 156 final int returnValue; 157 if (resource == null) { 158 returnValue = super.getRank(resource); 159 } else { 160 final Properties properties = resource.get(); 161 if (properties == null) { 162 returnValue = super.getRank(resource); 163 } else { 164 final String rankString = properties.getProperty("org.microbean.configuration.rank", "100"); 165 assert rankString != null; 166 int temp = 100; 167 try { 168 temp = Integer.parseInt(rankString); 169 } catch (final NumberFormatException ignoreMe) { 170 171 } finally { 172 returnValue = temp; 173 } 174 } 175 } 176 return returnValue; 177 } 178 179}