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