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    /**
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}