1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 package org.apache.axis2.util;
21
22 import java.text.Collator;
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.List;
26 import java.util.Locale;
27
28 /**
29 * JavaUtils
30 */
31 public class JavaUtils {
32 /**
33 * These are java keywords as specified at the following URL (sorted alphabetically).
34 * http://java.sun.com/docs/books/jls/second_edition/html/lexical.doc.html#229308
35 * Note that false, true, and null are not strictly keywords; they are literal values,
36 * but for the purposes of this array, they can be treated as literals.
37 * ****** PLEASE KEEP THIS LIST SORTED IN ASCENDING ORDER ******
38 */
39 static final String keywords[] =
40 {
41 "abstract", "assert", "boolean", "break", "byte", "case",
42 "catch", "char", "class", "const", "continue",
43 "default", "do", "double", "else", "extends",
44 "false", "final", "finally", "float", "for",
45 "goto", "if", "implements", "import", "instanceof",
46 "int", "interface", "long", "native", "new",
47 "null", "package", "private", "protected", "public",
48 "return", "short", "static", "strictfp", "super",
49 "switch", "synchronized", "this", "throw", "throws",
50 "transient", "true", "try", "void", "volatile",
51 "while"
52 };
53
54 /**
55 * Collator for comparing the strings
56 */
57 static final Collator englishCollator = Collator.getInstance(Locale.ENGLISH);
58
59 /**
60 * Use this character as suffix
61 */
62 static final char keywordPrefix = '_';
63
64 /**
65 * Is this an XML punctuation character?
66 */
67 private static boolean isPunctuation(char c) {
68 return '-' == c
69 || '.' == c
70 || ':' == c
71 || '\u00B7' == c
72 || '\u0387' == c
73 || '-' == c
74 || '\u06DD' == c
75 || '\u06DE' == c;
76 } // isPunctuation
77
78 /**
79 * Checks if the input string is a valid java keyword.
80 *
81 * @return Returns boolean.
82 */
83 public static boolean isJavaKeyword(String keyword) {
84 // None of the java keywords have uppercase characters
85 if (hasUpperCase(keyword)) {
86 return false;
87 }
88 return (Arrays.binarySearch(keywords, keyword, englishCollator) >= 0);
89 }
90
91 /**
92 * Check if the word has any uppercase letters
93 *
94 * @param word
95 * @return
96 */
97 public static boolean hasUpperCase(String word) {
98 if (word == null) {
99 return false;
100 }
101 int len = word.length();
102 for (int i = 0; i < len; i++) {
103 if (Character.isUpperCase(word.charAt(i))) {
104 return true;
105 }
106 }
107 return false;
108 }
109
110 /**
111 * Turns a java keyword string into a non-Java keyword string. (Right now
112 * this simply means appending an underscore.)
113 */
114 public static String makeNonJavaKeyword(String keyword) {
115 return keywordPrefix + keyword;
116 }
117
118 public static String xmlNameToJava(String name) {
119 // protect ourselves from garbage
120 if (name == null || name.length() == 0) {
121 return name;
122 }
123
124 char[] nameArray = name.toCharArray();
125 int nameLen = name.length();
126 StringBuffer result = new StringBuffer(nameLen);
127 boolean wordStart = false;
128
129 // The mapping indicates to convert first character.
130 int i = 0;
131 while (i < nameLen
132 && (isPunctuation(nameArray[i])
133 || !Character.isJavaIdentifierStart(nameArray[i]))) {
134 i++;
135 }
136 if (i < nameLen) {
137 // Decapitalization code used to be here, but we use the
138 // Introspector function now after we filter out all bad chars.
139
140 result.append(nameArray[i]);
141 //wordStart = !Character.isLetter(nameArray[i]);
142 wordStart = !Character.isLetter(nameArray[i]) && nameArray[i] != "_".charAt(0);
143 } else {
144 // The identifier cannot be mapped strictly according to
145 // JSR 101
146 if (Character.isJavaIdentifierPart(nameArray[0])) {
147 result.append("_").append(nameArray[0]);
148 } else {
149 // The XML identifier does not contain any characters
150 // we can map to Java. Using the length of the string
151 // will make it somewhat unique.
152 result.append("_").append(nameArray.length);
153 }
154 }
155
156 // The mapping indicates to skip over
157 // all characters that are not letters or
158 // digits. The first letter/digit
159 // following a skipped character is
160 // upper-cased.
161 for (++i; i < nameLen; ++i) {
162 char c = nameArray[i];
163
164 // if this is a bad char, skip it and remember to capitalize next
165 // good character we encounter
166 if (isPunctuation(c) || !Character.isJavaIdentifierPart(c)) {
167 wordStart = true;
168 continue;
169 }
170 if (wordStart && Character.isLowerCase(c)) {
171 result.append(Character.toUpperCase(c));
172 } else {
173 result.append(c);
174 }
175 // If c is not a character, but is a legal Java
176 // identifier character, capitalize the next character.
177 // For example: "22hi" becomes "22Hi"
178 //wordStart = !Character.isLetter(c);
179 wordStart = !Character.isLetter(c) && c != "_".charAt(0);
180 }
181
182 // covert back to a String
183 String newName = result.toString();
184
185 // check for Java keywords
186 if (isJavaKeyword(newName)) {
187 newName = makeNonJavaKeyword(newName);
188 }
189
190 return newName;
191 } // xmlNameToJava
192
193 /**
194 * Capitalizes the first character of the name.
195 *
196 * @param name
197 * @return Returns String.
198 */
199 public static String capitalizeFirstChar(String name) {
200
201 if ((name == null) || name.length() == 0) {
202 return name;
203 }
204
205 char start = name.charAt(0);
206
207 if (Character.isLowerCase(start)) {
208 start = Character.toUpperCase(start);
209
210 return start + name.substring(1);
211 }
212
213 return name;
214 } // capitalizeFirstChar
215
216 /**
217 * converts an xml name to a java identifier
218 *
219 * @param name
220 * @return java identifier
221 */
222
223 public static String xmlNameToJavaIdentifier(String name) {
224 String javaName = xmlNameToJava(name);
225 // convert the first letter to lowercase
226 if ((javaName != null) && (javaName.length() > 0)) {
227 javaName = javaName.substring(0, 1).toLowerCase() + javaName.substring(1);
228 }
229
230 return javaName;
231 }
232
233 /**
234 * Tests the String 'value':
235 * return 'false' if its 'false', '0', or 'no' - else 'true'
236 * <p/>
237 * Follow in 'C' tradition of boolean values:
238 * false is specific (0), everything else is true;
239 */
240 public static boolean isTrue(String value) {
241 return !isFalseExplicitly(value);
242 }
243
244 /**
245 * Tests the String 'value':
246 * return 'true' if its 'true', '1', or 'yes' - else 'false'
247 */
248 public static boolean isTrueExplicitly(String value) {
249 return value != null &&
250 (value.equalsIgnoreCase("true") ||
251 value.equals("1") ||
252 value.equalsIgnoreCase("yes"));
253 }
254
255 /**
256 * Tests the Object 'value':
257 * if its null, return default.
258 * if its a Boolean, return booleanValue()
259 * if its an Integer, return 'false' if its '0' else 'true'
260 * if its a String, return isTrueExplicitly((String)value).
261 * All other types return 'true'
262 */
263 public static boolean isTrueExplicitly(Object value, boolean defaultVal) {
264 if (value == null) {
265 return defaultVal;
266 }
267 if (value instanceof Boolean) {
268 return ((Boolean) value).booleanValue();
269 }
270 if (value instanceof Integer) {
271 return ((Integer) value).intValue() != 0;
272 }
273 if (value instanceof String) {
274 return isTrueExplicitly((String) value);
275 }
276 return defaultVal;
277 }
278
279 public static boolean isTrueExplicitly(Object value) {
280 return isTrueExplicitly(value, false);
281 }
282
283 /**
284 * Tests the Object 'value':
285 * if its null, return default.
286 * if its a Boolean, return booleanValue()
287 * if its an Integer, return 'false' if its '0' else 'true'
288 * if its a String, return 'false' if its 'false', 'no', or '0' - else 'true'
289 * All other types return 'true'
290 */
291 public static boolean isTrue(Object value, boolean defaultVal) {
292 return !isFalseExplicitly(value, !defaultVal);
293 }
294
295 public static boolean isTrue(Object value) {
296 return isTrue(value, false);
297 }
298
299 /**
300 * Tests the String 'value':
301 * return 'true' if its 'false', '0', or 'no' - else 'false'
302 * <p/>
303 * Follow in 'C' tradition of boolean values:
304 * false is specific (0), everything else is true;
305 */
306 public static boolean isFalse(String value) {
307 return isFalseExplicitly(value);
308 }
309
310 /**
311 * Tests the String 'value':
312 * return 'true' if its null, 'false', '0', or 'no' - else 'false'
313 */
314 public static boolean isFalseExplicitly(String value) {
315 return value == null ||
316 value.equalsIgnoreCase("false") ||
317 value.equals("0") ||
318 value.equalsIgnoreCase("no");
319 }
320
321 /**
322 * Tests the Object 'value':
323 * if its null, return default.
324 * if its a Boolean, return !booleanValue()
325 * if its an Integer, return 'true' if its '0' else 'false'
326 * if its a String, return isFalseExplicitly((String)value).
327 * All other types return 'false'
328 */
329 public static boolean isFalseExplicitly(Object value, boolean defaultVal) {
330 if (value == null) {
331 return defaultVal;
332 }
333 if (value instanceof Boolean) {
334 return !((Boolean) value).booleanValue();
335 }
336 if (value instanceof Integer) {
337 return ((Integer) value).intValue() == 0;
338 }
339 if (value instanceof String) {
340 return isFalseExplicitly((String) value);
341 }
342 return false;
343 }
344
345 public static boolean isFalseExplicitly(Object value) {
346 return isFalseExplicitly(value, true);
347 }
348
349 /**
350 * Tests the Object 'value':
351 * if its null, return default.
352 * if its a Boolean, return booleanValue()
353 * if its an Integer, return 'false' if its '0' else 'true'
354 * if its a String, return 'false' if its 'false', 'no', or '0' - else 'true'
355 * All other types return 'true'
356 */
357 public static boolean isFalse(Object value, boolean defaultVal) {
358 return isFalseExplicitly(value, defaultVal);
359 }
360
361 public static boolean isFalse(Object value) {
362 return isFalse(value, true);
363 }
364
365 public static boolean isJavaId(String id) {
366 if (id == null || id.length() == 0 || isJavaKeyword(id)) {
367 return false;
368 }
369 if (!Character.isJavaIdentifierStart(id.charAt(0))) {
370 return false;
371 }
372 for (int i = 1; i < id.length(); i++) {
373 if (!Character.isJavaIdentifierPart(id.charAt(i))) {
374 return false;
375 }
376 }
377 return true;
378 }
379
380 /**
381 * An empty immutable <code>String</code> array.
382 */
383 public static final String[] EMPTY_STRING_ARRAY = new String[0];
384
385 /**
386 * <p>Splits the provided text into an array, separator specified.
387 * This is an alternative to using StringTokenizer.</p>
388 * <p/>
389 * <p>The separator is not included in the returned String array.
390 * Adjacent separators are treated as one separator.</p>
391 * <p/>
392 * <p>A <code>null</code> input String returns <code>null</code>.</p>
393 * <p/>
394 * <pre>
395 * StringUtils.split(null, *) = null
396 * StringUtils.split("", *) = []
397 * StringUtils.split("a.b.c", '.') = ["a", "b", "c"]
398 * StringUtils.split("a..b.c", '.') = ["a", "b", "c"]
399 * StringUtils.split("a:b:c", '.') = ["a:b:c"]
400 * StringUtils.split("a\tb\nc", null) = ["a", "b", "c"]
401 * StringUtils.split("a b c", ' ') = ["a", "b", "c"]
402 * </pre>
403 *
404 * @param str the String to parse, may be null
405 * @param separatorChar the character used as the delimiter,
406 * <code>null</code> splits on whitespace
407 * @return an array of parsed Strings, <code>null</code> if null String input
408 */
409 public static String[] split(String str, char separatorChar) {
410 if (str == null) {
411 return null;
412 }
413 int len = str.length();
414 if (len == 0) {
415 return EMPTY_STRING_ARRAY;
416 }
417 List list = new ArrayList();
418 int i = 0, start = 0;
419 boolean match = false;
420 while (i < len) {
421 if (str.charAt(i) == separatorChar) {
422 if (match) {
423 list.add(str.substring(start, i));
424 match = false;
425 }
426 start = ++i;
427 continue;
428 }
429 match = true;
430 i++;
431 }
432 if (match) {
433 list.add(str.substring(start, i));
434 }
435 return (String[]) list.toArray(new String[list.size()]);
436 }
437
438 public static Class getWrapperClass(Class primitive) {
439 if (primitive == int.class) {
440 return java.lang.Integer.class;
441 } else if (primitive == short.class) {
442 return java.lang.Short.class;
443 } else if (primitive == boolean.class) {
444 return java.lang.Boolean.class;
445 } else if (primitive == byte.class) {
446 return java.lang.Byte.class;
447 } else if (primitive == long.class) {
448 return java.lang.Long.class;
449 } else if (primitive == double.class) {
450 return java.lang.Double.class;
451 } else if (primitive == float.class) {
452 return java.lang.Float.class;
453 } else if (primitive == char.class) {
454 return java.lang.Character.class;
455 }
456
457 return null;
458 }
459
460 public static Class getWrapperClass(String primitive) {
461 if (primitive.equals("int")) {
462 return java.lang.Integer.class;
463 } else if (primitive.equals("short")) {
464 return java.lang.Short.class;
465 } else if (primitive.equals("boolean")) {
466 return java.lang.Boolean.class;
467 } else if (primitive.equals("byte")) {
468 return java.lang.Byte.class;
469 } else if (primitive.equals("long")) {
470 return java.lang.Long.class;
471 } else if (primitive.equals("double")) {
472 return java.lang.Double.class;
473 } else if (primitive.equals("float")) {
474 return java.lang.Float.class;
475 } else if (primitive.equals("char")) {
476 return java.lang.Character.class;
477 }
478
479 return null;
480 }
481
482 /**
483 * Scans the parameter string for the parameter search ignoring case when
484 * comparing characters.
485 *
486 * @param string
487 * @param search If test is empty -1 is always returned.
488 * @return -1 if the string was not found or the index of the first matching
489 * character
490 */
491 public static int indexOfIgnoreCase(final String string,
492 final String search) {
493 int index = -1;
494 final int stringLength = string.length();
495 final int testLength = search.length();
496 if (stringLength > 1 || testLength > 1) {
497 final char firstCharOfTest = Character.toLowerCase(search.charAt(0));
498 final int lastStringCharacterToCheck = stringLength - testLength + 1;
499
500 for (int i = 0; i < lastStringCharacterToCheck; i++) {
501 if (firstCharOfTest == Character.toLowerCase(string.charAt(i))) {
502 index = i;
503 for (int j = 1; j < testLength; j++) {
504 final char c = string.charAt(i + j);
505 final char otherChar = search.charAt(j);
506 if (Character.toLowerCase(c) != Character.toLowerCase(otherChar)) {
507 index = -1;
508 break;
509 }
510 }
511 if (-1 != index) {
512 break;
513 }
514 }
515 }
516 }
517 return index;
518 }
519
520 /**
521 * replace: Like String.replace except that the old new items are strings.
522 *
523 * @param name string
524 * @param oldT old text to replace
525 * @param newT new text to use
526 * @return replacement string
527 */
528 public static final String replace(String name,
529 String oldT, String newT) {
530
531 if (name == null) return "";
532
533 // Create a string buffer that is twice initial length.
534 // This is a good starting point.
535 StringBuffer sb = new StringBuffer(name.length() * 2);
536
537 int len = oldT.length();
538 try {
539 int start = 0;
540 int i = name.indexOf(oldT, start);
541
542 while (i >= 0) {
543 sb.append(name.substring(start, i));
544 sb.append(newT);
545 start = i + len;
546 i = name.indexOf(oldT, start);
547 }
548 if (start < name.length())
549 sb.append(name.substring(start));
550 } catch (NullPointerException e) {
551 // No FFDC code needed
552 }
553
554 return new String(sb);
555 }
556 /**
557 * Get a string containing the stack of the current location.
558 * Note This utility is useful in debug scenarios to dump out
559 * the call stack.
560 *
561 * @return String
562 */
563 public static String callStackToString() {
564 return stackToString(new RuntimeException());
565 }
566
567 /**
568 * Get a string containing the stack of the specified exception
569 *
570 * @param e
571 * @return
572 */
573 public static String stackToString(Throwable e) {
574 java.io.StringWriter sw = new java.io.StringWriter();
575 java.io.BufferedWriter bw = new java.io.BufferedWriter(sw);
576 java.io.PrintWriter pw = new java.io.PrintWriter(bw);
577 e.printStackTrace(pw);
578 pw.close();
579 String text = sw.getBuffer().toString();
580 // Jump past the throwable
581 text = text.substring(text.indexOf("at"));
582 text = replace(text, "at ", "DEBUG_FRAME = ");
583 return text;
584 }
585 }