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.logging.log4j.util;
018
019import java.util.Iterator;
020import java.util.Locale;
021import java.util.Objects;
022
023/**
024 * <em>Consider this class private.</em>
025 * 
026 * @see <a href="http://commons.apache.org/proper/commons-lang/">Apache Commons Lang</a>
027 */
028public final class Strings {
029
030    private static final ThreadLocal<StringBuilder> tempStr = ThreadLocal.withInitial(StringBuilder::new);
031
032    /**
033     * The empty string.
034     */
035    public static final String EMPTY = "";
036    
037    /**
038     * The empty array.
039     */
040    public static final String[] EMPTY_ARRAY = {};
041    
042    /**
043     * OS-dependent line separator, defaults to {@code "\n"} if the system property {@code ""line.separator"} cannot be
044     * read.
045     */
046    public static final String LINE_SEPARATOR = PropertiesUtil.getProperties().getStringProperty("line.separator",
047            "\n");
048
049    /**
050     * Returns a double quoted string.
051     * 
052     * @param str a String
053     * @return {@code "str"}
054     */
055    public static String dquote(final String str) {
056        return Chars.DQUOTE + str + Chars.DQUOTE;
057    }
058    
059    /**
060     * Checks if a String is blank. A blank string is one that is either
061     * {@code null}, empty, or all characters are {@link Character#isWhitespace(char)}.
062     *
063     * @param s the String to check, may be {@code null}
064     * @return {@code true} if the String is {@code null}, empty, or or all characters are {@link Character#isWhitespace(char)}
065     */
066    public static boolean isBlank(final String s) {
067        if (s == null || s.isEmpty()) {
068            return true;
069        }
070        for (int i = 0; i < s.length(); i++) {
071            char c = s.charAt(i);
072            if (!Character.isWhitespace(c)) {
073                return false;
074            }
075        }
076        return true;
077    }
078
079    /**
080     * <p>
081     * Checks if a CharSequence is empty ("") or null.
082     * </p>
083     *
084     * <pre>
085     * Strings.isEmpty(null)      = true
086     * Strings.isEmpty("")        = true
087     * Strings.isEmpty(" ")       = false
088     * Strings.isEmpty("bob")     = false
089     * Strings.isEmpty("  bob  ") = false
090     * </pre>
091     *
092     * <p>
093     * NOTE: This method changed in Lang version 2.0. It no longer trims the CharSequence. That functionality is
094     * available in isBlank().
095     * </p>
096     *
097     * <p>
098     * Copied from Apache Commons Lang org.apache.commons.lang3.StringUtils.isEmpty(CharSequence)
099     * </p>
100     *
101     * @param cs the CharSequence to check, may be null
102     * @return {@code true} if the CharSequence is empty or null
103     */
104    public static boolean isEmpty(final CharSequence cs) {
105        return cs == null || cs.length() == 0;
106    }
107
108    /**
109     * Checks if a String is not blank. The opposite of {@link #isBlank(String)}.
110     *
111     * @param s the String to check, may be {@code null}
112     * @return {@code true} if the String is non-{@code null} and has content after being trimmed.
113     */
114    public static boolean isNotBlank(final String s) {
115        return !isBlank(s);
116    }
117
118    /**
119     * <p>
120     * Checks if a CharSequence is not empty ("") and not null.
121     * </p>
122     *
123     * <pre>
124     * Strings.isNotEmpty(null)      = false
125     * Strings.isNotEmpty("")        = false
126     * Strings.isNotEmpty(" ")       = true
127     * Strings.isNotEmpty("bob")     = true
128     * Strings.isNotEmpty("  bob  ") = true
129     * </pre>
130     *
131     * <p>
132     * Copied from Apache Commons Lang org.apache.commons.lang3.StringUtils.isNotEmpty(CharSequence)
133     * </p>
134     *
135     * @param cs the CharSequence to check, may be null
136     * @return {@code true} if the CharSequence is not empty and not null
137     */
138    public static boolean isNotEmpty(final CharSequence cs) {
139        return !isEmpty(cs);
140    }
141
142    /**
143     * <p>Joins the elements of the provided {@code Iterable} into
144     * a single String containing the provided elements.</p>
145     *
146     * <p>No delimiter is added before or after the list. Null objects or empty
147     * strings within the iteration are represented by empty strings.</p>
148     *
149     * @param iterable  the {@code Iterable} providing the values to join together, may be null
150     * @param separator  the separator character to use
151     * @return the joined String, {@code null} if null iterator input
152     */
153    public static String join(final Iterable<?> iterable, final char separator) {
154        if (iterable == null) {
155            return null;
156        }
157        return join(iterable.iterator(), separator);
158    }
159
160    /**
161     * <p>Joins the elements of the provided {@code Iterator} into
162     * a single String containing the provided elements.</p>
163     *
164     * <p>No delimiter is added before or after the list. Null objects or empty
165     * strings within the iteration are represented by empty strings.</p>
166     *
167     * @param iterator  the {@code Iterator} of values to join together, may be null
168     * @param separator  the separator character to use
169     * @return the joined String, {@code null} if null iterator input
170     */
171    public static String join(final Iterator<?> iterator, final char separator) {
172
173        // handle null, zero and one elements before building a buffer
174        if (iterator == null) {
175            return null;
176        }
177        if (!iterator.hasNext()) {
178            return EMPTY;
179        }
180        final Object first = iterator.next();
181        if (!iterator.hasNext()) {
182            return Objects.toString(first, EMPTY);
183        }
184
185        // two or more elements
186        final StringBuilder buf = new StringBuilder(256); // Java default is 16, probably too small
187        if (first != null) {
188            buf.append(first);
189        }
190
191        while (iterator.hasNext()) {
192            buf.append(separator);
193            final Object obj = iterator.next();
194            if (obj != null) {
195                buf.append(obj);
196            }
197        }
198
199        return buf.toString();
200    }
201
202    /**
203     * <p>Gets the leftmost {@code len} characters of a String.</p>
204     *
205     * <p>If {@code len} characters are not available, or the
206     * String is {@code null}, the String will be returned without
207     * an exception. An empty String is returned if len is negative.</p>
208     *
209     * <pre>
210     * StringUtils.left(null, *)    = null
211     * StringUtils.left(*, -ve)     = ""
212     * StringUtils.left("", *)      = ""
213     * StringUtils.left("abc", 0)   = ""
214     * StringUtils.left("abc", 2)   = "ab"
215     * StringUtils.left("abc", 4)   = "abc"
216     * </pre>
217     *
218     * <p>
219     * Copied from Apache Commons Lang org.apache.commons.lang3.StringUtils.
220     * </p>
221     * 
222     * @param str  the String to get the leftmost characters from, may be null
223     * @param len  the length of the required String
224     * @return the leftmost characters, {@code null} if null String input
225     */
226    public static String left(final String str, final int len) {
227        if (str == null) {
228            return null;
229        }
230        if (len < 0) {
231            return EMPTY;
232        }
233        if (str.length() <= len) {
234            return str;
235        }
236        return str.substring(0, len);
237    }
238
239    /**
240     * Returns a quoted string.
241     * 
242     * @param str a String
243     * @return {@code 'str'}
244     */
245    public static String quote(final String str) {
246        return Chars.QUOTE + str + Chars.QUOTE;
247    }
248    
249    /**
250     * <p>
251     * Removes control characters (char &lt;= 32) from both ends of this String returning {@code null} if the String is
252     * empty ("") after the trim or if it is {@code null}.
253     *
254     * <p>
255     * The String is trimmed using {@link String#trim()}. Trim removes start and end characters &lt;= 32.
256     * </p>
257     *
258     * <pre>
259     * Strings.trimToNull(null)          = null
260     * Strings.trimToNull("")            = null
261     * Strings.trimToNull("     ")       = null
262     * Strings.trimToNull("abc")         = "abc"
263     * Strings.trimToNull("    abc    ") = "abc"
264     * </pre>
265     *
266     * <p>
267     * Copied from Apache Commons Lang org.apache.commons.lang3.StringUtils.trimToNull(String)
268     * </p>
269     *
270     * @param str the String to be trimmed, may be null
271     * @return the trimmed String, {@code null} if only chars &lt;= 32, empty or null String input
272     */
273    public static String trimToNull(final String str) {
274        final String ts = str == null ? null : str.trim();
275        return isEmpty(ts) ? null : ts;
276    }
277
278    private Strings() {
279        // empty
280    }
281
282    /**
283     * Shorthand for {@code str.toUpperCase(Locale.ROOT);}
284     * @param str The string to upper case.
285     * @return a new string
286     * @see String#toLowerCase(Locale)
287     */
288    public static String toRootUpperCase(final String str) {
289        return str.toUpperCase(Locale.ROOT);
290    }
291
292    /**
293     * Concatenates 2 Strings without allocation.
294     * @param str1 the first string.
295     * @param str2 the second string.
296     * @return the concatenated String.
297     */
298    public static String concat(String str1, String str2) {
299        if (isEmpty(str1)) {
300            return str2;
301        } else if (isEmpty(str2)) {
302            return str1;
303        }
304        StringBuilder sb = tempStr.get();
305        try {
306            return sb.append(str1).append(str2).toString();
307        } finally {
308            sb.setLength(0);
309        }
310    }
311
312    /**
313     * Creates a new string repeating given {@code str} {@code count} times.
314     * @param str input string
315     * @param count the repetition count
316     * @return the new string
317     * @throws IllegalArgumentException if either {@code str} is null or {@code count} is negative
318     */
319    public static String repeat(final String str, final int count) {
320        Objects.requireNonNull(str, "str");
321        if (count < 0) {
322            throw new IllegalArgumentException("count");
323        }
324        StringBuilder sb = tempStr.get();
325        try {
326            for (int index = 0; index < count; index++) {
327                sb.append(str);
328            }
329            return sb.toString();
330        } finally {
331            sb.setLength(0);
332        }
333    }
334
335}