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