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