001/* 002 * Copyright 2009-2017 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2009-2017 UnboundID Corp. 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.LDAPCommandLineTool; 052import com.unboundid.util.Mutable; 053import com.unboundid.util.ThreadSafety; 054import com.unboundid.util.ThreadSafetyLevel; 055import com.unboundid.util.args.ArgumentException; 056import com.unboundid.util.args.ArgumentParser; 057import com.unboundid.util.args.BooleanArgument; 058import com.unboundid.util.args.DNArgument; 059import com.unboundid.util.args.FileArgument; 060import com.unboundid.util.args.StringArgument; 061 062import static com.unboundid.ldap.sdk.persist.PersistMessages.*; 063import static com.unboundid.util.Debug.*; 064import static com.unboundid.util.StaticUtils.*; 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<String>(); 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"); 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"); 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"); 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"); 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"); 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"); 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"); 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"); 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"); 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 (LDAPException le) 416 { 417 debugException(le); 418 err(ERR_GEN_SOURCE_CANNOT_CONNECT.get(getExceptionMessage(le))); 419 return le.getResultCode(); 420 } 421 422 final Schema schema; 423 try 424 { 425 schema = conn.getSchema(); 426 if (schema == null) 427 { 428 err(ERR_GEN_SOURCE_CANNOT_READ_SCHEMA.get( 429 ERR_GEN_SOURCE_SCHEMA_NOT_RETURNED.get())); 430 return ResultCode.NO_RESULTS_RETURNED; 431 } 432 } 433 catch (LDAPException le) 434 { 435 debugException(le); 436 err(ERR_GEN_SOURCE_CANNOT_READ_SCHEMA.get(getExceptionMessage(le))); 437 return le.getResultCode(); 438 } 439 finally 440 { 441 conn.close(); 442 } 443 444 return generateSourceFile(schema, terseArg.isPresent()); 445 } 446 447 448 449 /** 450 * Generates the source file using the information in the provided schema. 451 * 452 * @param schema The schema to use to generate the source file. 453 * @param terse Indicates whether to use terse mode when generating the 454 * source file. If this is {@code true}, then all optional 455 * elements will be omitted from annotations. 456 * 457 * @return A result code obtained for the processing. 458 */ 459 private ResultCode generateSourceFile(final Schema schema, 460 final boolean terse) 461 { 462 // Retrieve and process the structural object class. 463 final TreeMap<String,AttributeTypeDefinition> requiredAttrs = 464 new TreeMap<String,AttributeTypeDefinition>(); 465 final TreeMap<String,AttributeTypeDefinition> optionalAttrs = 466 new TreeMap<String,AttributeTypeDefinition>(); 467 final TreeMap<String,TreeSet<String>> requiredAttrOCs = 468 new TreeMap<String,TreeSet<String>>(); 469 final TreeMap<String,TreeSet<String>> optionalAttrOCs = 470 new TreeMap<String,TreeSet<String>>(); 471 final TreeMap<String,String> types = new TreeMap<String,String>(); 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 = 495 new TreeMap<String,ObjectClassDefinition>(); 496 if (auxiliaryClassArg.isPresent()) 497 { 498 for (final String s : auxiliaryClassArg.getValues()) 499 { 500 final ObjectClassDefinition oc = schema.getObjectClass(s); 501 if (oc == null) 502 { 503 err(ERR_GEN_SOURCE_AUXILIARY_CLASS_NOT_FOUND.get(s)); 504 return ResultCode.PARAM_ERROR; 505 } 506 507 if (oc.getObjectClassType(schema) != ObjectClassType.AUXILIARY) 508 { 509 err(ERR_GEN_SOURCE_AUXILIARY_CLASS_NOT_AUXILIARY.get(s)); 510 return ResultCode.PARAM_ERROR; 511 } 512 513 auxiliaryOCs.put(toLowerCase(s), oc); 514 515 processObjectClass(oc, schema, requiredAttrs, requiredAttrOCs, 516 optionalAttrs, optionalAttrOCs, types); 517 } 518 } 519 520 521 // Determine the appropriate set of superior object classes. 522 final TreeMap<String,ObjectClassDefinition> superiorOCs = 523 new TreeMap<String,ObjectClassDefinition>(); 524 for (final ObjectClassDefinition s : 525 structuralOC.getSuperiorClasses(schema, true)) 526 { 527 superiorOCs.put(toLowerCase(s.getNameOrOID()), s); 528 } 529 530 for (final ObjectClassDefinition d : auxiliaryOCs.values()) 531 { 532 for (final ObjectClassDefinition s : d.getSuperiorClasses(schema, true)) 533 { 534 superiorOCs.put(toLowerCase(s.getNameOrOID()), s); 535 } 536 } 537 538 superiorOCs.remove(toLowerCase(structuralClassName)); 539 for (final String s : auxiliaryOCs.keySet()) 540 { 541 superiorOCs.remove(s); 542 } 543 544 545 // Retrieve and process the operational attributes. 546 final TreeMap<String,AttributeTypeDefinition> operationalAttrs = 547 new TreeMap<String,AttributeTypeDefinition>(); 548 if (operationalAttributeArg.isPresent()) 549 { 550 for (final String s : operationalAttributeArg.getValues()) 551 { 552 final AttributeTypeDefinition d = schema.getAttributeType(s); 553 if (d == null) 554 { 555 err(ERR_GEN_SOURCE_OPERATIONAL_ATTRIBUTE_NOT_DEFINED.get(s)); 556 return ResultCode.PARAM_ERROR; 557 } 558 else if (! d.isOperational()) 559 { 560 err(ERR_GEN_SOURCE_OPERATIONAL_ATTRIBUTE_NOT_OPERATIONAL.get(s)); 561 return ResultCode.PARAM_ERROR; 562 } 563 else 564 { 565 final String lowerName = toLowerCase(s); 566 operationalAttrs.put(lowerName, d); 567 types.put(lowerName, getJavaType(schema, d)); 568 } 569 } 570 } 571 572 573 // Make sure all of the configured RDN attributes are allowed by at least 574 // one of the associated object classes. 575 final TreeSet<String> rdnAttrs = new TreeSet<String>(); 576 for (final String s : rdnAttributeArg.getValues()) 577 { 578 final AttributeTypeDefinition d = schema.getAttributeType(s); 579 if (d == null) 580 { 581 err(ERR_GEN_SOURCE_RDN_ATTRIBUTE_NOT_DEFINED.get(s)); 582 return ResultCode.PARAM_ERROR; 583 } 584 585 final String lowerName = toLowerCase(d.getNameOrOID()); 586 rdnAttrs.add(lowerName); 587 if (requiredAttrs.containsKey(lowerName)) 588 { 589 // No action required. 590 } 591 else if (optionalAttrs.containsKey(lowerName)) 592 { 593 // Move the attribute to the required set. 594 requiredAttrs.put(lowerName, optionalAttrs.remove(lowerName)); 595 requiredAttrOCs.put(lowerName, optionalAttrOCs.remove(lowerName)); 596 } 597 else 598 { 599 err(ERR_GEN_SOURCE_RDN_ATTRIBUTE_NOT_DEFINED.get(s)); 600 return ResultCode.PARAM_ERROR; 601 } 602 } 603 604 605 // Make sure all of the configured lazily-loaded attributes are allowed by 606 // at least one of the associated object classes or matches a configured 607 // operational attribute. 608 final TreeSet<String> lazyAttrs = new TreeSet<String>(); 609 for (final String s : lazyAttributeArg.getValues()) 610 { 611 final AttributeTypeDefinition d = schema.getAttributeType(s); 612 if (d == null) 613 { 614 err(ERR_GEN_SOURCE_LAZY_ATTRIBUTE_NOT_DEFINED.get(s)); 615 return ResultCode.PARAM_ERROR; 616 } 617 618 final String lowerName = toLowerCase(d.getNameOrOID()); 619 lazyAttrs.add(lowerName); 620 if (requiredAttrs.containsKey(lowerName) || 621 optionalAttrs.containsKey(lowerName) || 622 operationalAttrs.containsKey(lowerName)) 623 { 624 // No action required. 625 } 626 else 627 { 628 err(ERR_GEN_SOURCE_LAZY_ATTRIBUTE_NOT_ALLOWED.get(s)); 629 return ResultCode.PARAM_ERROR; 630 } 631 } 632 633 634 final String className; 635 if (classNameArg.isPresent()) 636 { 637 className = classNameArg.getValue(); 638 final StringBuilder invalidReason = new StringBuilder(); 639 if (! PersistUtils.isValidJavaIdentifier(className, invalidReason)) 640 { 641 err(ERR_GEN_SOURCE_INVALID_CLASS_NAME.get(className, 642 invalidReason.toString())); 643 return ResultCode.PARAM_ERROR; 644 } 645 } 646 else 647 { 648 className = 649 capitalize(PersistUtils.toJavaIdentifier(structuralClassName)); 650 } 651 652 653 final File sourceFile = new File(outputDirectoryArg.getValue(), 654 className + ".java"); 655 final PrintWriter writer; 656 try 657 { 658 writer = new PrintWriter(new FileWriter(sourceFile)); 659 } 660 catch (Exception e) 661 { 662 debugException(e); 663 err(ERR_GEN_SOURCE_CANNOT_CREATE_WRITER.get(sourceFile.getAbsolutePath(), 664 getExceptionMessage(e))); 665 return ResultCode.LOCAL_ERROR; 666 } 667 668 669 if (packageNameArg.isPresent()) 670 { 671 final String packageName = packageNameArg.getValue(); 672 if (packageName.length() > 0) 673 { 674 writer.println("package " + packageName + ';'); 675 writer.println(); 676 writer.println(); 677 writer.println(); 678 } 679 } 680 681 boolean javaImports = false; 682 if (needArrays) 683 { 684 writer.println("import " + Arrays.class.getName() + ';'); 685 javaImports = true; 686 } 687 688 if (needDate) 689 { 690 writer.println("import " + Date.class.getName() + ';'); 691 javaImports = true; 692 } 693 694 if (javaImports) 695 { 696 writer.println(); 697 } 698 699 if (needDN) 700 { 701 writer.println("import " + DN.class.getName() + ';'); 702 } 703 704 writer.println("import " + Entry.class.getName() + ';'); 705 writer.println("import " + Filter.class.getName() + ';'); 706 707 if (needDN) 708 { 709 writer.println("import " + LDAPException.class.getName() + ';'); 710 writer.println("import " + LDAPInterface.class.getName() + ';'); 711 } 712 713 writer.println("import " + ReadOnlyEntry.class.getName() + ';'); 714 writer.println("import " + DefaultObjectEncoder.class.getName() + ';'); 715 writer.println("import " + FieldInfo.class.getName() + ';'); 716 writer.println("import " + FilterUsage.class.getName() + ';'); 717 writer.println("import " + LDAPEntryField.class.getName() + ';'); 718 writer.println("import " + LDAPField.class.getName() + ';'); 719 writer.println("import " + LDAPObject.class.getName() + ';'); 720 writer.println("import " + LDAPObjectHandler.class.getName() + ';'); 721 writer.println("import " + LDAPPersister.class.getName() + ';'); 722 writer.println("import " + LDAPPersistException.class.getName() + ';'); 723 724 if (needPersistedObjects) 725 { 726 writer.println("import " + PersistedObjects.class.getName() + ';'); 727 } 728 729 writer.println("import " + PersistFilterType.class.getName() + ';'); 730 731 if (needDN) 732 { 733 writer.println("import " + PersistUtils.class.getName() + ';'); 734 } 735 736 writer.println(); 737 writer.println(); 738 writer.println(); 739 writer.println("/**"); 740 writer.println(" * This class provides an implementation of an object " + 741 "that can be used to"); 742 writer.println(" * represent " + structuralClassName + 743 " objects in the directory."); 744 writer.println(" * It was generated by the " + getToolName() + 745 " tool provided with the"); 746 writer.println(" * UnboundID LDAP SDK for Java. It " + 747 "may be customized as desired to better suit"); 748 writer.println(" * your needs."); 749 writer.println(" */"); 750 writer.println("@LDAPObject(structuralClass=\"" + structuralClassName + 751 "\","); 752 753 switch (auxiliaryOCs.size()) 754 { 755 case 0: 756 // No action required. 757 break; 758 759 case 1: 760 writer.println(" auxiliaryClass=\"" + 761 auxiliaryOCs.values().iterator().next().getNameOrOID() + "\","); 762 break; 763 764 default: 765 final Iterator<ObjectClassDefinition> iterator = 766 auxiliaryOCs.values().iterator(); 767 writer.println(" auxiliaryClass={ \"" + 768 iterator.next().getNameOrOID() + "\","); 769 while (iterator.hasNext()) 770 { 771 final String ocName = iterator.next().getNameOrOID(); 772 if (iterator.hasNext()) 773 { 774 writer.println(" \"" + ocName + 775 "\","); 776 } 777 else 778 { 779 writer.println(" \"" + ocName + 780 "\" },"); 781 } 782 } 783 break; 784 } 785 786 switch (superiorOCs.size()) 787 { 788 case 0: 789 // No action required. 790 break; 791 792 case 1: 793 writer.println(" superiorClass=\"" + 794 superiorOCs.values().iterator().next().getNameOrOID() + "\","); 795 break; 796 797 default: 798 final Iterator<ObjectClassDefinition> iterator = 799 superiorOCs.values().iterator(); 800 writer.println(" superiorClass={ \"" + 801 iterator.next().getNameOrOID() + "\","); 802 while (iterator.hasNext()) 803 { 804 final String ocName = iterator.next().getNameOrOID(); 805 if (iterator.hasNext()) 806 { 807 writer.println(" \"" + ocName + 808 "\","); 809 } 810 else 811 { 812 writer.println(" \"" + ocName + 813 "\" },"); 814 } 815 } 816 break; 817 } 818 819 if (defaultParentDNArg.isPresent()) 820 { 821 writer.println(" defaultParentDN=\"" + 822 defaultParentDNArg.getValue() + "\","); 823 } 824 825 writer.println(" postDecodeMethod=\"doPostDecode\","); 826 writer.println(" postEncodeMethod=\"doPostEncode\")"); 827 writer.println("public class " + className); 828 writer.println("{"); 829 830 if (! terse) 831 { 832 writer.println(" /*"); 833 writer.println(" * NOTE: This class includes a number of annotation " + 834 "elements which are not"); 835 writer.println(" * required but have been provided to make it easier " + 836 "to edit the resulting"); 837 writer.println(" * source code. If you want to exclude these " + 838 "unnecessary annotation"); 839 writer.println(" * elements, use the '--terse' command-line argument."); 840 writer.println(" */"); 841 writer.println(); 842 writer.println(); 843 writer.println(); 844 } 845 846 writer.println(" // The field to use to hold a read-only copy of the " + 847 "associated entry."); 848 writer.println(" @LDAPEntryField()"); 849 writer.println(" private ReadOnlyEntry ldapEntry;"); 850 851 852 // Add all of the fields. First the fields for the RDN attributes, then 853 // for the rest of the required attributes, then for the optional 854 // attributes, and finally any operational attributes. 855 for (final String lowerName : rdnAttrs) 856 { 857 final AttributeTypeDefinition d = requiredAttrs.get(lowerName); 858 final TreeSet<String> ocNames = requiredAttrOCs.get(lowerName); 859 writeField(writer, d, types.get(lowerName), ocNames, true, true, 860 structuralClassName, false, terse); 861 } 862 863 for (final String lowerName : requiredAttrs.keySet()) 864 { 865 if (rdnAttrs.contains(lowerName)) 866 { 867 continue; 868 } 869 870 final AttributeTypeDefinition d = requiredAttrs.get(lowerName); 871 final TreeSet<String> ocNames = requiredAttrOCs.get(lowerName); 872 writeField(writer, d, types.get(lowerName), ocNames, false, true, 873 structuralClassName, lazyAttrs.contains(lowerName), terse); 874 } 875 876 for (final String lowerName : optionalAttrs.keySet()) 877 { 878 final AttributeTypeDefinition d = optionalAttrs.get(lowerName); 879 final TreeSet<String> ocNames = optionalAttrOCs.get(lowerName); 880 writeField(writer, d, types.get(lowerName), ocNames, false, false, 881 structuralClassName, lazyAttrs.contains(lowerName), terse); 882 } 883 884 for (final String lowerName : operationalAttrs.keySet()) 885 { 886 final AttributeTypeDefinition d = operationalAttrs.get(lowerName); 887 final TreeSet<String> ocNames = EMPTY_TREE_SET; 888 writeField(writer, d, types.get(lowerName), ocNames, false, false, 889 structuralClassName, lazyAttrs.contains(lowerName), terse); 890 } 891 892 893 // Add the default constructor. 894 writer.println(); 895 writer.println(); 896 writer.println(); 897 writer.println(" /**"); 898 writer.println(" * Creates a new instance of this object. All fields " + 899 "will be uninitialized,"); 900 writer.println(" * so the setter methods should be used to assign " + 901 "values to them."); 902 writer.println(" */"); 903 writer.println(" public " + className + "()"); 904 writer.println(" {"); 905 writer.println(" // No initialization will be performed by default. " + 906 "Note that if you set"); 907 writer.println(" // values for any fields marked with an @LDAPField, " + 908 "@LDAPDNField, or"); 909 writer.println(" // @LDAPEntryField annotation, they will be " + 910 "overwritten in the course of"); 911 writer.println(" // decoding initializing this object from an LDAP " + 912 "entry."); 913 writer.println(" }"); 914 915 916 // Add a static decode method that can create an instance of the object 917 // from a given entry. 918 writer.println(); 919 writer.println(); 920 writer.println(); 921 writer.println(" /**"); 922 writer.println(" * Creates a new " + className + " object decoded"); 923 writer.println(" * from the provided entry."); 924 writer.println(" *"); 925 writer.println(" * @param entry The entry to be decoded."); 926 writer.println(" *"); 927 writer.println(" * @return The decoded " + className + " object."); 928 writer.println(" *"); 929 writer.println(" * @throws LDAPPersistException If a problem occurs " + 930 "while attempting to"); 931 writer.println(" * decode the provided " + 932 "entry."); 933 writer.println(" */"); 934 writer.println(" public static " + className + 935 " decode(final Entry entry)"); 936 writer.println(" throws LDAPPersistException"); 937 writer.println(" {"); 938 writer.println(" return getPersister().decode(entry);"); 939 writer.println(" }"); 940 941 942 // Add the getPersister method. 943 writer.println(""); 944 writer.println(""); 945 writer.println(""); 946 writer.println(" /**"); 947 writer.println(" * Retrieves an {@code LDAPPersister} instance that " + 948 "may be used to interact"); 949 writer.println(" * with objects of this type."); 950 writer.println(" *"); 951 writer.println(" * @return An {@code LDAPPersister} instance that may " + 952 "be used to interact"); 953 writer.println(" * with objects of this type."); 954 writer.println(" *"); 955 writer.println(" * @throws LDAPPersistException If a problem occurs " + 956 "while creating the"); 957 writer.println(" * " + 958 "{@code LDAPPersister} instance."); 959 writer.println(" */"); 960 writer.println(" public static LDAPPersister<" + className + 961 "> getPersister()"); 962 writer.println(" throws LDAPPersistException"); 963 writer.println(" {"); 964 writer.println(" return LDAPPersister.getInstance(" + className + 965 ".class);"); 966 writer.println(" }"); 967 968 969 // Add the post-decode and post-encode methods. 970 writer.println(); 971 writer.println(); 972 writer.println(); 973 writer.println(" /**"); 974 writer.println(" * Performs any processing that may be necessary after " + 975 "initializing this"); 976 writer.println(" * object from an LDAP entry."); 977 writer.println(" *"); 978 writer.println(" * @throws LDAPPersistException If there is a " + 979 "problem with the object after"); 980 writer.println(" * it has been decoded " + 981 "from an LDAP entry."); 982 writer.println(" */"); 983 writer.println(" private void doPostDecode()"); 984 writer.println(" throws LDAPPersistException"); 985 writer.println(" {"); 986 writer.println(" // No processing is needed by default. You may " + 987 "provide an implementation"); 988 writer.println(" // for this method if custom post-decode processing " + 989 "is needed."); 990 writer.println(" }"); 991 writer.println(); 992 writer.println(); 993 writer.println(); 994 writer.println(" /**"); 995 writer.println(" * Performs any processing that may be necessary after " + 996 "encoding this object"); 997 writer.println(" * to an LDAP entry."); 998 writer.println(" *"); 999 writer.println(" * @param entry The entry that has been generated. " + 1000 "It may be altered if"); 1001 writer.println(" * desired."); 1002 writer.println(" *"); 1003 writer.println(" * @throws LDAPPersistException If the generated " + 1004 "entry should not be used."); 1005 writer.println(" */"); 1006 writer.println(" private void doPostEncode(final Entry entry)"); 1007 writer.println(" throws LDAPPersistException"); 1008 writer.println(" {"); 1009 writer.println(" // No processing is needed by default. You may " + 1010 "provide an implementation"); 1011 writer.println(" // for this method if custom post-encode processing " + 1012 "is needed."); 1013 writer.println(" }"); 1014 1015 1016 // Add a method for getting a read-only copy of the associated entry. 1017 writer.println(); 1018 writer.println(); 1019 writer.println(); 1020 writer.println(" /**"); 1021 writer.println(" * Retrieves a read-only copy of the entry with which " + 1022 "this object is"); 1023 writer.println(" * associated, if it is available. It will only be " + 1024 "available if this object"); 1025 writer.println(" * was decoded from or encoded to an LDAP entry."); 1026 writer.println(" *"); 1027 writer.println(" * @return A read-only copy of the entry with which " + 1028 "this object is"); 1029 writer.println(" * associated, or {@code null} if it is not " + 1030 "available."); 1031 writer.println(" */"); 1032 writer.println(" public ReadOnlyEntry getLDAPEntry()"); 1033 writer.println(" {"); 1034 writer.println(" return ldapEntry;"); 1035 writer.println(" }"); 1036 1037 1038 // Add a method for getting the DN of the associated entry. 1039 writer.println(); 1040 writer.println(); 1041 writer.println(); 1042 writer.println(" /**"); 1043 writer.println(" * Retrieves the DN of the entry with which this " + 1044 "object is associated, if it"); 1045 writer.println(" * is available. It will only be available if this " + 1046 "object was decoded from or"); 1047 writer.println(" * encoded to an LDAP entry."); 1048 writer.println(" *"); 1049 writer.println(" * @return The DN of the entry with which this object " + 1050 "is associated, or"); 1051 writer.println(" * {@code null} if it is not available."); 1052 writer.println(" */"); 1053 writer.println(" public String getLDAPEntryDN()"); 1054 writer.println(" {"); 1055 writer.println(" if (ldapEntry == null)"); 1056 writer.println(" {"); 1057 writer.println(" return null;"); 1058 writer.println(" }"); 1059 writer.println(" else"); 1060 writer.println(" {"); 1061 writer.println(" return ldapEntry.getDN();"); 1062 writer.println(" }"); 1063 writer.println(" }"); 1064 1065 1066 // Add getter, setter, and filter generation methods for all of the fields 1067 // associated with LDAP attributes. First the fields for the RDN 1068 // attributes, then for the rest of the required attributes, and then for 1069 // the optional attributes. 1070 for (final String lowerName : rdnAttrs) 1071 { 1072 final AttributeTypeDefinition d = requiredAttrs.get(lowerName); 1073 writeFieldMethods(writer, d, types.get(lowerName), true); 1074 } 1075 1076 for (final String lowerName : requiredAttrs.keySet()) 1077 { 1078 if (rdnAttrs.contains(lowerName)) 1079 { 1080 continue; 1081 } 1082 1083 final AttributeTypeDefinition d = requiredAttrs.get(lowerName); 1084 writeFieldMethods(writer, d, types.get(lowerName), true); 1085 } 1086 1087 for (final String lowerName : optionalAttrs.keySet()) 1088 { 1089 final AttributeTypeDefinition d = optionalAttrs.get(lowerName); 1090 writeFieldMethods(writer, d, types.get(lowerName), true); 1091 } 1092 1093 for (final String lowerName : operationalAttrs.keySet()) 1094 { 1095 final AttributeTypeDefinition d = operationalAttrs.get(lowerName); 1096 writeFieldMethods(writer, d, types.get(lowerName), false); 1097 } 1098 1099 writeToString(writer, className, requiredAttrs.values(), 1100 optionalAttrs.values(), operationalAttrs.values()); 1101 1102 writer.println("}"); 1103 writer.println(); 1104 writer.close(); 1105 1106 return ResultCode.SUCCESS; 1107 } 1108 1109 1110 1111 1112 1113 /** 1114 * Performs an appropriate set of processing for the provided object class to 1115 * ensure that all of the required and optional attributes are classified 1116 * properly. 1117 * 1118 * @param oc The object class to process. 1119 * @param s The server schema. 1120 * @param ra The set of required attributes identified so far. 1121 * @param rac The object classes referenced by the required attributes. 1122 * @param oa The set of optional attributes identified so far. 1123 * @param oac The object classes referenced by the optional attributes. 1124 * @param t A map of attribute type names to Java types. 1125 */ 1126 void processObjectClass(final ObjectClassDefinition oc, final Schema s, 1127 final TreeMap<String,AttributeTypeDefinition> ra, 1128 final TreeMap<String,TreeSet<String>> rac, 1129 final TreeMap<String,AttributeTypeDefinition> oa, 1130 final TreeMap<String,TreeSet<String>> oac, 1131 final TreeMap<String,String> t) 1132 { 1133 for (final AttributeTypeDefinition d : oc.getRequiredAttributes(s, true)) 1134 { 1135 if (d.hasNameOrOID("objectClass")) 1136 { 1137 continue; 1138 } 1139 1140 final String lowerName = toLowerCase(d.getNameOrOID()); 1141 if (ra.containsKey(lowerName)) 1142 { 1143 rac.get(lowerName).add(oc.getNameOrOID()); 1144 } 1145 else if (oa.containsKey(lowerName)) 1146 { 1147 oa.remove(lowerName); 1148 ra.put(lowerName, d); 1149 1150 final TreeSet<String> ocSet = oac.remove(lowerName); 1151 ocSet.add(oc.getNameOrOID()); 1152 rac.put(lowerName, ocSet); 1153 } 1154 else 1155 { 1156 final TreeSet<String> ocSet = new TreeSet<String>(); 1157 ocSet.add(oc.getNameOrOID()); 1158 ra.put(lowerName, d); 1159 rac.put(lowerName, ocSet); 1160 t.put(lowerName, getJavaType(s, d)); 1161 } 1162 } 1163 1164 for (final AttributeTypeDefinition d : oc.getOptionalAttributes(s, true)) 1165 { 1166 if (d.hasNameOrOID("objectClass")) 1167 { 1168 continue; 1169 } 1170 1171 final String lowerName = toLowerCase(d.getNameOrOID()); 1172 if (ra.containsKey(lowerName)) 1173 { 1174 rac.get(lowerName).add(oc.getNameOrOID()); 1175 } 1176 else if (oa.containsKey(lowerName)) 1177 { 1178 oac.get(lowerName).add(oc.getNameOrOID()); 1179 } 1180 else 1181 { 1182 final TreeSet<String> ocSet = new TreeSet<String>(); 1183 ocSet.add(oc.getNameOrOID()); 1184 oa.put(lowerName, d); 1185 oac.put(lowerName, ocSet); 1186 t.put(lowerName, getJavaType(s, d)); 1187 } 1188 } 1189 } 1190 1191 1192 1193 /** 1194 * Writes information about a field to the Java class file. 1195 * 1196 * @param writer The writer to which the field information should be 1197 * written. 1198 * @param d The attribute type definition. 1199 * @param type The name of the Java type to use for the field. 1200 * @param ocNames The names of the object classes for the attribute type. 1201 * @param inRDN Indicates whether the attribute should be included in 1202 * generated entry RDNs. 1203 * @param required Indicates whether the attribute should be considered 1204 * required. 1205 * @param sc The name of the structural object class for the object. 1206 * @param lazy Indicates whether the field should be marked for lazy 1207 * loading. 1208 * @param terse Indicates whether to use terse mode. 1209 */ 1210 static void writeField(final PrintWriter writer, 1211 final AttributeTypeDefinition d, final String type, 1212 final TreeSet<String> ocNames, 1213 final boolean inRDN, final boolean required, 1214 final String sc, final boolean lazy, 1215 final boolean terse) 1216 { 1217 final String attrName = d.getNameOrOID(); 1218 final String fieldName = PersistUtils.toJavaIdentifier(attrName); 1219 1220 writer.println(); 1221 1222 if (inRDN) 1223 { 1224 writer.println(" // The field used for RDN attribute " + attrName + '.'); 1225 } 1226 else if (required) 1227 { 1228 writer.println(" // The field used for required attribute " + attrName + 1229 '.'); 1230 } 1231 else if (d.isOperational()) 1232 { 1233 writer.println(" // The field used for operational attribute " + 1234 attrName + '.'); 1235 } 1236 else 1237 { 1238 writer.println(" // The field used for optional attribute " + attrName + 1239 '.'); 1240 } 1241 1242 boolean added = false; 1243 if (terse && attrName.equalsIgnoreCase(fieldName)) 1244 { 1245 writer.print(" @LDAPField("); 1246 } 1247 else 1248 { 1249 writer.print(" @LDAPField(attribute=\"" + attrName + '"'); 1250 added = true; 1251 } 1252 1253 if (ocNames.isEmpty()) 1254 { 1255 // Don't need to do anything. This should only be the case for 1256 // operational attributes. 1257 } 1258 else if (ocNames.size() == 1) 1259 { 1260 if ((! terse) || (! ocNames.iterator().next().equalsIgnoreCase(sc))) 1261 { 1262 if (added) 1263 { 1264 writer.println(","); 1265 writer.print(" objectClass=\"" + 1266 ocNames.iterator().next() + '"'); 1267 } 1268 else 1269 { 1270 writer.println("objectClass=\"" + 1271 ocNames.iterator().next() + '"'); 1272 added = true; 1273 } 1274 } 1275 } 1276 else 1277 { 1278 final Iterator<String> iterator = ocNames.iterator(); 1279 if (added) 1280 { 1281 writer.println(","); 1282 writer.println(" objectClass={ \"" + 1283 iterator.next() + "\","); 1284 } 1285 else 1286 { 1287 writer.println("objectClass={ \"" + 1288 iterator.next() + "\","); 1289 added = true; 1290 } 1291 1292 while (iterator.hasNext()) 1293 { 1294 final String name = iterator.next(); 1295 if (iterator.hasNext()) 1296 { 1297 writer.println(" \"" + name + "\","); 1298 } 1299 else 1300 { 1301 writer.print(" \"" + name + "\" }"); 1302 } 1303 } 1304 } 1305 1306 if (inRDN) 1307 { 1308 if (added) 1309 { 1310 writer.println(","); 1311 writer.println(" inRDN=true,"); 1312 } 1313 else 1314 { 1315 writer.println("inRDN=true,"); 1316 added = true; 1317 } 1318 writer.print(" filterUsage=FilterUsage.ALWAYS_ALLOWED"); 1319 } 1320 else 1321 { 1322 if (! terse) 1323 { 1324 if (added) 1325 { 1326 writer.println(","); 1327 writer.print(" " + 1328 "filterUsage=FilterUsage.CONDITIONALLY_ALLOWED"); 1329 } 1330 else 1331 { 1332 writer.print("filterUsage=FilterUsage.CONDITIONALLY_ALLOWED"); 1333 added = true; 1334 } 1335 } 1336 } 1337 1338 if (required) 1339 { 1340 if (added) 1341 { 1342 writer.println(","); 1343 writer.print(" requiredForEncode=true"); 1344 } 1345 else 1346 { 1347 writer.print("requiredForEncode=true"); 1348 added = true; 1349 } 1350 } 1351 1352 if (d.isOperational()) 1353 { 1354 if (added) 1355 { 1356 writer.println(","); 1357 writer.println(" inAdd=false,"); 1358 } 1359 else 1360 { 1361 writer.println("inAdd=false,"); 1362 added = true; 1363 } 1364 1365 writer.print(" inModify=false"); 1366 } 1367 1368 if (lazy) 1369 { 1370 if (added) 1371 { 1372 writer.println(","); 1373 writer.print(" lazilyLoad=true"); 1374 } 1375 else 1376 { 1377 writer.print("lazilyLoad=true"); 1378 added = true; 1379 } 1380 } 1381 1382 writer.println(")"); 1383 if (d.isSingleValued()) 1384 { 1385 writer.println(" private " + type + ' ' + fieldName + ';'); 1386 } 1387 else 1388 { 1389 writer.println(" private " + type + "[] " + fieldName + ';'); 1390 } 1391 } 1392 1393 1394 1395 /** 1396 * Writes getter, setter, and filter creation methods for the specified 1397 * attribute. 1398 * 1399 * @param writer The writer to use to write the methods. 1400 * @param d The attribute type definition to be written. 1401 * @param type The name of the Java type to use for the attribute. 1402 * @param addSetter Indicates whether to write a setter method. 1403 */ 1404 static void writeFieldMethods(final PrintWriter writer, 1405 final AttributeTypeDefinition d, 1406 final String type, final boolean addSetter) 1407 { 1408 writer.println(); 1409 writer.println(); 1410 writer.println(); 1411 1412 final String attrName = d.getNameOrOID(); 1413 final String fieldName = PersistUtils.toJavaIdentifier(attrName); 1414 final String capFieldName = capitalize(fieldName); 1415 1416 if (d.isSingleValued()) 1417 { 1418 if (type.equals("DN")) 1419 { 1420 writer.println(" /**"); 1421 writer.println(" * Retrieves the first value for the field " + 1422 "associated with the"); 1423 writer.println(" * " + attrName + " attribute as a DN, if present."); 1424 writer.println(" *"); 1425 writer.println(" * @return The first value for the field " + 1426 "associated with the"); 1427 writer.println(" * " + attrName + " attribute, or"); 1428 writer.println(" * {@code null} if the field does not " + 1429 "have a value."); 1430 writer.println(" */"); 1431 writer.println(" public DN get" + capFieldName + "DN()"); 1432 writer.println(" {"); 1433 writer.println(" return " + fieldName + ';'); 1434 writer.println(" }"); 1435 1436 writer.println(); 1437 writer.println(); 1438 writer.println(); 1439 1440 writer.println(" /**"); 1441 writer.println(" * Retrieves the object referenced by the DN held " + 1442 "in the"); 1443 writer.println(" * " + attrName + " attribute, if present."); 1444 writer.println(" *"); 1445 writer.println(" * @param <T> The type of object to return."); 1446 writer.println(" *"); 1447 writer.println(" * @param connection The connection to use to " + 1448 "retrieve the entry. It must"); 1449 writer.println(" * not be {@code null}."); 1450 writer.println(" * @param type The type of object as which " + 1451 "to decode the entry. It"); 1452 writer.println(" * must not be {@code null}, " + 1453 "and the class must be marked"); 1454 writer.println(" * with the {@code LDAPObject} " + 1455 "annotation type."); 1456 writer.println(" *"); 1457 writer.println(" * @return The object decoded from the entry with " + 1458 "the associated DN, or"); 1459 writer.println(" * {@code null} if the field does not " + 1460 "have a value or the referenced"); 1461 writer.println(" * entry does not exist."); 1462 writer.println(" *"); 1463 writer.println(" * @throws LDAPException If a problem occurs " + 1464 "while attempting to retrieve"); 1465 writer.println(" * the entry or decode it " + 1466 "as an object of the"); 1467 writer.println(" * specified type."); 1468 writer.println(" */"); 1469 writer.println(" public <T> T get" + capFieldName + "Object("); 1470 writer.println(" final LDAPInterface connection,"); 1471 writer.println(" final Class<T> type)"); 1472 writer.println(" throws LDAPException"); 1473 writer.println(" {"); 1474 writer.println(" return PersistUtils.getEntryAsObject(" + fieldName + 1475 ','); 1476 writer.println(" type, connection);"); 1477 writer.println(" }"); 1478 1479 if (addSetter) 1480 { 1481 writer.println(); 1482 writer.println(); 1483 writer.println(); 1484 1485 writer.println(" /**"); 1486 writer.println(" * Sets the value for the field associated with " + 1487 "the"); 1488 writer.println(" * " + attrName + " attribute."); 1489 writer.println(" *"); 1490 writer.println(" * @param v The value for the field associated " + 1491 "with the"); 1492 writer.println(" * " + attrName + " attribute."); 1493 writer.println(" */"); 1494 writer.println(" public void set" + capFieldName + "(final DN v)"); 1495 writer.println(" {"); 1496 writer.println(" this." + fieldName + " = v;"); 1497 writer.println(" }"); 1498 1499 writer.println(); 1500 writer.println(); 1501 writer.println(); 1502 1503 writer.println(" /**"); 1504 writer.println(" * Sets the value for the field associated with " + 1505 "the"); 1506 writer.println(" * " + attrName + " attribute."); 1507 writer.println(" *"); 1508 writer.println(" * @param v The string representation of the " + 1509 "value for the field associated"); 1510 writer.println(" * with the " + attrName + 1511 " attribute."); 1512 writer.println(" *"); 1513 writer.println(" * @throws LDAPException If the provided " + 1514 "string cannot be parsed as a DN."); 1515 writer.println(" */"); 1516 writer.println(" public void set" + capFieldName + 1517 "(final String v)"); 1518 writer.println(" throws LDAPException"); 1519 writer.println(" {"); 1520 writer.println(" if (v == null)"); 1521 writer.println(" {"); 1522 writer.println(" this." + fieldName + " = null;"); 1523 writer.println(" }"); 1524 writer.println(" else"); 1525 writer.println(" {"); 1526 writer.println(" this." + fieldName + " = new DN(v);"); 1527 writer.println(" }"); 1528 writer.println(" }"); 1529 } 1530 } 1531 else 1532 { 1533 writer.println(" /**"); 1534 writer.println(" * Retrieves the value for the field associated " + 1535 "with the"); 1536 writer.println(" * " + attrName + " attribute, if present."); 1537 writer.println(" *"); 1538 writer.println(" * @return The value for the field associated " + 1539 "with the"); 1540 writer.println(" * " + attrName + " attribute, or"); 1541 writer.println(" * {@code null} if the field does not " + 1542 "have a value."); 1543 writer.println(" */"); 1544 writer.println(" public " + type + " get" + capFieldName + "()"); 1545 writer.println(" {"); 1546 writer.println(" return " + fieldName + ';'); 1547 writer.println(" }"); 1548 1549 if (addSetter) 1550 { 1551 writer.println(); 1552 writer.println(); 1553 writer.println(); 1554 1555 writer.println(" /**"); 1556 writer.println(" * Sets the value for the field associated with " + 1557 "the"); 1558 writer.println(" * " + attrName + " attribute."); 1559 writer.println(" *"); 1560 writer.println(" * @param v The value for the field associated " + 1561 "with the"); 1562 writer.println(" * " + attrName + " attribute."); 1563 writer.println(" */"); 1564 writer.println(" public void set" + capFieldName + "(final " + type + 1565 " v)"); 1566 writer.println(" {"); 1567 writer.println(" this." + fieldName + " = v;"); 1568 writer.println(" }"); 1569 } 1570 } 1571 } 1572 else 1573 { 1574 if (type.equals("DN")) 1575 { 1576 writer.println(" /**"); 1577 writer.println(" * Retrieves the first value for the field " + 1578 "associated with the"); 1579 writer.println(" * " + attrName + " attribute as a DN, if present."); 1580 writer.println(" *"); 1581 writer.println(" * @return The first value for the field " + 1582 "associated with the"); 1583 writer.println(" * " + attrName + " attribute, or"); 1584 writer.println(" * {@code null} if that attribute was not " + 1585 "present in the entry or"); 1586 writer.println(" * does not have any values."); 1587 writer.println(" */"); 1588 writer.println(" public DN getFirst" + capFieldName + "DN()"); 1589 writer.println(" {"); 1590 writer.println(" if ((" + fieldName + " == null) ||"); 1591 writer.println(" (" + fieldName + ".length == 0))"); 1592 writer.println(" {"); 1593 writer.println(" return null;"); 1594 writer.println(" }"); 1595 writer.println(" else"); 1596 writer.println(" {"); 1597 writer.println(" return " + fieldName + "[0];"); 1598 writer.println(" }"); 1599 writer.println(" }"); 1600 1601 writer.println(); 1602 writer.println(); 1603 writer.println(); 1604 1605 writer.println(" /**"); 1606 writer.println(" * Retrieves the values for the field associated " + 1607 "with the"); 1608 writer.println(" * " + attrName + " attribute as DNs, if present."); 1609 writer.println(" *"); 1610 writer.println(" * @return The values for the field associated " + 1611 "with the"); 1612 writer.println(" * " + attrName + " attribute, or"); 1613 writer.println(" * {@code null} if that attribute was not " + 1614 "present in the entry."); 1615 writer.println(" */"); 1616 writer.println(" public DN[] get" + capFieldName + "DNs()"); 1617 writer.println(" {"); 1618 writer.println(" return " + fieldName + ';'); 1619 writer.println(" }"); 1620 1621 writer.println(); 1622 writer.println(); 1623 writer.println(); 1624 1625 writer.println(" /**"); 1626 writer.println(" * Retrieves the values for the field associated " + 1627 "with the"); 1628 writer.println(" * " + attrName + " attribute as objects of the " + 1629 "specified type,"); 1630 writer.println(" * if present."); 1631 writer.println(" *"); 1632 writer.println(" * @param <T> The type of object to return."); 1633 writer.println(" *"); 1634 writer.println(" * @param connection The connection to use to " + 1635 "retrieve the entries. It"); 1636 writer.println(" * must not be {@code null}."); 1637 writer.println(" * @param type The type of object as which " + 1638 "the entries should be"); 1639 writer.println(" * decoded. It must not be " + 1640 "{@code null}, and the class"); 1641 writer.println(" * must be marked with the " + 1642 "{@code LDAPObject} annotation"); 1643 writer.println(" * type."); 1644 writer.println(" *"); 1645 writer.println(" * @return A {@code PersistedObjects} object that " + 1646 "may be used to iterate"); 1647 writer.println(" * across the resulting objects."); 1648 writer.println(" *"); 1649 writer.println(" * @throws LDAPException If the requested type " + 1650 "cannot be used with the LDAP"); 1651 writer.println(" * SDK persistence " + 1652 "framework."); 1653 writer.println(" */"); 1654 writer.println(" public <T> PersistedObjects<T> get" + capFieldName + 1655 "Objects("); 1656 writer.println(" final " + 1657 "LDAPInterface connection,"); 1658 writer.println(" final Class<T> " + 1659 "type)"); 1660 writer.println(" throws LDAPException"); 1661 writer.println(" {"); 1662 writer.println(" return PersistUtils.getEntriesAsObjects(" + 1663 fieldName + ','); 1664 writer.println(" type, connection);"); 1665 writer.println(" }"); 1666 1667 if (addSetter) 1668 { 1669 writer.println(); 1670 writer.println(); 1671 writer.println(); 1672 1673 writer.println(" /**"); 1674 writer.println(" * Sets the values for the field associated with " + 1675 "the"); 1676 writer.println(" * " + attrName + " attribute."); 1677 writer.println(" *"); 1678 writer.println(" * @param v The values for the field " + 1679 "associated with the"); 1680 writer.println(" * " + attrName + " attribute."); 1681 writer.println(" */"); 1682 writer.println(" public void set" + capFieldName + 1683 "(final DN... v)"); 1684 writer.println(" {"); 1685 writer.println(" this." + fieldName + " = v;"); 1686 writer.println(" }"); 1687 1688 writer.println(); 1689 writer.println(); 1690 writer.println(); 1691 1692 writer.println(" /**"); 1693 writer.println(" * Sets the values for the field associated with " + 1694 "the"); 1695 writer.println(" * " + attrName + " attribute."); 1696 writer.println(" *"); 1697 writer.println(" * @param v The string representations of the " + 1698 "values for the field"); 1699 writer.println(" * associated with the " + attrName + 1700 " attribute."); 1701 writer.println(" *"); 1702 writer.println(" * @throws LDAPException If any of the " + 1703 "provided strings cannot be parsed as"); 1704 writer.println(" * a DN."); 1705 writer.println(" */"); 1706 writer.println(" public void set" + capFieldName + 1707 "(final String... v)"); 1708 writer.println(" throws LDAPException"); 1709 writer.println(" {"); 1710 writer.println(" if (v == null)"); 1711 writer.println(" {"); 1712 writer.println(" this." + fieldName + " = null;"); 1713 writer.println(" }"); 1714 writer.println(" else"); 1715 writer.println(" {"); 1716 writer.println(" this." + fieldName + " = new DN[v.length];"); 1717 writer.println(" for (int i=0; i < v.length; i++)"); 1718 writer.println(" {"); 1719 writer.println(" this." + fieldName + "[i] = new DN(v[i]);"); 1720 writer.println(" }"); 1721 writer.println(" }"); 1722 writer.println(" }"); 1723 } 1724 } 1725 else 1726 { 1727 writer.println(" /**"); 1728 writer.println(" * Retrieves the first value for the field " + 1729 "associated with the"); 1730 writer.println(" * " + attrName + " attribute, if present."); 1731 writer.println(" *"); 1732 writer.println(" * @return The first value for the field " + 1733 "associated with the"); 1734 writer.println(" * " + attrName + " attribute, or"); 1735 writer.println(" * {@code null} if that attribute was not " + 1736 "present in the entry or"); 1737 writer.println(" * does not have any values."); 1738 writer.println(" */"); 1739 writer.println(" public " + type + " getFirst" + capFieldName + "()"); 1740 writer.println(" {"); 1741 writer.println(" if ((" + fieldName + " == null) ||"); 1742 writer.println(" (" + fieldName + ".length == 0))"); 1743 writer.println(" {"); 1744 writer.println(" return null;"); 1745 writer.println(" }"); 1746 writer.println(" else"); 1747 writer.println(" {"); 1748 writer.println(" return " + fieldName + "[0];"); 1749 writer.println(" }"); 1750 writer.println(" }"); 1751 1752 writer.println(); 1753 writer.println(); 1754 writer.println(); 1755 1756 writer.println(" /**"); 1757 writer.println(" * Retrieves the values for the field associated " + 1758 "with the"); 1759 writer.println(" * " + attrName + " attribute, if present."); 1760 writer.println(" *"); 1761 writer.println(" * @return The values for the field associated " + 1762 "with the"); 1763 writer.println(" * " + attrName + " attribute, or"); 1764 writer.println(" * {@code null} if that attribute was not " + 1765 "present in the entry."); 1766 writer.println(" */"); 1767 writer.println(" public " + type + "[] get" + capFieldName + "()"); 1768 writer.println(" {"); 1769 writer.println(" return " + fieldName + ';'); 1770 writer.println(" }"); 1771 1772 if (addSetter) 1773 { 1774 writer.println(); 1775 writer.println(); 1776 writer.println(); 1777 1778 writer.println(" /**"); 1779 writer.println(" * Sets the values for the field associated with " + 1780 "the"); 1781 writer.println(" * " + attrName + " attribute."); 1782 writer.println(" *"); 1783 writer.println(" * @param v The values for the field " + 1784 "associated with the"); 1785 writer.println(" * " + attrName + " attribute."); 1786 writer.println(" */"); 1787 writer.println(" public void set" + capFieldName + "(final " + type + 1788 "... v)"); 1789 writer.println(" {"); 1790 writer.println(" this." + fieldName + " = v;"); 1791 writer.println(" }"); 1792 } 1793 } 1794 } 1795 1796 1797 writer.println(); 1798 writer.println(); 1799 writer.println(); 1800 1801 writer.println(" /**"); 1802 writer.println(" * Generates a filter that may be used to search for " + 1803 "objects of this type"); 1804 writer.println(" * using the " + attrName + " attribute."); 1805 writer.println(" * The resulting filter may be combined with other " + 1806 "filter elements to create a"); 1807 writer.println(" * more complex filter."); 1808 writer.println(" *"); 1809 writer.println(" * @param filterType The type of filter to generate."); 1810 writer.println(" * @param value The value to use to use for the " + 1811 "filter. It may be"); 1812 writer.println(" * {@code null} only for a filter " + 1813 "type of"); 1814 writer.println(" * {@code PRESENCE}."); 1815 writer.println(" *"); 1816 writer.println(" * @return The generated search filter."); 1817 writer.println(" *"); 1818 writer.println(" * @throws LDAPPersistException If a problem is " + 1819 "encountered while attempting"); 1820 writer.println(" * to generate the " + 1821 "filter."); 1822 writer.println(" */"); 1823 writer.println(" public static Filter generate" + capFieldName + 1824 "Filter("); 1825 writer.println(" final PersistFilterType " + 1826 "filterType,"); 1827 writer.println(" final " + type + " value)"); 1828 writer.println(" throws LDAPPersistException"); 1829 writer.println(" {"); 1830 writer.println(" final byte[] valueBytes;"); 1831 writer.println(" if (filterType == PersistFilterType.PRESENCE)"); 1832 writer.println(" {"); 1833 writer.println(" valueBytes = null;"); 1834 writer.println(" }"); 1835 writer.println(" else"); 1836 writer.println(" {"); 1837 writer.println(" if (value == null)"); 1838 writer.println(" {"); 1839 writer.println(" throw new LDAPPersistException(\"Unable to " + 1840 "generate a filter of type \" +"); 1841 writer.println(" filterType.name() + \" with a null value " + 1842 "for attribute \" +"); 1843 writer.println(" \"" + attrName + "\");"); 1844 writer.println(" }"); 1845 writer.println(); 1846 writer.println(" final LDAPObjectHandler<?> objectHandler ="); 1847 writer.println(" getPersister().getObjectHandler();"); 1848 writer.println(" final FieldInfo fieldInfo = " + 1849 "objectHandler.getFields().get("); 1850 writer.println(" \"" + toLowerCase(attrName) + "\");"); 1851 writer.println(); 1852 writer.println(" final DefaultObjectEncoder objectEncoder = new " + 1853 "DefaultObjectEncoder();"); 1854 writer.println(" valueBytes = " + 1855 "objectEncoder.encodeFieldValue(fieldInfo.getField(),"); 1856 1857 if (d.isSingleValued()) 1858 { 1859 writer.println(" value,"); 1860 } 1861 else 1862 { 1863 writer.println(" new " + type + "[] { value },"); 1864 } 1865 1866 writer.println(" \"" + attrName + "\").getValueByteArray();"); 1867 writer.println(" }"); 1868 writer.println(); 1869 writer.println(" switch (filterType)"); 1870 writer.println(" {"); 1871 writer.println(" case PRESENCE:"); 1872 writer.println(" return Filter.createPresenceFilter("); 1873 writer.println(" \"" + attrName + "\");"); 1874 writer.println(" case EQUALITY:"); 1875 writer.println(" return Filter.createEqualityFilter("); 1876 writer.println(" \"" + attrName + "\","); 1877 writer.println(" valueBytes);"); 1878 writer.println(" case STARTS_WITH:"); 1879 writer.println(" return Filter.createSubstringFilter("); 1880 writer.println(" \"" + attrName + "\","); 1881 writer.println(" valueBytes, null, null);"); 1882 writer.println(" case ENDS_WITH:"); 1883 writer.println(" return Filter.createSubstringFilter("); 1884 writer.println(" \"" + attrName + "\","); 1885 writer.println(" null, null, valueBytes);"); 1886 writer.println(" case CONTAINS:"); 1887 writer.println(" return Filter.createSubstringFilter("); 1888 writer.println(" \"" + attrName + "\","); 1889 writer.println(" null, new byte[][] { valueBytes }, null);"); 1890 writer.println(" case GREATER_OR_EQUAL:"); 1891 writer.println(" return Filter.createGreaterOrEqualFilter("); 1892 writer.println(" \"" + attrName + "\","); 1893 writer.println(" valueBytes);"); 1894 writer.println(" case LESS_OR_EQUAL:"); 1895 writer.println(" return Filter.createLessOrEqualFilter("); 1896 writer.println(" \"" + attrName + "\","); 1897 writer.println(" valueBytes);"); 1898 writer.println(" case APPROXIMATELY_EQUAL_TO:"); 1899 writer.println(" return Filter.createApproximateMatchFilter("); 1900 writer.println(" \"" + attrName + "\","); 1901 writer.println(" valueBytes);"); 1902 writer.println(" default:"); 1903 writer.println(" // This should never happen."); 1904 writer.println(" throw new LDAPPersistException(\"Unrecognized " + 1905 "filter type \" +"); 1906 writer.println(" filterType.name());"); 1907 writer.println(" }"); 1908 writer.println(" }"); 1909 } 1910 1911 1912 1913 /** 1914 * Writes a {@code toString} method for the generated class. 1915 * 1916 * @param writer The writer to use to write the methods. 1917 * @param className The base name (without package information) for 1918 * the generated class. 1919 * @param requiredAttrs The set of required attributes for the generated 1920 * class. 1921 * @param optionalAttrs The set of optional attributes for the generated 1922 * class. 1923 * @param operationalAttrs The set of operational attributes for the 1924 * generated class. 1925 */ 1926 static void writeToString(final PrintWriter writer, 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 String getJavaType(final Schema schema, final AttributeTypeDefinition d) 2042 { 2043 if (! d.isSingleValued()) 2044 { 2045 needArrays = true; 2046 } 2047 2048 final String syntaxOID = d.getSyntaxOID(schema); 2049 if (syntaxOID == null) 2050 { 2051 return "String"; 2052 } 2053 2054 final String oid; 2055 final int bracePos = syntaxOID.indexOf('{'); 2056 if (bracePos > 0) 2057 { 2058 oid = syntaxOID.substring(0, bracePos); 2059 } 2060 else 2061 { 2062 oid = syntaxOID; 2063 } 2064 2065 if (oid.equals("1.3.6.1.4.1.1466.115.121.1.7")) 2066 { 2067 // Boolean 2068 return "Boolean"; 2069 } 2070 else if (oid.equals("1.3.6.1.4.1.4203.1.1.2") || 2071 oid.equals("1.3.6.1.4.1.1466.115.121.1.5") || 2072 oid.equals("1.3.6.1.4.1.1466.115.121.1.8") || 2073 oid.equals("1.3.6.1.4.1.1466.115.121.1.9") || 2074 oid.equals("1.3.6.1.4.1.1466.115.121.1.10") || 2075 oid.equals("1.3.6.1.4.1.1466.115.121.1.28") || 2076 oid.equals("1.3.6.1.4.1.1466.115.121.1.40")) 2077 { 2078 // auth password 2079 // binary 2080 // certificate 2081 // certificate list 2082 // certificate pair 2083 // JPEG 2084 // octet string 2085 return "byte[]"; 2086 } 2087 else if (oid.equals("1.3.6.1.4.1.1466.115.121.1.24")) 2088 { 2089 // generalized time. 2090 needDate = true; 2091 return "Date"; 2092 } 2093 else if (oid.equals("1.3.6.1.4.1.1466.115.121.1.27")) 2094 { 2095 // integer 2096 return "Long"; 2097 } 2098 else if (oid.equals("1.3.6.1.4.1.1466.115.121.1.12") || 2099 oid.equals("1.3.6.1.4.1.1466.115.121.1.34")) 2100 { 2101 // DN 2102 // name and optional UID 2103 needDN = true; 2104 if (! d.isSingleValued()) 2105 { 2106 needPersistedObjects = true; 2107 } 2108 return "DN"; 2109 } 2110 else 2111 { 2112 return "String"; 2113 } 2114 } 2115 2116 2117 2118 /** 2119 * {@inheritDoc} 2120 */ 2121 @Override() 2122 public LinkedHashMap<String[],String> getExampleUsages() 2123 { 2124 final LinkedHashMap<String[],String> examples = 2125 new LinkedHashMap<String[],String>(1); 2126 2127 final String[] args = 2128 { 2129 "--hostname", "server.example.com", 2130 "--port", "389", 2131 "--bindDN", "uid=admin,dc=example,dc=com", 2132 "--bindPassword", "password", 2133 "--outputDirectory", "src/com/example", 2134 "--structuralClass", "myStructuralClass", 2135 "--auxiliaryClass", "auxClass1", 2136 "--auxiliaryClass", "auxClass2", 2137 "--rdnAttribute", "cn", 2138 "--defaultParentDN", "dc=example,dc=com", 2139 "--packageName", "com.example", 2140 "--className", "MyObject" 2141 }; 2142 examples.put(args, INFO_GEN_SOURCE_EXAMPLE_1.get()); 2143 2144 return examples; 2145 } 2146}