Source code: org/roller/util/Utilities.java
1 package org.roller.util;
2
3 import org.apache.commons.lang.StringUtils;
4 import org.apache.commons.logging.Log;
5 import org.apache.commons.logging.LogFactory;
6
7 import java.io.BufferedInputStream;
8 import java.io.BufferedOutputStream;
9 import java.io.File;
10 import java.io.FileInputStream;
11 import java.io.FileOutputStream;
12 import java.io.IOException;
13 import java.io.InputStream;
14 import java.io.OutputStream;
15 import java.security.MessageDigest;
16 import java.util.Date;
17 import java.util.NoSuchElementException;
18 import java.util.StringTokenizer;
19
20
21 /**
22 * General purpose utilities.
23 * @author David M Johnson
24 * @author Lance Lavandowska
25 * @author Matt Raible (added encryption methods)
26 */
27 public class Utilities
28 {
29 /**
30 * The <code>Log</code> instance for this class.
31 */
32 private static Log log = LogFactory.getLog(Utilities.class);
33
34 /**
35 * Utility methods for calling StringUtils since it cannot be
36 * instantiated and Utilties can.
37 */
38 public static boolean isNotEmpty(String str)
39 {
40 return StringUtils.isNotEmpty(str);
41 }
42
43 //------------------------------------------------------------------------
44 /** Strip jsessionid off of a URL */
45 public static String stripJsessionId( String url )
46 {
47 // Strip off jsessionid found in referer URL
48 int startPos = url.indexOf(";jsessionid=");
49 if ( startPos != -1 )
50 {
51 int endPos = url.indexOf("?",startPos);
52 if ( endPos == -1 )
53 {
54 url = url.substring(0,startPos);
55 }
56 else
57 {
58 url = url.substring(0,startPos)
59 + url.substring(endPos,url.length());
60 }
61 }
62 return url;
63 }
64
65 //------------------------------------------------------------------------
66 /**
67 * Escape, but do not replace HTML.
68 * The default behaviour is to escape ampersands.
69 */
70 public static String escapeHTML(String s)
71 {
72 return escapeHTML(s, true);
73 }
74
75 //------------------------------------------------------------------------
76 /**
77 * Escape, but do not replace HTML.
78 * @param escapseAmpersand Optionally escape
79 * ampersands (&).
80 */
81 public static String escapeHTML(String s, boolean escapeAmpersand)
82 {
83 // got to do amp's first so we don't double escape
84 if (escapeAmpersand)
85 {
86 s = stringReplace(s, "&", "&");
87 }
88 s = stringReplace(s, " ", " ");
89 s = stringReplace(s, "\"", """);
90 s = stringReplace(s, "<", "<");
91 s = stringReplace(s, ">", ">");
92 return s;
93 }
94
95 //------------------------------------------------------------------------
96 /**
97 * Remove occurences of html, defined as any text
98 * between the characters "<" and ">".
99 */
100 public static String removeHTML(String str)
101 {
102 if (str == null) return "";
103 StringBuffer ret = new StringBuffer(str.length());
104 int start = 0;
105 int beginTag = str.indexOf("<");
106 int endTag = 0;
107 if (beginTag == -1)
108 return str;
109
110 while (beginTag >= start)
111 {
112 if (beginTag > 0)
113 {
114 ret.append(str.substring(start, beginTag));
115
116 // replace each tag with a space (looks better)
117 ret.append(" ");
118 }
119 endTag = str.indexOf(">", beginTag);
120
121 // if endTag found move "cursor" forward
122 if (endTag > -1)
123 {
124 start = endTag + 1;
125 beginTag = str.indexOf("<", start);
126 }
127 // if no endTag found, get rest of str and break
128 else
129 {
130 ret.append(str.substring(beginTag));
131 break;
132 }
133 }
134 // append everything after the last endTag
135 if (endTag > -1 && endTag + 1 < str.length())
136 {
137 ret.append(str.substring(endTag + 1));
138 }
139 return ret.toString().trim();
140 }
141
142 //------------------------------------------------------------------------
143 /** Run both removeHTML and escapeHTML on a string.
144 * @param s String to be run through removeHTML and escapeHTML.
145 * @return String with HTML removed and HTML special characters escaped.
146 */
147 public static String removeAndEscapeHTML( String s )
148 {
149 if ( s==null ) return "";
150 else return Utilities.escapeHTML( Utilities.removeHTML(s) );
151 }
152
153 //------------------------------------------------------------------------
154 /**
155 * Autoformat.
156 */
157 public static String autoformat(String s)
158 {
159 String ret = StringUtils.replace(s, "\n", "<br />");
160 return ret;
161 }
162
163 //------------------------------------------------------------------------
164 /**
165 * Format date in ISO-8601 format.
166 */
167 public static String formatIso8601Date(Date d)
168 {
169 return DateUtil.formatIso8601(d);
170 }
171
172 //------------------------------------------------------------------------
173 /**
174 * Return a date in RFC-822 format.
175 */
176 public static String formatRfc822Date(Date date)
177 {
178 return DateUtil.formatRfc822(date);
179 }
180
181 //------------------------------------------------------------------------
182 /**
183 * Replaces occurences of non-alphanumeric characters with an underscore.
184 */
185 public static String replaceNonAlphanumeric(String str)
186 {
187 return replaceNonAlphanumeric(str, '_');
188 }
189
190 //------------------------------------------------------------------------
191 /**
192 * Replaces occurences of non-alphanumeric characters with a
193 * supplied char.
194 */
195 public static String replaceNonAlphanumeric(String str, char subst)
196 {
197 StringBuffer ret = new StringBuffer(str.length());
198 char[] testChars = str.toCharArray();
199 for (int i = 0; i < testChars.length; i++)
200 {
201 if (Character.isLetterOrDigit(testChars[i]))
202 {
203 ret.append(testChars[i]);
204 }
205 else
206 {
207 ret.append( subst );
208 }
209 }
210 return ret.toString();
211 }
212
213 //------------------------------------------------------------------------
214 /**
215 * Remove occurences of non-alphanumeric characters.
216 */
217 public static String removeNonAlphanumeric(String str)
218 {
219 StringBuffer ret = new StringBuffer(str.length());
220 char[] testChars = str.toCharArray();
221 for (int i = 0; i < testChars.length; i++)
222 {
223 if (Character.isLetterOrDigit(testChars[i]))
224 {
225 ret.append(testChars[i]);
226 }
227 }
228 return ret.toString();
229 }
230
231 //------------------------------------------------------------------------
232 /**
233 * Replace occurrences of str1 in string str with str2
234 */
235 public static String stringReplace(String str, String str1, String str2)
236 {
237 String ret = StringUtils.replace(str,str1,str2);
238 return ret;
239 }
240
241 //------------------------------------------------------------------------
242 /**
243 * Replace occurrences of str1 in string str with str2
244 * @param str String to operate on
245 * @param str1 String to be replaced
246 * @param str2 String to be used as replacement
247 * @param maxCount Number of times to replace, 0 for all
248 */
249 public static String stringReplace(
250 String str,
251 String str1,
252 String str2,
253 int maxCount)
254 {
255 String ret = StringUtils.replace(str,str1,str2,maxCount);
256 return ret;
257 }
258
259 //--------------------------------------------------------------------------
260 /** Convert string to string array. */
261 public static String[] stringToStringArray(String instr, String delim)
262 throws NoSuchElementException, NumberFormatException
263 {
264 StringTokenizer toker = new StringTokenizer(instr, delim);
265 String stringArray[] = new String[toker.countTokens()];
266 int i = 0;
267
268 while (toker.hasMoreTokens())
269 {
270 stringArray[i++] = toker.nextToken();
271 }
272 return stringArray;
273 }
274
275 //--------------------------------------------------------------------------
276 /** Convert string to integer array. */
277 public static int[] stringToIntArray(String instr, String delim)
278 throws NoSuchElementException, NumberFormatException
279 {
280 StringTokenizer toker = new StringTokenizer(instr, delim);
281 int intArray[] = new int[toker.countTokens()];
282 int i = 0;
283
284 while (toker.hasMoreTokens())
285 {
286 String sInt = toker.nextToken();
287 int nInt = Integer.parseInt(sInt);
288 intArray[i++] = new Integer(nInt).intValue();
289 }
290 return intArray;
291 }
292
293 //-------------------------------------------------------------------
294 /** Convert integer array to a string. */
295 public static String intArrayToString(int[] intArray)
296 {
297 String ret = new String();
298 for (int i = 0; i < intArray.length; i++)
299 {
300 if (ret.length() > 0)
301 ret = ret + "," + Integer.toString(intArray[i]);
302 else
303 ret = Integer.toString(intArray[i]);
304 }
305 return ret;
306 }
307
308 //------------------------------------------------------------------------
309 public static void copyFile(File from, File to) throws IOException
310 {
311 InputStream in = null;
312 OutputStream out = null;
313
314 try
315 {
316 in = new FileInputStream(from);
317 }
318 catch (IOException ex)
319 {
320 throw new IOException(
321 "Utilities.copyFile: opening input stream '"
322 + from.getPath()
323 + "', "
324 + ex.getMessage());
325 }
326
327 try
328 {
329 out = new FileOutputStream(to);
330 }
331 catch (Exception ex)
332 {
333 try
334 {
335 in.close();
336 }
337 catch (IOException ex1)
338 {
339 }
340 throw new IOException(
341 "Utilities.copyFile: opening output stream '"
342 + to.getPath()
343 + "', "
344 + ex.getMessage());
345 }
346
347 copyInputToOutput(in, out, from.length());
348 }
349
350 //------------------------------------------------------------------------
351 /**
352 * Utility method to copy an input stream to an output stream.
353 * Wraps both streams in buffers. Ensures right numbers of bytes copied.
354 */
355 public static void copyInputToOutput(
356 InputStream input,
357 OutputStream output,
358 long byteCount)
359 throws IOException
360 {
361 int bytes;
362 long length;
363
364 BufferedInputStream in = new BufferedInputStream(input);
365 BufferedOutputStream out = new BufferedOutputStream(output);
366
367 byte[] buffer;
368 buffer = new byte[8192];
369
370 for (length = byteCount; length > 0;)
371 {
372 bytes = (int) (length > 8192 ? 8192 : length);
373
374 try
375 {
376 bytes = in.read(buffer, 0, bytes);
377 }
378 catch (IOException ex)
379 {
380 try
381 {
382 in.close();
383 out.close();
384 }
385 catch (IOException ex1)
386 {
387 }
388 throw new IOException(
389 "Reading input stream, " + ex.getMessage());
390 }
391
392 if (bytes < 0)
393 break;
394
395 length -= bytes;
396
397 try
398 {
399 out.write(buffer, 0, bytes);
400 }
401 catch (IOException ex)
402 {
403 try
404 {
405 in.close();
406 out.close();
407 }
408 catch (IOException ex1)
409 {
410 }
411 throw new IOException(
412 "Writing output stream, " + ex.getMessage());
413 }
414 }
415
416 try
417 {
418 in.close();
419 out.close();
420 }
421 catch (IOException ex)
422 {
423 throw new IOException("Closing file streams, " + ex.getMessage());
424 }
425 }
426
427 //------------------------------------------------------------------------
428 public static void copyInputToOutput(
429 InputStream input,
430 OutputStream output)
431 throws IOException
432 {
433 BufferedInputStream in = new BufferedInputStream(input);
434 BufferedOutputStream out = new BufferedOutputStream(output);
435 byte buffer[] = new byte[8192];
436 for (int count = 0; count != -1;)
437 {
438 count = in.read(buffer, 0, 8192);
439 if (count != -1)
440 out.write(buffer, 0, count);
441 }
442
443 try
444 {
445 in.close();
446 out.close();
447 }
448 catch (IOException ex)
449 {
450 throw new IOException("Closing file streams, " + ex.getMessage());
451 }
452 }
453
454 /**
455 * Encode a string using algorithm specified in web.xml and return the
456 * resulting encrypted password. If exception, the plain credentials
457 * string is returned
458 *
459 * @param password Password or other credentials to use in authenticating
460 * this username
461 * @param algorithm Algorithm used to do the digest
462 *
463 * @return encypted password based on the algorithm.
464 */
465 public static String encodePassword(String password, String algorithm)
466 {
467 byte[] unencodedPassword = password.getBytes();
468
469 MessageDigest md = null;
470
471 try {
472 // first create an instance, given the provider
473 md = MessageDigest.getInstance(algorithm);
474 } catch (Exception e) {
475 log.error("Exception: " + e);
476
477 return password;
478 }
479
480 md.reset();
481
482 // call the update method one or more times
483 // (useful when you don't know the size of your data, eg. stream)
484 md.update(unencodedPassword);
485
486 // now calculate the hash
487 byte[] encodedPassword = md.digest();
488
489 StringBuffer buf = new StringBuffer();
490
491 for (int i = 0; i < encodedPassword.length; i++) {
492 if (((int) encodedPassword[i] & 0xff) < 0x10) {
493 buf.append("0");
494 }
495
496 buf.append(Long.toString((int) encodedPassword[i] & 0xff, 16));
497 }
498
499 return buf.toString();
500 }
501
502 /**
503 * Encode a string using Base64 encoding. Used when storing passwords
504 * as cookies.
505 *
506 * This is weak encoding in that anyone can use the decodeString
507 * routine to reverse the encoding.
508 *
509 * @param str
510 * @return String
511 * @throws IOException
512 */
513 public static String encodeString(String str) throws IOException
514 {
515 sun.misc.BASE64Encoder encoder = new sun.misc.BASE64Encoder();
516 String encodedStr = new String(encoder.encodeBuffer(str.getBytes()));
517
518 return (encodedStr.trim());
519 }
520
521 /**
522 * Decode a string using Base64 encoding.
523 *
524 * @param str
525 * @return String
526 * @throws IOException
527 */
528 public static String decodeString(String str) throws IOException
529 {
530 sun.misc.BASE64Decoder dec = new sun.misc.BASE64Decoder();
531 String value = new String(dec.decodeBuffer(str));
532
533 return (value);
534 }
535 }