001/* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2008-2010 Sun Microsystems, Inc. 025 * Portions Copyright 2014 ForgeRock AS 026 */ 027package org.forgerock.opendj.config.dsconfig; 028 029import static com.forgerock.opendj.dsconfig.DsconfigMessages.*; 030 031import org.forgerock.i18n.LocalizableMessage; 032import org.forgerock.opendj.config.AbstractManagedObjectDefinition; 033import org.forgerock.opendj.config.ManagedObjectDefinition; 034import org.forgerock.opendj.config.PropertyDefinition; 035import org.forgerock.opendj.config.PropertyDefinitionUsageBuilder; 036import org.forgerock.opendj.config.PropertyException; 037import org.forgerock.opendj.config.RelationDefinition; 038import org.forgerock.opendj.config.client.IllegalManagedObjectNameException; 039import org.forgerock.opendj.config.client.ManagedObjectDecodingException; 040import org.forgerock.opendj.config.client.MissingMandatoryPropertiesException; 041import org.forgerock.opendj.config.client.OperationRejectedException; 042 043import com.forgerock.opendj.cli.Argument; 044import com.forgerock.opendj.cli.ArgumentException; 045import com.forgerock.opendj.cli.ClientException; 046import com.forgerock.opendj.cli.ConsoleApplication; 047import com.forgerock.opendj.cli.ReturnCode; 048import com.forgerock.opendj.cli.TableBuilder; 049import com.forgerock.opendj.cli.TextTablePrinter; 050 051/** 052 * A utility class for converting various admin exception types into argument exceptions. 053 */ 054public final class ArgumentExceptionFactory { 055 056 /** 057 * Creates a ClientException exception from an illegal managed object name exception. 058 * 059 * @param e 060 * The illegal managed object name exception. 061 * @param d 062 * The managed object definition. 063 * @return Returns a ClientException exception. 064 */ 065 public static ClientException adaptIllegalManagedObjectNameException(IllegalManagedObjectNameException e, 066 AbstractManagedObjectDefinition<?, ?> d) { 067 String illegalName = e.getIllegalName(); 068 PropertyDefinition<?> pd = e.getNamingPropertyDefinition(); 069 070 if (illegalName.length() == 0) { 071 LocalizableMessage message = ERR_DSCFG_ERROR_ILLEGAL_NAME_EMPTY.get(d.getUserFriendlyPluralName()); 072 return new ClientException(ReturnCode.ERROR_USER_DATA, message); 073 } else if (illegalName.trim().length() == 0) { 074 LocalizableMessage message = ERR_DSCFG_ERROR_ILLEGAL_NAME_BLANK.get(d.getUserFriendlyPluralName()); 075 return new ClientException(ReturnCode.ERROR_USER_DATA, message); 076 } else if (pd != null) { 077 try { 078 pd.decodeValue(illegalName); 079 } catch (PropertyException e1) { 080 PropertyDefinitionUsageBuilder b = new PropertyDefinitionUsageBuilder(true); 081 LocalizableMessage syntax = b.getUsage(pd); 082 083 LocalizableMessage message = ERR_DSCFG_ERROR_ILLEGAL_NAME_SYNTAX.get(illegalName, 084 d.getUserFriendlyName(), syntax); 085 return new ClientException(ReturnCode.ERROR_USER_DATA, message); 086 } 087 } 088 089 LocalizableMessage message = ERR_DSCFG_ERROR_ILLEGAL_NAME_UNKNOWN.get(illegalName, d.getUserFriendlyName()); 090 return new ClientException(ReturnCode.ERROR_USER_DATA, message); 091 } 092 093 /** 094 * Creates an argument exception from a property exception. 095 * 096 * @param e 097 * The property exception. 098 * @param d 099 * The managed object definition. 100 * @return Returns an argument exception. 101 */ 102 public static ArgumentException adaptPropertyException(PropertyException e, 103 AbstractManagedObjectDefinition<?, ?> d) { 104 return new ArgumentException(e.getMessageObject()); 105 } 106 107 /** 108 * Displays a table listing reasons why a managed object could not be decoded successfully. 109 * 110 * @param app 111 * The console application. 112 * @param e 113 * The managed object decoding exception. 114 */ 115 public static void displayManagedObjectDecodingException(ConsoleApplication app, ManagedObjectDecodingException e) { 116 AbstractManagedObjectDefinition<?, ?> d = e.getPartialManagedObject().getManagedObjectDefinition(); 117 LocalizableMessage ufn = d.getUserFriendlyName(); 118 LocalizableMessage msg = e.getCauses().size() == 1 ? ERR_GET_HEADING_MODE_SINGLE.get(ufn) 119 : ERR_GET_HEADING_MODE_PLURAL.get(ufn); 120 app.errPrintln(msg); 121 app.errPrintln(); 122 TableBuilder builder = new TableBuilder(); 123 for (PropertyException pe : e.getCauses()) { 124 ArgumentException ae = adaptPropertyException(pe, d); 125 builder.startRow(); 126 builder.appendCell("*"); 127 builder.appendCell(ae.getMessage()); 128 } 129 130 TextTablePrinter printer = new TextTablePrinter(app.getErrorStream()); 131 printer.setDisplayHeadings(false); 132 printer.setColumnWidth(1, 0); 133 printer.setIndentWidth(4); 134 builder.print(printer); 135 } 136 137 /** 138 * Displays a table listing missing mandatory properties. 139 * 140 * @param app 141 * The console application. 142 * @param e 143 * The missing mandatory property exception. 144 */ 145 public static void displayMissingMandatoryPropertyException(ConsoleApplication app, 146 MissingMandatoryPropertiesException e) { 147 LocalizableMessage ufn = e.getUserFriendlyName(); 148 LocalizableMessage msg; 149 final boolean onePropertyMissing = e.getCauses().size() == 1; 150 if (e.isCreate()) { 151 msg = onePropertyMissing ? ERR_CREATE_HEADING_MMPE_SINGLE.get(ufn) 152 : ERR_CREATE_HEADING_MMPE_PLURAL.get(ufn); 153 } else { 154 msg = onePropertyMissing ? ERR_MODIFY_HEADING_MMPE_SINGLE.get(ufn) 155 : ERR_MODIFY_HEADING_MMPE_PLURAL.get(ufn); 156 } 157 158 app.errPrintln(msg); 159 app.errPrintln(); 160 TableBuilder builder = new TableBuilder(); 161 builder.addSortKey(0); 162 builder.appendHeading(INFO_DSCFG_HEADING_PROPERTY_NAME.get()); 163 builder.appendHeading(INFO_DSCFG_HEADING_PROPERTY_SYNTAX.get()); 164 165 PropertyDefinitionUsageBuilder b = new PropertyDefinitionUsageBuilder(true); 166 for (PropertyException pe : e.getCauses()) { 167 PropertyDefinition<?> pd = pe.getPropertyDefinition(); 168 builder.startRow(); 169 builder.appendCell(pd.getName()); 170 builder.appendCell(b.getUsage(pd)); 171 } 172 173 TextTablePrinter printer = new TextTablePrinter(app.getErrorStream()); 174 printer.setDisplayHeadings(true); 175 printer.setColumnWidth(1, 0); 176 printer.setIndentWidth(4); 177 builder.print(printer); 178 } 179 180 /** 181 * Displays a table listing the reasons why an operation was rejected. 182 * 183 * @param app 184 * The console application. 185 * @param e 186 * The operation rejected exception. 187 */ 188 public static void displayOperationRejectedException(ConsoleApplication app, OperationRejectedException e) { 189 LocalizableMessage ufn = e.getUserFriendlyName(); 190 LocalizableMessage msg; 191 final boolean singleMessage = e.getMessages().size() == 1; 192 193 switch (e.getOperationType()) { 194 case CREATE: 195 msg = singleMessage ? ERR_DSCFG_ERROR_CREATE_ORE_SINGLE.get(ufn) 196 : ERR_DSCFG_ERROR_CREATE_ORE_PLURAL.get(ufn); 197 break; 198 case DELETE: 199 msg = singleMessage ? ERR_DSCFG_ERROR_DELETE_ORE_SINGLE.get(ufn) 200 : ERR_DSCFG_ERROR_DELETE_ORE_PLURAL.get(ufn); 201 break; 202 default: 203 msg = singleMessage ? ERR_DSCFG_ERROR_MODIFY_ORE_SINGLE.get(ufn) 204 : ERR_DSCFG_ERROR_MODIFY_ORE_PLURAL.get(ufn); 205 break; 206 } 207 208 app.errPrintln(msg); 209 app.errPrintln(); 210 TableBuilder builder = new TableBuilder(); 211 for (LocalizableMessage reason : e.getMessages()) { 212 builder.startRow(); 213 builder.appendCell("*"); 214 builder.appendCell(reason); 215 } 216 TextTablePrinter printer = new TextTablePrinter(app.getErrorStream()); 217 printer.setDisplayHeadings(false); 218 printer.setColumnWidth(1, 0); 219 printer.setIndentWidth(4); 220 builder.print(printer); 221 } 222 223 /** 224 * Creates an argument exception which should be used when a property modification argument is incompatible with a 225 * previous modification argument. 226 * 227 * @param arg 228 * The incompatible argument. 229 * @return Returns an argument exception. 230 */ 231 public static ArgumentException incompatiblePropertyModification(String arg) { 232 LocalizableMessage msg = ERR_DSCFG_ERROR_INCOMPATIBLE_PROPERTY_MOD.get(arg); 233 return new ArgumentException(msg); 234 } 235 236 /** 237 * Creates an argument exception which should be used when the client has not specified a bind password. 238 * 239 * @param bindDN 240 * The name of the user requiring a password. 241 * @return Returns an argument exception. 242 */ 243 public static ArgumentException missingBindPassword(String bindDN) { 244 LocalizableMessage msg = ERR_DSCFG_ERROR_NO_PASSWORD.get(bindDN); 245 return new ArgumentException(msg); 246 } 247 248 /** 249 * Creates an argument exception which should be used when the client has not specified a bind password. 250 * 251 * @param bindDN 252 * The name of the user requiring a password. 253 * @return Returns an argument exception. 254 */ 255 public static ArgumentException missingBindPassword(char[] bindDN) { 256 LocalizableMessage msg = ERR_DSCFG_ERROR_NO_PASSWORD.get(bindDN); 257 return new ArgumentException(msg); 258 } 259 260 /** 261 * Creates an argument exception which should be used when an argument, which is mandatory when the application is 262 * non-interactive, has not been specified. 263 * 264 * @param arg 265 * The missing argument. 266 * @return Returns an argument exception. 267 */ 268 public static ArgumentException missingMandatoryNonInteractiveArgument(Argument arg) { 269 LocalizableMessage msg = ERR_DSCFG_ERROR_MISSING_NON_INTERACTIVE_ARG.get(arg.getLongIdentifier()); 270 return new ArgumentException(msg); 271 } 272 273 /** 274 * Creates an argument exception which should be used when a property value argument is invalid because it does not 275 * a property name. 276 * 277 * @param arg 278 * The argument having the missing property name. 279 * @return Returns an argument exception. 280 */ 281 public static ArgumentException missingNameInPropertyArgument(String arg) { 282 LocalizableMessage msg = ERR_DSCFG_ERROR_NO_NAME_IN_PROPERTY_VALUE.get(arg); 283 return new ArgumentException(msg); 284 } 285 286 /** 287 * Creates an argument exception which should be used when a property modification argument is invalid because it 288 * does not a property name. 289 * 290 * @param arg 291 * The argument having the missing property name. 292 * @return Returns an argument exception. 293 */ 294 public static ArgumentException missingNameInPropertyModification(String arg) { 295 LocalizableMessage msg = ERR_DSCFG_ERROR_NO_NAME_IN_PROPERTY_MOD.get(arg); 296 return new ArgumentException(msg); 297 } 298 299 /** 300 * Creates an argument exception which should be used when a property value argument is invalid because it does not 301 * contain a separator between the property name and its value. 302 * 303 * @param arg 304 * The argument having a missing separator. 305 * @return Returns an argument exception. 306 */ 307 public static ArgumentException missingSeparatorInPropertyArgument(String arg) { 308 LocalizableMessage msg = ERR_DSCFG_ERROR_NO_SEPARATOR_IN_PROPERTY_VALUE.get(arg); 309 return new ArgumentException(msg); 310 } 311 312 /** 313 * Creates an argument exception which should be used when a property modification argument is invalid because it 314 * does not contain a separator between the property name and its value. 315 * 316 * @param arg 317 * The argument having a missing separator. 318 * @return Returns an argument exception. 319 */ 320 public static ArgumentException missingSeparatorInPropertyModification(String arg) { 321 LocalizableMessage msg = ERR_DSCFG_ERROR_NO_SEPARATOR_IN_PROPERTY_MOD.get(arg); 322 return new ArgumentException(msg); 323 } 324 325 /** 326 * Creates an argument exception which should be used when a property value argument is invalid because it does not 327 * a property value. 328 * 329 * @param arg 330 * The argument having the missing property value. 331 * @return Returns an argument exception. 332 */ 333 public static ArgumentException missingValueInPropertyArgument(String arg) { 334 LocalizableMessage msg = ERR_DSCFG_ERROR_NO_VALUE_IN_PROPERTY_VALUE.get(arg); 335 return new ArgumentException(msg); 336 } 337 338 /** 339 * Creates an argument exception which should be used when a property modification argument is invalid because it 340 * does not a property value. 341 * 342 * @param arg 343 * The argument having the missing property value. 344 * @return Returns an argument exception. 345 */ 346 public static ArgumentException missingValueInPropertyModification(String arg) { 347 LocalizableMessage msg = ERR_DSCFG_ERROR_NO_NAME_IN_PROPERTY_MOD.get(arg); 348 return new ArgumentException(msg); 349 } 350 351 /** 352 * Creates an argument exception which should be used when the connection parameters could not be read from the 353 * standard input. 354 * 355 * @param cause 356 * The reason why the connection parameters could not be read. 357 * @return Returns an argument exception. 358 */ 359 public static ArgumentException unableToReadConnectionParameters(Exception cause) { 360 LocalizableMessage message = ERR_DSCFG_ERROR_CANNOT_READ_CONNECTION_PARAMETERS.get(cause.getMessage()); 361 return new ArgumentException(message, cause); 362 } 363 364 /** 365 * Creates an argument exception which should be used when the bind password could not be read from the standard 366 * input because the application is non-interactive. 367 * 368 * @return Returns an argument exception. 369 */ 370 public static ArgumentException unableToReadBindPasswordInteractively() { 371 LocalizableMessage message = ERR_DSCFG_ERROR_BIND_PASSWORD_NONINTERACTIVE.get(); 372 return new ArgumentException(message); 373 } 374 375 /** 376 * Creates an argument exception which should be used when an attempt is made to reset a mandatory property that 377 * does not have any default values. 378 * 379 * @param d 380 * The managed object definition. 381 * @param name 382 * The name of the mandatory property. 383 * @param setOption 384 * The name of the option which should be used to set the property's values. 385 * @return Returns an argument exception. 386 */ 387 public static ArgumentException unableToResetMandatoryProperty(AbstractManagedObjectDefinition<?, ?> d, 388 String name, String setOption) { 389 LocalizableMessage message = ERR_DSCFG_ERROR_UNABLE_TO_RESET_MANDATORY_PROPERTY.get( 390 d.getUserFriendlyPluralName(), name, setOption); 391 return new ArgumentException(message); 392 } 393 394 /** 395 * Creates an argument exception which should be used when an attempt is made to reset a property with a value. 396 * 397 * @param name 398 * The name of the mandatory property. 399 * @param resetOption 400 * The name of the option which should be used to reset the property's values. 401 * @return Returns an argument exception. 402 */ 403 public static ArgumentException unableToResetPropertyWithValue(String name, String resetOption) { 404 LocalizableMessage message = ERR_DSCFG_ERROR_UNABLE_TO_RESET_PROPERTY_WITH_VALUE.get(resetOption, name, 405 resetOption); 406 return new ArgumentException(message); 407 } 408 409 /** 410 * Creates an argument exception which should be used when an attempt is made to set the naming property for a 411 * managed object during creation. 412 * 413 * @param d 414 * The managed object definition. 415 * @param pd 416 * The naming property definition. 417 * @return Returns an argument exception. 418 */ 419 public static ArgumentException unableToSetNamingProperty(AbstractManagedObjectDefinition<?, ?> d, 420 PropertyDefinition<?> pd) { 421 LocalizableMessage message = ERR_DSCFG_ERROR_UNABLE_TO_SET_NAMING_PROPERTY.get(pd.getName(), 422 d.getUserFriendlyName()); 423 return new ArgumentException(message); 424 } 425 426 /** 427 * Creates an argument exception which should be used when a component category argument is not recognized. 428 * 429 * @param categoryName 430 * The unrecognized component category. 431 * @return Returns an argument exception. 432 */ 433 public static ArgumentException unknownCategory(String categoryName) { 434 LocalizableMessage msg = ERR_DSCFG_ERROR_CATEGORY_UNRECOGNIZED.get(categoryName); 435 return new ArgumentException(msg); 436 } 437 438 /** 439 * Creates an argument exception which should be used when a property name is not recognized. 440 * 441 * @param d 442 * The managed object definition. 443 * @param name 444 * The unrecognized property name. 445 * @return Returns an argument exception. 446 */ 447 public static ArgumentException unknownProperty(AbstractManagedObjectDefinition<?, ?> d, String name) { 448 LocalizableMessage message = ERR_DSCFG_ERROR_PROPERTY_UNRECOGNIZED.get(name, d.getUserFriendlyPluralName()); 449 return new ArgumentException(message); 450 } 451 452 /** 453 * Creates an argument exception which should be used when a property name is not recognized. 454 * 455 * @param name 456 * The unrecognized property name. 457 * @return Returns an argument exception. 458 */ 459 public static ArgumentException unknownProperty(String name) { 460 LocalizableMessage message = ERR_DSCFG_ERROR_PROPERTY_UNRECOGNIZED_NO_DEFN.get(name); 461 return new ArgumentException(message); 462 } 463 464 /** 465 * Creates an argument exception which should be used when a sub-type argument in a create-xxx sub-command is not 466 * recognized. 467 * 468 * @param r 469 * The relation definition. 470 * @param typeName 471 * The unrecognized property sub-type. 472 * @param typeUsage 473 * A usage string describing the allowed sub-types. 474 * @return Returns an argument exception. 475 */ 476 public static ArgumentException unknownSubType(RelationDefinition<?, ?> r, String typeName, String typeUsage) { 477 LocalizableMessage msg = ERR_DSCFG_ERROR_SUB_TYPE_UNRECOGNIZED 478 .get(typeName, r.getUserFriendlyName(), typeUsage); 479 return new ArgumentException(msg); 480 } 481 482 /** 483 * Creates an argument exception which should be used when a managed object type argument is not associated with a 484 * category. 485 * 486 * @param categoryName 487 * The component category. 488 * @param typeName 489 * The unrecognized component type. 490 * @return Returns an argument exception. 491 */ 492 public static ArgumentException unknownTypeForCategory(String typeName, String categoryName) { 493 LocalizableMessage msg = ERR_DSCFG_ERROR_CATEGORY_TYPE_UNRECOGNIZED.get(typeName, categoryName); 494 return new ArgumentException(msg); 495 } 496 497 /** 498 * Creates an argument exception which should be used when a multi-valued property does not contain a given value. 499 * 500 * @param value 501 * The property value. 502 * @param propertyName 503 * The property name. 504 * @return Returns an argument exception. 505 */ 506 public static ArgumentException unknownValueForMultiValuedProperty(String value, String propertyName) { 507 LocalizableMessage msg = ERR_DSCFG_ERROR_VALUE_DOES_NOT_EXIST.get(value, propertyName); 508 return new ArgumentException(msg); 509 } 510 511 /** 512 * Creates an argument exception which should be used when a child component does not exist. 513 * 514 * @param componentName 515 * The component name. 516 * @return Returns an argument exception. 517 */ 518 public static ArgumentException unknownValueForChildComponent(String componentName) { 519 LocalizableMessage msg = ERR_DSCFG_ERROR_FINDER_NO_CHILDREN.get(componentName); 520 return new ArgumentException(msg); 521 } 522 523 /** 524 * Creates a CLI exception which should be used when a managed object is retrieved but does not have the correct 525 * type appropriate for the associated sub-command. 526 * 527 * @param r 528 * The relation definition. 529 * @param d 530 * The definition of the managed object that was retrieved. 531 * @param subcommandName 532 * the sub-command name. 533 * @return Returns a Client exception. 534 */ 535 public static ClientException wrongManagedObjectType(RelationDefinition<?, ?> r, ManagedObjectDefinition<?, ?> d, 536 String subcommandName) { 537 LocalizableMessage msg = ERR_DSCFG_ERROR_TYPE_UNRECOGNIZED_FOR_SUBCOMMAND.get(d.getUserFriendlyName(), 538 subcommandName); 539 return new ClientException(ReturnCode.ERROR_USER_DATA, msg); 540 } 541 542 /** Prevent instantiation. */ 543 private ArgumentExceptionFactory() { 544 // No implementation required. 545 } 546}