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