KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > blojsom > util > BlojsomUtils


1 /**
2  * Copyright (c) 2003-2006, David A. Czarnecki
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * Redistributions of source code must retain the above copyright notice, this list of conditions and the
9  * following disclaimer.
10  * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
11  * following disclaimer in the documentation and/or other materials provided with the distribution.
12  * Neither the name of "David A. Czarnecki" and "blojsom" nor the names of its contributors may be used to
13  * endorse or promote products derived from this software without specific prior written permission.
14  * Products derived from this software may not be called "blojsom", nor may "blojsom" appear in their name,
15  * without prior written permission of David A. Czarnecki.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
18  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
19  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
21  * EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */

31 package org.blojsom.util;
32
33 import org.blojsom.blog.Blog;
34 import org.blojsom.blog.Response;
35
36 import javax.servlet.http.HttpServletRequest JavaDoc;
37 import javax.servlet.http.HttpServletResponse JavaDoc;
38 import java.io.*;
39 import java.net.URLDecoder JavaDoc;
40 import java.net.URLEncoder JavaDoc;
41 import java.nio.ByteBuffer JavaDoc;
42 import java.nio.channels.FileChannel JavaDoc;
43 import java.security.MessageDigest JavaDoc;
44 import java.security.NoSuchAlgorithmException JavaDoc;
45 import java.text.Collator JavaDoc;
46 import java.text.SimpleDateFormat JavaDoc;
47 import java.util.*;
48 import java.util.regex.Pattern JavaDoc;
49 import java.util.regex.Matcher JavaDoc;
50
51 /**
52  * BlojsomUtils
53  *
54  * @author David Czarnecki
55  * @since blojsom 3.0
56  * @version $Id: BlojsomUtils.java,v 1.11 2006/09/09 18:37:02 czarneckid Exp $
57  */

58 public class BlojsomUtils implements BlojsomConstants {
59
60     private static final int REGEX_OPTIONS = Pattern.DOTALL | Pattern.CASE_INSENSITIVE;
61     private static final Pattern JavaDoc STRIP_HTML_PATTERN = Pattern.compile("^[^<>]*>|<.*?>|<[^<>]*$", REGEX_OPTIONS);
62
63     /**
64      * Private constructor so that the class cannot be instantiated.
65      */

66     private BlojsomUtils() {
67     }
68
69     /**
70      * Filter only directories
71      */

72     private static final FileFilter DIRECTORY_FILTER = new FileFilter() {
73
74         /**
75          * Tests whether or not the specified abstract pathname should be
76          * included in a pathname list.
77          *
78          * @param pathname The abstract pathname to be tested
79          * @return <code>true</code> if and only if <code>pathname</code>
80          * should be included
81          */

82         public boolean accept(File pathname) {
83             return (pathname.isDirectory());
84         }
85     };
86
87     /**
88      * Filter only files
89      */

90     private static final FileFilter FILE_FILTER = new FileFilter() {
91
92         /**
93          * Tests whether or not the specified abstract pathname should be
94          * included in a pathname list.
95          *
96          * @param pathname The abstract pathname to be tested
97          * @return <code>true</code> if and only if <code>pathname</code>
98          * should be included
99          */

100         public boolean accept(File pathname) {
101             return (!pathname.isDirectory());
102         }
103     };
104
105     /**
106      * RFC-822 format
107      * SimpleDateFormats are not threadsafe, but we should not need more than one per
108      * thread.
109      */

110     private static final ThreadLocal JavaDoc RFC_822_DATE_FORMAT_OBJECT = new ThreadLocal JavaDoc() {
111         protected Object JavaDoc initialValue() {
112             return new SimpleDateFormat JavaDoc(RFC_822_DATE_FORMAT, Locale.US);
113         }
114     };
115
116     /**
117      * ISO-8601 format
118      * SimpleDateFormats are not threadsafe, but we should not need more than one per
119      * thread.
120      */

121     private static final ThreadLocal JavaDoc ISO_8601_DATE_FORMAT_OBJECT = new ThreadLocal JavaDoc() {
122         protected Object JavaDoc initialValue() {
123             SimpleDateFormat JavaDoc sdf = new SimpleDateFormat JavaDoc(ISO_8601_DATE_FORMAT);
124             sdf.getTimeZone().setID("+00:00");
125             return sdf;
126         }
127     };
128
129     /**
130      * UTC format
131      * SimpleDateFormats are not threadsafe, but we should not need more than one per
132      * thread.
133      */

134     private static final ThreadLocal JavaDoc UTC_DATE_FORMAT_OBJECT = new ThreadLocal JavaDoc() {
135         protected Object JavaDoc initialValue() {
136             return new SimpleDateFormat JavaDoc(UTC_DATE_FORMAT);
137         }
138     };
139
140     /**
141      * Return a file filter which only returns directories
142      *
143      * @return File filter appropriate for filtering only directories
144      */

145     public static FileFilter getDirectoryFilter() {
146         return DIRECTORY_FILTER;
147     }
148
149     /**
150      * Return a file filter which only returns directories that are not one of a list
151      * of excluded directories
152      *
153      * @param excludedDirectories List of directories to exclude
154      * @return File filter appropriate for filtering only directories
155      */

156     public static FileFilter getDirectoryFilter(final String JavaDoc[] excludedDirectories) {
157         if (excludedDirectories == null) {
158             return DIRECTORY_FILTER;
159         }
160
161         return new FileFilter() {
162             public boolean accept(File pathname) {
163                 if (!pathname.isDirectory()) {
164                     return false;
165                 } else {
166                     for (int i = 0; i < excludedDirectories.length; i++) {
167                         String JavaDoc excludedDirectory = excludedDirectories[i];
168                         if (pathname.toString().matches(excludedDirectory)) {
169                             return false;
170                         }
171                     }
172                 }
173                 return true;
174             }
175         };
176     }
177
178     /**
179      * Return a date in RFC 822 style
180      *
181      * @param date Date
182      * @return Date formatted as RFC 822
183      */

184     public static String JavaDoc getRFC822Date(Date date) {
185         return ((SimpleDateFormat JavaDoc) RFC_822_DATE_FORMAT_OBJECT.get()).format(date);
186     }
187
188     /**
189      * Return a date formatted date
190      *
191      * @param date Date
192      * @param format Date Format String
193      * @param locale Locale Locale for retrieving proper date symbols
194      * @return Date formatted date
195      */

196     public static String JavaDoc getFormattedDate(Date date, String JavaDoc format, Locale locale) {
197         SimpleDateFormat JavaDoc sdf = new SimpleDateFormat JavaDoc(format, locale);
198         return sdf.format(date);
199     }
200
201     /**
202      * Return a date in ISO 8601 style
203      * http://www.w3.org/TR/NOTE-datetime
204      *
205      * @param date Date
206      * @return Date formatted as ISO 8601
207      */

208     public static String JavaDoc getISO8601Date(Date date) {
209         return ((SimpleDateFormat JavaDoc) ISO_8601_DATE_FORMAT_OBJECT.get()).format(date).replaceAll("GMT", "");
210     }
211
212     /**
213      * Return a date in UTC style
214      *
215      * @param date Date
216      * @return Date formatted as ISO 8601
217      */

218     public static String JavaDoc getUTCDate(Date date) {
219         return ((SimpleDateFormat JavaDoc) UTC_DATE_FORMAT_OBJECT.get()).format(date);
220     }
221
222     /**
223      * Return a file filter which takes a list of regular expressions to look for
224      *
225      * @param expressions List of regular expressions for files to retrieve
226      * @return File filter appropriate for filtering out a set of files based on regular expressions
227      */

228     public static FileFilter getRegularExpressionFilter(final String JavaDoc[] expressions) {
229         return new FileFilter() {
230
231             private Date today = new Date();
232
233             public boolean accept(File pathname) {
234                 if (pathname.isDirectory()) {
235                     return false;
236                 }
237
238                 for (int i = 0; i < expressions.length; i++) {
239                     String JavaDoc expression = expressions[i];
240                     if (pathname.getName().matches(expression)) {
241                         return pathname.lastModified() <= today.getTime();
242                     }
243                 }
244
245                 return false;
246             }
247         };
248     }
249
250     /**
251      * Return a file filter which takes a list of file extensions to look for
252      *
253      * @param extensions List of file extensions
254      * @return File filter appropriate for filtering out a set of file extensions
255      */

256     public static FileFilter getExtensionsFilter(final String JavaDoc[] extensions) {
257         return new FileFilter() {
258             public boolean accept(File pathname) {
259                 if (pathname.isDirectory()) {
260                     return false;
261                 }
262
263                 for (int i = 0; i < extensions.length; i++) {
264                     String JavaDoc extension = extensions[i];
265                     if (pathname.getName().endsWith(extension)) {
266                         return true;
267                     }
268                 }
269                 return false;
270             }
271         };
272     }
273
274     /**
275      * Return a file filter which takes a list of file extensions to look for
276      *
277      * @param extensions List of file extensions
278      * @param returnDirectories Whether or not to return
279      * @return File filter appropriate for filtering out a set of file extensions
280      */

281     public static FileFilter getExtensionsFilter(final String JavaDoc[] extensions, final String JavaDoc[] excludedDirectories, final boolean returnDirectories) {
282         return new FileFilter() {
283             public boolean accept(File pathname) {
284                 if (pathname.isDirectory() && returnDirectories) {
285                     String JavaDoc path = pathname.toString();
286
287                     for (int i = 0; i < excludedDirectories.length; i++) {
288                         String JavaDoc excludedDirectory = excludedDirectories[i];
289                         if (path.matches(excludedDirectory)) {
290                             return false;
291                         }
292                     }
293
294                     return true;
295                 }
296
297                 for (int i = 0; i < extensions.length; i++) {
298                     String JavaDoc extension = extensions[i];
299                     if (pathname.getName().matches(extension)) {
300                         return true;
301                     }
302                 }
303
304                 return false;
305             }
306         };
307     }
308
309     /**
310      * Return a file filter which takes a single file extension to look for
311      *
312      * @param extension File extension
313      * @return File filter appropriate for filtering out a single file extension
314      */

315     public static FileFilter getExtensionFilter(final String JavaDoc extension) {
316         return getExtensionsFilter(new String JavaDoc[]{extension});
317     }
318
319     /**
320      * Parse a comma-separated list of values; also parses over internal spaces
321      *
322      * @param commaList Comma-separated list
323      * @return Individual strings from the comma-separated list
324      */

325     public static String JavaDoc[] parseCommaList(String JavaDoc commaList) {
326         return parseDelimitedList(commaList, ", ");
327     }
328
329     /**
330      * Parse a comma-separated list of values
331      *
332      * @param commaList Comma-separated list
333      * @return Individual strings from the comma-separated list
334      */

335     public static String JavaDoc[] parseOnlyCommaList(String JavaDoc commaList) {
336         return parseOnlyCommaList(commaList, false);
337     }
338
339     /**
340      * Parse a comma-separated list of values
341      *
342      * @param commaList Comma-separated list
343      * @param trim If the contents of the array should be trimmed
344      * @return Individual strings from the comma-separated list
345      */

346     public static String JavaDoc[] parseOnlyCommaList(String JavaDoc commaList, boolean trim) {
347         return parseDelimitedList(commaList, ",", trim);
348     }
349
350     /**
351      * Parse a string into two separate strings based on the last comma in the input value
352      *
353      * @param value Input
354      * @return Parsed string
355      */

356     public static String JavaDoc[] parseLastComma(String JavaDoc value) {
357         if (checkNullOrBlank(value)) {
358             return new String JavaDoc[]{value};
359         }
360
361         int lastCommaIndex = value.lastIndexOf(",");
362
363         if (lastCommaIndex == -1) {
364             return new String JavaDoc[]{value};
365         } else {
366             return new String JavaDoc[]{value.substring(0, lastCommaIndex), value.substring(lastCommaIndex + 1)};
367         }
368     }
369
370     /**
371      * Parse a delimited list of values
372      *
373      * @param delimitedList Delimited list
374      * @param delimiter Field Delimiter
375      * @return Individual strings from the comma-separated list
376      */

377     public static String JavaDoc[] parseDelimitedList(String JavaDoc delimitedList, String JavaDoc delimiter) {
378         return parseDelimitedList(delimitedList, delimiter, false);
379     }
380
381     /**
382      * Parse a delimited list of values
383      *
384      * @param delimitedList Delimited list
385      * @param delimiter Field Delimiter
386      * @param trim If the contents of the array should be trimmed
387      * @return Individual strings from the comma-separated list
388      */

389     public static String JavaDoc[] parseDelimitedList(String JavaDoc delimitedList, String JavaDoc delimiter, boolean trim) {
390         if (delimitedList == null) {
391             return null;
392         }
393
394         StringTokenizer tokenizer = new StringTokenizer(delimitedList, delimiter);
395         ArrayList list = new ArrayList();
396         while (tokenizer.hasMoreTokens()) {
397             if (trim) {
398                 list.add(tokenizer.nextToken().trim());
399             } else {
400                 list.add(tokenizer.nextToken());
401             }
402         }
403
404         if (list.size() == 0) {
405             return new String JavaDoc[]{};
406         }
407
408         return (String JavaDoc[]) list.toArray(new String JavaDoc[list.size()]);
409     }
410
411     /**
412      * Convert the request parameters to a string
413      *
414      * @param request Servlet request
415      * @return Request parameters in the form &amp;name=value
416      */

417     public static String JavaDoc convertRequestParams(HttpServletRequest JavaDoc request) {
418         Enumeration paramNames = request.getParameterNames();
419         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
420         while (paramNames.hasMoreElements()) {
421             String JavaDoc name = (String JavaDoc) paramNames.nextElement();
422             String JavaDoc value = request.getParameter(name);
423             try {
424                 buffer.append(URLEncoder.encode(name, UTF8)).append("=").append(URLEncoder.encode(value, UTF8));
425             } catch (UnsupportedEncodingException e) {
426             }
427             if (paramNames.hasMoreElements()) {
428                 buffer.append("&");
429             }
430         }
431         return buffer.toString();
432     }
433
434     /**
435      * Convert the request parameters to a string
436      *
437      * @param request Servlet request
438      * @param ignoreParams Parameters to ignore when converting the request
439      * @return Request parameters in the form &amp;name=value
440      */

441     public static String JavaDoc convertRequestParams(HttpServletRequest JavaDoc request, Map ignoreParams) {
442         Enumeration paramNames = request.getParameterNames();
443         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
444         while (paramNames.hasMoreElements()) {
445             String JavaDoc name = (String JavaDoc) paramNames.nextElement();
446             String JavaDoc value = request.getParameter(name);
447             //noinspection EmptyCatchBlock
448
try {
449                 if (!ignoreParams.containsKey(name)) {
450                     buffer.append(URLEncoder.encode(name, UTF8)).append("=").append(URLEncoder.encode(value, UTF8)).append("&");
451                 }
452             } catch (UnsupportedEncodingException e) {
453             }
454         }
455
456         return buffer.toString();
457     }
458
459     /**
460      * Return a URL to the main blog site without the servlet path requested
461      *
462      * @param blogURL URL for the blog
463      * @param servletPath Servlet path under which the blog is placed
464      * @return URL to the blog up to the servlet path
465      */

466     public static String JavaDoc getBlogSiteURL(String JavaDoc blogURL, String JavaDoc servletPath) {
467         if (servletPath == null || "".equals(servletPath)) {
468             return blogURL;
469         }
470         int servletPathIndex = blogURL.indexOf(servletPath, 7);
471         if (servletPathIndex == -1) {
472             return blogURL;
473         }
474
475         return blogURL.substring(0, servletPathIndex);
476     }
477
478     /**
479      * Return an escaped string where &amp;, &lt;, &gt;, &quot;, and &apos; are converted to their HTML equivalents
480      *
481      * @param input Unescaped string
482      * @return Escaped string containing HTML equivalents for &amp;, &lt;, &gt;, &quot;, and &apos;
483      */

484     public static String JavaDoc escapeString(String JavaDoc input) {
485         if (input == null) {
486             return null;
487         }
488
489         String JavaDoc unescaped = replace(input, "&", "&amp;");
490         unescaped = replace(unescaped, "<", "&lt;");
491         unescaped = replace(unescaped, ">", "&gt;");
492         unescaped = replace(unescaped, "\"", "&quot;");
493         unescaped = replace(unescaped, "'", "&#39;");
494
495         return unescaped;
496     }
497
498     /**
499      * Return an escaped string where &amp;, &lt;, &gt; are converted to their HTML equivalents
500      *
501      * @param input Unescaped string
502      * @return Escaped string containing HTML equivalents for &amp;, &lt;, &gt;
503      */

504     public static String JavaDoc escapeStringSimple(String JavaDoc input) {
505         if (input == null) {
506             return null;
507         }
508
509         String JavaDoc unescaped = replace(input, "&", "&amp;");
510         unescaped = replace(unescaped, "<", "&lt;");
511         unescaped = replace(unescaped, ">", "&gt;");
512
513         return unescaped;
514     }
515
516     /**
517      * Return an escaped string where &lt;, &gt; are converted to their HTML equivalents
518      *
519      * @param input Unescaped string
520      * @return Escaped string containing HTML equivalents for &lt;, &gt;
521      */

522     public static String JavaDoc escapeBrackets(String JavaDoc input) {
523         if (input == null) {
524             return null;
525         }
526
527         String JavaDoc unescaped = replace(input, "<", "&lt;");
528         unescaped = replace(unescaped, ">", "&gt;");
529
530         return unescaped;
531     }
532
533     /**
534      * Return an escaped string where &lt;meta, &lt;link tags are escaped
535      *
536      * @param input Unescaped string
537      * @return Escaped string where &lt;meta, &lt;link tags are escaped
538      */

539     public static String JavaDoc escapeMetaAndLink(String JavaDoc input) {
540         if (input == null) {
541             return null;
542         }
543
544         String JavaDoc cleanedInput = input.replaceAll("<[mM][eE][tT][aA]", "&lt;meta");
545         cleanedInput = cleanedInput.replaceAll("<[lL][iI][nN][kK]", "&lt;link");
546         return cleanedInput;
547     }
548
549     /**
550      * Replace any occurances of a string pattern within a string with a different string.
551      *
552      * @param str The source string. This is the string that will be searched and have the replacements
553      * @param pattern The pattern to look for in str
554      * @param replace The string to insert in the place of <i>pattern</i>
555      * @return String with replace occurences
556      */

557     public static String JavaDoc replace(String JavaDoc str, String JavaDoc pattern, String JavaDoc replace) {
558         if (str == null || "".equals(str)) {
559             return str;
560         }
561
562         if (replace == null) {
563             return str;
564         }
565
566         if ("".equals(pattern)) {
567             return str;
568         }
569
570         int s = 0;
571         int e;
572         StringBuffer JavaDoc result = new StringBuffer JavaDoc();
573
574         while ((e = str.indexOf(pattern, s)) >= 0) {
575             result.append(str.substring(s, e));
576             result.append(replace);
577             s = e + pattern.length();
578         }
579         result.append(str.substring(s));
580         return result.toString();
581     }
582
583     /**
584      * Return the file extension for a given filename or <code>null</code> if no file extension
585      * is present
586      *
587      * @param filename Filename
588      * @return File extension without the . or <code>null</code> if no file extension is present
589      */

590     public static String JavaDoc getFileExtension(String JavaDoc filename) {
591         if (filename == null) {
592             return null;
593         }
594
595         int dotIndex = filename.lastIndexOf(".");
596         if (dotIndex == -1) {
597             return null;
598         } else {
599             return filename.substring(dotIndex + 1);
600         }
601     }
602
603     /**
604      * Return the filename without extension for a given filename
605      *
606      * @param filename Filename
607      * @return Filename up to the .
608      */

609     public static String JavaDoc getFilename(String JavaDoc filename) {
610         int dotIndex = filename.lastIndexOf(".");
611         if (dotIndex == -1) {
612             return filename;
613         } else {
614             return filename.substring(0, dotIndex);
615         }
616     }
617
618     /**
619      * Returns the base file name from the supplied file path. On the surface,
620      * this would appear to be a trivial task. Apparently, however, some Linux
621      * JDKs do not implement <code>File.getName()</code> correctly for Windows
622      * paths, so we attempt to take care of that here.
623      *
624      * @param filenameWithPath The full path to the file.
625      * @return The base file name, from the end of the path.
626      */

627     public static String JavaDoc getFilenameFromPath(String JavaDoc filenameWithPath) {
628         // First, ask the JDK for the base file name.
629
String JavaDoc fileName = new File(filenameWithPath).getName();
630
631         // Now check for a Windows file name parsed incorrectly.
632
int colonIndex = fileName.indexOf(":");
633         if (colonIndex == -1) {
634             // Check for a Windows SMB file path.
635
colonIndex = fileName.indexOf("\\\\");
636         }
637         int backslashIndex = fileName.lastIndexOf("\\");
638
639         if (colonIndex > -1 && backslashIndex > -1) {
640             // Consider this filename to be a full Windows path, and parse it
641
// accordingly to retrieve just the base file name.
642
fileName = fileName.substring(backslashIndex + 1);
643         }
644
645         return fileName;
646     }
647
648     /**
649      * Return a string of "YYYYMMDD"
650      *
651      * @param date Date from which to extract "key"
652      * @return String of "YYYYMMDD"
653      */

654     public static String JavaDoc getDateKey(Date date) {
655         StringBuffer JavaDoc value = new StringBuffer JavaDoc();
656         Calendar calendar = Calendar.getInstance();
657         long l;
658
659         calendar.setTime(date);
660         value.append(calendar.get(Calendar.YEAR));
661         // month and date need to be 2 digits; otherwise it is
662
// impossible to distinguish between e.g. November (11)
663
// and January (1) when using the date as a prefix
664
l = calendar.get(Calendar.MONTH) + 1;
665         if (l < 10) {
666             value.append("0");
667         }
668         value.append(l);
669         l = calendar.get(Calendar.DAY_OF_MONTH);
670         if (l < 10) {
671             value.append("0");
672         }
673         value.append(l);
674         // highest possible values above are 12 and 31, so no need to
675
// be generic & handle arbitrary-length digits
676

677         return value.toString();
678     }
679
680     /**
681      * Remove the initial "/" from a string
682      *
683      * @param input Input string
684      * @return Input string without initial "/" removed or <code>null</code> if the input was null
685      */

686     public static String JavaDoc removeInitialSlash(String JavaDoc input) {
687         if (input == null) {
688             return null;
689         }
690
691         if (!input.startsWith("/")) {
692             return input;
693         } else {
694             return input.substring(1);
695         }
696     }
697
698     /**
699      * Remove the trailing "/" from a string
700      *
701      * @param input Input string
702      * @return Input string with trailing "/" removed or <code>null</code> if the input was null
703      */

704     public static String JavaDoc removeTrailingSlash(String JavaDoc input) {
705         if (input == null) {
706             return null;
707         }
708
709         if (!input.endsWith("/")) {
710             return input;
711         } else {
712             return input.substring(0, input.length() - 1);
713         }
714     }
715
716     /**
717      * Remove the "/" from the beginning and end of a string
718      *
719      * @param input Input string
720      * @return Input string with beginning and ending "/" removed or <code>null</code> if the input was null
721      */

722     public static String JavaDoc removeSlashes(String JavaDoc input) {
723         input = removeInitialSlash(input);
724         input = removeTrailingSlash(input);
725         return input;
726     }
727
728     /**
729      * Extracts the first line in a given string, otherwise returns the first n bytes
730      *
731      * @param input String from which to extract the first line
732      * @param length Number of bytes to return if line seperator isnot found
733      * @return the first line of the string
734      */

735     public static String JavaDoc getFirstLine(String JavaDoc input, int length) {
736         String JavaDoc result;
737         String JavaDoc lineSeparator = LINE_SEPARATOR;
738         int titleIndex = input.indexOf(lineSeparator);
739         if (titleIndex == -1) {
740             result = input.substring(0, length) + "...";
741         } else {
742             result = input.substring(0, titleIndex);
743         }
744         return result;
745     }
746
747     /**
748      * Return the template name for a particular page
749      *
750      * @param flavorTemplate Flavor template filename
751      * @param page Requested page
752      * @return
753      */

754     public static String JavaDoc getTemplateForPage(String JavaDoc flavorTemplate, String JavaDoc page) {
755         int dotIndex = flavorTemplate.lastIndexOf(".");
756         if (dotIndex == -1) {
757             return flavorTemplate + '-' + page;
758         } else {
759             StringBuffer JavaDoc newTemplate = new StringBuffer JavaDoc();
760             if (page.startsWith("/")) {
761                 newTemplate.append(removeInitialSlash(page));
762             } else {
763                 newTemplate.append(flavorTemplate.substring(0, dotIndex));
764                 newTemplate.append("-");
765                 newTemplate.append(page);
766             }
767             newTemplate.append(".");
768             newTemplate.append(flavorTemplate.substring(dotIndex + 1, flavorTemplate.length()));
769             return newTemplate.toString();
770         }
771     }
772
773     /**
774      * Tries to retrieve a given key using getParameter(key) and if not available, will
775      * use getAttribute(key) from the servlet request
776      *
777      * @param key Parameter to retrieve
778      * @param httpServletRequest Request
779      * @return Value of the key as a string, or <code>null</code> if there is no parameter/attribute
780      */

781     public static String JavaDoc getRequestValue(String JavaDoc key, HttpServletRequest JavaDoc httpServletRequest) {
782         return getRequestValue(key, httpServletRequest, false);
783     }
784
785     /**
786      * Tries to retrieve a given key using getParameter(key) and if not available, will
787      * use getAttribute(key) from the servlet request
788      *
789      * @param key Parameter to retrieve
790      * @param httpServletRequest Request
791      * @param preferAttributes If request attributes should be checked before request parameters
792      * @return Value of the key as a string, or <code>null</code> if there is no parameter/attribute
793      */

794     public static String JavaDoc getRequestValue(String JavaDoc key, HttpServletRequest JavaDoc httpServletRequest, boolean preferAttributes) {
795         if (!preferAttributes) {
796             if (httpServletRequest.getParameter(key) != null) {
797                 return httpServletRequest.getParameter(key);
798             } else if (httpServletRequest.getAttribute(key) != null) {
799                 return httpServletRequest.getAttribute(key).toString();
800             }
801         } else {
802             if (httpServletRequest.getAttribute(key) != null) {
803                 return httpServletRequest.getAttribute(key).toString();
804             } else if (httpServletRequest.getParameter(key) != null) {
805                 return httpServletRequest.getParameter(key);
806             }
807         }
808
809         return null;
810     }
811
812     /**
813      * Get request values for a given key and if not available, returns and empty <code>String[]</code>
814      *
815      * @param key Parameter to retrieve
816      * @param httpServletRequest Request
817      * @return Request values for the key as a <code>String[]</code>
818      */

819     public static String JavaDoc[] getRequestValues(String JavaDoc key, HttpServletRequest JavaDoc httpServletRequest) {
820         String JavaDoc[] values = httpServletRequest.getParameterValues(key);
821
822         if (values == null) {
823             values = new String JavaDoc[0];
824         }
825
826         return values;
827     }
828
829     /**
830      * Return only the filename of a permalink request
831      *
832      * @param permalink Permalink request
833      * @param blogEntryExtensions Regex for blog entries so that we only pickup requests for valid blog entries
834      * @return Filename portion of permalink request
835      */

836     public static String JavaDoc getFilenameForPermalink(String JavaDoc permalink, String JavaDoc[] blogEntryExtensions) {
837         if (permalink == null) {
838             return null;
839         }
840
841         boolean matchesExtension = false;
842         for (int i = 0; i < blogEntryExtensions.length; i++) {
843             String JavaDoc blogEntryExtension = blogEntryExtensions[i];
844             if (permalink.matches(blogEntryExtension)) {
845                 matchesExtension = true;
846                 break;
847             }
848         }
849
850         if (!matchesExtension) {
851             return null;
852         }
853
854         int indexOfSlash = permalink.lastIndexOf("/");
855         if (indexOfSlash == -1) {
856             indexOfSlash = permalink.lastIndexOf("\\");
857         }
858
859         if (indexOfSlash == -1) {
860             return permalink;
861         } else {
862             String JavaDoc sanitizedPermalink = permalink.substring(indexOfSlash + 1, permalink.length());
863             if (sanitizedPermalink.startsWith("..")) {
864                 sanitizedPermalink = sanitizedPermalink.substring(2, sanitizedPermalink.length());
865             } else if (sanitizedPermalink.startsWith(".")) {
866                 sanitizedPermalink = sanitizedPermalink.substring(1, sanitizedPermalink.length());
867             }
868
869             return sanitizedPermalink;
870         }
871     }
872
873     /**
874      * Return an input string URL encoded
875      *
876      * @param input Input string
877      * @return URL encoded string, <code>null</code> if the input was null,
878      * or <code>input</code> unmodified there is an encoding exception
879      */

880     public static String JavaDoc urlEncode(String JavaDoc input) {
881         if (input == null) {
882             return null;
883         }
884
885         try {
886             return URLEncoder.encode(input, UTF8);
887         } catch (UnsupportedEncodingException e) {
888             return input;
889         }
890     }
891
892     /**
893      * Return an input string URL encoded for a URL link where '/' show as '/'
894      *
895      * @param input Input string
896      * @return URL encoded string, <code>null</code> if the input was null,
897      * or <code>input</code> unmodified there is an encoding exception
898      */

899     public static String JavaDoc urlEncodeForLink(String JavaDoc input) {
900         if (input == null) {
901             return null;
902         }
903
904         try {
905             String JavaDoc result = URLEncoder.encode(input, UTF8);
906             result = replace(result, "%2F", "/");
907             result = replace(result, "%20", "+");
908             return result;
909         } catch (UnsupportedEncodingException e) {
910             return input;
911         }
912     }
913
914     /**
915      * Return a URL decoded string
916      *
917      * @param input Input string
918      * @return URL decoded string or <code>null</code> if either the input was null or there is a decoding exception
919      */

920     public static String JavaDoc urlDecode(String JavaDoc input) {
921         if (input == null) {
922             return null;
923         }
924
925         try {
926             return URLDecoder.decode(input, UTF8);
927         } catch (UnsupportedEncodingException e) {
928             return null;
929         }
930     }
931
932     /**
933      * Create a Calendar Navigatation URL
934      *
935      * @param prefix Any URL Prefix
936      * @param month Month of navigation
937      * @param day Day of navigation
938      * @param year Year of navigation
939      * @return Properly formatted calendar navigation url
940      */

941     public static String JavaDoc getCalendarNavigationUrl(String JavaDoc prefix, int month, int day, int year) {
942         StringBuffer JavaDoc dateurl = new StringBuffer JavaDoc(prefix);
943
944         if (year != -1) {
945             dateurl.append(year).append("/");
946         }
947
948         if (month != -1) {
949             if (month < 10) {
950                 dateurl.append("0");
951             }
952
953             dateurl.append(month).append("/");
954         }
955
956         if (day != -1) {
957             if (day < 10) {
958                 dateurl.append("0");
959             }
960             
961             dateurl.append(day).append("/");
962         }
963
964         return dateurl.toString();
965     }
966
967     /**
968      * Return a comparator to sort by name
969      */

970     public static final Comparator FILE_NAME_COMPARATOR = new Comparator() {
971         public int compare(Object JavaDoc o1, Object JavaDoc o2) {
972             String JavaDoc s1 = (String JavaDoc) o1;
973             String JavaDoc s2 = (String JavaDoc) o2;
974
975             return s1.compareTo(s2);
976         }
977     };
978
979     static final byte[] HEX_DIGITS = {
980         (byte) '0', (byte) '1', (byte) '2', (byte) '3',
981         (byte) '4', (byte) '5', (byte) '6', (byte) '7',
982         (byte) '8', (byte) '9', (byte) 'a', (byte) 'b',
983         (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f'
984     };
985
986     /**
987      * Performs an MD5 Digest onthe given String content
988      *
989      * @param data Content to digest
990      * @return The Hash as Hex String
991      */

992     public static String JavaDoc digestString(String JavaDoc data) {
993         return digestString(data, DEFAULT_DIGEST_ALGORITHM);
994     }
995
996     /**
997      * Performs an Digest onthe given String content for the given algorithm
998      *
999      * @param data Content to digest
1000     * @param algorithm the algorithm to use (MD5, SHA1)
1001     * @return The Hash as Hex String
1002     */

1003    public static String JavaDoc digestString(String JavaDoc data, String JavaDoc algorithm) {
1004        String JavaDoc result = null;
1005        if (data != null) {
1006            try {
1007                MessageDigest JavaDoc _md = MessageDigest.getInstance(algorithm);
1008                _md.update(data.getBytes());
1009                byte[] _digest = _md.digest();
1010                String JavaDoc _ds;
1011                _ds = toHexString(_digest, 0, _digest.length);
1012                result = _ds;
1013            } catch (NoSuchAlgorithmException JavaDoc e) {
1014                result = null;
1015            }
1016        }
1017        return result;
1018    }
1019
1020    /**
1021     * Convert Byte Array to Hex Value
1022     *
1023     * @param buf Byte Array to convert to Hex Value
1024     * @param offset Starting Offset for Conversion
1025     * @param length Length to convery
1026     * @param value Hex Value
1027     */

1028    private static void toHexValue(byte[] buf, int offset, int length, int value) {
1029        do {
1030            buf[offset + --length] = HEX_DIGITS[value & 0x0f];
1031            value >>>= 4;
1032        } while (value != 0 && length > 0);
1033
1034        while (--length >= 0) {
1035            buf[offset + length] = HEX_DIGITS[0];
1036        }
1037    }
1038
1039    /**
1040     * Convert a byte array to a hex string
1041     *
1042     * @param buf Byte array to convert to hex string
1043     * @param offset Starting offset for conversion
1044     * @param length Length to convert
1045     * @return Hex string representing the byte array
1046     */

1047    public static String JavaDoc toHexString(byte[] buf, int offset, int length) {
1048        byte[] buf1 = new byte[length * 2];
1049        for (int i = 0; i < length; i++) {
1050            toHexValue(buf1, i * 2, 2, buf[i + offset]);
1051        }
1052        return new String JavaDoc(buf1);
1053    }
1054
1055    /**
1056     * Normalize a path to remove all ./, ../, .../, //, etc. type references
1057     *
1058     * @param path Input path
1059     * @return Normalized path
1060     */

1061    public static String JavaDoc normalize(String JavaDoc path) {
1062        if (path == null) {
1063            return null;
1064        }
1065
1066        String JavaDoc value = path;
1067        value = value.replaceAll("\\.*", "");
1068        value = value.replaceAll("/{2,}", "");
1069        return value;
1070    }
1071
1072    /**
1073     * Check to see if the given input string is <code>null</code> and if so, return a blank string instead
1074     *
1075     * @param input Input string
1076     * @return Blank string if the input string is <code>null</code>, otherwise just return the input string
1077     */

1078    public static String JavaDoc nullToBlank(String JavaDoc input) {
1079        return (input == null) ? "" : input;
1080    }
1081
1082    /**
1083     * Convert a set of {@link Properties} to a {@link Map}
1084     *
1085     * @param properties Properties to be converted to a Map
1086     * @return Map object containing all the keys and values from the original Properties object. If the
1087     * Properties object was null, a new Map is returned with no values.
1088     */

1089    public static Map propertiesToMap(Properties properties) {
1090        if (properties == null) {
1091            return new HashMap();
1092        } else {
1093            Iterator keyIterator = properties.keySet().iterator();
1094            Object JavaDoc key;
1095            Object JavaDoc value;
1096            HashMap convertedProperties = new HashMap();
1097            while (keyIterator.hasNext()) {
1098                key = keyIterator.next();
1099                value = properties.get(key);
1100                convertedProperties.put(key, value);
1101            }
1102
1103            return convertedProperties;
1104        }
1105    }
1106
1107    /**
1108     * Convert a {@link BlojsomProperties} object to a {@link Map}. If the properties object is <code>null</code>
1109     * an emtpy {@link Map} is returned.
1110     *
1111     * @param properties {@link BlojsomProperties}
1112     * @return {@link Map} containing keys and values from the properties
1113     */

1114    public static Map blojsomPropertiesToMap(Properties properties) {
1115        if (properties == null) {
1116            return new HashMap();
1117        } else {
1118            Iterator keyIterator = properties.keySet().iterator();
1119            Object JavaDoc key;
1120            Object JavaDoc value;
1121            HashMap convertedProperties = new HashMap();
1122            while (keyIterator.hasNext()) {
1123                key = keyIterator.next();
1124                value = properties.get(key);
1125                if (value instanceof List) {
1126                    convertedProperties.put(key, value);
1127                } else {
1128                    ArrayList values = new ArrayList();
1129                    values.add(value.toString());
1130                    convertedProperties.put(key, values);
1131                }
1132            }
1133
1134            return convertedProperties;
1135        }
1136    }
1137
1138    /**
1139     * Turn an array of strings into a single string separated by a given delimeter. If the incoming array is null, this
1140     * method returns the <code>null</code> string.
1141     *
1142     * @param array Array of strings
1143     * @param separator Separator between strings
1144     * @return Single string containing all the strings from the original array separated by the given delimeter, or <code>null</code> if the input was null.
1145     */

1146    public static String JavaDoc arrayOfStringsToString(String JavaDoc[] array, String JavaDoc separator) {
1147        if (array == null) {
1148            return null;
1149        }
1150
1151        StringBuffer JavaDoc result = new StringBuffer JavaDoc();
1152        if (array.length > 0) {
1153            result.append(array[0]);
1154            // now loop over the rest of the array, appending separators first
1155
for (int i = 1; i < array.length; i++) {
1156                result.append(separator);
1157                result.append(array[i]);
1158            }
1159        }
1160
1161        return result.toString();
1162    }
1163
1164    /**
1165     * Turn an array of strings into a single string separated by commas. If the incoming array is null, this
1166     * method returns the <code>null</code> string.
1167     *
1168     * @param array Array of strings
1169     * @return Single string containing all the strings from the original array separated by commas, or <code>null</code> if the input was null.
1170     */

1171    public static String JavaDoc arrayOfStringsToString(String JavaDoc[] array) {
1172        return arrayOfStringsToString(array, ", ");
1173    }
1174
1175    /**
1176     * Returns category information from the path provided to the method where the path provided is
1177     * assumed to be everything after the servlet instance with a user id at the very beginning of the path.
1178     * For example, /david/this/is/the/category
1179     *
1180     * @param pathInfo Path information
1181     * @return Everything after the second "/" character in the path
1182     */

1183    public static String JavaDoc getCategoryFromPath(String JavaDoc pathInfo) {
1184        if (pathInfo == null || "/".equals(pathInfo)) {
1185            return "/";
1186        } else {
1187            int categoryStart = pathInfo.indexOf("/", 1);
1188            if (categoryStart == -1) {
1189                return "/";
1190            } else {
1191                return pathInfo.substring(categoryStart);
1192            }
1193        }
1194    }
1195
1196    /**
1197     * Returns blog id information from the path provided to the method where the path provided is
1198     * assumed to be everything after the servlet instance with a user id at the very beginning of the path.
1199     * For example, /david/this/is/the/category
1200     *
1201     * @param pathInfo Path information
1202     * @return Everything before the second "/" character in the path
1203     */

1204    public static String JavaDoc getBlogFromPath(String JavaDoc pathInfo) {
1205        if (pathInfo == null || "/".equals(pathInfo)) {
1206            return null;
1207        } else {
1208            int userEnd = pathInfo.indexOf("/", 1);
1209            if (userEnd == -1) {
1210                return pathInfo.substring(1);
1211            } else {
1212                return pathInfo.substring(1, userEnd);
1213            }
1214        }
1215    }
1216
1217    /**
1218     * Delete a directory (or file) and any sub-directories underneath the directory
1219     *
1220     * @param directoryOrFile Directory or file to be deleted
1221     * @return <code>true</code> if the directory (or file) could be deleted, <code>false</code> otherwise
1222     */

1223    public static boolean deleteDirectory(File directoryOrFile) {
1224        return deleteDirectory(directoryOrFile, true);
1225    }
1226
1227    /**
1228     * Delete a directory (or file) and any sub-directories underneath the directory
1229     *
1230     * @param directoryOrFile Directory or file to be deleted
1231     * @param removeDirectoryOrFile If the directory of file should be deleted in addition to the sub-directories
1232     * @return <code>true</code> if the directory (or file) could be deleted, <code>false</code> otherwise
1233     */

1234    public static boolean deleteDirectory(File directoryOrFile, boolean removeDirectoryOrFile) {
1235        if (directoryOrFile.isDirectory()) {
1236            File[] children = directoryOrFile.listFiles();
1237            if (children != null && children.length > 0) {
1238                for (int i = 0; i < children.length; i++) {
1239                    boolean success = deleteDirectory(children[i]);
1240                    if (!success) {
1241                        return false;
1242                    }
1243                }
1244            }
1245        }
1246
1247        if (removeDirectoryOrFile) {
1248            return directoryOrFile.delete();
1249        }
1250
1251        return true;
1252    }
1253
1254    /**
1255     * Recursively copy a directory from a source to a target
1256     *
1257     * @param sourceDirectory Source directory
1258     * @param targetDirectory Destination directory
1259     * @throws IOException If there is an error copying the files and directories
1260     */

1261    public static void copyDirectory(File sourceDirectory, File targetDirectory) throws IOException {
1262        File[] sourceFiles = sourceDirectory.listFiles(FILE_FILTER);
1263        File[] sourceDirectories = sourceDirectory.listFiles(DIRECTORY_FILTER);
1264
1265        targetDirectory.mkdirs();
1266
1267        // Copy the files
1268
if (sourceFiles != null && sourceFiles.length > 0) {
1269            for (int i = 0; i < sourceFiles.length; i++) {
1270                File sourceFile = sourceFiles[i];
1271
1272                FileInputStream fis = new FileInputStream(sourceFile);
1273                FileOutputStream fos = new FileOutputStream(targetDirectory + File.separator + sourceFile.getName());
1274                FileChannel JavaDoc fcin = fis.getChannel();
1275                FileChannel JavaDoc fcout = fos.getChannel();
1276
1277                ByteBuffer JavaDoc buf = ByteBuffer.allocateDirect(8192);
1278                long size = fcin.size();
1279                long n = 0;
1280                while (n < size) {
1281                    buf.clear();
1282                    if (fcin.read(buf) < 0) {
1283                        break;
1284                    }
1285                    buf.flip();
1286                    n += fcout.write(buf);
1287                }
1288
1289                fcin.close();
1290                fcout.close();
1291                fis.close();
1292                fos.close();
1293            }
1294        }
1295
1296        // Copy the directories
1297
if (sourceDirectories != null && sourceDirectories.length > 0) {
1298            for (int i = 0; i < sourceDirectories.length; i++) {
1299                File directory = sourceDirectories[i];
1300                File newTargetDirectory = new File(targetDirectory, directory.getName());
1301
1302                copyDirectory(directory, newTargetDirectory);
1303            }
1304        }
1305    }
1306
1307    /**
1308     * Turn an array of strings into a Map where the keys and values are the input strings. If the incoming array is null, this
1309     * method returns an empty map.
1310     *
1311     * @param array Array of strings
1312     * @return Map Map containing all the strings from the original array or an empty map if the incoming array is null.
1313     */

1314    public static Map arrayOfStringsToMap(String JavaDoc[] array) {
1315        if (array == null) {
1316            return new HashMap();
1317        }
1318
1319        Map result = new HashMap();
1320        for (int i = 0; i < array.length; i++) {
1321            result.put(array[i], array[i]);
1322        }
1323
1324        return result;
1325    }
1326
1327    /**
1328     * Add a '/' at the beginning and end of the input string if necessary.
1329     *
1330     * @param input Input string
1331     * @return String with a '/' at the beginning and end of the original string, <code>null</code> if the input was <code>null</code>
1332     */

1333    public static String JavaDoc checkStartingAndEndingSlash(String JavaDoc input) {
1334        if (input == null) {
1335            return null;
1336        }
1337
1338        if (!input.startsWith("/")) {
1339            input = "/" + input;
1340        }
1341
1342        if (!input.endsWith("/")) {
1343            input += "/";
1344        }
1345
1346        return input;
1347    }
1348
1349    /**
1350     * Checks to see if the string is null or blank (after trimming)
1351     *
1352     * @param input Input string
1353     * @return <code>true</code> if the string is null or blank (after trimming), <code>false</code> otherwise
1354     */

1355    public static boolean checkNullOrBlank(String JavaDoc input) {
1356        return (input == null || "".equals(input.trim()));
1357    }
1358
1359    /**
1360     * Set various cache control HTTP headers so that the browser does not try and cache the page
1361     *
1362     * @param httpServletResponse Response
1363     */

1364    public static void setNoCacheControlHeaders(HttpServletResponse JavaDoc httpServletResponse) {
1365        httpServletResponse.setHeader(PRAGMA_HTTP_HEADER, NO_CACHE_HTTP_HEADER_VALUE);
1366        httpServletResponse.setHeader(CACHE_CONTROL_HTTP_HEADER, NO_CACHE_HTTP_HEADER_VALUE);
1367    }
1368
1369    /**
1370     * Check to see if a given map contains a particular key. Returns <code>true</code> if and only if the map and
1371     * key are not null and the map contains the key.
1372     *
1373     * @param map Map to check for given key
1374     * @param key Key to check for in map
1375     * @return Returns <code>true</code> if and only if the map and key are not null and the map contains the key.
1376     */

1377    public static boolean checkMapForKey(Map map, String JavaDoc key) {
1378        if (map == null) {
1379            return false;
1380        }
1381
1382        if (key == null) {
1383            return false;
1384        }
1385
1386        return map.containsKey(key);
1387    }
1388
1389    /**
1390     * Return the number of days between two dates
1391     *
1392     * @param startDate Start date
1393     * @param endDate End date
1394     * @return Number of days between two dates which may be 0 if either of the dates if <code>null</code>
1395     */

1396    public static int daysBetweenDates(Date startDate, Date endDate) {
1397        if (startDate == null || endDate == null) {
1398            return 0;
1399        }
1400
1401        Calendar calendarStartDate = Calendar.getInstance();
1402        calendarStartDate.setTime(startDate);
1403        int startDay = calendarStartDate.get(Calendar.DAY_OF_YEAR);
1404        int startYear = calendarStartDate.get(Calendar.YEAR);
1405        Calendar calendarEndDate = Calendar.getInstance();
1406        calendarEndDate.setTime(endDate);
1407        int endDay = calendarEndDate.get(Calendar.DAY_OF_YEAR);
1408        int endYear = calendarEndDate.get(Calendar.YEAR);
1409
1410        return Math.abs((endDay - startDay) + ((endYear - startYear) * 365));
1411    }
1412
1413    /**
1414     * Return a filename with the date as a long value before the file extension.
1415     *
1416     * @param filename Filename with extension
1417     * @return Filename as {filename}-{date}.{file extension} or <code>null</code> if there was no file extension
1418     */

1419    public static File getFilenameForDate(String JavaDoc filename) {
1420        String JavaDoc filenameWithoutExtension = getFilename(filename);
1421        String JavaDoc fileExtension = getFileExtension(filename);
1422
1423        if (fileExtension == null) {
1424            return null;
1425        } else {
1426            return new File(filenameWithoutExtension + "-" + new Date().getTime() + "." + fileExtension);
1427        }
1428    }
1429
1430    /**
1431     * Strip line terminator characters from an input string
1432     *
1433     * @param input Input string
1434     * @return Input with line terminator characters stripped or <code>null</code> if the input was <code>null</code>
1435     */

1436    public static String JavaDoc stripLineTerminators(String JavaDoc input) {
1437        return stripLineTerminators(input, "");
1438    }
1439
1440    /**
1441     * Strip line terminator characters from an input string
1442     *
1443     * @param input Input string
1444     * @param replacement Replacement string
1445     * @return Input with line terminator characters stripped or <code>null</code> if the input was <code>null</code>
1446     */

1447    public static String JavaDoc stripLineTerminators(String JavaDoc input, String JavaDoc replacement) {
1448        if (input == null) {
1449            return null;
1450        }
1451
1452        return input.replaceAll("[\n\r\f]", replacement);
1453    }
1454
1455    /**
1456     * Return the keys of a map as a comma-separated list
1457     *
1458     * @param input {@link Map}
1459     * @return Keys as a comma-separated list or an empty string if the input is <code>null</code> or contains no keys
1460     */

1461    public static String JavaDoc getKeysAsStringList(Map input) {
1462        StringBuffer JavaDoc result = new StringBuffer JavaDoc();
1463        if (input == null || input.size() == 0) {
1464            return result.toString();
1465        }
1466
1467        Iterator keyIterator = input.keySet().iterator();
1468        int counter = 0;
1469        while (keyIterator.hasNext()) {
1470            Object JavaDoc key = keyIterator.next();
1471            result.append(key);
1472
1473            if (counter < input.size() - 1) {
1474                result.append(", ");
1475            }
1476
1477            counter++;
1478        }
1479
1480        return result.toString();
1481    }
1482
1483    /**
1484     * Convert a list to a comma-separated string. If values in the list are <code>null</code>, a
1485     * space is printed. If the input is null or there are no items in the list, an empty
1486     * string is returned.
1487     *
1488     * @param values List of values
1489     * @return Comma-separated string
1490     */

1491    public static String JavaDoc listToCSV(List values) {
1492        StringBuffer JavaDoc result = new StringBuffer JavaDoc();
1493
1494        if (values != null && values.size() > 0) {
1495            for (int i = 0; i < values.size(); i++) {
1496                if (values.get(i) == null) {
1497                    result.append(" ");
1498                } else {
1499                    result.append(values.get(i));
1500                }
1501
1502                if (i < values.size() - 1) {
1503                    result.append(", ");
1504                }
1505            }
1506        }
1507
1508        return result.toString();
1509    }
1510
1511    /**
1512     * Convert a list of values to a {@link Map}. <code>null</code> values are not placed
1513     * in the returned <code>Map</code>.
1514     *
1515     * @param values List of values
1516     * @return {@link Map} where each key and value pair is from the list of values
1517     */

1518    public static Map listToMap(List values) {
1519        Map valueMap = new HashMap();
1520
1521        if (values != null && values.size() > 0) {
1522            Iterator valueIterator = values.iterator();
1523            Object JavaDoc value;
1524            while (valueIterator.hasNext()) {
1525                value = valueIterator.next();
1526                if (value != null) {
1527                    valueMap.put(value, value);
1528                }
1529            }
1530        }
1531
1532        return valueMap;
1533    }
1534
1535    /**
1536     * Return a comma-separated list of Strings as a {@link List}; trims space around value
1537     *
1538     * @param valuesAsString Comma-separated values
1539     * @return Comma-separated list of Strings as a {@link List}
1540     */

1541    public static List csvToList(String JavaDoc valuesAsString) {
1542        String JavaDoc[] values = parseOnlyCommaList(valuesAsString);
1543        ArrayList updated = new ArrayList();
1544        for (int i = 0; i < values.length; i++) {
1545            String JavaDoc value = values[i].trim();
1546            updated.add(value);
1547        }
1548
1549        return updated;
1550    }
1551
1552    /**
1553     * Construct a blog base URL from the request
1554     *
1555     * @param httpServletRequest Request
1556     * @return URL of the form <code>http://server:port/context_path</code>
1557     */

1558    public static String JavaDoc constructBaseURL(HttpServletRequest JavaDoc httpServletRequest) {
1559        StringBuffer JavaDoc result = new StringBuffer JavaDoc();
1560
1561        result.append(httpServletRequest.getScheme()).append("://");
1562        result.append(httpServletRequest.getServerName());
1563        if (httpServletRequest.getServerPort() != 80) {
1564            result.append(":").append(httpServletRequest.getServerPort());
1565        }
1566        result.append(httpServletRequest.getContextPath());
1567
1568        return result.toString();
1569    }
1570
1571    /**
1572     * Construct a blog URL from the request
1573     *
1574     * @param httpServletRequest Request
1575     * @param blogID Blog ID
1576     * @return URL of the form <code>http://server:port/context_path/servlet_path/blog_id/</code>
1577     */

1578    public static String JavaDoc constructBlogURL(HttpServletRequest JavaDoc httpServletRequest, String JavaDoc blogID) {
1579        StringBuffer JavaDoc result = new StringBuffer JavaDoc(constructBaseURL(httpServletRequest));
1580
1581        result.append(httpServletRequest.getServletPath()).append("/").append(blogID);
1582
1583        return result.toString();
1584    }
1585
1586    /**
1587     * Return a digested string of some content
1588     *
1589     * @param content Content from which to generate a hashed digest
1590     * @return {@link BlojsomUtils#digestString(String)}
1591     */

1592    public static String JavaDoc getHashableContent(String JavaDoc content) {
1593        String JavaDoc hashable = content;
1594
1595        if (content.length() > MAX_HASHABLE_LENGTH) {
1596            hashable = hashable.substring(0, MAX_HASHABLE_LENGTH);
1597        }
1598
1599        return digestString(hashable).toUpperCase();
1600    }
1601
1602    /**
1603     * Return a filename appropriate for the blog entry content
1604     *
1605     * @param title Blog entry title
1606     * @param content Blog entry content
1607     * @return Filename for the new blog entry
1608     */

1609    public static String JavaDoc getPostSlug(String JavaDoc title, String JavaDoc content) {
1610        String JavaDoc slug;
1611
1612        if (!checkNullOrBlank(title)) {
1613            slug = title.replaceAll("\\s", "_");
1614            slug = slug.replaceAll("'", "");
1615            slug = slug.replaceAll("\\p{Punct}", "_");
1616            slug = slug.replaceAll("_{2,}", "_");
1617            slug = slug.replaceAll("_", "-");
1618            String JavaDoc backup = slug;
1619            slug = slug.replaceAll("^-{1,}", "");
1620            slug = slug.replaceAll("-{1,}$", "");
1621            if (checkNullOrBlank(slug)) {
1622                slug = backup;
1623            }
1624        } else {
1625            slug = getHashableContent(content);
1626        }
1627
1628        return slug;
1629    }
1630
1631    /**
1632     * Create a {@link Locale} object from a string of form <code>language_country_variant</code>
1633     *
1634     * @param locale Locale string of form <code>language_country_variant</code>
1635     * @return {@link Locale} object with language, country, variant settings or {@link java.util.Locale#getDefault()}
1636     * if <code>locale</code> input is <code>null</code> or blank
1637     */

1638    public static Locale getLocaleFromString(String JavaDoc locale) {
1639        if (checkNullOrBlank(locale)) {
1640            return Locale.getDefault();
1641        }
1642
1643        String JavaDoc language = locale;
1644        String JavaDoc country = "";
1645        String JavaDoc variant = "";
1646
1647        // Check for language
1648
int index = language.indexOf('_');
1649        if (index >= 0) {
1650            country = language.substring(index + 1);
1651            language = language.substring(0, index);
1652        }
1653
1654        // Check for country and variant
1655
index = country.indexOf('_');
1656        if (index >= 0) {
1657            variant = country.substring(index + 1);
1658            country = country.substring(0, index);
1659        }
1660
1661        return new Locale(language, country, variant);
1662    }
1663
1664    /**
1665     * Return of a list of locale languages supported on this system (JVM)
1666     *
1667     * @param locale {@link Locale} used for sorting
1668     * @return List of locale languages supported on this system (JVM)
1669     */

1670    public static String JavaDoc[] getLanguagesForSystem(Locale locale) {
1671        Locale[] installedLocales = Locale.getAvailableLocales();
1672        ArrayList languageList = new ArrayList(installedLocales.length);
1673        String JavaDoc[] languages;
1674        String JavaDoc language;
1675
1676        for (int i = 0; i < installedLocales.length; i++) {
1677            Locale installedLocale = installedLocales[i];
1678            language = installedLocale.getLanguage();
1679            if (!languageList.contains(language) && !checkNullOrBlank(language)) {
1680                languageList.add(language);
1681            }
1682        }
1683
1684        languages = (String JavaDoc[]) languageList.toArray(new String JavaDoc[languageList.size()]);
1685        Collator JavaDoc collator = Collator.getInstance(locale);
1686        Arrays.sort(languages, collator);
1687
1688        return languages;
1689    }
1690
1691    /**
1692     * Return of a list of locale countries supported on this system (JVM)
1693     *
1694     * @param locale {@link Locale} used for sorting
1695     * @return Return of a list of locale countries supported on this system (JVM)
1696     */

1697    public static String JavaDoc[] getCountriesForSystem(Locale locale) {
1698        Locale[] installedLocales = Locale.getAvailableLocales();
1699        ArrayList countryList = new ArrayList(installedLocales.length);
1700        String JavaDoc[] countries;
1701        String JavaDoc country;
1702
1703        for (int i = 0; i < installedLocales.length; i++) {
1704            Locale installedLocale = installedLocales[i];
1705            country = installedLocale.getCountry();
1706            if (!countryList.contains(country) && !checkNullOrBlank(country)) {
1707                countryList.add(country);
1708            }
1709        }
1710
1711        countries = (String JavaDoc[]) countryList.toArray(new String JavaDoc[countryList.size()]);
1712        Collator JavaDoc collator = Collator.getInstance(locale);
1713        Arrays.sort(countries, collator);
1714
1715        return countries;
1716    }
1717
1718    /**
1719     * Return of a list of time zone IDs supported on this system (JVM)
1720     *
1721     * @param locale {@link Locale} used for sorting
1722     * @return Return of a list of time zone IDs supported on this system (JVM)
1723     */

1724    public static String JavaDoc[] getTimeZonesForSystem(Locale locale) {
1725        String JavaDoc[] timezones = TimeZone.getAvailableIDs();
1726
1727        Collator JavaDoc collator = Collator.getInstance(locale);
1728        Arrays.sort(timezones, collator);
1729
1730        return timezones;
1731    }
1732
1733    /**
1734     * List the files in a sub-directory of a given directory and strip the parent directory from the path
1735     * of the files added to the list.
1736     *
1737     * @param directory Sub-directory to start looking for files
1738     * @param parentDirectory Parent directory to strip
1739     * @param files List of files to add to
1740     */

1741    public static void listFilesInSubdirectories(File directory, String JavaDoc parentDirectory, List files) {
1742        if (directory.isDirectory()) {
1743            String JavaDoc[] children = directory.list();
1744            for (int i = 0; i < children.length; i++) {
1745                listFilesInSubdirectories(new File(directory, children[i]), parentDirectory, files);
1746            }
1747        } else {
1748            if (directory.getPath().startsWith(parentDirectory)) {
1749                files.add(new File(directory.getPath().substring(parentDirectory.length() + 1)));
1750            }
1751        }
1752    }
1753
1754    /**
1755     * List the sub-directories in a sub-directory of a given directory and strip the parent directory from the path
1756     * of the directories added to the list.
1757     *
1758     * @param directory Sub-directory to start looking for files
1759     * @param parentDirectory Parent directory to strip
1760     * @param directories List of directories to add to
1761     */

1762    public static void listDirectoriesInSubdirectories(File directory, String JavaDoc parentDirectory, List directories) {
1763        if (directory.isDirectory()) {
1764            String JavaDoc[] children = directory.list();
1765            for (int i = 0; i < children.length; i++) {
1766                listDirectoriesInSubdirectories(new File(directory, children[i]), parentDirectory, directories);
1767            }
1768
1769            if (directory.getPath().startsWith(parentDirectory)) {
1770                directories.add(new File(directory.getPath().substring(parentDirectory.length())));
1771            }
1772        }
1773    }
1774
1775    /**
1776     * Strip all HTML from a given piece of text
1777     *
1778     * @param text Text
1779     * @return text stripped of HTML between &lt; and &gt; tags or <code>null</code> if input was null or blank if input was blank
1780     */

1781    public static String JavaDoc stripHTML(String JavaDoc text) {
1782        if (checkNullOrBlank(text)) {
1783            return text;
1784        }
1785
1786        Matcher JavaDoc m = STRIP_HTML_PATTERN.matcher(text);
1787        
1788        return m.replaceAll("");
1789   }
1790
1791    /**
1792     * Convert a <code>String[]</code> to a <code>List</code>
1793     *
1794     * @param input <code>String[]</code>
1795     * @return <code>List</code> from string array
1796     */

1797    public static List arrayToList(String JavaDoc[] input) {
1798        if (input == null || input.length == 0) {
1799            return new ArrayList();
1800        } else {
1801            ArrayList value = new ArrayList(input.length);
1802
1803            for (int i = 0; i < input.length; i++) {
1804                String JavaDoc s = input[i];
1805                value.add(s);
1806            }
1807
1808            return value;
1809        }
1810    }
1811
1812    /**
1813     * Remove <code>null</code> values from a given list
1814     *
1815     * @param input List
1816     * @return List with <code>null</code> values removed
1817     */

1818    public static List removeNullValues(List input) {
1819        if (input == null) {
1820            return new ArrayList();
1821        } else {
1822            ArrayList sanitizedList = new ArrayList(input.size());
1823
1824            for (int i = 0; i < input.size(); i++) {
1825                if (input.get(i) != null) {
1826                    sanitizedList.add(input.get(i));
1827                }
1828            }
1829
1830            return sanitizedList;
1831        }
1832    }
1833
1834    /**
1835     * Add preceeding and trailing slashes to an input string. If input is <code>null</code> a "/" is returned.
1836     *
1837     * @param input Input
1838     * @return Input with preceeding and trailing slashes added
1839     */

1840    public static String JavaDoc addSlashes(String JavaDoc input) {
1841        if (input == null) {
1842            return "/";
1843        }
1844
1845        if (!input.startsWith("/")) {
1846            input = "/" + input;
1847        }
1848
1849        if (!input.endsWith("/")) {
1850            input += "/";
1851        }
1852
1853        return input;
1854    }
1855
1856    /**
1857     * Add a trailing slash to the input
1858     *
1859     * @param input Input
1860     * @return Input with trailing slash added
1861     */

1862    public static String JavaDoc addTrailingSlash(String JavaDoc input) {
1863        if (input == null) {
1864            return "/";
1865        }
1866
1867        if (!input.endsWith("/")) {
1868            input += "/";
1869        }
1870
1871        return input;
1872    }
1873
1874    /**
1875     * Check to see if the blog base URL or blog URL are present. If not, construct them dynamically by calling
1876     * {@link #constructBaseURL(javax.servlet.http.HttpServletRequest)} and {@link #constructBlogURL(javax.servlet.http.HttpServletRequest, String)}.
1877     *
1878     * @param httpServletRequest Request
1879     * @param blog {@link org.blojsom.blog.Blog}
1880     * @param blogID Blog ID
1881     */

1882    public static void resolveDynamicBaseAndBlogURL(HttpServletRequest JavaDoc httpServletRequest, Blog blog, String JavaDoc blogID) {
1883        if (checkNullOrBlank(blog.getBlogBaseURL())) {
1884            blog.setBlogBaseURL(constructBaseURL(httpServletRequest));
1885        }
1886
1887        if (checkNullOrBlank(blog.getBlogURL())) {
1888            blog.setBlogURL(constructBlogURL(httpServletRequest, blogID));
1889        }
1890
1891        if (checkNullOrBlank(blog.getBlogAdminURL())) {
1892            blog.setBlogAdminURL(constructBlogURL(httpServletRequest, blogID));
1893        }
1894
1895        if (checkNullOrBlank(blog.getBlogBaseAdminURL())) {
1896            blog.setBlogBaseAdminURL(constructBaseURL(httpServletRequest));
1897        }
1898    }
1899
1900    /**
1901     * Return a {@link List} as a string
1902     *
1903     * @param values {@link List} of values
1904     * @param separator Separator in-between values
1905     * @return {@link List} as a string where each item is separated by the <code>separator</code>
1906     */

1907    public static String JavaDoc listToString(List values, String JavaDoc separator) {
1908        StringBuffer JavaDoc valuesAsString = new StringBuffer JavaDoc();
1909
1910        if (values != null && values.size() > 0) {
1911            for (int i = 0; i < values.size(); i++) {
1912                String JavaDoc value = (String JavaDoc) values.get(i);
1913                valuesAsString.append(value);
1914                if (i < values.size() - 1) {
1915                    valuesAsString.append(separator);
1916                }
1917            }
1918        }
1919
1920        return valuesAsString.toString();
1921    }
1922
1923    public static Comparator RESPONSE_COMPARATOR = new Comparator() {
1924        public int compare(Object JavaDoc object, Object JavaDoc object1) {
1925            if (object instanceof Response && object1 instanceof Response) {
1926                Response obj = (Response) object;
1927                Response obj1 = (Response) object1;
1928
1929                if (obj.getDate().before(obj1.getDate())) {
1930                    return -1;
1931                } else if (obj.getDate().after(obj1.getDate())) {
1932                    return 1;
1933                }
1934            }
1935
1936            return 0;
1937        }
1938    };
1939
1940    /**
1941     * Find the first date of a year
1942     *
1943     * @param locale Locale
1944     * @param year Year
1945     * @return First date of the requested year
1946     */

1947    public static Date getFirstDateOfYear(Locale locale, int year) {
1948        Calendar calendar = Calendar.getInstance(locale);
1949
1950        calendar.set(Calendar.YEAR, year);
1951        calendar.set(Calendar.MONTH, calendar.getActualMinimum(Calendar.MONTH));
1952        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMinimum(Calendar.DAY_OF_MONTH));
1953        calendar.set(Calendar.HOUR_OF_DAY, calendar.getActualMinimum(Calendar.HOUR_OF_DAY));
1954        calendar.set(Calendar.MINUTE, calendar.getActualMinimum(Calendar.MINUTE));
1955        calendar.set(Calendar.SECOND, calendar.getActualMinimum(Calendar.SECOND));
1956        calendar.set(Calendar.MILLISECOND, calendar.getActualMinimum(Calendar.MILLISECOND));
1957
1958        return calendar.getTime();
1959    }
1960
1961    /**
1962     * Find the last date of a year
1963     *
1964     * @param locale Locale
1965     * @param year Year
1966     * @return Last date of the requested year
1967     */

1968    public static Date getLastDateOfYear(Locale locale, int year) {
1969        Calendar calendar = Calendar.getInstance(locale);
1970
1971        calendar.set(Calendar.YEAR, year);
1972        calendar.set(Calendar.MONTH, calendar.getActualMaximum(Calendar.MONTH));
1973        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
1974        calendar.set(Calendar.HOUR_OF_DAY, calendar.getActualMaximum(Calendar.HOUR_OF_DAY));
1975        calendar.set(Calendar.MINUTE, calendar.getActualMaximum(Calendar.MINUTE));
1976        calendar.set(Calendar.SECOND, calendar.getActualMaximum(Calendar.SECOND));
1977        calendar.set(Calendar.MILLISECOND, calendar.getActualMaximum(Calendar.MILLISECOND));
1978
1979        return calendar.getTime();
1980    }
1981
1982    /**
1983     * Find the first date of a year/month
1984     *
1985     * @param locale Locale
1986     * @param year Year
1987     * @param month Month
1988     * @return FIrst date of the requested year/month
1989     */

1990    public static Date getFirstDateOfYearMonth(Locale locale, int year, int month) {
1991        Calendar calendar = Calendar.getInstance(locale);
1992
1993        calendar.set(Calendar.YEAR, year);
1994        calendar.set(Calendar.MONTH, month);
1995        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMinimum(Calendar.DAY_OF_MONTH));
1996        calendar.set(Calendar.HOUR_OF_DAY, calendar.getActualMinimum(Calendar.HOUR_OF_DAY));
1997        calendar.set(Calendar.MINUTE, calendar.getActualMinimum(Calendar.MINUTE));
1998        calendar.set(Calendar.SECOND, calendar.getActualMinimum(Calendar.SECOND));
1999        calendar.set(Calendar.MILLISECOND, calendar.getActualMinimum(Calendar.MILLISECOND));
2000
2001        return calendar.getTime();
2002    }
2003
2004    /**
2005     * Find the last date of a year/month
2006     *
2007     * @param locale Locale
2008     * @param year Year
2009     * @param month Month
2010     * @return Last date of the requested year/month
2011     */

2012    public static Date getLastDateOfYearMonth(Locale locale, int year, int month) {
2013        Calendar calendar = Calendar.getInstance(locale);
2014
2015        calendar.set(Calendar.YEAR, year);
2016        calendar.set(Calendar.MONTH, month);
2017        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
2018        calendar.set(Calendar.HOUR_OF_DAY, calendar.getActualMaximum(Calendar.HOUR_OF_DAY));
2019        calendar.set(Calendar.MINUTE, calendar.getActualMaximum(Calendar.MINUTE));
2020        calendar.set(Calendar.SECOND, calendar.getActualMaximum(Calendar.SECOND));
2021        calendar.set(Calendar.MILLISECOND, calendar.getActualMaximum(Calendar.MILLISECOND));
2022
2023        return calendar.getTime();
2024    }
2025
2026    /**
2027     * Get the first date of a year/month/day
2028     *
2029     * @param locale Locale
2030     * @param year Year
2031     * @param month Month
2032     * @param day Day
2033     * @return First date of the requested year/month/day
2034     */

2035    public static Date getFirstDateOfYearMonthDay(Locale locale, int year, int month, int day) {
2036        Calendar calendar = Calendar.getInstance(locale);
2037
2038        calendar.set(Calendar.YEAR, year);
2039        calendar.set(Calendar.MONTH, month);
2040        if (day < calendar.getActualMinimum(Calendar.DAY_OF_MONTH)) {
2041            calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMinimum(Calendar.DAY_OF_MONTH));
2042        } else {
2043            calendar.set(Calendar.DAY_OF_MONTH, day);
2044        }
2045        calendar.set(Calendar.HOUR_OF_DAY, calendar.getActualMinimum(Calendar.HOUR_OF_DAY));
2046        calendar.set(Calendar.MINUTE, calendar.getActualMinimum(Calendar.MINUTE));
2047        calendar.set(Calendar.SECOND, calendar.getActualMinimum(Calendar.SECOND));
2048        calendar.set(Calendar.MILLISECOND, calendar.getActualMinimum(Calendar.MILLISECOND));
2049
2050        return calendar.getTime();
2051    }
2052
2053    /**
2054     * Get the last date of a year/month/day
2055     *
2056     * @param locale Locale
2057     * @param year Year
2058     * @param month Month
2059     * @param day Day
2060     * @return Last date of the requested year/month/day
2061     */

2062    public static Date getLastDateOfYearMonthDay(Locale locale, int year, int month, int day) {
2063        Calendar calendar = Calendar.getInstance(locale);
2064
2065        calendar.set(Calendar.YEAR, year);
2066        calendar.set(Calendar.MONTH, month);
2067        if (day > calendar.getActualMaximum(Calendar.DAY_OF_MONTH)) {
2068            calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
2069        } else {
2070            calendar.set(Calendar.DAY_OF_MONTH, day);
2071        }
2072        calendar.set(Calendar.HOUR_OF_DAY, calendar.getActualMaximum(Calendar.HOUR_OF_DAY));
2073        calendar.set(Calendar.MINUTE, calendar.getActualMaximum(Calendar.MINUTE));
2074        calendar.set(Calendar.SECOND, calendar.getActualMaximum(Calendar.SECOND));
2075        calendar.set(Calendar.MILLISECOND, calendar.getActualMaximum(Calendar.MILLISECOND));
2076
2077        return calendar.getTime();
2078    }
2079}
2080
Popular Tags