001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2006-2010 Sun Microsystems, Inc.
015 * Portions Copyright 2011-2016 ForgeRock AS.
016 */
017package org.opends.server.util;
018
019import static org.opends.messages.UtilityMessages.*;
020import static org.opends.server.util.ServerConstants.*;
021
022import java.io.BufferedReader;
023import java.io.Closeable;
024import java.io.File;
025import java.io.FileInputStream;
026import java.io.FileOutputStream;
027import java.io.IOException;
028import java.io.InputStream;
029import java.io.InputStreamReader;
030import java.io.UnsupportedEncodingException;
031import java.net.InetAddress;
032import java.net.InetSocketAddress;
033import java.net.ServerSocket;
034import java.net.Socket;
035import java.nio.ByteBuffer;
036import java.nio.channels.SelectionKey;
037import java.nio.channels.Selector;
038import java.nio.channels.SocketChannel;
039import java.text.ParseException;
040import java.text.SimpleDateFormat;
041import java.util.ArrayList;
042import java.util.Arrays;
043import java.util.Collection;
044import java.util.Collections;
045import java.util.Date;
046import java.util.HashSet;
047import java.util.Iterator;
048import java.util.LinkedHashMap;
049import java.util.List;
050import java.util.Map;
051import java.util.RandomAccess;
052import java.util.TimeZone;
053
054import javax.naming.InitialContext;
055import javax.naming.NamingException;
056
057import org.forgerock.i18n.LocalizableMessage;
058import org.forgerock.i18n.LocalizableMessageBuilder;
059import org.forgerock.i18n.LocalizableMessageDescriptor;
060import org.forgerock.i18n.slf4j.LocalizedLogger;
061import org.forgerock.opendj.ldap.AVA;
062import org.forgerock.opendj.ldap.ByteSequence;
063import org.forgerock.opendj.ldap.ByteString;
064import org.forgerock.opendj.ldap.DN;
065import org.forgerock.opendj.ldap.RDN;
066import org.forgerock.opendj.ldap.schema.AttributeType;
067import org.forgerock.util.Reject;
068import org.opends.messages.ToolMessages;
069import org.opends.server.api.ClientConnection;
070import org.opends.server.core.DirectoryServer;
071import org.opends.server.core.ServerContext;
072import org.opends.server.types.Attribute;
073import org.opends.server.types.AttributeBuilder;
074import org.opends.server.types.Entry;
075import org.opends.server.types.IdentifiedException;
076import org.opends.server.types.ObjectClass;
077
078import com.forgerock.opendj.cli.Argument;
079import com.forgerock.opendj.cli.ArgumentException;
080
081/**
082 * This class defines a number of static utility methods that may be used
083 * throughout the server.  Note that because of the frequency with which these
084 * methods are expected to be used, very little debug logging will be performed
085 * to prevent the log from filling up with unimportant calls and to reduce the
086 * impact that debugging may have on performance.
087 */
088@org.opends.server.types.PublicAPI(
089     stability=org.opends.server.types.StabilityLevel.UNCOMMITTED,
090     mayInstantiate=false,
091     mayExtend=false,
092     mayInvoke=true)
093public final class StaticUtils
094{
095  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
096
097  /** The number of bytes of a Java int. A Java int is 32 bits, i.e. 4 bytes. */
098  public static final int INT_SIZE = 4;
099  /** The number of bytes of a Java long. A Java int is 64 bits, i.e. 8 bytes. */
100  public static final int LONG_SIZE = 8;
101
102  /**
103   * Number of bytes in a Kibibyte.
104   * <p>
105   * Example usage:
106   * <pre>
107   * int _10KB = 10 * KB;
108   * </pre>
109   */
110  public static final int KB = 1024;
111  /**
112   * Number of bytes in a Mebibyte.
113   * <p>
114   * Example usage:
115   * <pre>
116   * int _10MB = 10 * MB;
117   * </pre>
118   */
119  public static final int MB = KB * KB;
120
121  /** Private constructor to prevent instantiation. */
122  private StaticUtils() {
123    // No implementation required.
124  }
125
126  /**
127   * Construct a byte array containing the UTF-8 encoding of the
128   * provided string. This is significantly faster
129   * than calling {@link String#getBytes(String)} for ASCII strings.
130   *
131   * @param s
132   *          The string to convert to a UTF-8 byte array.
133   * @return Returns a byte array containing the UTF-8 encoding of the
134   *         provided string.
135   */
136  public static byte[] getBytes(String s)
137  {
138    return com.forgerock.opendj.util.StaticUtils.getBytes(s);
139  }
140
141
142  /**
143   * Returns the provided byte array decoded as a UTF-8 string without throwing
144   * an UnsupportedEncodingException. This method is equivalent to:
145   *
146   * <pre>
147   * try
148   * {
149   *   return new String(bytes, &quot;UTF-8&quot;);
150   * }
151   * catch (UnsupportedEncodingException e)
152   * {
153   *   // Should never happen: UTF-8 is always supported.
154   *   throw new RuntimeException(e);
155   * }
156   * </pre>
157   *
158   * @param bytes
159   *          The byte array to be decoded as a UTF-8 string.
160   * @return The decoded string.
161   */
162  public static String decodeUTF8(final byte[] bytes)
163  {
164    Reject.ifNull(bytes);
165
166    if (bytes.length == 0)
167    {
168      return "".intern();
169    }
170
171    final StringBuilder builder = new StringBuilder(bytes.length);
172    final int sz = bytes.length;
173
174    for (int i = 0; i < sz; i++)
175    {
176      final byte b = bytes[i];
177      if ((b & 0x7f) != b)
178      {
179        try
180        {
181          builder.append(new String(bytes, i, (sz - i), "UTF-8"));
182        }
183        catch (UnsupportedEncodingException e)
184        {
185          // Should never happen: UTF-8 is always supported.
186          throw new RuntimeException(e);
187        }
188        break;
189      }
190      builder.append((char) b);
191    }
192    return builder.toString();
193  }
194
195
196
197  /**
198   * Retrieves a string representation of the provided byte in hexadecimal.
199   *
200   * @param b   The byte for which to retrieve the hexadecimal string
201   *            representation.
202   * @return The string representation of the provided byte in hexadecimal.
203   */
204
205  public static String byteToHex(final byte b)
206  {
207    return com.forgerock.opendj.util.StaticUtils.byteToHex(b);
208  }
209  /**
210   * Retrieves a string representation of the provided byte in hexadecimal.
211   *
212   * @param  b  The byte for which to retrieve the hexadecimal string
213   *            representation.
214   * @return The string representation of the provided byte in hexadecimal
215   *         using lowercase characters.
216   */
217  public static String byteToLowerHex(final byte b)
218  {
219    return com.forgerock.opendj.util.StaticUtils.byteToLowerHex(b);
220  }
221
222  /**
223   * Retrieves a string representation of the contents of the provided byte
224   * array using hexadecimal characters with no space between each byte.
225   *
226   * @param  b  The byte array containing the data.
227   *
228   * @return  A string representation of the contents of the provided byte
229   *          array using hexadecimal characters.
230   */
231  public static String bytesToHexNoSpace(byte[] b)
232  {
233    if (b == null || b.length == 0)
234    {
235      return "";
236    }
237
238    int arrayLength = b.length;
239    StringBuilder buffer = new StringBuilder(arrayLength * 2);
240
241    for (int i=0; i < arrayLength; i++)
242    {
243      buffer.append(byteToHex(b[i]));
244    }
245
246    return buffer.toString();
247  }
248
249
250
251  /**
252   * Retrieves a string representation of the contents of the provided byte
253   * array using hexadecimal characters and a space between each byte.
254   *
255   * @param  b  The byte array containing the data.
256   * @return  A string representation of the contents of the provided byte
257   *          array using hexadecimal characters.
258   */
259  public static String bytesToHex(byte[] b)
260  {
261    if (b == null || b.length == 0)
262    {
263      return "";
264    }
265
266    int arrayLength = b.length;
267    StringBuilder buffer = new StringBuilder((arrayLength - 1) * 3 + 2);
268    buffer.append(byteToHex(b[0]));
269
270    for (int i=1; i < arrayLength; i++)
271    {
272      buffer.append(" ");
273      buffer.append(byteToHex(b[i]));
274    }
275
276    return buffer.toString();
277  }
278
279  /**
280   * Retrieves a string representation of the contents of the provided byte
281   * sequence using hexadecimal characters and a space between each byte.
282   *
283   * @param b The byte sequence containing the data.
284   * @return A string representation of the contents of the provided byte
285   *         sequence using hexadecimal characters.
286   */
287  public static String bytesToHex(ByteSequence b)
288  {
289    if (b == null || b.length() == 0)
290    {
291      return "";
292    }
293
294    int arrayLength = b.length();
295    StringBuilder buffer = new StringBuilder((arrayLength - 1) * 3 + 2);
296    buffer.append(byteToHex(b.byteAt(0)));
297
298    for (int i=1; i < arrayLength; i++)
299    {
300      buffer.append(" ");
301      buffer.append(byteToHex(b.byteAt(i)));
302    }
303
304    return buffer.toString();
305  }
306
307
308
309  /**
310   * Retrieves a string representation of the contents of the provided byte
311   * array using hexadecimal characters and a colon between each byte.
312   *
313   * @param  b  The byte array containing the data.
314   *
315   * @return  A string representation of the contents of the provided byte
316   *          array using hexadecimal characters.
317   */
318  public static String bytesToColonDelimitedHex(byte[] b)
319  {
320    if (b == null || b.length == 0)
321    {
322      return "";
323    }
324
325    int arrayLength = b.length;
326    StringBuilder buffer = new StringBuilder((arrayLength - 1) * 3 + 2);
327    buffer.append(byteToHex(b[0]));
328
329    for (int i=1; i < arrayLength; i++)
330    {
331      buffer.append(":");
332      buffer.append(byteToHex(b[i]));
333    }
334
335    return buffer.toString();
336  }
337
338
339
340  /**
341   * Retrieves a string representation of the contents of the provided byte
342   * buffer using hexadecimal characters and a space between each byte.
343   *
344   * @param  b  The byte buffer containing the data.
345   *
346   * @return  A string representation of the contents of the provided byte
347   *          buffer using hexadecimal characters.
348   */
349  public static String bytesToHex(ByteBuffer b)
350  {
351    if (b == null)
352    {
353      return "";
354    }
355
356    int position = b.position();
357    int limit    = b.limit();
358    int length   = limit - position;
359
360    if (length == 0)
361    {
362      return "";
363    }
364
365    StringBuilder buffer = new StringBuilder((length - 1) * 3 + 2);
366    buffer.append(byteToHex(b.get()));
367
368    for (int i=1; i < length; i++)
369    {
370      buffer.append(" ");
371      buffer.append(byteToHex(b.get()));
372    }
373
374    b.position(position);
375    b.limit(limit);
376
377    return buffer.toString();
378  }
379
380
381
382  /**
383   * Appends a string representation of the provided byte array to the given
384   * buffer using the specified indent.  The data will be formatted with sixteen
385   * hex bytes in a row followed by the ASCII representation, then wrapping to a
386   * new line as necessary.
387   *
388   * @param  buffer  The buffer to which the information is to be appended.
389   * @param  b       The byte array containing the data to write.
390   * @param  indent  The number of spaces to indent the output.
391   */
392  public static void byteArrayToHexPlusAscii(StringBuilder buffer, byte[] b,
393                                             int indent)
394  {
395    StringBuilder indentBuf = new StringBuilder(indent);
396    for (int i=0 ; i < indent; i++)
397    {
398      indentBuf.append(' ');
399    }
400
401
402
403    int length = b.length;
404    int pos    = 0;
405    while (length - pos >= 16)
406    {
407      StringBuilder asciiBuf = new StringBuilder(17);
408
409      buffer.append(indentBuf);
410      buffer.append(byteToHex(b[pos]));
411      asciiBuf.append(byteToASCII(b[pos]));
412      pos++;
413
414      for (int i=1; i < 16; i++, pos++)
415      {
416        buffer.append(' ');
417        buffer.append(byteToHex(b[pos]));
418        asciiBuf.append(byteToASCII(b[pos]));
419
420        if (i == 7)
421        {
422          buffer.append("  ");
423          asciiBuf.append(' ');
424        }
425      }
426
427      buffer.append("  ");
428      buffer.append(asciiBuf);
429      buffer.append(EOL);
430    }
431
432
433    int remaining = length - pos;
434    if (remaining > 0)
435    {
436      StringBuilder asciiBuf = new StringBuilder(remaining+1);
437
438      buffer.append(indentBuf);
439      buffer.append(byteToHex(b[pos]));
440      asciiBuf.append(byteToASCII(b[pos]));
441      pos++;
442
443      for (int i=1; i < 16; i++)
444      {
445        buffer.append(' ');
446
447        if (i < remaining)
448        {
449          buffer.append(byteToHex(b[pos]));
450          asciiBuf.append(byteToASCII(b[pos]));
451          pos++;
452        }
453        else
454        {
455          buffer.append("  ");
456        }
457
458        if (i == 7)
459        {
460          buffer.append("  ");
461
462          if (i < remaining)
463          {
464            asciiBuf.append(' ');
465          }
466        }
467      }
468
469      buffer.append("  ");
470      buffer.append(asciiBuf);
471      buffer.append(EOL);
472    }
473  }
474
475  private static char byteToASCII(byte b)
476  {
477    return com.forgerock.opendj.util.StaticUtils.byteToASCII(b);
478  }
479
480  /**
481   * Appends a string representation of the remaining unread data in the
482   * provided byte buffer to the given buffer using the specified indent.
483   * The data will be formatted with sixteen hex bytes in a row followed by
484   * the ASCII representation, then wrapping to a new line as necessary.
485   * The state of the byte buffer is not changed.
486   *
487   * @param  buffer  The buffer to which the information is to be appended.
488   * @param  b       The byte buffer containing the data to write.
489   *                 The data from the position to the limit is written.
490   * @param  indent  The number of spaces to indent the output.
491   */
492  public static void byteArrayToHexPlusAscii(StringBuilder buffer, ByteBuffer b,
493                                             int indent)
494  {
495    StringBuilder indentBuf = new StringBuilder(indent);
496    for (int i=0 ; i < indent; i++)
497    {
498      indentBuf.append(' ');
499    }
500
501
502    int position = b.position();
503    int limit    = b.limit();
504    int length   = limit - position;
505    int pos      = 0;
506    while (length - pos >= 16)
507    {
508      StringBuilder asciiBuf = new StringBuilder(17);
509
510      byte currentByte = b.get();
511      buffer.append(indentBuf);
512      buffer.append(byteToHex(currentByte));
513      asciiBuf.append(byteToASCII(currentByte));
514      pos++;
515
516      for (int i=1; i < 16; i++, pos++)
517      {
518        currentByte = b.get();
519        buffer.append(' ');
520        buffer.append(byteToHex(currentByte));
521        asciiBuf.append(byteToASCII(currentByte));
522
523        if (i == 7)
524        {
525          buffer.append("  ");
526          asciiBuf.append(' ');
527        }
528      }
529
530      buffer.append("  ");
531      buffer.append(asciiBuf);
532      buffer.append(EOL);
533    }
534
535
536    int remaining = length - pos;
537    if (remaining > 0)
538    {
539      StringBuilder asciiBuf = new StringBuilder(remaining+1);
540
541      byte currentByte = b.get();
542      buffer.append(indentBuf);
543      buffer.append(byteToHex(currentByte));
544      asciiBuf.append(byteToASCII(currentByte));
545
546      for (int i=1; i < 16; i++)
547      {
548        buffer.append(' ');
549
550        if (i < remaining)
551        {
552          currentByte = b.get();
553          buffer.append(byteToHex(currentByte));
554          asciiBuf.append(byteToASCII(currentByte));
555        }
556        else
557        {
558          buffer.append("  ");
559        }
560
561        if (i == 7)
562        {
563          buffer.append("  ");
564
565          if (i < remaining)
566          {
567            asciiBuf.append(' ');
568          }
569        }
570      }
571
572      buffer.append("  ");
573      buffer.append(asciiBuf);
574      buffer.append(EOL);
575    }
576
577    b.position(position);
578    b.limit(limit);
579  }
580
581
582
583  /**
584   * Compare two byte arrays for order. Returns a negative integer,
585   * zero, or a positive integer as the first argument is less than,
586   * equal to, or greater than the second.
587   *
588   * @param a
589   *          The first byte array to be compared.
590   * @param a2
591   *          The second byte array to be compared.
592   * @return Returns a negative integer, zero, or a positive integer
593   *         if the first byte array is less than, equal to, or greater
594   *         than the second.
595   */
596  public static int compare(byte[] a, byte[] a2) {
597    if (a == a2) {
598      return 0;
599    }
600
601    if (a == null) {
602      return -1;
603    }
604
605    if (a2 == null) {
606      return 1;
607    }
608
609    int minLength = Math.min(a.length, a2.length);
610    for (int i = 0; i < minLength; i++) {
611      int firstByte = 0xFF & a[i];
612      int secondByte = 0xFF & a2[i];
613      if (firstByte != secondByte) {
614        if (firstByte < secondByte) {
615          return -1;
616        } else if (firstByte > secondByte) {
617          return 1;
618        }
619      }
620    }
621
622    return a.length - a2.length;
623  }
624
625
626
627  /**
628   * Indicates whether the two array lists are equal. They will be
629   * considered equal if they have the same number of elements, and
630   * the corresponding elements between them are equal (in the same
631   * order).
632   *
633   * @param list1
634   *          The first list for which to make the determination.
635   * @param list2
636   *          The second list for which to make the determination.
637   * @return {@code true} if the two array lists are equal, or
638   *         {@code false} if they are not.
639   */
640  public static boolean listsAreEqual(List<?> list1, List<?> list2)
641  {
642    if (list1 == null)
643    {
644      return list2 == null;
645    }
646    else if (list2 == null)
647    {
648      return false;
649    }
650
651    int numElements = list1.size();
652    if (numElements != list2.size())
653    {
654      return false;
655    }
656
657    // If either of the lists doesn't support random access, then fall back
658    // on their equals methods and go ahead and create some garbage with the
659    // iterators.
660    if (!(list1 instanceof RandomAccess) ||
661        !(list2 instanceof RandomAccess))
662    {
663      return list1.equals(list2);
664    }
665
666    // Otherwise we can just retrieve the elements efficiently via their index.
667    for (int i=0; i < numElements; i++)
668    {
669      Object o1 = list1.get(i);
670      Object o2 = list2.get(i);
671
672      if (o1 == null)
673      {
674        if (o2 != null)
675        {
676          return false;
677        }
678      }
679      else if (! o1.equals(o2))
680      {
681        return false;
682      }
683    }
684
685    return true;
686  }
687
688  /**
689   * Retrieves the best human-readable message for the provided exception.  For
690   * exceptions defined in the OpenDJ project, it will attempt to use the
691   * message (combining it with the message ID if available).  For some
692   * exceptions that use encapsulation (e.g., InvocationTargetException), it
693   * will be unwrapped and the cause will be treated.  For all others, the
694   *
695   *
696   * @param  t  The {@code Throwable} object for which to retrieve the message.
697   *
698   * @return  The human-readable message generated for the provided exception.
699   */
700  public static LocalizableMessage getExceptionMessage(Throwable t)
701  {
702    if (t instanceof IdentifiedException)
703    {
704      IdentifiedException ie = (IdentifiedException) t;
705
706      StringBuilder message = new StringBuilder();
707      message.append(ie.getMessage());
708      message.append(" (id=");
709      LocalizableMessage ieMsg = ie.getMessageObject();
710      if (ieMsg != null) {
711        message.append(ieMsg.resourceName()).append("-").append(ieMsg.ordinal());
712      } else {
713        message.append("-1");
714      }
715      message.append(")");
716      return LocalizableMessage.raw(message.toString());
717    }
718    else
719    {
720      return com.forgerock.opendj.util.StaticUtils.getExceptionMessage(t);
721    }
722  }
723
724
725
726  /**
727   * Retrieves a stack trace from the provided exception as a single-line
728   * string.
729   *
730   * @param  t  The exception for which to retrieve the stack trace.
731   *
732   * @return  A stack trace from the provided exception as a single-line string.
733   */
734  public static String stackTraceToSingleLineString(Throwable t)
735  {
736    return com.forgerock.opendj.util.StaticUtils.stackTraceToSingleLineString(t, DynamicConstants.DEBUG_BUILD);
737  }
738
739
740
741  /**
742   * Appends a single-line string representation of the provided exception to
743   * the given buffer.
744   *
745   * @param  buffer  The buffer to which the information is to be appended.
746   * @param  t       The exception for which to retrieve the stack trace.
747   */
748  public static void stackTraceToSingleLineString(StringBuilder buffer,
749                                                  Throwable t)
750  {
751    com.forgerock.opendj.util.StaticUtils.stackTraceToSingleLineString(buffer, t, DynamicConstants.DEBUG_BUILD);
752  }
753
754
755
756  /**
757   * Retrieves a string representation of the stack trace for the provided
758   * exception.
759   *
760   * @param  t  The exception for which to retrieve the stack trace.
761   *
762   * @return  A string representation of the stack trace for the provided
763   *          exception.
764   */
765  public static String stackTraceToString(Throwable t)
766  {
767    StringBuilder buffer = new StringBuilder();
768    stackTraceToString(buffer, t);
769    return buffer.toString();
770  }
771
772  /**
773   * Check if the stack trace of provided exception contains a given cause.
774   *
775   * @param throwable
776   *          exception that may contain the cause
777   * @param searchedCause
778   *          class of the cause to look for. Any subclass will match.
779   * @return true if and only if the given cause is found as a cause of any
780   *         level in the provided exception.
781   */
782  public static boolean stackTraceContainsCause(
783      Throwable throwable, Class<? extends Throwable> searchedCause)
784  {
785    Throwable t = throwable;
786    while ((t = t.getCause()) != null)
787    {
788      if (searchedCause.isAssignableFrom(t.getClass()))
789      {
790        return true;
791      }
792
793    }
794    return false;
795  }
796
797  /**
798   * Appends a string representation of the stack trace for the provided
799   * exception to the given buffer.
800   *
801   * @param  buffer  The buffer to which the information is to be appended.
802   * @param  t       The exception for which to retrieve the stack trace.
803   */
804  public static void stackTraceToString(StringBuilder buffer, Throwable t)
805  {
806    if (t == null)
807    {
808      return;
809    }
810
811    buffer.append(t);
812
813    for (StackTraceElement e : t.getStackTrace())
814    {
815      buffer.append(EOL);
816      buffer.append("  ");
817      buffer.append(e.getClassName());
818      buffer.append(".");
819      buffer.append(e.getMethodName());
820      buffer.append("(");
821      buffer.append(e.getFileName());
822      buffer.append(":");
823      buffer.append(e.getLineNumber());
824      buffer.append(")");
825    }
826
827    while (t.getCause() != null)
828    {
829      t = t.getCause();
830      buffer.append(EOL);
831      buffer.append("Caused by ");
832      buffer.append(t);
833
834      for (StackTraceElement e : t.getStackTrace())
835      {
836        buffer.append(EOL);
837        buffer.append("  ");
838        buffer.append(e.getClassName());
839        buffer.append(".");
840        buffer.append(e.getMethodName());
841        buffer.append("(");
842        buffer.append(e.getFileName());
843        buffer.append(":");
844        buffer.append(e.getLineNumber());
845        buffer.append(")");
846      }
847    }
848
849    buffer.append(EOL);
850  }
851
852
853
854  /**
855   * Retrieves a backtrace for the current thread consisting only of filenames
856   * and line numbers that may be useful in debugging the origin of problems
857   * that should not have happened.  Note that this may be an expensive
858   * operation to perform, so it should only be used for error conditions or
859   * debugging.
860   *
861   * @return  A backtrace for the current thread.
862   */
863  public static String getBacktrace()
864  {
865    StringBuilder buffer = new StringBuilder();
866
867    StackTraceElement[] elements = Thread.currentThread().getStackTrace();
868
869    if (elements.length > 1)
870    {
871      buffer.append(elements[1].getFileName());
872      buffer.append(":");
873      buffer.append(elements[1].getLineNumber());
874
875      for (int i=2; i < elements.length; i++)
876      {
877        buffer.append(" ");
878        buffer.append(elements[i].getFileName());
879        buffer.append(":");
880        buffer.append(elements[i].getLineNumber());
881      }
882    }
883
884    return buffer.toString();
885  }
886
887
888
889  /**
890   * Retrieves a backtrace for the provided exception consisting of only
891   * filenames and line numbers that may be useful in debugging the origin of
892   * problems.  This is less expensive than the call to
893   * {@code getBacktrace} without any arguments if an exception has already
894   * been thrown.
895   *
896   * @param  t  The exception for which to obtain the backtrace.
897   *
898   * @return  A backtrace from the provided exception.
899   */
900  public static String getBacktrace(Throwable t)
901  {
902    StringBuilder buffer = new StringBuilder();
903
904    StackTraceElement[] elements = t.getStackTrace();
905
906    if (elements.length > 0)
907    {
908      buffer.append(elements[0].getFileName());
909      buffer.append(":");
910      buffer.append(elements[0].getLineNumber());
911
912      for (int i=1; i < elements.length; i++)
913      {
914        buffer.append(" ");
915        buffer.append(elements[i].getFileName());
916        buffer.append(":");
917        buffer.append(elements[i].getLineNumber());
918      }
919    }
920
921    return buffer.toString();
922  }
923
924
925
926  /**
927   * Indicates whether the provided character is a numeric digit.
928   *
929   * @param  c  The character for which to make the determination.
930   *
931   * @return  {@code true} if the provided character represents a numeric
932   *          digit, or {@code false} if not.
933   */
934  public static boolean isDigit(final char c) {
935    return com.forgerock.opendj.util.StaticUtils.isDigit(c);
936  }
937
938
939
940  /**
941   * Indicates whether the provided character is an ASCII alphabetic character.
942   *
943   * @param  c  The character for which to make the determination.
944   *
945   * @return  {@code true} if the provided value is an uppercase or
946   *          lowercase ASCII alphabetic character, or {@code false} if it
947   *          is not.
948   */
949  public static boolean isAlpha(final char c) {
950    return com.forgerock.opendj.util.StaticUtils.isAlpha(c);
951  }
952
953  /**
954   * Indicates whether the provided character is a hexadecimal digit.
955   *
956   * @param  c  The character for which to make the determination.
957   *
958   * @return  {@code true} if the provided character represents a
959   *          hexadecimal digit, or {@code false} if not.
960   */
961  public static boolean isHexDigit(final char c) {
962    return com.forgerock.opendj.util.StaticUtils.isHexDigit(c);
963  }
964
965  /**
966   * Indicates whether the provided byte represents a hexadecimal digit.
967   *
968   * @param  b  The byte for which to make the determination.
969   *
970   * @return  {@code true} if the provided byte represents a hexadecimal
971   *          digit, or {@code false} if not.
972   */
973  public static boolean isHexDigit(byte b)
974  {
975    switch (b)
976    {
977      case '0':
978      case '1':
979      case '2':
980      case '3':
981      case '4':
982      case '5':
983      case '6':
984      case '7':
985      case '8':
986      case '9':
987      case 'A':
988      case 'B':
989      case 'C':
990      case 'D':
991      case 'E':
992      case 'F':
993      case 'a':
994      case 'b':
995      case 'c':
996      case 'd':
997      case 'e':
998      case 'f':
999        return true;
1000      default:
1001        return false;
1002    }
1003  }
1004
1005
1006
1007  /**
1008   * Converts the provided hexadecimal string to a byte array.
1009   *
1010   * @param  hexString  The hexadecimal string to convert to a byte array.
1011   *
1012   * @return  The byte array containing the binary representation of the
1013   *          provided hex string.
1014   *
1015   * @throws  ParseException  If the provided string contains invalid
1016   *                          hexadecimal digits or does not contain an even
1017   *                          number of digits.
1018   */
1019  public static byte[] hexStringToByteArray(String hexString)
1020         throws ParseException
1021  {
1022    int length;
1023    if (hexString == null || ((length = hexString.length()) == 0))
1024    {
1025      return new byte[0];
1026    }
1027
1028
1029    if ((length % 2) == 1)
1030    {
1031      LocalizableMessage message = ERR_HEX_DECODE_INVALID_LENGTH.get(hexString);
1032      throw new ParseException(message.toString(), 0);
1033    }
1034
1035
1036    int pos = 0;
1037    int arrayLength = length / 2;
1038    byte[] returnArray = new byte[arrayLength];
1039    for (int i=0; i < arrayLength; i++)
1040    {
1041      switch (hexString.charAt(pos++))
1042      {
1043        case '0':
1044          returnArray[i] = 0x00;
1045          break;
1046        case '1':
1047          returnArray[i] = 0x10;
1048          break;
1049        case '2':
1050          returnArray[i] = 0x20;
1051          break;
1052        case '3':
1053          returnArray[i] = 0x30;
1054          break;
1055        case '4':
1056          returnArray[i] = 0x40;
1057          break;
1058        case '5':
1059          returnArray[i] = 0x50;
1060          break;
1061        case '6':
1062          returnArray[i] = 0x60;
1063          break;
1064        case '7':
1065          returnArray[i] = 0x70;
1066          break;
1067        case '8':
1068          returnArray[i] = (byte) 0x80;
1069          break;
1070        case '9':
1071          returnArray[i] = (byte) 0x90;
1072          break;
1073        case 'A':
1074        case 'a':
1075          returnArray[i] = (byte) 0xA0;
1076          break;
1077        case 'B':
1078        case 'b':
1079          returnArray[i] = (byte) 0xB0;
1080          break;
1081        case 'C':
1082        case 'c':
1083          returnArray[i] = (byte) 0xC0;
1084          break;
1085        case 'D':
1086        case 'd':
1087          returnArray[i] = (byte) 0xD0;
1088          break;
1089        case 'E':
1090        case 'e':
1091          returnArray[i] = (byte) 0xE0;
1092          break;
1093        case 'F':
1094        case 'f':
1095          returnArray[i] = (byte) 0xF0;
1096          break;
1097        default:
1098          LocalizableMessage message = ERR_HEX_DECODE_INVALID_CHARACTER.get(
1099              hexString, hexString.charAt(pos-1));
1100          throw new ParseException(message.toString(), 0);
1101      }
1102
1103      switch (hexString.charAt(pos++))
1104      {
1105        case '0':
1106          // No action required.
1107          break;
1108        case '1':
1109          returnArray[i] |= 0x01;
1110          break;
1111        case '2':
1112          returnArray[i] |= 0x02;
1113          break;
1114        case '3':
1115          returnArray[i] |= 0x03;
1116          break;
1117        case '4':
1118          returnArray[i] |= 0x04;
1119          break;
1120        case '5':
1121          returnArray[i] |= 0x05;
1122          break;
1123        case '6':
1124          returnArray[i] |= 0x06;
1125          break;
1126        case '7':
1127          returnArray[i] |= 0x07;
1128          break;
1129        case '8':
1130          returnArray[i] |= 0x08;
1131          break;
1132        case '9':
1133          returnArray[i] |= 0x09;
1134          break;
1135        case 'A':
1136        case 'a':
1137          returnArray[i] |= 0x0A;
1138          break;
1139        case 'B':
1140        case 'b':
1141          returnArray[i] |= 0x0B;
1142          break;
1143        case 'C':
1144        case 'c':
1145          returnArray[i] |= 0x0C;
1146          break;
1147        case 'D':
1148        case 'd':
1149          returnArray[i] |= 0x0D;
1150          break;
1151        case 'E':
1152        case 'e':
1153          returnArray[i] |= 0x0E;
1154          break;
1155        case 'F':
1156        case 'f':
1157          returnArray[i] |= 0x0F;
1158          break;
1159        default:
1160          LocalizableMessage message = ERR_HEX_DECODE_INVALID_CHARACTER.get(
1161              hexString, hexString.charAt(pos-1));
1162          throw new ParseException(message.toString(), 0);
1163      }
1164    }
1165
1166    return returnArray;
1167  }
1168
1169
1170
1171  /**
1172   * Indicates whether the provided value needs to be base64-encoded if it is
1173   * represented in LDIF form.
1174   *
1175   * @param  valueBytes  The binary representation of the attribute value for
1176   *                     which to make the determination.
1177   *
1178   * @return  {@code true} if the value needs to be base64-encoded if it is
1179   *          represented in LDIF form, or {@code false} if not.
1180   */
1181  public static boolean needsBase64Encoding(ByteSequence valueBytes)
1182  {
1183    int length;
1184    if (valueBytes == null || ((length = valueBytes.length()) == 0))
1185    {
1186      return false;
1187    }
1188
1189
1190    // If the value starts with a space, colon, or less than, then it needs to
1191    // be base64-encoded.
1192    switch (valueBytes.byteAt(0))
1193    {
1194      case 0x20: // Space
1195      case 0x3A: // Colon
1196      case 0x3C: // Less-than
1197        return true;
1198    }
1199
1200
1201    // If the value ends with a space, then it needs to be base64-encoded.
1202    if (length > 1 && valueBytes.byteAt(length - 1) == 0x20)
1203    {
1204      return true;
1205    }
1206
1207
1208    // If the value contains a null, newline, or return character, then it needs
1209    // to be base64-encoded.
1210    byte b;
1211    for (int i = 0; i < valueBytes.length(); i++)
1212    {
1213      b = valueBytes.byteAt(i);
1214      if (b < 0 || 127 < b)
1215      {
1216        return true;
1217      }
1218
1219      switch (b)
1220      {
1221        case 0x00: // Null
1222        case 0x0A: // New line
1223        case 0x0D: // Carriage return
1224          return true;
1225      }
1226    }
1227
1228
1229    // If we've made it here, then there's no reason to base64-encode.
1230    return false;
1231  }
1232
1233
1234
1235  /**
1236   * Indicates whether the provided value needs to be base64-encoded if it is
1237   * represented in LDIF form.
1238   *
1239   * @param  valueString  The string representation of the attribute value for
1240   *                      which to make the determination.
1241   *
1242   * @return  {@code true} if the value needs to be base64-encoded if it is
1243   *          represented in LDIF form, or {@code false} if not.
1244   */
1245  public static boolean needsBase64Encoding(String valueString)
1246  {
1247    int length;
1248    if (valueString == null || ((length = valueString.length()) == 0))
1249    {
1250      return false;
1251    }
1252
1253
1254    // If the value starts with a space, colon, or less than, then it needs to
1255    // be base64-encoded.
1256    switch (valueString.charAt(0))
1257    {
1258      case ' ':
1259      case ':':
1260      case '<':
1261        return true;
1262    }
1263
1264
1265    // If the value ends with a space, then it needs to be base64-encoded.
1266    if (length > 1 && valueString.charAt(length - 1) == ' ')
1267    {
1268      return true;
1269    }
1270
1271
1272    // If the value contains a null, newline, or return character, then it needs
1273    // to be base64-encoded.
1274    for (int i=0; i < length; i++)
1275    {
1276      char c = valueString.charAt(i);
1277      if (c <= 0 || c == 0x0A || c == 0x0D || c > 127)
1278      {
1279        return true;
1280      }
1281    }
1282
1283
1284    // If we've made it here, then there's no reason to base64-encode.
1285    return false;
1286  }
1287
1288
1289
1290  /**
1291   * Indicates whether the use of the exec method will be allowed on this
1292   * system.  It will be allowed by default, but that capability will be removed
1293   * if the org.opends.server.DisableExec system property is set and has any
1294   * value other than "false", "off", "no", or "0".
1295   *
1296   * @return  {@code true} if the use of the exec method should be allowed,
1297   *          or {@code false} if it should not be allowed.
1298   */
1299  public static boolean mayUseExec()
1300  {
1301    return !DirectoryServer.getEnvironmentConfig().disableExec();
1302  }
1303
1304
1305
1306  /**
1307   * Executes the specified command on the system and captures its output.  This
1308   * will not return until the specified process has completed.
1309   *
1310   * @param  command           The command to execute.
1311   * @param  args              The set of arguments to provide to the command.
1312   * @param  workingDirectory  The working directory to use for the command, or
1313   *                           {@code null} if the default directory
1314   *                           should be used.
1315   * @param  environment       The set of environment variables that should be
1316   *                           set when executing the command, or
1317   *                           {@code null} if none are needed.
1318   * @param  output            The output generated by the command while it was
1319   *                           running.  This will include both standard
1320   *                           output and standard error.  It may be
1321   *                           {@code null} if the output does not need to
1322   *                           be captured.
1323   *
1324   * @return  The exit code for the command.
1325   *
1326   * @throws  IOException  If an I/O problem occurs while trying to execute the
1327   *                       command.
1328   *
1329   * @throws  SecurityException  If the security policy will not allow the
1330   *                             command to be executed.
1331   *
1332   * @throws InterruptedException If the current thread is interrupted by
1333   *                              another thread while it is waiting, then
1334   *                              the wait is ended and an InterruptedException
1335   *                              is thrown.
1336   */
1337  public static int exec(String command, String[] args, File workingDirectory,
1338                         Map<String,String> environment, List<String> output)
1339         throws IOException, SecurityException, InterruptedException
1340  {
1341    // See whether we'll allow the use of exec on this system.  If not, then
1342    // throw an exception.
1343    if (! mayUseExec())
1344    {
1345      throw new SecurityException(ERR_EXEC_DISABLED.get(command).toString());
1346    }
1347
1348
1349    ArrayList<String> commandAndArgs = new ArrayList<>();
1350    commandAndArgs.add(command);
1351    if (args != null && args.length > 0)
1352    {
1353      Collections.addAll(commandAndArgs, args);
1354    }
1355
1356    ProcessBuilder processBuilder = new ProcessBuilder(commandAndArgs);
1357    processBuilder.redirectErrorStream(true);
1358
1359    if (workingDirectory != null && workingDirectory.isDirectory())
1360    {
1361      processBuilder.directory(workingDirectory);
1362    }
1363
1364    if (environment != null && !environment.isEmpty())
1365    {
1366      processBuilder.environment().putAll(environment);
1367    }
1368
1369    Process process = processBuilder.start();
1370
1371    // We must exhaust stdout and stderr before calling waitfor. Since we
1372    // redirected the error stream, we just have to read from stdout.
1373    InputStream processStream =  process.getInputStream();
1374    BufferedReader reader =
1375        new BufferedReader(new InputStreamReader(processStream));
1376    String line = null;
1377
1378    try
1379    {
1380      while((line = reader.readLine()) != null)
1381      {
1382        if(output != null)
1383        {
1384          output.add(line);
1385        }
1386      }
1387    }
1388    catch(IOException ioe)
1389    {
1390      // If this happens, then we have no choice but to forcefully terminate
1391      // the process.
1392      try
1393      {
1394        process.destroy();
1395      }
1396      catch (Exception e)
1397      {
1398        logger.traceException(e);
1399      }
1400
1401      throw ioe;
1402    }
1403    finally
1404    {
1405      try
1406      {
1407        reader.close();
1408      }
1409      catch(IOException e)
1410      {
1411        logger.traceException(e);
1412      }
1413    }
1414
1415    return process.waitFor();
1416  }
1417
1418
1419
1420  /**
1421   * Indicates whether the provided string contains a name or OID for a schema
1422   * element like an attribute type or objectclass.
1423   *
1424   * @param  element        The string containing the substring for which to
1425   *                        make the determination.
1426   * @param  startPos       The position of the first character that is to be
1427   *                        checked.
1428   * @param  endPos         The position of the first character after the start
1429   *                        position that is not to be checked.
1430   * @param  invalidReason  The buffer to which the invalid reason is to be
1431   *                        appended if a problem is found.
1432   *
1433   * @return  {@code true} if the provided string contains a valid name or
1434   *          OID for a schema element, or {@code false} if it does not.
1435   */
1436  public static boolean isValidSchemaElement(String element, int startPos,
1437                                             int endPos,
1438                                             LocalizableMessageBuilder invalidReason)
1439  {
1440    if (element == null || startPos >= endPos)
1441    {
1442      invalidReason.append(ERR_SCHEMANAME_EMPTY_VALUE.get());
1443      return false;
1444    }
1445
1446
1447    char c = element.charAt(startPos);
1448    if (isAlpha(c))
1449    {
1450      // This can only be a name and not an OID.  The only remaining characters
1451      // must be letters, digits, dashes, and possibly the underscore.
1452      for (int i=startPos+1; i < endPos; i++)
1453      {
1454        c = element.charAt(i);
1455        if (!isAlpha(c)
1456            && !isDigit(c)
1457            && c != '-'
1458            && (c != '_' || !DirectoryServer.allowAttributeNameExceptions()))
1459        {
1460          // This is an illegal character for an attribute name.
1461          invalidReason.append(ERR_SCHEMANAME_ILLEGAL_CHAR.get(element, c, i));
1462          return false;
1463        }
1464      }
1465    }
1466    else if (isDigit(c))
1467    {
1468      // This should indicate an OID, but it may also be a name if name
1469      // exceptions are enabled.  Since we don't know for sure, we'll just
1470      // hold off until we know for sure.
1471      boolean isKnown    = !DirectoryServer.allowAttributeNameExceptions();
1472      boolean isNumeric  = true;
1473      boolean lastWasDot = false;
1474
1475      for (int i=startPos+1; i < endPos; i++)
1476      {
1477        c = element.charAt(i);
1478        if (c == '.')
1479        {
1480          if (isKnown)
1481          {
1482            if (isNumeric)
1483            {
1484              // This is probably legal unless the last character was also a
1485              // period.
1486              if (lastWasDot)
1487              {
1488                invalidReason.append(ERR_SCHEMANAME_CONSECUTIVE_PERIODS.get(
1489                        element, i));
1490                return false;
1491              }
1492              else
1493              {
1494                lastWasDot = true;
1495              }
1496            }
1497            else
1498            {
1499              // This is an illegal character.
1500              invalidReason.append(ERR_SCHEMANAME_ILLEGAL_CHAR.get(
1501                      element, c, i));
1502              return false;
1503            }
1504          }
1505          else
1506          {
1507            // Now we know that this must be a numeric OID and not an attribute
1508            // name with exceptions allowed.
1509            lastWasDot = true;
1510            isKnown    = true;
1511            isNumeric  = true;
1512          }
1513        }
1514        else
1515        {
1516          lastWasDot = false;
1517
1518          if (isAlpha(c) || c == '-' || c == '_')
1519          {
1520            if (isKnown)
1521            {
1522              if (isNumeric)
1523              {
1524                // This is an illegal character for a numeric OID.
1525                invalidReason.append(ERR_SCHEMANAME_ILLEGAL_CHAR.get(
1526                        element, c, i));
1527                return false;
1528              }
1529            }
1530            else
1531            {
1532              // Now we know that this must be an attribute name with exceptions
1533              // allowed and not a numeric OID.
1534              isKnown   = true;
1535              isNumeric = false;
1536            }
1537          }
1538          else if (! isDigit(c))
1539          {
1540            // This is an illegal character.
1541            invalidReason.append(ERR_SCHEMANAME_ILLEGAL_CHAR.get(
1542                    element, c, i));
1543            return false;
1544          }
1545        }
1546      }
1547    }
1548    else
1549    {
1550      // This is an illegal character.
1551      invalidReason.append(ERR_SCHEMANAME_ILLEGAL_CHAR.get(
1552              element, c, startPos));
1553      return false;
1554    }
1555
1556
1557    // If we've gotten here, then the value is fine.
1558    return true;
1559  }
1560
1561
1562
1563  /**
1564   * Indicates whether the provided TCP address is already in use.
1565   *
1566   * @param  address        IP address of the TCP address for which to make
1567   *                        the determination.
1568   * @param  port           TCP port number of the TCP address for which to
1569   *                        make the determination.
1570   * @param  allowReuse     Whether or not TCP address reuse is allowed when
1571   *                        making the determination.
1572   *
1573   * @return  {@code true} if the provided TCP address is already in
1574   *          use, or {@code false} otherwise.
1575   */
1576  public static boolean isAddressInUse(
1577    InetAddress address, int port,
1578    boolean allowReuse)
1579  {
1580    // Return pessimistic.
1581    boolean isInUse = true;
1582    Socket clientSocket = null;
1583    ServerSocket serverSocket = null;
1584    try {
1585      // HACK:
1586      // With dual stacks we can have a situation when INADDR_ANY/PORT
1587      // is bound in TCP4 space but available in TCP6 space and since
1588      // JavaServerSocket implemantation will always use TCP46 on dual
1589      // stacks the bind below will always succeed in such cases thus
1590      // shadowing anything that is already bound to INADDR_ANY/PORT.
1591      // While technically correct, with IPv4 and IPv6 being separate
1592      // address spaces, it presents a problem to end users because a
1593      // common case scenario is to have a single service serving both
1594      // address spaces ie listening to the same port in both spaces
1595      // on wildcard addresses 0 and ::. ServerSocket implemantation
1596      // does not provide any means of working with each address space
1597      // separately such as doing TCP4 or TCP6 only binds thus we have
1598      // to do a dummy connect to INADDR_ANY/PORT to check if it is
1599      // bound to something already. This is only needed for wildcard
1600      // addresses as specific IPv4 or IPv6 addresses will always be
1601      // handled in their respective address space.
1602      if (address.isAnyLocalAddress()) {
1603        clientSocket = new Socket();
1604        try {
1605          // This might fail on some stacks but this is the best we
1606          // can do. No need for explicit timeout since it is local
1607          // address and we have to know for sure unless it fails.
1608          clientSocket.connect(new InetSocketAddress(address, port));
1609        } catch (IOException e) {
1610        // Expected, ignore.
1611        }
1612        if (clientSocket.isConnected()) {
1613          return true;
1614        }
1615      }
1616      serverSocket = new ServerSocket();
1617      serverSocket.setReuseAddress(allowReuse);
1618      serverSocket.bind(new InetSocketAddress(address, port));
1619      isInUse = false;
1620    } catch (IOException e) {
1621      isInUse = true;
1622    } finally {
1623      try {
1624        if (serverSocket != null) {
1625          serverSocket.close();
1626        }
1627      } catch (Exception e) {}
1628      try {
1629        if (clientSocket != null) {
1630          clientSocket.close();
1631        }
1632      } catch (Exception e) {}
1633    }
1634    return isInUse;
1635  }
1636
1637
1638
1639  /**
1640   * Returns a lower-case string representation of a given string, verifying for null input string.
1641   * {@see com.forgerock.opendj.util.StaticUtils#toLowerCase(String s)}
1642   *
1643   * @param s the mixed case string
1644   * @return a lower-case string
1645   */
1646  public static String toLowerCase(String s)
1647  {
1648    return (s == null ? null : com.forgerock.opendj.util.StaticUtils.toLowerCase(s));
1649  }
1650
1651  /**
1652   * Appends a lower-case string representation of a given ByteSequence to a StringBuilder,
1653   * verifying for null input.
1654   * {@see com.forgerock.opendj.util.StaticUtils#toLowerCase(ByteSequence s, StringBuilder string)}
1655   *
1656   * @param  b       The byte array for which to obtain the lowercase string
1657   *                 representation.
1658   * @param  buffer  The buffer to which the lowercase form of the string should
1659   *                 be appended.
1660   * @param  trim    Indicates whether leading and trailing spaces should be
1661   *                 omitted from the string representation.
1662   */
1663  public static void toLowerCase(ByteSequence b, StringBuilder buffer, boolean trim)
1664  {
1665    if (b == null)
1666    {
1667      return;
1668    }
1669
1670    if (trim)
1671    {
1672      int begin = 0;
1673      int end = b.length() - 1;
1674      while (begin <= end)
1675      {
1676        if (b.byteAt(begin) == ' ')
1677        {
1678          begin++;
1679        }
1680        else if (b.byteAt(end) == ' ')
1681        {
1682          end--;
1683        }
1684        else
1685        {
1686          break;
1687        }
1688      }
1689      if (begin > 0 || end < b.length() - 1)
1690      {
1691        b = b.subSequence(begin, end + 1);
1692      }
1693    }
1694
1695    com.forgerock.opendj.util.StaticUtils.toLowerCase(b, buffer);
1696  }
1697
1698
1699
1700  /**
1701   * Retrieves an uppercase representation of the given string.  This
1702   * implementation presumes that the provided string will contain only ASCII
1703   * characters and is optimized for that case.  However, if a non-ASCII
1704   * character is encountered it will fall back on a more expensive algorithm
1705   * that will work properly for non-ASCII characters.
1706   *
1707   * @param  s  The string for which to obtain the uppercase representation.
1708   *
1709   * @return  The uppercase representation of the given string.
1710   */
1711  public static String toUpperCase(String s)
1712  {
1713    if (s == null)
1714    {
1715      return null;
1716    }
1717
1718    StringBuilder buffer = new StringBuilder(s.length());
1719    toUpperCase(s, buffer);
1720    return buffer.toString();
1721  }
1722
1723
1724
1725  /**
1726   * Appends an uppercase representation of the given string to the provided
1727   * buffer.  This implementation presumes that the provided string will contain
1728   * only ASCII characters and is optimized for that case.  However, if a
1729   * non-ASCII character is encountered it will fall back on a more expensive
1730   * algorithm that will work properly for non-ASCII characters.
1731   *
1732   * @param  s       The string for which to obtain the uppercase
1733   *                 representation.
1734   * @param  buffer  The buffer to which the uppercase form of the string should
1735   *                 be appended.
1736   */
1737  public static void toUpperCase(String s, StringBuilder buffer)
1738  {
1739    if (s == null)
1740    {
1741      return;
1742    }
1743
1744    int length = s.length();
1745    for (int i=0; i < length; i++)
1746    {
1747      char c = s.charAt(i);
1748
1749      if ((c & 0x7F) != c)
1750      {
1751        buffer.append(s.substring(i).toUpperCase());
1752        return;
1753      }
1754
1755      switch (c)
1756      {
1757        case 'a':
1758          buffer.append('A');
1759          break;
1760        case 'b':
1761          buffer.append('B');
1762          break;
1763        case 'c':
1764          buffer.append('C');
1765          break;
1766        case 'd':
1767          buffer.append('D');
1768          break;
1769        case 'e':
1770          buffer.append('E');
1771          break;
1772        case 'f':
1773          buffer.append('F');
1774          break;
1775        case 'g':
1776          buffer.append('G');
1777          break;
1778        case 'h':
1779          buffer.append('H');
1780          break;
1781        case 'i':
1782          buffer.append('I');
1783          break;
1784        case 'j':
1785          buffer.append('J');
1786          break;
1787        case 'k':
1788          buffer.append('K');
1789          break;
1790        case 'l':
1791          buffer.append('L');
1792          break;
1793        case 'm':
1794          buffer.append('M');
1795          break;
1796        case 'n':
1797          buffer.append('N');
1798          break;
1799        case 'o':
1800          buffer.append('O');
1801          break;
1802        case 'p':
1803          buffer.append('P');
1804          break;
1805        case 'q':
1806          buffer.append('Q');
1807          break;
1808        case 'r':
1809          buffer.append('R');
1810          break;
1811        case 's':
1812          buffer.append('S');
1813          break;
1814        case 't':
1815          buffer.append('T');
1816          break;
1817        case 'u':
1818          buffer.append('U');
1819          break;
1820        case 'v':
1821          buffer.append('V');
1822          break;
1823        case 'w':
1824          buffer.append('W');
1825          break;
1826        case 'x':
1827          buffer.append('X');
1828          break;
1829        case 'y':
1830          buffer.append('Y');
1831          break;
1832        case 'z':
1833          buffer.append('Z');
1834          break;
1835        default:
1836          buffer.append(c);
1837      }
1838    }
1839  }
1840
1841
1842
1843  /**
1844   * Appends an uppercase string representation of the contents of the given
1845   * byte array to the provided buffer, optionally trimming leading and trailing
1846   * spaces.  This implementation presumes that the provided string will contain
1847   * only ASCII characters and is optimized for that case.  However, if a
1848   * non-ASCII character is encountered it will fall back on a more expensive
1849   * algorithm that will work properly for non-ASCII characters.
1850   *
1851   * @param  b       The byte array for which to obtain the uppercase string
1852   *                 representation.
1853   * @param  buffer  The buffer to which the uppercase form of the string should
1854   *                 be appended.
1855   * @param  trim    Indicates whether leading and trailing spaces should be
1856   *                 omitted from the string representation.
1857   */
1858  public static void toUpperCase(byte[] b, StringBuilder buffer, boolean trim)
1859  {
1860    if (b == null)
1861    {
1862      return;
1863    }
1864
1865    int length = b.length;
1866    for (int i=0; i < length; i++)
1867    {
1868      if ((b[i] & 0x7F) != b[i])
1869      {
1870        try
1871        {
1872          buffer.append(new String(b, i, (length-i), "UTF-8").toUpperCase());
1873        }
1874        catch (Exception e)
1875        {
1876          logger.traceException(e);
1877          buffer.append(new String(b, i, (length - i)).toUpperCase());
1878        }
1879        break;
1880      }
1881
1882      int bufferLength = buffer.length();
1883      switch (b[i])
1884      {
1885        case ' ':
1886          // If we don't care about trimming, then we can always append the
1887          // space.  Otherwise, only do so if there are other characters in the value.
1888          if (trim && bufferLength == 0)
1889          {
1890            break;
1891          }
1892
1893          buffer.append(' ');
1894          break;
1895        case 'a':
1896          buffer.append('A');
1897          break;
1898        case 'b':
1899          buffer.append('B');
1900          break;
1901        case 'c':
1902          buffer.append('C');
1903          break;
1904        case 'd':
1905          buffer.append('D');
1906          break;
1907        case 'e':
1908          buffer.append('E');
1909          break;
1910        case 'f':
1911          buffer.append('F');
1912          break;
1913        case 'g':
1914          buffer.append('G');
1915          break;
1916        case 'h':
1917          buffer.append('H');
1918          break;
1919        case 'i':
1920          buffer.append('I');
1921          break;
1922        case 'j':
1923          buffer.append('J');
1924          break;
1925        case 'k':
1926          buffer.append('K');
1927          break;
1928        case 'l':
1929          buffer.append('L');
1930          break;
1931        case 'm':
1932          buffer.append('M');
1933          break;
1934        case 'n':
1935          buffer.append('N');
1936          break;
1937        case 'o':
1938          buffer.append('O');
1939          break;
1940        case 'p':
1941          buffer.append('P');
1942          break;
1943        case 'q':
1944          buffer.append('Q');
1945          break;
1946        case 'r':
1947          buffer.append('R');
1948          break;
1949        case 's':
1950          buffer.append('S');
1951          break;
1952        case 't':
1953          buffer.append('T');
1954          break;
1955        case 'u':
1956          buffer.append('U');
1957          break;
1958        case 'v':
1959          buffer.append('V');
1960          break;
1961        case 'w':
1962          buffer.append('W');
1963          break;
1964        case 'x':
1965          buffer.append('X');
1966          break;
1967        case 'y':
1968          buffer.append('Y');
1969          break;
1970        case 'z':
1971          buffer.append('Z');
1972          break;
1973        default:
1974          buffer.append((char) b[i]);
1975      }
1976    }
1977
1978    if (trim)
1979    {
1980      // Strip off any trailing spaces.
1981      for (int i=buffer.length()-1; i > 0; i--)
1982      {
1983        if (buffer.charAt(i) == ' ')
1984        {
1985          buffer.delete(i, i+1);
1986        }
1987        else
1988        {
1989          break;
1990        }
1991      }
1992    }
1993  }
1994
1995
1996
1997  /**
1998   * Append a string to a string builder, escaping any double quotes
1999   * according to the StringValue production in RFC 3641.
2000   * <p>
2001   * In RFC 3641 the StringValue production looks like this:
2002   *
2003   * <pre>
2004   *    StringValue       = dquote *SafeUTF8Character dquote
2005   *    dquote            = %x22 ; &quot; (double quote)
2006   *    SafeUTF8Character = %x00-21 / %x23-7F /   ; ASCII minus dquote
2007   *                        dquote dquote /       ; escaped double quote
2008   *                        %xC0-DF %x80-BF /     ; 2 byte UTF-8 character
2009   *                        %xE0-EF 2(%x80-BF) /  ; 3 byte UTF-8 character
2010   *                        %xF0-F7 3(%x80-BF)    ; 4 byte UTF-8 character
2011   * </pre>
2012   *
2013   * <p>
2014   * That is, strings are surrounded by double-quotes and any internal
2015   * double-quotes are doubled up.
2016   *
2017   * @param builder
2018   *          The string builder.
2019   * @param string
2020   *          The string to escape and append.
2021   * @return Returns the string builder.
2022   */
2023  public static StringBuilder toRFC3641StringValue(StringBuilder builder,
2024      String string)
2025  {
2026    // Initial double-quote.
2027    builder.append('"');
2028
2029    for (char c : string.toCharArray())
2030    {
2031      if (c == '"')
2032      {
2033        // Internal double-quotes are escaped using a double-quote.
2034        builder.append('"');
2035      }
2036      builder.append(c);
2037    }
2038
2039    // Trailing double-quote.
2040    builder.append('"');
2041
2042    return builder;
2043  }
2044
2045
2046
2047  /**
2048   * Retrieves a string array containing the contents of the provided
2049   * list of strings.
2050   *
2051   * @param stringList
2052   *          The string list to convert to an array.
2053   * @return A string array containing the contents of the provided list
2054   *         of strings.
2055   */
2056  public static String[] listToArray(List<String> stringList)
2057  {
2058    if (stringList == null)
2059    {
2060      return null;
2061    }
2062
2063    String[] stringArray = new String[stringList.size()];
2064    stringList.toArray(stringArray);
2065    return stringArray;
2066  }
2067
2068  /**
2069   * Retrieves an array list containing the contents of the provided array.
2070   *
2071   * @param  stringArray  The string array to convert to an array list.
2072   *
2073   * @return  An array list containing the contents of the provided array.
2074   */
2075  public static ArrayList<String> arrayToList(String... stringArray)
2076  {
2077    if (stringArray == null)
2078    {
2079      return null;
2080    }
2081
2082    ArrayList<String> stringList = new ArrayList<>(stringArray.length);
2083    Collections.addAll(stringList, stringArray);
2084    return stringList;
2085  }
2086
2087
2088  /**
2089   * Attempts to delete the specified file or directory. If it is a directory,
2090   * then any files or subdirectories that it contains will be recursively
2091   * deleted as well.
2092   *
2093   * @param file
2094   *          The file or directory to be removed.
2095   * @return {@code true} if the specified file and any subordinates are all
2096   *         successfully removed, or {@code false} if at least one element in
2097   *         the subtree could not be removed or file does not exists.
2098   */
2099  public static boolean recursiveDelete(File file)
2100  {
2101    if (file.exists())
2102    {
2103      boolean successful = true;
2104      if (file.isDirectory())
2105      {
2106        File[] childList = file.listFiles();
2107        if (childList != null)
2108        {
2109          for (File f : childList)
2110          {
2111            successful &= recursiveDelete(f);
2112          }
2113        }
2114      }
2115
2116      return successful & file.delete();
2117    }
2118    return false;
2119  }
2120
2121
2122
2123  /**
2124   * Moves the indicated file to the specified directory by creating a new file
2125   * in the target directory, copying the contents of the existing file, and
2126   * removing the existing file.  The file to move must exist and must be a
2127   * file.  The target directory must exist, must be a directory, and must not
2128   * be the directory in which the file currently resides.
2129   *
2130   * @param  fileToMove       The file to move to the target directory.
2131   * @param  targetDirectory  The directory into which the file should be moved.
2132   *
2133   * @throws  IOException  If a problem occurs while attempting to move the
2134   *                       file.
2135   */
2136  public static void moveFile(File fileToMove, File targetDirectory)
2137         throws IOException
2138  {
2139    if (! fileToMove.exists())
2140    {
2141      LocalizableMessage message = ERR_MOVEFILE_NO_SUCH_FILE.get(fileToMove.getPath());
2142      throw new IOException(message.toString());
2143    }
2144
2145    if (! fileToMove.isFile())
2146    {
2147      LocalizableMessage message = ERR_MOVEFILE_NOT_FILE.get(fileToMove.getPath());
2148      throw new IOException(message.toString());
2149    }
2150
2151    if (! targetDirectory.exists())
2152    {
2153      LocalizableMessage message =
2154          ERR_MOVEFILE_NO_SUCH_DIRECTORY.get(targetDirectory.getPath());
2155      throw new IOException(message.toString());
2156    }
2157
2158    if (! targetDirectory.isDirectory())
2159    {
2160      LocalizableMessage message =
2161          ERR_MOVEFILE_NOT_DIRECTORY.get(targetDirectory.getPath());
2162      throw new IOException(message.toString());
2163    }
2164
2165    String newFilePath = targetDirectory.getPath() + File.separator +
2166                         fileToMove.getName();
2167    FileInputStream  inputStream  = new FileInputStream(fileToMove);
2168    FileOutputStream outputStream = new FileOutputStream(newFilePath, false);
2169    byte[] buffer = new byte[8192];
2170    while (true)
2171    {
2172      int bytesRead = inputStream.read(buffer);
2173      if (bytesRead < 0)
2174      {
2175        break;
2176      }
2177
2178      outputStream.write(buffer, 0, bytesRead);
2179    }
2180
2181    outputStream.flush();
2182    outputStream.close();
2183    inputStream.close();
2184    fileToMove.delete();
2185  }
2186
2187  /**
2188   * Renames the source file to the target file.  If the target file exists
2189   * it is first deleted.  The rename and delete operation return values
2190   * are checked for success and if unsuccessful, this method throws an
2191   * exception.
2192   *
2193   * @param fileToRename The file to rename.
2194   * @param target       The file to which {@code fileToRename} will be
2195   *                     moved.
2196   * @throws IOException If a problem occurs while attempting to rename the
2197   *                     file.  On the Windows platform, this typically
2198   *                     indicates that the file is in use by this or another
2199   *                     application.
2200   */
2201  public static void renameFile(File fileToRename, File target)
2202          throws IOException {
2203    if (fileToRename != null && target != null)
2204    {
2205      synchronized(target)
2206      {
2207        if (target.exists() && !target.delete())
2208        {
2209          LocalizableMessage message =
2210              ERR_RENAMEFILE_CANNOT_DELETE_TARGET.get(target.getPath());
2211          throw new IOException(message.toString());
2212        }
2213      }
2214      if (!fileToRename.renameTo(target))
2215      {
2216        LocalizableMessage message = ERR_RENAMEFILE_CANNOT_RENAME.get(
2217            fileToRename.getPath(), target.getPath());
2218        throw new IOException(message.toString());
2219
2220      }
2221    }
2222  }
2223
2224
2225  /**
2226   * Indicates whether the provided path refers to a relative path rather than
2227   * an absolute path.
2228   *
2229   * @param  path  The path string for which to make the determination.
2230   *
2231   * @return  {@code true} if the provided path is relative, or
2232   *          {@code false} if it is absolute.
2233   */
2234  public static boolean isRelativePath(String path)
2235  {
2236    File f = new File(path);
2237    return !f.isAbsolute();
2238  }
2239
2240
2241
2242  /**
2243   * Retrieves a {@code File} object corresponding to the specified path.
2244   * If the given path is an absolute path, then it will be used.  If the path
2245   * is relative, then it will be interpreted as if it were relative to the
2246   * Directory Server root.
2247   *
2248   * @param  path  The path string to be retrieved as a {@code File}
2249   *
2250   * @return  A {@code File} object that corresponds to the specified path.
2251   */
2252  public static File getFileForPath(String path)
2253  {
2254    File f = new File (path);
2255
2256    if (f.isAbsolute())
2257    {
2258      return f;
2259    }
2260    else
2261    {
2262      return new File(DirectoryServer.getInstanceRoot() + File.separator +
2263          path);
2264    }
2265  }
2266
2267  /**
2268   * Retrieves a {@code File} object corresponding to the specified path.
2269   * If the given path is an absolute path, then it will be used.  If the path
2270   * is relative, then it will be interpreted as if it were relative to the
2271   * Directory Server root.
2272   *
2273   * @param path
2274   *           The path string to be retrieved as a {@code File}.
2275   * @param serverContext
2276   *           The server context.
2277   *
2278   * @return  A {@code File} object that corresponds to the specified path.
2279   */
2280  public static File getFileForPath(String path, ServerContext serverContext)
2281  {
2282    File f = new File (path);
2283
2284    if (f.isAbsolute())
2285    {
2286      return f;
2287    }
2288    else
2289    {
2290      return new File(serverContext.getInstanceRoot() + File.separator +
2291          path);
2292    }
2293  }
2294
2295
2296
2297  /**
2298   * Creates a new, blank entry with the given DN.  It will contain only the
2299   * attribute(s) contained in the RDN.  The choice of objectclasses will be
2300   * based on the RDN attribute.  If there is a single RDN attribute, then the
2301   * following mapping will be used:
2302   * <BR>
2303   * <UL>
2304   *   <LI>c attribute :: country objectclass</LI>
2305   *   <LI>dc attribute :: domain objectclass</LI>
2306   *   <LI>o attribute :: organization objectclass</LI>
2307   *   <LI>ou attribute :: organizationalUnit objectclass</LI>
2308   * </UL>
2309   * <BR>
2310   * Any other single RDN attribute types, or any case in which there are
2311   * multiple RDN attributes, will use the untypedObject objectclass.  If the
2312   * RDN includes one or more attributes that are not allowed in the
2313   * untypedObject objectclass, then the extensibleObject class will also be
2314   * added.  Note that this method cannot be used to generate an entry
2315   * with an empty or null DN.
2316   *
2317   * @param  dn  The DN to use for the entry.
2318   *
2319   * @return  The entry created with the provided DN.
2320   */
2321  public static Entry createEntry(DN dn)
2322  {
2323    // If the provided DN was null or empty, then return null because we don't
2324    // support it.
2325    if (dn == null || dn.isRootDN())
2326    {
2327      return null;
2328    }
2329
2330
2331    // Get the information about the RDN attributes.
2332    RDN rdn = dn.rdn();
2333
2334    // If there is only one RDN attribute, then see which objectclass we should use.
2335    ObjectClass structuralClass = DirectoryServer.getObjectClass(getObjectClassName(rdn));
2336
2337    // Get the top and untypedObject classes to include in the entry.
2338    LinkedHashMap<ObjectClass,String> objectClasses = new LinkedHashMap<>(3);
2339
2340    objectClasses.put(DirectoryServer.getTopObjectClass(), OC_TOP);
2341    objectClasses.put(structuralClass, structuralClass.getNameOrOID());
2342
2343
2344    // Iterate through the RDN attributes and add them to the set of user or
2345    // operational attributes.
2346    LinkedHashMap<AttributeType,List<Attribute>> userAttributes = new LinkedHashMap<>();
2347    LinkedHashMap<AttributeType,List<Attribute>> operationalAttributes = new LinkedHashMap<>();
2348
2349    boolean extensibleObjectAdded = false;
2350    for (AVA ava : rdn)
2351    {
2352      AttributeType attrType = ava.getAttributeType();
2353
2354      // First, see if this type is allowed by the untypedObject class.  If not,
2355      // then we'll need to include the extensibleObject class.
2356      if (!structuralClass.isRequiredOrOptional(attrType) && !extensibleObjectAdded)
2357      {
2358        ObjectClass extensibleObjectOC =
2359             DirectoryServer.getObjectClass(OC_EXTENSIBLE_OBJECT_LC);
2360        if (extensibleObjectOC == null)
2361        {
2362          extensibleObjectOC =
2363               DirectoryServer.getDefaultObjectClass(OC_EXTENSIBLE_OBJECT);
2364        }
2365        objectClasses.put(extensibleObjectOC, OC_EXTENSIBLE_OBJECT);
2366        extensibleObjectAdded = true;
2367      }
2368
2369
2370      // Create the attribute and add it to the appropriate map.
2371      addAttributeValue(attrType.isOperational() ? operationalAttributes : userAttributes, ava);
2372    }
2373
2374
2375    // Create and return the entry.
2376    return new Entry(dn, objectClasses, userAttributes, operationalAttributes);
2377  }
2378
2379  private static String getObjectClassName(RDN rdn)
2380  {
2381    if (rdn.size() == 1)
2382    {
2383      final AttributeType attrType = rdn.getFirstAVA().getAttributeType();
2384      if (attrType.hasName(ATTR_C))
2385      {
2386        return OC_COUNTRY;
2387      }
2388      else if (attrType.hasName(ATTR_DC))
2389      {
2390        return OC_DOMAIN;
2391      }
2392      else if (attrType.hasName(ATTR_O))
2393      {
2394        return OC_ORGANIZATION;
2395      }
2396      else if (attrType.hasName(ATTR_OU))
2397      {
2398        return OC_ORGANIZATIONAL_UNIT_LC;
2399      }
2400    }
2401    return OC_UNTYPED_OBJECT_LC;
2402  }
2403
2404  private static void addAttributeValue(LinkedHashMap<AttributeType, List<Attribute>> attrs, AVA ava)
2405  {
2406    AttributeType attrType = ava.getAttributeType();
2407    ByteString attrValue = ava.getAttributeValue();
2408    List<Attribute> attrList = attrs.get(attrType);
2409    if (attrList != null && !attrList.isEmpty())
2410    {
2411      AttributeBuilder builder = new AttributeBuilder(attrList.get(0));
2412      builder.add(attrValue);
2413      attrList.set(0, builder.toAttribute());
2414    }
2415    else
2416    {
2417      AttributeBuilder builder = new AttributeBuilder(attrType, ava.getAttributeName());
2418      builder.add(attrValue);
2419      attrs.put(attrType, builder.toAttributeList());
2420    }
2421  }
2422
2423  /**
2424   * Retrieves a user-friendly string that indicates the length of time (in
2425   * days, hours, minutes, and seconds) in the specified number of seconds.
2426   *
2427   * @param  numSeconds  The number of seconds to be converted to a more
2428   *                     user-friendly value.
2429   *
2430   * @return  The user-friendly representation of the specified number of
2431   *          seconds.
2432   */
2433  public static LocalizableMessage secondsToTimeString(long numSeconds)
2434  {
2435    if (numSeconds < 60)
2436    {
2437      // We can express it in seconds.
2438      return INFO_TIME_IN_SECONDS.get(numSeconds);
2439    }
2440    else if (numSeconds < 3600)
2441    {
2442      // We can express it in minutes and seconds.
2443      long m = numSeconds / 60;
2444      long s = numSeconds % 60;
2445      return INFO_TIME_IN_MINUTES_SECONDS.get(m, s);
2446    }
2447    else if (numSeconds < 86400)
2448    {
2449      // We can express it in hours, minutes, and seconds.
2450      long h = numSeconds / 3600;
2451      long m = (numSeconds % 3600) / 60;
2452      long s = numSeconds % 3600 % 60;
2453      return INFO_TIME_IN_HOURS_MINUTES_SECONDS.get(h, m, s);
2454    }
2455    else
2456    {
2457      // We can express it in days, hours, minutes, and seconds.
2458      long d = numSeconds / 86400;
2459      long h = (numSeconds % 86400) / 3600;
2460      long m = (numSeconds % 86400 % 3600) / 60;
2461      long s = numSeconds % 86400 % 3600 % 60;
2462      return INFO_TIME_IN_DAYS_HOURS_MINUTES_SECONDS.get(d, h, m, s);
2463    }
2464  }
2465
2466  /**
2467   * Checks that no more that one of a set of arguments is present.  This
2468   * utility should be used after argument parser has parsed a set of
2469   * arguments.
2470   *
2471   * @param  args to test for the presence of more than one
2472   * @throws ArgumentException if more than one of {@code args} is
2473   *         present and containing an error message identifying the
2474   *         arguments in violation
2475   */
2476  public static void checkOnlyOneArgPresent(Argument... args)
2477    throws ArgumentException
2478  {
2479    if (args != null) {
2480      for (Argument arg : args) {
2481        for (Argument otherArg : args) {
2482          if (arg != otherArg && arg.isPresent() && otherArg.isPresent()) {
2483            throw new ArgumentException(
2484                    ToolMessages.ERR_INCOMPATIBLE_ARGUMENTS.get(arg.getLongIdentifier(), otherArg.getLongIdentifier()));
2485          }
2486        }
2487      }
2488    }
2489  }
2490
2491  /**
2492   * Converts a string representing a time in "yyyyMMddHHmmss.SSS'Z'" or
2493   * "yyyyMMddHHmmss" to a {@code Date}.
2494   *
2495   * @param timeStr string formatted appropriately
2496   * @return Date object; null if {@code timeStr} is null
2497   * @throws ParseException if there was a problem converting the string to
2498   *         a {@code Date}.
2499   */
2500  public static Date parseDateTimeString(String timeStr) throws ParseException
2501  {
2502    Date dateTime = null;
2503    if (timeStr != null)
2504    {
2505      if (timeStr.endsWith("Z"))
2506      {
2507        try
2508        {
2509          SimpleDateFormat dateFormat =
2510            new SimpleDateFormat(DATE_FORMAT_GENERALIZED_TIME);
2511          dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
2512          dateFormat.setLenient(true);
2513          dateTime = dateFormat.parse(timeStr);
2514        }
2515        catch (ParseException pe)
2516        {
2517          // Best effort: try with GMT time.
2518          SimpleDateFormat dateFormat =
2519            new SimpleDateFormat(DATE_FORMAT_GMT_TIME);
2520          dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
2521          dateFormat.setLenient(true);
2522          dateTime = dateFormat.parse(timeStr);
2523        }
2524      }
2525      else
2526      {
2527        SimpleDateFormat dateFormat =
2528            new SimpleDateFormat(DATE_FORMAT_COMPACT_LOCAL_TIME);
2529        dateFormat.setLenient(true);
2530        dateTime = dateFormat.parse(timeStr);
2531      }
2532    }
2533    return dateTime;
2534  }
2535
2536  /**
2537   * Formats a Date to String representation in "yyyyMMddHHmmss'Z'".
2538   *
2539   * @param date to format; null if {@code date} is null
2540   * @return string representation of the date
2541   */
2542  public static String formatDateTimeString(Date date)
2543  {
2544    String timeStr = null;
2545    if (date != null)
2546    {
2547      SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT_GMT_TIME);
2548      dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
2549      timeStr = dateFormat.format(date);
2550    }
2551    return timeStr;
2552  }
2553
2554  /**
2555   * Indicates whether or not a string represents a syntactically correct
2556   * email address.
2557   *
2558   * @param addr to validate
2559   * @return boolean where {@code true} indicates that the string is a
2560   *         syntactically correct email address
2561   */
2562  public static boolean isEmailAddress(String addr) {
2563
2564    // This just does basic syntax checking.  Perhaps we
2565    // might want to be stricter about this.
2566    return addr != null && addr.contains("@") && addr.contains(".");
2567
2568  }
2569
2570
2571
2572  /**
2573   * Writes the contents of the provided buffer to the client,
2574   * terminating the connection if the write is unsuccessful for too
2575   * long (e.g., if the client is unresponsive or there is a network
2576   * problem). If possible, it will attempt to use the selector returned
2577   * by the {@code ClientConnection.getWriteSelector} method, but it is
2578   * capable of working even if that method returns {@code null}. <BR>
2579   *
2580   * Note that the original position and limit values will not be
2581   * preserved, so if that is important to the caller, then it should
2582   * record them before calling this method and restore them after it
2583   * returns.
2584   *
2585   * @param clientConnection
2586   *          The client connection to which the data is to be written.
2587   * @param buffer
2588   *          The data to be written to the client.
2589   * @return {@code true} if all the data in the provided buffer was
2590   *         written to the client and the connection may remain
2591   *         established, or {@code false} if a problem occurred
2592   *         and the client connection is no longer valid. Note that if
2593   *         this method does return {@code false}, then it must
2594   *         have already disconnected the client.
2595   * @throws IOException
2596   *           If a problem occurs while attempting to write data to the
2597   *           client. The caller will be responsible for catching this
2598   *           and terminating the client connection.
2599   */
2600  public static boolean writeWithTimeout(ClientConnection clientConnection,
2601      ByteBuffer buffer) throws IOException
2602  {
2603    SocketChannel socketChannel = clientConnection.getSocketChannel();
2604    long startTime = System.currentTimeMillis();
2605    long waitTime = clientConnection.getMaxBlockedWriteTimeLimit();
2606    if (waitTime <= 0)
2607    {
2608      // We won't support an infinite time limit, so fall back to using
2609      // five minutes, which is a very long timeout given that we're
2610      // blocking a worker thread.
2611      waitTime = 300000L;
2612    }
2613
2614    long stopTime = startTime + waitTime;
2615
2616    Selector selector = clientConnection.getWriteSelector();
2617    if (selector == null)
2618    {
2619      // The client connection does not provide a selector, so we'll
2620      // fall back
2621      // to a more inefficient way that will work without a selector.
2622      while (buffer.hasRemaining()
2623          && System.currentTimeMillis() < stopTime)
2624      {
2625        if (socketChannel.write(buffer) < 0)
2626        {
2627          // The client connection has been closed.
2628          return false;
2629        }
2630      }
2631
2632      if (buffer.hasRemaining())
2633      {
2634        // If we've gotten here, then the write timed out.
2635        return false;
2636      }
2637
2638      return true;
2639    }
2640
2641    // Register with the selector for handling write operations.
2642    SelectionKey key =
2643        socketChannel.register(selector, SelectionKey.OP_WRITE);
2644
2645    try
2646    {
2647      selector.select(waitTime);
2648      while (buffer.hasRemaining())
2649      {
2650        long currentTime = System.currentTimeMillis();
2651        if (currentTime >= stopTime)
2652        {
2653          // We've been blocked for too long.
2654          return false;
2655        }
2656        else
2657        {
2658          waitTime = stopTime - currentTime;
2659        }
2660
2661        Iterator<SelectionKey> iterator =
2662            selector.selectedKeys().iterator();
2663        while (iterator.hasNext())
2664        {
2665          SelectionKey k = iterator.next();
2666          if (k.isWritable())
2667          {
2668            int bytesWritten = socketChannel.write(buffer);
2669            if (bytesWritten < 0)
2670            {
2671              // The client connection has been closed.
2672              return false;
2673            }
2674
2675            iterator.remove();
2676          }
2677        }
2678
2679        if (buffer.hasRemaining())
2680        {
2681          selector.select(waitTime);
2682        }
2683      }
2684
2685      return true;
2686    }
2687    finally
2688    {
2689      if (key.isValid())
2690      {
2691        key.cancel();
2692        selector.selectNow();
2693      }
2694    }
2695  }
2696
2697
2698
2699  /**
2700   * Add all of the superior objectclasses to the specified objectclass
2701   * map if they don't already exist. Used by add and import-ldif to
2702   * add missing superior objectclasses to entries that don't have them.
2703   *
2704   * @param objectClasses A Map of objectclasses.
2705   */
2706  public static void addSuperiorObjectClasses(Map<ObjectClass,
2707      String> objectClasses) {
2708      HashSet<ObjectClass> additionalClasses = null;
2709      for (ObjectClass oc : objectClasses.keySet())
2710      {
2711        for(ObjectClass superiorClass : oc.getSuperiorClasses())
2712        {
2713          if (! objectClasses.containsKey(superiorClass))
2714          {
2715            if (additionalClasses == null)
2716            {
2717              additionalClasses = new HashSet<>();
2718            }
2719
2720            additionalClasses.add(superiorClass);
2721          }
2722        }
2723      }
2724
2725      if (additionalClasses != null)
2726      {
2727        for (ObjectClass oc : additionalClasses)
2728        {
2729          addObjectClassChain(oc, objectClasses);
2730        }
2731      }
2732  }
2733
2734  private static void addObjectClassChain(ObjectClass objectClass,
2735      Map<ObjectClass, String> objectClasses)
2736  {
2737    if (objectClasses != null){
2738      if (! objectClasses.containsKey(objectClass))
2739      {
2740        objectClasses.put(objectClass, objectClass.getNameOrOID());
2741      }
2742
2743      for(ObjectClass superiorClass : objectClass.getSuperiorClasses())
2744      {
2745        if (! objectClasses.containsKey(superiorClass))
2746        {
2747          addObjectClassChain(superiorClass, objectClasses);
2748        }
2749      }
2750    }
2751  }
2752
2753
2754  /**
2755   * Closes the provided {@link Closeable}'s ignoring any errors which
2756   * occurred.
2757   *
2758   * @param closeables The closeables to be closed, which may be
2759   *        {@code null}.
2760   */
2761  public static void close(Closeable... closeables)
2762  {
2763    if (closeables == null)
2764    {
2765      return;
2766    }
2767    close(Arrays.asList(closeables));
2768  }
2769
2770  /**
2771   * Closes the provided {@link Closeable}'s ignoring any errors which occurred.
2772   *
2773   * @param closeables
2774   *          The closeables to be closed, which may be {@code null}.
2775   */
2776  public static void close(Collection<? extends Closeable> closeables)
2777  {
2778    if (closeables == null)
2779    {
2780      return;
2781    }
2782    for (Closeable closeable : closeables)
2783    {
2784      if (closeable != null)
2785      {
2786        try
2787        {
2788          closeable.close();
2789        }
2790        catch (IOException ignored)
2791        {
2792          logger.traceException(ignored);
2793        }
2794      }
2795    }
2796  }
2797
2798  /**
2799   * Closes the provided {@link InitialContext}'s ignoring any errors which occurred.
2800   *
2801   * @param ctxs
2802   *          The contexts to be closed, which may be {@code null}.
2803   */
2804  public static void close(InitialContext... ctxs)
2805  {
2806    if (ctxs == null)
2807    {
2808      return;
2809    }
2810    for (InitialContext ctx : ctxs)
2811    {
2812      if (ctx != null)
2813      {
2814        try
2815        {
2816          ctx.close();
2817        }
2818        catch (NamingException ignored)
2819        {
2820          // ignore
2821        }
2822      }
2823    }
2824  }
2825
2826  /**
2827   * Calls {@link Thread#sleep(long)}, surrounding it with the mandatory
2828   * {@code try} / {@code catch(InterruptedException)} block.
2829   *
2830   * @param millis
2831   *          the length of time to sleep in milliseconds
2832   */
2833  public static void sleep(long millis)
2834  {
2835    try
2836    {
2837      Thread.sleep(millis);
2838    }
2839    catch (InterruptedException wokenUp)
2840    {
2841      // ignore
2842    }
2843  }
2844
2845  /**
2846   * Test if the provided message corresponds to the provided descriptor.
2847   *
2848   * @param msg
2849   *          The i18n message.
2850   * @param desc
2851   *          The message descriptor.
2852   * @return {@code true} if message corresponds to descriptor
2853   */
2854  public static boolean hasDescriptor(LocalizableMessage msg,
2855      LocalizableMessageDescriptor.Arg0 desc)
2856  {
2857    return msg.ordinal() == desc.ordinal()
2858        && msg.resourceName().equals(desc.resourceName());
2859  }
2860
2861  /**
2862   * Test if the provided message corresponds to the provided descriptor.
2863   *
2864   * @param msg
2865   *          The i18n message.
2866   * @param desc
2867   *          The message descriptor.
2868   * @return {@code true} if message corresponds to descriptor
2869   */
2870  public static boolean hasDescriptor(LocalizableMessage msg,
2871      LocalizableMessageDescriptor.Arg1 desc)
2872  {
2873    return msg.ordinal() == desc.ordinal()
2874        && msg.resourceName().equals(desc.resourceName());
2875  }
2876
2877  /**
2878   * Test if the provided message corresponds to the provided descriptor.
2879   *
2880   * @param msg
2881   *          The i18n message.
2882   * @param desc
2883   *          The message descriptor.
2884   * @return {@code true} if message corresponds to descriptor
2885   */
2886  public static boolean hasDescriptor(LocalizableMessage msg,
2887      LocalizableMessageDescriptor.Arg2 desc)
2888  {
2889    return msg.ordinal() == desc.ordinal()
2890        && msg.resourceName().equals(desc.resourceName());
2891  }
2892
2893  /**
2894   * Test if the provided message corresponds to the provided descriptor.
2895   *
2896   * @param msg
2897   *          The i18n message.
2898   * @param desc
2899   *          The message descriptor.
2900   * @return {@code true} if message corresponds to descriptor
2901   */
2902  public static boolean hasDescriptor(LocalizableMessage msg,
2903      LocalizableMessageDescriptor.Arg3 desc)
2904  {
2905    return msg.ordinal() == desc.ordinal()
2906        && msg.resourceName().equals(desc.resourceName());
2907  }
2908
2909  /**
2910   * Test if the provided message corresponds to the provided descriptor.
2911   *
2912   * @param msg
2913   *          The i18n message.
2914   * @param desc
2915   *          The message descriptor.
2916   * @return {@code true} if message corresponds to descriptor
2917   */
2918  public static boolean hasDescriptor(LocalizableMessage msg,
2919      LocalizableMessageDescriptor.Arg7 desc)
2920  {
2921    return msg.ordinal() == desc.ordinal()
2922        && msg.resourceName().equals(desc.resourceName());
2923  }
2924
2925  /**
2926   * Returns an {@link Iterable} returning the passed in {@link Iterator}. THis
2927   * allows using methods returning Iterators with foreach statements.
2928   * <p>
2929   * For example, consider a method with this signature:
2930   * <p>
2931   * <code>public Iterator&lt;String&gt; myIteratorMethod();</code>
2932   * <p>
2933   * Classical use with for or while loop:
2934   *
2935   * <pre>
2936   * for (Iterator&lt;String&gt; it = myIteratorMethod(); it.hasNext();)
2937   * {
2938   *   String s = it.next();
2939   *   // use it
2940   * }
2941   *
2942   * Iterator&lt;String&gt; it = myIteratorMethod();
2943   * while(it.hasNext();)
2944   * {
2945   *   String s = it.next();
2946   *   // use it
2947   * }
2948   * </pre>
2949   *
2950   * Improved use with foreach:
2951   *
2952   * <pre>
2953   * for (String s : StaticUtils.toIterable(myIteratorMethod()))
2954   * {
2955   * }
2956   * </pre>
2957   *
2958   * </p>
2959   *
2960   * @param <T>
2961   *          the generic type of the passed in Iterator and for the returned
2962   *          Iterable.
2963   * @param iterator
2964   *          the Iterator that will be returned by the Iterable.
2965   * @return an Iterable returning the passed in Iterator
2966   */
2967  public static <T> Iterable<T> toIterable(final Iterator<T> iterator)
2968  {
2969    return new Iterable<T>()
2970    {
2971      @Override
2972      public Iterator<T> iterator()
2973      {
2974        return iterator;
2975      }
2976    };
2977  }
2978
2979  /**
2980   * Returns true if the version of the server is an OEM one, and therefore doesn't support the JE backend.
2981   * @return {@code true} if the version of the server is an OEM version and {@code false} otherwise.
2982   */
2983  public static boolean isOEMVersion()
2984  {
2985    return !isClassAvailable("org.opends.server.backends.jeb.JEBackend");
2986  }
2987
2988  /**
2989   * Returns true if the class is available in the classpath.
2990   * @param className the string representing the class to check.
2991   * @return {@code true} if the class is available in the classpath and {@code false} otherwise.
2992   */
2993  public static boolean isClassAvailable(final String className)
2994  {
2995    try
2996    {
2997      Class.forName(className);
2998      return true;
2999    }
3000    catch (Exception e)
3001    {
3002      return false;
3003    }
3004  }
3005}
3006