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 logToolInvocationByDefault() 267 { 268 return false; 269 } 270 271 272 273 /** 274 * {@inheritDoc} 275 */ 276 @Override() 277 @Nullable() 278 protected String getToolCompletionMessage() 279 { 280 return completionMessage.get(); 281 } 282 283 284 285 /** 286 * {@inheritDoc} 287 */ 288 @Override() 289 public void addToolArguments(@NotNull final ArgumentParser parser) 290 throws ArgumentException 291 { 292 final boolean pingIdentityDSAvailable = 293 SchemaValidator.PING_IDENTITY_DIRECTORY_SERVER_AVAILABLE; 294 295 296 final List<File> defaultSchemaPaths = new ArrayList<>(1); 297 if (pingIdentityDSAvailable && 298 (SchemaValidator.PING_IDENTITY_DIRECTORY_SERVER_SCHEMA_DIR != null)) 299 { 300 defaultSchemaPaths.add( 301 SchemaValidator.PING_IDENTITY_DIRECTORY_SERVER_SCHEMA_DIR); 302 } 303 304 schemaPath = new FileArgument(null, "schema-path", true, 0, null, 305 INFO_VALIDATE_SCHEMA_ARG_DESC_SCHEMA_PATH.get(), true, true, false, 306 false, defaultSchemaPaths); 307 schemaPath.addLongIdentifier("schemaPath", true); 308 schemaPath.addLongIdentifier("schema-file", true); 309 schemaPath.addLongIdentifier("schemaFile", true); 310 schemaPath.addLongIdentifier("schema-directory", true); 311 schemaPath.addLongIdentifier("schemaDirectory", true); 312 schemaPath.addLongIdentifier("schema-dir", true); 313 schemaPath.addLongIdentifier("schemaDir", true); 314 schemaPath.addLongIdentifier("file", true); 315 schemaPath.addLongIdentifier("directory", true); 316 schemaPath.addLongIdentifier("path", true); 317 schemaPath.setArgumentGroupName(INFO_VALIDATE_SCHEMA_ARG_GROUP_INPUT.get()); 318 parser.addArgument(schemaPath); 319 320 321 allowMultipleEntriesPerSchemaFile = new BooleanArgument(null, 322 "allow-multiple-entries-per-schema-file", 1, 323 INFO_VALIDATE_SCHEMA_ARG_DESC_ALLOW_MULTIPLE_ENTRIES.get()); 324 allowMultipleEntriesPerSchemaFile.addLongIdentifier( 325 "allowMultipleEntriesPerSchemaFile", true); 326 allowMultipleEntriesPerSchemaFile.setArgumentGroupName( 327 INFO_VALIDATE_SCHEMA_ARG_GROUP_INPUT.get()); 328 parser.addArgument(allowMultipleEntriesPerSchemaFile); 329 330 331 allowSchemaFilesInSubdirectories = new BooleanArgument(null, 332 "allow-schema-files-in-subdirectories", 1, 333 INFO_VALIDATE_SCHEMA_ARG_DESC_ALLOW_SUB_DIRS.get()); 334 allowSchemaFilesInSubdirectories.addLongIdentifier( 335 "allow-schema-files-in-sub-directories", true); 336 allowSchemaFilesInSubdirectories.addLongIdentifier( 337 "allowSchemaFilesInSubDirectories", true); 338 allowSchemaFilesInSubdirectories.setArgumentGroupName( 339 INFO_VALIDATE_SCHEMA_ARG_GROUP_INPUT.get()); 340 parser.addArgument(allowSchemaFilesInSubdirectories); 341 342 343 allowedElementType = new StringArgument(null, "allowed-element-type", false, 344 0, INFO_VALIDATE_SCHEMA_ARG_PLACEHOLDER_ELEMENT_TYPE.get(), 345 INFO_VALIDATE_SCHEMA_ARG_DESC_ALLOWED_ELEMENT_TYPE.get()); 346 allowedElementType.addLongIdentifier("allowedElementType", true); 347 allowedElementType.addLongIdentifier("allowed-schema-element-type", true); 348 allowedElementType.addLongIdentifier("allowedSchemaElementType", true); 349 allowedElementType.addLongIdentifier("allow-element-type", true); 350 allowedElementType.addLongIdentifier("allowElementType", true); 351 allowedElementType.addLongIdentifier("allow-schema-element-type", true); 352 allowedElementType.addLongIdentifier("allowSchemaElementType", true); 353 allowedElementType.addLongIdentifier("allowed-element", true); 354 allowedElementType.addLongIdentifier("allowedElement", true); 355 allowedElementType.addLongIdentifier("allow-element", true); 356 allowedElementType.addLongIdentifier("allowElement", true); 357 allowedElementType.setArgumentGroupName( 358 INFO_VALIDATE_SCHEMA_ARG_GROUP_VALIDATION.get()); 359 parser.addArgument(allowedElementType); 360 361 362 prohibitedElementType = new StringArgument(null, "prohibited-element-type", 363 false, 0, INFO_VALIDATE_SCHEMA_ARG_PLACEHOLDER_ELEMENT_TYPE.get(), 364 INFO_VALIDATE_SCHEMA_ARG_DESC_PROHIBITED_ELEMENT_TYPE.get()); 365 prohibitedElementType.addLongIdentifier("prohibitedElementType", true); 366 prohibitedElementType.addLongIdentifier("prohibited-schema-element-type", 367 true); 368 prohibitedElementType.addLongIdentifier("prohibitedSchemaElementType", 369 true); 370 prohibitedElementType.addLongIdentifier("prohibit-element-type", true); 371 prohibitedElementType.addLongIdentifier("prohibitElementType", true); 372 prohibitedElementType.addLongIdentifier("prohibit-schema-element-type", 373 true); 374 prohibitedElementType.addLongIdentifier("prohibitSchemaElementType", true); 375 prohibitedElementType.addLongIdentifier("prohibited-element", true); 376 prohibitedElementType.addLongIdentifier("prohibitedElement", true); 377 prohibitedElementType.addLongIdentifier("prohibit-element", true); 378 prohibitedElementType.addLongIdentifier("prohibitElement", true); 379 prohibitedElementType.setArgumentGroupName( 380 INFO_VALIDATE_SCHEMA_ARG_GROUP_VALIDATION.get()); 381 parser.addArgument(prohibitedElementType); 382 383 384 allowRedefiningElements = new BooleanArgument(null, 385 "allow-redefining-elements", 1, 386 INFO_VALIDATE_SCHEMA_ARG_DESC_ALLOW_REDEFINING.get()); 387 allowRedefiningElements.addLongIdentifier( 388 "allow-re-defining-elements", true); 389 allowRedefiningElements.addLongIdentifier( 390 "allowRedefiningElements", true); 391 allowRedefiningElements.addLongIdentifier( 392 "allow-redefining-schema-elements", true); 393 allowRedefiningElements.addLongIdentifier( 394 "allow-re-defining-schema-elements", true); 395 allowRedefiningElements.addLongIdentifier( 396 "allowRedefiningSchemaElements", true); 397 allowRedefiningElements.setArgumentGroupName( 398 INFO_VALIDATE_SCHEMA_ARG_GROUP_VALIDATION.get()); 399 parser.addArgument(allowRedefiningElements); 400 401 402 allowUndefinedElementType = new StringArgument(null, 403 "allow-undefined-element-type", false, 0, 404 INFO_VALIDATE_SCHEMA_ARG_PLACEHOLDER_ELEMENT_TYPE.get(), 405 INFO_VALIDATE_SCHEMA_ARG_DESC_ALLOW_UNDEFINED.get()); 406 allowUndefinedElementType.addLongIdentifier("allowUndefinedElementType", 407 true); 408 allowUndefinedElementType.addLongIdentifier( 409 "allow-undefined-schema-element-type", true); 410 allowUndefinedElementType.addLongIdentifier( 411 "allowUndefinedSchemaElementType", true); 412 allowUndefinedElementType.addLongIdentifier( 413 "allowed-undefined-element-type", true); 414 allowUndefinedElementType.addLongIdentifier("allowedUndefinedElementType", 415 true); 416 allowUndefinedElementType.addLongIdentifier( 417 "allowed-undefined-schema-element-type", true); 418 allowUndefinedElementType.addLongIdentifier( 419 "allowedUndefinedSchemaElementType", true); 420 allowUndefinedElementType.addLongIdentifier("allow-undefined-element", 421 true); 422 allowUndefinedElementType.addLongIdentifier("allowUndefinedType", true); 423 allowUndefinedElementType.addLongIdentifier("allow-undefined-type", true); 424 allowUndefinedElementType.addLongIdentifier("allowUndefinedElement", true); 425 allowUndefinedElementType.addLongIdentifier("allowed-undefined-element", 426 true); 427 allowUndefinedElementType.addLongIdentifier("allowedUndefinedType", true); 428 allowUndefinedElementType.addLongIdentifier("allowed-undefined-type", true); 429 allowUndefinedElementType.addLongIdentifier("allowedUndefinedElement", 430 true); 431 allowUndefinedElementType.setArgumentGroupName( 432 INFO_VALIDATE_SCHEMA_ARG_GROUP_VALIDATION.get()); 433 parser.addArgument(allowUndefinedElementType); 434 435 436 useLenientOIDValidation = new BooleanArgument(null, 437 "use-lenient-oid-validation", 1, 438 INFO_VALIDATE_SCHEMA_ARG_DESC_LENIENT_OID.get()); 439 useLenientOIDValidation.addLongIdentifier( 440 "useLenientOIDValidation", true); 441 useLenientOIDValidation.addLongIdentifier( 442 "allow-lenient-oid-validation", true); 443 useLenientOIDValidation.addLongIdentifier( 444 "allowLenientOIDValidation", true); 445 useLenientOIDValidation.addLongIdentifier( 446 "lenient-oid-validation", true); 447 useLenientOIDValidation.addLongIdentifier( 448 "lenientOIDValidation", true); 449 useLenientOIDValidation.setArgumentGroupName( 450 INFO_VALIDATE_SCHEMA_ARG_GROUP_VALIDATION.get()); 451 parser.addArgument(useLenientOIDValidation); 452 453 454 allowNonNumericOIDs = new BooleanArgument(null, "allow-non-numeric-oids", 455 1, INFO_VALIDATE_SCHEMA_ARG_DESC_ALLOW_NON_NUMERIC_OID.get()); 456 allowNonNumericOIDs.addLongIdentifier("allow-nonnumeric-oids", true); 457 allowNonNumericOIDs.addLongIdentifier("allowNonNumericOIDs", true); 458 allowNonNumericOIDs.addLongIdentifier("allow-non-numeric-oid", true); 459 allowNonNumericOIDs.addLongIdentifier("allow-nonnumeric-oid", true); 460 allowNonNumericOIDs.addLongIdentifier("allowNonNumericOID", true); 461 allowNonNumericOIDs.setArgumentGroupName( 462 INFO_VALIDATE_SCHEMA_ARG_GROUP_VALIDATION.get()); 463 parser.addArgument(allowNonNumericOIDs); 464 465 466 allowElementsWithoutNames = new BooleanArgument(null, 467 "allow-elements-without-names", 1, 468 INFO_VALIDATE_SCHEMA_ARG_DESC_ALLOW_MISSING_NAME.get()); 469 allowElementsWithoutNames.addLongIdentifier("allowElementsWithoutNames", 470 true); 471 allowElementsWithoutNames.addLongIdentifier( 472 "allow-schema-elements-without-names", true); 473 allowElementsWithoutNames.addLongIdentifier( 474 "allowSchemaElementsWithoutNames", true); 475 allowElementsWithoutNames.addLongIdentifier("allow-elements-missing-names", 476 true); 477 allowElementsWithoutNames.addLongIdentifier("allowElementsMissingNames", 478 true); 479 allowElementsWithoutNames.addLongIdentifier( 480 "allow-schema-elements-missing-names", true); 481 allowElementsWithoutNames.addLongIdentifier( 482 "allowSchemaElementsMissingNames", true); 483 allowElementsWithoutNames.addLongIdentifier("allow-missing-names", 484 true); 485 allowElementsWithoutNames.addLongIdentifier("allowEMissingNames", 486 true); 487 allowElementsWithoutNames.setArgumentGroupName( 488 INFO_VALIDATE_SCHEMA_ARG_GROUP_VALIDATION.get()); 489 parser.addArgument(allowElementsWithoutNames); 490 491 492 useLenientNameValidation = new BooleanArgument(null, 493 "use-lenient-name-validation", 1, 494 INFO_VALIDATE_SCHEMA_ARG_DESC_LENIENT_NAMES.get()); 495 useLenientNameValidation.addLongIdentifier("useLenientNameValidation", 496 true); 497 useLenientNameValidation.addLongIdentifier("allow-lenient-name-validation", 498 true); 499 useLenientNameValidation.addLongIdentifier("allowLenientNameValidation", 500 true); 501 useLenientNameValidation.addLongIdentifier("lenient-name-validation", true); 502 useLenientNameValidation.addLongIdentifier("lenientNameValidation", true); 503 useLenientNameValidation.setArgumentGroupName( 504 INFO_VALIDATE_SCHEMA_ARG_GROUP_VALIDATION.get()); 505 parser.addArgument(useLenientNameValidation); 506 507 508 allowAttributeTypesWithoutSyntax = new BooleanArgument(null, 509 "allow-attribute-types-without-syntax", 1, 510 INFO_VALIDATE_SCHEMA_ARG_DESC_ALLOW_AT_WITHOUT_SYNTAX.get()); 511 allowAttributeTypesWithoutSyntax.addLongIdentifier( 512 "allowAttributeTypesWithoutSyntax", true); 513 allowAttributeTypesWithoutSyntax.addLongIdentifier( 514 "allow-attribute-type-without-syntax", true); 515 allowAttributeTypesWithoutSyntax.addLongIdentifier( 516 "allowAttributeTypeWithoutSyntax", true); 517 allowAttributeTypesWithoutSyntax.addLongIdentifier( 518 "allow-attribute-types-missing-Syntax", true); 519 allowAttributeTypesWithoutSyntax.addLongIdentifier( 520 "allowAttributeTypesMissingSyntax", true); 521 allowAttributeTypesWithoutSyntax.addLongIdentifier( 522 "allow-attribute-type-missing-syntax", true); 523 allowAttributeTypesWithoutSyntax.addLongIdentifier( 524 "allowAttributeTypeMissingSyntax", true); 525 allowAttributeTypesWithoutSyntax.setArgumentGroupName( 526 INFO_VALIDATE_SCHEMA_ARG_GROUP_VALIDATION.get()); 527 parser.addArgument(allowAttributeTypesWithoutSyntax); 528 529 530 rejectAttributeTypesWithoutEqualityMatchingRule = new BooleanArgument(null, 531 "reject-attribute-types-without-equality-matching-rule", 1, 532 INFO_VALIDATE_SCHEMA_ARG_DESC_REJECT_AT_WITHOUT_EQ_MR.get()); 533 rejectAttributeTypesWithoutEqualityMatchingRule.addLongIdentifier( 534 "rejectAttributeTypesWithoutEqualityMatchingRule", true); 535 rejectAttributeTypesWithoutEqualityMatchingRule.addLongIdentifier( 536 "reject-attribute-type-without-equality-matching-rule", true); 537 rejectAttributeTypesWithoutEqualityMatchingRule.addLongIdentifier( 538 "rejectAttributeTypeWithoutEqualityMatchingRule", true); 539 rejectAttributeTypesWithoutEqualityMatchingRule.addLongIdentifier( 540 "reject-attribute-types-missing-equality-matching-rule", true); 541 rejectAttributeTypesWithoutEqualityMatchingRule.addLongIdentifier( 542 "rejectAttributeTypesMissingEqualityMatchingRule", true); 543 rejectAttributeTypesWithoutEqualityMatchingRule.addLongIdentifier( 544 "reject-attribute-type-missing-equality-matching-rule", true); 545 rejectAttributeTypesWithoutEqualityMatchingRule.addLongIdentifier( 546 "rejectAttributeTypeMissingEqualityMatchingRule", true); 547 rejectAttributeTypesWithoutEqualityMatchingRule.setArgumentGroupName( 548 INFO_VALIDATE_SCHEMA_ARG_GROUP_VALIDATION.get()); 549 parser.addArgument(rejectAttributeTypesWithoutEqualityMatchingRule); 550 551 552 allowStructuralObjectClassesWithoutSuperior = new BooleanArgument(null, 553 "allow-structural-object-classes-without-superior", 1, 554 INFO_VALIDATE_SCHEMA_ARG_DESC_ALLOW_MISSING_MISSING_OC_SUP.get()); 555 allowStructuralObjectClassesWithoutSuperior.addLongIdentifier( 556 "allow-structural-objectclasses-without-superior", true); 557 allowStructuralObjectClassesWithoutSuperior.addLongIdentifier( 558 "allowStructuralObjectClassesWithoutSuperior", true); 559 allowStructuralObjectClassesWithoutSuperior.addLongIdentifier( 560 "allow-structural-object-class-without-superior", true); 561 allowStructuralObjectClassesWithoutSuperior.addLongIdentifier( 562 "allow-structural-objectclass-without-superior", true); 563 allowStructuralObjectClassesWithoutSuperior.addLongIdentifier( 564 "allowStructuralObjectClassWithoutSuperior", true); 565 allowStructuralObjectClassesWithoutSuperior.addLongIdentifier( 566 "allow-structural-classes-without-superior", true); 567 allowStructuralObjectClassesWithoutSuperior.addLongIdentifier( 568 "allowStructuralClassesWithoutSuperior", true); 569 allowStructuralObjectClassesWithoutSuperior.addLongIdentifier( 570 "allow-structural-class-without-superior", true); 571 allowStructuralObjectClassesWithoutSuperior.addLongIdentifier( 572 "allowStructuralClassWithoutSuperior", true); 573 allowStructuralObjectClassesWithoutSuperior.addLongIdentifier( 574 "allow-object-classes-without-superior", true); 575 allowStructuralObjectClassesWithoutSuperior.addLongIdentifier( 576 "allow-objectclasses-without-superior", true); 577 allowStructuralObjectClassesWithoutSuperior.addLongIdentifier( 578 "allowObjectClassesWithoutSuperior", true); 579 allowStructuralObjectClassesWithoutSuperior.addLongIdentifier( 580 "allow-object-class-without-superior", true); 581 allowStructuralObjectClassesWithoutSuperior.addLongIdentifier( 582 "allow-objectclass-without-superior", true); 583 allowStructuralObjectClassesWithoutSuperior.addLongIdentifier( 584 "allowObjectClassWithoutSuperior", true); 585 allowStructuralObjectClassesWithoutSuperior.setArgumentGroupName( 586 INFO_VALIDATE_SCHEMA_ARG_GROUP_VALIDATION.get()); 587 parser.addArgument(allowStructuralObjectClassesWithoutSuperior); 588 589 590 rejectObjectClassesWithMultipleSuperiors = new BooleanArgument(null, 591 "reject-object-classes-with-multiple-superiors", 1, 592 INFO_VALIDATE_SCHEMA_ARG_DESC_REJECT_MULTIPLE_OC_SUP.get()); 593 rejectObjectClassesWithMultipleSuperiors.addLongIdentifier( 594 "reject-objectclasses-with-multiple-superiors", true); 595 rejectObjectClassesWithMultipleSuperiors.addLongIdentifier( 596 "rejectObjectClassesWithMultipleSuperiors", true); 597 rejectObjectClassesWithMultipleSuperiors.addLongIdentifier( 598 "reject-object-class-with-multiple-superiors", true); 599 rejectObjectClassesWithMultipleSuperiors.addLongIdentifier( 600 "reject-objectclass-with-multiple-superiors", true); 601 rejectObjectClassesWithMultipleSuperiors.addLongIdentifier( 602 "rejectObjectClassWithMultipleSuperiors", true); 603 rejectObjectClassesWithMultipleSuperiors.addLongIdentifier( 604 "reject-object-classes-with-multiple-superior-classes", true); 605 rejectObjectClassesWithMultipleSuperiors.addLongIdentifier( 606 "reject-objectclasses-with-multiple-superior-classes", true); 607 rejectObjectClassesWithMultipleSuperiors.addLongIdentifier( 608 "rejectObjectClassesWithMultipleSuperiorClasses", true); 609 rejectObjectClassesWithMultipleSuperiors.addLongIdentifier( 610 "reject-object-class-with-multiple-superior-classes", true); 611 rejectObjectClassesWithMultipleSuperiors.addLongIdentifier( 612 "reject-objectclass-with-multiple-superior-classes", true); 613 rejectObjectClassesWithMultipleSuperiors.addLongIdentifier( 614 "rejectObjectClassWithMultipleSuperiorClasses", true); 615 rejectObjectClassesWithMultipleSuperiors.setArgumentGroupName( 616 INFO_VALIDATE_SCHEMA_ARG_GROUP_VALIDATION.get()); 617 if (pingIdentityDSAvailable) 618 { 619 rejectObjectClassesWithMultipleSuperiors.setHidden(true); 620 } 621 parser.addArgument(rejectObjectClassesWithMultipleSuperiors); 622 623 624 allowEmptyDescriptions = new BooleanArgument(null, 625 "allow-empty-descriptions", 1, 626 INFO_VALIDATE_SCHEMA_ARG_DESC_ALLOW_EMPTY_DESC.get()); 627 allowEmptyDescriptions.addLongIdentifier("allowEmptyDescriptions", true); 628 allowEmptyDescriptions.addLongIdentifier("allow-empty-description", true); 629 allowEmptyDescriptions.addLongIdentifier("allowEmptyDescription", true); 630 allowEmptyDescriptions.addLongIdentifier("allow-empty-desc", true); 631 allowEmptyDescriptions.addLongIdentifier("allowEmptyDESC", true); 632 allowEmptyDescriptions.setArgumentGroupName( 633 INFO_VALIDATE_SCHEMA_ARG_GROUP_VALIDATION.get()); 634 parser.addArgument(allowEmptyDescriptions); 635 636 637 // The allowed and prohibited schema element type arguments cannot be used 638 // together. 639 parser.addExclusiveArgumentSet(allowedElementType, prohibitedElementType); 640 } 641 642 643 644 /** 645 * {@inheritDoc} 646 */ 647 @Override() 648 public void doExtendedArgumentValidation() 649 throws ArgumentException 650 { 651 // If the allowed element type argument is present, then validate its 652 // values. 653 if (allowedElementType.isPresent()) 654 { 655 for (final String value : allowedElementType.getValues()) 656 { 657 if (SchemaElementType.forName(value) == null) 658 { 659 final String message = ERR_VALIDATE_SCHEMA_NO_SUCH_ELEMENT_TYPE.get( 660 value, allowedElementType.getIdentifierString()); 661 completionMessage.set(message); 662 throw new ArgumentException(message); 663 } 664 } 665 } 666 667 668 // If the prohibited element type argument is present, then validate its 669 // values, and make sure that not all element types are prohibited. 670 if (prohibitedElementType.isPresent()) 671 { 672 final Set<SchemaElementType> allowedTypes = 673 EnumSet.allOf(SchemaElementType.class); 674 675 for (final String value : prohibitedElementType.getValues()) 676 { 677 final SchemaElementType type = SchemaElementType.forName(value); 678 if (type == null) 679 { 680 final String message = ERR_VALIDATE_SCHEMA_NO_SUCH_ELEMENT_TYPE.get( 681 value, prohibitedElementType.getIdentifierString()); 682 completionMessage.set(message); 683 throw new ArgumentException(message); 684 } 685 else 686 { 687 allowedTypes.remove(type); 688 } 689 } 690 691 if (allowedTypes.isEmpty()) 692 { 693 final String message = 694 ERR_VALIDATE_SCHEMA_ALL_ELEMENT_TYPES_PROHIBITED.get( 695 prohibitedElementType.getIdentifierString()); 696 completionMessage.set(message); 697 throw new ArgumentException(message); 698 } 699 } 700 701 702 if (allowUndefinedElementType.isPresent()) 703 { 704 for (final String value : allowUndefinedElementType.getValues()) 705 { 706 if (SchemaElementType.forName(value) == null) 707 { 708 final String message = ERR_VALIDATE_SCHEMA_NO_SUCH_ELEMENT_TYPE.get( 709 value, allowUndefinedElementType.getIdentifierString()); 710 completionMessage.set(message); 711 throw new ArgumentException(message); 712 } 713 } 714 } 715 } 716 717 718 719 /** 720 * {@inheritDoc} 721 */ 722 @Override() 723 @NotNull() 724 public ResultCode doToolProcessing() 725 { 726 // Create the schema validator instance. 727 final SchemaValidator schemaValidator = new SchemaValidator(); 728 729 schemaValidator.setEnsureSchemaEntryIsValid(true); 730 schemaValidator.setAllowInvalidObjectClassInheritance(false); 731 schemaValidator.setAllowCollectiveAttributes(true); 732 schemaValidator.setAllowObsoleteElements(true); 733 734 schemaValidator.setAllowMultipleEntriesPerFile( 735 allowMultipleEntriesPerSchemaFile.isPresent()); 736 schemaValidator.setAllowSchemaFilesInSubDirectories( 737 allowSchemaFilesInSubdirectories.isPresent()); 738 schemaValidator.setAllowRedefiningElements( 739 allowRedefiningElements.isPresent()); 740 schemaValidator.setAllowElementsWithoutNames( 741 allowElementsWithoutNames.isPresent()); 742 schemaValidator.setOIDValidation( 743 allowNonNumericOIDs.isPresent(), 744 allowNonNumericOIDs.isPresent(), 745 (! useLenientOIDValidation.isPresent())); 746 schemaValidator.setAllowNamesWithInitialDigit( 747 useLenientNameValidation.isPresent()); 748 schemaValidator.setAllowNamesWithInitialHyphen( 749 useLenientNameValidation.isPresent()); 750 schemaValidator.setAllowNamesWithUnderscore( 751 useLenientNameValidation.isPresent()); 752 schemaValidator.setAllowEmptyDescription( 753 allowEmptyDescriptions.isPresent()); 754 schemaValidator.setAllowAttributeTypesWithoutSyntax( 755 allowAttributeTypesWithoutSyntax.isPresent()); 756 schemaValidator.setAllowAttributeTypesWithoutEqualityMatchingRule( 757 ! rejectAttributeTypesWithoutEqualityMatchingRule.isPresent()); 758 schemaValidator.setAllowStructuralObjectClassWithoutSuperior( 759 allowStructuralObjectClassesWithoutSuperior.isPresent()); 760 schemaValidator.setAllowMultipleSuperiorObjectClasses( 761 ! rejectObjectClassesWithMultipleSuperiors.isPresent()); 762 763 if (allowedElementType.isPresent()) 764 { 765 final Set<SchemaElementType> allowedTypes = 766 EnumSet.noneOf(SchemaElementType.class); 767 for (final String value : allowedElementType.getValues()) 768 { 769 allowedTypes.add(SchemaElementType.forName(value)); 770 } 771 772 schemaValidator.setAllowedSchemaElementTypes(allowedTypes); 773 } 774 else if (prohibitedElementType.isPresent()) 775 { 776 final Set<SchemaElementType> allowedTypes = 777 EnumSet.allOf(SchemaElementType.class); 778 for (final String value : prohibitedElementType.getValues()) 779 { 780 allowedTypes.remove(SchemaElementType.forName(value)); 781 } 782 783 schemaValidator.setAllowedSchemaElementTypes(allowedTypes); 784 } 785 786 if (allowUndefinedElementType.isPresent()) 787 { 788 final Set<SchemaElementType> elementTypes = 789 EnumSet.noneOf(SchemaElementType.class); 790 for (final String value : allowUndefinedElementType.getValues()) 791 { 792 elementTypes.add(SchemaElementType.forName(value)); 793 } 794 795 schemaValidator.setAllowReferencesToUndefinedElementTypes(elementTypes); 796 } 797 798 799 // Use the schema validator to parse the scheme elements in the provided 800 // paths. 801 Schema schema = null; 802 final List<String> errorMessages = new ArrayList<>(); 803 for (final File f : schemaPath.getValues()) 804 { 805 schema = schemaValidator.validateSchema(f, schema, errorMessages); 806 } 807 808 809 // If we ended up with an empty set of error messages, then return a success 810 // result. 811 final int numErrors = errorMessages.size(); 812 if (numErrors == 0) 813 { 814 completionMessage.set(INFO_VALIDATE_SCHEMA_NO_ERRORS.get()); 815 wrapOut(0, WRAP_COLUMN, INFO_VALIDATE_SCHEMA_NO_ERRORS.get()); 816 return ResultCode.SUCCESS; 817 } 818 819 820 // If we've gotten here, then there were errors. Display them and get the 821 // final string to use as the completion message. 822 final String finalMessage; 823 if (numErrors == 1) 824 { 825 wrapErr(0, WRAP_COLUMN, ERR_VALIDATE_SCHEMA_ERROR_FOUND.get()); 826 finalMessage = ERR_VALIDATE_SCHEMA_ONE_ERROR.get(); 827 } 828 else 829 { 830 wrapErr(0, WRAP_COLUMN, ERR_VALIDATE_SCHEMA_ERRORS_FOUND.get()); 831 finalMessage = ERR_VALIDATE_SCHEMA_MULTIPLE_ERRORS.get(numErrors); 832 } 833 834 for (final String errorMessage : errorMessages) 835 { 836 err(); 837 838 boolean firstLine = true; 839 for (final String line : 840 StaticUtils.wrapLine(errorMessage, (WRAP_COLUMN - 2))) 841 { 842 if (firstLine) 843 { 844 err("* " + line); 845 firstLine = false; 846 } 847 else 848 { 849 err(" " + line); 850 } 851 } 852 } 853 854 completionMessage.set(finalMessage); 855 856 err(); 857 wrapErr(0, WRAP_COLUMN, finalMessage); 858 859 return ResultCode.DECODING_ERROR; 860 } 861 862 863 864 /** 865 * {@inheritDoc} 866 */ 867 @Override() 868 @NotNull() 869 public LinkedHashMap<String[],String> getExampleUsages() 870 { 871 final LinkedHashMap<String[],String> examples = new LinkedHashMap<>(); 872 873 examples.put( 874 new String[] 875 { 876 "--schema-path", "/path/to/schema" 877 }, 878 INFO_VALIDATE_SCHEMA_EXAMPLE_1.get()); 879 880 examples.put( 881 new String[] 882 { 883 "--schema-path", "/path/to/schema", 884 "--allow-multiple-entries-per-schema-file", 885 "--allow-schema-files-in-subdirectories", 886 "--allow-redefining-elements", 887 "--allow-undefined-element-type", "attribute-syntax", 888 "--allow-undefined-element-type", "matching-rule", 889 "--use-lenient-oid-validation", 890 "--allow-non-numeric-oids", 891 "--allow-elements-without-names", 892 "--use-lenient-name-validation", 893 "--allow-attribute-types-without-syntax", 894 "--allow-structural-object-classes-without-superior", 895 "--allow-empty-descriptions" 896 }, 897 INFO_VALIDATE_SCHEMA_EXAMPLE_2.get()); 898 899 return examples; 900 } 901}