    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *     https://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 implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017package org.apache.commons.configuration2.convert;
    018
    019import java.util.Collection;
    020import java.util.Collections;
    021import java.util.IdentityHashMap;
    022import java.util.List;
    023
    024/**
    025 * <p>
    026 * Definition of an interface that controls the handling of list delimiters in configuration properties.
    027 * </p>
    028 * <p>
    029 * {@link org.apache.commons.configuration2.AbstractConfiguration AbstractConfiguration} supports list delimiters in
    030 * property values. If such a delimiter is found, the value actually contains multiple values and has to be split. This
    031 * is useful for instance for {@link org.apache.commons.configuration2.PropertiesConfiguration PropertiesConfiguration}:
    032 * properties files that have to be compatible with the {@link java.util.Properties} class cannot have multiple
    033 * occurrences of a single property key, therefore a different storage scheme for multi-valued properties is needed. A
    034 * possible storage scheme could look as follows:
    035 * </p>
    036 *
    037 * <pre>
    038 * myProperty=value1,value2,value3
    039 * </pre>
    040 *
    041 * <p>
    042 * Here a comma is used as list delimiter. When parsing this property (and using a corresponding
    043 * {@code ListDelimiterHandler} implementation) the string value is split, and three values are added for the property
    044 * key.
    045 * </p>
    046 * <p>
    047 * A {@code ListDelimiterHandler} knows how to parse and to escape property values. It is called by concrete
    048 * {@code Configuration} implementations when they have to deal with properties with multiple values.
    049 * </p>
    050 *
    051 * @since 2.0
    052 */
    053public interface ListDelimiterHandler {
    054
    055    /**
    056     * A specialized {@code ValueTransformer} implementation which does no transformation. The {@code transformValue()}
    057     * method just returns the passed in object without changes. This instance can be used by configurations which do not
    058     * require additional encoding.
    059     */
    060    ValueTransformer NOOP_TRANSFORMER = value -> value;
    061
    062    /**
    063     * Escapes the specified single value object. This method is called for properties containing only a single value. So
    064     * this method can rely on the fact that the passed in object is not a list. An implementation has to check whether the
    065     * value contains list delimiter characters and - if so - escape them accordingly.
    066     *
    067     * @param value the value to be escaped
    068     * @param transformer a {@code ValueTransformer} for an additional encoding (must not be <strong>null</strong>)
    069     * @return the escaped value
    070     */
    071    Object escape(Object value, ValueTransformer transformer);
    072
    073    /**
    074     * Escapes all values in the given list and concatenates them to a single string. This operation is required by
    075     * configurations that have to represent properties with multiple values in a single line in their external
    076     * configuration representation. This may require an advanced escaping in some cases.
    077     *
    078     * @param values the list with all the values to be converted to a single value
    079     * @param transformer a {@code ValueTransformer} for an additional encoding (must not be <strong>null</strong>)
    080     * @return the resulting escaped value
    081     */
    082    Object escapeList(List<?> values, ValueTransformer transformer);
    083
    084    /**
    085     * Extracts all values contained in the specified object up to the given limit. The passed in object is evaluated (if
    086     * necessary in a recursive way). If it is a complex object (for example a collection or an array), all its elements are
    087     * processed recursively and added to a target collection. The process stops if the limit is reached, but depending on
    088     * the input object, it might be exceeded. (The limit is just an indicator to stop the process to avoid unnecessary work
    089     * if the caller is only interested in a few values.)
    090     *
    091     * @param value the value to be processed
    092     * @param limit the limit for aborting the processing
    093     * @return a &quot;flat&quot; collection containing all primitive values of the passed in object
    094     * @since 2.9.0
    095     */
    096    default Collection<?> flatten(final Object value, final int limit) {
    097        return AbstractListDelimiterHandler.flatten(this, value, limit, Collections.newSetFromMap(new IdentityHashMap<>()));
    098    }
    099
    100    /**
    101     * Parses the specified value for list delimiters and splits it if necessary. The passed in object can be either a
    102     * single value or a complex one, for example a collection, an array, or an {@code Iterable}. It is the responsibility of this
    103     * method to return an {@code Iterable} which contains all extracted values.
    104     *
    105     * @param value the value to be parsed
    106     * @return an {@code Iterable} allowing access to all extracted values
    107     */
    108    Iterable<?> parse(Object value);
    109
    110    /**
    111     * Splits the specified string at the list delimiter and returns a collection with all extracted components. A concrete
    112     * implementation also has to deal with escape characters which might mask a list delimiter character at certain
    113     * positions. The boolean {@code trim} flag determines whether each extracted component should be trimmed. This
    114     * typically makes sense as the list delimiter may be surrounded by whitespace. However, there may be specific use cases
    115     * in which automatic trimming is not desired.
    116     *
    117     * @param s the string to be split
    118     * @param trim a flag whether each component of the string is to be trimmed
    119     * @return a collection with all components extracted from the string
    120     */
    121    Collection<String> split(String s, boolean trim);
    122
    123}