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}