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