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}