001 /*
002 * Copyright 2008-2014 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2008-2014 UnboundID Corp.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021 package com.unboundid.ldap.sdk.examples;
022
023
024
025 import java.io.File;
026 import java.io.FileInputStream;
027 import java.io.InputStream;
028 import java.io.IOException;
029 import java.io.OutputStream;
030 import java.util.ArrayList;
031 import java.util.Iterator;
032 import java.util.TreeMap;
033 import java.util.LinkedHashMap;
034 import java.util.List;
035 import java.util.concurrent.atomic.AtomicLong;
036 import java.util.zip.GZIPInputStream;
037
038 import com.unboundid.ldap.sdk.Entry;
039 import com.unboundid.ldap.sdk.LDAPConnection;
040 import com.unboundid.ldap.sdk.LDAPException;
041 import com.unboundid.ldap.sdk.ResultCode;
042 import com.unboundid.ldap.sdk.Version;
043 import com.unboundid.ldap.sdk.schema.Schema;
044 import com.unboundid.ldap.sdk.schema.EntryValidator;
045 import com.unboundid.ldif.DuplicateValueBehavior;
046 import com.unboundid.ldif.LDIFException;
047 import com.unboundid.ldif.LDIFReader;
048 import com.unboundid.ldif.LDIFReaderEntryTranslator;
049 import com.unboundid.ldif.LDIFWriter;
050 import com.unboundid.util.LDAPCommandLineTool;
051 import com.unboundid.util.ThreadSafety;
052 import com.unboundid.util.ThreadSafetyLevel;
053 import com.unboundid.util.args.ArgumentException;
054 import com.unboundid.util.args.ArgumentParser;
055 import com.unboundid.util.args.BooleanArgument;
056 import com.unboundid.util.args.FileArgument;
057 import com.unboundid.util.args.IntegerArgument;
058
059 import static com.unboundid.util.StaticUtils.*;
060
061
062
063 /**
064 * This class provides a simple tool that can be used to validate that the
065 * contents of an LDIF file are valid. This includes ensuring that the contents
066 * can be parsed as valid LDIF, and it can also ensure that the LDIF content
067 * conforms to the server schema. It will obtain the schema by connecting to
068 * the server and retrieving the default schema (i.e., the schema which governs
069 * the root DSE). By default, a thorough set of validation will be performed,
070 * but it is possible to disable certain types of validation.
071 * <BR><BR>
072 * Some of the APIs demonstrated by this example include:
073 * <UL>
074 * <LI>Argument Parsing (from the {@code com.unboundid.util.args}
075 * package)</LI>
076 * <LI>LDAP Command-Line Tool (from the {@code com.unboundid.util}
077 * package)</LI>
078 * <LI>LDIF Processing (from the {@code com.unboundid.ldif} package)</LI>
079 * <LI>Schema Parsing (from the {@code com.unboundid.ldap.sdk.schema}
080 * package)</LI>
081 * </UL>
082 * <BR><BR>
083 * Supported arguments include those allowed by the {@link LDAPCommandLineTool}
084 * class (to obtain the information to use to connect to the server to read the
085 * schema), as well as the following additional arguments:
086 * <UL>
087 * <LI>"--schemaDirectory {path}" -- specifies the path to a directory
088 * containing files with schema definitions. If this argument is
089 * provided, then no attempt will be made to communicate with a directory
090 * server.</LI>
091 * <LI>"-f {path}" or "--ldifFile {path}" -- specifies the path to the LDIF
092 * file to be validated.</LI>
093 * <LI>"-c" or "--isCompressed" -- indicates that the LDIF file is
094 * compressed.</LI>
095 * <LI>"-R {path}" or "--rejectFile {path}" -- specifies the path to the file
096 * to be written with information about all entries that failed
097 * validation.</LI>
098 * <LI>"-t {num}" or "--numThreads {num}" -- specifies the number of
099 * concurrent threads to use when processing the LDIF. If this is not
100 * provided, then a default of one thread will be used.</LI>
101 * <LI>"--ignoreUndefinedObjectClasses" -- indicates that the validation
102 * process should ignore validation failures due to entries that contain
103 * object classes not defined in the server schema.</LI>
104 * <LI>"--ignoreUndefinedAttributes" -- indicates that the validation process
105 * should ignore validation failures due to entries that contain
106 * attributes not defined in the server schema.</LI>
107 * <LI>"--ignoreMalformedDNs" -- indicates that the validation process should
108 * ignore validation failures due to entries with malformed DNs.</LI>
109 * <LI>"--ignoreStructuralObjectClasses" -- indicates that the validation
110 * process should ignore validation failures due to entries that either do
111 * not have a structural object class or that have multiple structural
112 * object classes.</LI>
113 * <LI>"--ignoreProhibitedObjectClasses" -- indicates that the validation
114 * process should ignore validation failures due to entries containing
115 * auxiliary classes that are not allowed by a DIT content rule, or
116 * abstract classes that are not subclassed by an auxiliary or structural
117 * class contained in the entry.</LI>
118 * <LI>"--ignoreProhibitedAttributes" -- indicates that the validation process
119 * should ignore validation failures due to entries including attributes
120 * that are not allowed or are explicitly prohibited by a DIT content
121 * rule.</LI>
122 * <LI>"--ignoreMissingAttributes" -- indicates that the validation process
123 * should ignore validation failures due to entries missing required
124 * attributes.</LI>
125 * <LI>"--ignoreSingleValuedAttributes" -- indicates that the validation
126 * process should ignore validation failures due to single-valued
127 * attributes containing multiple values.</LI>
128 * <LI>"--ignoreAttributeSyntax" -- indicates that the validation process
129 * should ignore validation failures due to attribute values which violate
130 * the associated attribute syntax.</LI>
131 * <LI>"--ignoreNameForms" -- indicates that the validation process should
132 * ignore validation failures due to name form violations (in which the
133 * entry's RDN does not comply with the associated name form).</LI>
134 * </UL>
135 */
136 @ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
137 public final class ValidateLDIF
138 extends LDAPCommandLineTool
139 implements LDIFReaderEntryTranslator
140 {
141 /**
142 * The end-of-line character for this platform.
143 */
144 private static final String EOL = System.getProperty("line.separator", "\n");
145
146
147
148 // The arguments used by this program.
149 private BooleanArgument ignoreDuplicateValues;
150 private BooleanArgument ignoreUndefinedObjectClasses;
151 private BooleanArgument ignoreUndefinedAttributes;
152 private BooleanArgument ignoreMalformedDNs;
153 private BooleanArgument ignoreMissingSuperiorObjectClasses;
154 private BooleanArgument ignoreStructuralObjectClasses;
155 private BooleanArgument ignoreProhibitedObjectClasses;
156 private BooleanArgument ignoreProhibitedAttributes;
157 private BooleanArgument ignoreMissingAttributes;
158 private BooleanArgument ignoreSingleValuedAttributes;
159 private BooleanArgument ignoreAttributeSyntax;
160 private BooleanArgument ignoreNameForms;
161 private BooleanArgument isCompressed;
162 private FileArgument schemaDirectory;
163 private FileArgument ldifFile;
164 private FileArgument rejectFile;
165 private IntegerArgument numThreads;
166
167 // The counter used to keep track of the number of entries processed.
168 private final AtomicLong entriesProcessed = new AtomicLong(0L);
169
170 // The counter used to keep track of the number of entries that could not be
171 // parsed as valid entries.
172 private final AtomicLong malformedEntries = new AtomicLong(0L);
173
174 // The entry validator that will be used to validate the entries.
175 private EntryValidator entryValidator;
176
177 // The LDIF writer that will be used to write rejected entries.
178 private LDIFWriter rejectWriter;
179
180
181
182 /**
183 * Parse the provided command line arguments and make the appropriate set of
184 * changes.
185 *
186 * @param args The command line arguments provided to this program.
187 */
188 public static void main(final String[] args)
189 {
190 final ResultCode resultCode = main(args, System.out, System.err);
191 if (resultCode != ResultCode.SUCCESS)
192 {
193 System.exit(resultCode.intValue());
194 }
195 }
196
197
198
199 /**
200 * Parse the provided command line arguments and make the appropriate set of
201 * changes.
202 *
203 * @param args The command line arguments provided to this program.
204 * @param outStream The output stream to which standard out should be
205 * written. It may be {@code null} if output should be
206 * suppressed.
207 * @param errStream The output stream to which standard error should be
208 * written. It may be {@code null} if error messages
209 * should be suppressed.
210 *
211 * @return A result code indicating whether the processing was successful.
212 */
213 public static ResultCode main(final String[] args,
214 final OutputStream outStream,
215 final OutputStream errStream)
216 {
217 final ValidateLDIF validateLDIF = new ValidateLDIF(outStream, errStream);
218 return validateLDIF.runTool(args);
219 }
220
221
222
223 /**
224 * Creates a new instance of this tool.
225 *
226 * @param outStream The output stream to which standard out should be
227 * written. It may be {@code null} if output should be
228 * suppressed.
229 * @param errStream The output stream to which standard error should be
230 * written. It may be {@code null} if error messages
231 * should be suppressed.
232 */
233 public ValidateLDIF(final OutputStream outStream,
234 final OutputStream errStream)
235 {
236 super(outStream, errStream);
237 }
238
239
240
241 /**
242 * Retrieves the name for this tool.
243 *
244 * @return The name for this tool.
245 */
246 @Override()
247 public String getToolName()
248 {
249 return "validate-ldif";
250 }
251
252
253
254 /**
255 * Retrieves the description for this tool.
256 *
257 * @return The description for this tool.
258 */
259 @Override()
260 public String getToolDescription()
261 {
262 return "Validate the contents of an LDIF file " +
263 "against the server schema.";
264 }
265
266
267
268 /**
269 * Retrieves the version string for this tool.
270 *
271 * @return The version string for this tool.
272 */
273 @Override()
274 public String getToolVersion()
275 {
276 return Version.NUMERIC_VERSION_STRING;
277 }
278
279
280
281 /**
282 * Adds the arguments used by this program that aren't already provided by the
283 * generic {@code LDAPCommandLineTool} framework.
284 *
285 * @param parser The argument parser to which the arguments should be added.
286 *
287 * @throws ArgumentException If a problem occurs while adding the arguments.
288 */
289 @Override()
290 public void addNonLDAPArguments(final ArgumentParser parser)
291 throws ArgumentException
292 {
293 String description = "The path to the LDIF file to process.";
294 ldifFile = new FileArgument('f', "ldifFile", true, 1, "{path}", description,
295 true, true, true, false);
296 parser.addArgument(ldifFile);
297
298 description = "Indicates that the specified LDIF file is compressed " +
299 "using gzip compression.";
300 isCompressed = new BooleanArgument('c', "isCompressed", description);
301 parser.addArgument(isCompressed);
302
303 description = "The path to the file to which rejected entries should be " +
304 "written.";
305 rejectFile = new FileArgument('R', "rejectFile", false, 1, "{path}",
306 description, false, true, true, false);
307 parser.addArgument(rejectFile);
308
309 description = "The path to a directory containing one or more LDIF files " +
310 "with the schema information to use. If this is provided, " +
311 "then no LDAP communication will be performed.";
312 schemaDirectory = new FileArgument(null, "schemaDirectory", false, 1,
313 "{path}", description, true, true, false, true);
314 parser.addArgument(schemaDirectory);
315
316 description = "The number of threads to use when processing the LDIF file.";
317 numThreads = new IntegerArgument('t', "numThreads", true, 1, "{num}",
318 description, 1, Integer.MAX_VALUE, 1);
319 parser.addArgument(numThreads);
320
321 description = "Ignore validation failures due to entries containing " +
322 "duplicate values for the same attribute.";
323 ignoreDuplicateValues =
324 new BooleanArgument(null, "ignoreDuplicateValues", description);
325 parser.addArgument(ignoreDuplicateValues);
326
327 description = "Ignore validation failures due to object classes not " +
328 "defined in the schema.";
329 ignoreUndefinedObjectClasses =
330 new BooleanArgument(null, "ignoreUndefinedObjectClasses", description);
331 parser.addArgument(ignoreUndefinedObjectClasses);
332
333 description = "Ignore validation failures due to attributes not defined " +
334 "in the schema.";
335 ignoreUndefinedAttributes =
336 new BooleanArgument(null, "ignoreUndefinedAttributes", description);
337 parser.addArgument(ignoreUndefinedAttributes);
338
339 description = "Ignore validation failures due to entries with malformed " +
340 "DNs.";
341 ignoreMalformedDNs =
342 new BooleanArgument(null, "ignoreMalformedDNs", description);
343 parser.addArgument(ignoreMalformedDNs);
344
345 description = "Ignore validation failures due to entries without exactly " +
346 "structural object class.";
347 ignoreStructuralObjectClasses =
348 new BooleanArgument(null, "ignoreStructuralObjectClasses",
349 description);
350 parser.addArgument(ignoreStructuralObjectClasses);
351
352 description = "Ignore validation failures due to entries with object " +
353 "classes that are not allowed.";
354 ignoreProhibitedObjectClasses =
355 new BooleanArgument(null, "ignoreProhibitedObjectClasses",
356 description);
357 parser.addArgument(ignoreProhibitedObjectClasses);
358
359 description = "Ignore validation failures due to entries that are " +
360 "one or more superior object classes.";
361 ignoreMissingSuperiorObjectClasses =
362 new BooleanArgument(null, "ignoreMissingSuperiorObjectClasses",
363 description);
364 parser.addArgument(ignoreMissingSuperiorObjectClasses);
365
366 description = "Ignore validation failures due to entries with attributes " +
367 "that are not allowed.";
368 ignoreProhibitedAttributes =
369 new BooleanArgument(null, "ignoreProhibitedAttributes", description);
370 parser.addArgument(ignoreProhibitedAttributes);
371
372 description = "Ignore validation failures due to entries missing " +
373 "required attributes.";
374 ignoreMissingAttributes =
375 new BooleanArgument(null, "ignoreMissingAttributes", description);
376 parser.addArgument(ignoreMissingAttributes);
377
378 description = "Ignore validation failures due to entries with multiple " +
379 "values for single-valued attributes.";
380 ignoreSingleValuedAttributes =
381 new BooleanArgument(null, "ignoreSingleValuedAttributes", description);
382 parser.addArgument(ignoreSingleValuedAttributes);
383
384 description = "Ignore validation failures due to entries with attribute " +
385 "values that violate their associated syntax.";
386 ignoreAttributeSyntax =
387 new BooleanArgument(null, "ignoreAttributeSyntax", description);
388 parser.addArgument(ignoreAttributeSyntax);
389
390 description = "Ignore validation failures due to entries with RDNs " +
391 "that violate the associated name form definition.";
392 ignoreNameForms = new BooleanArgument(null, "ignoreNameForms", description);
393 parser.addArgument(ignoreNameForms);
394 }
395
396
397
398 /**
399 * Performs the actual processing for this tool. In this case, it gets a
400 * connection to the directory server and uses it to retrieve the server
401 * schema. It then reads the LDIF file and validates each entry accordingly.
402 *
403 * @return The result code for the processing that was performed.
404 */
405 @Override()
406 public ResultCode doToolProcessing()
407 {
408 // Get the connection to the directory server and use it to read the schema.
409 final Schema schema;
410 if (schemaDirectory.isPresent())
411 {
412 final File schemaDir = schemaDirectory.getValue();
413
414 try
415 {
416 final TreeMap<String,File> fileMap = new TreeMap<String,File>();
417 for (final File f : schemaDir.listFiles())
418 {
419 final String name = f.getName();
420 if (f.isFile() && name.endsWith(".ldif"))
421 {
422 fileMap.put(name, f);
423 }
424 }
425
426 if (fileMap.isEmpty())
427 {
428 err("No LDIF files found in directory " +
429 schemaDir.getAbsolutePath());
430 return ResultCode.PARAM_ERROR;
431 }
432
433 final ArrayList<File> fileList = new ArrayList<File>(fileMap.values());
434 schema = Schema.getSchema(fileList);
435 }
436 catch (Exception e)
437 {
438 err("Unable to read schema from files in directory " +
439 schemaDir.getAbsolutePath() + ": " + getExceptionMessage(e));
440 return ResultCode.LOCAL_ERROR;
441 }
442 }
443 else
444 {
445 try
446 {
447 final LDAPConnection connection = getConnection();
448 schema = connection.getSchema();
449 connection.close();
450 }
451 catch (LDAPException le)
452 {
453 err("Unable to connect to the directory server and read the schema: ",
454 le.getMessage());
455 return le.getResultCode();
456 }
457 }
458
459
460 // Create the entry validator and initialize its configuration.
461 entryValidator = new EntryValidator(schema);
462 entryValidator.setCheckAttributeSyntax(!ignoreAttributeSyntax.isPresent());
463 entryValidator.setCheckMalformedDNs(!ignoreMalformedDNs.isPresent());
464 entryValidator.setCheckMissingAttributes(
465 !ignoreMissingAttributes.isPresent());
466 entryValidator.setCheckNameForms(!ignoreNameForms.isPresent());
467 entryValidator.setCheckProhibitedAttributes(
468 !ignoreProhibitedAttributes.isPresent());
469 entryValidator.setCheckProhibitedObjectClasses(
470 !ignoreProhibitedObjectClasses.isPresent());
471 entryValidator.setCheckMissingSuperiorObjectClasses(
472 !ignoreMissingSuperiorObjectClasses.isPresent());
473 entryValidator.setCheckSingleValuedAttributes(
474 !ignoreSingleValuedAttributes.isPresent());
475 entryValidator.setCheckStructuralObjectClasses(
476 !ignoreStructuralObjectClasses.isPresent());
477 entryValidator.setCheckUndefinedAttributes(
478 !ignoreUndefinedAttributes.isPresent());
479 entryValidator.setCheckUndefinedObjectClasses(
480 !ignoreUndefinedObjectClasses.isPresent());
481
482
483 // Create an LDIF reader that can be used to read through the LDIF file.
484 final LDIFReader ldifReader;
485 rejectWriter = null;
486 try
487 {
488 InputStream inputStream = new FileInputStream(ldifFile.getValue());
489 if (isCompressed.isPresent())
490 {
491 inputStream = new GZIPInputStream(inputStream);
492 }
493 ldifReader = new LDIFReader(inputStream, numThreads.getValue(), this);
494 }
495 catch (Exception e)
496 {
497 err("Unable to open the LDIF reader: ", getExceptionMessage(e));
498 return ResultCode.LOCAL_ERROR;
499 }
500
501 ldifReader.setSchema(schema);
502 if (ignoreDuplicateValues.isPresent())
503 {
504 ldifReader.setDuplicateValueBehavior(DuplicateValueBehavior.STRIP);
505 }
506 else
507 {
508 ldifReader.setDuplicateValueBehavior(DuplicateValueBehavior.REJECT);
509 }
510
511 try
512 {
513 // Create an LDIF writer that can be used to write information about
514 // rejected entries.
515 try
516 {
517 if (rejectFile.isPresent())
518 {
519 rejectWriter = new LDIFWriter(rejectFile.getValue());
520 }
521 }
522 catch (Exception e)
523 {
524 err("Unable to create the reject writer: ", getExceptionMessage(e));
525 return ResultCode.LOCAL_ERROR;
526 }
527
528 ResultCode resultCode = ResultCode.SUCCESS;
529 while (true)
530 {
531 try
532 {
533 final Entry e = ldifReader.readEntry();
534 if (e == null)
535 {
536 // Because we're performing parallel processing and returning null
537 // from the translate method, LDIFReader.readEntry() should never
538 // return a non-null value. However, it can throw an LDIFException
539 // if it encounters an invalid entry, or an IOException if there's
540 // a problem reading from the file, so we should still iterate
541 // through all of the entries to catch and report on those problems.
542 break;
543 }
544 }
545 catch (LDIFException le)
546 {
547 malformedEntries.incrementAndGet();
548
549 if (resultCode == ResultCode.SUCCESS)
550 {
551 resultCode = ResultCode.DECODING_ERROR;
552 }
553
554 if (rejectWriter != null)
555 {
556 try
557 {
558 rejectWriter.writeComment(
559 "Unable to parse an entry read from LDIF:", false, false);
560 if (le.mayContinueReading())
561 {
562 rejectWriter.writeComment(getExceptionMessage(le), false, true);
563 }
564 else
565 {
566 rejectWriter.writeComment(getExceptionMessage(le), false,
567 false);
568 rejectWriter.writeComment("Unable to continue LDIF processing.",
569 false, true);
570 err("Aborting LDIF processing: ", getExceptionMessage(le));
571 return ResultCode.LOCAL_ERROR;
572 }
573 }
574 catch (IOException ioe)
575 {
576 err("Unable to write to the reject file:",
577 getExceptionMessage(ioe));
578 err("LDIF parse failure that triggered the rejection: ",
579 getExceptionMessage(le));
580 return ResultCode.LOCAL_ERROR;
581 }
582 }
583 }
584 catch (IOException ioe)
585 {
586
587 if (rejectWriter != null)
588 {
589 try
590 {
591 rejectWriter.writeComment("I/O error reading from LDIF:", false,
592 false);
593 rejectWriter.writeComment(getExceptionMessage(ioe), false,
594 true);
595 return ResultCode.LOCAL_ERROR;
596 }
597 catch (Exception ex)
598 {
599 err("I/O error reading from LDIF:", getExceptionMessage(ioe));
600 return ResultCode.LOCAL_ERROR;
601 }
602 }
603 }
604 }
605
606 if (malformedEntries.get() > 0)
607 {
608 out(malformedEntries.get() + " entries were malformed and could not " +
609 "be read from the LDIF file.");
610 }
611
612 if (entryValidator.getInvalidEntries() > 0)
613 {
614 if (resultCode == ResultCode.SUCCESS)
615 {
616 resultCode = ResultCode.OBJECT_CLASS_VIOLATION;
617 }
618
619 for (final String s : entryValidator.getInvalidEntrySummary(true))
620 {
621 out(s);
622 }
623 }
624 else
625 {
626 if (malformedEntries.get() == 0)
627 {
628 out("No errors were encountered.");
629 }
630 }
631
632 return resultCode;
633 }
634 finally
635 {
636 try
637 {
638 ldifReader.close();
639 }
640 catch (Exception e) {}
641
642 try
643 {
644 if (rejectWriter != null)
645 {
646 rejectWriter.close();
647 }
648 }
649 catch (Exception e) {}
650 }
651 }
652
653
654
655 /**
656 * Examines the provided entry to determine whether it conforms to the
657 * server schema.
658 *
659 * @param entry The entry to be examined.
660 * @param firstLineNumber The line number of the LDIF source on which the
661 * provided entry begins.
662 *
663 * @return The updated entry. This method will always return {@code null}
664 * because all of the real processing needed for the entry is
665 * performed in this method and the entry isn't needed any more
666 * after this method is done.
667 */
668 public Entry translate(final Entry entry, final long firstLineNumber)
669 {
670 final ArrayList<String> invalidReasons = new ArrayList<String>(5);
671 if (! entryValidator.entryIsValid(entry, invalidReasons))
672 {
673 if (rejectWriter != null)
674 {
675 synchronized (this)
676 {
677 try
678 {
679 rejectWriter.writeEntry(entry, listToString(invalidReasons));
680 }
681 catch (IOException ioe) {}
682 }
683 }
684 }
685
686 final long numEntries = entriesProcessed.incrementAndGet();
687 if ((numEntries % 1000L) == 0L)
688 {
689 out("Processed ", numEntries, " entries.");
690 }
691
692 return null;
693 }
694
695
696
697 /**
698 * Converts the provided list of strings into a single string. It will
699 * contain line breaks after all but the last element.
700 *
701 * @param l The list of strings to convert to a single string.
702 *
703 * @return The string from the provided list, or {@code null} if the provided
704 * list is empty or {@code null}.
705 */
706 private static String listToString(final List<String> l)
707 {
708 if ((l == null) || (l.isEmpty()))
709 {
710 return null;
711 }
712
713 final StringBuilder buffer = new StringBuilder();
714 final Iterator<String> iterator = l.iterator();
715 while (iterator.hasNext())
716 {
717 buffer.append(iterator.next());
718 if (iterator.hasNext())
719 {
720 buffer.append(EOL);
721 }
722 }
723
724 return buffer.toString();
725 }
726
727
728
729 /**
730 * {@inheritDoc}
731 */
732 @Override()
733 public LinkedHashMap<String[],String> getExampleUsages()
734 {
735 final LinkedHashMap<String[],String> examples =
736 new LinkedHashMap<String[],String>(2);
737
738 String[] args =
739 {
740 "--hostname", "server.example.com",
741 "--port", "389",
742 "--ldifFile", "data.ldif",
743 "--rejectFile", "rejects.ldif",
744 "--numThreads", "4"
745 };
746 String description =
747 "Validate the contents of the 'data.ldif' file using the schema " +
748 "defined in the specified directory server using four concurrent " +
749 "threads. All types of validation will be performed, and " +
750 "information about any errors will be written to the 'rejects.ldif' " +
751 "file.";
752 examples.put(args, description);
753
754
755 args = new String[]
756 {
757 "--schemaDirectory", "/ds/config/schema",
758 "--ldifFile", "data.ldif",
759 "--rejectFile", "rejects.ldif",
760 "--ignoreStructuralObjectClasses",
761 "--ignoreAttributeSyntax"
762 };
763 description =
764 "Validate the contents of the 'data.ldif' file using the schema " +
765 "defined in LDIF files contained in the /ds/config/schema directory " +
766 "using a single thread. Any errors resulting from entries that do " +
767 "not have exactly one structural object class or from values which " +
768 "violate the syntax for their associated attribute types will be " +
769 "ignored. Information about any other failures will be written to " +
770 "the 'rejects.ldif' file.";
771 examples.put(args, description);
772
773 return examples;
774 }
775
776
777
778 /**
779 * @return EntryValidator
780 *
781 * Returns the EntryValidator
782 */
783 public EntryValidator getEntryValidator()
784 {
785 return entryValidator;
786 }
787 }