001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2006-2009 Sun Microsystems, Inc. 015 * Portions Copyright 2013-2016 ForgeRock AS. 016 */ 017package org.opends.server.tools.makeldif; 018 019import org.forgerock.i18n.LocalizableMessage; 020 021import java.io.BufferedReader; 022import java.io.File; 023import java.io.FileReader; 024import java.io.InputStream; 025import java.io.InputStreamReader; 026import java.io.IOException; 027import java.util.ArrayList; 028import java.util.HashMap; 029import java.util.LinkedHashMap; 030import java.util.List; 031import java.util.Map; 032import java.util.Random; 033import java.util.StringTokenizer; 034 035import org.opends.server.core.DirectoryServer; 036import org.forgerock.opendj.ldap.schema.AttributeType; 037import org.forgerock.opendj.ldap.DN; 038import org.opends.server.types.InitializationException; 039 040import static org.opends.messages.ToolMessages.*; 041import static org.opends.server.util.StaticUtils.*; 042 043/** 044 * This class defines a template file, which is a collection of constant 045 * definitions, branches, and templates. 046 */ 047public class TemplateFile 048{ 049 /** The name of the file holding the list of first names. */ 050 public static final String FIRST_NAME_FILE = "first.names"; 051 /** The name of the file holding the list of last names. */ 052 public static final String LAST_NAME_FILE = "last.names"; 053 054 055 /** 056 * A map of the contents of various text files used during the parsing 057 * process, mapped from absolute path to the array of lines in the file. 058 */ 059 private final HashMap<String, String[]> fileLines = new HashMap<>(); 060 061 /** The index of the next first name value that should be used. */ 062 private int firstNameIndex; 063 /** The index of the next last name value that should be used. */ 064 private int lastNameIndex; 065 066 /** 067 * A counter used to keep track of the number of times that the larger of the 068 * first/last name list has been completed. 069 */ 070 private int nameLoopCounter; 071 /** 072 * A counter that will be used in case we have exhausted all possible first 073 * and last name combinations. 074 */ 075 private int nameUniquenessCounter; 076 077 /** The set of branch definitions for this template file. */ 078 private final LinkedHashMap<DN, Branch> branches = new LinkedHashMap<>(); 079 /** The set of constant definitions for this template file. */ 080 private final LinkedHashMap<String, String> constants = new LinkedHashMap<>(); 081 /** The set of registered tags for this template file. */ 082 private final LinkedHashMap<String, Tag> registeredTags = new LinkedHashMap<>(); 083 /** The set of template definitions for this template file. */ 084 private final LinkedHashMap<String, Template> templates = new LinkedHashMap<>(); 085 086 /** The random number generator for this template file. */ 087 private Random random; 088 089 /** The next first name that should be used. */ 090 private String firstName; 091 /** The next last name that should be used. */ 092 private String lastName; 093 094 /** 095 * The resource path to use for filesystem elements that cannot be found 096 * anywhere else. 097 */ 098 private String resourcePath; 099 /** The path to the directory containing the template file, if available. */ 100 private String templatePath; 101 102 /** The set of first names to use when generating the LDIF. */ 103 private String[] firstNames; 104 /** The set of last names to use when generating the LDIF. */ 105 private String[] lastNames; 106 107 108 109 /** 110 * Creates a new, empty template file structure. 111 * 112 * @param resourcePath The path to the directory that may contain additional 113 * resource files needed during the LDIF generation 114 * process. 115 */ 116 public TemplateFile(String resourcePath) 117 { 118 this(resourcePath, new Random()); 119 } 120 121 122 123 /** 124 * Creates a new, empty template file structure. 125 * 126 * 127 * @param resourcePath The path to the directory that may contain additional 128 * resource files needed during the LDIF generation 129 * process. 130 * @param random The random number generator for this template file. 131 */ 132 public TemplateFile(String resourcePath, Random random) 133 { 134 this.resourcePath = resourcePath; 135 this.random = random; 136 137 firstNames = new String[0]; 138 lastNames = new String[0]; 139 nameUniquenessCounter = 1; 140 141 registerDefaultTags(); 142 143 try 144 { 145 readNameFiles(); 146 } 147 catch (IOException ioe) 148 { 149 // FIXME -- What to do here? 150 ioe.printStackTrace(); 151 firstNames = new String[] { "John" }; 152 lastNames = new String[] { "Doe" }; 153 } 154 } 155 156 157 158 /** 159 * Retrieves the set of tags that have been registered. They will be in the 160 * form of a mapping between the name of the tag (in all lowercase characters) 161 * and the corresponding tag implementation. 162 * 163 * @return The set of tags that have been registered. 164 */ 165 public Map<String,Tag> getTags() 166 { 167 return registeredTags; 168 } 169 170 171 172 /** 173 * Retrieves the tag with the specified name. 174 * 175 * @param lowerName The name of the tag to retrieve, in all lowercase 176 * characters. 177 * 178 * @return The requested tag, or <CODE>null</CODE> if no such tag has been 179 * registered. 180 */ 181 public Tag getTag(String lowerName) 182 { 183 return registeredTags.get(lowerName); 184 } 185 186 187 188 /** 189 * Registers the specified class as a tag that may be used in templates. 190 * 191 * @param tagClass The fully-qualified name of the class to register as a 192 * tag. 193 * 194 * @throws MakeLDIFException If a problem occurs while attempting to 195 * register the specified tag. 196 */ 197 public void registerTag(String tagClass) 198 throws MakeLDIFException 199 { 200 Class c; 201 try 202 { 203 c = Class.forName(tagClass); 204 } 205 catch (Exception e) 206 { 207 LocalizableMessage message = ERR_MAKELDIF_CANNOT_LOAD_TAG_CLASS.get(tagClass); 208 throw new MakeLDIFException(message, e); 209 } 210 211 Tag t; 212 try 213 { 214 t = (Tag) c.newInstance(); 215 } 216 catch (Exception e) 217 { 218 LocalizableMessage message = ERR_MAKELDIF_CANNOT_INSTANTIATE_TAG.get(tagClass); 219 throw new MakeLDIFException(message, e); 220 } 221 222 String lowerName = toLowerCase(t.getName()); 223 if (registeredTags.containsKey(lowerName)) 224 { 225 LocalizableMessage message = 226 ERR_MAKELDIF_CONFLICTING_TAG_NAME.get(tagClass, t.getName()); 227 throw new MakeLDIFException(message); 228 } 229 else 230 { 231 registeredTags.put(lowerName, t); 232 } 233 } 234 235 236 237 /** 238 * Registers the set of tags that will always be available for use in 239 * templates. 240 */ 241 private void registerDefaultTags() 242 { 243 Class[] defaultTagClasses = new Class[] 244 { 245 AttributeValueTag.class, 246 DNTag.class, 247 FileTag.class, 248 FirstNameTag.class, 249 GUIDTag.class, 250 IfAbsentTag.class, 251 IfPresentTag.class, 252 LastNameTag.class, 253 ListTag.class, 254 ParentDNTag.class, 255 PresenceTag.class, 256 RandomTag.class, 257 RDNTag.class, 258 SequentialTag.class, 259 StaticTextTag.class, 260 UnderscoreDNTag.class, 261 UnderscoreParentDNTag.class 262 }; 263 264 for (Class c : defaultTagClasses) 265 { 266 try 267 { 268 Tag t = (Tag) c.newInstance(); 269 registeredTags.put(toLowerCase(t.getName()), t); 270 } 271 catch (Exception e) 272 { 273 // This should never happen. 274 e.printStackTrace(); 275 } 276 } 277 } 278 279 280 281 /** 282 * Retrieves the set of constants defined for this template file. 283 * 284 * @return The set of constants defined for this template file. 285 */ 286 public Map<String,String> getConstants() 287 { 288 return constants; 289 } 290 291 292 293 /** 294 * Retrieves the value of the constant with the specified name. 295 * 296 * @param lowerName The name of the constant to retrieve, in all lowercase 297 * characters. 298 * 299 * @return The value of the constant with the specified name, or 300 * <CODE>null</CODE> if there is no such constant. 301 */ 302 public String getConstant(String lowerName) 303 { 304 return constants.get(lowerName); 305 } 306 307 308 309 /** 310 * Registers the provided constant for use in the template. 311 * 312 * @param name The name for the constant. 313 * @param value The value for the constant. 314 */ 315 public void registerConstant(String name, String value) 316 { 317 constants.put(toLowerCase(name), value); 318 } 319 320 321 322 /** 323 * Retrieves the set of branches defined in this template file. 324 * 325 * @return The set of branches defined in this template file. 326 */ 327 public Map<DN,Branch> getBranches() 328 { 329 return branches; 330 } 331 332 333 334 /** 335 * Retrieves the branch registered with the specified DN. 336 * 337 * @param branchDN The DN for which to retrieve the corresponding branch. 338 * 339 * @return The requested branch, or <CODE>null</CODE> if no such branch has 340 * been registered. 341 */ 342 public Branch getBranch(DN branchDN) 343 { 344 return branches.get(branchDN); 345 } 346 347 348 349 /** 350 * Registers the provided branch in this template file. 351 * 352 * @param branch The branch to be registered. 353 */ 354 public void registerBranch(Branch branch) 355 { 356 branches.put(branch.getBranchDN(), branch); 357 } 358 359 360 361 /** 362 * Retrieves the set of templates defined in this template file. 363 * 364 * @return The set of templates defined in this template file. 365 */ 366 public Map<String,Template> getTemplates() 367 { 368 return templates; 369 } 370 371 372 373 /** 374 * Retrieves the template with the specified name. 375 * 376 * @param lowerName The name of the template to retrieve, in all lowercase 377 * characters. 378 * 379 * @return The requested template, or <CODE>null</CODE> if there is no such 380 * template. 381 */ 382 public Template getTemplate(String lowerName) 383 { 384 return templates.get(lowerName); 385 } 386 387 388 389 /** 390 * Registers the provided template for use in this template file. 391 * 392 * @param template The template to be registered. 393 */ 394 public void registerTemplate(Template template) 395 { 396 templates.put(toLowerCase(template.getName()), template); 397 } 398 399 400 401 /** 402 * Retrieves the random number generator for this template file. 403 * 404 * @return The random number generator for this template file. 405 */ 406 public Random getRandom() 407 { 408 return random; 409 } 410 411 412 413 /** 414 * Reads the contents of the first and last name files into the appropriate 415 * arrays and sets up the associated index pointers. 416 * 417 * @throws IOException If a problem occurs while reading either of the 418 * files. 419 */ 420 private void readNameFiles() 421 throws IOException 422 { 423 File f = getFile(FIRST_NAME_FILE); 424 List<String> nameList = readLines(f); 425 firstNames = new String[nameList.size()]; 426 nameList.toArray(firstNames); 427 428 f = getFile(LAST_NAME_FILE); 429 nameList = readLines(f); 430 lastNames = new String[nameList.size()]; 431 nameList.toArray(lastNames); 432 } 433 434 private List<String> readLines(File f) throws IOException 435 { 436 try (BufferedReader reader = new BufferedReader(new FileReader(f))) 437 { 438 ArrayList<String> lines = new ArrayList<>(); 439 while (true) 440 { 441 String line = reader.readLine(); 442 if (line == null) 443 { 444 break; 445 } 446 lines.add(line); 447 } 448 return lines; 449 } 450 } 451 452 453 454 /** 455 * Updates the first and last name indexes to choose new values. The 456 * algorithm used is designed to ensure that the combination of first and last 457 * names will never be repeated. It depends on the number of first names and 458 * the number of last names being relatively prime. This method should be 459 * called before beginning generation of each template entry. 460 */ 461 public void nextFirstAndLastNames() 462 { 463 firstName = firstNames[firstNameIndex++]; 464 lastName = lastNames[lastNameIndex++]; 465 466 467 // If we've already exhausted every possible combination, then append an 468 // integer to the last name. 469 if (nameUniquenessCounter > 1) 470 { 471 lastName += nameUniquenessCounter; 472 } 473 474 if (firstNameIndex >= firstNames.length) 475 { 476 // We're at the end of the first name list, so start over. If the first 477 // name list is larger than the last name list, then we'll also need to 478 // set the last name index to the next loop counter position. 479 firstNameIndex = 0; 480 if (firstNames.length > lastNames.length) 481 { 482 lastNameIndex = ++nameLoopCounter; 483 if (lastNameIndex >= lastNames.length) 484 { 485 lastNameIndex = 0; 486 nameUniquenessCounter++; 487 } 488 } 489 } 490 491 if (lastNameIndex >= lastNames.length) 492 { 493 // We're at the end of the last name list, so start over. If the last 494 // name list is larger than the first name list, then we'll also need to 495 // set the first name index to the next loop counter position. 496 lastNameIndex = 0; 497 if (lastNames.length > firstNames.length) 498 { 499 firstNameIndex = ++nameLoopCounter; 500 if (firstNameIndex >= firstNames.length) 501 { 502 firstNameIndex = 0; 503 nameUniquenessCounter++; 504 } 505 } 506 } 507 } 508 509 510 511 /** 512 * Retrieves the first name value that should be used for the current entry. 513 * 514 * @return The first name value that should be used for the current entry. 515 */ 516 public String getFirstName() 517 { 518 return firstName; 519 } 520 521 522 523 /** 524 * Retrieves the last name value that should be used for the current entry. 525 * 526 * @return The last name value that should be used for the current entry. 527 */ 528 public String getLastName() 529 { 530 return lastName; 531 } 532 533 534 535 /** 536 * Parses the contents of the specified file as a MakeLDIF template file 537 * definition. 538 * 539 * @param filename The name of the file containing the template data. 540 * @param warnings A list into which any warnings identified may be placed. 541 * 542 * @throws IOException If a problem occurs while attempting to read data 543 * from the specified file. 544 * 545 * @throws InitializationException If a problem occurs while initializing 546 * any of the MakeLDIF components. 547 * 548 * @throws MakeLDIFException If any other problem occurs while parsing the 549 * template file. 550 */ 551 public void parse(String filename, List<LocalizableMessage> warnings) 552 throws IOException, InitializationException, MakeLDIFException 553 { 554 templatePath = null; 555 File f = getFile(filename); 556 if (f == null || !f.exists()) 557 { 558 LocalizableMessage message = ERR_MAKELDIF_COULD_NOT_FIND_TEMPLATE_FILE.get(filename); 559 throw new IOException(message.toString()); 560 } 561 templatePath = f.getParentFile().getAbsolutePath(); 562 563 List<String> fileLines = readLines(f); 564 String[] lines = new String[fileLines.size()]; 565 fileLines.toArray(lines); 566 parse(lines, warnings); 567 } 568 569 570 571 /** 572 * Parses the data read from the provided input stream as a MakeLDIF template 573 * file definition. 574 * 575 * @param inputStream The input stream from which to read the template file 576 * data. 577 * @param warnings A list into which any warnings identified may be 578 * placed. 579 * 580 * @throws IOException If a problem occurs while attempting to read data 581 * from the provided input stream. 582 * 583 * @throws InitializationException If a problem occurs while initializing 584 * any of the MakeLDIF components. 585 * 586 * @throws MakeLDIFException If any other problem occurs while parsing the 587 * template file. 588 */ 589 public void parse(InputStream inputStream, List<LocalizableMessage> warnings) 590 throws IOException, InitializationException, MakeLDIFException 591 { 592 ArrayList<String> fileLines = new ArrayList<>(); 593 594 try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) 595 { 596 while (true) 597 { 598 String line = reader.readLine(); 599 if (line == null) 600 { 601 break; 602 } 603 fileLines.add(line); 604 } 605 } 606 607 String[] lines = new String[fileLines.size()]; 608 fileLines.toArray(lines); 609 parse(lines, warnings); 610 } 611 612 613 614 /** 615 * Parses the provided data as a MakeLDIF template file definition. 616 * 617 * @param lines The lines that make up the template file. 618 * @param warnings A list into which any warnings identified may be placed. 619 * 620 * @throws InitializationException If a problem occurs while initializing 621 * any of the MakeLDIF components. 622 * 623 * @throws MakeLDIFException If any other problem occurs while parsing the 624 * template file. 625 */ 626 public void parse(String[] lines, List<LocalizableMessage> warnings) 627 throws InitializationException, MakeLDIFException 628 { 629 // Create temporary variables that will be used to hold the data read. 630 LinkedHashMap<String,Tag> templateFileIncludeTags = new LinkedHashMap<>(); 631 LinkedHashMap<String,String> templateFileConstants = new LinkedHashMap<>(); 632 LinkedHashMap<DN,Branch> templateFileBranches = new LinkedHashMap<>(); 633 LinkedHashMap<String,Template> templateFileTemplates = new LinkedHashMap<>(); 634 635 for (int lineNumber=0; lineNumber < lines.length; lineNumber++) 636 { 637 String line = lines[lineNumber]; 638 639 line = replaceConstants(line, lineNumber, 640 templateFileConstants, warnings); 641 642 String lowerLine = toLowerCase(line); 643 if (line.length() == 0 || line.startsWith("#")) 644 { 645 // This is a comment or a blank line, so we'll ignore it. 646 continue; 647 } 648 else if (lowerLine.startsWith("include ")) 649 { 650 // This should be an include definition. The next element should be the 651 // name of the class. Load and instantiate it and make sure there are 652 // no conflicts. 653 String className = line.substring(8).trim(); 654 655 Class tagClass; 656 try 657 { 658 tagClass = Class.forName(className); 659 } 660 catch (Exception e) 661 { 662 LocalizableMessage message = ERR_MAKELDIF_CANNOT_LOAD_TAG_CLASS.get(className); 663 throw new MakeLDIFException(message, e); 664 } 665 666 Tag tag; 667 try 668 { 669 tag = (Tag) tagClass.newInstance(); 670 } 671 catch (Exception e) 672 { 673 LocalizableMessage message = ERR_MAKELDIF_CANNOT_INSTANTIATE_TAG.get(className); 674 throw new MakeLDIFException(message, e); 675 } 676 677 String lowerName = toLowerCase(tag.getName()); 678 if (registeredTags.containsKey(lowerName) || 679 templateFileIncludeTags.containsKey(lowerName)) 680 { 681 LocalizableMessage message = 682 ERR_MAKELDIF_CONFLICTING_TAG_NAME.get(className, tag.getName()); 683 throw new MakeLDIFException(message); 684 } 685 686 templateFileIncludeTags.put(lowerName, tag); 687 } 688 else if (lowerLine.startsWith("define ")) 689 { 690 // This should be a constant definition. The rest of the line should 691 // contain the constant name, an equal sign, and the constant value. 692 int equalPos = line.indexOf('=', 7); 693 if (equalPos < 0) 694 { 695 LocalizableMessage message = ERR_MAKELDIF_DEFINE_MISSING_EQUALS.get(lineNumber); 696 throw new MakeLDIFException(message); 697 } 698 699 String name = line.substring(7, equalPos).trim(); 700 if (name.length() == 0) 701 { 702 LocalizableMessage message = ERR_MAKELDIF_DEFINE_NAME_EMPTY.get(lineNumber); 703 throw new MakeLDIFException(message); 704 } 705 706 String lowerName = toLowerCase(name); 707 if (templateFileConstants.containsKey(lowerName)) 708 { 709 LocalizableMessage message = 710 ERR_MAKELDIF_CONFLICTING_CONSTANT_NAME.get(name, lineNumber); 711 throw new MakeLDIFException(message); 712 } 713 714 String value = line.substring(equalPos+1); 715 if (value.length() == 0) 716 { 717 LocalizableMessage message = ERR_MAKELDIF_WARNING_DEFINE_VALUE_EMPTY.get( 718 name, lineNumber); 719 warnings.add(message); 720 } 721 722 templateFileConstants.put(lowerName, value); 723 } 724 else if (lowerLine.startsWith("branch: ")) 725 { 726 int startLineNumber = lineNumber; 727 ArrayList<String> lineList = new ArrayList<>(); 728 lineList.add(line); 729 while (true) 730 { 731 lineNumber++; 732 if (lineNumber >= lines.length) 733 { 734 break; 735 } 736 737 line = lines[lineNumber]; 738 if (line.length() == 0) 739 { 740 break; 741 } 742 line = replaceConstants(line, lineNumber, templateFileConstants, warnings); 743 lineList.add(line); 744 } 745 746 String[] branchLines = new String[lineList.size()]; 747 lineList.toArray(branchLines); 748 749 Branch b = parseBranchDefinition(branchLines, lineNumber, 750 templateFileIncludeTags, 751 warnings); 752 DN branchDN = b.getBranchDN(); 753 if (templateFileBranches.containsKey(branchDN)) 754 { 755 LocalizableMessage message = ERR_MAKELDIF_CONFLICTING_BRANCH_DN.get(branchDN, startLineNumber); 756 throw new MakeLDIFException(message); 757 } 758 else 759 { 760 templateFileBranches.put(branchDN, b); 761 } 762 } 763 else if (lowerLine.startsWith("template: ")) 764 { 765 int startLineNumber = lineNumber; 766 ArrayList<String> lineList = new ArrayList<>(); 767 lineList.add(line); 768 while (true) 769 { 770 lineNumber++; 771 if (lineNumber >= lines.length) 772 { 773 break; 774 } 775 776 line = lines[lineNumber]; 777 if (line.length() == 0) 778 { 779 break; 780 } 781 line = replaceConstants(line, lineNumber, templateFileConstants, warnings); 782 lineList.add(line); 783 } 784 785 String[] templateLines = new String[lineList.size()]; 786 lineList.toArray(templateLines); 787 788 Template t = parseTemplateDefinition(templateLines, startLineNumber, 789 templateFileIncludeTags, 790 templateFileTemplates, warnings); 791 String lowerName = toLowerCase(t.getName()); 792 if (templateFileTemplates.containsKey(lowerName)) 793 { 794 LocalizableMessage message = ERR_MAKELDIF_CONFLICTING_TEMPLATE_NAME.get(t.getName(), startLineNumber); 795 throw new MakeLDIFException(message); 796 } 797 templateFileTemplates.put(lowerName, t); 798 } 799 else 800 { 801 LocalizableMessage message = 802 ERR_MAKELDIF_UNEXPECTED_TEMPLATE_FILE_LINE.get(line, lineNumber); 803 throw new MakeLDIFException(message); 804 } 805 } 806 807 808 // If we've gotten here, then we're almost done. We just need to finalize 809 // the branch and template definitions and then update the template file 810 // variables. 811 for (Branch b : templateFileBranches.values()) 812 { 813 b.completeBranchInitialization(templateFileTemplates); 814 } 815 816 for (Template t : templateFileTemplates.values()) 817 { 818 t.completeTemplateInitialization(templateFileTemplates); 819 } 820 821 registeredTags.putAll(templateFileIncludeTags); 822 constants.putAll(templateFileConstants); 823 branches.putAll(templateFileBranches); 824 templates.putAll(templateFileTemplates); 825 } 826 827 828 /** 829 * Parse a line and replace all constants within [ ] with their 830 * values. 831 * 832 * @param line The line to parse. 833 * @param lineNumber The line number in the template file. 834 * @param constants The set of constants defined in the template file. 835 * @param warnings A list into which any warnings identified may be 836 * placed. 837 * @return The line in which all constant variables have been replaced 838 * with their value 839 */ 840 private String replaceConstants(String line, int lineNumber, 841 Map<String,String> constants, 842 List<LocalizableMessage> warnings) 843 { 844 int closePos = line.lastIndexOf(']'); 845 // Loop until we've scanned all closing brackets 846 do 847 { 848 // Skip escaped closing brackets 849 while (closePos > 0 && 850 line.charAt(closePos - 1) == '\\') 851 { 852 closePos = line.lastIndexOf(']', closePos - 1); 853 } 854 if (closePos > 0) 855 { 856 StringBuilder lineBuffer = new StringBuilder(line); 857 int openPos = line.lastIndexOf('[', closePos); 858 // Find the opening bracket. If it's escaped, then it's not a constant 859 if ((openPos > 0 && line.charAt(openPos - 1) != '\\') 860 || openPos == 0) 861 { 862 String constantName = 863 toLowerCase(line.substring(openPos+1, closePos)); 864 String constantValue = constants.get(constantName); 865 if (constantValue == null) 866 { 867 LocalizableMessage message = WARN_MAKELDIF_WARNING_UNDEFINED_CONSTANT.get( 868 constantName, lineNumber); 869 warnings.add(message); 870 } 871 else 872 { 873 lineBuffer.replace(openPos, closePos+1, constantValue); 874 } 875 } 876 if (openPos >= 0) 877 { 878 closePos = openPos; 879 } 880 line = lineBuffer.toString(); 881 closePos = line.lastIndexOf(']', closePos); 882 } 883 } while (closePos > 0); 884 return line; 885 } 886 887 /** 888 * Parses the information contained in the provided set of lines as a MakeLDIF 889 * branch definition. 890 * 891 * 892 * @param branchLines The set of lines containing the branch definition. 893 * @param startLineNumber The line number in the template file on which the 894 * first of the branch lines appears. 895 * @param tags The set of defined tags from the template file. 896 * Note that this does not include the tags that are 897 * always registered by default. 898 * @param warnings A list into which any warnings identified may be 899 * placed. 900 * 901 * @return The decoded branch definition. 902 * 903 * @throws InitializationException If a problem occurs while initializing 904 * any of the branch elements. 905 * 906 * @throws MakeLDIFException If some other problem occurs during processing. 907 */ 908 private Branch parseBranchDefinition(String[] branchLines, 909 int startLineNumber, 910 Map<String, Tag> tags, 911 List<LocalizableMessage> warnings) 912 throws InitializationException, MakeLDIFException 913 { 914 // The first line must be "branch: " followed by the branch DN. 915 String dnString = branchLines[0].substring(8).trim(); 916 DN branchDN; 917 try 918 { 919 branchDN = DN.valueOf(dnString); 920 } 921 catch (Exception e) 922 { 923 LocalizableMessage message = 924 ERR_MAKELDIF_CANNOT_DECODE_BRANCH_DN.get(dnString, startLineNumber); 925 throw new MakeLDIFException(message); 926 } 927 928 929 // Create a new branch that will be used for the verification process. 930 Branch branch = new Branch(this, branchDN); 931 932 for (int i=1; i < branchLines.length; i++) 933 { 934 String line = branchLines[i]; 935 String lowerLine = toLowerCase(line); 936 int lineNumber = startLineNumber + i; 937 938 if (lowerLine.startsWith("#")) 939 { 940 // It's a comment, so we should ignore it. 941 continue; 942 } 943 else if (lowerLine.startsWith("subordinatetemplate: ")) 944 { 945 // It's a subordinate template, so we'll want to parse the name and the 946 // number of entries. 947 int colonPos = line.indexOf(':', 21); 948 if (colonPos <= 21) 949 { 950 LocalizableMessage message = ERR_MAKELDIF_BRANCH_SUBORDINATE_TEMPLATE_NO_COLON. 951 get(lineNumber, dnString); 952 throw new MakeLDIFException(message); 953 } 954 955 String templateName = line.substring(21, colonPos).trim(); 956 957 int numEntries; 958 try 959 { 960 numEntries = Integer.parseInt(line.substring(colonPos+1).trim()); 961 if (numEntries < 0) 962 { 963 LocalizableMessage message = 964 ERR_MAKELDIF_BRANCH_SUBORDINATE_INVALID_NUM_ENTRIES. 965 get(lineNumber, dnString, numEntries, templateName); 966 throw new MakeLDIFException(message); 967 } 968 else if (numEntries == 0) 969 { 970 LocalizableMessage message = WARN_MAKELDIF_BRANCH_SUBORDINATE_ZERO_ENTRIES.get( 971 lineNumber, dnString, 972 templateName); 973 warnings.add(message); 974 } 975 976 branch.addSubordinateTemplate(templateName, numEntries); 977 } 978 catch (NumberFormatException nfe) 979 { 980 LocalizableMessage message = 981 ERR_MAKELDIF_BRANCH_SUBORDINATE_CANT_PARSE_NUMENTRIES. 982 get(templateName, lineNumber, dnString); 983 throw new MakeLDIFException(message); 984 } 985 } 986 else 987 { 988 TemplateLine templateLine = parseTemplateLine(line, lowerLine, 989 lineNumber, branch, null, 990 tags, warnings); 991 branch.addExtraLine(templateLine); 992 } 993 } 994 995 return branch; 996 } 997 998 999 1000 /** 1001 * Parses the information contained in the provided set of lines as a MakeLDIF 1002 * template definition. 1003 * 1004 * 1005 * @param templateLines The set of lines containing the template 1006 * definition. 1007 * @param startLineNumber The line number in the template file on which the 1008 * first of the template lines appears. 1009 * @param tags The set of defined tags from the template file. 1010 * Note that this does not include the tags that are 1011 * always registered by default. 1012 * @param definedTemplates The set of templates already defined in the 1013 * template file. 1014 * @param warnings A list into which any warnings identified may be 1015 * placed. 1016 * 1017 * @return The decoded template definition. 1018 * 1019 * @throws InitializationException If a problem occurs while initializing 1020 * any of the template elements. 1021 * 1022 * @throws MakeLDIFException If some other problem occurs during processing. 1023 */ 1024 private Template parseTemplateDefinition(String[] templateLines, 1025 int startLineNumber, 1026 Map<String, Tag> tags, 1027 Map<String, Template> 1028 definedTemplates, 1029 List<LocalizableMessage> warnings) 1030 throws InitializationException, MakeLDIFException 1031 { 1032 // The first line must be "template: " followed by the template name. 1033 String templateName = templateLines[0].substring(10).trim(); 1034 1035 1036 // The next line may start with either "extends: ", "rdnAttr: ", or 1037 // "subordinateTemplate: ". Keep reading until we find something that's 1038 // not one of those. 1039 int arrayLineNumber = 1; 1040 Template parentTemplate = null; 1041 AttributeType[] rdnAttributes = null; 1042 ArrayList<String> subTemplateNames = new ArrayList<>(); 1043 ArrayList<Integer> entriesPerTemplate = new ArrayList<>(); 1044 for ( ; arrayLineNumber < templateLines.length; arrayLineNumber++) 1045 { 1046 int lineNumber = startLineNumber + arrayLineNumber; 1047 String line = templateLines[arrayLineNumber]; 1048 String lowerLine = toLowerCase(line); 1049 1050 if (lowerLine.startsWith("#")) 1051 { 1052 // It's a comment. Ignore it. 1053 continue; 1054 } 1055 else if (lowerLine.startsWith("extends: ")) 1056 { 1057 String parentTemplateName = line.substring(9).trim(); 1058 parentTemplate = definedTemplates.get(parentTemplateName.toLowerCase()); 1059 if (parentTemplate == null) 1060 { 1061 LocalizableMessage message = ERR_MAKELDIF_TEMPLATE_INVALID_PARENT_TEMPLATE.get( 1062 parentTemplateName, lineNumber, templateName); 1063 throw new MakeLDIFException(message); 1064 } 1065 } 1066 else if (lowerLine.startsWith("rdnattr: ")) 1067 { 1068 // This is the set of RDN attributes. If there are multiple, they may 1069 // be separated by plus signs. 1070 ArrayList<AttributeType> attrList = new ArrayList<>(); 1071 String rdnAttrNames = lowerLine.substring(9).trim(); 1072 StringTokenizer tokenizer = new StringTokenizer(rdnAttrNames, "+"); 1073 while (tokenizer.hasMoreTokens()) 1074 { 1075 attrList.add(DirectoryServer.getAttributeType(tokenizer.nextToken())); 1076 } 1077 1078 rdnAttributes = new AttributeType[attrList.size()]; 1079 attrList.toArray(rdnAttributes); 1080 } 1081 else if (lowerLine.startsWith("subordinatetemplate: ")) 1082 { 1083 // It's a subordinate template, so we'll want to parse the name and the 1084 // number of entries. 1085 int colonPos = line.indexOf(':', 21); 1086 if (colonPos <= 21) 1087 { 1088 LocalizableMessage message = ERR_MAKELDIF_TEMPLATE_SUBORDINATE_TEMPLATE_NO_COLON. 1089 get(lineNumber, templateName); 1090 throw new MakeLDIFException(message); 1091 } 1092 1093 String subTemplateName = line.substring(21, colonPos).trim(); 1094 1095 int numEntries; 1096 try 1097 { 1098 numEntries = Integer.parseInt(line.substring(colonPos+1).trim()); 1099 if (numEntries < 0) 1100 { 1101 LocalizableMessage message = 1102 ERR_MAKELDIF_TEMPLATE_SUBORDINATE_INVALID_NUM_ENTRIES. 1103 get(lineNumber, templateName, numEntries, subTemplateName); 1104 throw new MakeLDIFException(message); 1105 } 1106 else if (numEntries == 0) 1107 { 1108 LocalizableMessage message = WARN_MAKELDIF_TEMPLATE_SUBORDINATE_ZERO_ENTRIES 1109 .get(lineNumber, templateName, subTemplateName); 1110 warnings.add(message); 1111 } 1112 1113 subTemplateNames.add(subTemplateName); 1114 entriesPerTemplate.add(numEntries); 1115 } 1116 catch (NumberFormatException nfe) 1117 { 1118 LocalizableMessage message = 1119 ERR_MAKELDIF_TEMPLATE_SUBORDINATE_CANT_PARSE_NUMENTRIES. 1120 get(subTemplateName, lineNumber, templateName); 1121 throw new MakeLDIFException(message); 1122 } 1123 } 1124 else 1125 { 1126 // It's something we don't recognize, so it must be a template line. 1127 break; 1128 } 1129 } 1130 1131 // Create a new template that will be used for the verification process. 1132 String[] subordinateTemplateNames = new String[subTemplateNames.size()]; 1133 subTemplateNames.toArray(subordinateTemplateNames); 1134 1135 int[] numEntriesPerTemplate = new int[entriesPerTemplate.size()]; 1136 for (int i=0; i < numEntriesPerTemplate.length; i++) 1137 { 1138 numEntriesPerTemplate[i] = entriesPerTemplate.get(i); 1139 } 1140 1141 TemplateLine[] parsedLines; 1142 if (parentTemplate == null) 1143 { 1144 parsedLines = new TemplateLine[0]; 1145 } 1146 else 1147 { 1148 TemplateLine[] parentLines = parentTemplate.getTemplateLines(); 1149 parsedLines = new TemplateLine[parentLines.length]; 1150 System.arraycopy(parentLines, 0, parsedLines, 0, parentLines.length); 1151 } 1152 1153 Template template = new Template(this, templateName, rdnAttributes, 1154 subordinateTemplateNames, 1155 numEntriesPerTemplate, parsedLines); 1156 1157 for ( ; arrayLineNumber < templateLines.length; arrayLineNumber++) 1158 { 1159 String line = templateLines[arrayLineNumber]; 1160 String lowerLine = toLowerCase(line); 1161 int lineNumber = startLineNumber + arrayLineNumber; 1162 1163 if (lowerLine.startsWith("#")) 1164 { 1165 // It's a comment, so we should ignore it. 1166 continue; 1167 } 1168 else 1169 { 1170 TemplateLine templateLine = parseTemplateLine(line, lowerLine, 1171 lineNumber, null, 1172 template, tags, warnings); 1173 template.addTemplateLine(templateLine); 1174 } 1175 } 1176 1177 return template; 1178 } 1179 1180 1181 1182 /** 1183 * Parses the provided line as a template line. Note that exactly one of the 1184 * branch or template arguments must be non-null and the other must be null. 1185 * 1186 * @param line The text of the template line. 1187 * @param lowerLine The template line in all lowercase characters. 1188 * @param lineNumber The line number on which the template line appears. 1189 * @param branch The branch with which the template line is associated. 1190 * @param template The template with which the template line is 1191 * associated. 1192 * @param tags The set of defined tags from the template file. Note 1193 * that this does not include the tags that are always 1194 * registered by default. 1195 * @param warnings A list into which any warnings identified may be 1196 * placed. 1197 * 1198 * @return The template line that has been parsed. 1199 * 1200 * @throws InitializationException If a problem occurs while initializing 1201 * any of the template elements. 1202 * 1203 * @throws MakeLDIFException If some other problem occurs during processing. 1204 */ 1205 private TemplateLine parseTemplateLine(String line, String lowerLine, 1206 int lineNumber, Branch branch, 1207 Template template, 1208 Map<String,Tag> tags, 1209 List<LocalizableMessage> warnings) 1210 throws InitializationException, MakeLDIFException 1211 { 1212 // The first component must be the attribute type, followed by a colon. 1213 int colonPos = lowerLine.indexOf(':'); 1214 if (colonPos < 0) 1215 { 1216 if (branch == null) 1217 { 1218 LocalizableMessage message = ERR_MAKELDIF_NO_COLON_IN_TEMPLATE_LINE.get( 1219 lineNumber, template.getName()); 1220 throw new MakeLDIFException(message); 1221 } 1222 else 1223 { 1224 LocalizableMessage message = ERR_MAKELDIF_NO_COLON_IN_BRANCH_EXTRA_LINE.get( 1225 lineNumber, branch.getBranchDN()); 1226 throw new MakeLDIFException(message); 1227 } 1228 } 1229 else if (colonPos == 0) 1230 { 1231 if (branch == null) 1232 { 1233 LocalizableMessage message = ERR_MAKELDIF_NO_ATTR_IN_TEMPLATE_LINE.get( 1234 lineNumber, template.getName()); 1235 throw new MakeLDIFException(message); 1236 } 1237 else 1238 { 1239 LocalizableMessage message = ERR_MAKELDIF_NO_ATTR_IN_BRANCH_EXTRA_LINE.get( 1240 lineNumber, branch.getBranchDN()); 1241 throw new MakeLDIFException(message); 1242 } 1243 } 1244 1245 AttributeType attributeType = DirectoryServer.getAttributeType(lowerLine.substring(0, colonPos)); 1246 1247 // First, check whether the value is an URL value: <attrName>:< <url> 1248 int length = line.length(); 1249 int pos = colonPos + 1; 1250 boolean valueIsURL = false; 1251 boolean valueIsBase64 = false; 1252 if (pos < length) 1253 { 1254 if (lowerLine.charAt(pos) == '<') 1255 { 1256 valueIsURL = true; 1257 pos ++; 1258 } 1259 else if (lowerLine.charAt(pos) == ':') 1260 { 1261 valueIsBase64 = true; 1262 pos ++; 1263 } 1264 } 1265 // Then, find the position of the first non-blank character in the line. 1266 while (pos < length && lowerLine.charAt(pos) == ' ') 1267 { 1268 pos++; 1269 } 1270 1271 if (pos >= length) 1272 { 1273 // We've hit the end of the line with no value. We'll allow it, but add a 1274 // warning. 1275 if (branch == null) 1276 { 1277 LocalizableMessage message = WARN_MAKELDIF_NO_VALUE_IN_TEMPLATE_LINE.get( 1278 lineNumber, template.getName()); 1279 warnings.add(message); 1280 } 1281 else 1282 { 1283 LocalizableMessage message = WARN_MAKELDIF_NO_VALUE_IN_BRANCH_EXTRA_LINE.get( 1284 lineNumber, branch.getBranchDN()); 1285 warnings.add(message); 1286 } 1287 } 1288 1289 1290 // Define constants that specify what we're currently parsing. 1291 final int PARSING_STATIC_TEXT = 0; 1292 final int PARSING_REPLACEMENT_TAG = 1; 1293 final int PARSING_ATTRIBUTE_TAG = 2; 1294 final int PARSING_ESCAPED_CHAR = 3; 1295 1296 int phase = PARSING_STATIC_TEXT; 1297 int previousPhase = PARSING_STATIC_TEXT; 1298 1299 ArrayList<Tag> tagList = new ArrayList<>(); 1300 StringBuilder buffer = new StringBuilder(); 1301 1302 for ( ; pos < length; pos++) 1303 { 1304 char c = line.charAt(pos); 1305 switch (phase) 1306 { 1307 case PARSING_STATIC_TEXT: 1308 switch (c) 1309 { 1310 case '\\': 1311 phase = PARSING_ESCAPED_CHAR; 1312 previousPhase = PARSING_STATIC_TEXT; 1313 break; 1314 case '<': 1315 if (buffer.length() > 0) 1316 { 1317 StaticTextTag t = new StaticTextTag(); 1318 String[] args = new String[] { buffer.toString() }; 1319 t.initializeForBranch(this, branch, args, lineNumber, 1320 warnings); 1321 tagList.add(t); 1322 buffer = new StringBuilder(); 1323 } 1324 1325 phase = PARSING_REPLACEMENT_TAG; 1326 break; 1327 case '{': 1328 if (buffer.length() > 0) 1329 { 1330 StaticTextTag t = new StaticTextTag(); 1331 String[] args = new String[] { buffer.toString() }; 1332 t.initializeForBranch(this, branch, args, lineNumber, 1333 warnings); 1334 tagList.add(t); 1335 buffer = new StringBuilder(); 1336 } 1337 1338 phase = PARSING_ATTRIBUTE_TAG; 1339 break; 1340 default: 1341 buffer.append(c); 1342 } 1343 break; 1344 1345 case PARSING_REPLACEMENT_TAG: 1346 switch (c) 1347 { 1348 case '\\': 1349 phase = PARSING_ESCAPED_CHAR; 1350 previousPhase = PARSING_REPLACEMENT_TAG; 1351 break; 1352 case '>': 1353 Tag t = parseReplacementTag(buffer.toString(), branch, template, 1354 lineNumber, tags, warnings); 1355 tagList.add(t); 1356 buffer = new StringBuilder(); 1357 1358 phase = PARSING_STATIC_TEXT; 1359 break; 1360 default: 1361 buffer.append(c); 1362 break; 1363 } 1364 break; 1365 1366 case PARSING_ATTRIBUTE_TAG: 1367 switch (c) 1368 { 1369 case '\\': 1370 phase = PARSING_ESCAPED_CHAR; 1371 previousPhase = PARSING_ATTRIBUTE_TAG; 1372 break; 1373 case '}': 1374 Tag t = parseAttributeTag(buffer.toString(), branch, template, 1375 lineNumber, warnings); 1376 tagList.add(t); 1377 buffer = new StringBuilder(); 1378 1379 phase = PARSING_STATIC_TEXT; 1380 break; 1381 default: 1382 buffer.append(c); 1383 break; 1384 } 1385 break; 1386 1387 case PARSING_ESCAPED_CHAR: 1388 buffer.append(c); 1389 phase = previousPhase; 1390 break; 1391 } 1392 } 1393 1394 if (phase == PARSING_STATIC_TEXT) 1395 { 1396 if (buffer.length() > 0) 1397 { 1398 StaticTextTag t = new StaticTextTag(); 1399 String[] args = new String[] { buffer.toString() }; 1400 t.initializeForBranch(this, branch, args, lineNumber, warnings); 1401 tagList.add(t); 1402 } 1403 } 1404 else 1405 { 1406 LocalizableMessage message = ERR_MAKELDIF_INCOMPLETE_TAG.get(lineNumber); 1407 throw new InitializationException(message); 1408 } 1409 1410 Tag[] tagArray = new Tag[tagList.size()]; 1411 tagList.toArray(tagArray); 1412 return new TemplateLine(attributeType, lineNumber, tagArray, valueIsURL, 1413 valueIsBase64); 1414 } 1415 1416 1417 1418 /** 1419 * Parses the provided string as a replacement tag. Exactly one of the branch 1420 * or template must be null, and the other must be non-null. 1421 * 1422 * @param tagString The string containing the encoded tag. 1423 * @param branch The branch in which this tag appears. 1424 * @param template The template in which this tag appears. 1425 * @param lineNumber The line number on which this tag appears in the 1426 * template file. 1427 * @param tags The set of defined tags from the template file. Note 1428 * that this does not include the tags that are always 1429 * registered by default. 1430 * @param warnings A list into which any warnings identified may be 1431 * placed. 1432 * 1433 * @return The replacement tag parsed from the provided string. 1434 * 1435 * @throws InitializationException If a problem occurs while initializing 1436 * the tag. 1437 * 1438 * @throws MakeLDIFException If some other problem occurs during processing. 1439 */ 1440 private Tag parseReplacementTag(String tagString, Branch branch, 1441 Template template, int lineNumber, 1442 Map<String,Tag> tags, 1443 List<LocalizableMessage> warnings) 1444 throws InitializationException, MakeLDIFException 1445 { 1446 // The components of the replacement tag will be separated by colons, with 1447 // the first being the tag name and the remainder being arguments. 1448 StringTokenizer tokenizer = new StringTokenizer(tagString, ":"); 1449 String tagName = tokenizer.nextToken().trim(); 1450 String lowerTagName = toLowerCase(tagName); 1451 1452 Tag t = getTag(lowerTagName); 1453 if (t == null) 1454 { 1455 t = tags.get(lowerTagName); 1456 if (t == null) 1457 { 1458 LocalizableMessage message = ERR_MAKELDIF_NO_SUCH_TAG.get(tagName, lineNumber); 1459 throw new MakeLDIFException(message); 1460 } 1461 } 1462 1463 ArrayList<String> argList = new ArrayList<>(); 1464 while (tokenizer.hasMoreTokens()) 1465 { 1466 argList.add(tokenizer.nextToken().trim()); 1467 } 1468 1469 String[] args = new String[argList.size()]; 1470 argList.toArray(args); 1471 1472 1473 Tag newTag; 1474 try 1475 { 1476 newTag = t.getClass().newInstance(); 1477 } 1478 catch (Exception e) 1479 { 1480 throw new MakeLDIFException(ERR_MAKELDIF_CANNOT_INSTANTIATE_NEW_TAG.get(tagName, lineNumber, e), e); 1481 } 1482 1483 1484 if (branch == null) 1485 { 1486 newTag.initializeForTemplate(this, template, args, lineNumber, warnings); 1487 } 1488 else 1489 { 1490 if (newTag.allowedInBranch()) 1491 { 1492 newTag.initializeForBranch(this, branch, args, lineNumber, warnings); 1493 } 1494 else 1495 { 1496 LocalizableMessage message = ERR_MAKELDIF_TAG_NOT_ALLOWED_IN_BRANCH.get( 1497 newTag.getName(), lineNumber); 1498 throw new MakeLDIFException(message); 1499 } 1500 } 1501 1502 return newTag; 1503 } 1504 1505 1506 1507 /** 1508 * Parses the provided string as an attribute tag. Exactly one of the branch 1509 * or template must be null, and the other must be non-null. 1510 * 1511 * @param tagString The string containing the encoded tag. 1512 * @param branch The branch in which this tag appears. 1513 * @param template The template in which this tag appears. 1514 * @param lineNumber The line number on which this tag appears in the 1515 * template file. 1516 * @param warnings A list into which any warnings identified may be 1517 * placed. 1518 * 1519 * @return The attribute tag parsed from the provided string. 1520 * 1521 * @throws InitializationException If a problem occurs while initializing 1522 * the tag. 1523 * 1524 * @throws MakeLDIFException If some other problem occurs during processing. 1525 */ 1526 private Tag parseAttributeTag(String tagString, Branch branch, 1527 Template template, int lineNumber, 1528 List<LocalizableMessage> warnings) 1529 throws InitializationException, MakeLDIFException 1530 { 1531 // The attribute tag must have at least one argument, which is the name of 1532 // the attribute to reference. It may have a second argument, which is the 1533 // number of characters to use from the attribute value. The arguments will 1534 // be delimited by colons. 1535 StringTokenizer tokenizer = new StringTokenizer(tagString, ":"); 1536 ArrayList<String> argList = new ArrayList<>(); 1537 while (tokenizer.hasMoreTokens()) 1538 { 1539 argList.add(tokenizer.nextToken()); 1540 } 1541 1542 String[] args = new String[argList.size()]; 1543 argList.toArray(args); 1544 1545 AttributeValueTag tag = new AttributeValueTag(); 1546 if (branch == null) 1547 { 1548 tag.initializeForTemplate(this, template, args, lineNumber, warnings); 1549 } 1550 else 1551 { 1552 tag.initializeForBranch(this, branch, args, lineNumber, warnings); 1553 } 1554 1555 return tag; 1556 } 1557 1558 1559 1560 /** 1561 * Retrieves a File object based on the provided path. If the given path is 1562 * absolute, then that absolute path will be used. If it is relative, then it 1563 * will first be evaluated relative to the current working directory. If that 1564 * path doesn't exist, then it will be evaluated relative to the resource 1565 * path. If that path doesn't exist, then it will be evaluated relative to 1566 * the directory containing the template file. 1567 * 1568 * @param path The path provided for the file. 1569 * 1570 * @return The File object for the specified path, or <CODE>null</CODE> if 1571 * the specified file could not be found. 1572 */ 1573 public File getFile(String path) 1574 { 1575 // First, see if the file exists using the given path. This will work if 1576 // the file is absolute, or it's relative to the current working directory. 1577 File f = new File(path); 1578 if (f.exists()) 1579 { 1580 return f; 1581 } 1582 1583 1584 // If the provided path was absolute, then use it anyway, even though we 1585 // couldn't find the file. 1586 if (f.isAbsolute()) 1587 { 1588 return f; 1589 } 1590 1591 1592 // Try a path relative to the resource directory. 1593 String newPath = resourcePath + File.separator + path; 1594 f = new File(newPath); 1595 if (f.exists()) 1596 { 1597 return f; 1598 } 1599 1600 1601 // Try a path relative to the template directory, if it's available. 1602 if (templatePath != null) 1603 { 1604 newPath = templatePath = File.separator + path; 1605 f = new File(newPath); 1606 if (f.exists()) 1607 { 1608 return f; 1609 } 1610 } 1611 1612 return null; 1613 } 1614 1615 1616 1617 /** 1618 * Retrieves the lines of the specified file as a string array. If the result 1619 * is already cached, then it will be used. If the result is not cached, then 1620 * the file data will be cached so that the contents can be re-used if there 1621 * are multiple references to the same file. 1622 * 1623 * @param file The file for which to retrieve the contents. 1624 * 1625 * @return An array containing the lines of the specified file. 1626 * 1627 * @throws IOException If a problem occurs while reading the file. 1628 */ 1629 public String[] getFileLines(File file) throws IOException 1630 { 1631 String absolutePath = file.getAbsolutePath(); 1632 String[] lines = fileLines.get(absolutePath); 1633 if (lines == null) 1634 { 1635 List<String> lineList = readLines(file); 1636 1637 lines = new String[lineList.size()]; 1638 lineList.toArray(lines); 1639 lineList.clear(); 1640 fileLines.put(absolutePath, lines); 1641 } 1642 1643 return lines; 1644 } 1645 1646 1647 1648 /** 1649 * Generates the LDIF content and writes it to the provided LDIF writer. 1650 * 1651 * @param entryWriter The entry writer that should be used to write the 1652 * entries. 1653 * 1654 * @return The result that indicates whether processing should continue. 1655 * 1656 * @throws IOException If an error occurs while writing to the LDIF file. 1657 * 1658 * @throws MakeLDIFException If some other problem occurs. 1659 */ 1660 public TagResult generateLDIF(EntryWriter entryWriter) 1661 throws IOException, MakeLDIFException 1662 { 1663 for (Branch b : branches.values()) 1664 { 1665 TagResult result = b.writeEntries(entryWriter); 1666 if (!result.keepProcessingTemplateFile()) 1667 { 1668 return result; 1669 } 1670 } 1671 1672 entryWriter.closeEntryWriter(); 1673 return TagResult.SUCCESS_RESULT; 1674 } 1675} 1676