ConfigurationPropertiesFactoryBean.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *     http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */

  17. package org.apache.commons.configuration2.spring;

  18. import java.util.Properties;
  19. import java.util.stream.Stream;

  20. import org.apache.commons.configuration2.CompositeConfiguration;
  21. import org.apache.commons.configuration2.Configuration;
  22. import org.apache.commons.configuration2.ConfigurationConverter;
  23. import org.apache.commons.configuration2.builder.fluent.Configurations;
  24. import org.apache.commons.lang3.ArrayUtils;
  25. import org.springframework.beans.factory.FactoryBean;
  26. import org.springframework.beans.factory.InitializingBean;
  27. import org.springframework.core.io.Resource;
  28. import org.springframework.util.Assert;

  29. /**
  30.  * <p>
  31.  * FactoryBean which wraps a Commons CompositeConfiguration object for usage with PropertiesLoaderSupport. This allows
  32.  * the compositeConfiguration object to behave like a normal {@link Properties} object which can be passed on to
  33.  * setProperties() method allowing PropertyOverrideConfigurer and PropertyPlaceholderConfigurer to take advantage of
  34.  * Commons Configuration.
  35.  * </p>
  36.  * <p>
  37.  * Internally a CompositeConfiguration object is used for merging multiple Configuration objects.
  38.  * </p>
  39.  *
  40.  * @see java.util.Properties
  41.  * @see org.springframework.core.io.support.PropertiesLoaderSupport
  42.  */
  43. public class ConfigurationPropertiesFactoryBean implements InitializingBean, FactoryBean<Properties> {

  44.     /**
  45.      * Creates a defensive copy of the specified array. Handles null values correctly.
  46.      *
  47.      * @param src the source array
  48.      * @param <T> the type of the array
  49.      * @return the defensive copy of the array
  50.      */
  51.     private static <T> T[] clone(final T[] src) {
  52.         return src != null ? src.clone() : null;
  53.     }

  54.     /** Internal CompositeConfiguration containing the merged configuration objects **/
  55.     private CompositeConfiguration compositeConfiguration;

  56.     /** Supplied configurations that will be merged in compositeConfiguration **/
  57.     private Configuration[] configurations;

  58.     /** Spring resources for loading configurations **/
  59.     private Resource[] locations;

  60.     /** @see org.apache.commons.configuration2.AbstractConfiguration#throwExceptionOnMissing **/
  61.     private boolean throwExceptionOnMissing = true;

  62.     /**
  63.      * Constructs a new instance.
  64.      */
  65.     public ConfigurationPropertiesFactoryBean() {
  66.     }

  67.     /**
  68.      * Constructs a new instance.
  69.      *
  70.      * @param configuration The configuration to compose.
  71.      */
  72.     public ConfigurationPropertiesFactoryBean(final Configuration configuration) {
  73.         Assert.notNull(configuration, "configuration");
  74.         this.compositeConfiguration = new CompositeConfiguration(configuration);
  75.     }

  76.     /**
  77.      * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
  78.      */
  79.     @Override
  80.     public void afterPropertiesSet() throws Exception {
  81.         if (compositeConfiguration == null && ArrayUtils.isEmpty(configurations) && ArrayUtils.isEmpty(locations)) {
  82.             throw new IllegalArgumentException("no configuration object or location specified");
  83.         }

  84.         if (compositeConfiguration == null) {
  85.             compositeConfiguration = new CompositeConfiguration();
  86.         }

  87.         compositeConfiguration.setThrowExceptionOnMissing(throwExceptionOnMissing);

  88.         if (configurations != null) {
  89.             Stream.of(configurations).forEach(compositeConfiguration::addConfiguration);
  90.         }

  91.         if (locations != null) {
  92.             for (final Resource location : locations) {
  93.                 compositeConfiguration.addConfiguration(new Configurations().properties(location.getURL()));
  94.             }
  95.         }
  96.     }

  97.     /**
  98.      * Gets the composite configuration.
  99.      *
  100.      * @return the composite configuration.
  101.      */
  102.     public CompositeConfiguration getConfiguration() {
  103.         return compositeConfiguration;
  104.     }

  105.     /**
  106.      * Gets a copy of the configurations.
  107.      *
  108.      * @return a copy of the configurations.
  109.      */
  110.     public Configuration[] getConfigurations() {
  111.         return clone(configurations);
  112.     }

  113.     /**
  114.      * Gets a copy of the resource locations.
  115.      *
  116.      * @return a copy of the resource locations.
  117.      */
  118.     public Resource[] getLocations() {
  119.         return clone(locations);
  120.     }

  121.     /**
  122.      * @see org.springframework.beans.factory.FactoryBean#getObject()
  123.      */
  124.     @Override
  125.     public Properties getObject() throws Exception {
  126.         return compositeConfiguration != null ? ConfigurationConverter.getProperties(compositeConfiguration) : null;
  127.     }

  128.     /**
  129.      * @see org.springframework.beans.factory.FactoryBean#getObjectType()
  130.      */
  131.     @Override
  132.     public Class<?> getObjectType() {
  133.         return Properties.class;
  134.     }

  135.     /**
  136.      * @see org.springframework.beans.factory.FactoryBean#isSingleton()
  137.      */
  138.     @Override
  139.     public boolean isSingleton() {
  140.         return true;
  141.     }

  142.     /**
  143.      * Tests the underlying CompositeConfiguration throwExceptionOnMissing flag.
  144.      *
  145.      * @return the underlying CompositeConfiguration throwExceptionOnMissing flag.
  146.      */
  147.     public boolean isThrowExceptionOnMissing() {
  148.         return throwExceptionOnMissing;
  149.     }

  150.     /**
  151.      * Sets the commons configurations objects which will be used as properties.
  152.      *
  153.      * @param configurations commons configurations objects which will be used as properties.
  154.      */
  155.     public void setConfigurations(final Configuration... configurations) {
  156.         this.configurations = clone(configurations);
  157.     }

  158.     /**
  159.      * Shortcut for loading compositeConfiguration from Spring resources. It will internally create a
  160.      * PropertiesConfiguration object based on the URL retrieved from the given Resources.
  161.      *
  162.      * @param locations resources of configuration files
  163.      */
  164.     public void setLocations(final Resource... locations) {
  165.         this.locations = clone(locations);
  166.     }

  167.     /**
  168.      * Sets the underlying CompositeConfiguration throwExceptionOnMissing flag.
  169.      *
  170.      * @see org.apache.commons.configuration2.AbstractConfiguration#setThrowExceptionOnMissing(boolean)
  171.      * @param throwExceptionOnMissing The new value for the property
  172.      */
  173.     public void setThrowExceptionOnMissing(final boolean throwExceptionOnMissing) {
  174.         this.throwExceptionOnMissing = throwExceptionOnMissing;
  175.     }
  176. }