KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jivesoftware > whack > util > StringUtils


1 /**
2  * $RCSfile: StringUtils.java,v $
3  * $Revision: 1.1 $
4  * $Date: 2005/02/06 20:04:40 $
5  *
6  * Copyright 2003-2004 Jive Software.
7  *
8  * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */

20
21 package org.jivesoftware.whack.util;
22
23 import java.io.UnsupportedEncodingException JavaDoc;
24 import java.security.MessageDigest JavaDoc;
25 import java.security.NoSuchAlgorithmException JavaDoc;
26 import java.util.Random JavaDoc;
27
28 /**
29  * A collection of utility methods for String objects.
30  */

31 public class StringUtils {
32
33     private static final char[] QUOTE_ENCODE = """.toCharArray();
34     private static final char[] AMP_ENCODE = "&".toCharArray();
35     private static final char[] LT_ENCODE = "<".toCharArray();
36     private static final char[] GT_ENCODE = ">".toCharArray();
37
38     /**
39      * Returns the name portion of a XMPP address. For example, for the
40      * address "matt@jivesoftware.com/Smack", "matt" would be returned. If no
41      * username is present in the address, the empty string will be returned.
42      *
43      * @param XMPPAddress the XMPP address.
44      * @return the name portion of the XMPP address.
45      */

46     public static String JavaDoc parseName(String JavaDoc XMPPAddress) {
47         if (XMPPAddress == null) {
48             return null;
49         }
50         int atIndex = XMPPAddress.indexOf("@");
51         if (atIndex <= 0) {
52             return "";
53         }
54         else {
55             return XMPPAddress.substring(0, atIndex);
56         }
57     }
58
59     /**
60      * Returns the server portion of a XMPP address. For example, for the
61      * address "matt@jivesoftware.com/Smack", "jivesoftware.com" would be returned.
62      * If no server is present in the address, the empty string will be returned.
63      *
64      * @param XMPPAddress the XMPP address.
65      * @return the server portion of the XMPP address.
66      */

67     public static String JavaDoc parseServer(String JavaDoc XMPPAddress) {
68         if (XMPPAddress == null) {
69             return null;
70         }
71         int atIndex = XMPPAddress.indexOf("@");
72         // If the String ends with '@', return the empty string.
73
if (atIndex + 1 > XMPPAddress.length()) {
74             return "";
75         }
76         int slashIndex = XMPPAddress.indexOf("/");
77         if (slashIndex > 0) {
78             return XMPPAddress.substring(atIndex + 1, slashIndex);
79         }
80         else {
81             return XMPPAddress.substring(atIndex + 1);
82         }
83     }
84
85     /**
86      * Returns the resource portion of a XMPP address. For example, for the
87      * address "matt@jivesoftware.com/Smack", "Smack" would be returned. If no
88      * resource is present in the address, the empty string will be returned.
89      *
90      * @param XMPPAddress the XMPP address.
91      * @return the resource portion of the XMPP address.
92      */

93     public static String JavaDoc parseResource(String JavaDoc XMPPAddress) {
94         if (XMPPAddress == null) {
95             return null;
96         }
97         int slashIndex = XMPPAddress.indexOf("/");
98         if (slashIndex + 1 > XMPPAddress.length() || slashIndex < 0) {
99             return "";
100         }
101         else {
102             return XMPPAddress.substring(slashIndex + 1);
103         }
104     }
105
106     /**
107      * Returns the XMPP address with any resource information removed. For example,
108      * for the address "matt@jivesoftware.com/Smack", "matt@jivesoftware.com" would
109      * be returned.
110      *
111      * @param XMPPAddress the XMPP address.
112      * @return the bare XMPP address without resource information.
113      */

114     public static String JavaDoc parseBareAddress(String JavaDoc XMPPAddress) {
115         if (XMPPAddress == null) {
116             return null;
117         }
118         int slashIndex = XMPPAddress.indexOf("/");
119         if (slashIndex < 0) {
120             return XMPPAddress;
121         }
122         else if (slashIndex == 0) {
123             return "";
124         }
125         else {
126             return XMPPAddress.substring(0, slashIndex);
127         }
128     }
129
130     /**
131      * Escapes all necessary characters in the String so that it can be used
132      * in an XML doc.
133      *
134      * @param string the string to escape.
135      * @return the string with appropriate characters escaped.
136      */

137     public static final String JavaDoc escapeForXML(String JavaDoc string) {
138         if (string == null) {
139             return null;
140         }
141         char ch;
142         int i=0;
143         int last=0;
144         char[] input = string.toCharArray();
145         int len = input.length;
146         StringBuffer JavaDoc out = new StringBuffer JavaDoc((int)(len*1.3));
147         for (; i < len; i++) {
148             ch = input[i];
149             if (ch > '>') {
150                 continue;
151             }
152             else if (ch == '<') {
153                 if (i > last) {
154                     out.append(input, last, i - last);
155                 }
156                 last = i + 1;
157                 out.append(LT_ENCODE);
158             }
159             else if (ch == '>') {
160                 if (i > last) {
161                     out.append(input, last, i - last);
162                 }
163                 last = i + 1;
164                 out.append(GT_ENCODE);
165             }
166
167             else if (ch == '&') {
168                 if (i > last) {
169                     out.append(input, last, i - last);
170                 }
171                 // Do nothing if the string is of the form &#235; (unicode value)
172
if (!(len > i + 5
173                     && input[i + 1] == '#'
174                     && Character.isDigit(input[i + 2])
175                     && Character.isDigit(input[i + 3])
176                     && Character.isDigit(input[i + 4])
177                     && input[i + 5] == ';')) {
178                         last = i + 1;
179                         out.append(AMP_ENCODE);
180                     }
181             }
182             else if (ch == '"') {
183                 if (i > last) {
184                     out.append(input, last, i - last);
185                 }
186                 last = i + 1;
187                 out.append(QUOTE_ENCODE);
188             }
189         }
190         if (last == 0) {
191             return string;
192         }
193         if (i > last) {
194             out.append(input, last, i - last);
195         }
196         return out.toString();
197     }
198
199     /**
200      * Used by the hash method.
201      */

202     private static MessageDigest JavaDoc digest = null;
203
204     /**
205      * Hashes a String using the SHA-1 algorithm and returns the result as a
206      * String of hexadecimal numbers. This method is synchronized to avoid
207      * excessive MessageDigest object creation. If calling this method becomes
208      * a bottleneck in your code, you may wish to maintain a pool of
209      * MessageDigest objects instead of using this method.
210      * <p>
211      * A hash is a one-way function -- that is, given an
212      * input, an output is easily computed. However, given the output, the
213      * input is almost impossible to compute. This is useful for passwords
214      * since we can store the hash and a hacker will then have a very hard time
215      * determining the original password.
216      *
217      * @param data the String to compute the hash of.
218      * @return a hashed version of the passed-in String
219      */

220     public synchronized static final String JavaDoc hash(String JavaDoc data) {
221         if (digest == null) {
222             try {
223                 digest = MessageDigest.getInstance("SHA-1");
224             }
225             catch (NoSuchAlgorithmException JavaDoc nsae) {
226                 System.err.println("Failed to load the SHA-1 MessageDigest. " +
227                 "Jive will be unable to function normally.");
228             }
229         }
230         // Now, compute hash.
231
try {
232             digest.update(data.getBytes("UTF-8"));
233         }
234         catch (UnsupportedEncodingException JavaDoc e) {
235             System.err.println(e);
236         }
237         return encodeHex(digest.digest());
238     }
239
240     /**
241      * Turns an array of bytes into a String representing each byte as an
242      * unsigned hex number.
243      * <p>
244      * Method by Santeri Paavolainen, Helsinki Finland 1996<br>
245      * (c) Santeri Paavolainen, Helsinki Finland 1996<br>
246      * Distributed under LGPL.
247      *
248      * @param bytes an array of bytes to convert to a hex-string
249      * @return generated hex string
250      */

251     public static final String JavaDoc encodeHex(byte[] bytes) {
252         StringBuffer JavaDoc buf = new StringBuffer JavaDoc(bytes.length * 2);
253         int i;
254
255         for (i = 0; i < bytes.length; i++) {
256             if (((int) bytes[i] & 0xff) < 0x10) {
257                 buf.append("0");
258             }
259             buf.append(Long.toString((int) bytes[i] & 0xff, 16));
260         }
261         return buf.toString();
262     }
263
264     //*********************************************************************
265
//* Base64 - a simple base64 encoder and decoder.
266
//*
267
//* Copyright (c) 1999, Bob Withers - bwit@pobox.com
268
//*
269
//* This code may be freely used for any purpose, either personal
270
//* or commercial, provided the authors copyright notice remains
271
//* intact.
272
//*********************************************************************
273

274     private static final int fillchar = '=';
275     private static final String JavaDoc cvt = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
276                                     + "0123456789+/";
277
278     /**
279      * Encodes a String as a base64 String.
280      *
281      * @param data a String to encode.
282      * @return a base64 encoded String.
283      */

284     public static String JavaDoc encodeBase64(String JavaDoc data) {
285         byte [] bytes = null;
286         try {
287             bytes = data.getBytes("ISO-8859-1");
288         }
289         catch (UnsupportedEncodingException JavaDoc uee) {
290             uee.printStackTrace();
291         }
292         return encodeBase64(bytes);
293     }
294
295     /**
296      * Encodes a byte array into a base64 String.
297      *
298      * @param data a byte array to encode.
299      * @return a base64 encode String.
300      */

301     public static String JavaDoc encodeBase64(byte[] data) {
302         int c;
303         int len = data.length;
304         StringBuffer JavaDoc ret = new StringBuffer JavaDoc(((len / 3) + 1) * 4);
305         for (int i = 0; i < len; ++i) {
306             c = (data[i] >> 2) & 0x3f;
307             ret.append(cvt.charAt(c));
308             c = (data[i] << 4) & 0x3f;
309             if (++i < len)
310                 c |= (data[i] >> 4) & 0x0f;
311
312             ret.append(cvt.charAt(c));
313             if (i < len) {
314                 c = (data[i] << 2) & 0x3f;
315                 if (++i < len)
316                     c |= (data[i] >> 6) & 0x03;
317
318                 ret.append(cvt.charAt(c));
319             }
320             else {
321                 ++i;
322                 ret.append((char) fillchar);
323             }
324
325             if (i < len) {
326                 c = data[i] & 0x3f;
327                 ret.append(cvt.charAt(c));
328             }
329             else {
330                 ret.append((char) fillchar);
331             }
332         }
333         return ret.toString();
334     }
335
336     /**
337      * Decodes a base64 String.
338      *
339      * @param data a base64 encoded String to decode.
340      * @return the decoded String.
341      */

342     public static byte[] decodeBase64(String JavaDoc data) {
343         byte [] bytes = null;
344         try {
345             bytes = data.getBytes("ISO-8859-1");
346             return decodeBase64(bytes).getBytes("ISO-8859-1");
347         }
348         catch (UnsupportedEncodingException JavaDoc uee) {
349             uee.printStackTrace();
350         }
351         return new byte[] { };
352     }
353
354     /**
355      * Decodes a base64 aray of bytes.
356      *
357      * @param data a base64 encode byte array to decode.
358      * @return the decoded String.
359      */

360     private static String JavaDoc decodeBase64(byte[] data) {
361         int c, c1;
362         int len = data.length;
363         StringBuffer JavaDoc ret = new StringBuffer JavaDoc((len * 3) / 4);
364         for (int i = 0; i < len; ++i) {
365             c = cvt.indexOf(data[i]);
366             ++i;
367             c1 = cvt.indexOf(data[i]);
368             c = ((c << 2) | ((c1 >> 4) & 0x3));
369             ret.append((char) c);
370             if (++i < len) {
371                 c = data[i];
372                 if (fillchar == c)
373                     break;
374
375                 c = cvt.indexOf(c);
376                 c1 = ((c1 << 4) & 0xf0) | ((c >> 2) & 0xf);
377                 ret.append((char) c1);
378             }
379
380             if (++i < len) {
381                 c1 = data[i];
382                 if (fillchar == c1)
383                     break;
384
385                 c1 = cvt.indexOf(c1);
386                 c = ((c << 6) & 0xc0) | c1;
387                 ret.append((char) c);
388             }
389         }
390         return ret.toString();
391     }
392
393     /**
394      * Pseudo-random number generator object for use with randomString().
395      * The Random class is not considered to be cryptographically secure, so
396      * only use these random Strings for low to medium security applications.
397      */

398     private static Random JavaDoc randGen = new Random JavaDoc();
399
400     /**
401      * Array of numbers and letters of mixed case. Numbers appear in the list
402      * twice so that there is a more equal chance that a number will be picked.
403      * We can use the array to get a random number or letter by picking a random
404      * array index.
405      */

406     private static char[] numbersAndLetters = ("0123456789abcdefghijklmnopqrstuvwxyz" +
407                     "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ").toCharArray();
408
409     /**
410      * Returns a random String of numbers and letters (lower and upper case)
411      * of the specified length. The method uses the Random class that is
412      * built-in to Java which is suitable for low to medium grade security uses.
413      * This means that the output is only pseudo random, i.e., each number is
414      * mathematically generated so is not truly random.<p>
415      *
416      * The specified length must be at least one. If not, the method will return
417      * null.
418      *
419      * @param length the desired length of the random String to return.
420      * @return a random String of numbers and letters of the specified length.
421      */

422     public static final String JavaDoc randomString(int length) {
423         if (length < 1) {
424             return null;
425         }
426         // Create a char buffer to put random letters and numbers in.
427
char [] randBuffer = new char[length];
428         for (int i=0; i<randBuffer.length; i++) {
429             randBuffer[i] = numbersAndLetters[randGen.nextInt(71)];
430         }
431         return new String JavaDoc(randBuffer);
432     }
433
434     private StringUtils() {
435         // Not instantiable.
436
}
437 }
Popular Tags