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