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