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