001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.lib.collab.util;
043:
044: import java.io.UnsupportedEncodingException;
045: import java.lang.*;
046: import java.util.*;
047: import java.text.*;
048: import org.jabberstudio.jso.JID;
049: import org.netbeans.lib.collab.xmpp.JIDUtil;
050:
051: /**
052: * String Utility class for performing common String operations such as sort,
053: * substitution, etc...
054: *
055: */
056: public class StringUtility {
057:
058: public static final String UTIL_PROVIDER = "org.netbeans.lib.collab.xmpp.JIDUtil.Provider";
059: public static final String LEGACY_PROVIDER = "org.netbeans.lib.collab.xmpp.util.LegacyJIDUtil";
060: public static final String XEP106_PROVIDER = "org.netbeans.lib.collab.xmpp.util.XEP106JIDUtil";
061:
062: /**
063: * platform-specific line separator
064: */
065: public final static String lineSeparator = System
066: .getProperty("line.separator");
067: private final static Collator collator = Collator.getInstance();
068:
069: /**
070: *
071: *
072: * @param
073: */
074: final static public String getBooleanString(boolean b) {
075: if (b)
076: return "true";
077: return "false";
078: }
079:
080: /**
081: *
082: *
083: * @param input string
084: */
085: final static public boolean getBoolean(String str)
086: throws IllegalArgumentException {
087: if (str.equalsIgnoreCase("false") || str.equalsIgnoreCase("n")
088: || str.equalsIgnoreCase("no")
089: || str.equalsIgnoreCase("deny")
090: || str.equalsIgnoreCase("0")
091: || str.equalsIgnoreCase("off")) {
092: return false;
093: } else if (str.equalsIgnoreCase("true")
094: || str.equalsIgnoreCase("y")
095: || str.equalsIgnoreCase("yes")
096: || str.equalsIgnoreCase("allow")
097: || str.equalsIgnoreCase("1")
098: || str.equalsIgnoreCase("on")) {
099: return true;
100: } else {
101: throw new IllegalArgumentException("Not a boolean: " + str);
102: }
103: }
104:
105: /**
106: *
107: *
108: * @param defaultValue value used if the input string does not map
109: * to a boolean value
110: * @param input string
111: */
112: final static public boolean getBoolean(String str,
113: boolean defaultValue) {
114: if (str == null) {
115: return defaultValue;
116: } else if (str.equalsIgnoreCase("false")
117: || str.equalsIgnoreCase("n")
118: || str.equalsIgnoreCase("no")
119: || str.equalsIgnoreCase("deny")
120: || str.equalsIgnoreCase("off")) {
121: return false;
122: } else if (str.equalsIgnoreCase("true")
123: || str.equalsIgnoreCase("y")
124: || str.equalsIgnoreCase("yes")
125: || str.equalsIgnoreCase("allow")
126: || str.equalsIgnoreCase("on")) {
127: return true;
128: } else {
129: return defaultValue;
130: }
131: }
132:
133: /**
134: *
135: *
136: * @param
137: */
138: //replaces all occurences of string a with string b
139: final static public String replaceString(String replace,
140: String with, String in) {
141: int start = 0;
142: int foundAt = in.indexOf(replace, start);
143: if (foundAt < 0)
144: return in; //if nothing found then just return
145: StringBuffer ret = new StringBuffer();
146: int len = replace.length();
147: while (true) {
148: ret.append(in.substring(start, foundAt));
149: ret.append(with);
150: start = foundAt + len;
151: foundAt = in.indexOf(replace, start);
152: if (foundAt < 0) {
153: ret.append(in.substring(start));
154: break;
155: }
156: }
157: return ret.toString();
158: }
159:
160: /**
161: *
162: *
163: * @param
164: */
165: final static public Object[] sort(Object[] a) {
166: if ((a == null) || (a.length <= 1))
167: return a;
168: return _sort(a, 0, a.length - 1);
169: }
170:
171: /**
172: *
173: *
174: * @param
175: */
176: final static public Vector sort(Vector v) {
177: if ((v == null) || (v.size() <= 1))
178: return v;
179: return _sort(v, 0, v.size() - 1);
180: }
181:
182: /**
183: *
184: *
185: * @param
186: */
187: final static private Object[] _sort(Object a[], int lo0, int hi0) {
188: if ((a == null) || (a.length <= 1))
189: return a;
190: if (lo0 < hi0) {
191: int q = partition(a, lo0, hi0);
192: if (q == hi0) {
193: q--;
194: }
195: _sort(a, lo0, q);
196: _sort(a, q + 1, hi0);
197: }
198: return a;
199: }
200:
201: /**
202: *
203: *
204: * @param
205: */
206: final static private Vector _sort(Vector v, int lo0, int hi0) {
207: if ((v == null) || (v.size() <= 1))
208: return v;
209: if (lo0 < hi0) {
210: int q = partition(v, lo0, hi0);
211: if (q == hi0) {
212: q--;
213: }
214: _sort(v, lo0, q);
215: _sort(v, q + 1, hi0);
216: }
217: return v;
218: }
219:
220: /**
221: *
222: *
223: * @param
224: */
225: final static private String getString(Object o) {
226: if (o == null) {
227: return "";
228: } else {
229: return o.toString();
230: }
231:
232: /*} else if (o instanceof String){
233: return (String)o;
234: } else {
235: return o.toString();
236: }*/
237: }
238:
239: /**
240: *
241: *
242: * @param
243: */
244: final static private int partition(Vector v, int p, int r) {
245: String pivot = getString(v.elementAt(p));
246: int lo = p;
247: int hi = r;
248:
249: while (true) {
250: String strhi, strlo;
251: strhi = getString(v.elementAt(hi));
252: while (collator.compare(strhi, pivot) >= 0 && lo < hi) {
253: hi--;
254: strhi = getString(v.elementAt(hi));
255: }
256: strlo = getString(v.elementAt(lo));
257: while (collator.compare(strlo, pivot) < 0 && lo < hi) {
258: lo++;
259: strlo = getString(v.elementAt(lo));
260: }
261: if (lo < hi) {
262: Object temp = v.elementAt(lo);
263: v.setElementAt(v.elementAt(hi), lo);
264: v.setElementAt(temp, hi);
265: } else
266: return hi;
267: }
268: }
269:
270: /**
271: *
272: *
273: * @param
274: */
275:
276: final static private int partition(Object a[], int p, int r) {
277: String pivot = getString(a[p]);
278: int lo = p;
279: int hi = r;
280:
281: while (true) {
282: String strhi, strlo;
283: strhi = getString(a[hi]);
284: while (collator.compare(strhi, pivot) >= 0 && lo < hi) {
285: hi--;
286: strhi = getString(a[hi]);
287: }
288: strlo = getString(a[lo]);
289: while (collator.compare(strlo, pivot) < 0 && lo < hi) {
290: lo++;
291: strlo = getString(a[lo]);
292: }
293: if (lo < hi) {
294: Object temp = a[lo];
295: a[lo] = a[hi];
296: a[hi] = temp;
297: } else
298: return hi;
299: }
300: }
301:
302: /**
303: * substitutes all instances of a pattern within a String, by another
304: * String
305: * @param in input string
306: * @param swapOut pattern to replace
307: * @param swapIn String to replace instances of the pattern with
308: * @return new String in which all instances of swapOut have been replaced
309: * substituted with swapIn
310: */
311: public static String substitute(final String in,
312: final String swapOut, final String swapIn) {
313: if (in == null || in.length() <= 0)
314: return in;
315: if (swapOut == null || swapOut.length() <= 0)
316: return in;
317: if (swapIn == null)
318: return in;
319: if (swapOut.equals(swapIn))
320: return in;
321:
322: String cur = in;
323: StringBuffer out = new StringBuffer();
324: int swapOutLen = swapOut.length();
325: int offset = -1;
326:
327: while ((offset = cur.indexOf(swapOut)) >= 0) {
328: out.append(cur.substring(0, offset));
329: out.append(swapIn);
330: cur = cur.substring(offset + swapOutLen);
331: }
332:
333: if (out != null) {
334: out.append(cur);
335: return out.toString();
336: } else {
337: return in;
338: }
339: }
340:
341: public static String substitute(final String in, final char c,
342: final String swapIn) {
343: return substitute(in, String.valueOf(c), swapIn);
344: }
345:
346: public static String substitute(final String in,
347: final String swapOut, final char c) {
348: return substitute(in, swapOut, String.valueOf(c));
349: }
350:
351: /**
352: * Performs a series of substitution on a String.
353: * Given a table of attribute value pairs, it replaces
354: * patterns referring to attributes in the table with those
355: * attributes' values.
356: * Patterns to substitute are identified by a constant
357: * header followed by the attribute name followed by a
358: * constant trailer.
359: * <p>Example:</p>
360: * <p>Given the following table
361: * <ul>
362: * <li>predator = cat</li>
363: * <li>prey = mouse</li>
364: * </ul>
365: * </p>
366: * <p>Given the following header : "${attr:"
367: * </p>
368: * <p>Given the following header : "}"
369: * </p>
370: * <p>Given the following input String: <br>
371: * <dd>The ${attr:color} ${attr:predator} eats the ${attr:prey}.
372: * </p>
373: * <p>The returned string will be:<br>
374: * <dd>The ${attr:color} cat eats the mouse.
375: * </p>
376: * Note that ${attr:color} is not replaced because the color
377: * attribute is not present in the attributes table. Remaining
378: * macros can be processed using the other substituteMacros
379: * method.
380: *
381: * @param in input string
382: * @param attributes attributes/values Map
383: * @param header macro header
384: * @param trailer macro trailer
385: *
386: * @return new String in which no unprocessed macro remains
387: */
388: public static String substituteMacros(String in, Map attributes,
389: String header, String trailer) {
390: String out = in;
391: for (Iterator i = attributes.keySet().iterator(); i.hasNext();) {
392: String key = (String) i.next();
393: out = substitute(out, header + key + trailer, attributes
394: .get(key).toString());
395: }
396: return out;
397:
398: }
399:
400: /**
401: * Substitute patterns identified by a trailer and a header
402: * with a fixed substitution string. The characters that
403: * are between the header and the trailer are removed.
404: * This method can be used to replace or remove attribute
405: * macros that have not bee substituted by substituteMacros
406: *
407: * @param in input string
408: * @param substitution substitution string
409: * @param header macro header
410: * @param trailer macro trailer
411: */
412: public static String substituteMacros(String in, String header,
413: String trailer, String substitution) {
414: String cur = in;
415: StringBuffer buf = null;
416: int headerLen = header.length();
417: int trailerLen = trailer.length();
418: int offset;
419: while ((offset = cur.indexOf(header)) >= 0) {
420: if (buf == null) {
421: buf = new StringBuffer(cur.substring(0, offset));
422: } else {
423: buf.append(cur.substring(0, offset));
424: }
425: buf.append(substitution);
426:
427: cur = cur.substring(offset + headerLen);
428:
429: offset = cur.indexOf(trailer);
430: if (offset > 0) {
431: cur = cur.substring(offset + trailerLen);
432: }
433: }
434:
435: if (buf != null) {
436: buf.append(cur);
437: return buf.toString();
438: } else {
439: return in;
440: }
441: }
442:
443: public static String quoteSpecialCharacters(String in) {
444: return JIDUtil.getProvider().quoteSpecialCharacters(in);
445: }
446:
447: public static String unquoteSpecialCharacters(String in) {
448: return JIDUtil.getProvider().unquoteSpecialCharacters(in);
449: }
450:
451: /**
452: * extract the domain component of an address.
453: * If no domain component is found, the specified
454: * default domain is returned
455: */
456: public static String getDomainFromAddress(String in,
457: String defaultDomain) {
458: return JIDUtil.getProvider().getDomainFromAddress(in,
459: defaultDomain);
460: }
461:
462: public static boolean hasDomain(String in) {
463: return JIDUtil.getProvider().hasDomain(in);
464: }
465:
466: public static String getLocalPartFromAddress(String in) {
467: return JIDUtil.getProvider().getLocalPartFromAddress(in);
468: }
469:
470: /**
471: * append specified domain component if no domain is present.
472: */
473: public static String appendDomainToAddress(String in,
474: String defaultDomain) {
475: return JIDUtil.getProvider().appendDomainToAddress(in,
476: defaultDomain);
477: }
478:
479: /**
480: * removes the resource string from the uid
481: */
482: public static String removeResource(String str) {
483: if (str == null)
484: return null;
485: int index = str.indexOf('/');
486: if (index != -1)
487: return str.substring(0, index);
488: return str;
489: }
490:
491: /**
492: * gets the resource string from the uid
493: */
494: public static String getResource(String str) {
495: if (str == null)
496: return null;
497: int index = str.indexOf('/');
498: if (index != -1)
499: return str.substring(index + 1);
500: return null;
501: }
502:
503: public static boolean hasResource(String str) {
504: return null == str || -1 != str.indexOf('/');
505: }
506:
507: /**
508: * very weak verification
509: */
510: public static boolean isValidEmailAddress(String s) {
511: int len = s.length();
512: int i = s.lastIndexOf('@');
513: if (len > 3 && i > 0 && i < len - 1 && s.charAt(i - 1) != '\\') {
514: return true;
515: } else {
516: return false;
517: }
518: }
519:
520: /**
521: * very weak verification
522: */
523: public static boolean isValidPhoneNumber(String s) {
524: char[] c = s.toCharArray();
525: for (int i = 0; i < c.length; i++) {
526: if (!Character.isDigit(c[i]) && c[i] != '+' && c[i] != '-'
527: && !Character.isWhitespace(c[i]))
528: return false;
529: }
530: if (s.length() < 3)
531: return false;
532: else
533: return true;
534: }
535:
536: /**
537: * This function search a string for the characters passed through _charToSearch
538: * and return the first occurence of one of them.
539: * @param s The string to search
540: * @param _charToSearch the characters to search for
541: * @return Return a array containing :
542: * - index 0 : the position of the character in the string.
543: * - index 1 : the character found at this position.
544: */
545: public static LinkedList getFirstCharAndIndexOf(String s,
546: LinkedList charToSearch) {
547: int i, tmpPos;
548: LinkedList toReturn = new LinkedList();
549: toReturn.add(0, new Integer(-1));
550: toReturn.add(1, new String(""));
551: // System.out.println("getFirstCharAndIndexOf : s="+s+"; v="+_charToSearch.toString());
552: for (i = 0; i < charToSearch.size(); i++) {
553: tmpPos = s.indexOf((String) charToSearch.get(i));
554: if (tmpPos >= 0) {
555: if ((((Integer) toReturn.get(0)).intValue() > tmpPos)
556: || (((Integer) toReturn.get(0)).intValue() == -1)) {
557: toReturn.set(0, new Integer(tmpPos));
558: toReturn.set(1, new String((String) charToSearch
559: .get(i)));
560: }
561: }
562: }
563: return (toReturn);
564: }
565:
566: /*
567: * This reads a Set and returns the first attribute of the set.
568: *@param Object o - The set from which the first attribute is required.
569: *@return Returns the first attribute of the set as a String.
570: */
571: final static public String getFirstAttr(Object o) {
572: Set e = null;
573: try {
574: e = (Set) o;
575: if ((e == null) || e.isEmpty()) {
576: return null;
577: }
578: return (String) e.iterator().next();
579: } catch (NoSuchElementException nsee) {
580: //e.printStackTrace(nsee);
581: return null;
582: } catch (ClassCastException cce) {
583: //e.printStackTrace(cce);
584: return null;
585: }
586: }
587:
588: /*
589: * This reads a Set and returns the first attribute of the set.
590: *@param Object o - The set from which the first attribute is required.
591: *@param def - The default value if the Set is empty.
592: *@return Returns the first attribute of the set as a String.
593: */
594: final static public String getStringAttr(Object o, String def) {
595: String val = getFirstAttr(o);
596: return ((val == null) ? def : val);
597: }
598:
599: /**
600: * This methods determines if a given string is present in an array of strings
601: * @param strArray An array of strings to search
602: * @param str The string which needs to be searched
603: * @return true if the str is present in strArray
604: */
605: final static public boolean contains(String[] strArray, String str) {
606: for (int i = 0; i < strArray.length; i++) {
607: if (strArray[i].equals(str))
608: return true;
609: }
610: return false;
611: }
612:
613: public static final int getMajorVersion(String str) {
614: if (null == str) {
615: return 0;
616: }
617: str = str.trim();
618: int indx = str.indexOf('.');
619: try {
620: if (-1 != indx) {
621: return Integer.parseInt(str.substring(0, indx).trim());
622: }
623: } catch (NumberFormatException nEx) {
624: }
625: return 0;
626: }
627:
628: private static final int MAX_JID_PORION_ALLOWED_SIZE = 1023;
629:
630: private static boolean isJIDPartLengthValid(String str,
631: String charset) {
632: try {
633: // treat null's as valid.
634: return null == str
635: || str.getBytes(charset).length <= MAX_JID_PORION_ALLOWED_SIZE;
636: } catch (UnsupportedEncodingException iEx) {
637: // fallback.
638: return str.length() <= MAX_JID_PORION_ALLOWED_SIZE;
639: }
640: }
641:
642: // Add other validations later.
643: // As of now :
644: // 1) Length validity.
645: public static boolean isJIDValid(JID jid, String charset) {
646:
647: if (null == charset) {
648: charset = "UTF-8";
649: }
650:
651: return null == jid ? true : isJIDPartLengthValid(jid
652: .getDomain(), charset)
653: && isJIDPartLengthValid(jid.getNode(), charset)
654: && isJIDPartLengthValid(jid.getResource(), charset);
655: }
656: }
|