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     */
017    package org.apache.camel.util;
018    
019    import static org.apache.camel.util.StringQuoteHelper.doubleQuote;
020    
021    /**
022     * Helper methods for working with Strings. 
023     */
024    public final class StringHelper {
025    
026        /**
027         * Constructor of utility class should be private.
028         */
029        private StringHelper() {
030        }
031        
032        /**
033         * Ensures that <code>s</code> is friendly for a URL or file system.
034         * 
035         * @param s String to be sanitized.
036         * @return sanitized version of <code>s</code>.
037         * @throws NullPointerException if <code>s</code> is <code>null</code>.
038         */
039        public static String sanitize(String s) {
040            return s
041                .replace(':', '-')
042                .replace('_', '-')
043                .replace('.', '-')
044                .replace('/', '-')
045                .replace('\\', '-');
046        }
047    
048        /**
049         * Counts the number of times the given char is in the string
050         *
051         * @param s  the string
052         * @param ch the char
053         * @return number of times char is located in the string
054         */
055        public static int countChar(String s, char ch) {
056            if (ObjectHelper.isEmpty(s)) {
057                return 0;
058            }
059    
060            int matches = 0;
061            for (int i = 0; i < s.length(); i++) {
062                char c = s.charAt(i);
063                if (ch == c) {
064                    matches++;
065                }
066            }
067    
068            return matches;
069        }
070    
071        public static String removeQuotes(String s) {
072            if (ObjectHelper.isEmpty(s)) {
073                return s;
074            }
075    
076            s = s.replaceAll("'", "");
077            s = s.replaceAll("\"", "");
078            return s;
079        }
080    
081        public static String removeLeadingAndEndingQuotes(String s) {
082            if (ObjectHelper.isEmpty(s)) {
083                return s;
084            }
085    
086            String copy = s.trim();
087            if (copy.startsWith("'") && copy.endsWith("'")) {
088                return copy.substring(1, copy.length() - 1);
089            }
090            if (copy.startsWith("\"") && copy.endsWith("\"")) {
091                return copy.substring(1, copy.length() - 1);
092            }
093    
094            // no quotes, so return as-is
095            return s;
096        }
097        
098        public static boolean isQuoted(String s) {
099            if (ObjectHelper.isEmpty(s)) {
100                return false;
101            }
102    
103            if (s.startsWith("'") && s.endsWith("'")) {
104                return true;
105            }
106            if (s.startsWith("\"") && s.endsWith("\"")) {
107                return true;
108            }
109    
110            return false;
111        }
112    
113        /**
114         * Encodes the text into safe XML by replacing < > and & with XML tokens
115         *
116         * @param text  the text
117         * @return the encoded text
118         */
119        public static String xmlEncode(String text) {
120            if (text == null) {
121                return "";
122            }
123            // must replace amp first, so we dont replace &lt; to amp later
124            return text.replaceAll("&", "&amp;").replaceAll("\"", "&quot;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
125        }
126    
127        /**
128         * Determines if the string has at least one letter in upper case
129         * @param text the text
130         * @return <tt>true</tt> if at least one letter is upper case, <tt>false</tt> otherwise
131         */
132        public static boolean hasUpperCase(String text) {
133            if (text == null) {
134                return false;
135            }
136    
137            for (int i = 0; i < text.length(); i++) {
138                char ch = text.charAt(i);
139                if (Character.isUpperCase(ch)) {
140                    return true;
141                }
142            }
143    
144            return false;
145        }
146    
147        /**
148         * Does the expression have the language start token?
149         *
150         * @param expression the expression
151         * @param language the name of the language, such as simple
152         * @return <tt>true</tt> if the expression contains the start token, <tt>false</tt> otherwise
153         */
154        public static boolean hasStartToken(String expression, String language) {
155            if (expression == null) {
156                return false;
157            }
158    
159            // for the simple language the expression start token could be "${"
160            if ("simple".equalsIgnoreCase(language) && expression.indexOf("${") >= 0) {
161                return true;
162            }
163    
164            if (language != null && expression.indexOf("$" + language + "{") >= 0) {
165                return true;
166            }
167    
168            return false;
169        }
170    
171        /**
172         * Replaces all the from tokens in the given input string.
173         * <p/>
174         * This implementation is not recursive, not does it check for tokens in the replacement string.
175         *
176         * @param input  the input string
177         * @param from   the from string, must <b>not</b> be <tt>null</tt> or empty
178         * @param to     the replacement string, must <b>not</b> be empty
179         * @return the replaced string, or the input string if no replacement was needed
180         * @throws IllegalArgumentException if the input arguments is invalid
181         */
182        public static String replaceAll(String input, String from, String to) {
183            if (ObjectHelper.isEmpty(input)) {
184                return input;
185            }
186            if (from == null) {
187                throw new IllegalArgumentException("from cannot be null");
188            }
189            if (to == null) {
190                // to can be empty, so only check for null
191                throw new IllegalArgumentException("to cannot be null");
192            }
193    
194            // fast check if there is any from at all
195            if (!input.contains(from)) {
196                return input;
197            }
198    
199            final int len = from.length();
200            final int max = input.length();
201            StringBuilder sb = new StringBuilder(max);
202            for (int i = 0; i < max;) {
203                if (i + len <= max) {
204                    String token = input.substring(i, i + len);
205                    if (from.equals(token)) {
206                        sb.append(to);
207                        // fast forward
208                        i = i + len;
209                        continue;
210                    }
211                }
212    
213                // append single char
214                sb.append(input.charAt(i));
215                // forward to next
216                i++;
217            }
218            return sb.toString();
219        }
220    
221        /**
222         * Creates a json tuple with the given name/value pair.
223         *
224         * @param name  the name
225         * @param value the value
226         * @param isMap whether the tuple should be map
227         * @return the json
228         */
229        public static String toJson(String name, String value, boolean isMap) {
230            if (isMap) {
231                return "{ " + doubleQuote(name) + ": " + doubleQuote(value) + " }";
232            } else {
233                return doubleQuote(name) + ": " + doubleQuote(value);
234            }
235        }
236    
237    }