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