001/* 002 * Copyright 2020-2024 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2020-2024 Ping Identity Corporation 007 * 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 */ 020/* 021 * Copyright (C) 2020-2024 Ping Identity Corporation 022 * 023 * This program is free software; you can redistribute it and/or modify 024 * it under the terms of the GNU General Public License (GPLv2 only) 025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 026 * as published by the Free Software Foundation. 027 * 028 * This program is distributed in the hope that it will be useful, 029 * but WITHOUT ANY WARRANTY; without even the implied warranty of 030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 031 * GNU General Public License for more details. 032 * 033 * You should have received a copy of the GNU General Public License 034 * along with this program; if not, see <http://www.gnu.org/licenses>. 035 */ 036package com.unboundid.ldap.sdk.schema; 037 038 039 040import java.io.File; 041import java.io.OutputStream; 042import java.util.ArrayList; 043import java.util.EnumSet; 044import java.util.LinkedHashMap; 045import java.util.List; 046import java.util.Set; 047import java.util.concurrent.atomic.AtomicReference; 048 049import com.unboundid.ldap.sdk.ResultCode; 050import com.unboundid.ldap.sdk.Version; 051import com.unboundid.util.CommandLineTool; 052import com.unboundid.util.NotNull; 053import com.unboundid.util.Nullable; 054import com.unboundid.util.StaticUtils; 055import com.unboundid.util.ThreadSafety; 056import com.unboundid.util.ThreadSafetyLevel; 057import com.unboundid.util.args.ArgumentException; 058import com.unboundid.util.args.ArgumentParser; 059import com.unboundid.util.args.BooleanArgument; 060import com.unboundid.util.args.FileArgument; 061import com.unboundid.util.args.StringArgument; 062 063import static com.unboundid.ldap.sdk.schema.SchemaMessages.*; 064 065 066 067/** 068 * This class provides a command-line tool that may be used to validate 069 * definitions read from one or more schema files. It uses the 070 * {@link SchemaValidator} to perform the core of the processing. 071 */ 072@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE) 073public final class ValidateLDAPSchema 074 extends CommandLineTool 075{ 076 /** 077 * The column at which long lines should be wrapped. 078 */ 079 private static final int WRAP_COLUMN = StaticUtils.TERMINAL_WIDTH_COLUMNS - 1; 080 081 082 083 // A reference to the completion message for this tool. 084 @NotNull private final AtomicReference<String> completionMessage; 085 086 // Arguments used by this tool. 087 @Nullable private BooleanArgument allowAttributeTypesWithoutSyntax; 088 @Nullable private BooleanArgument allowElementsWithoutNames; 089 @Nullable private BooleanArgument allowEmptyDescriptions; 090 @Nullable private BooleanArgument allowMultipleEntriesPerSchemaFile; 091 @Nullable private BooleanArgument allowNonNumericOIDs; 092 @Nullable private BooleanArgument allowRedefiningElements; 093 @Nullable private BooleanArgument allowSchemaFilesInSubdirectories; 094 @Nullable private BooleanArgument allowStructuralObjectClassesWithoutSuperior; 095 @Nullable private BooleanArgument 096 rejectAttributeTypesWithoutEqualityMatchingRule; 097 @Nullable private BooleanArgument rejectObjectClassesWithMultipleSuperiors; 098 @Nullable private BooleanArgument useLenientNameValidation; 099 @Nullable private BooleanArgument useLenientOIDValidation; 100 @Nullable private FileArgument schemaPath; 101 @Nullable private StringArgument allowedElementType; 102 @Nullable private StringArgument allowUndefinedElementType; 103 @Nullable private StringArgument prohibitedElementType; 104 105 106 107 /** 108 * Runs this tool with the provided set of command-line arguments. 109 * 110 * @param args The command-line arguments provided to this program. 111 */ 112 public static void main(@NotNull final String... args) 113 { 114 final ResultCode resultCode = main(System.out, System.err, args); 115 if (resultCode != ResultCode.SUCCESS) 116 { 117 System.exit(resultCode.intValue()); 118 } 119 } 120 121 122 123 /** 124 * Runs this tool with the provided set of command-line arguments. 125 * 126 * @param out The output stream to use for standard output. It may be 127 * {@code null} if standard output should be suppressed. 128 * @param err The output stream to use for standard error. It may be 129 * {@code null} if standard error should be suppressed. 130 * @param args The command-line arguments provided to this program. 131 * 132 * @return A result code that indicates whether processing completed 133 * successfully. 134 */ 135 @NotNull() 136 public static ResultCode main(@Nullable final OutputStream out, 137 @Nullable final OutputStream err, 138 @NotNull final String... args) 139 { 140 final ValidateLDAPSchema tool = new ValidateLDAPSchema(out, err); 141 return tool.runTool(args); 142 } 143 144 145 146 /** 147 * Creates a new instance of this tool with the provided output and error 148 * streams. 149 * 150 * @param out The output stream to use for standard output. It may be 151 * {@code null} if standard output should be suppressed. 152 * @param err The output stream to use for standard error. It may be 153 * {@code null} if standard error should be suppressed. 154 */ 155 public ValidateLDAPSchema(@Nullable final OutputStream out, 156 @Nullable final OutputStream err) 157 { 158 super(out, err); 159 160 completionMessage = new AtomicReference<>(); 161 162 allowAttributeTypesWithoutSyntax = null; 163 allowElementsWithoutNames = null; 164 allowEmptyDescriptions = null; 165 allowMultipleEntriesPerSchemaFile = null; 166 allowNonNumericOIDs = null; 167 allowRedefiningElements = null; 168 allowSchemaFilesInSubdirectories = null; 169 allowStructuralObjectClassesWithoutSuperior = null; 170 rejectAttributeTypesWithoutEqualityMatchingRule = null; 171 rejectObjectClassesWithMultipleSuperiors = null; 172 useLenientNameValidation = null; 173 useLenientOIDValidation = null; 174 schemaPath = null; 175 allowedElementType = null; 176 allowUndefinedElementType = null; 177 prohibitedElementType = null; 178 } 179 180 181 182 /** 183 * {@inheritDoc} 184 */ 185 @Override() 186 @NotNull() 187 public String getToolName() 188 { 189 return "validate-ldap-schema"; 190 } 191 192 193 194 /** 195 * {@inheritDoc} 196 */ 197 @Override() 198 @NotNull() 199 public String getToolDescription() 200 { 201 return INFO_VALIDATE_SCHEMA_TOOL_DESCRIPTION.get(); 202 } 203 204 205 206 /** 207 * {@inheritDoc} 208 */ 209 @Override() 210 @NotNull() 211 public String getToolVersion() 212 { 213 return Version.NUMERIC_VERSION_STRING; 214 } 215 216 217 218 /** 219 * {@inheritDoc} 220 */ 221 @Override() 222 public boolean supportsInteractiveMode() 223 { 224 return true; 225 } 226 227 228 229 /** 230 * {@inheritDoc} 231 */ 232 @Override() 233 public boolean defaultsToInteractiveMode() 234 { 235 return (! SchemaValidator.PING_IDENTITY_DIRECTORY_SERVER_AVAILABLE); 236 } 237 238 239 240 /** 241 * {@inheritDoc} 242 */ 243 @Override() 244 public boolean supportsPropertiesFile() 245 { 246 return true; 247 } 248 249 250 251 /** 252 * {@inheritDoc} 253 */ 254 @Override() 255 protected boolean supportsOutputFile() 256 { 257 return true; 258 } 259 260 261 262 /** 263 * {@inheritDoc} 264 */ 265 @Override() 266 protected boolean supportsDebugLogging() 267 { 268 return true; 269 } 270 271 272 273 /** 274 * {@inheritDoc} 275 */ 276 @Override() 277 protected boolean logToolInvocationByDefault() 278 { 279 return false; 280 } 281 282 283 284 /** 285 * {@inheritDoc} 286 */ 287 @Override() 288 @Nullable() 289 protected String getToolCompletionMessage() 290 { 291 return completionMessage.get(); 292 } 293 294 295 296 /** 297 * {@inheritDoc} 298 */ 299 @Override() 300 public void addToolArguments(@NotNull final ArgumentParser parser) 301 throws ArgumentException 302 { 303 final boolean pingIdentityDSAvailable = 304 SchemaValidator.PING_IDENTITY_DIRECTORY_SERVER_AVAILABLE; 305 306 307 final List<File> defaultSchemaPaths = new ArrayList<>(1); 308 if (pingIdentityDSAvailable && 309 (SchemaValidator.PING_IDENTITY_DIRECTORY_SERVER_SCHEMA_DIR != null)) 310 { 311 defaultSchemaPaths.add( 312 SchemaValidator.PING_IDENTITY_DIRECTORY_SERVER_SCHEMA_DIR); 313 } 314 315 schemaPath = new FileArgument(null, "schema-path", true, 0, null, 316 INFO_VALIDATE_SCHEMA_ARG_DESC_SCHEMA_PATH.get(), true, true, false, 317 false, defaultSchemaPaths); 318 schemaPath.addLongIdentifier("schemaPath", true); 319 schemaPath.addLongIdentifier("schema-file", true); 320 schemaPath.addLongIdentifier("schemaFile", true); 321 schemaPath.addLongIdentifier("schema-directory", true); 322 schemaPath.addLongIdentifier("schemaDirectory", true); 323 schemaPath.addLongIdentifier("schema-dir", true); 324 schemaPath.addLongIdentifier("schemaDir", true); 325 schemaPath.addLongIdentifier("file", true); 326 schemaPath.addLongIdentifier("directory", true); 327 schemaPath.addLongIdentifier("path", true); 328 schemaPath.setArgumentGroupName(INFO_VALIDATE_SCHEMA_ARG_GROUP_INPUT.get()); 329 parser.addArgument(schemaPath); 330 331 332 allowMultipleEntriesPerSchemaFile = new BooleanArgument(null, 333 "allow-multiple-entries-per-schema-file", 1, 334 INFO_VALIDATE_SCHEMA_ARG_DESC_ALLOW_MULTIPLE_ENTRIES.get()); 335 allowMultipleEntriesPerSchemaFile.addLongIdentifier( 336 "allowMultipleEntriesPerSchemaFile", true); 337 allowMultipleEntriesPerSchemaFile.setArgumentGroupName( 338 INFO_VALIDATE_SCHEMA_ARG_GROUP_INPUT.get()); 339 parser.addArgument(allowMultipleEntriesPerSchemaFile); 340 341 342 allowSchemaFilesInSubdirectories = new BooleanArgument(null, 343 "allow-schema-files-in-subdirectories", 1, 344 INFO_VALIDATE_SCHEMA_ARG_DESC_ALLOW_SUB_DIRS.get()); 345 allowSchemaFilesInSubdirectories.addLongIdentifier( 346 "allow-schema-files-in-sub-directories", true); 347 allowSchemaFilesInSubdirectories.addLongIdentifier( 348 "allowSchemaFilesInSubDirectories", true); 349 allowSchemaFilesInSubdirectories.setArgumentGroupName( 350 INFO_VALIDATE_SCHEMA_ARG_GROUP_INPUT.get()); 351 parser.addArgument(allowSchemaFilesInSubdirectories); 352 353 354 allowedElementType = new StringArgument(null, "allowed-element-type", false, 355 0, INFO_VALIDATE_SCHEMA_ARG_PLACEHOLDER_ELEMENT_TYPE.get(), 356 INFO_VALIDATE_SCHEMA_ARG_DESC_ALLOWED_ELEMENT_TYPE.get()); 357 allowedElementType.addLongIdentifier("allowedElementType", true); 358 allowedElementType.addLongIdentifier("allowed-schema-element-type", true); 359 allowedElementType.addLongIdentifier("allowedSchemaElementType", true); 360 allowedElementType.addLongIdentifier("allow-element-type", true); 361 allowedElementType.addLongIdentifier("allowElementType", true); 362 allowedElementType.addLongIdentifier("allow-schema-element-type", true); 363 allowedElementType.addLongIdentifier("allowSchemaElementType", true); 364 allowedElementType.addLongIdentifier("allowed-element", true); 365 allowedElementType.addLongIdentifier("allowedElement", true); 366 allowedElementType.addLongIdentifier("allow-element", true); 367 allowedElementType.addLongIdentifier("allowElement", true); 368 allowedElementType.setArgumentGroupName( 369 INFO_VALIDATE_SCHEMA_ARG_GROUP_VALIDATION.get()); 370 parser.addArgument(allowedElementType); 371 372 373 prohibitedElementType = new StringArgument(null, "prohibited-element-type", 374 false, 0, INFO_VALIDATE_SCHEMA_ARG_PLACEHOLDER_ELEMENT_TYPE.get(), 375 INFO_VALIDATE_SCHEMA_ARG_DESC_PROHIBITED_ELEMENT_TYPE.get()); 376 prohibitedElementType.addLongIdentifier("prohibitedElementType", true); 377 prohibitedElementType.addLongIdentifier("prohibited-schema-element-type", 378 true); 379 prohibitedElementType.addLongIdentifier("prohibitedSchemaElementType", 380 true); 381 prohibitedElementType.addLongIdentifier("prohibit-element-type", true); 382 prohibitedElementType.addLongIdentifier("prohibitElementType", true); 383 prohibitedElementType.addLongIdentifier("prohibit-schema-element-type", 384 true); 385 prohibitedElementType.addLongIdentifier("prohibitSchemaElementType", true); 386 prohibitedElementType.addLongIdentifier("prohibited-element", true); 387 prohibitedElementType.addLongIdentifier("prohibitedElement", true); 388 prohibitedElementType.addLongIdentifier("prohibit-element", true); 389 prohibitedElementType.addLongIdentifier("prohibitElement", true); 390 prohibitedElementType.setArgumentGroupName( 391 INFO_VALIDATE_SCHEMA_ARG_GROUP_VALIDATION.get()); 392 parser.addArgument(prohibitedElementType); 393 394 395 allowRedefiningElements = new BooleanArgument(null, 396 "allow-redefining-elements", 1, 397 INFO_VALIDATE_SCHEMA_ARG_DESC_ALLOW_REDEFINING.get()); 398 allowRedefiningElements.addLongIdentifier( 399 "allow-re-defining-elements", true); 400 allowRedefiningElements.addLongIdentifier( 401 "allowRedefiningElements", true); 402 allowRedefiningElements.addLongIdentifier( 403 "allow-redefining-schema-elements", true); 404 allowRedefiningElements.addLongIdentifier( 405 "allow-re-defining-schema-elements", true); 406 allowRedefiningElements.addLongIdentifier( 407 "allowRedefiningSchemaElements", true); 408 allowRedefiningElements.setArgumentGroupName( 409 INFO_VALIDATE_SCHEMA_ARG_GROUP_VALIDATION.get()); 410 parser.addArgument(allowRedefiningElements); 411 412 413 allowUndefinedElementType = new StringArgument(null, 414 "allow-undefined-element-type", false, 0, 415 INFO_VALIDATE_SCHEMA_ARG_PLACEHOLDER_ELEMENT_TYPE.get(), 416 INFO_VALIDATE_SCHEMA_ARG_DESC_ALLOW_UNDEFINED.get()); 417 allowUndefinedElementType.addLongIdentifier("allowUndefinedElementType", 418 true); 419 allowUndefinedElementType.addLongIdentifier( 420 "allow-undefined-schema-element-type", true); 421 allowUndefinedElementType.addLongIdentifier( 422 "allowUndefinedSchemaElementType", true); 423 allowUndefinedElementType.addLongIdentifier( 424 "allowed-undefined-element-type", true); 425 allowUndefinedElementType.addLongIdentifier("allowedUndefinedElementType", 426 true); 427 allowUndefinedElementType.addLongIdentifier( 428 "allowed-undefined-schema-element-type", true); 429 allowUndefinedElementType.addLongIdentifier( 430 "allowedUndefinedSchemaElementType", true); 431 allowUndefinedElementType.addLongIdentifier("allow-undefined-element", 432 true); 433 allowUndefinedElementType.addLongIdentifier("allowUndefinedType", true); 434 allowUndefinedElementType.addLongIdentifier("allow-undefined-type", true); 435 allowUndefinedElementType.addLongIdentifier("allowUndefinedElement", true); 436 allowUndefinedElementType.addLongIdentifier("allowed-undefined-element", 437 true); 438 allowUndefinedElementType.addLongIdentifier("allowedUndefinedType", true); 439 allowUndefinedElementType.addLongIdentifier("allowed-undefined-type", true); 440 allowUndefinedElementType.addLongIdentifier("allowedUndefinedElement", 441 true); 442 allowUndefinedElementType.setArgumentGroupName( 443 INFO_VALIDATE_SCHEMA_ARG_GROUP_VALIDATION.get()); 444 parser.addArgument(allowUndefinedElementType); 445 446 447 useLenientOIDValidation = new BooleanArgument(null, 448 "use-lenient-oid-validation", 1, 449 INFO_VALIDATE_SCHEMA_ARG_DESC_LENIENT_OID.get()); 450 useLenientOIDValidation.addLongIdentifier( 451 "useLenientOIDValidation", true); 452 useLenientOIDValidation.addLongIdentifier( 453 "allow-lenient-oid-validation", true); 454 useLenientOIDValidation.addLongIdentifier( 455 "allowLenientOIDValidation", true); 456 useLenientOIDValidation.addLongIdentifier( 457 "lenient-oid-validation", true); 458 useLenientOIDValidation.addLongIdentifier( 459 "lenientOIDValidation", true); 460 useLenientOIDValidation.setArgumentGroupName( 461 INFO_VALIDATE_SCHEMA_ARG_GROUP_VALIDATION.get()); 462 parser.addArgument(useLenientOIDValidation); 463 464 465 allowNonNumericOIDs = new BooleanArgument(null, "allow-non-numeric-oids", 466 1, INFO_VALIDATE_SCHEMA_ARG_DESC_ALLOW_NON_NUMERIC_OID.get()); 467 allowNonNumericOIDs.addLongIdentifier("allow-nonnumeric-oids", true); 468 allowNonNumericOIDs.addLongIdentifier("allowNonNumericOIDs", true); 469 allowNonNumericOIDs.addLongIdentifier("allow-non-numeric-oid", true); 470 allowNonNumericOIDs.addLongIdentifier("allow-nonnumeric-oid", true); 471 allowNonNumericOIDs.addLongIdentifier("allowNonNumericOID", true); 472 allowNonNumericOIDs.setArgumentGroupName( 473 INFO_VALIDATE_SCHEMA_ARG_GROUP_VALIDATION.get()); 474 parser.addArgument(allowNonNumericOIDs); 475 476 477 allowElementsWithoutNames = new BooleanArgument(null, 478 "allow-elements-without-names", 1, 479 INFO_VALIDATE_SCHEMA_ARG_DESC_ALLOW_MISSING_NAME.get()); 480 allowElementsWithoutNames.addLongIdentifier("allowElementsWithoutNames", 481 true); 482 allowElementsWithoutNames.addLongIdentifier( 483 "allow-schema-elements-without-names", true); 484 allowElementsWithoutNames.addLongIdentifier( 485 "allowSchemaElementsWithoutNames", true); 486 allowElementsWithoutNames.addLongIdentifier("allow-elements-missing-names", 487 true); 488 allowElementsWithoutNames.addLongIdentifier("allowElementsMissingNames", 489 true); 490 allowElementsWithoutNames.addLongIdentifier( 491 "allow-schema-elements-missing-names", true); 492 allowElementsWithoutNames.addLongIdentifier( 493 "allowSchemaElementsMissingNames", true); 494 allowElementsWithoutNames.addLongIdentifier("allow-missing-names", 495 true); 496 allowElementsWithoutNames.addLongIdentifier("allowEMissingNames", 497 true); 498 allowElementsWithoutNames.setArgumentGroupName( 499 INFO_VALIDATE_SCHEMA_ARG_GROUP_VALIDATION.get()); 500 parser.addArgument(allowElementsWithoutNames); 501 502 503 useLenientNameValidation = new BooleanArgument(null, 504 "use-lenient-name-validation", 1, 505 INFO_VALIDATE_SCHEMA_ARG_DESC_LENIENT_NAMES.get()); 506 useLenientNameValidation.addLongIdentifier("useLenientNameValidation", 507 true); 508 useLenientNameValidation.addLongIdentifier("allow-lenient-name-validation", 509 true); 510 useLenientNameValidation.addLongIdentifier("allowLenientNameValidation", 511 true); 512 useLenientNameValidation.addLongIdentifier("lenient-name-validation", true); 513 useLenientNameValidation.addLongIdentifier("lenientNameValidation", true); 514 useLenientNameValidation.setArgumentGroupName( 515 INFO_VALIDATE_SCHEMA_ARG_GROUP_VALIDATION.get()); 516 parser.addArgument(useLenientNameValidation); 517 518 519 allowAttributeTypesWithoutSyntax = new BooleanArgument(null, 520 "allow-attribute-types-without-syntax", 1, 521 INFO_VALIDATE_SCHEMA_ARG_DESC_ALLOW_AT_WITHOUT_SYNTAX.get()); 522 allowAttributeTypesWithoutSyntax.addLongIdentifier( 523 "allowAttributeTypesWithoutSyntax", true); 524 allowAttributeTypesWithoutSyntax.addLongIdentifier( 525 "allow-attribute-type-without-syntax", true); 526 allowAttributeTypesWithoutSyntax.addLongIdentifier( 527 "allowAttributeTypeWithoutSyntax", true); 528 allowAttributeTypesWithoutSyntax.addLongIdentifier( 529 "allow-attribute-types-missing-Syntax", true); 530 allowAttributeTypesWithoutSyntax.addLongIdentifier( 531 "allowAttributeTypesMissingSyntax", true); 532 allowAttributeTypesWithoutSyntax.addLongIdentifier( 533 "allow-attribute-type-missing-syntax", true); 534 allowAttributeTypesWithoutSyntax.addLongIdentifier( 535 "allowAttributeTypeMissingSyntax", true); 536 allowAttributeTypesWithoutSyntax.setArgumentGroupName( 537 INFO_VALIDATE_SCHEMA_ARG_GROUP_VALIDATION.get()); 538 parser.addArgument(allowAttributeTypesWithoutSyntax); 539 540 541 rejectAttributeTypesWithoutEqualityMatchingRule = new BooleanArgument(null, 542 "reject-attribute-types-without-equality-matching-rule", 1, 543 INFO_VALIDATE_SCHEMA_ARG_DESC_REJECT_AT_WITHOUT_EQ_MR.get()); 544 rejectAttributeTypesWithoutEqualityMatchingRule.addLongIdentifier( 545 "rejectAttributeTypesWithoutEqualityMatchingRule", true); 546 rejectAttributeTypesWithoutEqualityMatchingRule.addLongIdentifier( 547 "reject-attribute-type-without-equality-matching-rule", true); 548 rejectAttributeTypesWithoutEqualityMatchingRule.addLongIdentifier( 549 "rejectAttributeTypeWithoutEqualityMatchingRule", true); 550 rejectAttributeTypesWithoutEqualityMatchingRule.addLongIdentifier( 551 "reject-attribute-types-missing-equality-matching-rule", true); 552 rejectAttributeTypesWithoutEqualityMatchingRule.addLongIdentifier( 553 "rejectAttributeTypesMissingEqualityMatchingRule", true); 554 rejectAttributeTypesWithoutEqualityMatchingRule.addLongIdentifier( 555 "reject-attribute-type-missing-equality-matching-rule", true); 556 rejectAttributeTypesWithoutEqualityMatchingRule.addLongIdentifier( 557 "rejectAttributeTypeMissingEqualityMatchingRule", true); 558 rejectAttributeTypesWithoutEqualityMatchingRule.setArgumentGroupName( 559 INFO_VALIDATE_SCHEMA_ARG_GROUP_VALIDATION.get()); 560 parser.addArgument(rejectAttributeTypesWithoutEqualityMatchingRule); 561 562 563 allowStructuralObjectClassesWithoutSuperior = new BooleanArgument(null, 564 "allow-structural-object-classes-without-superior", 1, 565 INFO_VALIDATE_SCHEMA_ARG_DESC_ALLOW_MISSING_MISSING_OC_SUP.get()); 566 allowStructuralObjectClassesWithoutSuperior.addLongIdentifier( 567 "allow-structural-objectclasses-without-superior", true); 568 allowStructuralObjectClassesWithoutSuperior.addLongIdentifier( 569 "allowStructuralObjectClassesWithoutSuperior", true); 570 allowStructuralObjectClassesWithoutSuperior.addLongIdentifier( 571 "allow-structural-object-class-without-superior", true); 572 allowStructuralObjectClassesWithoutSuperior.addLongIdentifier( 573 "allow-structural-objectclass-without-superior", true); 574 allowStructuralObjectClassesWithoutSuperior.addLongIdentifier( 575 "allowStructuralObjectClassWithoutSuperior", true); 576 allowStructuralObjectClassesWithoutSuperior.addLongIdentifier( 577 "allow-structural-classes-without-superior", true); 578 allowStructuralObjectClassesWithoutSuperior.addLongIdentifier( 579 "allowStructuralClassesWithoutSuperior", true); 580 allowStructuralObjectClassesWithoutSuperior.addLongIdentifier( 581 "allow-structural-class-without-superior", true); 582 allowStructuralObjectClassesWithoutSuperior.addLongIdentifier( 583 "allowStructuralClassWithoutSuperior", true); 584 allowStructuralObjectClassesWithoutSuperior.addLongIdentifier( 585 "allow-object-classes-without-superior", true); 586 allowStructuralObjectClassesWithoutSuperior.addLongIdentifier( 587 "allow-objectclasses-without-superior", true); 588 allowStructuralObjectClassesWithoutSuperior.addLongIdentifier( 589 "allowObjectClassesWithoutSuperior", true); 590 allowStructuralObjectClassesWithoutSuperior.addLongIdentifier( 591 "allow-object-class-without-superior", true); 592 allowStructuralObjectClassesWithoutSuperior.addLongIdentifier( 593 "allow-objectclass-without-superior", true); 594 allowStructuralObjectClassesWithoutSuperior.addLongIdentifier( 595 "allowObjectClassWithoutSuperior", true); 596 allowStructuralObjectClassesWithoutSuperior.setArgumentGroupName( 597 INFO_VALIDATE_SCHEMA_ARG_GROUP_VALIDATION.get()); 598 parser.addArgument(allowStructuralObjectClassesWithoutSuperior); 599 600 601 rejectObjectClassesWithMultipleSuperiors = new BooleanArgument(null, 602 "reject-object-classes-with-multiple-superiors", 1, 603 INFO_VALIDATE_SCHEMA_ARG_DESC_REJECT_MULTIPLE_OC_SUP.get()); 604 rejectObjectClassesWithMultipleSuperiors.addLongIdentifier( 605 "reject-objectclasses-with-multiple-superiors", true); 606 rejectObjectClassesWithMultipleSuperiors.addLongIdentifier( 607 "rejectObjectClassesWithMultipleSuperiors", true); 608 rejectObjectClassesWithMultipleSuperiors.addLongIdentifier( 609 "reject-object-class-with-multiple-superiors", true); 610 rejectObjectClassesWithMultipleSuperiors.addLongIdentifier( 611 "reject-objectclass-with-multiple-superiors", true); 612 rejectObjectClassesWithMultipleSuperiors.addLongIdentifier( 613 "rejectObjectClassWithMultipleSuperiors", true); 614 rejectObjectClassesWithMultipleSuperiors.addLongIdentifier( 615 "reject-object-classes-with-multiple-superior-classes", true); 616 rejectObjectClassesWithMultipleSuperiors.addLongIdentifier( 617 "reject-objectclasses-with-multiple-superior-classes", true); 618 rejectObjectClassesWithMultipleSuperiors.addLongIdentifier( 619 "rejectObjectClassesWithMultipleSuperiorClasses", true); 620 rejectObjectClassesWithMultipleSuperiors.addLongIdentifier( 621 "reject-object-class-with-multiple-superior-classes", true); 622 rejectObjectClassesWithMultipleSuperiors.addLongIdentifier( 623 "reject-objectclass-with-multiple-superior-classes", true); 624 rejectObjectClassesWithMultipleSuperiors.addLongIdentifier( 625 "rejectObjectClassWithMultipleSuperiorClasses", true); 626 rejectObjectClassesWithMultipleSuperiors.setArgumentGroupName( 627 INFO_VALIDATE_SCHEMA_ARG_GROUP_VALIDATION.get()); 628 if (pingIdentityDSAvailable) 629 { 630 rejectObjectClassesWithMultipleSuperiors.setHidden(true); 631 } 632 parser.addArgument(rejectObjectClassesWithMultipleSuperiors); 633 634 635 allowEmptyDescriptions = new BooleanArgument(null, 636 "allow-empty-descriptions", 1, 637 INFO_VALIDATE_SCHEMA_ARG_DESC_ALLOW_EMPTY_DESC.get()); 638 allowEmptyDescriptions.addLongIdentifier("allowEmptyDescriptions", true); 639 allowEmptyDescriptions.addLongIdentifier("allow-empty-description", true); 640 allowEmptyDescriptions.addLongIdentifier("allowEmptyDescription", true); 641 allowEmptyDescriptions.addLongIdentifier("allow-empty-desc", true); 642 allowEmptyDescriptions.addLongIdentifier("allowEmptyDESC", true); 643 allowEmptyDescriptions.setArgumentGroupName( 644 INFO_VALIDATE_SCHEMA_ARG_GROUP_VALIDATION.get()); 645 parser.addArgument(allowEmptyDescriptions); 646 647 648 // The allowed and prohibited schema element type arguments cannot be used 649 // together. 650 parser.addExclusiveArgumentSet(allowedElementType, prohibitedElementType); 651 } 652 653 654 655 /** 656 * {@inheritDoc} 657 */ 658 @Override() 659 public void doExtendedArgumentValidation() 660 throws ArgumentException 661 { 662 // If the allowed element type argument is present, then validate its 663 // values. 664 if (allowedElementType.isPresent()) 665 { 666 for (final String value : allowedElementType.getValues()) 667 { 668 if (SchemaElementType.forName(value) == null) 669 { 670 final String message = ERR_VALIDATE_SCHEMA_NO_SUCH_ELEMENT_TYPE.get( 671 value, allowedElementType.getIdentifierString()); 672 completionMessage.set(message); 673 throw new ArgumentException(message); 674 } 675 } 676 } 677 678 679 // If the prohibited element type argument is present, then validate its 680 // values, and make sure that not all element types are prohibited. 681 if (prohibitedElementType.isPresent()) 682 { 683 final Set<SchemaElementType> allowedTypes = 684 EnumSet.allOf(SchemaElementType.class); 685 686 for (final String value : prohibitedElementType.getValues()) 687 { 688 final SchemaElementType type = SchemaElementType.forName(value); 689 if (type == null) 690 { 691 final String message = ERR_VALIDATE_SCHEMA_NO_SUCH_ELEMENT_TYPE.get( 692 value, prohibitedElementType.getIdentifierString()); 693 completionMessage.set(message); 694 throw new ArgumentException(message); 695 } 696 else 697 { 698 allowedTypes.remove(type); 699 } 700 } 701 702 if (allowedTypes.isEmpty()) 703 { 704 final String message = 705 ERR_VALIDATE_SCHEMA_ALL_ELEMENT_TYPES_PROHIBITED.get( 706 prohibitedElementType.getIdentifierString()); 707 completionMessage.set(message); 708 throw new ArgumentException(message); 709 } 710 } 711 712 713 if (allowUndefinedElementType.isPresent()) 714 { 715 for (final String value : allowUndefinedElementType.getValues()) 716 { 717 if (SchemaElementType.forName(value) == null) 718 { 719 final String message = ERR_VALIDATE_SCHEMA_NO_SUCH_ELEMENT_TYPE.get( 720 value, allowUndefinedElementType.getIdentifierString()); 721 completionMessage.set(message); 722 throw new ArgumentException(message); 723 } 724 } 725 } 726 } 727 728 729 730 /** 731 * {@inheritDoc} 732 */ 733 @Override() 734 @NotNull() 735 public ResultCode doToolProcessing() 736 { 737 // Create the schema validator instance. 738 final SchemaValidator schemaValidator = new SchemaValidator(); 739 740 schemaValidator.setEnsureSchemaEntryIsValid(true); 741 schemaValidator.setAllowInvalidObjectClassInheritance(false); 742 schemaValidator.setAllowCollectiveAttributes(true); 743 schemaValidator.setAllowObsoleteElements(true); 744 745 schemaValidator.setAllowMultipleEntriesPerFile( 746 allowMultipleEntriesPerSchemaFile.isPresent()); 747 schemaValidator.setAllowSchemaFilesInSubDirectories( 748 allowSchemaFilesInSubdirectories.isPresent()); 749 schemaValidator.setAllowRedefiningElements( 750 allowRedefiningElements.isPresent()); 751 schemaValidator.setAllowElementsWithoutNames( 752 allowElementsWithoutNames.isPresent()); 753 schemaValidator.setOIDValidation( 754 allowNonNumericOIDs.isPresent(), 755 allowNonNumericOIDs.isPresent(), 756 (! useLenientOIDValidation.isPresent())); 757 schemaValidator.setAllowNamesWithInitialDigit( 758 useLenientNameValidation.isPresent()); 759 schemaValidator.setAllowNamesWithInitialHyphen( 760 useLenientNameValidation.isPresent()); 761 schemaValidator.setAllowNamesWithUnderscore( 762 useLenientNameValidation.isPresent()); 763 schemaValidator.setAllowEmptyDescription( 764 allowEmptyDescriptions.isPresent()); 765 schemaValidator.setAllowAttributeTypesWithoutSyntax( 766 allowAttributeTypesWithoutSyntax.isPresent()); 767 schemaValidator.setAllowAttributeTypesWithoutEqualityMatchingRule( 768 ! rejectAttributeTypesWithoutEqualityMatchingRule.isPresent()); 769 schemaValidator.setAllowStructuralObjectClassWithoutSuperior( 770 allowStructuralObjectClassesWithoutSuperior.isPresent()); 771 schemaValidator.setAllowMultipleSuperiorObjectClasses( 772 ! rejectObjectClassesWithMultipleSuperiors.isPresent()); 773 774 if (allowedElementType.isPresent()) 775 { 776 final Set<SchemaElementType> allowedTypes = 777 EnumSet.noneOf(SchemaElementType.class); 778 for (final String value : allowedElementType.getValues()) 779 { 780 allowedTypes.add(SchemaElementType.forName(value)); 781 } 782 783 schemaValidator.setAllowedSchemaElementTypes(allowedTypes); 784 } 785 else if (prohibitedElementType.isPresent()) 786 { 787 final Set<SchemaElementType> allowedTypes = 788 EnumSet.allOf(SchemaElementType.class); 789 for (final String value : prohibitedElementType.getValues()) 790 { 791 allowedTypes.remove(SchemaElementType.forName(value)); 792 } 793 794 schemaValidator.setAllowedSchemaElementTypes(allowedTypes); 795 } 796 797 if (allowUndefinedElementType.isPresent()) 798 { 799 final Set<SchemaElementType> elementTypes = 800 EnumSet.noneOf(SchemaElementType.class); 801 for (final String value : allowUndefinedElementType.getValues()) 802 { 803 elementTypes.add(SchemaElementType.forName(value)); 804 } 805 806 schemaValidator.setAllowReferencesToUndefinedElementTypes(elementTypes); 807 } 808 809 810 // Use the schema validator to parse the scheme elements in the provided 811 // paths. 812 Schema schema = null; 813 final List<String> errorMessages = new ArrayList<>(); 814 for (final File f : schemaPath.getValues()) 815 { 816 schema = schemaValidator.validateSchema(f, schema, errorMessages); 817 } 818 819 820 // If we ended up with an empty set of error messages, then return a success 821 // result. 822 final int numErrors = errorMessages.size(); 823 if (numErrors == 0) 824 { 825 completionMessage.set(INFO_VALIDATE_SCHEMA_NO_ERRORS.get()); 826 wrapOut(0, WRAP_COLUMN, INFO_VALIDATE_SCHEMA_NO_ERRORS.get()); 827 return ResultCode.SUCCESS; 828 } 829 830 831 // If we've gotten here, then there were errors. Display them and get the 832 // final string to use as the completion message. 833 final String finalMessage; 834 if (numErrors == 1) 835 { 836 wrapErr(0, WRAP_COLUMN, ERR_VALIDATE_SCHEMA_ERROR_FOUND.get()); 837 finalMessage = ERR_VALIDATE_SCHEMA_ONE_ERROR.get(); 838 } 839 else 840 { 841 wrapErr(0, WRAP_COLUMN, ERR_VALIDATE_SCHEMA_ERRORS_FOUND.get()); 842 finalMessage = ERR_VALIDATE_SCHEMA_MULTIPLE_ERRORS.get(numErrors); 843 } 844 845 for (final String errorMessage : errorMessages) 846 { 847 err(); 848 849 boolean firstLine = true; 850 for (final String line : 851 StaticUtils.wrapLine(errorMessage, (WRAP_COLUMN - 2))) 852 { 853 if (firstLine) 854 { 855 err("* " + line); 856 firstLine = false; 857 } 858 else 859 { 860 err(" " + line); 861 } 862 } 863 } 864 865 completionMessage.set(finalMessage); 866 867 err(); 868 wrapErr(0, WRAP_COLUMN, finalMessage); 869 870 return ResultCode.DECODING_ERROR; 871 } 872 873 874 875 /** 876 * {@inheritDoc} 877 */ 878 @Override() 879 @NotNull() 880 public LinkedHashMap<String[],String> getExampleUsages() 881 { 882 final LinkedHashMap<String[],String> examples = new LinkedHashMap<>(); 883 884 examples.put( 885 new String[] 886 { 887 "--schema-path", "/path/to/schema" 888 }, 889 INFO_VALIDATE_SCHEMA_EXAMPLE_1.get()); 890 891 examples.put( 892 new String[] 893 { 894 "--schema-path", "/path/to/schema", 895 "--allow-multiple-entries-per-schema-file", 896 "--allow-schema-files-in-subdirectories", 897 "--allow-redefining-elements", 898 "--allow-undefined-element-type", "attribute-syntax", 899 "--allow-undefined-element-type", "matching-rule", 900 "--use-lenient-oid-validation", 901 "--allow-non-numeric-oids", 902 "--allow-elements-without-names", 903 "--use-lenient-name-validation", 904 "--allow-attribute-types-without-syntax", 905 "--allow-structural-object-classes-without-superior", 906 "--allow-empty-descriptions" 907 }, 908 INFO_VALIDATE_SCHEMA_EXAMPLE_2.get()); 909 910 return examples; 911 } 912}