KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > riotfamily > common > util > FormatUtils


1 /* ***** BEGIN LICENSE BLOCK *****
2  * Version: MPL 1.1
3  * The contents of this file are subject to the Mozilla Public License Version
4  * 1.1 (the "License"); you may not use this file except in compliance with
5  * the License. You may obtain a copy of the License at
6  * http://www.mozilla.org/MPL/
7  *
8  * Software distributed under the License is distributed on an "AS IS" basis,
9  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
10  * for the specific language governing rights and limitations under the
11  * License.
12  *
13  * The Original Code is Riot.
14  *
15  * The Initial Developer of the Original Code is
16  * Neteye GmbH.
17  * Portions created by the Initial Developer are Copyright (C) 2006
18  * the Initial Developer. All Rights Reserved.
19  *
20  * Contributor(s):
21  * Felix Gnass [fgnass at neteye dot de]
22  *
23  * ***** END LICENSE BLOCK ***** */

24 package org.riotfamily.common.util;
25
26 import java.io.IOException JavaDoc;
27 import java.io.StringReader JavaDoc;
28 import java.io.UnsupportedEncodingException JavaDoc;
29 import java.net.URLDecoder JavaDoc;
30 import java.net.URLEncoder JavaDoc;
31 import java.text.DecimalFormat JavaDoc;
32 import java.text.NumberFormat JavaDoc;
33 import java.text.SimpleDateFormat JavaDoc;
34 import java.util.Calendar JavaDoc;
35 import java.util.Date JavaDoc;
36 import java.util.regex.Matcher JavaDoc;
37 import java.util.regex.Pattern JavaDoc;
38
39 import org.apache.commons.logging.Log;
40 import org.apache.commons.logging.LogFactory;
41 import org.springframework.util.ClassUtils;
42
43 /**
44  * Utility class that provides some simple text formatting methods.
45  */

46 public final class FormatUtils {
47
48     private static final Log log = LogFactory.getLog(FormatUtils.class);
49
50     private static NumberFormat JavaDoc numberFormat = new DecimalFormat JavaDoc("0.#");
51
52     private static SimpleDateFormat JavaDoc dateFormat = new SimpleDateFormat JavaDoc(
53             "yyyy-MM-dd HH:mm");
54
55     private static final String JavaDoc OP_ADDITION = "+";
56
57     private static final String JavaDoc OP_SUBTRACTION = "-";
58
59     private static final String JavaDoc ENTITY_LT = "<";
60
61     private static final String JavaDoc ENTITY_GT = ">";
62
63     private static final String JavaDoc ENTITY_AMP = "&";
64
65     private static final String JavaDoc ENTITY_QUOT = """;
66
67     private static final String JavaDoc BASE64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
68             "abcdefghijklmnopqrstuvwxyz0123456789+/=";
69
70     private FormatUtils() {
71     }
72
73     /**
74      * Returns a formatted string using an appropriate unit (Bytes, KB or MB).
75      */

76     public static String JavaDoc formatByteSize(long bytes) {
77         if (bytes < 1024) {
78             return numberFormat.format(bytes) + " Bytes";
79         }
80         float kb = (float) bytes / 1024;
81         if (kb < 1024) {
82             return numberFormat.format(kb) + " KB";
83         }
84         float mb = kb / 1024;
85         return numberFormat.format(mb) + " MB";
86     }
87
88     /**
89      * <pre>
90      * camelCase -> Camel Case
91      * CamelCASE -> Camel CASE
92      * Cam31Case -> Cam 31 Case
93      * </pre>
94      */

95     public static String JavaDoc camelToTitleCase(String JavaDoc s) {
96         if (s == null) {
97             return null;
98         }
99         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
100         char last = 0;
101         for (int i = 0; i < s.length(); i++) {
102             char c = s.charAt(i);
103             if (Character.isUpperCase(c) && last > 0 && !Character.isUpperCase(last)) {
104                 sb.append(' ');
105             }
106             else if (Character.isDigit(c) && last > 0 && !Character.isDigit(last)) {
107                 sb.append(' ');
108             }
109             if (i == 0) {
110                 c = Character.toUpperCase(c);
111             }
112             sb.append(c);
113             last = c;
114         }
115         return sb.toString();
116     }
117
118     /**
119      * <pre>
120      * foo-bar -> fooBar
121      * Foo-bAR -> FooBAR
122      * </pre>
123      */

124     public static String JavaDoc xmlToCamelCase(String JavaDoc s) {
125         StringBuffer JavaDoc sb = new StringBuffer JavaDoc(s);
126         int offset = 0;
127         int i;
128         while ((i = sb.indexOf("-", offset)) >= 0) {
129             sb.deleteCharAt(i);
130             sb.setCharAt(i, Character.toUpperCase(sb.charAt(i)));
131             offset = i;
132         }
133         return sb.toString();
134     }
135
136     /**
137      * <pre>
138      * foo-bar -> Foo Bar
139      * fooBar -> Foo Bar
140      * </pre>
141      */

142     public static String JavaDoc xmlToTitleCase(String JavaDoc s) {
143         return camelToTitleCase(xmlToCamelCase(s));
144     }
145
146     /**
147      * <pre>
148      * foo.bar -> Foo Bar
149      * foo.barBar -> Foo Bar Bar
150      * </pre>
151      */

152     public static String JavaDoc propertyToTitleCase(String JavaDoc s) {
153         if (s == null) {
154             return null;
155         }
156         return xmlToTitleCase(s.replace('.', '-'));
157     }
158
159     /**
160      * <pre>
161      * foo.bar -> Foo Bar
162      * foo-foo_bar -> Foo Foo Bar
163      * foo.barBar -> Foo Bar Bar
164      * </pre>
165      */

166     public static String JavaDoc fileNameToTitleCase(String JavaDoc s) {
167         if (s == null) {
168             return null;
169         }
170         return propertyToTitleCase(s.replace('_', '-'));
171     }
172
173     /**
174      * <pre>
175      * CamelCase -> camel-case
176      * camelCASE -> camel-case
177      * </pre>
178      */

179     public static String JavaDoc camelToXmlCase(String JavaDoc s) {
180         if (s == null) {
181             return null;
182         }
183         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
184         boolean lastWasLower = false;
185         for (int i = 0; i < s.length(); i++) {
186             char c = s.charAt(i);
187             if (Character.isUpperCase(c)) {
188                 if (lastWasLower) {
189                     sb.append('-');
190                 }
191                 c = Character.toLowerCase(c);
192             }
193             else {
194                 lastWasLower = true;
195             }
196             sb.append(c);
197         }
198         return sb.toString();
199     }
200
201     /**
202      * "a", "b", "c" -> "a b c a-b a-b-c"
203      * "a", "b", null -> "a b a-b"
204      */

205     public static String JavaDoc combine(String JavaDoc[] s) {
206         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
207         for (int i = 0; i < s.length; i++) {
208             if (s[i] != null) {
209                 sb.append(s[i]);
210                 if (i < s.length - 1 && s[i + 1] != null) {
211                     sb.append(' ');
212                 }
213             }
214         }
215         for (int j = 1; j < s.length; j++) {
216             if (s[j] != null) {
217                 sb.append(' ');
218                 for (int i = 0; i <= j; i++) {
219                     sb.append(s[i]);
220                     if (i < j && s[i + 1] != null) {
221                         sb.append('-');
222                     }
223                 }
224             }
225         }
226         return sb.toString();
227     }
228
229     /**
230      * Truncates the given String if its length exceeds the specified value.
231      * @since 6.4
232      */

233     public static String JavaDoc truncate(String JavaDoc s, int length) {
234         if (s == null || s.length() <= length) {
235             return s;
236         }
237         return s.substring(0, length);
238     }
239
240     /**
241      * Converts the given String into a valid CSS class name.
242      */

243     public static String JavaDoc toCssClass(String JavaDoc s) {
244         if (s == null) {
245             return null;
246         }
247         s = s.replaceAll("[.\\s/]", "-");
248         s = s.replaceAll("[^\\w-_]", "");
249         return s;
250     }
251
252     /**
253      * Parses a formatted String and returns the value in milliseconds. You can
254      * use one of the following suffixes:
255      *
256      * <pre>
257      * s - seconds
258      * m - minutes
259      * h - hours
260      * D - days
261      * W - weeks
262      * M - months
263      * Y - years
264      * </pre>
265      */

266     public static long parseMillis(String JavaDoc s) {
267         if (s == null) {
268             return 0;
269         }
270         long millis = 0;
271         int i = 0;
272         int length = s.length();
273         while (i < length) {
274             long delta = 0;
275             char ch = 0;
276             for (; i < length; i++) {
277                 ch = s.charAt(i);
278                 if (!Character.isDigit(ch)) {
279                     i++;
280                     break;
281                 }
282                 delta *= 10;
283                 delta += Character.getNumericValue(ch);
284             }
285             switch (ch) {
286             case 's':
287             case 'S':
288             default:
289                 millis += 1000 * delta;
290                 break;
291
292             case 'm':
293                 millis += 60 * 1000 * delta;
294                 break;
295
296             case 'h':
297             case 'H':
298                 millis += 60L * 60 * 1000 * delta;
299                 break;
300
301             case 'd':
302             case 'D':
303                 millis += 24L * 60 * 60 * 1000 * delta;
304                 break;
305
306             case 'w':
307             case 'W':
308                 millis += 7L * 24 * 60 * 60 * 1000 * delta;
309                 break;
310
311             case 'M':
312                 millis += 30L * 24 * 60 * 60 * 1000 * delta;
313                 break;
314
315             case 'y':
316             case 'Y':
317                 millis += 365L * 24 * 60 * 60 * 1000 * delta;
318                 break;
319             }
320         }
321         return millis;
322     }
323
324     /**
325      * Returns a formatted string using the pattern hh:mm:ss. The hours are
326      * omitted if they are zero, the minutes are padded with a '0' character
327      * if they are less than 10.
328      */

329     public static String JavaDoc formatMillis(long millis) {
330         int hours = (int) (millis / (1000 * 60 * 60));
331         int minutes = (int) (millis / (1000 * 60)) % 60;
332         int seconds = (int) (millis / 1000) % 60;
333         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
334         if (hours > 0) {
335             sb.append(hours);
336             sb.append(':');
337         }
338         if (minutes < 10 && hours > 0) {
339             sb.append(0);
340         }
341         sb.append(minutes);
342         sb.append(':');
343         if (seconds < 10) {
344             sb.append(0);
345         }
346         sb.append(seconds);
347         return sb.toString();
348     }
349
350     /**
351      * Returns the extension of the given filename. Examples:
352      *
353      * <pre>
354      * $quot;foo.bar&quot; - &quot;bar&quot;
355      * &quot;/some/file.name.foo&quot; - &quot;foo&quot;
356      * </pre>
357      *
358      * The following examples will return an empty String:
359      *
360      * <pre>
361      * &quot;foo&quot;
362      * &quot;foo.&quot;
363      * &quot;/dir.with.dots/file&quot;
364      * &quot;.bar&quot;
365      * &quot;/foo/.bar&quot;
366      * </pre>
367      */

368     public static String JavaDoc getExtension(String JavaDoc filename) {
369         if (filename == null) {
370             return "";
371         }
372         int i = filename.lastIndexOf('.');
373         if (i <= 0 || i == filename.length() - 1
374                 || filename.indexOf('/', i) != -1
375                 || filename.indexOf('\\', i) != -1) {
376
377             return "";
378         }
379         return filename.substring(i + 1);
380     }
381
382     /**
383      * Returns the the filename without it's extension.
384      */

385     public static String JavaDoc stripExtension(String JavaDoc filename) {
386         String JavaDoc extension = getExtension(filename);
387         return filename
388                 .substring(0, filename.length() - extension.length() - 1);
389     }
390
391     /**
392      * Parses a formatted String and returns the date. The date to parse starts
393      * with today. You can use one of the following sufixes:
394      *
395      * <pre>
396      *
397      * D - days
398      * W - weeks
399      * M - months
400      * Y - years
401      * </pre>
402      *
403      * Days is option, any number without a suffix is treated as a number of
404      * days
405      */

406     public static Date JavaDoc parseDate(String JavaDoc s) {
407         if (s.startsWith("today")) {
408             String JavaDoc op = null;
409             int days = 0;
410             int months = 0;
411             int years = 0;
412
413             s = s.substring(5);
414             int i = 0;
415             int length = s.length();
416             long delta = 0;
417             while (i < length) {
418
419                 char ch = 0;
420                 for (; i < length; i++) {
421                     ch = s.charAt(i);
422                     if (!Character.isDigit(ch)) {
423                         i++;
424                         break;
425                     }
426                     delta *= 10;
427                     delta += Character.getNumericValue(ch);
428                 }
429                 switch (ch) {
430                 case '+':
431                     op = OP_ADDITION;
432                     break;
433                 case '-':
434                     op = OP_SUBTRACTION;
435                     break;
436                 case 'd':
437                 case 'D':
438                     if (OP_ADDITION.equals(op)) {
439                         days += delta;
440                     }
441                     else if (OP_SUBTRACTION.equals(op)) {
442                         days -= delta;
443                     }
444                     op = null;
445                     delta = 0;
446                     break;
447
448                 case 'w':
449                 case 'W':
450                     if (OP_ADDITION.equals(op)) {
451                         days += 7 * delta;
452                     }
453                     else if (OP_SUBTRACTION.equals(op)) {
454                         days -= 7 * delta;
455                     }
456                     op = null;
457                     delta = 0;
458                     break;
459
460                 case 'M':
461                     if (OP_ADDITION.equals(op)) {
462                         months += delta;
463                     }
464                     else if (OP_SUBTRACTION.equals(op)) {
465                         months -= delta;
466                     }
467                     op = null;
468                     delta = 0;
469                     break;
470
471                 case 'y':
472                 case 'Y':
473                     if (OP_ADDITION.equals(op)) {
474                         years += delta;
475                     }
476                     else if (OP_SUBTRACTION.equals(op)) {
477                         years -= delta;
478                     }
479                     op = null;
480                     delta = 0;
481                     break;
482                 }
483                 if (delta > 0) {
484                     if (OP_ADDITION.equals(op)) {
485                         days += delta;
486                     }
487                     else if (OP_SUBTRACTION.equals(op)) {
488                         days -= delta;
489                     }
490                 }
491
492             }
493             Calendar JavaDoc c = Calendar.getInstance();
494             c.setTime(new Date JavaDoc());
495             c.add(Calendar.DATE, days);
496             c.add(Calendar.MONTH, months);
497             c.add(Calendar.YEAR, years);
498             return c.getTime();
499         }
500         return null;
501     }
502
503     public static String JavaDoc formatIsoDate(Date JavaDoc date) {
504         return dateFormat.format(date);
505     }
506
507     /**
508      * Invokes toLowerCase(), converts all whitespaces to underscores and
509      * removes all characters other than a-z, 0-9, dot, underscore or minus.
510      */

511     public static String JavaDoc toFilename(String JavaDoc s) {
512         s = s.toLowerCase();
513         s = s.replaceAll("\\s+", "_");
514         s = s.replaceAll("[^a-z_0-9.-]", "");
515         return s;
516     }
517
518     /**
519      * Turn special characters into escaped characters conforming to XML.
520      *
521      * @param input the input string
522      * @return the escaped string
523      */

524     public static String JavaDoc xmlEscape(String JavaDoc input) {
525         if (input == null) {
526             return input;
527         }
528         StringBuffer JavaDoc filtered = new StringBuffer JavaDoc(input.length() + 42);
529         char c;
530         for (int i = 0; i < input.length(); i++) {
531             c = input.charAt(i);
532             if (c == '<') {
533                 filtered.append(ENTITY_LT);
534             }
535             else if (c == '>') {
536                 filtered.append(ENTITY_GT);
537             }
538             else if (c == '&') {
539                 filtered.append(ENTITY_AMP);
540             }
541             else if (c == '"') {
542                 filtered.append(ENTITY_QUOT);
543             }
544             else {
545                 filtered.append(c);
546             }
547         }
548         return filtered.toString();
549     }
550
551     public static String JavaDoc escapeChars(String JavaDoc s, String JavaDoc chars, char escape) {
552         StringBuffer JavaDoc sb = new StringBuffer JavaDoc(s);
553         for (int i = 0; i < sb.length(); i++) {
554             if (chars.indexOf(sb.charAt(i)) != -1) {
555                 sb.insert(i, escape);
556                 i++;
557             }
558         }
559         return sb.toString();
560     }
561
562     public static String JavaDoc regexEscape(String JavaDoc s) {
563         return escapeChars(s, ".+*?{[^$", '\\');
564     }
565
566     /**
567      * Translates the given string into application/x-www-form-urlencoded
568      * format using UTF-8 as encoding scheme.
569      */

570     public static String JavaDoc uriEscape(String JavaDoc input) {
571         try {
572             return URLEncoder.encode(input, "UTF-8");
573         }
574         catch (UnsupportedEncodingException JavaDoc e) {
575             throw new IllegalStateException JavaDoc(e);
576         }
577     }
578
579     /**
580      * Decodes the given application/x-www-form-urlencoded string using
581      * UTF-8 as encoding scheme.
582      */

583     public static String JavaDoc uriUnescape(String JavaDoc input) {
584         try {
585             return URLDecoder.decode(input, "UTF-8");
586         }
587         catch (UnsupportedEncodingException JavaDoc e) {
588             throw new IllegalStateException JavaDoc(e);
589         }
590     }
591
592     /**
593      * Escapes all XML special characters in the given array. Dates and
594      * primitive-wrappers are left as-is, all other objects are converted to
595      * their String representation and escaped using
596      * {@link #xmlEscape(String)}.
597      * @since 6.4
598      */

599     public static Object JavaDoc[] htmlEscapeArgs(Object JavaDoc[] args) {
600         Object JavaDoc[] escapedArgs = new Object JavaDoc[args.length];
601         escapedArgs = new Object JavaDoc[args.length];
602         for (int i = 0; i < args.length; i++) {
603             Object JavaDoc arg = args[i];
604             if (arg instanceof String JavaDoc) {
605                 escapedArgs[i] = xmlEscape((String JavaDoc) arg);
606             }
607             else if (ClassUtils.isPrimitiveWrapper(arg.getClass())
608                     || arg instanceof Date JavaDoc) {
609
610                 escapedArgs[i] = arg;
611             }
612             else {
613                 escapedArgs[i] = xmlEscape(arg.toString());
614             }
615         }
616         return escapedArgs;
617     }
618
619     /**
620      * Extracts an integer from a String using the first capture group of the
621      * given regular expression.
622      * @since 6.4
623      */

624     public static int extractInt(String JavaDoc s, String JavaDoc regex) {
625         Pattern JavaDoc pattern = Pattern.compile(regex);
626         Matcher JavaDoc matcher = pattern.matcher(s);
627         if (matcher.find()) {
628             String JavaDoc group = matcher.group(1);
629             try {
630                 return Integer.parseInt(group);
631             }
632             catch (NumberFormatException JavaDoc e) {
633                 log.error("Not a valid number: " + group);
634             }
635         }
636         return -1;
637     }
638
639     public static String JavaDoc stripWhitespaces(String JavaDoc s) {
640         return stripWhitespaces(s, false);
641     }
642
643     public static String JavaDoc stripWhitespaces(String JavaDoc s, boolean preserveBreaks) {
644         StringReader JavaDoc in = new StringReader JavaDoc(s);
645         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
646         try {
647             boolean lineBreak = false;
648             boolean charsWritten = false;
649             int count = 0;
650             int i;
651             while ((i = in.read()) != -1) {
652                 char c = (char) i;
653                 if (Character.isWhitespace(c)) {
654                     if (charsWritten) {
655                         count++;
656                         if (preserveBreaks && c == '\n') {
657                             lineBreak = true;
658                         }
659                     }
660                 }
661                 else {
662                     if (count > 0) {
663                         sb.append(lineBreak ? '\n' : ' ');
664                         count = 0;
665                         lineBreak = false;
666                     }
667                     sb.append(c);
668                     charsWritten = true;
669                 }
670             }
671         }
672         catch (IOException JavaDoc e) {
673             // Should never happen since we are using a StringReader
674
}
675         finally {
676             in.close();
677         }
678         return sb.toString();
679     }
680
681     /**
682      * Decodes the given Base64 encoded String.
683      * @since 6.5
684      */

685     public static String JavaDoc decodeBase64(String JavaDoc s) {
686         if (s == null) {
687             return null;
688         }
689         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
690         int c1, c2, c3;
691         int e1, e2, e3, e4;
692         for (int i = 0; i < s.length();) {
693             e1 = BASE64.indexOf(s.charAt(i++));
694             e2 = BASE64.indexOf(s.charAt(i++));
695             e3 = BASE64.indexOf(s.charAt(i++));
696             e4 = BASE64.indexOf(s.charAt(i++));
697
698             c1 = (e1 << 2) | (e2 >> 4);
699             c2 = ((e2 & 15) << 4) | (e3 >> 2);
700             c3 = ((e3 & 3) << 6) | e4;
701
702             sb.append((char) c1);
703             if (e3 != 64) {
704                 sb.append((char) c2);
705             }
706             if (e4 != 64) {
707                 sb.append((char) c3);
708             }
709         }
710         return sb.toString();
711     }
712
713 }
714
Popular Tags