001/* 002 * Copyright 2009-2019 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2009-2019 Ping Identity Corporation 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU General Public License (GPLv2 only) 010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 011 * as published by the Free Software Foundation. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Public License for more details. 017 * 018 * You should have received a copy of the GNU General Public License 019 * along with this program; if not, see <http://www.gnu.org/licenses>. 020 */ 021package com.unboundid.ldap.sdk.persist; 022 023 024 025import java.io.File; 026import java.io.FileWriter; 027import java.io.OutputStream; 028import java.io.PrintWriter; 029import java.io.Serializable; 030import java.util.Arrays; 031import java.util.Collection; 032import java.util.Date; 033import java.util.Iterator; 034import java.util.LinkedHashMap; 035import java.util.TreeMap; 036import java.util.TreeSet; 037 038import com.unboundid.ldap.sdk.DN; 039import com.unboundid.ldap.sdk.Entry; 040import com.unboundid.ldap.sdk.Filter; 041import com.unboundid.ldap.sdk.LDAPConnection; 042import com.unboundid.ldap.sdk.LDAPException; 043import com.unboundid.ldap.sdk.LDAPInterface; 044import com.unboundid.ldap.sdk.ReadOnlyEntry; 045import com.unboundid.ldap.sdk.ResultCode; 046import com.unboundid.ldap.sdk.Version; 047import com.unboundid.ldap.sdk.schema.AttributeTypeDefinition; 048import com.unboundid.ldap.sdk.schema.ObjectClassDefinition; 049import com.unboundid.ldap.sdk.schema.ObjectClassType; 050import com.unboundid.ldap.sdk.schema.Schema; 051import com.unboundid.util.Debug; 052import com.unboundid.util.LDAPCommandLineTool; 053import com.unboundid.util.Mutable; 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.DNArgument; 061import com.unboundid.util.args.FileArgument; 062import com.unboundid.util.args.StringArgument; 063 064import static com.unboundid.ldap.sdk.persist.PersistMessages.*; 065 066 067 068/** 069 * This class provides a tool which can be used to generate source code for a 070 * Java class file based on information read from the schema of an LDAP 071 * directory server. 072 */ 073@Mutable() 074@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE) 075public final class GenerateSourceFromSchema 076 extends LDAPCommandLineTool 077 implements Serializable 078{ 079 /** 080 * The serial version UID for this serializable class. 081 */ 082 private static final long serialVersionUID = 3488976364950590266L; 083 084 085 086 /** 087 * A pre-allocated empty tree set. 088 */ 089 private static final TreeSet<String> EMPTY_TREE_SET = new TreeSet<>(); 090 091 092 093 // Arguments used by this tool. 094 private BooleanArgument terseArg; 095 private DNArgument defaultParentDNArg; 096 private FileArgument outputDirectoryArg; 097 private StringArgument auxiliaryClassArg; 098 private StringArgument classNameArg; 099 private StringArgument lazyAttributeArg; 100 private StringArgument operationalAttributeArg; 101 private StringArgument packageNameArg; 102 private StringArgument rdnAttributeArg; 103 private StringArgument structuralClassArg; 104 105 // Indicates whether any multivalued attributes have been identified, and 106 // therefore we need to include java.util.Arrays in the import list. 107 private boolean needArrays; 108 109 // Indicates whether any date attributes have been identified, and therefore 110 // we need to include java.util.Date in the import list. 111 private boolean needDate; 112 113 // Indicates whether any DN-syntax attributes have been identified, and 114 // therefore we need to include com.unboundid.ldap.sdk.DN in the import list. 115 private boolean needDN; 116 117 // Indicates whether 118 // Indicates whether any DN-syntax attributes have been identified, and 119 // therefore we need to include 120 // com.unboundid.ldap.sdk.persist.PersistedObjects in the import list. 121 private boolean needPersistedObjects; 122 123 124 125 /** 126 * Parse the provided command line arguments and perform the appropriate 127 * processing. 128 * 129 * @param args The command line arguments provided to this program. 130 */ 131 public static void main(final String[] args) 132 { 133 final ResultCode resultCode = main(args, System.out, System.err); 134 if (resultCode != ResultCode.SUCCESS) 135 { 136 System.exit(resultCode.intValue()); 137 } 138 } 139 140 141 142 /** 143 * Parse the provided command line arguments and perform the appropriate 144 * processing. 145 * 146 * @param args The command line arguments provided to this program. 147 * @param outStream The output stream to which standard out should be 148 * written. It may be {@code null} if output should be 149 * suppressed. 150 * @param errStream The output stream to which standard error should be 151 * written. It may be {@code null} if error messages 152 * should be suppressed. 153 * 154 * @return A result code indicating whether the processing was successful. 155 */ 156 public static ResultCode main(final String[] args, 157 final OutputStream outStream, 158 final OutputStream errStream) 159 { 160 final GenerateSourceFromSchema tool = 161 new GenerateSourceFromSchema(outStream, errStream); 162 return tool.runTool(args); 163 } 164 165 166 167 /** 168 * Creates a new instance of this tool. 169 * 170 * @param outStream The output stream to which standard out should be 171 * written. It may be {@code null} if output should be 172 * suppressed. 173 * @param errStream The output stream to which standard error should be 174 * written. It may be {@code null} if error messages 175 * should be suppressed. 176 */ 177 public GenerateSourceFromSchema(final OutputStream outStream, 178 final OutputStream errStream) 179 { 180 super(outStream, errStream); 181 182 needArrays = false; 183 needDate = false; 184 needDN = false; 185 needPersistedObjects = false; 186 } 187 188 189 190 /** 191 * {@inheritDoc} 192 */ 193 @Override() 194 public String getToolName() 195 { 196 return "generate-source-from-schema"; 197 } 198 199 200 201 /** 202 * {@inheritDoc} 203 */ 204 @Override() 205 public String getToolDescription() 206 { 207 return INFO_GEN_SOURCE_TOOL_DESCRIPTION.get(); 208 } 209 210 211 212 /** 213 * Retrieves the version string for this tool. 214 * 215 * @return The version string for this tool. 216 */ 217 @Override() 218 public String getToolVersion() 219 { 220 return Version.NUMERIC_VERSION_STRING; 221 } 222 223 224 225 /** 226 * Indicates whether this tool should provide support for an interactive mode, 227 * in which the tool offers a mode in which the arguments can be provided in 228 * a text-driven menu rather than requiring them to be given on the command 229 * line. If interactive mode is supported, it may be invoked using the 230 * "--interactive" argument. Alternately, if interactive mode is supported 231 * and {@link #defaultsToInteractiveMode()} returns {@code true}, then 232 * interactive mode may be invoked by simply launching the tool without any 233 * arguments. 234 * 235 * @return {@code true} if this tool supports interactive mode, or 236 * {@code false} if not. 237 */ 238 @Override() 239 public boolean supportsInteractiveMode() 240 { 241 return true; 242 } 243 244 245 246 /** 247 * Indicates whether this tool defaults to launching in interactive mode if 248 * the tool is invoked without any command-line arguments. This will only be 249 * used if {@link #supportsInteractiveMode()} returns {@code true}. 250 * 251 * @return {@code true} if this tool defaults to using interactive mode if 252 * launched without any command-line arguments, or {@code false} if 253 * not. 254 */ 255 @Override() 256 public boolean defaultsToInteractiveMode() 257 { 258 return true; 259 } 260 261 262 263 /** 264 * Indicates whether this tool should provide arguments for redirecting output 265 * to a file. If this method returns {@code true}, then the tool will offer 266 * an "--outputFile" argument that will specify the path to a file to which 267 * all standard output and standard error content will be written, and it will 268 * also offer a "--teeToStandardOut" argument that can only be used if the 269 * "--outputFile" argument is present and will cause all output to be written 270 * to both the specified output file and to standard output. 271 * 272 * @return {@code true} if this tool should provide arguments for redirecting 273 * output to a file, or {@code false} if not. 274 */ 275 @Override() 276 protected boolean supportsOutputFile() 277 { 278 return true; 279 } 280 281 282 283 /** 284 * Indicates whether this tool should default to interactively prompting for 285 * the bind password if a password is required but no argument was provided 286 * to indicate how to get the password. 287 * 288 * @return {@code true} if this tool should default to interactively 289 * prompting for the bind password, or {@code false} if not. 290 */ 291 @Override() 292 protected boolean defaultToPromptForBindPassword() 293 { 294 return true; 295 } 296 297 298 299 /** 300 * Indicates whether this tool supports the use of a properties file for 301 * specifying default values for arguments that aren't specified on the 302 * command line. 303 * 304 * @return {@code true} if this tool supports the use of a properties file 305 * for specifying default values for arguments that aren't specified 306 * on the command line, or {@code false} if not. 307 */ 308 @Override() 309 public boolean supportsPropertiesFile() 310 { 311 return true; 312 } 313 314 315 316 /** 317 * Indicates whether the LDAP-specific arguments should include alternate 318 * versions of all long identifiers that consist of multiple words so that 319 * they are available in both camelCase and dash-separated versions. 320 * 321 * @return {@code true} if this tool should provide multiple versions of 322 * long identifiers for LDAP-specific arguments, or {@code false} if 323 * not. 324 */ 325 @Override() 326 protected boolean includeAlternateLongIdentifiers() 327 { 328 return true; 329 } 330 331 332 333 /** 334 * {@inheritDoc} 335 */ 336 @Override() 337 public void addNonLDAPArguments(final ArgumentParser parser) 338 throws ArgumentException 339 { 340 outputDirectoryArg = new FileArgument('d', "outputDirectory", false, 1, 341 INFO_GEN_SOURCE_VALUE_PLACEHOLDER_PATH.get(), 342 INFO_GEN_SOURCE_ARG_DESCRIPTION_OUTPUT_DIRECTORY.get(), true, true, 343 false, true); 344 outputDirectoryArg.addLongIdentifier("output-directory", true); 345 parser.addArgument(outputDirectoryArg); 346 347 structuralClassArg = new StringArgument('s', "structuralClass", true, 1, 348 INFO_GEN_SOURCE_VALUE_PLACEHOLDER_NAME.get(), 349 INFO_GEN_SOURCE_ARG_DESCRIPTION_STRUCTURAL_CLASS.get()); 350 structuralClassArg.addLongIdentifier("structural-class", true); 351 parser.addArgument(structuralClassArg); 352 353 auxiliaryClassArg = new StringArgument('a', "auxiliaryClass", false, 0, 354 INFO_GEN_SOURCE_VALUE_PLACEHOLDER_NAME.get(), 355 INFO_GEN_SOURCE_ARG_DESCRIPTION_AUXILIARY_CLASS.get()); 356 auxiliaryClassArg.addLongIdentifier("auxiliary-class", true); 357 parser.addArgument(auxiliaryClassArg); 358 359 rdnAttributeArg = new StringArgument('r', "rdnAttribute", true, 0, 360 INFO_GEN_SOURCE_VALUE_PLACEHOLDER_NAME.get(), 361 INFO_GEN_SOURCE_ARG_DESCRIPTION_RDN_ATTRIBUTE.get()); 362 rdnAttributeArg.addLongIdentifier("rdn-attribute", true); 363 parser.addArgument(rdnAttributeArg); 364 365 lazyAttributeArg = new StringArgument('l', "lazyAttribute", false, 0, 366 INFO_GEN_SOURCE_VALUE_PLACEHOLDER_NAME.get(), 367 INFO_GEN_SOURCE_ARG_DESCRIPTION_LAZY_ATTRIBUTE.get()); 368 lazyAttributeArg.addLongIdentifier("lazy-attribute", true); 369 parser.addArgument(lazyAttributeArg); 370 371 operationalAttributeArg = new StringArgument('O', "operationalAttribute", 372 false, 0, INFO_GEN_SOURCE_VALUE_PLACEHOLDER_NAME.get(), 373 INFO_GEN_SOURCE_ARG_DESCRIPTION_OPERATIONAL_ATTRIBUTE.get()); 374 operationalAttributeArg.addLongIdentifier("operational-attribute", true); 375 parser.addArgument(operationalAttributeArg); 376 377 defaultParentDNArg = new DNArgument('b', "defaultParentDN", false, 1, 378 INFO_GEN_SOURCE_VALUE_PLACEHOLDER_DN.get(), 379 INFO_GEN_SOURCE_ARG_DESCRIPTION_DEFAULT_PARENT_DN.get()); 380 defaultParentDNArg.addLongIdentifier("default-parent-dn", true); 381 parser.addArgument(defaultParentDNArg); 382 383 packageNameArg = new StringArgument('n', "packageName", false, 1, 384 INFO_GEN_SOURCE_VALUE_PLACEHOLDER_NAME.get(), 385 INFO_GEN_SOURCE_ARG_DESCRIPTION_PACKAGE_NAME.get()); 386 packageNameArg.addLongIdentifier("package-name", true); 387 parser.addArgument(packageNameArg); 388 389 classNameArg = new StringArgument('c', "className", false, 1, 390 INFO_GEN_SOURCE_VALUE_PLACEHOLDER_NAME.get(), 391 INFO_GEN_SOURCE_ARG_DESCRIPTION_CLASS_NAME.get()); 392 classNameArg.addLongIdentifier("class-name", true); 393 parser.addArgument(classNameArg); 394 395 terseArg = new BooleanArgument('t', "terse", 1, 396 INFO_GEN_SOURCE_ARG_DESCRIPTION_TERSE.get()); 397 parser.addArgument(terseArg); 398 } 399 400 401 402 /** 403 * {@inheritDoc} 404 */ 405 @Override() 406 public ResultCode doToolProcessing() 407 { 408 // Establish a connection to the target directory server and retrieve the 409 // schema. 410 final LDAPConnection conn; 411 try 412 { 413 conn = getConnection(); 414 } 415 catch (final LDAPException le) 416 { 417 Debug.debugException(le); 418 err(ERR_GEN_SOURCE_CANNOT_CONNECT.get( 419 StaticUtils.getExceptionMessage(le))); 420 return le.getResultCode(); 421 } 422 423 final Schema schema; 424 try 425 { 426 schema = conn.getSchema(); 427 if (schema == null) 428 { 429 err(ERR_GEN_SOURCE_CANNOT_READ_SCHEMA.get( 430 ERR_GEN_SOURCE_SCHEMA_NOT_RETURNED.get())); 431 return ResultCode.NO_RESULTS_RETURNED; 432 } 433 } 434 catch (final LDAPException le) 435 { 436 Debug.debugException(le); 437 err(ERR_GEN_SOURCE_CANNOT_READ_SCHEMA.get( 438 StaticUtils.getExceptionMessage(le))); 439 return le.getResultCode(); 440 } 441 finally 442 { 443 conn.close(); 444 } 445 446 return generateSourceFile(schema, terseArg.isPresent()); 447 } 448 449 450 451 /** 452 * Generates the source file using the information in the provided schema. 453 * 454 * @param schema The schema to use to generate the source file. 455 * @param terse Indicates whether to use terse mode when generating the 456 * source file. If this is {@code true}, then all optional 457 * elements will be omitted from annotations. 458 * 459 * @return A result code obtained for the processing. 460 */ 461 private ResultCode generateSourceFile(final Schema schema, 462 final boolean terse) 463 { 464 // Retrieve and process the structural object class. 465 final TreeMap<String,AttributeTypeDefinition> requiredAttrs = 466 new TreeMap<>(); 467 final TreeMap<String,AttributeTypeDefinition> optionalAttrs = 468 new TreeMap<>(); 469 final TreeMap<String,TreeSet<String>> requiredAttrOCs = new TreeMap<>(); 470 final TreeMap<String,TreeSet<String>> optionalAttrOCs = new TreeMap<>(); 471 final TreeMap<String,String> types = new TreeMap<>(); 472 473 final String structuralClassName = structuralClassArg.getValue(); 474 final ObjectClassDefinition structuralOC = 475 schema.getObjectClass(structuralClassName); 476 if (structuralOC == null) 477 { 478 err(ERR_GEN_SOURCE_STRUCTURAL_CLASS_NOT_FOUND.get(structuralClassName)); 479 return ResultCode.PARAM_ERROR; 480 } 481 482 if (structuralOC.getObjectClassType(schema) != ObjectClassType.STRUCTURAL) 483 { 484 err(ERR_GEN_SOURCE_STRUCTURAL_CLASS_NOT_STRUCTURAL.get( 485 structuralClassName)); 486 return ResultCode.PARAM_ERROR; 487 } 488 489 processObjectClass(structuralOC, schema, requiredAttrs, requiredAttrOCs, 490 optionalAttrs, optionalAttrOCs, types); 491 492 493 // Retrieve and process the auxiliary object classes. 494 final TreeMap<String,ObjectClassDefinition> auxiliaryOCs = new TreeMap<>(); 495 if (auxiliaryClassArg.isPresent()) 496 { 497 for (final String s : auxiliaryClassArg.getValues()) 498 { 499 final ObjectClassDefinition oc = schema.getObjectClass(s); 500 if (oc == null) 501 { 502 err(ERR_GEN_SOURCE_AUXILIARY_CLASS_NOT_FOUND.get(s)); 503 return ResultCode.PARAM_ERROR; 504 } 505 506 if (oc.getObjectClassType(schema) != ObjectClassType.AUXILIARY) 507 { 508 err(ERR_GEN_SOURCE_AUXILIARY_CLASS_NOT_AUXILIARY.get(s)); 509 return ResultCode.PARAM_ERROR; 510 } 511 512 auxiliaryOCs.put(StaticUtils.toLowerCase(s), oc); 513 514 processObjectClass(oc, schema, requiredAttrs, requiredAttrOCs, 515 optionalAttrs, optionalAttrOCs, types); 516 } 517 } 518 519 520 // Determine the appropriate set of superior object classes. 521 final TreeMap<String,ObjectClassDefinition> superiorOCs = new TreeMap<>(); 522 for (final ObjectClassDefinition s : 523 structuralOC.getSuperiorClasses(schema, true)) 524 { 525 superiorOCs.put(StaticUtils.toLowerCase(s.getNameOrOID()), s); 526 } 527 528 for (final ObjectClassDefinition d : auxiliaryOCs.values()) 529 { 530 for (final ObjectClassDefinition s : d.getSuperiorClasses(schema, true)) 531 { 532 superiorOCs.put(StaticUtils.toLowerCase(s.getNameOrOID()), s); 533 } 534 } 535 536 superiorOCs.remove(StaticUtils.toLowerCase(structuralClassName)); 537 for (final String s : auxiliaryOCs.keySet()) 538 { 539 superiorOCs.remove(s); 540 } 541 542 543 // Retrieve and process the operational attributes. 544 final TreeMap<String,AttributeTypeDefinition> operationalAttrs = 545 new TreeMap<>(); 546 if (operationalAttributeArg.isPresent()) 547 { 548 for (final String s : operationalAttributeArg.getValues()) 549 { 550 final AttributeTypeDefinition d = schema.getAttributeType(s); 551 if (d == null) 552 { 553 err(ERR_GEN_SOURCE_OPERATIONAL_ATTRIBUTE_NOT_DEFINED.get(s)); 554 return ResultCode.PARAM_ERROR; 555 } 556 else if (! d.isOperational()) 557 { 558 err(ERR_GEN_SOURCE_OPERATIONAL_ATTRIBUTE_NOT_OPERATIONAL.get(s)); 559 return ResultCode.PARAM_ERROR; 560 } 561 else 562 { 563 final String lowerName = StaticUtils.toLowerCase(s); 564 operationalAttrs.put(lowerName, d); 565 types.put(lowerName, getJavaType(schema, d)); 566 } 567 } 568 } 569 570 571 // Make sure all of the configured RDN attributes are allowed by at least 572 // one of the associated object classes. 573 final TreeSet<String> rdnAttrs = new TreeSet<>(); 574 for (final String s : rdnAttributeArg.getValues()) 575 { 576 final AttributeTypeDefinition d = schema.getAttributeType(s); 577 if (d == null) 578 { 579 err(ERR_GEN_SOURCE_RDN_ATTRIBUTE_NOT_DEFINED.get(s)); 580 return ResultCode.PARAM_ERROR; 581 } 582 583 final String lowerName = StaticUtils.toLowerCase(d.getNameOrOID()); 584 rdnAttrs.add(lowerName); 585 if (requiredAttrs.containsKey(lowerName)) 586 { 587 // No action required. 588 } 589 else if (optionalAttrs.containsKey(lowerName)) 590 { 591 // Move the attribute to the required set. 592 requiredAttrs.put(lowerName, optionalAttrs.remove(lowerName)); 593 requiredAttrOCs.put(lowerName, optionalAttrOCs.remove(lowerName)); 594 } 595 else 596 { 597 err(ERR_GEN_SOURCE_RDN_ATTRIBUTE_NOT_DEFINED.get(s)); 598 return ResultCode.PARAM_ERROR; 599 } 600 } 601 602 603 // Make sure all of the configured lazily-loaded attributes are allowed by 604 // at least one of the associated object classes or matches a configured 605 // operational attribute. 606 final TreeSet<String> lazyAttrs = new TreeSet<>(); 607 for (final String s : lazyAttributeArg.getValues()) 608 { 609 final AttributeTypeDefinition d = schema.getAttributeType(s); 610 if (d == null) 611 { 612 err(ERR_GEN_SOURCE_LAZY_ATTRIBUTE_NOT_DEFINED.get(s)); 613 return ResultCode.PARAM_ERROR; 614 } 615 616 final String lowerName = StaticUtils.toLowerCase(d.getNameOrOID()); 617 lazyAttrs.add(lowerName); 618 if (requiredAttrs.containsKey(lowerName) || 619 optionalAttrs.containsKey(lowerName) || 620 operationalAttrs.containsKey(lowerName)) 621 { 622 // No action required. 623 } 624 else 625 { 626 err(ERR_GEN_SOURCE_LAZY_ATTRIBUTE_NOT_ALLOWED.get(s)); 627 return ResultCode.PARAM_ERROR; 628 } 629 } 630 631 632 final String className; 633 if (classNameArg.isPresent()) 634 { 635 className = classNameArg.getValue(); 636 final StringBuilder invalidReason = new StringBuilder(); 637 if (! PersistUtils.isValidJavaIdentifier(className, invalidReason)) 638 { 639 err(ERR_GEN_SOURCE_INVALID_CLASS_NAME.get(className, 640 invalidReason.toString())); 641 return ResultCode.PARAM_ERROR; 642 } 643 } 644 else 645 { 646 className = StaticUtils.capitalize( 647 PersistUtils.toJavaIdentifier(structuralClassName)); 648 } 649 650 651 final File sourceFile = new File(outputDirectoryArg.getValue(), 652 className + ".java"); 653 final PrintWriter writer; 654 try 655 { 656 writer = new PrintWriter(new FileWriter(sourceFile)); 657 } 658 catch (final Exception e) 659 { 660 Debug.debugException(e); 661 err(ERR_GEN_SOURCE_CANNOT_CREATE_WRITER.get(sourceFile.getAbsolutePath(), 662 StaticUtils.getExceptionMessage(e))); 663 return ResultCode.LOCAL_ERROR; 664 } 665 666 667 if (packageNameArg.isPresent()) 668 { 669 final String packageName = packageNameArg.getValue(); 670 if (! packageName.isEmpty()) 671 { 672 writer.println("package " + packageName + ';'); 673 writer.println(); 674 writer.println(); 675 writer.println(); 676 } 677 } 678 679 boolean javaImports = false; 680 if (needArrays) 681 { 682 writer.println("import " + Arrays.class.getName() + ';'); 683 javaImports = true; 684 } 685 686 if (needDate) 687 { 688 writer.println("import " + Date.class.getName() + ';'); 689 javaImports = true; 690 } 691 692 if (javaImports) 693 { 694 writer.println(); 695 } 696 697 if (needDN) 698 { 699 writer.println("import " + DN.class.getName() + ';'); 700 } 701 702 writer.println("import " + Entry.class.getName() + ';'); 703 writer.println("import " + Filter.class.getName() + ';'); 704 705 if (needDN) 706 { 707 writer.println("import " + LDAPException.class.getName() + ';'); 708 writer.println("import " + LDAPInterface.class.getName() + ';'); 709 } 710 711 writer.println("import " + ReadOnlyEntry.class.getName() + ';'); 712 writer.println("import " + DefaultObjectEncoder.class.getName() + ';'); 713 writer.println("import " + FieldInfo.class.getName() + ';'); 714 writer.println("import " + FilterUsage.class.getName() + ';'); 715 writer.println("import " + LDAPEntryField.class.getName() + ';'); 716 writer.println("import " + LDAPField.class.getName() + ';'); 717 writer.println("import " + LDAPObject.class.getName() + ';'); 718 writer.println("import " + LDAPObjectHandler.class.getName() + ';'); 719 writer.println("import " + LDAPPersister.class.getName() + ';'); 720 writer.println("import " + LDAPPersistException.class.getName() + ';'); 721 722 if (needPersistedObjects) 723 { 724 writer.println("import " + PersistedObjects.class.getName() + ';'); 725 } 726 727 writer.println("import " + PersistFilterType.class.getName() + ';'); 728 729 if (needDN) 730 { 731 writer.println("import " + PersistUtils.class.getName() + ';'); 732 } 733 734 writer.println(); 735 writer.println(); 736 writer.println(); 737 writer.println("/**"); 738 writer.println(" * This class provides an implementation of an object " + 739 "that can be used to"); 740 writer.println(" * represent " + structuralClassName + 741 " objects in the directory."); 742 writer.println(" * It was generated by the " + getToolName() + 743 " tool provided with the"); 744 writer.println(" * UnboundID LDAP SDK for Java. It " + 745 "may be customized as desired to better suit"); 746 writer.println(" * your needs."); 747 writer.println(" */"); 748 writer.println("@LDAPObject(structuralClass=\"" + structuralClassName + 749 "\","); 750 751 switch (auxiliaryOCs.size()) 752 { 753 case 0: 754 // No action required. 755 break; 756 757 case 1: 758 writer.println(" auxiliaryClass=\"" + 759 auxiliaryOCs.values().iterator().next().getNameOrOID() + "\","); 760 break; 761 762 default: 763 final Iterator<ObjectClassDefinition> iterator = 764 auxiliaryOCs.values().iterator(); 765 writer.println(" auxiliaryClass={ \"" + 766 iterator.next().getNameOrOID() + "\","); 767 while (iterator.hasNext()) 768 { 769 final String ocName = iterator.next().getNameOrOID(); 770 if (iterator.hasNext()) 771 { 772 writer.println(" \"" + ocName + 773 "\","); 774 } 775 else 776 { 777 writer.println(" \"" + ocName + 778 "\" },"); 779 } 780 } 781 break; 782 } 783 784 switch (superiorOCs.size()) 785 { 786 case 0: 787 // No action required. 788 break; 789 790 case 1: 791 writer.println(" superiorClass=\"" + 792 superiorOCs.values().iterator().next().getNameOrOID() + "\","); 793 break; 794 795 default: 796 final Iterator<ObjectClassDefinition> iterator = 797 superiorOCs.values().iterator(); 798 writer.println(" superiorClass={ \"" + 799 iterator.next().getNameOrOID() + "\","); 800 while (iterator.hasNext()) 801 { 802 final String ocName = iterator.next().getNameOrOID(); 803 if (iterator.hasNext()) 804 { 805 writer.println(" \"" + ocName + 806 "\","); 807 } 808 else 809 { 810 writer.println(" \"" + ocName + 811 "\" },"); 812 } 813 } 814 break; 815 } 816 817 if (defaultParentDNArg.isPresent()) 818 { 819 writer.println(" defaultParentDN=\"" + 820 defaultParentDNArg.getValue() + "\","); 821 } 822 823 writer.println(" postDecodeMethod=\"doPostDecode\","); 824 writer.println(" postEncodeMethod=\"doPostEncode\")"); 825 writer.println("public class " + className); 826 writer.println("{"); 827 828 if (! terse) 829 { 830 writer.println(" /*"); 831 writer.println(" * NOTE: This class includes a number of annotation " + 832 "elements which are not"); 833 writer.println(" * required but have been provided to make it easier " + 834 "to edit the resulting"); 835 writer.println(" * source code. If you want to exclude these " + 836 "unnecessary annotation"); 837 writer.println(" * elements, use the '--terse' command-line argument."); 838 writer.println(" */"); 839 writer.println(); 840 writer.println(); 841 writer.println(); 842 } 843 844 writer.println(" // The field to use to hold a read-only copy of the " + 845 "associated entry."); 846 writer.println(" @LDAPEntryField()"); 847 writer.println(" private ReadOnlyEntry ldapEntry;"); 848 849 850 // Add all of the fields. First the fields for the RDN attributes, then 851 // for the rest of the required attributes, then for the optional 852 // attributes, and finally any operational attributes. 853 for (final String lowerName : rdnAttrs) 854 { 855 final AttributeTypeDefinition d = requiredAttrs.get(lowerName); 856 final TreeSet<String> ocNames = requiredAttrOCs.get(lowerName); 857 writeField(writer, d, types.get(lowerName), ocNames, true, true, 858 structuralClassName, false, terse); 859 } 860 861 for (final String lowerName : requiredAttrs.keySet()) 862 { 863 if (rdnAttrs.contains(lowerName)) 864 { 865 continue; 866 } 867 868 final AttributeTypeDefinition d = requiredAttrs.get(lowerName); 869 final TreeSet<String> ocNames = requiredAttrOCs.get(lowerName); 870 writeField(writer, d, types.get(lowerName), ocNames, false, true, 871 structuralClassName, lazyAttrs.contains(lowerName), terse); 872 } 873 874 for (final String lowerName : optionalAttrs.keySet()) 875 { 876 final AttributeTypeDefinition d = optionalAttrs.get(lowerName); 877 final TreeSet<String> ocNames = optionalAttrOCs.get(lowerName); 878 writeField(writer, d, types.get(lowerName), ocNames, false, false, 879 structuralClassName, lazyAttrs.contains(lowerName), terse); 880 } 881 882 for (final String lowerName : operationalAttrs.keySet()) 883 { 884 final AttributeTypeDefinition d = operationalAttrs.get(lowerName); 885 final TreeSet<String> ocNames = EMPTY_TREE_SET; 886 writeField(writer, d, types.get(lowerName), ocNames, false, false, 887 structuralClassName, lazyAttrs.contains(lowerName), terse); 888 } 889 890 891 // Add the default constructor. 892 writer.println(); 893 writer.println(); 894 writer.println(); 895 writer.println(" /**"); 896 writer.println(" * Creates a new instance of this object. All fields " + 897 "will be uninitialized,"); 898 writer.println(" * so the setter methods should be used to assign " + 899 "values to them."); 900 writer.println(" */"); 901 writer.println(" public " + className + "()"); 902 writer.println(" {"); 903 writer.println(" // No initialization will be performed by default. " + 904 "Note that if you set"); 905 writer.println(" // values for any fields marked with an @LDAPField, " + 906 "@LDAPDNField, or"); 907 writer.println(" // @LDAPEntryField annotation, they will be " + 908 "overwritten in the course of"); 909 writer.println(" // decoding initializing this object from an LDAP " + 910 "entry."); 911 writer.println(" }"); 912 913 914 // Add a static decode method that can create an instance of the object 915 // from a given entry. 916 writer.println(); 917 writer.println(); 918 writer.println(); 919 writer.println(" /**"); 920 writer.println(" * Creates a new " + className + " object decoded"); 921 writer.println(" * from the provided entry."); 922 writer.println(" *"); 923 writer.println(" * @param entry The entry to be decoded."); 924 writer.println(" *"); 925 writer.println(" * @return The decoded " + className + " object."); 926 writer.println(" *"); 927 writer.println(" * @throws LDAPPersistException If a problem occurs " + 928 "while attempting to"); 929 writer.println(" * decode the provided " + 930 "entry."); 931 writer.println(" */"); 932 writer.println(" public static " + className + 933 " decode(final Entry entry)"); 934 writer.println(" throws LDAPPersistException"); 935 writer.println(" {"); 936 writer.println(" return getPersister().decode(entry);"); 937 writer.println(" }"); 938 939 940 // Add the getPersister method. 941 writer.println(""); 942 writer.println(""); 943 writer.println(""); 944 writer.println(" /**"); 945 writer.println(" * Retrieves an {@code LDAPPersister} instance that " + 946 "may be used to interact"); 947 writer.println(" * with objects of this type."); 948 writer.println(" *"); 949 writer.println(" * @return An {@code LDAPPersister} instance that may " + 950 "be used to interact"); 951 writer.println(" * with objects of this type."); 952 writer.println(" *"); 953 writer.println(" * @throws LDAPPersistException If a problem occurs " + 954 "while creating the"); 955 writer.println(" * " + 956 "{@code LDAPPersister} instance."); 957 writer.println(" */"); 958 writer.println(" public static LDAPPersister<" + className + 959 "> getPersister()"); 960 writer.println(" throws LDAPPersistException"); 961 writer.println(" {"); 962 writer.println(" return LDAPPersister.getInstance(" + className + 963 ".class);"); 964 writer.println(" }"); 965 966 967 // Add the post-decode and post-encode methods. 968 writer.println(); 969 writer.println(); 970 writer.println(); 971 writer.println(" /**"); 972 writer.println(" * Performs any processing that may be necessary after " + 973 "initializing this"); 974 writer.println(" * object from an LDAP entry."); 975 writer.println(" *"); 976 writer.println(" * @throws LDAPPersistException If there is a " + 977 "problem with the object after"); 978 writer.println(" * it has been decoded " + 979 "from an LDAP entry."); 980 writer.println(" */"); 981 writer.println(" private void doPostDecode()"); 982 writer.println(" throws LDAPPersistException"); 983 writer.println(" {"); 984 writer.println(" // No processing is needed by default. You may " + 985 "provide an implementation"); 986 writer.println(" // for this method if custom post-decode processing " + 987 "is needed."); 988 writer.println(" }"); 989 writer.println(); 990 writer.println(); 991 writer.println(); 992 writer.println(" /**"); 993 writer.println(" * Performs any processing that may be necessary after " + 994 "encoding this object"); 995 writer.println(" * to an LDAP entry."); 996 writer.println(" *"); 997 writer.println(" * @param entry The entry that has been generated. " + 998 "It may be altered if"); 999 writer.println(" * desired."); 1000 writer.println(" *"); 1001 writer.println(" * @throws LDAPPersistException If the generated " + 1002 "entry should not be used."); 1003 writer.println(" */"); 1004 writer.println(" private void doPostEncode(final Entry entry)"); 1005 writer.println(" throws LDAPPersistException"); 1006 writer.println(" {"); 1007 writer.println(" // No processing is needed by default. You may " + 1008 "provide an implementation"); 1009 writer.println(" // for this method if custom post-encode processing " + 1010 "is needed."); 1011 writer.println(" }"); 1012 1013 1014 // Add a method for getting a read-only copy of the associated entry. 1015 writer.println(); 1016 writer.println(); 1017 writer.println(); 1018 writer.println(" /**"); 1019 writer.println(" * Retrieves a read-only copy of the entry with which " + 1020 "this object is"); 1021 writer.println(" * associated, if it is available. It will only be " + 1022 "available if this object"); 1023 writer.println(" * was decoded from or encoded to an LDAP entry."); 1024 writer.println(" *"); 1025 writer.println(" * @return A read-only copy of the entry with which " + 1026 "this object is"); 1027 writer.println(" * associated, or {@code null} if it is not " + 1028 "available."); 1029 writer.println(" */"); 1030 writer.println(" public ReadOnlyEntry getLDAPEntry()"); 1031 writer.println(" {"); 1032 writer.println(" return ldapEntry;"); 1033 writer.println(" }"); 1034 1035 1036 // Add a method for getting the DN of the associated entry. 1037 writer.println(); 1038 writer.println(); 1039 writer.println(); 1040 writer.println(" /**"); 1041 writer.println(" * Retrieves the DN of the entry with which this " + 1042 "object is associated, if it"); 1043 writer.println(" * is available. It will only be available if this " + 1044 "object was decoded from or"); 1045 writer.println(" * encoded to an LDAP entry."); 1046 writer.println(" *"); 1047 writer.println(" * @return The DN of the entry with which this object " + 1048 "is associated, or"); 1049 writer.println(" * {@code null} if it is not available."); 1050 writer.println(" */"); 1051 writer.println(" public String getLDAPEntryDN()"); 1052 writer.println(" {"); 1053 writer.println(" if (ldapEntry == null)"); 1054 writer.println(" {"); 1055 writer.println(" return null;"); 1056 writer.println(" }"); 1057 writer.println(" else"); 1058 writer.println(" {"); 1059 writer.println(" return ldapEntry.getDN();"); 1060 writer.println(" }"); 1061 writer.println(" }"); 1062 1063 1064 // Add getter, setter, and filter generation methods for all of the fields 1065 // associated with LDAP attributes. First the fields for the RDN 1066 // attributes, then for the rest of the required attributes, and then for 1067 // the optional attributes. 1068 for (final String lowerName : rdnAttrs) 1069 { 1070 final AttributeTypeDefinition d = requiredAttrs.get(lowerName); 1071 writeFieldMethods(writer, d, types.get(lowerName), true); 1072 } 1073 1074 for (final String lowerName : requiredAttrs.keySet()) 1075 { 1076 if (rdnAttrs.contains(lowerName)) 1077 { 1078 continue; 1079 } 1080 1081 final AttributeTypeDefinition d = requiredAttrs.get(lowerName); 1082 writeFieldMethods(writer, d, types.get(lowerName), true); 1083 } 1084 1085 for (final String lowerName : optionalAttrs.keySet()) 1086 { 1087 final AttributeTypeDefinition d = optionalAttrs.get(lowerName); 1088 writeFieldMethods(writer, d, types.get(lowerName), true); 1089 } 1090 1091 for (final String lowerName : operationalAttrs.keySet()) 1092 { 1093 final AttributeTypeDefinition d = operationalAttrs.get(lowerName); 1094 writeFieldMethods(writer, d, types.get(lowerName), false); 1095 } 1096 1097 writeToString(writer, className, requiredAttrs.values(), 1098 optionalAttrs.values(), operationalAttrs.values()); 1099 1100 writer.println("}"); 1101 writer.println(); 1102 writer.close(); 1103 1104 return ResultCode.SUCCESS; 1105 } 1106 1107 1108 1109 /** 1110 * Performs an appropriate set of processing for the provided object class to 1111 * ensure that all of the required and optional attributes are classified 1112 * properly. 1113 * 1114 * @param oc The object class to process. 1115 * @param s The server schema. 1116 * @param ra The set of required attributes identified so far. 1117 * @param rac The object classes referenced by the required attributes. 1118 * @param oa The set of optional attributes identified so far. 1119 * @param oac The object classes referenced by the optional attributes. 1120 * @param t A map of attribute type names to Java types. 1121 */ 1122 private void processObjectClass(final ObjectClassDefinition oc, 1123 final Schema s, 1124 final TreeMap<String,AttributeTypeDefinition> ra, 1125 final TreeMap<String,TreeSet<String>> rac, 1126 final TreeMap<String,AttributeTypeDefinition> oa, 1127 final TreeMap<String,TreeSet<String>> oac, 1128 final TreeMap<String,String> t) 1129 { 1130 for (final AttributeTypeDefinition d : oc.getRequiredAttributes(s, true)) 1131 { 1132 if (d.hasNameOrOID("objectClass")) 1133 { 1134 continue; 1135 } 1136 1137 final String lowerName = StaticUtils.toLowerCase(d.getNameOrOID()); 1138 if (ra.containsKey(lowerName)) 1139 { 1140 rac.get(lowerName).add(oc.getNameOrOID()); 1141 } 1142 else if (oa.containsKey(lowerName)) 1143 { 1144 oa.remove(lowerName); 1145 ra.put(lowerName, d); 1146 1147 final TreeSet<String> ocSet = oac.remove(lowerName); 1148 ocSet.add(oc.getNameOrOID()); 1149 rac.put(lowerName, ocSet); 1150 } 1151 else 1152 { 1153 final TreeSet<String> ocSet = new TreeSet<>(); 1154 ocSet.add(oc.getNameOrOID()); 1155 ra.put(lowerName, d); 1156 rac.put(lowerName, ocSet); 1157 t.put(lowerName, getJavaType(s, d)); 1158 } 1159 } 1160 1161 for (final AttributeTypeDefinition d : oc.getOptionalAttributes(s, true)) 1162 { 1163 if (d.hasNameOrOID("objectClass")) 1164 { 1165 continue; 1166 } 1167 1168 final String lowerName = StaticUtils.toLowerCase(d.getNameOrOID()); 1169 if (ra.containsKey(lowerName)) 1170 { 1171 rac.get(lowerName).add(oc.getNameOrOID()); 1172 } 1173 else if (oa.containsKey(lowerName)) 1174 { 1175 oac.get(lowerName).add(oc.getNameOrOID()); 1176 } 1177 else 1178 { 1179 final TreeSet<String> ocSet = new TreeSet<>(); 1180 ocSet.add(oc.getNameOrOID()); 1181 oa.put(lowerName, d); 1182 oac.put(lowerName, ocSet); 1183 t.put(lowerName, getJavaType(s, d)); 1184 } 1185 } 1186 } 1187 1188 1189 1190 /** 1191 * Writes information about a field to the Java class file. 1192 * 1193 * @param writer The writer to which the field information should be 1194 * written. 1195 * @param d The attribute type definition. 1196 * @param type The name of the Java type to use for the field. 1197 * @param ocNames The names of the object classes for the attribute type. 1198 * @param inRDN Indicates whether the attribute should be included in 1199 * generated entry RDNs. 1200 * @param required Indicates whether the attribute should be considered 1201 * required. 1202 * @param sc The name of the structural object class for the object. 1203 * @param lazy Indicates whether the field should be marked for lazy 1204 * loading. 1205 * @param terse Indicates whether to use terse mode. 1206 */ 1207 private static void writeField(final PrintWriter writer, 1208 final AttributeTypeDefinition d, final String type, 1209 final TreeSet<String> ocNames, 1210 final boolean inRDN, final boolean required, 1211 final String sc, final boolean lazy, 1212 final boolean terse) 1213 { 1214 final String attrName = d.getNameOrOID(); 1215 final String fieldName = PersistUtils.toJavaIdentifier(attrName); 1216 1217 writer.println(); 1218 1219 if (inRDN) 1220 { 1221 writer.println(" // The field used for RDN attribute " + attrName + '.'); 1222 } 1223 else if (required) 1224 { 1225 writer.println(" // The field used for required attribute " + attrName + 1226 '.'); 1227 } 1228 else if (d.isOperational()) 1229 { 1230 writer.println(" // The field used for operational attribute " + 1231 attrName + '.'); 1232 } 1233 else 1234 { 1235 writer.println(" // The field used for optional attribute " + attrName + 1236 '.'); 1237 } 1238 1239 boolean added = false; 1240 if (terse && attrName.equalsIgnoreCase(fieldName)) 1241 { 1242 writer.print(" @LDAPField("); 1243 } 1244 else 1245 { 1246 writer.print(" @LDAPField(attribute=\"" + attrName + '"'); 1247 added = true; 1248 } 1249 1250 if (ocNames.isEmpty()) 1251 { 1252 // Don't need to do anything. This should only be the case for 1253 // operational attributes. 1254 } 1255 else if (ocNames.size() == 1) 1256 { 1257 if ((! terse) || (! ocNames.iterator().next().equalsIgnoreCase(sc))) 1258 { 1259 if (added) 1260 { 1261 writer.println(","); 1262 writer.print(" objectClass=\"" + 1263 ocNames.iterator().next() + '"'); 1264 } 1265 else 1266 { 1267 writer.println("objectClass=\"" + 1268 ocNames.iterator().next() + '"'); 1269 added = true; 1270 } 1271 } 1272 } 1273 else 1274 { 1275 final Iterator<String> iterator = ocNames.iterator(); 1276 if (added) 1277 { 1278 writer.println(","); 1279 writer.println(" objectClass={ \"" + 1280 iterator.next() + "\","); 1281 } 1282 else 1283 { 1284 writer.println("objectClass={ \"" + 1285 iterator.next() + "\","); 1286 added = true; 1287 } 1288 1289 while (iterator.hasNext()) 1290 { 1291 final String name = iterator.next(); 1292 if (iterator.hasNext()) 1293 { 1294 writer.println(" \"" + name + "\","); 1295 } 1296 else 1297 { 1298 writer.print(" \"" + name + "\" }"); 1299 } 1300 } 1301 } 1302 1303 if (inRDN) 1304 { 1305 if (added) 1306 { 1307 writer.println(","); 1308 writer.println(" inRDN=true,"); 1309 } 1310 else 1311 { 1312 writer.println("inRDN=true,"); 1313 added = true; 1314 } 1315 writer.print(" filterUsage=FilterUsage.ALWAYS_ALLOWED"); 1316 } 1317 else 1318 { 1319 if (! terse) 1320 { 1321 if (added) 1322 { 1323 writer.println(","); 1324 writer.print(" " + 1325 "filterUsage=FilterUsage.CONDITIONALLY_ALLOWED"); 1326 } 1327 else 1328 { 1329 writer.print("filterUsage=FilterUsage.CONDITIONALLY_ALLOWED"); 1330 added = true; 1331 } 1332 } 1333 } 1334 1335 if (required) 1336 { 1337 if (added) 1338 { 1339 writer.println(","); 1340 writer.print(" requiredForEncode=true"); 1341 } 1342 else 1343 { 1344 writer.print("requiredForEncode=true"); 1345 added = true; 1346 } 1347 } 1348 1349 if (d.isOperational()) 1350 { 1351 if (added) 1352 { 1353 writer.println(","); 1354 writer.println(" inAdd=false,"); 1355 } 1356 else 1357 { 1358 writer.println("inAdd=false,"); 1359 added = true; 1360 } 1361 1362 writer.print(" inModify=false"); 1363 } 1364 1365 if (lazy) 1366 { 1367 if (added) 1368 { 1369 writer.println(","); 1370 writer.print(" lazilyLoad=true"); 1371 } 1372 else 1373 { 1374 writer.print("lazilyLoad=true"); 1375 added = true; 1376 } 1377 } 1378 1379 writer.println(")"); 1380 if (d.isSingleValued()) 1381 { 1382 writer.println(" private " + type + ' ' + fieldName + ';'); 1383 } 1384 else 1385 { 1386 writer.println(" private " + type + "[] " + fieldName + ';'); 1387 } 1388 } 1389 1390 1391 1392 /** 1393 * Writes getter, setter, and filter creation methods for the specified 1394 * attribute. 1395 * 1396 * @param writer The writer to use to write the methods. 1397 * @param d The attribute type definition to be written. 1398 * @param type The name of the Java type to use for the attribute. 1399 * @param addSetter Indicates whether to write a setter method. 1400 */ 1401 private static void writeFieldMethods(final PrintWriter writer, 1402 final AttributeTypeDefinition d, 1403 final String type, 1404 final boolean addSetter) 1405 { 1406 writer.println(); 1407 writer.println(); 1408 writer.println(); 1409 1410 final String attrName = d.getNameOrOID(); 1411 final String fieldName = PersistUtils.toJavaIdentifier(attrName); 1412 final String capFieldName = StaticUtils.capitalize(fieldName); 1413 1414 if (d.isSingleValued()) 1415 { 1416 if (type.equals("DN")) 1417 { 1418 writer.println(" /**"); 1419 writer.println(" * Retrieves the first value for the field " + 1420 "associated with the"); 1421 writer.println(" * " + attrName + " attribute as a DN, if present."); 1422 writer.println(" *"); 1423 writer.println(" * @return The first value for the field " + 1424 "associated with the"); 1425 writer.println(" * " + attrName + " attribute, or"); 1426 writer.println(" * {@code null} if the field does not " + 1427 "have a value."); 1428 writer.println(" */"); 1429 writer.println(" public DN get" + capFieldName + "DN()"); 1430 writer.println(" {"); 1431 writer.println(" return " + fieldName + ';'); 1432 writer.println(" }"); 1433 1434 writer.println(); 1435 writer.println(); 1436 writer.println(); 1437 1438 writer.println(" /**"); 1439 writer.println(" * Retrieves the object referenced by the DN held " + 1440 "in the"); 1441 writer.println(" * " + attrName + " attribute, if present."); 1442 writer.println(" *"); 1443 writer.println(" * @param <T> The type of object to return."); 1444 writer.println(" *"); 1445 writer.println(" * @param connection The connection to use to " + 1446 "retrieve the entry. It must"); 1447 writer.println(" * not be {@code null}."); 1448 writer.println(" * @param type The type of object as which " + 1449 "to decode the entry. It"); 1450 writer.println(" * must not be {@code null}, " + 1451 "and the class must be marked"); 1452 writer.println(" * with the {@code LDAPObject} " + 1453 "annotation type."); 1454 writer.println(" *"); 1455 writer.println(" * @return The object decoded from the entry with " + 1456 "the associated DN, or"); 1457 writer.println(" * {@code null} if the field does not " + 1458 "have a value or the referenced"); 1459 writer.println(" * entry does not exist."); 1460 writer.println(" *"); 1461 writer.println(" * @throws LDAPException If a problem occurs " + 1462 "while attempting to retrieve"); 1463 writer.println(" * the entry or decode it " + 1464 "as an object of the"); 1465 writer.println(" * specified type."); 1466 writer.println(" */"); 1467 writer.println(" public <T> T get" + capFieldName + "Object("); 1468 writer.println(" final LDAPInterface connection,"); 1469 writer.println(" final Class<T> type)"); 1470 writer.println(" throws LDAPException"); 1471 writer.println(" {"); 1472 writer.println(" return PersistUtils.getEntryAsObject(" + fieldName + 1473 ','); 1474 writer.println(" type, connection);"); 1475 writer.println(" }"); 1476 1477 if (addSetter) 1478 { 1479 writer.println(); 1480 writer.println(); 1481 writer.println(); 1482 1483 writer.println(" /**"); 1484 writer.println(" * Sets the value for the field associated with " + 1485 "the"); 1486 writer.println(" * " + attrName + " attribute."); 1487 writer.println(" *"); 1488 writer.println(" * @param v The value for the field associated " + 1489 "with the"); 1490 writer.println(" * " + attrName + " attribute."); 1491 writer.println(" */"); 1492 writer.println(" public void set" + capFieldName + "(final DN v)"); 1493 writer.println(" {"); 1494 writer.println(" this." + fieldName + " = v;"); 1495 writer.println(" }"); 1496 1497 writer.println(); 1498 writer.println(); 1499 writer.println(); 1500 1501 writer.println(" /**"); 1502 writer.println(" * Sets the value for the field associated with " + 1503 "the"); 1504 writer.println(" * " + attrName + " attribute."); 1505 writer.println(" *"); 1506 writer.println(" * @param v The string representation of the " + 1507 "value for the field associated"); 1508 writer.println(" * with the " + attrName + 1509 " attribute."); 1510 writer.println(" *"); 1511 writer.println(" * @throws LDAPException If the provided " + 1512 "string cannot be parsed as a DN."); 1513 writer.println(" */"); 1514 writer.println(" public void set" + capFieldName + 1515 "(final String v)"); 1516 writer.println(" throws LDAPException"); 1517 writer.println(" {"); 1518 writer.println(" if (v == null)"); 1519 writer.println(" {"); 1520 writer.println(" this." + fieldName + " = null;"); 1521 writer.println(" }"); 1522 writer.println(" else"); 1523 writer.println(" {"); 1524 writer.println(" this." + fieldName + " = new DN(v);"); 1525 writer.println(" }"); 1526 writer.println(" }"); 1527 } 1528 } 1529 else 1530 { 1531 writer.println(" /**"); 1532 writer.println(" * Retrieves the value for the field associated " + 1533 "with the"); 1534 writer.println(" * " + attrName + " attribute, if present."); 1535 writer.println(" *"); 1536 writer.println(" * @return The value for the field associated " + 1537 "with the"); 1538 writer.println(" * " + attrName + " attribute, or"); 1539 writer.println(" * {@code null} if the field does not " + 1540 "have a value."); 1541 writer.println(" */"); 1542 writer.println(" public " + type + " get" + capFieldName + "()"); 1543 writer.println(" {"); 1544 writer.println(" return " + fieldName + ';'); 1545 writer.println(" }"); 1546 1547 if (addSetter) 1548 { 1549 writer.println(); 1550 writer.println(); 1551 writer.println(); 1552 1553 writer.println(" /**"); 1554 writer.println(" * Sets the value for the field associated with " + 1555 "the"); 1556 writer.println(" * " + attrName + " attribute."); 1557 writer.println(" *"); 1558 writer.println(" * @param v The value for the field associated " + 1559 "with the"); 1560 writer.println(" * " + attrName + " attribute."); 1561 writer.println(" */"); 1562 writer.println(" public void set" + capFieldName + "(final " + type + 1563 " v)"); 1564 writer.println(" {"); 1565 writer.println(" this." + fieldName + " = v;"); 1566 writer.println(" }"); 1567 } 1568 } 1569 } 1570 else 1571 { 1572 if (type.equals("DN")) 1573 { 1574 writer.println(" /**"); 1575 writer.println(" * Retrieves the first value for the field " + 1576 "associated with the"); 1577 writer.println(" * " + attrName + " attribute as a DN, if present."); 1578 writer.println(" *"); 1579 writer.println(" * @return The first value for the field " + 1580 "associated with the"); 1581 writer.println(" * " + attrName + " attribute, or"); 1582 writer.println(" * {@code null} if that attribute was not " + 1583 "present in the entry or"); 1584 writer.println(" * does not have any values."); 1585 writer.println(" */"); 1586 writer.println(" public DN getFirst" + capFieldName + "DN()"); 1587 writer.println(" {"); 1588 writer.println(" if ((" + fieldName + " == null) ||"); 1589 writer.println(" (" + fieldName + ".length == 0))"); 1590 writer.println(" {"); 1591 writer.println(" return null;"); 1592 writer.println(" }"); 1593 writer.println(" else"); 1594 writer.println(" {"); 1595 writer.println(" return " + fieldName + "[0];"); 1596 writer.println(" }"); 1597 writer.println(" }"); 1598 1599 writer.println(); 1600 writer.println(); 1601 writer.println(); 1602 1603 writer.println(" /**"); 1604 writer.println(" * Retrieves the values for the field associated " + 1605 "with the"); 1606 writer.println(" * " + attrName + " attribute as DNs, if present."); 1607 writer.println(" *"); 1608 writer.println(" * @return The values for the field associated " + 1609 "with the"); 1610 writer.println(" * " + attrName + " attribute, or"); 1611 writer.println(" * {@code null} if that attribute was not " + 1612 "present in the entry."); 1613 writer.println(" */"); 1614 writer.println(" public DN[] get" + capFieldName + "DNs()"); 1615 writer.println(" {"); 1616 writer.println(" return " + fieldName + ';'); 1617 writer.println(" }"); 1618 1619 writer.println(); 1620 writer.println(); 1621 writer.println(); 1622 1623 writer.println(" /**"); 1624 writer.println(" * Retrieves the values for the field associated " + 1625 "with the"); 1626 writer.println(" * " + attrName + " attribute as objects of the " + 1627 "specified type,"); 1628 writer.println(" * if present."); 1629 writer.println(" *"); 1630 writer.println(" * @param <T> The type of object to return."); 1631 writer.println(" *"); 1632 writer.println(" * @param connection The connection to use to " + 1633 "retrieve the entries. It"); 1634 writer.println(" * must not be {@code null}."); 1635 writer.println(" * @param type The type of object as which " + 1636 "the entries should be"); 1637 writer.println(" * decoded. It must not be " + 1638 "{@code null}, and the class"); 1639 writer.println(" * must be marked with the " + 1640 "{@code LDAPObject} annotation"); 1641 writer.println(" * type."); 1642 writer.println(" *"); 1643 writer.println(" * @return A {@code PersistedObjects} object that " + 1644 "may be used to iterate"); 1645 writer.println(" * across the resulting objects."); 1646 writer.println(" *"); 1647 writer.println(" * @throws LDAPException If the requested type " + 1648 "cannot be used with the LDAP"); 1649 writer.println(" * SDK persistence " + 1650 "framework."); 1651 writer.println(" */"); 1652 writer.println(" public <T> PersistedObjects<T> get" + capFieldName + 1653 "Objects("); 1654 writer.println(" final " + 1655 "LDAPInterface connection,"); 1656 writer.println(" final Class<T> " + 1657 "type)"); 1658 writer.println(" throws LDAPException"); 1659 writer.println(" {"); 1660 writer.println(" return PersistUtils.getEntriesAsObjects(" + 1661 fieldName + ','); 1662 writer.println(" type, connection);"); 1663 writer.println(" }"); 1664 1665 if (addSetter) 1666 { 1667 writer.println(); 1668 writer.println(); 1669 writer.println(); 1670 1671 writer.println(" /**"); 1672 writer.println(" * Sets the values for the field associated with " + 1673 "the"); 1674 writer.println(" * " + attrName + " attribute."); 1675 writer.println(" *"); 1676 writer.println(" * @param v The values for the field " + 1677 "associated with the"); 1678 writer.println(" * " + attrName + " attribute."); 1679 writer.println(" */"); 1680 writer.println(" public void set" + capFieldName + 1681 "(final DN... v)"); 1682 writer.println(" {"); 1683 writer.println(" this." + fieldName + " = v;"); 1684 writer.println(" }"); 1685 1686 writer.println(); 1687 writer.println(); 1688 writer.println(); 1689 1690 writer.println(" /**"); 1691 writer.println(" * Sets the values for the field associated with " + 1692 "the"); 1693 writer.println(" * " + attrName + " attribute."); 1694 writer.println(" *"); 1695 writer.println(" * @param v The string representations of the " + 1696 "values for the field"); 1697 writer.println(" * associated with the " + attrName + 1698 " attribute."); 1699 writer.println(" *"); 1700 writer.println(" * @throws LDAPException If any of the " + 1701 "provided strings cannot be parsed as"); 1702 writer.println(" * a DN."); 1703 writer.println(" */"); 1704 writer.println(" public void set" + capFieldName + 1705 "(final String... v)"); 1706 writer.println(" throws LDAPException"); 1707 writer.println(" {"); 1708 writer.println(" if (v == null)"); 1709 writer.println(" {"); 1710 writer.println(" this." + fieldName + " = null;"); 1711 writer.println(" }"); 1712 writer.println(" else"); 1713 writer.println(" {"); 1714 writer.println(" this." + fieldName + " = new DN[v.length];"); 1715 writer.println(" for (int i=0; i < v.length; i++)"); 1716 writer.println(" {"); 1717 writer.println(" this." + fieldName + "[i] = new DN(v[i]);"); 1718 writer.println(" }"); 1719 writer.println(" }"); 1720 writer.println(" }"); 1721 } 1722 } 1723 else 1724 { 1725 writer.println(" /**"); 1726 writer.println(" * Retrieves the first value for the field " + 1727 "associated with the"); 1728 writer.println(" * " + attrName + " attribute, if present."); 1729 writer.println(" *"); 1730 writer.println(" * @return The first value for the field " + 1731 "associated with the"); 1732 writer.println(" * " + attrName + " attribute, or"); 1733 writer.println(" * {@code null} if that attribute was not " + 1734 "present in the entry or"); 1735 writer.println(" * does not have any values."); 1736 writer.println(" */"); 1737 writer.println(" public " + type + " getFirst" + capFieldName + "()"); 1738 writer.println(" {"); 1739 writer.println(" if ((" + fieldName + " == null) ||"); 1740 writer.println(" (" + fieldName + ".length == 0))"); 1741 writer.println(" {"); 1742 writer.println(" return null;"); 1743 writer.println(" }"); 1744 writer.println(" else"); 1745 writer.println(" {"); 1746 writer.println(" return " + fieldName + "[0];"); 1747 writer.println(" }"); 1748 writer.println(" }"); 1749 1750 writer.println(); 1751 writer.println(); 1752 writer.println(); 1753 1754 writer.println(" /**"); 1755 writer.println(" * Retrieves the values for the field associated " + 1756 "with the"); 1757 writer.println(" * " + attrName + " attribute, if present."); 1758 writer.println(" *"); 1759 writer.println(" * @return The values for the field associated " + 1760 "with the"); 1761 writer.println(" * " + attrName + " attribute, or"); 1762 writer.println(" * {@code null} if that attribute was not " + 1763 "present in the entry."); 1764 writer.println(" */"); 1765 writer.println(" public " + type + "[] get" + capFieldName + "()"); 1766 writer.println(" {"); 1767 writer.println(" return " + fieldName + ';'); 1768 writer.println(" }"); 1769 1770 if (addSetter) 1771 { 1772 writer.println(); 1773 writer.println(); 1774 writer.println(); 1775 1776 writer.println(" /**"); 1777 writer.println(" * Sets the values for the field associated with " + 1778 "the"); 1779 writer.println(" * " + attrName + " attribute."); 1780 writer.println(" *"); 1781 writer.println(" * @param v The values for the field " + 1782 "associated with the"); 1783 writer.println(" * " + attrName + " attribute."); 1784 writer.println(" */"); 1785 writer.println(" public void set" + capFieldName + "(final " + type + 1786 "... v)"); 1787 writer.println(" {"); 1788 writer.println(" this." + fieldName + " = v;"); 1789 writer.println(" }"); 1790 } 1791 } 1792 } 1793 1794 1795 writer.println(); 1796 writer.println(); 1797 writer.println(); 1798 1799 writer.println(" /**"); 1800 writer.println(" * Generates a filter that may be used to search for " + 1801 "objects of this type"); 1802 writer.println(" * using the " + attrName + " attribute."); 1803 writer.println(" * The resulting filter may be combined with other " + 1804 "filter elements to create a"); 1805 writer.println(" * more complex filter."); 1806 writer.println(" *"); 1807 writer.println(" * @param filterType The type of filter to generate."); 1808 writer.println(" * @param value The value to use to use for the " + 1809 "filter. It may be"); 1810 writer.println(" * {@code null} only for a filter " + 1811 "type of"); 1812 writer.println(" * {@code PRESENCE}."); 1813 writer.println(" *"); 1814 writer.println(" * @return The generated search filter."); 1815 writer.println(" *"); 1816 writer.println(" * @throws LDAPPersistException If a problem is " + 1817 "encountered while attempting"); 1818 writer.println(" * to generate the " + 1819 "filter."); 1820 writer.println(" */"); 1821 writer.println(" public static Filter generate" + capFieldName + 1822 "Filter("); 1823 writer.println(" final PersistFilterType " + 1824 "filterType,"); 1825 writer.println(" final " + type + " value)"); 1826 writer.println(" throws LDAPPersistException"); 1827 writer.println(" {"); 1828 writer.println(" final byte[] valueBytes;"); 1829 writer.println(" if (filterType == PersistFilterType.PRESENCE)"); 1830 writer.println(" {"); 1831 writer.println(" valueBytes = null;"); 1832 writer.println(" }"); 1833 writer.println(" else"); 1834 writer.println(" {"); 1835 writer.println(" if (value == null)"); 1836 writer.println(" {"); 1837 writer.println(" throw new LDAPPersistException(\"Unable to " + 1838 "generate a filter of type \" +"); 1839 writer.println(" filterType.name() + \" with a null value " + 1840 "for attribute \" +"); 1841 writer.println(" \"" + attrName + "\");"); 1842 writer.println(" }"); 1843 writer.println(); 1844 writer.println(" final LDAPObjectHandler<?> objectHandler ="); 1845 writer.println(" getPersister().getObjectHandler();"); 1846 writer.println(" final FieldInfo fieldInfo = " + 1847 "objectHandler.getFields().get("); 1848 writer.println(" \"" + StaticUtils.toLowerCase(attrName) + 1849 "\");"); 1850 writer.println(); 1851 writer.println(" final DefaultObjectEncoder objectEncoder = new " + 1852 "DefaultObjectEncoder();"); 1853 writer.println(" valueBytes = " + 1854 "objectEncoder.encodeFieldValue(fieldInfo.getField(),"); 1855 1856 if (d.isSingleValued()) 1857 { 1858 writer.println(" value,"); 1859 } 1860 else 1861 { 1862 writer.println(" new " + type + "[] { value },"); 1863 } 1864 1865 writer.println(" \"" + attrName + "\").getValueByteArray();"); 1866 writer.println(" }"); 1867 writer.println(); 1868 writer.println(" switch (filterType)"); 1869 writer.println(" {"); 1870 writer.println(" case PRESENCE:"); 1871 writer.println(" return Filter.createPresenceFilter("); 1872 writer.println(" \"" + attrName + "\");"); 1873 writer.println(" case EQUALITY:"); 1874 writer.println(" return Filter.createEqualityFilter("); 1875 writer.println(" \"" + attrName + "\","); 1876 writer.println(" valueBytes);"); 1877 writer.println(" case STARTS_WITH:"); 1878 writer.println(" return Filter.createSubstringFilter("); 1879 writer.println(" \"" + attrName + "\","); 1880 writer.println(" valueBytes, null, null);"); 1881 writer.println(" case ENDS_WITH:"); 1882 writer.println(" return Filter.createSubstringFilter("); 1883 writer.println(" \"" + attrName + "\","); 1884 writer.println(" null, null, valueBytes);"); 1885 writer.println(" case CONTAINS:"); 1886 writer.println(" return Filter.createSubstringFilter("); 1887 writer.println(" \"" + attrName + "\","); 1888 writer.println(" null, new byte[][] { valueBytes }, null);"); 1889 writer.println(" case GREATER_OR_EQUAL:"); 1890 writer.println(" return Filter.createGreaterOrEqualFilter("); 1891 writer.println(" \"" + attrName + "\","); 1892 writer.println(" valueBytes);"); 1893 writer.println(" case LESS_OR_EQUAL:"); 1894 writer.println(" return Filter.createLessOrEqualFilter("); 1895 writer.println(" \"" + attrName + "\","); 1896 writer.println(" valueBytes);"); 1897 writer.println(" case APPROXIMATELY_EQUAL_TO:"); 1898 writer.println(" return Filter.createApproximateMatchFilter("); 1899 writer.println(" \"" + attrName + "\","); 1900 writer.println(" valueBytes);"); 1901 writer.println(" default:"); 1902 writer.println(" // This should never happen."); 1903 writer.println(" throw new LDAPPersistException(\"Unrecognized " + 1904 "filter type \" +"); 1905 writer.println(" filterType.name());"); 1906 writer.println(" }"); 1907 writer.println(" }"); 1908 } 1909 1910 1911 1912 /** 1913 * Writes a {@code toString} method for the generated class. 1914 * 1915 * @param writer The writer to use to write the methods. 1916 * @param className The base name (without package information) for 1917 * the generated class. 1918 * @param requiredAttrs The set of required attributes for the generated 1919 * class. 1920 * @param optionalAttrs The set of optional attributes for the generated 1921 * class. 1922 * @param operationalAttrs The set of operational attributes for the 1923 * generated class. 1924 */ 1925 private static void writeToString(final PrintWriter writer, 1926 final String className, 1927 final Collection<AttributeTypeDefinition> requiredAttrs, 1928 final Collection<AttributeTypeDefinition> optionalAttrs, 1929 final Collection<AttributeTypeDefinition> operationalAttrs) 1930 { 1931 writer.println(); 1932 writer.println(); 1933 writer.println(); 1934 writer.println(" /**"); 1935 writer.println(" * Retrieves a string representation of this"); 1936 writer.println(" * {@code " + className + "} object."); 1937 writer.println(" *"); 1938 writer.println(" * @return A string representation of this"); 1939 writer.println(" * {@code " + className + "} object."); 1940 writer.println(" */"); 1941 writer.println(" @Override()"); 1942 writer.println(" public String toString()"); 1943 writer.println(" {"); 1944 writer.println(" final StringBuilder buffer = new StringBuilder();"); 1945 writer.println(" toString(buffer);"); 1946 writer.println(" return buffer.toString();"); 1947 writer.println(" }"); 1948 1949 writer.println(); 1950 writer.println(); 1951 writer.println(); 1952 writer.println(" /**"); 1953 writer.println(" * Appends a string representation of this"); 1954 writer.println(" * {@code " + className + "} object"); 1955 writer.println(" * to the provided buffer."); 1956 writer.println(" *"); 1957 writer.println(" * @param buffer The buffer to which the string " + 1958 "representation should be"); 1959 writer.println(" * appended."); 1960 writer.println(" */"); 1961 writer.println(" public void toString(final StringBuilder buffer)"); 1962 writer.println(" {"); 1963 writer.println(" buffer.append(\"" + className + "(\");"); 1964 writer.println(); 1965 writer.println(" boolean appended = false;"); 1966 writer.println(" if (ldapEntry != null)"); 1967 writer.println(" {"); 1968 writer.println(" appended = true;"); 1969 writer.println(" buffer.append(\"entryDN='\");"); 1970 writer.println(" buffer.append(ldapEntry.getDN());"); 1971 writer.println(" buffer.append('\\'');"); 1972 writer.println(" }"); 1973 1974 for (final AttributeTypeDefinition d : requiredAttrs) 1975 { 1976 writeToStringField(writer, d); 1977 } 1978 1979 for (final AttributeTypeDefinition d : optionalAttrs) 1980 { 1981 writeToStringField(writer, d); 1982 } 1983 1984 for (final AttributeTypeDefinition d : operationalAttrs) 1985 { 1986 writeToStringField(writer, d); 1987 } 1988 1989 writer.println(); 1990 writer.println(" buffer.append(')');"); 1991 writer.println(" }"); 1992 } 1993 1994 1995 1996 /** 1997 * Writes information about the provided field for use in the {@code toString} 1998 * method. 1999 * 2000 * @param w The writer to use to write the {@code toString} content. 2001 * @param d The attribute type definition for the field to write. 2002 */ 2003 private static void writeToStringField(final PrintWriter w, 2004 final AttributeTypeDefinition d) 2005 { 2006 final String fieldName = PersistUtils.toJavaIdentifier(d.getNameOrOID()); 2007 w.println(); 2008 w.println(" if (" + fieldName + " != null)"); 2009 w.println(" {"); 2010 w.println(" if (appended)"); 2011 w.println(" {"); 2012 w.println(" buffer.append(\", \");"); 2013 w.println(" }"); 2014 w.println(" appended = true;"); 2015 w.println(" buffer.append(\"" + fieldName + "=\");"); 2016 if (d.isSingleValued()) 2017 { 2018 w.println(" buffer.append(" + fieldName + ");"); 2019 } 2020 else 2021 { 2022 w.println(" buffer.append(Arrays.toString(" + fieldName + "));"); 2023 } 2024 w.println(" }"); 2025 } 2026 2027 2028 2029 /** 2030 * Retrieves the Java type to use for the provided attribute type definition. 2031 * For multi-valued attributes, the value returned will be the base type 2032 * without square brackets to indicate an array. 2033 * 2034 * @param schema The schema to use to determine the syntax for the 2035 * attribute. 2036 * @param d The attribute type definition for which to get the Java 2037 * type. 2038 * 2039 * @return The Java type to use for the provided attribute type definition. 2040 */ 2041 private String getJavaType(final Schema schema, 2042 final AttributeTypeDefinition d) 2043 { 2044 if (! d.isSingleValued()) 2045 { 2046 needArrays = true; 2047 } 2048 2049 final String syntaxOID = d.getSyntaxOID(schema); 2050 if (syntaxOID == null) 2051 { 2052 return "String"; 2053 } 2054 2055 final String oid; 2056 final int bracePos = syntaxOID.indexOf('{'); 2057 if (bracePos > 0) 2058 { 2059 oid = syntaxOID.substring(0, bracePos); 2060 } 2061 else 2062 { 2063 oid = syntaxOID; 2064 } 2065 2066 if (oid.equals("1.3.6.1.4.1.1466.115.121.1.7")) 2067 { 2068 // Boolean 2069 return "Boolean"; 2070 } 2071 else if (oid.equals("1.3.6.1.4.1.4203.1.1.2") || 2072 oid.equals("1.3.6.1.4.1.1466.115.121.1.5") || 2073 oid.equals("1.3.6.1.4.1.1466.115.121.1.8") || 2074 oid.equals("1.3.6.1.4.1.1466.115.121.1.9") || 2075 oid.equals("1.3.6.1.4.1.1466.115.121.1.10") || 2076 oid.equals("1.3.6.1.4.1.1466.115.121.1.28") || 2077 oid.equals("1.3.6.1.4.1.1466.115.121.1.40")) 2078 { 2079 // auth password 2080 // binary 2081 // certificate 2082 // certificate list 2083 // certificate pair 2084 // JPEG 2085 // octet string 2086 return "byte[]"; 2087 } 2088 else if (oid.equals("1.3.6.1.4.1.1466.115.121.1.24")) 2089 { 2090 // generalized time. 2091 needDate = true; 2092 return "Date"; 2093 } 2094 else if (oid.equals("1.3.6.1.4.1.1466.115.121.1.27")) 2095 { 2096 // integer 2097 return "Long"; 2098 } 2099 else if (oid.equals("1.3.6.1.4.1.1466.115.121.1.12") || 2100 oid.equals("1.3.6.1.4.1.1466.115.121.1.34")) 2101 { 2102 // DN 2103 // name and optional UID 2104 needDN = true; 2105 if (! d.isSingleValued()) 2106 { 2107 needPersistedObjects = true; 2108 } 2109 return "DN"; 2110 } 2111 else 2112 { 2113 return "String"; 2114 } 2115 } 2116 2117 2118 2119 /** 2120 * {@inheritDoc} 2121 */ 2122 @Override() 2123 public LinkedHashMap<String[],String> getExampleUsages() 2124 { 2125 final LinkedHashMap<String[],String> examples = 2126 new LinkedHashMap<>(StaticUtils.computeMapCapacity(1)); 2127 2128 final String[] args = 2129 { 2130 "--hostname", "server.example.com", 2131 "--port", "389", 2132 "--bindDN", "uid=admin,dc=example,dc=com", 2133 "--bindPassword", "password", 2134 "--outputDirectory", "src/com/example", 2135 "--structuralClass", "myStructuralClass", 2136 "--auxiliaryClass", "auxClass1", 2137 "--auxiliaryClass", "auxClass2", 2138 "--rdnAttribute", "cn", 2139 "--defaultParentDN", "dc=example,dc=com", 2140 "--packageName", "com.example", 2141 "--className", "MyObject" 2142 }; 2143 examples.put(args, INFO_GEN_SOURCE_EXAMPLE_1.get()); 2144 2145 return examples; 2146 } 2147}