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.BufferedInputStream;
020import java.io.InputStream;
021import java.io.IOException;
022
023import java.net.URL;
024
025import java.util.Map;
026import java.util.Properties;
027
028import java.util.concurrent.ConcurrentHashMap;
029
030import java.util.function.Function;
031
032import org.microbean.configuration.Configurations;
033
034import org.microbean.configuration.api.ConfigurationException;
035
036import org.microbean.configuration.spi.AbstractResourceLoadingConfiguration.Resource;
037
038import org.microbean.configuration.spi.converter.StringToMapStringStringConverter;
039
040public class PropertiesLoader implements Function<Map<? extends String, ? extends String>, Resource<? extends Properties>> {
041
042  private final ClassLoader resourceLoader;
043  
044  protected final String name;
045
046  public PropertiesLoader(final String name) {
047    this(Thread.currentThread().getContextClassLoader(), name);
048  }
049  
050  public PropertiesLoader(final ClassLoader resourceLoader, final String name) {
051    super();
052    this.name = name;
053    this.resourceLoader = resourceLoader;
054  }
055
056  @Override
057  public Resource<? extends Properties> apply(final Map<? extends String, ? extends String> requestedConfigurationCoordinates) {
058    Resource<? extends Properties> returnValue = null;
059    if (this.name != null) {
060      ClassLoader resourceLoader = this.resourceLoader;
061      if (resourceLoader == null) {
062        resourceLoader = Thread.currentThread().getContextClassLoader();
063        if (resourceLoader == null) {
064          resourceLoader = this.getClass().getClassLoader();
065        }
066      }
067      assert resourceLoader != null;
068      final URL resource = resourceLoader.getResource(this.computeResourceName(requestedConfigurationCoordinates));
069      if (resource != null) {
070        Properties properties = null;
071        try (final InputStream inputStream = new BufferedInputStream(resource.openStream())) {
072          if (inputStream != null) {
073            properties = new Properties();
074            properties.load(inputStream);
075          }
076        } catch (final IOException ioException) {
077          throw new ConfigurationException(ioException.getMessage(), ioException);
078        }
079        returnValue = new Resource<>(properties, new StringToMapStringStringConverter().convert(properties.getProperty(Configurations.CONFIGURATION_COORDINATES)));
080      }
081    }
082    return returnValue;
083  }
084
085  protected String computeResourceName(final Map<? extends String, ? extends String> requestedConfigurationCoordinates) {
086    return this.name;
087  }
088
089}