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