1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache license, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the license for the specific language governing permissions and
15  * limitations under the license.
16  */

17 package org.apache.logging.log4j.util;
18
19 import java.util.Iterator;
20 import java.util.Locale;
21 import java.util.Objects;
22
23 /**
24  * <em>Consider this class private.</em>
25  * 
26  * @see <a href="http://commons.apache.org/proper/commons-lang/">Apache Commons Lang</a>
27  */

28 public final class Strings {
29
30     private static final ThreadLocal<StringBuilder> tempStr = ThreadLocal.withInitial(StringBuilder::new);
31
32     /**
33      * The empty string.
34      */

35     public static final String EMPTY = "";
36     private static final String COMMA_DELIMITED_RE = "\\s*,\\s*";
37     
38     /**
39      * The empty array.
40      */

41     public static final String[] EMPTY_ARRAY = {};
42     
43     /**
44      * OS-dependent line separator, defaults to {@code "\n"if the system property {@code ""line.separator"} cannot be
45      * read.
46      */

47     public static final String LINE_SEPARATOR = PropertiesUtil.getProperties().getStringProperty("line.separator",
48             "\n");
49
50     /**
51      * Returns a double quoted string.
52      * 
53      * @param str a String
54      * @return {@code "str"}
55      */

56     public static String dquote(final String str) {
57         return Chars.DQUOTE + str + Chars.DQUOTE;
58     }
59     
60     /**
61      * Checks if a String is blank. A blank string is one that is either
62      * {@code null}, empty, or all characters are {@link Character#isWhitespace(char)}.
63      *
64      * @param s the String to check, may be {@code null}
65      * @return {@code trueif the String is {@code null}, empty, or or all characters are {@link Character#isWhitespace(char)}
66      */

67     public static boolean isBlank(final String s) {
68         if (s == null || s.isEmpty()) {
69             return true;
70         }
71         for (int i = 0; i < s.length(); i++) {
72             char c = s.charAt(i);
73             if (!Character.isWhitespace(c)) {
74                 return false;
75             }
76         }
77         return true;
78     }
79
80     /**
81      * <p>
82      * Checks if a CharSequence is empty ("") or null.
83      * </p>
84      *
85      * <pre>
86      * Strings.isEmpty(null)      = true
87      * Strings.isEmpty("")        = true
88      * Strings.isEmpty(" ")       = false
89      * Strings.isEmpty("bob")     = false
90      * Strings.isEmpty("  bob  ") = false
91      * </pre>
92      *
93      * <p>
94      * NOTE: This method changed in Lang version 2.0. It no longer trims the CharSequence. That functionality is
95      * available in isBlank().
96      * </p>
97      *
98      * <p>
99      * Copied from Apache Commons Lang org.apache.commons.lang3.StringUtils.isEmpty(CharSequence)
100      * </p>
101      *
102      * @param cs the CharSequence to check, may be null
103      * @return {@code trueif the CharSequence is empty or null
104      */

105     public static boolean isEmpty(final CharSequence cs) {
106         return cs == null || cs.length() == 0;
107     }
108
109     /**
110      * Checks if a String is not blank. The opposite of {@link #isBlank(String)}.
111      *
112      * @param s the String to check, may be {@code null}
113      * @return {@code trueif the String is non-{@code null} and has content after being trimmed.
114      */

115     public static boolean isNotBlank(final String s) {
116         return !isBlank(s);
117     }
118
119     /**
120      * <p>
121      * Checks if a CharSequence is not empty ("") and not null.
122      * </p>
123      *
124      * <pre>
125      * Strings.isNotEmpty(null)      = false
126      * Strings.isNotEmpty("")        = false
127      * Strings.isNotEmpty(" ")       = true
128      * Strings.isNotEmpty("bob")     = true
129      * Strings.isNotEmpty("  bob  ") = true
130      * </pre>
131      *
132      * <p>
133      * Copied from Apache Commons Lang org.apache.commons.lang3.StringUtils.isNotEmpty(CharSequence)
134      * </p>
135      *
136      * @param cs the CharSequence to check, may be null
137      * @return {@code trueif the CharSequence is not empty and not null
138      */

139     public static boolean isNotEmpty(final CharSequence cs) {
140         return !isEmpty(cs);
141     }
142
143     /**
144      * <p>Joins the elements of the provided {@code Iterable} into
145      * a single String containing the provided elements.</p>
146      *
147      * <p>No delimiter is added before or after the list. Null objects or empty
148      * strings within the iteration are represented by empty strings.</p>
149      *
150      * @param iterable  the {@code Iterable} providing the values to join together, may be null
151      * @param separator  the separator character to use
152      * @return the joined String, {@code nullif null iterator input
153      */

154     public static String join(final Iterable<?> iterable, final char separator) {
155         if (iterable == null) {
156             return null;
157         }
158         return join(iterable.iterator(), separator);
159     }
160
161     /**
162      * <p>Joins the elements of the provided {@code Iterator} into
163      * a single String containing the provided elements.</p>
164      *
165      * <p>No delimiter is added before or after the list. Null objects or empty
166      * strings within the iteration are represented by empty strings.</p>
167      *
168      * @param iterator  the {@code Iterator} of values to join together, may be null
169      * @param separator  the separator character to use
170      * @return the joined String, {@code nullif null iterator input
171      */

172     public static String join(final Iterator<?> iterator, final char separator) {
173
174         // handle null, zero and one elements before building a buffer
175         if (iterator == null) {
176             return null;
177         }
178         if (!iterator.hasNext()) {
179             return EMPTY;
180         }
181         final Object first = iterator.next();
182         if (!iterator.hasNext()) {
183             return Objects.toString(first, EMPTY);
184         }
185
186         // two or more elements
187         final StringBuilder buf = new StringBuilder(256); // Java default is 16, probably too small
188         if (first != null) {
189             buf.append(first);
190         }
191
192         while (iterator.hasNext()) {
193             buf.append(separator);
194             final Object obj = iterator.next();
195             if (obj != null) {
196                 buf.append(obj);
197             }
198         }
199
200         return buf.toString();
201     }
202
203     public static String[] splitList(String string) {
204         return string != null ? string.split(COMMA_DELIMITED_RE) : new String[0];
205     }
206
207     /**
208      * <p>Gets the leftmost {@code len} characters of a String.</p>
209      *
210      * <p>If {@code len} characters are not available, or the
211      * String is {@code null}, the String will be returned without
212      * an exception. An empty String is returned if len is negative.</p>
213      *
214      * <pre>
215      * StringUtils.left(null, *)    = null
216      * StringUtils.left(*, -ve)     = ""
217      * StringUtils.left("", *)      = ""
218      * StringUtils.left("abc", 0)   = ""
219      * StringUtils.left("abc", 2)   = "ab"
220      * StringUtils.left("abc", 4)   = "abc"
221      * </pre>
222      *
223      * <p>
224      * Copied from Apache Commons Lang org.apache.commons.lang3.StringUtils.
225      * </p>
226      * 
227      * @param str  the String to get the leftmost characters from, may be null
228      * @param len  the length of the required String
229      * @return the leftmost characters, {@code nullif null String input
230      */

231     public static String left(final String str, final int len) {
232         if (str == null) {
233             return null;
234         }
235         if (len < 0) {
236             return EMPTY;
237         }
238         if (str.length() <= len) {
239             return str;
240         }
241         return str.substring(0, len);
242     }
243
244     /**
245      * Returns a quoted string.
246      * 
247      * @param str a String
248      * @return {@code 'str'}
249      */

250     public static String quote(final String str) {
251         return Chars.QUOTE + str + Chars.QUOTE;
252     }
253     
254     /**
255      * <p>
256      * Removes control characters (char &lt;= 32) from both ends of this String returning {@code nullif the String is
257      * empty ("") after the trim or if it is {@code null}.
258      *
259      * <p>
260      * The String is trimmed using {@link String#trim()}. Trim removes start and end characters &lt;= 32.
261      * </p>
262      *
263      * <pre>
264      * Strings.trimToNull(null)          = null
265      * Strings.trimToNull("")            = null
266      * Strings.trimToNull("     ")       = null
267      * Strings.trimToNull("abc")         = "abc"
268      * Strings.trimToNull("    abc    ") = "abc"
269      * </pre>
270      *
271      * <p>
272      * Copied from Apache Commons Lang org.apache.commons.lang3.StringUtils.trimToNull(String)
273      * </p>
274      *
275      * @param str the String to be trimmed, may be null
276      * @return the trimmed String, {@code nullif only chars &lt;= 32, empty or null String input
277      */

278     public static String trimToNull(final String str) {
279         final String ts = str == null ? null : str.trim();
280         return isEmpty(ts) ? null : ts;
281     }
282
283     private Strings() {
284         // empty
285     }
286
287     /**
288      * Shorthand for {@code str.toLowerCase(Locale.ROOT);}
289      * @param str The string to upper case.
290      * @return a new string
291      * @see String#toLowerCase(Locale)
292      */

293     public static String toRootLowerCase(final String str) {
294         return str.toLowerCase(Locale.ROOT);
295     }
296
297     /**
298      * Shorthand for {@code str.toUpperCase(Locale.ROOT);}
299      * @param str The string to lower case.
300      * @return a new string
301      * @see String#toLowerCase(Locale)
302      */

303     public static String toRootUpperCase(final String str) {
304         return str.toUpperCase(Locale.ROOT);
305     }
306
307     /**
308      * Concatenates 2 Strings without allocation.
309      * @param str1 the first string.
310      * @param str2 the second string.
311      * @return the concatenated String.
312      */

313     public static String concat(String str1, String str2) {
314         if (isEmpty(str1)) {
315             return str2;
316         } else if (isEmpty(str2)) {
317             return str1;
318         }
319         StringBuilder sb = tempStr.get();
320         try {
321             return sb.append(str1).append(str2).toString();
322         } finally {
323             sb.setLength(0);
324         }
325     }
326
327     /**
328      * Creates a new string repeating given {@code str} {@code count} times.
329      * @param str input string
330      * @param count the repetition count
331      * @return the new string
332      * @throws IllegalArgumentException if either {@code str} is null or {@code count} is negative
333      */

334     public static String repeat(final String str, final int count) {
335         Objects.requireNonNull(str, "str");
336         if (count < 0) {
337             throw new IllegalArgumentException("count");
338         }
339         StringBuilder sb = tempStr.get();
340         try {
341             for (int index = 0; index < count; index++) {
342                 sb.append(str);
343             }
344             return sb.toString();
345         } finally {
346             sb.setLength(0);
347         }
348     }
349
350 }
351