BaseConfiguration.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;

  18. import java.util.ArrayList;
  19. import java.util.Collection;
  20. import java.util.Iterator;
  21. import java.util.LinkedHashMap;
  22. import java.util.List;
  23. import java.util.Map;

  24. import org.apache.commons.configuration2.ex.ConfigurationRuntimeException;

  25. /**
  26.  * Basic configuration class. Stores the configuration data but does not provide any load or save functions. If you want
  27.  * to load your Configuration from a file use PropertiesConfiguration or XmlConfiguration.
  28.  *
  29.  * This class extends normal Java properties by adding the possibility to use the same key many times concatenating the
  30.  * value strings instead of overwriting them.
  31.  */
  32. public class BaseConfiguration extends AbstractConfiguration implements Cloneable {
  33.     /** Stores the configuration key-value pairs */
  34.     private Map<String, Object> store = new LinkedHashMap<>();

  35.     /**
  36.      * Adds a key/value pair to the map. This routine does no magic morphing. It ensures the keylist is maintained
  37.      *
  38.      * @param key key to use for mapping
  39.      * @param value object to store
  40.      */
  41.     @Override
  42.     protected void addPropertyDirect(final String key, final Object value) {
  43.         final Object previousValue = getPropertyInternal(key);

  44.         if (previousValue == null) {
  45.             store.put(key, value);
  46.         } else if (previousValue instanceof List) {
  47.             // safe to case because we have created the lists ourselves
  48.             @SuppressWarnings("unchecked")
  49.             final List<Object> valueList = (List<Object>) previousValue;
  50.             // the value is added to the existing list
  51.             valueList.add(value);
  52.         } else {
  53.             // the previous value is replaced by a list containing the previous value and the new value
  54.             final List<Object> list = new ArrayList<>();
  55.             list.add(previousValue);
  56.             list.add(value);

  57.             store.put(key, list);
  58.         }
  59.     }

  60.     @Override
  61.     protected void clearInternal() {
  62.         store.clear();
  63.     }

  64.     /**
  65.      * Clear a property in the configuration.
  66.      *
  67.      * @param key the key to remove along with corresponding value.
  68.      */
  69.     @Override
  70.     protected void clearPropertyDirect(final String key) {
  71.         store.remove(key);
  72.     }

  73.     /**
  74.      * Creates a copy of this object. This implementation will create a deep clone, i.e. the map that stores the properties
  75.      * is cloned, too. So changes performed at the copy won't affect the original and vice versa.
  76.      *
  77.      * @return the copy
  78.      * @since 1.3
  79.      */
  80.     @Override
  81.     public Object clone() {
  82.         try {
  83.             final BaseConfiguration copy = (BaseConfiguration) super.clone();
  84.             cloneStore(copy);
  85.             copy.cloneInterpolator(this);

  86.             return copy;
  87.         } catch (final CloneNotSupportedException cex) {
  88.             // should not happen
  89.             throw new ConfigurationRuntimeException(cex);
  90.         }
  91.     }

  92.     /**
  93.      * Clones the internal map with the data of this configuration.
  94.      *
  95.      * @param copy the copy created by the {@code clone()} method
  96.      * @throws CloneNotSupportedException if the map cannot be cloned
  97.      */
  98.     private void cloneStore(final BaseConfiguration copy) throws CloneNotSupportedException {
  99.         // This is safe because the type of the map is known
  100.         @SuppressWarnings("unchecked")
  101.         final Map<String, Object> clonedStore = (Map<String, Object>) ConfigurationUtils.clone(store);
  102.         copy.store = clonedStore;

  103.         // Handle collections in the map; they have to be cloned, too
  104.         store.forEach((k, v) -> {
  105.             if (v instanceof Collection) {
  106.                 // This is safe because the collections were created by ourselves
  107.                 @SuppressWarnings("unchecked")
  108.                 final Collection<String> strList = (Collection<String>) v;
  109.                 copy.store.put(k, new ArrayList<>(strList));
  110.             }
  111.         });
  112.     }

  113.     /**
  114.      * check if the configuration contains the key
  115.      *
  116.      * @param key the configuration key
  117.      * @return {@code true} if Configuration contain given key, {@code false} otherwise.
  118.      */
  119.     @Override
  120.     protected boolean containsKeyInternal(final String key) {
  121.         return store.containsKey(key);
  122.     }

  123.     /**
  124.      * Tests whether this configuration contains one or more matches to this value. This operation stops at first
  125.      * match but may be more expensive than the containsKey method.
  126.      * @since 2.11.0
  127.      */
  128.     @Override
  129.     protected boolean containsValueInternal(final Object value) {
  130.         return store.containsValue(value);
  131.     }

  132.     /**
  133.      * Gets the list of the keys contained in the configuration repository.
  134.      *
  135.      * @return An Iterator.
  136.      */
  137.     @Override
  138.     protected Iterator<String> getKeysInternal() {
  139.         return store.keySet().iterator();
  140.     }

  141.     /**
  142.      * Reads property from underlying map.
  143.      *
  144.      * @param key key to use for mapping
  145.      * @return object associated with the given configuration key.
  146.      */
  147.     @Override
  148.     protected Object getPropertyInternal(final String key) {
  149.         return store.get(key);
  150.     }

  151.     /**
  152.      * Check if the configuration is empty
  153.      *
  154.      * @return {@code true} if Configuration is empty, {@code false} otherwise.
  155.      */
  156.     @Override
  157.     protected boolean isEmptyInternal() {
  158.         return store.isEmpty();
  159.     }

  160.     /**
  161.      * {@inheritDoc} This implementation obtains the size directly from the map used as data store. So this is a rather
  162.      * efficient implementation.
  163.      */
  164.     @Override
  165.     protected int sizeInternal() {
  166.         return store.size();
  167.     }
  168. }