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 *     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 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.List;
021
022/**
023 * <p>
024 * Definition of an interface that controls the handling of list delimiters in
025 * configuration properties.
026 * </p>
027 * <p>
028 * {@link org.apache.commons.configuration2.AbstractConfiguration
029 * AbstractConfiguration} supports list delimiters in property values. If such a
030 * delimiter is found, the value actually contains multiple values and has to be
031 * split. This is useful for instance for
032 * {@link org.apache.commons.configuration2.PropertiesConfiguration
033 * PropertiesConfiguration}: properties files that have to be compatible with
034 * the {@code java.util.Properties} class cannot have multiple occurrences of a
035 * single property key, therefore a different storage scheme for multi-valued
036 * properties is needed. A possible storage scheme could look as follows:
037 * </p>
038 *
039 * <pre>
040 * myProperty=value1,value2,value3
041 * </pre>
042 *
043 * <p>
044 * Here a comma is used as list delimiter. When parsing this property (and using
045 * a corresponding {@code ListDelimiterHandler} implementation) the string value
046 * is split, and three values are added for the property key.
047 * </p>
048 * <p>
049 * A {@code ListDelimiterHandler} knows how to parse and to escape property
050 * values. It is called by concrete {@code Configuration} implementations when
051 * they have to deal with properties with multiple values.
052 * </p>
053 *
054 * @since 2.0
055 */
056public interface ListDelimiterHandler
057{
058    /**
059     * A specialized {@code ValueTransformer} implementation which does no
060     * transformation. The {@code transformValue()} method just returns the
061     * passed in object without changes. This instance can be used by
062     * configurations which do not require additional encoding.
063     */
064    ValueTransformer NOOP_TRANSFORMER = value -> value;
065
066    /**
067     * Parses the specified value for list delimiters and splits it if
068     * necessary. The passed in object can be either a single value or a complex
069     * one, e.g. a collection, an array, or an {@code Iterable}. It is the
070     * responsibility of this method to return an {@code Iterable} which
071     * contains all extracted values.
072     *
073     * @param value the value to be parsed
074     * @return an {@code Iterable} allowing access to all extracted values
075     */
076    Iterable<?> parse(Object value);
077
078    /**
079     * Splits the specified string at the list delimiter and returns a
080     * collection with all extracted components. A concrete implementation also
081     * has to deal with escape characters which might mask a list delimiter
082     * character at certain positions. The boolean {@code trim} flag determines
083     * whether each extracted component should be trimmed. This typically makes
084     * sense as the list delimiter may be surrounded by whitespace. However,
085     * there may be specific use cases in which automatic trimming is not
086     * desired.
087     *
088     * @param s the string to be split
089     * @param trim a flag whether each component of the string is to be trimmed
090     * @return a collection with all components extracted from the string
091     */
092    Collection<String> split(String s, boolean trim);
093
094    /**
095     * Escapes the specified single value object. This method is called for
096     * properties containing only a single value. So this method can rely on the
097     * fact that the passed in object is not a list. An implementation has to
098     * check whether the value contains list delimiter characters and - if so -
099     * escape them accordingly.
100     *
101     * @param value the value to be escaped
102     * @param transformer a {@code ValueTransformer} for an additional encoding
103     *        (must not be <b>null</b>)
104     * @return the escaped value
105     */
106    Object escape(Object value, ValueTransformer transformer);
107
108    /**
109     * Escapes all values in the given list and concatenates them to a single
110     * string. This operation is required by configurations that have to
111     * represent properties with multiple values in a single line in their
112     * external configuration representation. This may require an advanced
113     * escaping in some cases.
114     *
115     * @param values the list with all the values to be converted to a single
116     *        value
117     * @param transformer a {@code ValueTransformer} for an additional encoding
118     *        (must not be <b>null</b>)
119     * @return the resulting escaped value
120     */
121    Object escapeList(List<?> values, ValueTransformer transformer);
122}