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