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