    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.tree;
    018
    019import org.apache.commons.lang3.builder.EqualsBuilder;
    020import org.apache.commons.lang3.builder.HashCodeBuilder;
    021import org.apache.commons.lang3.builder.ToStringBuilder;
    022
    023/**
    024 * <p>
    025 * A class representing the various symbols that are supported in keys recognized by {@link DefaultExpressionEngine}.
    026 * </p>
    027 * <p>
    028 * An instance of this class is associated with each instance of {@code DefaultExpressionEngine}. It determines which
    029 * concrete symbols are used to define elements like separators, attributes, etc. within a configuration key.
    030 * </p>
    031 * <p>
    032 * Instances are created using the nested {@code Builder} class. They are immutable and can be shared between arbitrary
    033 * components.
    034 * </p>
    035 *
    036 * @since 2.0
    037 */
    038public final class DefaultExpressionEngineSymbols {
    039    /**
    040     * A builder class for creating instances of {@code DefaultExpressionEngineSymbols}.
    041     */
    042    public static class Builder {
    043        /** Stores the property delimiter. */
    044        private String propertyDelimiter;
    045
    046        /** Stores the escaped property delimiter. */
    047        private String escapedDelimiter;
    048
    049        /** Stores the attribute start marker. */
    050        private String attributeStart;
    051
    052        /** Stores the attribute end marker. */
    053        private String attributeEnd;
    054
    055        /** Stores the index start marker. */
    056        private String indexStart;
    057
    058        /** Stores the index end marker. */
    059        private String indexEnd;
    060
    061        /**
    062         * Creates a new, uninitialized instance of {@code Builder}. All symbols are undefined.
    063         */
    064        public Builder() {
    065        }
    066
    067        /**
    068         * Creates a new instance of {@code Builder} whose properties are initialized from the passed in
    069         * {@code DefaultExpressionEngineSymbols} object. This is useful if symbols are to be created which are similar to the
    070         * passed in instance.
    071         *
    072         * @param c the {@code DefaultExpressionEngineSymbols} object serving as starting point for this builder
    073         */
    074        public Builder(final DefaultExpressionEngineSymbols c) {
    075            propertyDelimiter = c.getPropertyDelimiter();
    076            escapedDelimiter = c.getEscapedDelimiter();
    077            indexStart = c.getIndexStart();
    078            indexEnd = c.getIndexEnd();
    079            attributeStart = c.getAttributeStart();
    080            attributeEnd = c.getAttributeEnd();
    081        }
    082
    083        /**
    084         * Creates the {@code DefaultExpressionEngineSymbols} instance based on the properties set for this builder object. This
    085         * method does not change the state of this builder. So it is possible to change properties and create another
    086         * {@code DefaultExpressionEngineSymbols} instance.
    087         *
    088         * @return the newly created {@code DefaultExpressionEngineSymbols} instance
    089         */
    090        public DefaultExpressionEngineSymbols create() {
    091            return new DefaultExpressionEngineSymbols(this);
    092        }
    093
    094        /**
    095         * Sets the string representing the end marker of an attribute in a property key.
    096         *
    097         * @param attributeEnd the attribute end marker
    098         * @return a reference to this object for method chaining
    099         */
    100        public Builder setAttributeEnd(final String attributeEnd) {
    101            this.attributeEnd = attributeEnd;
    102            return this;
    103        }
    104
    105        /**
    106         * Sets the string representing the start marker of an attribute in a property key. Attribute start and end marker are
    107         * used together to detect attributes in a property key.
    108         *
    109         * @param attributeStart the attribute start marker
    110         * @return a reference to this object for method chaining
    111         */
    112        public Builder setAttributeStart(final String attributeStart) {
    113            this.attributeStart = attributeStart;
    114            return this;
    115        }
    116
    117        /**
    118         * Sets the string representing an escaped property delimiter. With this string a delimiter that belongs to the key of a
    119         * property can be escaped. If for instance &quot;.&quot; is used as property delimiter, you can set the escaped
    120         * delimiter to &quot;\.&quot; and can then escape the delimiter with a back slash.
    121         *
    122         * @param escapedDelimiter the escaped property delimiter
    123         * @return a reference to this object for method chaining
    124         */
    125        public Builder setEscapedDelimiter(final String escapedDelimiter) {
    126            this.escapedDelimiter = escapedDelimiter;
    127            return this;
    128        }
    129
    130        /**
    131         * Sets the string representing the end of an index in a property key.
    132         *
    133         * @param indexEnd the index end
    134         * @return a reference to this object for method chaining
    135         */
    136        public Builder setIndexEnd(final String indexEnd) {
    137            this.indexEnd = indexEnd;
    138            return this;
    139        }
    140
    141        /**
    142         * Sets the string representing the start of an index in a property key. Index start and end marker are used together to
    143         * detect indices in a property key.
    144         *
    145         * @param is the index start
    146         * @return a reference to this object for method chaining
    147         */
    148        public Builder setIndexStart(final String is) {
    149            this.indexStart = is;
    150            return this;
    151        }
    152
    153        /**
    154         * Sets the string representing a delimiter for properties.
    155         *
    156         * @param propertyDelimiter the property delimiter
    157         * @return a reference to this object for method chaining
    158         */
    159        public Builder setPropertyDelimiter(final String propertyDelimiter) {
    160            this.propertyDelimiter = propertyDelimiter;
    161            return this;
    162        }
    163    }
    164
    165    /** Constant for the default property delimiter. */
    166    public static final String DEFAULT_PROPERTY_DELIMITER = ".";
    167
    168    /** Constant for the default escaped property delimiter. */
    169    public static final String DEFAULT_ESCAPED_DELIMITER = DEFAULT_PROPERTY_DELIMITER + DEFAULT_PROPERTY_DELIMITER;
    170
    171    /** Constant for the default attribute start marker. */
    172    public static final String DEFAULT_ATTRIBUTE_START = "[@";
    173
    174    /** Constant for the default attribute end marker. */
    175    public static final String DEFAULT_ATTRIBUTE_END = "]";
    176
    177    /** Constant for the default index start marker. */
    178    public static final String DEFAULT_INDEX_START = "(";
    179
    180    /** Constant for the default index end marker. */
    181    public static final String DEFAULT_INDEX_END = ")";
    182
    183    /**
    184     * An instance with default symbols. This instance is used by the default instance of {@code DefaultExpressionEngine}.
    185     */
    186    public static final DefaultExpressionEngineSymbols DEFAULT_SYMBOLS = createDefaultSmybols();
    187
    188    /**
    189     * Creates the {@code DefaultExpressionEngineSymbols} object with default symbols.
    190     *
    191     * @return the default symbols instance
    192     */
    193    private static DefaultExpressionEngineSymbols createDefaultSmybols() {
    194        return new Builder().setPropertyDelimiter(DEFAULT_PROPERTY_DELIMITER).setEscapedDelimiter(DEFAULT_ESCAPED_DELIMITER).setIndexStart(DEFAULT_INDEX_START)
    195            .setIndexEnd(DEFAULT_INDEX_END).setAttributeStart(DEFAULT_ATTRIBUTE_START).setAttributeEnd(DEFAULT_ATTRIBUTE_END).create();
    196    }
    197
    198    /** Stores the property delimiter. */
    199    private final String propertyDelimiter;
    200
    201    /** Stores the escaped property delimiter. */
    202    private final String escapedDelimiter;
    203
    204    /** Stores the attribute start marker. */
    205    private final String attributeStart;
    206
    207    /** Stores the attribute end marker. */
    208    private final String attributeEnd;
    209
    210    /** Stores the index start marker. */
    211    private final String indexStart;
    212
    213    /** Stores the index end marker. */
    214    private final String indexEnd;
    215
    216    /**
    217     * Creates a new instance of {@code DefaultExpressionEngineSymbols}.
    218     *
    219     * @param b the builder for defining the properties of this instance
    220     */
    221    private DefaultExpressionEngineSymbols(final Builder b) {
    222        propertyDelimiter = b.propertyDelimiter;
    223        escapedDelimiter = b.escapedDelimiter;
    224        indexStart = b.indexStart;
    225        indexEnd = b.indexEnd;
    226        attributeStart = b.attributeStart;
    227        attributeEnd = b.attributeEnd;
    228    }
    229
    230    /**
    231     * Compares this object with another one. Two instances of {@code DefaultExpressionEngineSymbols} are considered equal
    232     * if all of their properties are equal.
    233     *
    234     * @param obj the object to compare to
    235     * @return a flag whether these objects are equal
    236     */
    237    @Override
    238    public boolean equals(final Object obj) {
    239        if (this == obj) {
    240            return true;
    241        }
    242        if (!(obj instanceof DefaultExpressionEngineSymbols)) {
    243            return false;
    244        }
    245
    246        final DefaultExpressionEngineSymbols c = (DefaultExpressionEngineSymbols) obj;
    247        return new EqualsBuilder().append(getPropertyDelimiter(), c.getPropertyDelimiter()).append(getEscapedDelimiter(), c.getEscapedDelimiter())
    248            .append(getIndexStart(), c.getIndexStart()).append(getIndexEnd(), c.getIndexEnd()).append(getAttributeStart(), c.getAttributeStart())
    249            .append(getAttributeEnd(), c.getAttributeEnd()).isEquals();
    250    }
    251
    252    /**
    253     * Gets the string representing an attribute end marker.
    254     *
    255     * @return the attribute end marker
    256     */
    257    public String getAttributeEnd() {
    258        return attributeEnd;
    259    }
    260
    261    /**
    262     * Gets the string representing an attribute start marker.
    263     *
    264     * @return the attribute start marker
    265     */
    266    public String getAttributeStart() {
    267        return attributeStart;
    268    }
    269
    270    /**
    271     * Gets the string representing an escaped property delimiter.
    272     *
    273     * @return the escaped property delimiter
    274     */
    275    public String getEscapedDelimiter() {
    276        return escapedDelimiter;
    277    }
    278
    279    /**
    280     * Gets the string representing the end of an index in a property key.
    281     *
    282     * @return the index end marker
    283     */
    284    public String getIndexEnd() {
    285        return indexEnd;
    286    }
    287
    288    /**
    289     * Gets the string representing the start of an index in a property key.
    290     *
    291     * @return the index start marker
    292     */
    293    public String getIndexStart() {
    294        return indexStart;
    295    }
    296
    297    /**
    298     * Gets the string used as delimiter in property keys.
    299     *
    300     * @return the property delimiter
    301     */
    302    public String getPropertyDelimiter() {
    303        return propertyDelimiter;
    304    }
    305
    306    /**
    307     * Returns a hash code for this object.
    308     *
    309     * @return a hash code
    310     */
    311    @Override
    312    public int hashCode() {
    313        return new HashCodeBuilder().append(getPropertyDelimiter()).append(getEscapedDelimiter()).append(getIndexStart()).append(getIndexEnd())
    314            .append(getAttributeStart()).append(getAttributeEnd()).toHashCode();
    315    }
    316
    317    /**
    318     * Returns a string representation for this object. This string contains the values of all properties.
    319     *
    320     * @return a string for this object
    321     */
    322    @Override
    323    public String toString() {
    324        return new ToStringBuilder(this).append("propertyDelimiter", getPropertyDelimiter()).append("escapedDelimiter", getEscapedDelimiter())
    325            .append("indexStart", getIndexStart()).append("indexEnd", getIndexEnd()).append("attributeStart", getAttributeStart())
    326            .append("attributeEnd", getAttributeEnd()).toString();
    327    }
    328}