001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2006-2010 Sun Microsystems, Inc.
025 *      Portions Copyright 2011-2015 ForgeRock AS
026 */
027package org.opends.server.util;
028
029import static org.opends.messages.UtilityMessages.*;
030import static org.opends.server.util.ServerConstants.*;
031
032import java.io.*;
033import java.lang.reflect.InvocationTargetException;
034import java.net.InetAddress;
035import java.net.InetSocketAddress;
036import java.net.ServerSocket;
037import java.net.Socket;
038import java.nio.ByteBuffer;
039import java.nio.channels.SelectionKey;
040import java.nio.channels.Selector;
041import java.nio.channels.SocketChannel;
042import java.text.ParseException;
043import java.text.SimpleDateFormat;
044import java.util.*;
045
046import javax.naming.InitialContext;
047import javax.naming.NamingException;
048
049import org.forgerock.i18n.LocalizableMessage;
050import org.forgerock.i18n.LocalizableMessageBuilder;
051import org.forgerock.i18n.LocalizableMessageDescriptor;
052import org.forgerock.i18n.slf4j.LocalizedLogger;
053import org.forgerock.opendj.ldap.ByteSequence;
054import org.forgerock.opendj.ldap.ByteString;
055import org.forgerock.util.Reject;
056import org.opends.messages.ToolMessages;
057import org.opends.server.api.ClientConnection;
058import org.opends.server.core.DirectoryServer;
059import org.opends.server.core.ServerContext;
060import org.opends.server.types.*;
061
062import com.forgerock.opendj.cli.Argument;
063import com.forgerock.opendj.cli.ArgumentException;
064
065/**
066 * This class defines a number of static utility methods that may be used
067 * throughout the server.  Note that because of the frequency with which these
068 * methods are expected to be used, very little debug logging will be performed
069 * to prevent the log from filling up with unimportant calls and to reduce the
070 * impact that debugging may have on performance.
071 */
072@org.opends.server.types.PublicAPI(
073     stability=org.opends.server.types.StabilityLevel.UNCOMMITTED,
074     mayInstantiate=false,
075     mayExtend=false,
076     mayInvoke=true)
077public final class StaticUtils
078{
079  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
080
081  /** The number of bytes of a Java int. A Java int is 32 bits, i.e. 4 bytes. */
082  public static final int INT_SIZE = 4;
083  /** The number of bytes of a Java long. A Java int is 64 bits, i.e. 8 bytes. */
084  public static final int LONG_SIZE = 8;
085
086  /**
087   * Number of bytes in a Kibibyte.
088   * <p>
089   * Example usage:
090   * <pre>
091   * int _10KB = 10 * KB;
092   * </pre>
093   */
094  public static final int KB = 1024;
095  /**
096   * Number of bytes in a Mebibyte.
097   * <p>
098   * Example usage:
099   * <pre>
100   * int _10MB = 10 * MB;
101   * </pre>
102   */
103  public static final int MB = KB * KB;
104
105  /** Private constructor to prevent instantiation. */
106  private StaticUtils() {
107    // No implementation required.
108  }
109
110
111
112  /**
113   * Construct a byte array containing the UTF-8 encoding of the
114   * provided string. This is significantly faster
115   * than calling {@link String#getBytes(String)} for ASCII strings.
116   *
117   * @param s
118   *          The string to convert to a UTF-8 byte array.
119   * @return Returns a byte array containing the UTF-8 encoding of the
120   *         provided string.
121   */
122  public static byte[] getBytes(String s)
123  {
124    if (s == null)
125    {
126      return null;
127    }
128
129    try
130    {
131      char c;
132      int length = s.length();
133      byte[] returnArray = new byte[length];
134      for (int i=0; i < length; i++)
135      {
136        c = s.charAt(i);
137        returnArray[i] = (byte) (c & 0x0000007F);
138        if (c != returnArray[i])
139        {
140          return s.getBytes("UTF-8");
141        }
142      }
143
144      return returnArray;
145    }
146    catch (Exception e)
147    {
148      logger.traceException(e);
149
150      try
151      {
152        return s.getBytes("UTF-8");
153      }
154      catch (Exception e2)
155      {
156        logger.traceException(e2);
157
158        return s.getBytes();
159      }
160    }
161  }
162
163
164
165  /**
166   * Returns the provided byte array decoded as a UTF-8 string without throwing
167   * an UnsupportedEncodingException. This method is equivalent to:
168   *
169   * <pre>
170   * try
171   * {
172   *   return new String(bytes, &quot;UTF-8&quot;);
173   * }
174   * catch (UnsupportedEncodingException e)
175   * {
176   *   // Should never happen: UTF-8 is always supported.
177   *   throw new RuntimeException(e);
178   * }
179   * </pre>
180   *
181   * @param bytes
182   *          The byte array to be decoded as a UTF-8 string.
183   * @return The decoded string.
184   */
185  public static String decodeUTF8(final byte[] bytes)
186  {
187    Reject.ifNull(bytes);
188
189    if (bytes.length == 0)
190    {
191      return "".intern();
192    }
193
194    final StringBuilder builder = new StringBuilder(bytes.length);
195    final int sz = bytes.length;
196
197    for (int i = 0; i < sz; i++)
198    {
199      final byte b = bytes[i];
200      if ((b & 0x7f) != b)
201      {
202        try
203        {
204          builder.append(new String(bytes, i, (sz - i), "UTF-8"));
205        }
206        catch (UnsupportedEncodingException e)
207        {
208          // Should never happen: UTF-8 is always supported.
209          throw new RuntimeException(e);
210        }
211        break;
212      }
213      builder.append((char) b);
214    }
215    return builder.toString();
216  }
217
218
219
220  /**
221   * Construct a byte array containing the UTF-8 encoding of the
222   * provided <code>char</code> array.
223   *
224   * @param chars
225   *          The character array to convert to a UTF-8 byte array.
226   * @return Returns a byte array containing the UTF-8 encoding of the
227   *         provided <code>char</code> array.
228   */
229  public static byte[] getBytes(char[] chars)
230  {
231    return getBytes(new String(chars));
232  }
233
234
235
236  /**
237   * Retrieves a string representation of the provided byte in hexadecimal.
238   *
239   * @param  b  The byte for which to retrieve the hexadecimal string
240   *            representation.
241   *
242   * @return  The string representation of the provided byte in hexadecimal.
243   */
244  public static String byteToHex(byte b)
245  {
246    switch (b & 0xFF)
247    {
248      case 0x00:  return "00";
249      case 0x01:  return "01";
250      case 0x02:  return "02";
251      case 0x03:  return "03";
252      case 0x04:  return "04";
253      case 0x05:  return "05";
254      case 0x06:  return "06";
255      case 0x07:  return "07";
256      case 0x08:  return "08";
257      case 0x09:  return "09";
258      case 0x0A:  return "0A";
259      case 0x0B:  return "0B";
260      case 0x0C:  return "0C";
261      case 0x0D:  return "0D";
262      case 0x0E:  return "0E";
263      case 0x0F:  return "0F";
264      case 0x10:  return "10";
265      case 0x11:  return "11";
266      case 0x12:  return "12";
267      case 0x13:  return "13";
268      case 0x14:  return "14";
269      case 0x15:  return "15";
270      case 0x16:  return "16";
271      case 0x17:  return "17";
272      case 0x18:  return "18";
273      case 0x19:  return "19";
274      case 0x1A:  return "1A";
275      case 0x1B:  return "1B";
276      case 0x1C:  return "1C";
277      case 0x1D:  return "1D";
278      case 0x1E:  return "1E";
279      case 0x1F:  return "1F";
280      case 0x20:  return "20";
281      case 0x21:  return "21";
282      case 0x22:  return "22";
283      case 0x23:  return "23";
284      case 0x24:  return "24";
285      case 0x25:  return "25";
286      case 0x26:  return "26";
287      case 0x27:  return "27";
288      case 0x28:  return "28";
289      case 0x29:  return "29";
290      case 0x2A:  return "2A";
291      case 0x2B:  return "2B";
292      case 0x2C:  return "2C";
293      case 0x2D:  return "2D";
294      case 0x2E:  return "2E";
295      case 0x2F:  return "2F";
296      case 0x30:  return "30";
297      case 0x31:  return "31";
298      case 0x32:  return "32";
299      case 0x33:  return "33";
300      case 0x34:  return "34";
301      case 0x35:  return "35";
302      case 0x36:  return "36";
303      case 0x37:  return "37";
304      case 0x38:  return "38";
305      case 0x39:  return "39";
306      case 0x3A:  return "3A";
307      case 0x3B:  return "3B";
308      case 0x3C:  return "3C";
309      case 0x3D:  return "3D";
310      case 0x3E:  return "3E";
311      case 0x3F:  return "3F";
312      case 0x40:  return "40";
313      case 0x41:  return "41";
314      case 0x42:  return "42";
315      case 0x43:  return "43";
316      case 0x44:  return "44";
317      case 0x45:  return "45";
318      case 0x46:  return "46";
319      case 0x47:  return "47";
320      case 0x48:  return "48";
321      case 0x49:  return "49";
322      case 0x4A:  return "4A";
323      case 0x4B:  return "4B";
324      case 0x4C:  return "4C";
325      case 0x4D:  return "4D";
326      case 0x4E:  return "4E";
327      case 0x4F:  return "4F";
328      case 0x50:  return "50";
329      case 0x51:  return "51";
330      case 0x52:  return "52";
331      case 0x53:  return "53";
332      case 0x54:  return "54";
333      case 0x55:  return "55";
334      case 0x56:  return "56";
335      case 0x57:  return "57";
336      case 0x58:  return "58";
337      case 0x59:  return "59";
338      case 0x5A:  return "5A";
339      case 0x5B:  return "5B";
340      case 0x5C:  return "5C";
341      case 0x5D:  return "5D";
342      case 0x5E:  return "5E";
343      case 0x5F:  return "5F";
344      case 0x60:  return "60";
345      case 0x61:  return "61";
346      case 0x62:  return "62";
347      case 0x63:  return "63";
348      case 0x64:  return "64";
349      case 0x65:  return "65";
350      case 0x66:  return "66";
351      case 0x67:  return "67";
352      case 0x68:  return "68";
353      case 0x69:  return "69";
354      case 0x6A:  return "6A";
355      case 0x6B:  return "6B";
356      case 0x6C:  return "6C";
357      case 0x6D:  return "6D";
358      case 0x6E:  return "6E";
359      case 0x6F:  return "6F";
360      case 0x70:  return "70";
361      case 0x71:  return "71";
362      case 0x72:  return "72";
363      case 0x73:  return "73";
364      case 0x74:  return "74";
365      case 0x75:  return "75";
366      case 0x76:  return "76";
367      case 0x77:  return "77";
368      case 0x78:  return "78";
369      case 0x79:  return "79";
370      case 0x7A:  return "7A";
371      case 0x7B:  return "7B";
372      case 0x7C:  return "7C";
373      case 0x7D:  return "7D";
374      case 0x7E:  return "7E";
375      case 0x7F:  return "7F";
376      case 0x80:  return "80";
377      case 0x81:  return "81";
378      case 0x82:  return "82";
379      case 0x83:  return "83";
380      case 0x84:  return "84";
381      case 0x85:  return "85";
382      case 0x86:  return "86";
383      case 0x87:  return "87";
384      case 0x88:  return "88";
385      case 0x89:  return "89";
386      case 0x8A:  return "8A";
387      case 0x8B:  return "8B";
388      case 0x8C:  return "8C";
389      case 0x8D:  return "8D";
390      case 0x8E:  return "8E";
391      case 0x8F:  return "8F";
392      case 0x90:  return "90";
393      case 0x91:  return "91";
394      case 0x92:  return "92";
395      case 0x93:  return "93";
396      case 0x94:  return "94";
397      case 0x95:  return "95";
398      case 0x96:  return "96";
399      case 0x97:  return "97";
400      case 0x98:  return "98";
401      case 0x99:  return "99";
402      case 0x9A:  return "9A";
403      case 0x9B:  return "9B";
404      case 0x9C:  return "9C";
405      case 0x9D:  return "9D";
406      case 0x9E:  return "9E";
407      case 0x9F:  return "9F";
408      case 0xA0:  return "A0";
409      case 0xA1:  return "A1";
410      case 0xA2:  return "A2";
411      case 0xA3:  return "A3";
412      case 0xA4:  return "A4";
413      case 0xA5:  return "A5";
414      case 0xA6:  return "A6";
415      case 0xA7:  return "A7";
416      case 0xA8:  return "A8";
417      case 0xA9:  return "A9";
418      case 0xAA:  return "AA";
419      case 0xAB:  return "AB";
420      case 0xAC:  return "AC";
421      case 0xAD:  return "AD";
422      case 0xAE:  return "AE";
423      case 0xAF:  return "AF";
424      case 0xB0:  return "B0";
425      case 0xB1:  return "B1";
426      case 0xB2:  return "B2";
427      case 0xB3:  return "B3";
428      case 0xB4:  return "B4";
429      case 0xB5:  return "B5";
430      case 0xB6:  return "B6";
431      case 0xB7:  return "B7";
432      case 0xB8:  return "B8";
433      case 0xB9:  return "B9";
434      case 0xBA:  return "BA";
435      case 0xBB:  return "BB";
436      case 0xBC:  return "BC";
437      case 0xBD:  return "BD";
438      case 0xBE:  return "BE";
439      case 0xBF:  return "BF";
440      case 0xC0:  return "C0";
441      case 0xC1:  return "C1";
442      case 0xC2:  return "C2";
443      case 0xC3:  return "C3";
444      case 0xC4:  return "C4";
445      case 0xC5:  return "C5";
446      case 0xC6:  return "C6";
447      case 0xC7:  return "C7";
448      case 0xC8:  return "C8";
449      case 0xC9:  return "C9";
450      case 0xCA:  return "CA";
451      case 0xCB:  return "CB";
452      case 0xCC:  return "CC";
453      case 0xCD:  return "CD";
454      case 0xCE:  return "CE";
455      case 0xCF:  return "CF";
456      case 0xD0:  return "D0";
457      case 0xD1:  return "D1";
458      case 0xD2:  return "D2";
459      case 0xD3:  return "D3";
460      case 0xD4:  return "D4";
461      case 0xD5:  return "D5";
462      case 0xD6:  return "D6";
463      case 0xD7:  return "D7";
464      case 0xD8:  return "D8";
465      case 0xD9:  return "D9";
466      case 0xDA:  return "DA";
467      case 0xDB:  return "DB";
468      case 0xDC:  return "DC";
469      case 0xDD:  return "DD";
470      case 0xDE:  return "DE";
471      case 0xDF:  return "DF";
472      case 0xE0:  return "E0";
473      case 0xE1:  return "E1";
474      case 0xE2:  return "E2";
475      case 0xE3:  return "E3";
476      case 0xE4:  return "E4";
477      case 0xE5:  return "E5";
478      case 0xE6:  return "E6";
479      case 0xE7:  return "E7";
480      case 0xE8:  return "E8";
481      case 0xE9:  return "E9";
482      case 0xEA:  return "EA";
483      case 0xEB:  return "EB";
484      case 0xEC:  return "EC";
485      case 0xED:  return "ED";
486      case 0xEE:  return "EE";
487      case 0xEF:  return "EF";
488      case 0xF0:  return "F0";
489      case 0xF1:  return "F1";
490      case 0xF2:  return "F2";
491      case 0xF3:  return "F3";
492      case 0xF4:  return "F4";
493      case 0xF5:  return "F5";
494      case 0xF6:  return "F6";
495      case 0xF7:  return "F7";
496      case 0xF8:  return "F8";
497      case 0xF9:  return "F9";
498      case 0xFA:  return "FA";
499      case 0xFB:  return "FB";
500      case 0xFC:  return "FC";
501      case 0xFD:  return "FD";
502      case 0xFE:  return "FE";
503      case 0xFF:  return "FF";
504      default:    return "??";
505    }
506  }
507
508
509
510  /**
511   * Retrieves a string representation of the provided byte in hexadecimal.
512   *
513   * @param  b  The byte for which to retrieve the hexadecimal string
514   *            representation.
515   *
516   * @return  The string representation of the provided byte in hexadecimal
517   *          using lowercase characters.
518   */
519  public static String byteToLowerHex(byte b)
520  {
521    switch (b & 0xFF)
522    {
523      case 0x00:  return "00";
524      case 0x01:  return "01";
525      case 0x02:  return "02";
526      case 0x03:  return "03";
527      case 0x04:  return "04";
528      case 0x05:  return "05";
529      case 0x06:  return "06";
530      case 0x07:  return "07";
531      case 0x08:  return "08";
532      case 0x09:  return "09";
533      case 0x0A:  return "0a";
534      case 0x0B:  return "0b";
535      case 0x0C:  return "0c";
536      case 0x0D:  return "0d";
537      case 0x0E:  return "0e";
538      case 0x0F:  return "0f";
539      case 0x10:  return "10";
540      case 0x11:  return "11";
541      case 0x12:  return "12";
542      case 0x13:  return "13";
543      case 0x14:  return "14";
544      case 0x15:  return "15";
545      case 0x16:  return "16";
546      case 0x17:  return "17";
547      case 0x18:  return "18";
548      case 0x19:  return "19";
549      case 0x1A:  return "1a";
550      case 0x1B:  return "1b";
551      case 0x1C:  return "1c";
552      case 0x1D:  return "1d";
553      case 0x1E:  return "1e";
554      case 0x1F:  return "1f";
555      case 0x20:  return "20";
556      case 0x21:  return "21";
557      case 0x22:  return "22";
558      case 0x23:  return "23";
559      case 0x24:  return "24";
560      case 0x25:  return "25";
561      case 0x26:  return "26";
562      case 0x27:  return "27";
563      case 0x28:  return "28";
564      case 0x29:  return "29";
565      case 0x2A:  return "2a";
566      case 0x2B:  return "2b";
567      case 0x2C:  return "2c";
568      case 0x2D:  return "2d";
569      case 0x2E:  return "2e";
570      case 0x2F:  return "2f";
571      case 0x30:  return "30";
572      case 0x31:  return "31";
573      case 0x32:  return "32";
574      case 0x33:  return "33";
575      case 0x34:  return "34";
576      case 0x35:  return "35";
577      case 0x36:  return "36";
578      case 0x37:  return "37";
579      case 0x38:  return "38";
580      case 0x39:  return "39";
581      case 0x3A:  return "3a";
582      case 0x3B:  return "3b";
583      case 0x3C:  return "3c";
584      case 0x3D:  return "3d";
585      case 0x3E:  return "3e";
586      case 0x3F:  return "3f";
587      case 0x40:  return "40";
588      case 0x41:  return "41";
589      case 0x42:  return "42";
590      case 0x43:  return "43";
591      case 0x44:  return "44";
592      case 0x45:  return "45";
593      case 0x46:  return "46";
594      case 0x47:  return "47";
595      case 0x48:  return "48";
596      case 0x49:  return "49";
597      case 0x4A:  return "4a";
598      case 0x4B:  return "4b";
599      case 0x4C:  return "4c";
600      case 0x4D:  return "4d";
601      case 0x4E:  return "4e";
602      case 0x4F:  return "4f";
603      case 0x50:  return "50";
604      case 0x51:  return "51";
605      case 0x52:  return "52";
606      case 0x53:  return "53";
607      case 0x54:  return "54";
608      case 0x55:  return "55";
609      case 0x56:  return "56";
610      case 0x57:  return "57";
611      case 0x58:  return "58";
612      case 0x59:  return "59";
613      case 0x5A:  return "5a";
614      case 0x5B:  return "5b";
615      case 0x5C:  return "5c";
616      case 0x5D:  return "5d";
617      case 0x5E:  return "5e";
618      case 0x5F:  return "5f";
619      case 0x60:  return "60";
620      case 0x61:  return "61";
621      case 0x62:  return "62";
622      case 0x63:  return "63";
623      case 0x64:  return "64";
624      case 0x65:  return "65";
625      case 0x66:  return "66";
626      case 0x67:  return "67";
627      case 0x68:  return "68";
628      case 0x69:  return "69";
629      case 0x6A:  return "6a";
630      case 0x6B:  return "6b";
631      case 0x6C:  return "6c";
632      case 0x6D:  return "6d";
633      case 0x6E:  return "6e";
634      case 0x6F:  return "6f";
635      case 0x70:  return "70";
636      case 0x71:  return "71";
637      case 0x72:  return "72";
638      case 0x73:  return "73";
639      case 0x74:  return "74";
640      case 0x75:  return "75";
641      case 0x76:  return "76";
642      case 0x77:  return "77";
643      case 0x78:  return "78";
644      case 0x79:  return "79";
645      case 0x7A:  return "7a";
646      case 0x7B:  return "7b";
647      case 0x7C:  return "7c";
648      case 0x7D:  return "7d";
649      case 0x7E:  return "7e";
650      case 0x7F:  return "7f";
651      case 0x80:  return "80";
652      case 0x81:  return "81";
653      case 0x82:  return "82";
654      case 0x83:  return "83";
655      case 0x84:  return "84";
656      case 0x85:  return "85";
657      case 0x86:  return "86";
658      case 0x87:  return "87";
659      case 0x88:  return "88";
660      case 0x89:  return "89";
661      case 0x8A:  return "8a";
662      case 0x8B:  return "8b";
663      case 0x8C:  return "8c";
664      case 0x8D:  return "8d";
665      case 0x8E:  return "8e";
666      case 0x8F:  return "8f";
667      case 0x90:  return "90";
668      case 0x91:  return "91";
669      case 0x92:  return "92";
670      case 0x93:  return "93";
671      case 0x94:  return "94";
672      case 0x95:  return "95";
673      case 0x96:  return "96";
674      case 0x97:  return "97";
675      case 0x98:  return "98";
676      case 0x99:  return "99";
677      case 0x9A:  return "9a";
678      case 0x9B:  return "9b";
679      case 0x9C:  return "9c";
680      case 0x9D:  return "9d";
681      case 0x9E:  return "9e";
682      case 0x9F:  return "9f";
683      case 0xA0:  return "a0";
684      case 0xA1:  return "a1";
685      case 0xA2:  return "a2";
686      case 0xA3:  return "a3";
687      case 0xA4:  return "a4";
688      case 0xA5:  return "a5";
689      case 0xA6:  return "a6";
690      case 0xA7:  return "a7";
691      case 0xA8:  return "a8";
692      case 0xA9:  return "a9";
693      case 0xAA:  return "aa";
694      case 0xAB:  return "ab";
695      case 0xAC:  return "ac";
696      case 0xAD:  return "ad";
697      case 0xAE:  return "ae";
698      case 0xAF:  return "af";
699      case 0xB0:  return "b0";
700      case 0xB1:  return "b1";
701      case 0xB2:  return "b2";
702      case 0xB3:  return "b3";
703      case 0xB4:  return "b4";
704      case 0xB5:  return "b5";
705      case 0xB6:  return "b6";
706      case 0xB7:  return "b7";
707      case 0xB8:  return "b8";
708      case 0xB9:  return "b9";
709      case 0xBA:  return "ba";
710      case 0xBB:  return "bb";
711      case 0xBC:  return "bc";
712      case 0xBD:  return "bd";
713      case 0xBE:  return "be";
714      case 0xBF:  return "bf";
715      case 0xC0:  return "c0";
716      case 0xC1:  return "c1";
717      case 0xC2:  return "c2";
718      case 0xC3:  return "c3";
719      case 0xC4:  return "c4";
720      case 0xC5:  return "c5";
721      case 0xC6:  return "c6";
722      case 0xC7:  return "c7";
723      case 0xC8:  return "c8";
724      case 0xC9:  return "c9";
725      case 0xCA:  return "ca";
726      case 0xCB:  return "cb";
727      case 0xCC:  return "cc";
728      case 0xCD:  return "cd";
729      case 0xCE:  return "ce";
730      case 0xCF:  return "cf";
731      case 0xD0:  return "d0";
732      case 0xD1:  return "d1";
733      case 0xD2:  return "d2";
734      case 0xD3:  return "d3";
735      case 0xD4:  return "d4";
736      case 0xD5:  return "d5";
737      case 0xD6:  return "d6";
738      case 0xD7:  return "d7";
739      case 0xD8:  return "d8";
740      case 0xD9:  return "d9";
741      case 0xDA:  return "da";
742      case 0xDB:  return "db";
743      case 0xDC:  return "dc";
744      case 0xDD:  return "dd";
745      case 0xDE:  return "de";
746      case 0xDF:  return "df";
747      case 0xE0:  return "e0";
748      case 0xE1:  return "e1";
749      case 0xE2:  return "e2";
750      case 0xE3:  return "e3";
751      case 0xE4:  return "e4";
752      case 0xE5:  return "e5";
753      case 0xE6:  return "e6";
754      case 0xE7:  return "e7";
755      case 0xE8:  return "e8";
756      case 0xE9:  return "e9";
757      case 0xEA:  return "ea";
758      case 0xEB:  return "eb";
759      case 0xEC:  return "ec";
760      case 0xED:  return "ed";
761      case 0xEE:  return "ee";
762      case 0xEF:  return "ef";
763      case 0xF0:  return "f0";
764      case 0xF1:  return "f1";
765      case 0xF2:  return "f2";
766      case 0xF3:  return "f3";
767      case 0xF4:  return "f4";
768      case 0xF5:  return "f5";
769      case 0xF6:  return "f6";
770      case 0xF7:  return "f7";
771      case 0xF8:  return "f8";
772      case 0xF9:  return "f9";
773      case 0xFA:  return "fa";
774      case 0xFB:  return "fb";
775      case 0xFC:  return "fc";
776      case 0xFD:  return "fd";
777      case 0xFE:  return "fe";
778      case 0xFF:  return "ff";
779      default:    return "??";
780    }
781  }
782
783
784
785  /**
786   * Retrieves the printable ASCII representation of the provided byte.
787   *
788   * @param  b  The byte for which to retrieve the printable ASCII
789   *            representation.
790   *
791   * @return  The printable ASCII representation of the provided byte, or a
792   *          space if the provided byte does not have  printable ASCII
793   *          representation.
794   */
795  public static char byteToASCII(byte b)
796  {
797    if (32 <= b && b <= 126)
798    {
799      return (char) b;
800    }
801    return ' ';
802  }
803
804
805
806  /**
807   * Retrieves a string representation of the contents of the provided byte
808   * array using hexadecimal characters with no space between each byte.
809   *
810   * @param  b  The byte array containing the data.
811   *
812   * @return  A string representation of the contents of the provided byte
813   *          array using hexadecimal characters.
814   */
815  public static String bytesToHexNoSpace(byte[] b)
816  {
817    if (b == null || b.length == 0)
818    {
819      return "";
820    }
821
822    int arrayLength = b.length;
823    StringBuilder buffer = new StringBuilder(arrayLength * 2);
824
825    for (int i=0; i < arrayLength; i++)
826    {
827      buffer.append(byteToHex(b[i]));
828    }
829
830    return buffer.toString();
831  }
832
833
834
835  /**
836   * Retrieves a string representation of the contents of the provided byte
837   * array using hexadecimal characters and a space between each byte.
838   *
839   * @param  b  The byte array containing the data.
840   * @return  A string representation of the contents of the provided byte
841   *          array using hexadecimal characters.
842   */
843  public static String bytesToHex(byte[] b)
844  {
845    if (b == null || b.length == 0)
846    {
847      return "";
848    }
849
850    int arrayLength = b.length;
851    StringBuilder buffer = new StringBuilder((arrayLength - 1) * 3 + 2);
852    buffer.append(byteToHex(b[0]));
853
854    for (int i=1; i < arrayLength; i++)
855    {
856      buffer.append(" ");
857      buffer.append(byteToHex(b[i]));
858    }
859
860    return buffer.toString();
861  }
862
863  /**
864   * Retrieves a string representation of the contents of the provided byte
865   * sequence using hexadecimal characters and a space between each byte.
866   *
867   * @param b The byte sequence containing the data.
868   * @return A string representation of the contents of the provided byte
869   *         sequence using hexadecimal characters.
870   */
871  public static String bytesToHex(ByteSequence b)
872  {
873    if (b == null || b.length() == 0)
874    {
875      return "";
876    }
877
878    int arrayLength = b.length();
879    StringBuilder buffer = new StringBuilder((arrayLength - 1) * 3 + 2);
880    buffer.append(byteToHex(b.byteAt(0)));
881
882    for (int i=1; i < arrayLength; i++)
883    {
884      buffer.append(" ");
885      buffer.append(byteToHex(b.byteAt(i)));
886    }
887
888    return buffer.toString();
889  }
890
891
892
893  /**
894   * Retrieves a string representation of the contents of the provided byte
895   * array using hexadecimal characters and a colon between each byte.
896   *
897   * @param  b  The byte array containing the data.
898   *
899   * @return  A string representation of the contents of the provided byte
900   *          array using hexadecimal characters.
901   */
902  public static String bytesToColonDelimitedHex(byte[] b)
903  {
904    if (b == null || b.length == 0)
905    {
906      return "";
907    }
908
909    int arrayLength = b.length;
910    StringBuilder buffer = new StringBuilder((arrayLength - 1) * 3 + 2);
911    buffer.append(byteToHex(b[0]));
912
913    for (int i=1; i < arrayLength; i++)
914    {
915      buffer.append(":");
916      buffer.append(byteToHex(b[i]));
917    }
918
919    return buffer.toString();
920  }
921
922
923
924  /**
925   * Retrieves a string representation of the contents of the provided byte
926   * buffer using hexadecimal characters and a space between each byte.
927   *
928   * @param  b  The byte buffer containing the data.
929   *
930   * @return  A string representation of the contents of the provided byte
931   *          buffer using hexadecimal characters.
932   */
933  public static String bytesToHex(ByteBuffer b)
934  {
935    if (b == null)
936    {
937      return "";
938    }
939
940    int position = b.position();
941    int limit    = b.limit();
942    int length   = limit - position;
943
944    if (length == 0)
945    {
946      return "";
947    }
948
949    StringBuilder buffer = new StringBuilder((length - 1) * 3 + 2);
950    buffer.append(byteToHex(b.get()));
951
952    for (int i=1; i < length; i++)
953    {
954      buffer.append(" ");
955      buffer.append(byteToHex(b.get()));
956    }
957
958    b.position(position);
959    b.limit(limit);
960
961    return buffer.toString();
962  }
963
964
965
966  /**
967   * Appends a string representation of the provided byte array to the given
968   * buffer using the specified indent.  The data will be formatted with sixteen
969   * hex bytes in a row followed by the ASCII representation, then wrapping to a
970   * new line as necessary.
971   *
972   * @param  buffer  The buffer to which the information is to be appended.
973   * @param  b       The byte array containing the data to write.
974   * @param  indent  The number of spaces to indent the output.
975   */
976  public static void byteArrayToHexPlusAscii(StringBuilder buffer, byte[] b,
977                                             int indent)
978  {
979    StringBuilder indentBuf = new StringBuilder(indent);
980    for (int i=0 ; i < indent; i++)
981    {
982      indentBuf.append(' ');
983    }
984
985
986
987    int length = b.length;
988    int pos    = 0;
989    while (length - pos >= 16)
990    {
991      StringBuilder asciiBuf = new StringBuilder(17);
992
993      buffer.append(indentBuf);
994      buffer.append(byteToHex(b[pos]));
995      asciiBuf.append(byteToASCII(b[pos]));
996      pos++;
997
998      for (int i=1; i < 16; i++, pos++)
999      {
1000        buffer.append(' ');
1001        buffer.append(byteToHex(b[pos]));
1002        asciiBuf.append(byteToASCII(b[pos]));
1003
1004        if (i == 7)
1005        {
1006          buffer.append("  ");
1007          asciiBuf.append(' ');
1008        }
1009      }
1010
1011      buffer.append("  ");
1012      buffer.append(asciiBuf);
1013      buffer.append(EOL);
1014    }
1015
1016
1017    int remaining = length - pos;
1018    if (remaining > 0)
1019    {
1020      StringBuilder asciiBuf = new StringBuilder(remaining+1);
1021
1022      buffer.append(indentBuf);
1023      buffer.append(byteToHex(b[pos]));
1024      asciiBuf.append(byteToASCII(b[pos]));
1025      pos++;
1026
1027      for (int i=1; i < 16; i++)
1028      {
1029        buffer.append(' ');
1030
1031        if (i < remaining)
1032        {
1033          buffer.append(byteToHex(b[pos]));
1034          asciiBuf.append(byteToASCII(b[pos]));
1035          pos++;
1036        }
1037        else
1038        {
1039          buffer.append("  ");
1040        }
1041
1042        if (i == 7)
1043        {
1044          buffer.append("  ");
1045
1046          if (i < remaining)
1047          {
1048            asciiBuf.append(' ');
1049          }
1050        }
1051      }
1052
1053      buffer.append("  ");
1054      buffer.append(asciiBuf);
1055      buffer.append(EOL);
1056    }
1057  }
1058
1059
1060
1061  /**
1062   * Appends a string representation of the remaining unread data in the
1063   * provided byte buffer to the given buffer using the specified indent.
1064   * The data will be formatted with sixteen hex bytes in a row followed by
1065   * the ASCII representation, then wrapping to a new line as necessary.
1066   * The state of the byte buffer is not changed.
1067   *
1068   * @param  buffer  The buffer to which the information is to be appended.
1069   * @param  b       The byte buffer containing the data to write.
1070   *                 The data from the position to the limit is written.
1071   * @param  indent  The number of spaces to indent the output.
1072   */
1073  public static void byteArrayToHexPlusAscii(StringBuilder buffer, ByteBuffer b,
1074                                             int indent)
1075  {
1076    StringBuilder indentBuf = new StringBuilder(indent);
1077    for (int i=0 ; i < indent; i++)
1078    {
1079      indentBuf.append(' ');
1080    }
1081
1082
1083    int position = b.position();
1084    int limit    = b.limit();
1085    int length   = limit - position;
1086    int pos      = 0;
1087    while (length - pos >= 16)
1088    {
1089      StringBuilder asciiBuf = new StringBuilder(17);
1090
1091      byte currentByte = b.get();
1092      buffer.append(indentBuf);
1093      buffer.append(byteToHex(currentByte));
1094      asciiBuf.append(byteToASCII(currentByte));
1095      pos++;
1096
1097      for (int i=1; i < 16; i++, pos++)
1098      {
1099        currentByte = b.get();
1100        buffer.append(' ');
1101        buffer.append(byteToHex(currentByte));
1102        asciiBuf.append(byteToASCII(currentByte));
1103
1104        if (i == 7)
1105        {
1106          buffer.append("  ");
1107          asciiBuf.append(' ');
1108        }
1109      }
1110
1111      buffer.append("  ");
1112      buffer.append(asciiBuf);
1113      buffer.append(EOL);
1114    }
1115
1116
1117    int remaining = length - pos;
1118    if (remaining > 0)
1119    {
1120      StringBuilder asciiBuf = new StringBuilder(remaining+1);
1121
1122      byte currentByte = b.get();
1123      buffer.append(indentBuf);
1124      buffer.append(byteToHex(currentByte));
1125      asciiBuf.append(byteToASCII(currentByte));
1126
1127      for (int i=1; i < 16; i++)
1128      {
1129        buffer.append(' ');
1130
1131        if (i < remaining)
1132        {
1133          currentByte = b.get();
1134          buffer.append(byteToHex(currentByte));
1135          asciiBuf.append(byteToASCII(currentByte));
1136        }
1137        else
1138        {
1139          buffer.append("  ");
1140        }
1141
1142        if (i == 7)
1143        {
1144          buffer.append("  ");
1145
1146          if (i < remaining)
1147          {
1148            asciiBuf.append(' ');
1149          }
1150        }
1151      }
1152
1153      buffer.append("  ");
1154      buffer.append(asciiBuf);
1155      buffer.append(EOL);
1156    }
1157
1158    b.position(position);
1159    b.limit(limit);
1160  }
1161
1162
1163
1164  /**
1165   * Retrieves a binary representation of the provided byte.  It will always be
1166   * a sequence of eight zeros and/or ones.
1167   *
1168   * @param  b  The byte for which to retrieve the binary representation.
1169   *
1170   * @return  The binary representation for the provided byte.
1171   */
1172  public static String byteToBinary(byte b)
1173  {
1174    switch (b & 0xFF)
1175    {
1176      case 0x00:  return "00000000";
1177      case 0x01:  return "00000001";
1178      case 0x02:  return "00000010";
1179      case 0x03:  return "00000011";
1180      case 0x04:  return "00000100";
1181      case 0x05:  return "00000101";
1182      case 0x06:  return "00000110";
1183      case 0x07:  return "00000111";
1184      case 0x08:  return "00001000";
1185      case 0x09:  return "00001001";
1186      case 0x0A:  return "00001010";
1187      case 0x0B:  return "00001011";
1188      case 0x0C:  return "00001100";
1189      case 0x0D:  return "00001101";
1190      case 0x0E:  return "00001110";
1191      case 0x0F:  return "00001111";
1192      case 0x10:  return "00010000";
1193      case 0x11:  return "00010001";
1194      case 0x12:  return "00010010";
1195      case 0x13:  return "00010011";
1196      case 0x14:  return "00010100";
1197      case 0x15:  return "00010101";
1198      case 0x16:  return "00010110";
1199      case 0x17:  return "00010111";
1200      case 0x18:  return "00011000";
1201      case 0x19:  return "00011001";
1202      case 0x1A:  return "00011010";
1203      case 0x1B:  return "00011011";
1204      case 0x1C:  return "00011100";
1205      case 0x1D:  return "00011101";
1206      case 0x1E:  return "00011110";
1207      case 0x1F:  return "00011111";
1208      case 0x20:  return "00100000";
1209      case 0x21:  return "00100001";
1210      case 0x22:  return "00100010";
1211      case 0x23:  return "00100011";
1212      case 0x24:  return "00100100";
1213      case 0x25:  return "00100101";
1214      case 0x26:  return "00100110";
1215      case 0x27:  return "00100111";
1216      case 0x28:  return "00101000";
1217      case 0x29:  return "00101001";
1218      case 0x2A:  return "00101010";
1219      case 0x2B:  return "00101011";
1220      case 0x2C:  return "00101100";
1221      case 0x2D:  return "00101101";
1222      case 0x2E:  return "00101110";
1223      case 0x2F:  return "00101111";
1224      case 0x30:  return "00110000";
1225      case 0x31:  return "00110001";
1226      case 0x32:  return "00110010";
1227      case 0x33:  return "00110011";
1228      case 0x34:  return "00110100";
1229      case 0x35:  return "00110101";
1230      case 0x36:  return "00110110";
1231      case 0x37:  return "00110111";
1232      case 0x38:  return "00111000";
1233      case 0x39:  return "00111001";
1234      case 0x3A:  return "00111010";
1235      case 0x3B:  return "00111011";
1236      case 0x3C:  return "00111100";
1237      case 0x3D:  return "00111101";
1238      case 0x3E:  return "00111110";
1239      case 0x3F:  return "00111111";
1240      case 0x40:  return "01000000";
1241      case 0x41:  return "01000001";
1242      case 0x42:  return "01000010";
1243      case 0x43:  return "01000011";
1244      case 0x44:  return "01000100";
1245      case 0x45:  return "01000101";
1246      case 0x46:  return "01000110";
1247      case 0x47:  return "01000111";
1248      case 0x48:  return "01001000";
1249      case 0x49:  return "01001001";
1250      case 0x4A:  return "01001010";
1251      case 0x4B:  return "01001011";
1252      case 0x4C:  return "01001100";
1253      case 0x4D:  return "01001101";
1254      case 0x4E:  return "01001110";
1255      case 0x4F:  return "01001111";
1256      case 0x50:  return "01010000";
1257      case 0x51:  return "01010001";
1258      case 0x52:  return "01010010";
1259      case 0x53:  return "01010011";
1260      case 0x54:  return "01010100";
1261      case 0x55:  return "01010101";
1262      case 0x56:  return "01010110";
1263      case 0x57:  return "01010111";
1264      case 0x58:  return "01011000";
1265      case 0x59:  return "01011001";
1266      case 0x5A:  return "01011010";
1267      case 0x5B:  return "01011011";
1268      case 0x5C:  return "01011100";
1269      case 0x5D:  return "01011101";
1270      case 0x5E:  return "01011110";
1271      case 0x5F:  return "01011111";
1272      case 0x60:  return "01100000";
1273      case 0x61:  return "01100001";
1274      case 0x62:  return "01100010";
1275      case 0x63:  return "01100011";
1276      case 0x64:  return "01100100";
1277      case 0x65:  return "01100101";
1278      case 0x66:  return "01100110";
1279      case 0x67:  return "01100111";
1280      case 0x68:  return "01101000";
1281      case 0x69:  return "01101001";
1282      case 0x6A:  return "01101010";
1283      case 0x6B:  return "01101011";
1284      case 0x6C:  return "01101100";
1285      case 0x6D:  return "01101101";
1286      case 0x6E:  return "01101110";
1287      case 0x6F:  return "01101111";
1288      case 0x70:  return "01110000";
1289      case 0x71:  return "01110001";
1290      case 0x72:  return "01110010";
1291      case 0x73:  return "01110011";
1292      case 0x74:  return "01110100";
1293      case 0x75:  return "01110101";
1294      case 0x76:  return "01110110";
1295      case 0x77:  return "01110111";
1296      case 0x78:  return "01111000";
1297      case 0x79:  return "01111001";
1298      case 0x7A:  return "01111010";
1299      case 0x7B:  return "01111011";
1300      case 0x7C:  return "01111100";
1301      case 0x7D:  return "01111101";
1302      case 0x7E:  return "01111110";
1303      case 0x7F:  return "01111111";
1304      case 0x80:  return "10000000";
1305      case 0x81:  return "10000001";
1306      case 0x82:  return "10000010";
1307      case 0x83:  return "10000011";
1308      case 0x84:  return "10000100";
1309      case 0x85:  return "10000101";
1310      case 0x86:  return "10000110";
1311      case 0x87:  return "10000111";
1312      case 0x88:  return "10001000";
1313      case 0x89:  return "10001001";
1314      case 0x8A:  return "10001010";
1315      case 0x8B:  return "10001011";
1316      case 0x8C:  return "10001100";
1317      case 0x8D:  return "10001101";
1318      case 0x8E:  return "10001110";
1319      case 0x8F:  return "10001111";
1320      case 0x90:  return "10010000";
1321      case 0x91:  return "10010001";
1322      case 0x92:  return "10010010";
1323      case 0x93:  return "10010011";
1324      case 0x94:  return "10010100";
1325      case 0x95:  return "10010101";
1326      case 0x96:  return "10010110";
1327      case 0x97:  return "10010111";
1328      case 0x98:  return "10011000";
1329      case 0x99:  return "10011001";
1330      case 0x9A:  return "10011010";
1331      case 0x9B:  return "10011011";
1332      case 0x9C:  return "10011100";
1333      case 0x9D:  return "10011101";
1334      case 0x9E:  return "10011110";
1335      case 0x9F:  return "10011111";
1336      case 0xA0:  return "10100000";
1337      case 0xA1:  return "10100001";
1338      case 0xA2:  return "10100010";
1339      case 0xA3:  return "10100011";
1340      case 0xA4:  return "10100100";
1341      case 0xA5:  return "10100101";
1342      case 0xA6:  return "10100110";
1343      case 0xA7:  return "10100111";
1344      case 0xA8:  return "10101000";
1345      case 0xA9:  return "10101001";
1346      case 0xAA:  return "10101010";
1347      case 0xAB:  return "10101011";
1348      case 0xAC:  return "10101100";
1349      case 0xAD:  return "10101101";
1350      case 0xAE:  return "10101110";
1351      case 0xAF:  return "10101111";
1352      case 0xB0:  return "10110000";
1353      case 0xB1:  return "10110001";
1354      case 0xB2:  return "10110010";
1355      case 0xB3:  return "10110011";
1356      case 0xB4:  return "10110100";
1357      case 0xB5:  return "10110101";
1358      case 0xB6:  return "10110110";
1359      case 0xB7:  return "10110111";
1360      case 0xB8:  return "10111000";
1361      case 0xB9:  return "10111001";
1362      case 0xBA:  return "10111010";
1363      case 0xBB:  return "10111011";
1364      case 0xBC:  return "10111100";
1365      case 0xBD:  return "10111101";
1366      case 0xBE:  return "10111110";
1367      case 0xBF:  return "10111111";
1368      case 0xC0:  return "11000000";
1369      case 0xC1:  return "11000001";
1370      case 0xC2:  return "11000010";
1371      case 0xC3:  return "11000011";
1372      case 0xC4:  return "11000100";
1373      case 0xC5:  return "11000101";
1374      case 0xC6:  return "11000110";
1375      case 0xC7:  return "11000111";
1376      case 0xC8:  return "11001000";
1377      case 0xC9:  return "11001001";
1378      case 0xCA:  return "11001010";
1379      case 0xCB:  return "11001011";
1380      case 0xCC:  return "11001100";
1381      case 0xCD:  return "11001101";
1382      case 0xCE:  return "11001110";
1383      case 0xCF:  return "11001111";
1384      case 0xD0:  return "11010000";
1385      case 0xD1:  return "11010001";
1386      case 0xD2:  return "11010010";
1387      case 0xD3:  return "11010011";
1388      case 0xD4:  return "11010100";
1389      case 0xD5:  return "11010101";
1390      case 0xD6:  return "11010110";
1391      case 0xD7:  return "11010111";
1392      case 0xD8:  return "11011000";
1393      case 0xD9:  return "11011001";
1394      case 0xDA:  return "11011010";
1395      case 0xDB:  return "11011011";
1396      case 0xDC:  return "11011100";
1397      case 0xDD:  return "11011101";
1398      case 0xDE:  return "11011110";
1399      case 0xDF:  return "11011111";
1400      case 0xE0:  return "11100000";
1401      case 0xE1:  return "11100001";
1402      case 0xE2:  return "11100010";
1403      case 0xE3:  return "11100011";
1404      case 0xE4:  return "11100100";
1405      case 0xE5:  return "11100101";
1406      case 0xE6:  return "11100110";
1407      case 0xE7:  return "11100111";
1408      case 0xE8:  return "11101000";
1409      case 0xE9:  return "11101001";
1410      case 0xEA:  return "11101010";
1411      case 0xEB:  return "11101011";
1412      case 0xEC:  return "11101100";
1413      case 0xED:  return "11101101";
1414      case 0xEE:  return "11101110";
1415      case 0xEF:  return "11101111";
1416      case 0xF0:  return "11110000";
1417      case 0xF1:  return "11110001";
1418      case 0xF2:  return "11110010";
1419      case 0xF3:  return "11110011";
1420      case 0xF4:  return "11110100";
1421      case 0xF5:  return "11110101";
1422      case 0xF6:  return "11110110";
1423      case 0xF7:  return "11110111";
1424      case 0xF8:  return "11111000";
1425      case 0xF9:  return "11111001";
1426      case 0xFA:  return "11111010";
1427      case 0xFB:  return "11111011";
1428      case 0xFC:  return "11111100";
1429      case 0xFD:  return "11111101";
1430      case 0xFE:  return "11111110";
1431      case 0xFF:  return "11111111";
1432      default:    return "????????";
1433    }
1434  }
1435
1436
1437
1438  /**
1439   * Compare two byte arrays for order. Returns a negative integer,
1440   * zero, or a positive integer as the first argument is less than,
1441   * equal to, or greater than the second.
1442   *
1443   * @param a
1444   *          The first byte array to be compared.
1445   * @param a2
1446   *          The second byte array to be compared.
1447   * @return Returns a negative integer, zero, or a positive integer
1448   *         if the first byte array is less than, equal to, or greater
1449   *         than the second.
1450   */
1451  public static int compare(byte[] a, byte[] a2) {
1452    if (a == a2) {
1453      return 0;
1454    }
1455
1456    if (a == null) {
1457      return -1;
1458    }
1459
1460    if (a2 == null) {
1461      return 1;
1462    }
1463
1464    int minLength = Math.min(a.length, a2.length);
1465    for (int i = 0; i < minLength; i++) {
1466      int firstByte = 0xFF & a[i];
1467      int secondByte = 0xFF & a2[i];
1468      if (firstByte != secondByte) {
1469        if (firstByte < secondByte) {
1470          return -1;
1471        } else if (firstByte > secondByte) {
1472          return 1;
1473        }
1474      }
1475    }
1476
1477    return a.length - a2.length;
1478  }
1479
1480
1481
1482  /**
1483   * Indicates whether the two array lists are equal. They will be
1484   * considered equal if they have the same number of elements, and
1485   * the corresponding elements between them are equal (in the same
1486   * order).
1487   *
1488   * @param list1
1489   *          The first list for which to make the determination.
1490   * @param list2
1491   *          The second list for which to make the determination.
1492   * @return <CODE>true</CODE> if the two array lists are equal, or
1493   *         <CODE>false</CODE> if they are not.
1494   */
1495  public static boolean listsAreEqual(List<?> list1, List<?> list2)
1496  {
1497    if (list1 == null)
1498    {
1499      return list2 == null;
1500    }
1501    else if (list2 == null)
1502    {
1503      return false;
1504    }
1505
1506    int numElements = list1.size();
1507    if (numElements != list2.size())
1508    {
1509      return false;
1510    }
1511
1512    // If either of the lists doesn't support random access, then fall back
1513    // on their equals methods and go ahead and create some garbage with the
1514    // iterators.
1515    if (!(list1 instanceof RandomAccess) ||
1516        !(list2 instanceof RandomAccess))
1517    {
1518      return list1.equals(list2);
1519    }
1520
1521    // Otherwise we can just retrieve the elements efficiently via their index.
1522    for (int i=0; i < numElements; i++)
1523    {
1524      Object o1 = list1.get(i);
1525      Object o2 = list2.get(i);
1526
1527      if (o1 == null)
1528      {
1529        if (o2 != null)
1530        {
1531          return false;
1532        }
1533      }
1534      else if (! o1.equals(o2))
1535      {
1536        return false;
1537      }
1538    }
1539
1540    return true;
1541  }
1542
1543  /**
1544   * Retrieves the best human-readable message for the provided exception.  For
1545   * exceptions defined in the OpenDJ project, it will attempt to use the
1546   * message (combining it with the message ID if available).  For some
1547   * exceptions that use encapsulation (e.g., InvocationTargetException), it
1548   * will be unwrapped and the cause will be treated.  For all others, the
1549   *
1550   *
1551   * @param  t  The {@code Throwable} object for which to retrieve the message.
1552   *
1553   * @return  The human-readable message generated for the provided exception.
1554   */
1555  public static LocalizableMessage getExceptionMessage(Throwable t)
1556  {
1557    if (t instanceof IdentifiedException)
1558    {
1559      IdentifiedException ie = (IdentifiedException) t;
1560
1561      StringBuilder message = new StringBuilder();
1562      message.append(ie.getMessage());
1563      message.append(" (id=");
1564      LocalizableMessage ieMsg = ie.getMessageObject();
1565      if (ieMsg != null) {
1566        message.append(ieMsg.resourceName()).append("-").append(ieMsg.ordinal());
1567      } else {
1568        message.append("-1");
1569      }
1570      message.append(")");
1571      return LocalizableMessage.raw(message.toString());
1572    }
1573    else if (t instanceof NullPointerException)
1574    {
1575      LocalizableMessageBuilder message = new LocalizableMessageBuilder();
1576      message.append("NullPointerException(");
1577
1578      StackTraceElement[] stackElements = t.getStackTrace();
1579      if (stackElements.length > 0)
1580      {
1581        message.append(stackElements[0].getFileName());
1582        message.append(":");
1583        message.append(stackElements[0].getLineNumber());
1584      }
1585
1586      message.append(")");
1587      return message.toMessage();
1588    }
1589    else if (t instanceof InvocationTargetException && t.getCause() != null)
1590    {
1591      return getExceptionMessage(t.getCause());
1592    }
1593    else
1594    {
1595      StringBuilder message = new StringBuilder();
1596
1597      String className = t.getClass().getName();
1598      int periodPos = className.lastIndexOf('.');
1599      if (periodPos > 0)
1600      {
1601        message.append(className.substring(periodPos+1));
1602      }
1603      else
1604      {
1605        message.append(className);
1606      }
1607
1608      message.append("(");
1609      if (t.getMessage() == null)
1610      {
1611        StackTraceElement[] stackElements = t.getStackTrace();
1612
1613        if (stackElements.length > 0)
1614        {
1615          message.append(stackElements[0].getFileName());
1616          message.append(":");
1617          message.append(stackElements[0].getLineNumber());
1618
1619          // FIXME Temporary to debug issue 2256.
1620          if (t instanceof IllegalStateException)
1621          {
1622            for (int i = 1; i < stackElements.length; i++)
1623            {
1624              message.append(' ');
1625              message.append(stackElements[i].getFileName());
1626              message.append(":");
1627              message.append(stackElements[i].getLineNumber());
1628            }
1629          }
1630        }
1631      }
1632      else
1633      {
1634        message.append(t.getMessage());
1635      }
1636
1637      message.append(")");
1638
1639      return LocalizableMessage.raw(message.toString());
1640    }
1641  }
1642
1643
1644
1645  /**
1646   * Retrieves a stack trace from the provided exception as a single-line
1647   * string.
1648   *
1649   * @param  t  The exception for which to retrieve the stack trace.
1650   *
1651   * @return  A stack trace from the provided exception as a single-line string.
1652   */
1653  public static String stackTraceToSingleLineString(Throwable t)
1654  {
1655    return com.forgerock.opendj.util.StaticUtils.stackTraceToSingleLineString(
1656        t, DynamicConstants.DEBUG_BUILD);
1657  }
1658
1659
1660
1661  /**
1662   * Appends a single-line string representation of the provided exception to
1663   * the given buffer.
1664   *
1665   * @param  buffer  The buffer to which the information is to be appended.
1666   * @param  t       The exception for which to retrieve the stack trace.
1667   */
1668  public static void stackTraceToSingleLineString(StringBuilder buffer,
1669                                                  Throwable t)
1670  {
1671    com.forgerock.opendj.util.StaticUtils.stackTraceToSingleLineString(
1672        buffer, t, DynamicConstants.DEBUG_BUILD);
1673  }
1674
1675
1676
1677  /**
1678   * Retrieves a string representation of the stack trace for the provided
1679   * exception.
1680   *
1681   * @param  t  The exception for which to retrieve the stack trace.
1682   *
1683   * @return  A string representation of the stack trace for the provided
1684   *          exception.
1685   */
1686  public static String stackTraceToString(Throwable t)
1687  {
1688    StringBuilder buffer = new StringBuilder();
1689    stackTraceToString(buffer, t);
1690    return buffer.toString();
1691  }
1692
1693  /**
1694   * Check if the stack trace of provided exception contains a given cause.
1695   *
1696   * @param throwable
1697   *          exception that may contain the cause
1698   * @param searchedCause
1699   *          class of the cause to look for. Any subclass will match.
1700   * @return true if and only if the given cause is found as a cause of any
1701   *         level in the provided exception.
1702   */
1703  public static boolean stackTraceContainsCause(
1704      Throwable throwable, Class<? extends Throwable> searchedCause)
1705  {
1706    Throwable t = throwable;
1707    while ((t = t.getCause()) != null)
1708    {
1709      if (searchedCause.isAssignableFrom(t.getClass()))
1710      {
1711        return true;
1712      }
1713
1714    }
1715    return false;
1716  }
1717
1718  /**
1719   * Appends a string representation of the stack trace for the provided
1720   * exception to the given buffer.
1721   *
1722   * @param  buffer  The buffer to which the information is to be appended.
1723   * @param  t       The exception for which to retrieve the stack trace.
1724   */
1725  public static void stackTraceToString(StringBuilder buffer, Throwable t)
1726  {
1727    if (t == null)
1728    {
1729      return;
1730    }
1731
1732    buffer.append(t);
1733
1734    for (StackTraceElement e : t.getStackTrace())
1735    {
1736      buffer.append(EOL);
1737      buffer.append("  ");
1738      buffer.append(e.getClassName());
1739      buffer.append(".");
1740      buffer.append(e.getMethodName());
1741      buffer.append("(");
1742      buffer.append(e.getFileName());
1743      buffer.append(":");
1744      buffer.append(e.getLineNumber());
1745      buffer.append(")");
1746    }
1747
1748    while (t.getCause() != null)
1749    {
1750      t = t.getCause();
1751      buffer.append(EOL);
1752      buffer.append("Caused by ");
1753      buffer.append(t);
1754
1755      for (StackTraceElement e : t.getStackTrace())
1756      {
1757        buffer.append(EOL);
1758        buffer.append("  ");
1759        buffer.append(e.getClassName());
1760        buffer.append(".");
1761        buffer.append(e.getMethodName());
1762        buffer.append("(");
1763        buffer.append(e.getFileName());
1764        buffer.append(":");
1765        buffer.append(e.getLineNumber());
1766        buffer.append(")");
1767      }
1768    }
1769
1770    buffer.append(EOL);
1771  }
1772
1773
1774
1775  /**
1776   * Retrieves a backtrace for the current thread consisting only of filenames
1777   * and line numbers that may be useful in debugging the origin of problems
1778   * that should not have happened.  Note that this may be an expensive
1779   * operation to perform, so it should only be used for error conditions or
1780   * debugging.
1781   *
1782   * @return  A backtrace for the current thread.
1783   */
1784  public static String getBacktrace()
1785  {
1786    StringBuilder buffer = new StringBuilder();
1787
1788    StackTraceElement[] elements = Thread.currentThread().getStackTrace();
1789
1790    if (elements.length > 1)
1791    {
1792      buffer.append(elements[1].getFileName());
1793      buffer.append(":");
1794      buffer.append(elements[1].getLineNumber());
1795
1796      for (int i=2; i < elements.length; i++)
1797      {
1798        buffer.append(" ");
1799        buffer.append(elements[i].getFileName());
1800        buffer.append(":");
1801        buffer.append(elements[i].getLineNumber());
1802      }
1803    }
1804
1805    return buffer.toString();
1806  }
1807
1808
1809
1810  /**
1811   * Retrieves a backtrace for the provided exception consisting of only
1812   * filenames and line numbers that may be useful in debugging the origin of
1813   * problems.  This is less expensive than the call to
1814   * <CODE>getBacktrace</CODE> without any arguments if an exception has already
1815   * been thrown.
1816   *
1817   * @param  t  The exception for which to obtain the backtrace.
1818   *
1819   * @return  A backtrace from the provided exception.
1820   */
1821  public static String getBacktrace(Throwable t)
1822  {
1823    StringBuilder buffer = new StringBuilder();
1824
1825    StackTraceElement[] elements = t.getStackTrace();
1826
1827    if (elements.length > 0)
1828    {
1829      buffer.append(elements[0].getFileName());
1830      buffer.append(":");
1831      buffer.append(elements[0].getLineNumber());
1832
1833      for (int i=1; i < elements.length; i++)
1834      {
1835        buffer.append(" ");
1836        buffer.append(elements[i].getFileName());
1837        buffer.append(":");
1838        buffer.append(elements[i].getLineNumber());
1839      }
1840    }
1841
1842    return buffer.toString();
1843  }
1844
1845
1846
1847  /**
1848   * Indicates whether the provided character is a numeric digit.
1849   *
1850   * @param  c  The character for which to make the determination.
1851   *
1852   * @return  <CODE>true</CODE> if the provided character represents a numeric
1853   *          digit, or <CODE>false</CODE> if not.
1854   */
1855  public static boolean isDigit(char c)
1856  {
1857    switch (c)
1858    {
1859      case '0':
1860      case '1':
1861      case '2':
1862      case '3':
1863      case '4':
1864      case '5':
1865      case '6':
1866      case '7':
1867      case '8':
1868      case '9':
1869        return true;
1870      default:
1871        return false;
1872    }
1873  }
1874
1875
1876
1877  /**
1878   * Indicates whether the provided character is an ASCII alphabetic character.
1879   *
1880   * @param  c  The character for which to make the determination.
1881   *
1882   * @return  <CODE>true</CODE> if the provided value is an uppercase or
1883   *          lowercase ASCII alphabetic character, or <CODE>false</CODE> if it
1884   *          is not.
1885   */
1886  public static boolean isAlpha(char c)
1887  {
1888    switch (c)
1889    {
1890      case 'A':
1891      case 'B':
1892      case 'C':
1893      case 'D':
1894      case 'E':
1895      case 'F':
1896      case 'G':
1897      case 'H':
1898      case 'I':
1899      case 'J':
1900      case 'K':
1901      case 'L':
1902      case 'M':
1903      case 'N':
1904      case 'O':
1905      case 'P':
1906      case 'Q':
1907      case 'R':
1908      case 'S':
1909      case 'T':
1910      case 'U':
1911      case 'V':
1912      case 'W':
1913      case 'X':
1914      case 'Y':
1915      case 'Z':
1916        return true;
1917
1918      case '[':
1919      case '\\':
1920      case ']':
1921      case '^':
1922      case '_':
1923      case '`':
1924        // Making sure all possible cases are present in one contiguous range
1925        // can result in a performance improvement.
1926        return false;
1927
1928      case 'a':
1929      case 'b':
1930      case 'c':
1931      case 'd':
1932      case 'e':
1933      case 'f':
1934      case 'g':
1935      case 'h':
1936      case 'i':
1937      case 'j':
1938      case 'k':
1939      case 'l':
1940      case 'm':
1941      case 'n':
1942      case 'o':
1943      case 'p':
1944      case 'q':
1945      case 'r':
1946      case 's':
1947      case 't':
1948      case 'u':
1949      case 'v':
1950      case 'w':
1951      case 'x':
1952      case 'y':
1953      case 'z':
1954        return true;
1955      default:
1956        return false;
1957    }
1958  }
1959
1960
1961
1962  /**
1963   * Indicates whether the provided character is a hexadecimal digit.
1964   *
1965   * @param  c  The character for which to make the determination.
1966   *
1967   * @return  <CODE>true</CODE> if the provided character represents a
1968   *          hexadecimal digit, or <CODE>false</CODE> if not.
1969   */
1970  public static boolean isHexDigit(char c)
1971  {
1972    switch (c)
1973    {
1974      case '0':
1975      case '1':
1976      case '2':
1977      case '3':
1978      case '4':
1979      case '5':
1980      case '6':
1981      case '7':
1982      case '8':
1983      case '9':
1984      case 'A':
1985      case 'B':
1986      case 'C':
1987      case 'D':
1988      case 'E':
1989      case 'F':
1990      case 'a':
1991      case 'b':
1992      case 'c':
1993      case 'd':
1994      case 'e':
1995      case 'f':
1996        return true;
1997      default:
1998        return false;
1999    }
2000  }
2001
2002
2003
2004  /**
2005   * Indicates whether the provided byte represents a hexadecimal digit.
2006   *
2007   * @param  b  The byte for which to make the determination.
2008   *
2009   * @return  <CODE>true</CODE> if the provided byte represents a hexadecimal
2010   *          digit, or <CODE>false</CODE> if not.
2011   */
2012  public static boolean isHexDigit(byte b)
2013  {
2014    switch (b)
2015    {
2016      case '0':
2017      case '1':
2018      case '2':
2019      case '3':
2020      case '4':
2021      case '5':
2022      case '6':
2023      case '7':
2024      case '8':
2025      case '9':
2026      case 'A':
2027      case 'B':
2028      case 'C':
2029      case 'D':
2030      case 'E':
2031      case 'F':
2032      case 'a':
2033      case 'b':
2034      case 'c':
2035      case 'd':
2036      case 'e':
2037      case 'f':
2038        return true;
2039      default:
2040        return false;
2041    }
2042  }
2043
2044
2045
2046  /**
2047   * Converts the provided hexadecimal string to a byte array.
2048   *
2049   * @param  hexString  The hexadecimal string to convert to a byte array.
2050   *
2051   * @return  The byte array containing the binary representation of the
2052   *          provided hex string.
2053   *
2054   * @throws  ParseException  If the provided string contains invalid
2055   *                          hexadecimal digits or does not contain an even
2056   *                          number of digits.
2057   */
2058  public static byte[] hexStringToByteArray(String hexString)
2059         throws ParseException
2060  {
2061    int length;
2062    if (hexString == null || ((length = hexString.length()) == 0))
2063    {
2064      return new byte[0];
2065    }
2066
2067
2068    if ((length % 2) == 1)
2069    {
2070      LocalizableMessage message = ERR_HEX_DECODE_INVALID_LENGTH.get(hexString);
2071      throw new ParseException(message.toString(), 0);
2072    }
2073
2074
2075    int pos = 0;
2076    int arrayLength = length / 2;
2077    byte[] returnArray = new byte[arrayLength];
2078    for (int i=0; i < arrayLength; i++)
2079    {
2080      switch (hexString.charAt(pos++))
2081      {
2082        case '0':
2083          returnArray[i] = 0x00;
2084          break;
2085        case '1':
2086          returnArray[i] = 0x10;
2087          break;
2088        case '2':
2089          returnArray[i] = 0x20;
2090          break;
2091        case '3':
2092          returnArray[i] = 0x30;
2093          break;
2094        case '4':
2095          returnArray[i] = 0x40;
2096          break;
2097        case '5':
2098          returnArray[i] = 0x50;
2099          break;
2100        case '6':
2101          returnArray[i] = 0x60;
2102          break;
2103        case '7':
2104          returnArray[i] = 0x70;
2105          break;
2106        case '8':
2107          returnArray[i] = (byte) 0x80;
2108          break;
2109        case '9':
2110          returnArray[i] = (byte) 0x90;
2111          break;
2112        case 'A':
2113        case 'a':
2114          returnArray[i] = (byte) 0xA0;
2115          break;
2116        case 'B':
2117        case 'b':
2118          returnArray[i] = (byte) 0xB0;
2119          break;
2120        case 'C':
2121        case 'c':
2122          returnArray[i] = (byte) 0xC0;
2123          break;
2124        case 'D':
2125        case 'd':
2126          returnArray[i] = (byte) 0xD0;
2127          break;
2128        case 'E':
2129        case 'e':
2130          returnArray[i] = (byte) 0xE0;
2131          break;
2132        case 'F':
2133        case 'f':
2134          returnArray[i] = (byte) 0xF0;
2135          break;
2136        default:
2137          LocalizableMessage message = ERR_HEX_DECODE_INVALID_CHARACTER.get(
2138              hexString, hexString.charAt(pos-1));
2139          throw new ParseException(message.toString(), 0);
2140      }
2141
2142      switch (hexString.charAt(pos++))
2143      {
2144        case '0':
2145          // No action required.
2146          break;
2147        case '1':
2148          returnArray[i] |= 0x01;
2149          break;
2150        case '2':
2151          returnArray[i] |= 0x02;
2152          break;
2153        case '3':
2154          returnArray[i] |= 0x03;
2155          break;
2156        case '4':
2157          returnArray[i] |= 0x04;
2158          break;
2159        case '5':
2160          returnArray[i] |= 0x05;
2161          break;
2162        case '6':
2163          returnArray[i] |= 0x06;
2164          break;
2165        case '7':
2166          returnArray[i] |= 0x07;
2167          break;
2168        case '8':
2169          returnArray[i] |= 0x08;
2170          break;
2171        case '9':
2172          returnArray[i] |= 0x09;
2173          break;
2174        case 'A':
2175        case 'a':
2176          returnArray[i] |= 0x0A;
2177          break;
2178        case 'B':
2179        case 'b':
2180          returnArray[i] |= 0x0B;
2181          break;
2182        case 'C':
2183        case 'c':
2184          returnArray[i] |= 0x0C;
2185          break;
2186        case 'D':
2187        case 'd':
2188          returnArray[i] |= 0x0D;
2189          break;
2190        case 'E':
2191        case 'e':
2192          returnArray[i] |= 0x0E;
2193          break;
2194        case 'F':
2195        case 'f':
2196          returnArray[i] |= 0x0F;
2197          break;
2198        default:
2199          LocalizableMessage message = ERR_HEX_DECODE_INVALID_CHARACTER.get(
2200              hexString, hexString.charAt(pos-1));
2201          throw new ParseException(message.toString(), 0);
2202      }
2203    }
2204
2205    return returnArray;
2206  }
2207
2208
2209
2210  /**
2211   * Indicates whether the provided value needs to be base64-encoded if it is
2212   * represented in LDIF form.
2213   *
2214   * @param  valueBytes  The binary representation of the attribute value for
2215   *                     which to make the determination.
2216   *
2217   * @return  <CODE>true</CODE> if the value needs to be base64-encoded if it is
2218   *          represented in LDIF form, or <CODE>false</CODE> if not.
2219   */
2220  public static boolean needsBase64Encoding(ByteSequence valueBytes)
2221  {
2222    int length;
2223    if (valueBytes == null || ((length = valueBytes.length()) == 0))
2224    {
2225      return false;
2226    }
2227
2228
2229    // If the value starts with a space, colon, or less than, then it needs to
2230    // be base64-encoded.
2231    switch (valueBytes.byteAt(0))
2232    {
2233      case 0x20: // Space
2234      case 0x3A: // Colon
2235      case 0x3C: // Less-than
2236        return true;
2237    }
2238
2239
2240    // If the value ends with a space, then it needs to be base64-encoded.
2241    if (length > 1 && valueBytes.byteAt(length-1) == 0x20)
2242    {
2243      return true;
2244    }
2245
2246
2247    // If the value contains a null, newline, or return character, then it needs
2248    // to be base64-encoded.
2249    byte b;
2250    for (int i = 0; i < valueBytes.length(); i++)
2251    {
2252      b = valueBytes.byteAt(i);
2253      if (b < 0 || 127 < b)
2254      {
2255        return true;
2256      }
2257
2258      switch (b)
2259      {
2260        case 0x00: // Null
2261        case 0x0A: // New line
2262        case 0x0D: // Carriage return
2263          return true;
2264      }
2265    }
2266
2267
2268    // If we've made it here, then there's no reason to base64-encode.
2269    return false;
2270  }
2271
2272
2273
2274  /**
2275   * Indicates whether the provided value needs to be base64-encoded if it is
2276   * represented in LDIF form.
2277   *
2278   * @param  valueString  The string representation of the attribute value for
2279   *                      which to make the determination.
2280   *
2281   * @return  <CODE>true</CODE> if the value needs to be base64-encoded if it is
2282   *          represented in LDIF form, or <CODE>false</CODE> if not.
2283   */
2284  public static boolean needsBase64Encoding(String valueString)
2285  {
2286    int length;
2287    if (valueString == null || ((length = valueString.length()) == 0))
2288    {
2289      return false;
2290    }
2291
2292
2293    // If the value starts with a space, colon, or less than, then it needs to
2294    // be base64-encoded.
2295    switch (valueString.charAt(0))
2296    {
2297      case ' ':
2298      case ':':
2299      case '<':
2300        return true;
2301    }
2302
2303
2304    // If the value ends with a space, then it needs to be base64-encoded.
2305    if (length > 1 && valueString.charAt(length-1) == ' ')
2306    {
2307      return true;
2308    }
2309
2310
2311    // If the value contains a null, newline, or return character, then it needs
2312    // to be base64-encoded.
2313    for (int i=0; i < length; i++)
2314    {
2315      char c = valueString.charAt(i);
2316      if (c <= 0 || c == 0x0A || c == 0x0D || c > 127)
2317      {
2318        return true;
2319      }
2320    }
2321
2322
2323    // If we've made it here, then there's no reason to base64-encode.
2324    return false;
2325  }
2326
2327
2328
2329  /**
2330   * Indicates whether the use of the exec method will be allowed on this
2331   * system.  It will be allowed by default, but that capability will be removed
2332   * if the org.opends.server.DisableExec system property is set and has any
2333   * value other than "false", "off", "no", or "0".
2334   *
2335   * @return  <CODE>true</CODE> if the use of the exec method should be allowed,
2336   *          or <CODE>false</CODE> if it should not be allowed.
2337   */
2338  public static boolean mayUseExec()
2339  {
2340    return !DirectoryServer.getEnvironmentConfig().disableExec();
2341  }
2342
2343
2344
2345  /**
2346   * Executes the specified command on the system and captures its output.  This
2347   * will not return until the specified process has completed.
2348   *
2349   * @param  command           The command to execute.
2350   * @param  args              The set of arguments to provide to the command.
2351   * @param  workingDirectory  The working directory to use for the command, or
2352   *                           <CODE>null</CODE> if the default directory
2353   *                           should be used.
2354   * @param  environment       The set of environment variables that should be
2355   *                           set when executing the command, or
2356   *                           <CODE>null</CODE> if none are needed.
2357   * @param  output            The output generated by the command while it was
2358   *                           running.  This will include both standard
2359   *                           output and standard error.  It may be
2360   *                           <CODE>null</CODE> if the output does not need to
2361   *                           be captured.
2362   *
2363   * @return  The exit code for the command.
2364   *
2365   * @throws  IOException  If an I/O problem occurs while trying to execute the
2366   *                       command.
2367   *
2368   * @throws  SecurityException  If the security policy will not allow the
2369   *                             command to be executed.
2370   *
2371   * @throws InterruptedException If the current thread is interrupted by
2372   *                              another thread while it is waiting, then
2373   *                              the wait is ended and an InterruptedException
2374   *                              is thrown.
2375   */
2376  public static int exec(String command, String[] args, File workingDirectory,
2377                         Map<String,String> environment, List<String> output)
2378         throws IOException, SecurityException, InterruptedException
2379  {
2380    // See whether we'll allow the use of exec on this system.  If not, then
2381    // throw an exception.
2382    if (! mayUseExec())
2383    {
2384      throw new SecurityException(ERR_EXEC_DISABLED.get(command).toString());
2385    }
2386
2387
2388    ArrayList<String> commandAndArgs = new ArrayList<>();
2389    commandAndArgs.add(command);
2390    if (args != null && args.length > 0)
2391    {
2392      Collections.addAll(commandAndArgs, args);
2393    }
2394
2395    ProcessBuilder processBuilder = new ProcessBuilder(commandAndArgs);
2396    processBuilder.redirectErrorStream(true);
2397
2398    if (workingDirectory != null && workingDirectory.isDirectory())
2399    {
2400      processBuilder.directory(workingDirectory);
2401    }
2402
2403    if (environment != null && !environment.isEmpty())
2404    {
2405      processBuilder.environment().putAll(environment);
2406    }
2407
2408    Process process = processBuilder.start();
2409
2410    // We must exhaust stdout and stderr before calling waitfor. Since we
2411    // redirected the error stream, we just have to read from stdout.
2412    InputStream processStream =  process.getInputStream();
2413    BufferedReader reader =
2414        new BufferedReader(new InputStreamReader(processStream));
2415    String line = null;
2416
2417    try
2418    {
2419      while((line = reader.readLine()) != null)
2420      {
2421        if(output != null)
2422        {
2423          output.add(line);
2424        }
2425      }
2426    }
2427    catch(IOException ioe)
2428    {
2429      // If this happens, then we have no choice but to forcefully terminate
2430      // the process.
2431      try
2432      {
2433        process.destroy();
2434      }
2435      catch (Exception e)
2436      {
2437        logger.traceException(e);
2438      }
2439
2440      throw ioe;
2441    }
2442    finally
2443    {
2444      try
2445      {
2446        reader.close();
2447      }
2448      catch(IOException e)
2449      {
2450        logger.traceException(e);
2451      }
2452    }
2453
2454    return process.waitFor();
2455  }
2456
2457
2458
2459  /**
2460   * Indicates whether the provided string contains a name or OID for a schema
2461   * element like an attribute type or objectclass.
2462   *
2463   * @param  element        The string containing the substring for which to
2464   *                        make the determination.
2465   * @param  startPos       The position of the first character that is to be
2466   *                        checked.
2467   * @param  endPos         The position of the first character after the start
2468   *                        position that is not to be checked.
2469   * @param  invalidReason  The buffer to which the invalid reason is to be
2470   *                        appended if a problem is found.
2471   *
2472   * @return  <CODE>true</CODE> if the provided string contains a valid name or
2473   *          OID for a schema element, or <CODE>false</CODE> if it does not.
2474   */
2475  public static boolean isValidSchemaElement(String element, int startPos,
2476                                             int endPos,
2477                                             LocalizableMessageBuilder invalidReason)
2478  {
2479    if (element == null || startPos >= endPos)
2480    {
2481      invalidReason.append(ERR_SCHEMANAME_EMPTY_VALUE.get());
2482      return false;
2483    }
2484
2485
2486    char c = element.charAt(startPos);
2487    if (isAlpha(c))
2488    {
2489      // This can only be a name and not an OID.  The only remaining characters
2490      // must be letters, digits, dashes, and possibly the underscore.
2491      for (int i=startPos+1; i < endPos; i++)
2492      {
2493        c = element.charAt(i);
2494        if (!isAlpha(c)
2495            && !isDigit(c)
2496            && c != '-'
2497            && (c != '_' || !DirectoryServer.allowAttributeNameExceptions()))
2498        {
2499          // This is an illegal character for an attribute name.
2500          invalidReason.append(ERR_SCHEMANAME_ILLEGAL_CHAR.get(element, c, i));
2501          return false;
2502        }
2503      }
2504    }
2505    else if (isDigit(c))
2506    {
2507      // This should indicate an OID, but it may also be a name if name
2508      // exceptions are enabled.  Since we don't know for sure, we'll just
2509      // hold off until we know for sure.
2510      boolean isKnown    = !DirectoryServer.allowAttributeNameExceptions();
2511      boolean isNumeric  = true;
2512      boolean lastWasDot = false;
2513
2514      for (int i=startPos+1; i < endPos; i++)
2515      {
2516        c = element.charAt(i);
2517        if (c == '.')
2518        {
2519          if (isKnown)
2520          {
2521            if (isNumeric)
2522            {
2523              // This is probably legal unless the last character was also a
2524              // period.
2525              if (lastWasDot)
2526              {
2527                invalidReason.append(ERR_SCHEMANAME_CONSECUTIVE_PERIODS.get(
2528                        element, i));
2529                return false;
2530              }
2531              else
2532              {
2533                lastWasDot = true;
2534              }
2535            }
2536            else
2537            {
2538              // This is an illegal character.
2539              invalidReason.append(ERR_SCHEMANAME_ILLEGAL_CHAR.get(
2540                      element, c, i));
2541              return false;
2542            }
2543          }
2544          else
2545          {
2546            // Now we know that this must be a numeric OID and not an attribute
2547            // name with exceptions allowed.
2548            lastWasDot = true;
2549            isKnown    = true;
2550            isNumeric  = true;
2551          }
2552        }
2553        else
2554        {
2555          lastWasDot = false;
2556
2557          if (isAlpha(c) || c == '-' || c == '_')
2558          {
2559            if (isKnown)
2560            {
2561              if (isNumeric)
2562              {
2563                // This is an illegal character for a numeric OID.
2564                invalidReason.append(ERR_SCHEMANAME_ILLEGAL_CHAR.get(
2565                        element, c, i));
2566                return false;
2567              }
2568            }
2569            else
2570            {
2571              // Now we know that this must be an attribute name with exceptions
2572              // allowed and not a numeric OID.
2573              isKnown   = true;
2574              isNumeric = false;
2575            }
2576          }
2577          else if (! isDigit(c))
2578          {
2579            // This is an illegal character.
2580            invalidReason.append(ERR_SCHEMANAME_ILLEGAL_CHAR.get(
2581                    element, c, i));
2582            return false;
2583          }
2584        }
2585      }
2586    }
2587    else
2588    {
2589      // This is an illegal character.
2590      invalidReason.append(ERR_SCHEMANAME_ILLEGAL_CHAR.get(
2591              element, c, startPos));
2592      return false;
2593    }
2594
2595
2596    // If we've gotten here, then the value is fine.
2597    return true;
2598  }
2599
2600
2601
2602  /**
2603   * Indicates whether the provided TCP address is already in use.
2604   *
2605   * @param  address        IP address of the TCP address for which to make
2606   *                        the determination.
2607   * @param  port           TCP port number of the TCP address for which to
2608   *                        make the determination.
2609   * @param  allowReuse     Whether or not TCP address reuse is allowed when
2610   *                        making the determination.
2611   *
2612   * @return  <CODE>true</CODE> if the provided TCP address is already in
2613   *          use, or <CODE>false</CODE> otherwise.
2614   */
2615  public static boolean isAddressInUse(
2616    InetAddress address, int port,
2617    boolean allowReuse)
2618  {
2619    // Return pessimistic.
2620    boolean isInUse = true;
2621    Socket clientSocket = null;
2622    ServerSocket serverSocket = null;
2623    try {
2624      // HACK:
2625      // With dual stacks we can have a situation when INADDR_ANY/PORT
2626      // is bound in TCP4 space but available in TCP6 space and since
2627      // JavaServerSocket implemantation will always use TCP46 on dual
2628      // stacks the bind below will always succeed in such cases thus
2629      // shadowing anything that is already bound to INADDR_ANY/PORT.
2630      // While technically correct, with IPv4 and IPv6 being separate
2631      // address spaces, it presents a problem to end users because a
2632      // common case scenario is to have a single service serving both
2633      // address spaces ie listening to the same port in both spaces
2634      // on wildcard addresses 0 and ::. ServerSocket implemantation
2635      // does not provide any means of working with each address space
2636      // separately such as doing TCP4 or TCP6 only binds thus we have
2637      // to do a dummy connect to INADDR_ANY/PORT to check if it is
2638      // bound to something already. This is only needed for wildcard
2639      // addresses as specific IPv4 or IPv6 addresses will always be
2640      // handled in their respective address space.
2641      if (address.isAnyLocalAddress()) {
2642        clientSocket = new Socket();
2643        try {
2644          // This might fail on some stacks but this is the best we
2645          // can do. No need for explicit timeout since it is local
2646          // address and we have to know for sure unless it fails.
2647          clientSocket.connect(new InetSocketAddress(address, port));
2648        } catch (IOException e) {
2649        // Expected, ignore.
2650        }
2651        if (clientSocket.isConnected()) {
2652          return true;
2653        }
2654      }
2655      serverSocket = new ServerSocket();
2656      serverSocket.setReuseAddress(allowReuse);
2657      serverSocket.bind(new InetSocketAddress(address, port));
2658      isInUse = false;
2659    } catch (IOException e) {
2660      isInUse = true;
2661    } finally {
2662      try {
2663        if (serverSocket != null) {
2664          serverSocket.close();
2665        }
2666      } catch (Exception e) {}
2667      try {
2668        if (clientSocket != null) {
2669          clientSocket.close();
2670        }
2671      } catch (Exception e) {}
2672    }
2673    return isInUse;
2674  }
2675
2676
2677
2678  /**
2679   * Retrieves a lowercase representation of the given string.  This
2680   * implementation presumes that the provided string will contain only ASCII
2681   * characters and is optimized for that case.  However, if a non-ASCII
2682   * character is encountered it will fall back on a more expensive algorithm
2683   * that will work properly for non-ASCII characters.
2684   *
2685   * @param  s  The string for which to obtain the lowercase representation.
2686   *
2687   * @return  The lowercase representation of the given string.
2688   */
2689  public static String toLowerCase(String s)
2690  {
2691    if (s == null)
2692    {
2693      return null;
2694    }
2695
2696    StringBuilder buffer = new StringBuilder(s.length());
2697    toLowerCase(s, buffer);
2698    return buffer.toString();
2699  }
2700
2701
2702
2703  /**
2704   * Appends a lowercase representation of the given string to the provided
2705   * buffer.  This implementation presumes that the provided string will contain
2706   * only ASCII characters and is optimized for that case.  However, if a
2707   * non-ASCII character is encountered it will fall back on a more expensive
2708   * algorithm that will work properly for non-ASCII characters.
2709   *
2710   * @param  s       The string for which to obtain the lowercase
2711   *                 representation.
2712   * @param  buffer  The buffer to which the lowercase form of the string should
2713   *                 be appended.
2714   */
2715  public static void toLowerCase(String s, StringBuilder buffer)
2716  {
2717    if (s == null)
2718    {
2719      return;
2720    }
2721
2722    int length = s.length();
2723    for (int i=0; i < length; i++)
2724    {
2725      char c = s.charAt(i);
2726
2727      if ((c & 0x7F) != c)
2728      {
2729        buffer.append(s.substring(i).toLowerCase());
2730        return;
2731      }
2732
2733      switch (c)
2734      {
2735        case 'A':
2736          buffer.append('a');
2737          break;
2738        case 'B':
2739          buffer.append('b');
2740          break;
2741        case 'C':
2742          buffer.append('c');
2743          break;
2744        case 'D':
2745          buffer.append('d');
2746          break;
2747        case 'E':
2748          buffer.append('e');
2749          break;
2750        case 'F':
2751          buffer.append('f');
2752          break;
2753        case 'G':
2754          buffer.append('g');
2755          break;
2756        case 'H':
2757          buffer.append('h');
2758          break;
2759        case 'I':
2760          buffer.append('i');
2761          break;
2762        case 'J':
2763          buffer.append('j');
2764          break;
2765        case 'K':
2766          buffer.append('k');
2767          break;
2768        case 'L':
2769          buffer.append('l');
2770          break;
2771        case 'M':
2772          buffer.append('m');
2773          break;
2774        case 'N':
2775          buffer.append('n');
2776          break;
2777        case 'O':
2778          buffer.append('o');
2779          break;
2780        case 'P':
2781          buffer.append('p');
2782          break;
2783        case 'Q':
2784          buffer.append('q');
2785          break;
2786        case 'R':
2787          buffer.append('r');
2788          break;
2789        case 'S':
2790          buffer.append('s');
2791          break;
2792        case 'T':
2793          buffer.append('t');
2794          break;
2795        case 'U':
2796          buffer.append('u');
2797          break;
2798        case 'V':
2799          buffer.append('v');
2800          break;
2801        case 'W':
2802          buffer.append('w');
2803          break;
2804        case 'X':
2805          buffer.append('x');
2806          break;
2807        case 'Y':
2808          buffer.append('y');
2809          break;
2810        case 'Z':
2811          buffer.append('z');
2812          break;
2813        default:
2814          buffer.append(c);
2815      }
2816    }
2817  }
2818
2819
2820
2821  /**
2822   * Appends a lowercase string representation of the contents of the given byte
2823   * array to the provided buffer, optionally trimming leading and trailing
2824   * spaces.  This implementation presumes that the provided string will contain
2825   * only ASCII characters and is optimized for that case.  However, if a
2826   * non-ASCII character is encountered it will fall back on a more expensive
2827   * algorithm that will work properly for non-ASCII characters.
2828   *
2829   * @param  b       The byte array for which to obtain the lowercase string
2830   *                 representation.
2831   * @param  buffer  The buffer to which the lowercase form of the string should
2832   *                 be appended.
2833   * @param  trim    Indicates whether leading and trailing spaces should be
2834   *                 omitted from the string representation.
2835   */
2836  public static void toLowerCase(ByteSequence b, StringBuilder buffer,
2837                                 boolean trim)
2838  {
2839    if (b == null)
2840    {
2841      return;
2842    }
2843
2844    int origBufferLen = buffer.length();
2845    int length = b.length();
2846    for (int i=0; i < length; i++)
2847    {
2848      if ((b.byteAt(i) & 0x7F) != b.byteAt(i))
2849      {
2850        buffer.replace(origBufferLen, buffer.length(),
2851            b.toString().toLowerCase());
2852        break;
2853      }
2854
2855      int bufferLength = buffer.length();
2856      switch (b.byteAt(i))
2857      {
2858        case ' ':
2859          // If we don't care about trimming, then we can always append the
2860          // space.  Otherwise, only do so if there are other characters in the value.
2861          if (trim && bufferLength == 0)
2862          {
2863            break;
2864          }
2865
2866          buffer.append(' ');
2867          break;
2868        case 'A':
2869          buffer.append('a');
2870          break;
2871        case 'B':
2872          buffer.append('b');
2873          break;
2874        case 'C':
2875          buffer.append('c');
2876          break;
2877        case 'D':
2878          buffer.append('d');
2879          break;
2880        case 'E':
2881          buffer.append('e');
2882          break;
2883        case 'F':
2884          buffer.append('f');
2885          break;
2886        case 'G':
2887          buffer.append('g');
2888          break;
2889        case 'H':
2890          buffer.append('h');
2891          break;
2892        case 'I':
2893          buffer.append('i');
2894          break;
2895        case 'J':
2896          buffer.append('j');
2897          break;
2898        case 'K':
2899          buffer.append('k');
2900          break;
2901        case 'L':
2902          buffer.append('l');
2903          break;
2904        case 'M':
2905          buffer.append('m');
2906          break;
2907        case 'N':
2908          buffer.append('n');
2909          break;
2910        case 'O':
2911          buffer.append('o');
2912          break;
2913        case 'P':
2914          buffer.append('p');
2915          break;
2916        case 'Q':
2917          buffer.append('q');
2918          break;
2919        case 'R':
2920          buffer.append('r');
2921          break;
2922        case 'S':
2923          buffer.append('s');
2924          break;
2925        case 'T':
2926          buffer.append('t');
2927          break;
2928        case 'U':
2929          buffer.append('u');
2930          break;
2931        case 'V':
2932          buffer.append('v');
2933          break;
2934        case 'W':
2935          buffer.append('w');
2936          break;
2937        case 'X':
2938          buffer.append('x');
2939          break;
2940        case 'Y':
2941          buffer.append('y');
2942          break;
2943        case 'Z':
2944          buffer.append('z');
2945          break;
2946        default:
2947          buffer.append((char) b.byteAt(i));
2948      }
2949    }
2950
2951    if (trim)
2952    {
2953      // Strip off any trailing spaces.
2954      for (int i=buffer.length()-1; i > 0; i--)
2955      {
2956        if (buffer.charAt(i) == ' ')
2957        {
2958          buffer.delete(i, i+1);
2959        }
2960        else
2961        {
2962          break;
2963        }
2964      }
2965    }
2966  }
2967
2968
2969
2970  /**
2971   * Retrieves an uppercase representation of the given string.  This
2972   * implementation presumes that the provided string will contain only ASCII
2973   * characters and is optimized for that case.  However, if a non-ASCII
2974   * character is encountered it will fall back on a more expensive algorithm
2975   * that will work properly for non-ASCII characters.
2976   *
2977   * @param  s  The string for which to obtain the uppercase representation.
2978   *
2979   * @return  The uppercase representation of the given string.
2980   */
2981  public static String toUpperCase(String s)
2982  {
2983    if (s == null)
2984    {
2985      return null;
2986    }
2987
2988    StringBuilder buffer = new StringBuilder(s.length());
2989    toUpperCase(s, buffer);
2990    return buffer.toString();
2991  }
2992
2993
2994
2995  /**
2996   * Appends an uppercase representation of the given string to the provided
2997   * buffer.  This implementation presumes that the provided string will contain
2998   * only ASCII characters and is optimized for that case.  However, if a
2999   * non-ASCII character is encountered it will fall back on a more expensive
3000   * algorithm that will work properly for non-ASCII characters.
3001   *
3002   * @param  s       The string for which to obtain the uppercase
3003   *                 representation.
3004   * @param  buffer  The buffer to which the uppercase form of the string should
3005   *                 be appended.
3006   */
3007  public static void toUpperCase(String s, StringBuilder buffer)
3008  {
3009    if (s == null)
3010    {
3011      return;
3012    }
3013
3014    int length = s.length();
3015    for (int i=0; i < length; i++)
3016    {
3017      char c = s.charAt(i);
3018
3019      if ((c & 0x7F) != c)
3020      {
3021        buffer.append(s.substring(i).toUpperCase());
3022        return;
3023      }
3024
3025      switch (c)
3026      {
3027        case 'a':
3028          buffer.append('A');
3029          break;
3030        case 'b':
3031          buffer.append('B');
3032          break;
3033        case 'c':
3034          buffer.append('C');
3035          break;
3036        case 'd':
3037          buffer.append('D');
3038          break;
3039        case 'e':
3040          buffer.append('E');
3041          break;
3042        case 'f':
3043          buffer.append('F');
3044          break;
3045        case 'g':
3046          buffer.append('G');
3047          break;
3048        case 'h':
3049          buffer.append('H');
3050          break;
3051        case 'i':
3052          buffer.append('I');
3053          break;
3054        case 'j':
3055          buffer.append('J');
3056          break;
3057        case 'k':
3058          buffer.append('K');
3059          break;
3060        case 'l':
3061          buffer.append('L');
3062          break;
3063        case 'm':
3064          buffer.append('M');
3065          break;
3066        case 'n':
3067          buffer.append('N');
3068          break;
3069        case 'o':
3070          buffer.append('O');
3071          break;
3072        case 'p':
3073          buffer.append('P');
3074          break;
3075        case 'q':
3076          buffer.append('Q');
3077          break;
3078        case 'r':
3079          buffer.append('R');
3080          break;
3081        case 's':
3082          buffer.append('S');
3083          break;
3084        case 't':
3085          buffer.append('T');
3086          break;
3087        case 'u':
3088          buffer.append('U');
3089          break;
3090        case 'v':
3091          buffer.append('V');
3092          break;
3093        case 'w':
3094          buffer.append('W');
3095          break;
3096        case 'x':
3097          buffer.append('X');
3098          break;
3099        case 'y':
3100          buffer.append('Y');
3101          break;
3102        case 'z':
3103          buffer.append('Z');
3104          break;
3105        default:
3106          buffer.append(c);
3107      }
3108    }
3109  }
3110
3111
3112
3113  /**
3114   * Appends an uppercase string representation of the contents of the given
3115   * byte array to the provided buffer, optionally trimming leading and trailing
3116   * spaces.  This implementation presumes that the provided string will contain
3117   * only ASCII characters and is optimized for that case.  However, if a
3118   * non-ASCII character is encountered it will fall back on a more expensive
3119   * algorithm that will work properly for non-ASCII characters.
3120   *
3121   * @param  b       The byte array for which to obtain the uppercase string
3122   *                 representation.
3123   * @param  buffer  The buffer to which the uppercase form of the string should
3124   *                 be appended.
3125   * @param  trim    Indicates whether leading and trailing spaces should be
3126   *                 omitted from the string representation.
3127   */
3128  public static void toUpperCase(byte[] b, StringBuilder buffer, boolean trim)
3129  {
3130    if (b == null)
3131    {
3132      return;
3133    }
3134
3135    int length = b.length;
3136    for (int i=0; i < length; i++)
3137    {
3138      if ((b[i] & 0x7F) != b[i])
3139      {
3140        try
3141        {
3142          buffer.append(new String(b, i, (length-i), "UTF-8").toUpperCase());
3143        }
3144        catch (Exception e)
3145        {
3146          logger.traceException(e);
3147          buffer.append(new String(b, i, (length - i)).toUpperCase());
3148        }
3149        break;
3150      }
3151
3152      int bufferLength = buffer.length();
3153      switch (b[i])
3154      {
3155        case ' ':
3156          // If we don't care about trimming, then we can always append the
3157          // space.  Otherwise, only do so if there are other characters in the value.
3158          if (trim && bufferLength == 0)
3159          {
3160            break;
3161          }
3162
3163          buffer.append(' ');
3164          break;
3165        case 'a':
3166          buffer.append('A');
3167          break;
3168        case 'b':
3169          buffer.append('B');
3170          break;
3171        case 'c':
3172          buffer.append('C');
3173          break;
3174        case 'd':
3175          buffer.append('D');
3176          break;
3177        case 'e':
3178          buffer.append('E');
3179          break;
3180        case 'f':
3181          buffer.append('F');
3182          break;
3183        case 'g':
3184          buffer.append('G');
3185          break;
3186        case 'h':
3187          buffer.append('H');
3188          break;
3189        case 'i':
3190          buffer.append('I');
3191          break;
3192        case 'j':
3193          buffer.append('J');
3194          break;
3195        case 'k':
3196          buffer.append('K');
3197          break;
3198        case 'l':
3199          buffer.append('L');
3200          break;
3201        case 'm':
3202          buffer.append('M');
3203          break;
3204        case 'n':
3205          buffer.append('N');
3206          break;
3207        case 'o':
3208          buffer.append('O');
3209          break;
3210        case 'p':
3211          buffer.append('P');
3212          break;
3213        case 'q':
3214          buffer.append('Q');
3215          break;
3216        case 'r':
3217          buffer.append('R');
3218          break;
3219        case 's':
3220          buffer.append('S');
3221          break;
3222        case 't':
3223          buffer.append('T');
3224          break;
3225        case 'u':
3226          buffer.append('U');
3227          break;
3228        case 'v':
3229          buffer.append('V');
3230          break;
3231        case 'w':
3232          buffer.append('W');
3233          break;
3234        case 'x':
3235          buffer.append('X');
3236          break;
3237        case 'y':
3238          buffer.append('Y');
3239          break;
3240        case 'z':
3241          buffer.append('Z');
3242          break;
3243        default:
3244          buffer.append((char) b[i]);
3245      }
3246    }
3247
3248    if (trim)
3249    {
3250      // Strip off any trailing spaces.
3251      for (int i=buffer.length()-1; i > 0; i--)
3252      {
3253        if (buffer.charAt(i) == ' ')
3254        {
3255          buffer.delete(i, i+1);
3256        }
3257        else
3258        {
3259          break;
3260        }
3261      }
3262    }
3263  }
3264
3265
3266
3267  /**
3268   * Append a string to a string builder, escaping any double quotes
3269   * according to the StringValue production in RFC 3641.
3270   * <p>
3271   * In RFC 3641 the StringValue production looks like this:
3272   *
3273   * <pre>
3274   *    StringValue       = dquote *SafeUTF8Character dquote
3275   *    dquote            = %x22 ; &quot; (double quote)
3276   *    SafeUTF8Character = %x00-21 / %x23-7F /   ; ASCII minus dquote
3277   *                        dquote dquote /       ; escaped double quote
3278   *                        %xC0-DF %x80-BF /     ; 2 byte UTF-8 character
3279   *                        %xE0-EF 2(%x80-BF) /  ; 3 byte UTF-8 character
3280   *                        %xF0-F7 3(%x80-BF)    ; 4 byte UTF-8 character
3281   * </pre>
3282   *
3283   * <p>
3284   * That is, strings are surrounded by double-quotes and any internal
3285   * double-quotes are doubled up.
3286   *
3287   * @param builder
3288   *          The string builder.
3289   * @param string
3290   *          The string to escape and append.
3291   * @return Returns the string builder.
3292   */
3293  public static StringBuilder toRFC3641StringValue(StringBuilder builder,
3294      String string)
3295  {
3296    // Initial double-quote.
3297    builder.append('"');
3298
3299    for (char c : string.toCharArray())
3300    {
3301      if (c == '"')
3302      {
3303        // Internal double-quotes are escaped using a double-quote.
3304        builder.append('"');
3305      }
3306      builder.append(c);
3307    }
3308
3309    // Trailing double-quote.
3310    builder.append('"');
3311
3312    return builder;
3313  }
3314
3315
3316
3317  /**
3318   * Retrieves a string array containing the contents of the provided
3319   * list of strings.
3320   *
3321   * @param stringList
3322   *          The string list to convert to an array.
3323   * @return A string array containing the contents of the provided list
3324   *         of strings.
3325   */
3326  public static String[] listToArray(List<String> stringList)
3327  {
3328    if (stringList == null)
3329    {
3330      return null;
3331    }
3332
3333    String[] stringArray = new String[stringList.size()];
3334    stringList.toArray(stringArray);
3335    return stringArray;
3336  }
3337
3338  /**
3339   * Retrieves an array list containing the contents of the provided array.
3340   *
3341   * @param  stringArray  The string array to convert to an array list.
3342   *
3343   * @return  An array list containing the contents of the provided array.
3344   */
3345  public static ArrayList<String> arrayToList(String... stringArray)
3346  {
3347    if (stringArray == null)
3348    {
3349      return null;
3350    }
3351
3352    ArrayList<String> stringList = new ArrayList<>(stringArray.length);
3353    Collections.addAll(stringList, stringArray);
3354    return stringList;
3355  }
3356
3357
3358  /**
3359   * Attempts to delete the specified file or directory. If it is a directory,
3360   * then any files or subdirectories that it contains will be recursively
3361   * deleted as well.
3362   *
3363   * @param file
3364   *          The file or directory to be removed.
3365   * @return {@code true} if the specified file and any subordinates are all
3366   *         successfully removed, or {@code false} if at least one element in
3367   *         the subtree could not be removed or file does not exists.
3368   */
3369  public static boolean recursiveDelete(File file)
3370  {
3371    if (file.exists())
3372    {
3373      boolean successful = true;
3374      if (file.isDirectory())
3375      {
3376        File[] childList = file.listFiles();
3377        if (childList != null)
3378        {
3379          for (File f : childList)
3380          {
3381            successful &= recursiveDelete(f);
3382          }
3383        }
3384      }
3385
3386      return successful & file.delete();
3387    }
3388    return false;
3389  }
3390
3391
3392
3393  /**
3394   * Moves the indicated file to the specified directory by creating a new file
3395   * in the target directory, copying the contents of the existing file, and
3396   * removing the existing file.  The file to move must exist and must be a
3397   * file.  The target directory must exist, must be a directory, and must not
3398   * be the directory in which the file currently resides.
3399   *
3400   * @param  fileToMove       The file to move to the target directory.
3401   * @param  targetDirectory  The directory into which the file should be moved.
3402   *
3403   * @throws  IOException  If a problem occurs while attempting to move the
3404   *                       file.
3405   */
3406  public static void moveFile(File fileToMove, File targetDirectory)
3407         throws IOException
3408  {
3409    if (! fileToMove.exists())
3410    {
3411      LocalizableMessage message = ERR_MOVEFILE_NO_SUCH_FILE.get(fileToMove.getPath());
3412      throw new IOException(message.toString());
3413    }
3414
3415    if (! fileToMove.isFile())
3416    {
3417      LocalizableMessage message = ERR_MOVEFILE_NOT_FILE.get(fileToMove.getPath());
3418      throw new IOException(message.toString());
3419    }
3420
3421    if (! targetDirectory.exists())
3422    {
3423      LocalizableMessage message =
3424          ERR_MOVEFILE_NO_SUCH_DIRECTORY.get(targetDirectory.getPath());
3425      throw new IOException(message.toString());
3426    }
3427
3428    if (! targetDirectory.isDirectory())
3429    {
3430      LocalizableMessage message =
3431          ERR_MOVEFILE_NOT_DIRECTORY.get(targetDirectory.getPath());
3432      throw new IOException(message.toString());
3433    }
3434
3435    String newFilePath = targetDirectory.getPath() + File.separator +
3436                         fileToMove.getName();
3437    FileInputStream  inputStream  = new FileInputStream(fileToMove);
3438    FileOutputStream outputStream = new FileOutputStream(newFilePath, false);
3439    byte[] buffer = new byte[8192];
3440    while (true)
3441    {
3442      int bytesRead = inputStream.read(buffer);
3443      if (bytesRead < 0)
3444      {
3445        break;
3446      }
3447
3448      outputStream.write(buffer, 0, bytesRead);
3449    }
3450
3451    outputStream.flush();
3452    outputStream.close();
3453    inputStream.close();
3454    fileToMove.delete();
3455  }
3456
3457  /**
3458   * Renames the source file to the target file.  If the target file exists
3459   * it is first deleted.  The rename and delete operation return values
3460   * are checked for success and if unsuccessful, this method throws an
3461   * exception.
3462   *
3463   * @param fileToRename The file to rename.
3464   * @param target       The file to which <code>fileToRename</code> will be
3465   *                     moved.
3466   * @throws IOException If a problem occurs while attempting to rename the
3467   *                     file.  On the Windows platform, this typically
3468   *                     indicates that the file is in use by this or another
3469   *                     application.
3470   */
3471  public static void renameFile(File fileToRename, File target)
3472          throws IOException {
3473    if (fileToRename != null && target != null)
3474    {
3475      synchronized(target)
3476      {
3477        if (target.exists() && !target.delete())
3478        {
3479          LocalizableMessage message =
3480              ERR_RENAMEFILE_CANNOT_DELETE_TARGET.get(target.getPath());
3481          throw new IOException(message.toString());
3482        }
3483      }
3484      if (!fileToRename.renameTo(target))
3485      {
3486        LocalizableMessage message = ERR_RENAMEFILE_CANNOT_RENAME.get(
3487            fileToRename.getPath(), target.getPath());
3488        throw new IOException(message.toString());
3489
3490      }
3491    }
3492  }
3493
3494
3495  /**
3496   * Indicates whether the provided path refers to a relative path rather than
3497   * an absolute path.
3498   *
3499   * @param  path  The path string for which to make the determination.
3500   *
3501   * @return  <CODE>true</CODE> if the provided path is relative, or
3502   *          <CODE>false</CODE> if it is absolute.
3503   */
3504  public static boolean isRelativePath(String path)
3505  {
3506    File f = new File(path);
3507    return !f.isAbsolute();
3508  }
3509
3510
3511
3512  /**
3513   * Retrieves a <CODE>File</CODE> object corresponding to the specified path.
3514   * If the given path is an absolute path, then it will be used.  If the path
3515   * is relative, then it will be interpreted as if it were relative to the
3516   * Directory Server root.
3517   *
3518   * @param  path  The path string to be retrieved as a <CODE>File</CODE>
3519   *
3520   * @return  A <CODE>File</CODE> object that corresponds to the specified path.
3521   */
3522  public static File getFileForPath(String path)
3523  {
3524    File f = new File (path);
3525
3526    if (f.isAbsolute())
3527    {
3528      return f;
3529    }
3530    else
3531    {
3532      return new File(DirectoryServer.getInstanceRoot() + File.separator +
3533          path);
3534    }
3535  }
3536
3537  /**
3538   * Retrieves a <CODE>File</CODE> object corresponding to the specified path.
3539   * If the given path is an absolute path, then it will be used.  If the path
3540   * is relative, then it will be interpreted as if it were relative to the
3541   * Directory Server root.
3542   *
3543   * @param path
3544   *           The path string to be retrieved as a <CODE>File</CODE>.
3545   * @param serverContext
3546   *           The server context.
3547   *
3548   * @return  A <CODE>File</CODE> object that corresponds to the specified path.
3549   */
3550  public static File getFileForPath(String path, ServerContext serverContext)
3551  {
3552    File f = new File (path);
3553
3554    if (f.isAbsolute())
3555    {
3556      return f;
3557    }
3558    else
3559    {
3560      return new File(serverContext.getInstanceRoot() + File.separator +
3561          path);
3562    }
3563  }
3564
3565
3566
3567  /**
3568   * Creates a new, blank entry with the given DN.  It will contain only the
3569   * attribute(s) contained in the RDN.  The choice of objectclasses will be
3570   * based on the RDN attribute.  If there is a single RDN attribute, then the
3571   * following mapping will be used:
3572   * <BR>
3573   * <UL>
3574   *   <LI>c attribute :: country objectclass</LI>
3575   *   <LI>dc attribute :: domain objectclass</LI>
3576   *   <LI>o attribute :: organization objectclass</LI>
3577   *   <LI>ou attribute :: organizationalUnit objectclass</LI>
3578   * </UL>
3579   * <BR>
3580   * Any other single RDN attribute types, or any case in which there are
3581   * multiple RDN attributes, will use the untypedObject objectclass.  If the
3582   * RDN includes one or more attributes that are not allowed in the
3583   * untypedObject objectclass, then the extensibleObject class will also be
3584   * added.  Note that this method cannot be used to generate an entry
3585   * with an empty or null DN.
3586   *
3587   * @param  dn  The DN to use for the entry.
3588   *
3589   * @return  The entry created with the provided DN.
3590   */
3591  public static Entry createEntry(DN dn)
3592  {
3593    // If the provided DN was null or empty, then return null because we don't
3594    // support it.
3595    if (dn == null || dn.isRootDN())
3596    {
3597      return null;
3598    }
3599
3600
3601    // Get the information about the RDN attributes.
3602    RDN rdn = dn.rdn();
3603    int numAVAs = rdn.getNumValues();
3604
3605    // If there is only one RDN attribute, then see which objectclass we should use.
3606    ObjectClass structuralClass = DirectoryServer.getObjectClass(getObjectClassName(rdn, numAVAs));
3607
3608    // Get the top and untypedObject classes to include in the entry.
3609    LinkedHashMap<ObjectClass,String> objectClasses = new LinkedHashMap<>(3);
3610
3611    objectClasses.put(DirectoryServer.getTopObjectClass(), OC_TOP);
3612    objectClasses.put(structuralClass, structuralClass.getNameOrOID());
3613
3614
3615    // Iterate through the RDN attributes and add them to the set of user or
3616    // operational attributes.
3617    LinkedHashMap<AttributeType,List<Attribute>> userAttributes = new LinkedHashMap<>();
3618    LinkedHashMap<AttributeType,List<Attribute>> operationalAttributes = new LinkedHashMap<>();
3619
3620    boolean extensibleObjectAdded = false;
3621    for (int i=0; i < numAVAs; i++)
3622    {
3623      AttributeType attrType = rdn.getAttributeType(i);
3624      ByteString attrValue = rdn.getAttributeValue(i);
3625      String attrName = rdn.getAttributeName(i);
3626
3627      // First, see if this type is allowed by the untypedObject class.  If not,
3628      // then we'll need to include the extensibleObject class.
3629      if (!structuralClass.isRequiredOrOptional(attrType) && !extensibleObjectAdded)
3630      {
3631        ObjectClass extensibleObjectOC =
3632             DirectoryServer.getObjectClass(OC_EXTENSIBLE_OBJECT_LC);
3633        if (extensibleObjectOC == null)
3634        {
3635          extensibleObjectOC =
3636               DirectoryServer.getDefaultObjectClass(OC_EXTENSIBLE_OBJECT);
3637        }
3638        objectClasses.put(extensibleObjectOC, OC_EXTENSIBLE_OBJECT);
3639        extensibleObjectAdded = true;
3640      }
3641
3642
3643      // Create the attribute and add it to the appropriate map.
3644      if (attrType.isOperational())
3645      {
3646        addAttributeValue(operationalAttributes, attrType, attrName, attrValue);
3647      }
3648      else
3649      {
3650        addAttributeValue(userAttributes, attrType, attrName, attrValue);
3651      }
3652    }
3653
3654
3655    // Create and return the entry.
3656    return new Entry(dn, objectClasses, userAttributes, operationalAttributes);
3657  }
3658
3659  private static String getObjectClassName(RDN rdn, int numAVAs)
3660  {
3661    if (numAVAs == 1)
3662    {
3663      final AttributeType attrType = rdn.getAttributeType(0);
3664      if (attrType.hasName(ATTR_C))
3665      {
3666        return OC_COUNTRY;
3667      }
3668      else if (attrType.hasName(ATTR_DC))
3669      {
3670        return OC_DOMAIN;
3671      }
3672      else if (attrType.hasName(ATTR_O))
3673      {
3674        return OC_ORGANIZATION;
3675      }
3676      else if (attrType.hasName(ATTR_OU))
3677      {
3678        return OC_ORGANIZATIONAL_UNIT_LC;
3679      }
3680    }
3681    return OC_UNTYPED_OBJECT_LC;
3682  }
3683
3684  private static void addAttributeValue(LinkedHashMap<AttributeType, List<Attribute>> attrs,
3685      AttributeType attrType, String attrName, ByteString attrValue)
3686  {
3687    List<Attribute> attrList = attrs.get(attrType);
3688    if (attrList != null && !attrList.isEmpty())
3689    {
3690      AttributeBuilder builder = new AttributeBuilder(attrList.get(0));
3691      builder.add(attrValue);
3692      attrList.set(0, builder.toAttribute());
3693    }
3694    else
3695    {
3696      AttributeBuilder builder = new AttributeBuilder(attrType, attrName);
3697      builder.add(attrValue);
3698      attrs.put(attrType, builder.toAttributeList());
3699    }
3700  }
3701
3702  /**
3703   * Retrieves a user-friendly string that indicates the length of time (in
3704   * days, hours, minutes, and seconds) in the specified number of seconds.
3705   *
3706   * @param  numSeconds  The number of seconds to be converted to a more
3707   *                     user-friendly value.
3708   *
3709   * @return  The user-friendly representation of the specified number of
3710   *          seconds.
3711   */
3712  public static LocalizableMessage secondsToTimeString(long numSeconds)
3713  {
3714    if (numSeconds < 60)
3715    {
3716      // We can express it in seconds.
3717      return INFO_TIME_IN_SECONDS.get(numSeconds);
3718    }
3719    else if (numSeconds < 3600)
3720    {
3721      // We can express it in minutes and seconds.
3722      long m = numSeconds / 60;
3723      long s = numSeconds % 60;
3724      return INFO_TIME_IN_MINUTES_SECONDS.get(m, s);
3725    }
3726    else if (numSeconds < 86400)
3727    {
3728      // We can express it in hours, minutes, and seconds.
3729      long h = numSeconds / 3600;
3730      long m = (numSeconds % 3600) / 60;
3731      long s = numSeconds % 3600 % 60;
3732      return INFO_TIME_IN_HOURS_MINUTES_SECONDS.get(h, m, s);
3733    }
3734    else
3735    {
3736      // We can express it in days, hours, minutes, and seconds.
3737      long d = numSeconds / 86400;
3738      long h = (numSeconds % 86400) / 3600;
3739      long m = (numSeconds % 86400 % 3600) / 60;
3740      long s = numSeconds % 86400 % 3600 % 60;
3741      return INFO_TIME_IN_DAYS_HOURS_MINUTES_SECONDS.get(d, h, m, s);
3742    }
3743  }
3744
3745  /**
3746   * Checks that no more that one of a set of arguments is present.  This
3747   * utility should be used after argument parser has parsed a set of
3748   * arguments.
3749   *
3750   * @param  args to test for the presence of more than one
3751   * @throws ArgumentException if more than one of <code>args</code> is
3752   *         present and containing an error message identifying the
3753   *         arguments in violation
3754   */
3755  public static void checkOnlyOneArgPresent(Argument... args)
3756    throws ArgumentException
3757  {
3758    if (args != null) {
3759      for (Argument arg : args) {
3760        for (Argument otherArg : args) {
3761          if (arg != otherArg && arg.isPresent() && otherArg.isPresent()) {
3762            throw new ArgumentException(
3763                    ToolMessages.ERR_INCOMPATIBLE_ARGUMENTS.get(
3764                            arg.getName(), otherArg.getName()));
3765          }
3766        }
3767      }
3768    }
3769  }
3770
3771  /**
3772   * Converts a string representing a time in "yyyyMMddHHmmss.SSS'Z'" or
3773   * "yyyyMMddHHmmss" to a <code>Date</code>.
3774   *
3775   * @param timeStr string formatted appropriately
3776   * @return Date object; null if <code>timeStr</code> is null
3777   * @throws ParseException if there was a problem converting the string to
3778   *         a <code>Date</code>.
3779   */
3780  public static Date parseDateTimeString(String timeStr) throws ParseException
3781  {
3782    Date dateTime = null;
3783    if (timeStr != null)
3784    {
3785      if (timeStr.endsWith("Z"))
3786      {
3787        try
3788        {
3789          SimpleDateFormat dateFormat =
3790            new SimpleDateFormat(DATE_FORMAT_GENERALIZED_TIME);
3791          dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
3792          dateFormat.setLenient(true);
3793          dateTime = dateFormat.parse(timeStr);
3794        }
3795        catch (ParseException pe)
3796        {
3797          // Best effort: try with GMT time.
3798          SimpleDateFormat dateFormat =
3799            new SimpleDateFormat(DATE_FORMAT_GMT_TIME);
3800          dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
3801          dateFormat.setLenient(true);
3802          dateTime = dateFormat.parse(timeStr);
3803        }
3804      }
3805      else
3806      {
3807        SimpleDateFormat dateFormat =
3808            new SimpleDateFormat(DATE_FORMAT_COMPACT_LOCAL_TIME);
3809        dateFormat.setLenient(true);
3810        dateTime = dateFormat.parse(timeStr);
3811      }
3812    }
3813    return dateTime;
3814  }
3815
3816  /**
3817   * Formats a Date to String representation in "yyyyMMddHHmmss'Z'".
3818   *
3819   * @param date to format; null if <code>date</code> is null
3820   * @return string representation of the date
3821   */
3822  public static String formatDateTimeString(Date date)
3823  {
3824    String timeStr = null;
3825    if (date != null)
3826    {
3827      SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT_GMT_TIME);
3828      dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
3829      timeStr = dateFormat.format(date);
3830    }
3831    return timeStr;
3832  }
3833
3834  /**
3835   * Indicates whether or not a string represents a syntactically correct
3836   * email address.
3837   *
3838   * @param addr to validate
3839   * @return boolean where <code>true</code> indicates that the string is a
3840   *         syntactically correct email address
3841   */
3842  public static boolean isEmailAddress(String addr) {
3843
3844    // This just does basic syntax checking.  Perhaps we
3845    // might want to be stricter about this.
3846    return addr != null && addr.contains("@") && addr.contains(".");
3847
3848  }
3849
3850
3851
3852  /**
3853   * Writes the contents of the provided buffer to the client,
3854   * terminating the connection if the write is unsuccessful for too
3855   * long (e.g., if the client is unresponsive or there is a network
3856   * problem). If possible, it will attempt to use the selector returned
3857   * by the {@code ClientConnection.getWriteSelector} method, but it is
3858   * capable of working even if that method returns {@code null}. <BR>
3859   *
3860   * Note that the original position and limit values will not be
3861   * preserved, so if that is important to the caller, then it should
3862   * record them before calling this method and restore them after it
3863   * returns.
3864   *
3865   * @param clientConnection
3866   *          The client connection to which the data is to be written.
3867   * @param buffer
3868   *          The data to be written to the client.
3869   * @return <CODE>true</CODE> if all the data in the provided buffer was
3870   *         written to the client and the connection may remain
3871   *         established, or <CODE>false</CODE> if a problem occurred
3872   *         and the client connection is no longer valid. Note that if
3873   *         this method does return <CODE>false</CODE>, then it must
3874   *         have already disconnected the client.
3875   * @throws IOException
3876   *           If a problem occurs while attempting to write data to the
3877   *           client. The caller will be responsible for catching this
3878   *           and terminating the client connection.
3879   */
3880  public static boolean writeWithTimeout(ClientConnection clientConnection,
3881      ByteBuffer buffer) throws IOException
3882  {
3883    SocketChannel socketChannel = clientConnection.getSocketChannel();
3884    long startTime = System.currentTimeMillis();
3885    long waitTime = clientConnection.getMaxBlockedWriteTimeLimit();
3886    if (waitTime <= 0)
3887    {
3888      // We won't support an infinite time limit, so fall back to using
3889      // five minutes, which is a very long timeout given that we're
3890      // blocking a worker thread.
3891      waitTime = 300000L;
3892    }
3893
3894    long stopTime = startTime + waitTime;
3895
3896    Selector selector = clientConnection.getWriteSelector();
3897    if (selector == null)
3898    {
3899      // The client connection does not provide a selector, so we'll
3900      // fall back
3901      // to a more inefficient way that will work without a selector.
3902      while (buffer.hasRemaining()
3903          && System.currentTimeMillis() < stopTime)
3904      {
3905        if (socketChannel.write(buffer) < 0)
3906        {
3907          // The client connection has been closed.
3908          return false;
3909        }
3910      }
3911
3912      if (buffer.hasRemaining())
3913      {
3914        // If we've gotten here, then the write timed out.
3915        return false;
3916      }
3917
3918      return true;
3919    }
3920
3921    // Register with the selector for handling write operations.
3922    SelectionKey key =
3923        socketChannel.register(selector, SelectionKey.OP_WRITE);
3924
3925    try
3926    {
3927      selector.select(waitTime);
3928      while (buffer.hasRemaining())
3929      {
3930        long currentTime = System.currentTimeMillis();
3931        if (currentTime >= stopTime)
3932        {
3933          // We've been blocked for too long.
3934          return false;
3935        }
3936        else
3937        {
3938          waitTime = stopTime - currentTime;
3939        }
3940
3941        Iterator<SelectionKey> iterator =
3942            selector.selectedKeys().iterator();
3943        while (iterator.hasNext())
3944        {
3945          SelectionKey k = iterator.next();
3946          if (k.isWritable())
3947          {
3948            int bytesWritten = socketChannel.write(buffer);
3949            if (bytesWritten < 0)
3950            {
3951              // The client connection has been closed.
3952              return false;
3953            }
3954
3955            iterator.remove();
3956          }
3957        }
3958
3959        if (buffer.hasRemaining())
3960        {
3961          selector.select(waitTime);
3962        }
3963      }
3964
3965      return true;
3966    }
3967    finally
3968    {
3969      if (key.isValid())
3970      {
3971        key.cancel();
3972        selector.selectNow();
3973      }
3974    }
3975  }
3976
3977
3978
3979  /**
3980   * Add all of the superior objectclasses to the specified objectclass
3981   * map if they don't already exist. Used by add and import-ldif to
3982   * add missing superior objectclasses to entries that don't have them.
3983   *
3984   * @param objectClasses A Map of objectclasses.
3985   */
3986  public static void addSuperiorObjectClasses(Map<ObjectClass,
3987      String> objectClasses) {
3988      HashSet<ObjectClass> additionalClasses = null;
3989      for (ObjectClass oc : objectClasses.keySet())
3990      {
3991        for(ObjectClass superiorClass : oc.getSuperiorClasses())
3992        {
3993          if (! objectClasses.containsKey(superiorClass))
3994          {
3995            if (additionalClasses == null)
3996            {
3997              additionalClasses = new HashSet<>();
3998            }
3999
4000            additionalClasses.add(superiorClass);
4001          }
4002        }
4003      }
4004
4005      if (additionalClasses != null)
4006      {
4007        for (ObjectClass oc : additionalClasses)
4008        {
4009          addObjectClassChain(oc, objectClasses);
4010        }
4011      }
4012  }
4013
4014  private static void addObjectClassChain(ObjectClass objectClass,
4015      Map<ObjectClass, String> objectClasses)
4016  {
4017    if (objectClasses != null){
4018      if (! objectClasses.containsKey(objectClass))
4019      {
4020        objectClasses.put(objectClass, objectClass.getNameOrOID());
4021      }
4022
4023      for(ObjectClass superiorClass : objectClass.getSuperiorClasses())
4024      {
4025        if (! objectClasses.containsKey(superiorClass))
4026        {
4027          addObjectClassChain(superiorClass, objectClasses);
4028        }
4029      }
4030    }
4031  }
4032
4033
4034  /**
4035   * Closes the provided {@link Closeable}'s ignoring any errors which
4036   * occurred.
4037   *
4038   * @param closeables The closeables to be closed, which may be
4039   *        <code>null</code>.
4040   */
4041  public static void close(Closeable... closeables)
4042  {
4043    if (closeables == null)
4044    {
4045      return;
4046    }
4047    close(Arrays.asList(closeables));
4048  }
4049
4050  /**
4051   * Closes the provided {@link Closeable}'s ignoring any errors which occurred.
4052   *
4053   * @param closeables
4054   *          The closeables to be closed, which may be <code>null</code>.
4055   */
4056  public static void close(Collection<? extends Closeable> closeables)
4057  {
4058    if (closeables == null)
4059    {
4060      return;
4061    }
4062    for (Closeable closeable : closeables)
4063    {
4064      if (closeable != null)
4065      {
4066        try
4067        {
4068          closeable.close();
4069        }
4070        catch (IOException ignored)
4071        {
4072          logger.traceException(ignored);
4073        }
4074      }
4075    }
4076  }
4077
4078  /**
4079   * Closes the provided {@link InitialContext}s ignoring any errors which occurred.
4080   *
4081   * @param ctxs
4082   *          The contexts to be closed, which may be <code>null</code>.
4083   */
4084  public static void close(InitialContext... ctxs)
4085  {
4086    if (ctxs == null)
4087    {
4088      return;
4089    }
4090    for (InitialContext ctx : ctxs)
4091    {
4092      if (ctx != null)
4093      {
4094        try
4095        {
4096          ctx.close();
4097        }
4098        catch (NamingException ignored)
4099        {
4100          // ignore
4101        }
4102      }
4103    }
4104  }
4105
4106  /**
4107   * Calls {@link Thread#sleep(long)}, surrounding it with the mandatory
4108   * <code>try</code> / <code>catch(InterruptedException)</code> block.
4109   *
4110   * @param millis
4111   *          the length of time to sleep in milliseconds
4112   */
4113  public static void sleep(long millis)
4114  {
4115    try
4116    {
4117      Thread.sleep(millis);
4118    }
4119    catch (InterruptedException wokenUp)
4120    {
4121      // ignore
4122    }
4123  }
4124
4125  /**
4126   * Test if the provided message corresponds to the provided descriptor.
4127   *
4128   * @param msg
4129   *          The i18n message.
4130   * @param desc
4131   *          The message descriptor.
4132   * @return {@code true} if message corresponds to descriptor
4133   */
4134  public static boolean hasDescriptor(LocalizableMessage msg,
4135      LocalizableMessageDescriptor.Arg0 desc)
4136  {
4137    return msg.ordinal() == desc.ordinal()
4138        && msg.resourceName().equals(desc.resourceName());
4139  }
4140
4141  /**
4142   * Test if the provided message corresponds to the provided descriptor.
4143   *
4144   * @param msg
4145   *          The i18n message.
4146   * @param desc
4147   *          The message descriptor.
4148   * @return {@code true} if message corresponds to descriptor
4149   */
4150  public static boolean hasDescriptor(LocalizableMessage msg,
4151      LocalizableMessageDescriptor.Arg1 desc)
4152  {
4153    return msg.ordinal() == desc.ordinal()
4154        && msg.resourceName().equals(desc.resourceName());
4155  }
4156
4157  /**
4158   * Test if the provided message corresponds to the provided descriptor.
4159   *
4160   * @param msg
4161   *          The i18n message.
4162   * @param desc
4163   *          The message descriptor.
4164   * @return {@code true} if message corresponds to descriptor
4165   */
4166  public static boolean hasDescriptor(LocalizableMessage msg,
4167      LocalizableMessageDescriptor.Arg2 desc)
4168  {
4169    return msg.ordinal() == desc.ordinal()
4170        && msg.resourceName().equals(desc.resourceName());
4171  }
4172
4173  /**
4174   * Test if the provided message corresponds to the provided descriptor.
4175   *
4176   * @param msg
4177   *          The i18n message.
4178   * @param desc
4179   *          The message descriptor.
4180   * @return {@code true} if message corresponds to descriptor
4181   */
4182  public static boolean hasDescriptor(LocalizableMessage msg,
4183      LocalizableMessageDescriptor.Arg3 desc)
4184  {
4185    return msg.ordinal() == desc.ordinal()
4186        && msg.resourceName().equals(desc.resourceName());
4187  }
4188
4189  /**
4190   * Test if the provided message corresponds to the provided descriptor.
4191   *
4192   * @param msg
4193   *          The i18n message.
4194   * @param desc
4195   *          The message descriptor.
4196   * @return {@code true} if message corresponds to descriptor
4197   */
4198  public static boolean hasDescriptor(LocalizableMessage msg,
4199      LocalizableMessageDescriptor.Arg7 desc)
4200  {
4201    return msg.ordinal() == desc.ordinal()
4202        && msg.resourceName().equals(desc.resourceName());
4203  }
4204
4205  /**
4206   * Returns an {@link Iterable} returning the passed in {@link Iterator}. THis
4207   * allows using methods returning Iterators with foreach statements.
4208   * <p>
4209   * For example, consider a method with this signature:
4210   * <p>
4211   * <code>public Iterator&lt;String&gt; myIteratorMethod();</code>
4212   * <p>
4213   * Classical use with for or while loop:
4214   *
4215   * <pre>
4216   * for (Iterator&lt;String&gt; it = myIteratorMethod(); it.hasNext();)
4217   * {
4218   *   String s = it.next();
4219   *   // use it
4220   * }
4221   *
4222   * Iterator&lt;String&gt; it = myIteratorMethod();
4223   * while(it.hasNext();)
4224   * {
4225   *   String s = it.next();
4226   *   // use it
4227   * }
4228   * </pre>
4229   *
4230   * Improved use with foreach:
4231   *
4232   * <pre>
4233   * for (String s : StaticUtils.toIterable(myIteratorMethod()))
4234   * {
4235   * }
4236   * </pre>
4237   *
4238   * </p>
4239   *
4240   * @param <T>
4241   *          the generic type of the passed in Iterator and for the returned
4242   *          Iterable.
4243   * @param iterator
4244   *          the Iterator that will be returned by the Iterable.
4245   * @return an Iterable returning the passed in Iterator
4246   */
4247  public static <T> Iterable<T> toIterable(final Iterator<T> iterator)
4248  {
4249    return new Iterable<T>()
4250    {
4251      @Override
4252      public Iterator<T> iterator()
4253      {
4254        return iterator;
4255      }
4256    };
4257  }
4258}
4259