opendj3/opendj-core/src/main/java/com/forgerock/opendj/util/Pair.java
New file @@ -0,0 +1,152 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt * or http://forgerock.org/license/CDDLv1.0.html. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at legal-notices/CDDLv1_0.txt. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2013 ForgeRock AS */ package com.forgerock.opendj.util; /** * Ordered pair of arbitrary objects. * * @param <F> * type of the first pair element * @param <S> * type of the second pair element */ public final class Pair<F, S> { /** An empty Pair. */ public static final Pair<?, ?> EMPTY = Pair.of(null, null); /** The first pair element. */ private final F first; /** The second pair element. */ private final S second; /** * Creates a pair. * * @param first * the first element of the constructed pair * @param second * the second element of the constructed pair */ private Pair(F first, S second) { this.first = first; this.second = second; } /** * Factory method to build a new Pair. * * @param first * the first element of the constructed pair * @param second * the second element of the constructed pair * @param <F> * type of the first pair element * @param <S> * type of the second pair element * @return A new Pair built with the provided elements */ public static <F, S> Pair<F, S> of(F first, S second) { return new Pair<F, S>(first, second); } /** * Returns an empty Pair matching the required types. * * @param <F> * type of the first pair element * @param <S> * type of the second pair element * @return An empty Pair matching the required types */ @SuppressWarnings("unchecked") public static <F, S> Pair<F, S> empty() { return (Pair<F, S>) EMPTY; } /** * Returns the first element of this pair. * * @return the first element of this pair */ public F getFirst() { return first; } /** * Returns the second element of this pair. * * @return the second element of this pair */ public S getSecond() { return second; } /** {@inheritDoc} */ @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((first == null) ? 0 : first.hashCode()); result = prime * result + ((second == null) ? 0 : second.hashCode()); return result; } /** {@inheritDoc} */ @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof Pair)) { return false; } Pair<?, ?> other = (Pair<?, ?>) obj; if (first == null) { if (other.first != null) { return false; } } else if (!first.equals(other.first)) { return false; } if (second == null) { if (other.second != null) { return false; } } else if (!second.equals(other.second)) { return false; } return true; } /** {@inheritDoc} */ @Override public String toString() { return "Pair [" + first + ", " + second + "]"; } } opendj3/opendj-core/src/main/java/org/forgerock/opendj/ldap/RDN.java
@@ -31,6 +31,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.List; @@ -42,6 +43,7 @@ import com.forgerock.opendj.util.Iterators; import com.forgerock.opendj.util.SubstringReader; import com.forgerock.opendj.util.Validator; /** * A relative distinguished name (RDN) as defined in RFC 4512 section 2.3 is the @@ -216,7 +218,32 @@ this.avas = new AVA[] { new AVA(attributeType, attributeValue) }; } /** * Creates a new RDN using the provided AVAs. * * @param avas * The attribute-value assertions used to build this RDN. * @throws NullPointerException * If {@code avas} is {@code null} or contains a null ava. */ public RDN(final AVA... avas) { this(avas, null); } /** * Creates a new RDN using the provided AVAs. * * @param avas * The attribute-value assertions used to build this RDN. * @throws NullPointerException * If {@code ava} is {@code null} or contains null ava. */ public RDN(Collection<AVA> avas) { this(avas.toArray(new AVA[avas.size()]), null); } private RDN(final AVA[] avas, final String stringValue) { Validator.ensureNotNull((Object[]) avas); this.avas = avas; this.stringValue = stringValue; } opendj3/opendj-core/src/main/java/org/forgerock/opendj/ldif/EntryGenerator.java
@@ -31,20 +31,17 @@ import java.io.IOException; import java.io.InputStream; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.Random; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import org.forgerock.i18n.LocalizableMessage; import org.forgerock.opendj.ldap.DecodeException; import org.forgerock.opendj.ldap.Entry; import org.forgerock.opendj.ldap.schema.Schema; import org.forgerock.opendj.ldif.TemplateFile.EntryWriter; import org.forgerock.opendj.ldif.TemplateFile.TemplateEntry; import com.forgerock.opendj.util.Validator; @@ -52,247 +49,187 @@ * Generator of entries based on a {@code TemplateFile template file}, which can * be provided as a file, a list of lines, an array of lines, or an input * stream. * <p> * To build a generator with all default values, including default template * file, use the empty constructor: * * <pre> * generator = new EntryGenerator(); * </pre> * <p> * To build a generator with some custom values, use the non-empty constructor * and the <code>set</code> methods: * * <pre> * generator = new EntryGenerator(templatePath) * .setResourcePath(path) * .setSchema(schema) * </pre> */ public final class EntryGenerator implements EntryReader { private static final TemplateEntry POISON_ENTRY = TemplateFile.TemplateEntry.NULL_TEMPLATE_ENTRY; private static final int DEFAULT_RANDOM_SEED = 1; /** Template file that contains directives for generation of entries. */ private final TemplateFile templateFile; private TemplateFile templateFile; /** Queue used to hold generated entries until they can be read. */ private final BlockingQueue<TemplateEntry> entryQueue; /** Warnings issued by the parsing of the template file. */ private final List<LocalizableMessage> warnings = new LinkedList<LocalizableMessage>(); /** The next available entry. */ private TemplateEntry nextEntry; /** Indicates if the generator is closed. */ private boolean isClosed = false; private final List<LocalizableMessage> warnings; /** Indicates if the generator is initialized, which means template file has been parsed. */ private boolean isInitialized = false; private volatile IOException ioException; private volatile boolean generationIsFinished = false; private volatile boolean isClosed = false; /** Thread that provides generation of entries. */ private Thread generationThread; /** Random seed is used to generate random data. */ private int randomSeed = DEFAULT_RANDOM_SEED; /** * Creates a reader. * * @param templateFile * contains definition of entries to generate. It must have * already been parsed * @param warnings * list of warnings that were issued when parsing the template * file * @param entryQueue * used to hold generated entries and block generation until * entries are read * Path to the directory that may contain additional resource files needed * during the generation process. It may be {@code null}. */ private EntryGenerator(TemplateFile templateFile, LinkedList<LocalizableMessage> warnings, BlockingQueue<TemplateEntry> entryQueue) { this.templateFile = templateFile; this.warnings = warnings; this.entryQueue = entryQueue; private String resourcePath; /** * Schema is used to create attributes. If not provided, the default schema * is used. */ private Schema schema; /** * Path of template file, can be {@code null} if template file has been * provided through another way. */ private String templatePath; /** * Lines of template file, can be {@code null} if template file has been * provided through another way. */ private String[] templateLines; /** * Input stream containing template file, can be {@code null} if template * file has been provided through another way. */ private InputStream templateStream; /** Dictionary of constants to use in the template file. */ private Map<String, String> constants = new HashMap<String, String>(); /** * Creates a generator using default values. * <p> * The default template file will be used to generate entries. */ public EntryGenerator() { // nothing to do } /** * Returns a builder to create a reader based on a template file given by * the provided path. * Creates a generator from the provided template path. * * @param templatePath * path of the template file * @return a builder allowing to create the reader * Path of the template file. */ public static Builder newReader(final String templatePath) { return new Builder(templatePath); public EntryGenerator(final String templatePath) { Validator.ensureNotNull(templatePath); this.templatePath = templatePath; } /** * Returns a builder to create a reader based on a template file given by * the provided lines. * Creates a generator from the provided template lines. * * @param templateLines * lines defining the template file * @return a builder allowing to create the reader * Lines defining the template file. */ public static Builder newReader(final String... templateLines) { return new Builder(templateLines); public EntryGenerator(final String... templateLines) { Validator.ensureNotNull((Object[]) templateLines); this.templateLines = templateLines; } /** * Returns a builder to create a reader based on a template file given by * the provided lines. * Creates a generator from the provided template lines. * * @param templateLines * lines defining the template file * @return a builder allowing to create the reader * Lines defining the template file. */ public static Builder newReader(final List<String> templateLines) { return new Builder(templateLines.toArray(new String[templateLines.size()])); public EntryGenerator(final List<String> templateLines) { Validator.ensureNotNull(templateLines); this.templateLines = templateLines.toArray(new String[templateLines.size()]); } /** * Returns a builder to create a reader based on a template file given by * the provided stream. * Creates a generator from the provided input stream. * * @param templateStream * input stream to read the template file * @return a builder allowing to create the reader * Input stream to read the template file. */ public static Builder newReader(final InputStream templateStream) { return new Builder(templateStream); public EntryGenerator(final InputStream templateStream) { Validator.ensureNotNull(templateStream); this.templateStream = templateStream; } /** * Builder of {@code EntryGenerator readers}. * <p> * Sets the random seed to use when generating entries. * * To build a reader with all default values: * <pre> * {@code reader = EntryGenerator.newReader(...).build() } * </pre> * <p> * * To build a reader with some custom values, using the * <code>set</code> methods: * <pre> * {@code reader = EntryGenerator.newReader(...). * setResourcePath(path). * setSchema(schema). * build() } * </pre> * @param seed * Seed to use. * @return A reference to this {@code EntryGenerator}. */ public static final class Builder { private static final int DEFAULT_QUEUE_SIZE = 100; private static final int DEFAULT_RANDOM_SEED = 1; private static final String DEFAULT_RESOURCE_PATH = "."; private String templatePath; private String[] templateLines; private InputStream templateStream; private TemplateFile templateFile; private int maxNumberOfEntriesInQueue = DEFAULT_QUEUE_SIZE; private int randomSeed = DEFAULT_RANDOM_SEED; private String resourcePath = DEFAULT_RESOURCE_PATH; private Schema schema; private Builder(String templatePath) { this.templatePath = templatePath; } private Builder(String[] templateLines) { this.templateLines = templateLines; } private Builder(InputStream templateStream) { this.templateStream = templateStream; } /** * Sets the capacity of the queue holding generated entries. * * @param max * capacity of the queue that holds generated entries * @return A reference to this {@code EntryGenerator.Builder}. */ public Builder setMaxNumberOfEntriesInQueue(final int max) { Validator.ensureTrue(max > 0, "queue capacity must be strictly superior to zero"); maxNumberOfEntriesInQueue = max; return this; } /** * Sets the random seed to use when generating entries. * * @param seed * seed to use * @return A reference to this {@code EntryGenerator.Builder}. */ public Builder setRandomSeed(final int seed) { randomSeed = seed; return this; } /** * Sets the resource path, used to looks for resources files like first * names, last names, or other custom resources. * * @param path * resource path * @return A reference to this {@code EntryGenerator.Builder}. */ public Builder setResourcePath(final String path) { Validator.ensureNotNull(path); resourcePath = path; return this; } /** * Sets the schema which should be when generating entries. The default * schema is used if no other is specified. * * @param schema * The schema which should be used for generating entries. * @return A reference to this {@code EntryGenerator.Builder}. */ public Builder setSchema(final Schema schema) { this.schema = schema; return this; } /** * Return an instance of reader. * * @return a new instance of reader * @throws IOException * If an error occurs while reading template file. * @throws DecodeException * If some other problem occurs during initialization */ public EntryGenerator build() throws IOException, DecodeException { if (schema == null) { schema = Schema.getDefaultSchema(); } templateFile = new TemplateFile(schema, resourcePath, new Random(randomSeed)); LinkedList<LocalizableMessage> warnings = new LinkedList<LocalizableMessage>(); try { if (templatePath != null) { templateFile.parse(templatePath, warnings); } else if (templateLines != null) { templateFile.parse(templateLines, warnings); } else if (templateStream != null) { templateFile.parse(templateStream, warnings); } else { // this should never happen throw DecodeException.fatalError(ERR_ENTRY_GENERATOR_MISSING_TEMPLATE_FILE.get()); } } catch (IOException e) { throw e; } catch (Exception e) { throw DecodeException.fatalError(ERR_ENTRY_GENERATOR_EXCEPTION_DURING_PARSE.get(e.getMessage()), e); } EntryGenerator reader = new EntryGenerator(templateFile, warnings, new LinkedBlockingQueue<TemplateEntry>(maxNumberOfEntriesInQueue)); reader.startEntriesGeneration(); return reader; } public EntryGenerator setRandomSeed(final int seed) { randomSeed = seed; return this; } /** * Start generation of entries by launching a separate thread. * Sets the resource path, used to looks for resources files like first * names, last names, or other custom resources. * * @param path * Resource path. * @return A reference to this {@code EntryGenerator}. */ private void startEntriesGeneration() { generationThread = new Thread(new EntriesGenerator(new MakeEntryWriter(), templateFile), "MakeLDIF Generator Thread"); generationThread.start(); public EntryGenerator setResourcePath(final String path) { Validator.ensureNotNull(path); resourcePath = path; return this; } /** * Sets the schema which should be when generating entries. The default * schema is used if no other is specified. * * @param schema * The schema which should be used for generating entries. * @return A reference to this {@code EntryGenerator}. */ public EntryGenerator setSchema(final Schema schema) { this.schema = schema; return this; } /** * Sets a constant to use in template file. It overrides the constant set in * the template file. * * @param name * Name of the constant. * @param value * Value of the constant. * @return A reference to this {@code EntryGenerator}. */ public EntryGenerator setConstant(String name, Object value) { constants.put(name, value.toString()); return this; } /** * Checks if there are some warning(s) after the parsing of template file. * <p> * Warnings are available only after the first call to {@code hasNext()} or * {@code readEntry()} methods. * * @return true if there is at least one warning */ @@ -302,6 +239,9 @@ /** * Returns the warnings generated by the parsing of template file. * <p> * Warnings are available only after the first call to {@code hasNext()} * or {@code readEntry()} methods. * * @return the list of warnings, which is empty if there is no warning */ @@ -312,120 +252,60 @@ @Override public void close() { isClosed = true; ioException = null; try { generationThread.join(0); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } @Override public boolean hasNext() throws IOException { if (isClosed) { return false; } else if (ioException != null) { throw ioException; } else if (nextEntry != null) { return true; } else if (generationIsFinished) { nextEntry = entryQueue.poll(); } else { try { nextEntry = entryQueue.take(); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); } } if (nextEntry == POISON_ENTRY) { nextEntry = null; } return nextEntry != null; ensureGeneratorIsInitialized(); return templateFile.hasNext(); } @Override public Entry readEntry() throws IOException { if (!hasNext()) { // LDIF reader has completed successfully. throw new NoSuchElementException(); } else { final Entry entry = nextEntry.toEntry(); nextEntry = null; return entry; return templateFile.nextEntry(); } } /** * Entry writer that store entries into the entry queue of this reader, and * record close and exception events. * Check that generator is initialized, and initialize it * if it has not been initialized. */ private final class MakeEntryWriter implements EntryWriter { @Override public boolean writeEntry(final TemplateEntry entry) { while (!isClosed) { try { if (entryQueue.offer(entry, 500, TimeUnit.MILLISECONDS)) { return true; } } catch (InterruptedException ie) { // nothing to do } } return false; } @Override public void closeEntryWriter() { generationIsFinished = true; writeEntry(POISON_ENTRY); } public void setIOException(final IOException ioe) { ioException = ioe; private void ensureGeneratorIsInitialized() throws IOException { if (!isInitialized) { isInitialized = true; initialize(); } } /** * Generator of entries, that writes entries to a provided * {@code EntryWriter writer}. * Initializes the generator, by retrieving template file and parsing it. */ private static final class EntriesGenerator implements Runnable { private final MakeEntryWriter entryWriter; private final TemplateFile templateFile; /** * Creates a generator that writes to provided writer using the provided * template file. * * @param entryWriter * @param templateFile */ EntriesGenerator(final MakeEntryWriter entryWriter, final TemplateFile templateFile) { this.entryWriter = entryWriter; this.templateFile = templateFile; private void initialize() throws IOException { if (schema == null) { schema = Schema.getDefaultSchema(); } /** * Run the generation of entries. */ public void run() { generate(); } /** * Generates entries to the entry writer. */ void generate() { try { templateFile.generateEntries(entryWriter); } catch (IOException e) { entryWriter.setIOException(e); entryWriter.closeEntryWriter(); templateFile = new TemplateFile(schema, constants, resourcePath, new Random(randomSeed)); try { if (templatePath != null) { templateFile.parse(templatePath, warnings); } else if (templateLines != null) { templateFile.parse(templateLines, warnings); } else if (templateStream != null) { templateFile.parse(templateStream, warnings); } else { // use default template file templateFile.parse(warnings); } } catch (IOException e) { throw e; } catch (Exception e) { throw DecodeException.fatalError(ERR_ENTRY_GENERATOR_EXCEPTION_DURING_PARSE.get(e.getMessage()), e); } } opendj3/opendj-core/src/main/java/org/forgerock/opendj/ldif/TemplateFile.java
@@ -36,29 +36,30 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.Random; import java.util.Set; import java.util.StringTokenizer; import org.forgerock.i18n.LocalizableMessage; import org.forgerock.opendj.ldap.AVA; import org.forgerock.opendj.ldap.Attribute; import org.forgerock.opendj.ldap.AttributeDescription; import org.forgerock.opendj.ldap.AttributeFactory; import org.forgerock.opendj.ldap.ByteString; import org.forgerock.opendj.ldap.DN; import org.forgerock.opendj.ldap.DecodeException; import org.forgerock.opendj.ldap.Entries; import org.forgerock.opendj.ldap.Entry; import org.forgerock.opendj.ldap.LinkedAttribute; import org.forgerock.opendj.ldap.LinkedHashMapEntry; import org.forgerock.opendj.ldap.RDN; import org.forgerock.opendj.ldap.schema.AttributeType; import org.forgerock.opendj.ldap.schema.CoreSchema; import org.forgerock.opendj.ldap.schema.ObjectClass; import org.forgerock.opendj.ldap.schema.Schema; import org.forgerock.opendj.ldif.TemplateTag.AttributeValueTag; import org.forgerock.opendj.ldif.TemplateTag.DNTag; @@ -79,7 +80,9 @@ import org.forgerock.opendj.ldif.TemplateTag.UnderscoreDNTag; import org.forgerock.opendj.ldif.TemplateTag.UnderscoreParentDNTag; import com.forgerock.opendj.util.Pair; import com.forgerock.opendj.util.StaticUtils; import com.forgerock.opendj.util.Validator; /** * A template file allow to generate entries from a collection of constant @@ -88,21 +91,24 @@ * @see EntryGenerator */ class TemplateFile { /** * The name of the file holding the list of first names. */ public static final String FIRST_NAME_FILE = "first.names"; /** * The name of the file holding the list of last names. */ public static final String LAST_NAME_FILE = "last.names"; /** Default resource path used if no resource path is provided. */ private static final File DEFAULT_RESOURCES_PATH = new File("org/forgerock/opendj/ldif"); /** Default template path used if no template file is provided. */ private static final String DEFAULT_TEMPLATE_PATH = "example.template"; /** The name of the file holding the list of first names. */ private static final String FIRST_NAME_FILE = "first.names"; /** The name of the file holding the list of last names. */ private static final String LAST_NAME_FILE = "last.names"; /** * A map of the contents of various text files used during the parsing * process, mapped from absolute path to the array of lines in the file. */ private Map<String, String[]> fileLines; private final Map<String, String[]> fileLines = new HashMap<String, String[]>(); /** The index of the next first name value that should be used. */ private int firstNameIndex; @@ -120,22 +126,22 @@ * A counter that will be used in case we have exhausted all possible first * and last name combinations. */ private int nameUniquenessCounter; private int nameUniquenessCounter = 1; /** The set of branch definitions for this template file. */ private Map<DN, Branch> branches; private final Map<DN, Branch> branches = new LinkedHashMap<DN, Branch>(); /** The set of constant definitions for this template file. */ private Map<String, String> constants; private final Map<String, String> constants; /** The set of registered tags for this template file. */ private Map<String, TemplateTag> registeredTags; private final Map<String, TemplateTag> registeredTags = new LinkedHashMap<String, TemplateTag>(); /** The set of template definitions for this template file. */ private Map<String, Template> templates; private final Map<String, Template> templates = new LinkedHashMap<String, Template>(); /** The random number generator for this template file. */ private Random random; private final Random random; /** The next first name that should be used. */ private String firstName; @@ -149,14 +155,11 @@ */ private String resourcePath; /** The path to the directory containing the template file, if available. */ private String templatePath; /** The set of first names to use when generating the LDIF. */ private String[] firstNames; private String[] firstNames = new String[0]; /** The set of last names to use when generating the LDIF. */ private String[] lastNames; private String[] lastNames = new String[0]; /** Schema used to create attributes. */ private final Schema schema; @@ -165,110 +168,54 @@ * Creates a new, empty template file structure. * * @param schema * LDAP Schema to use * LDAP Schema to use. * @param constants * Constants to use, override any constant defined in the * template file. May be {@code null}. * @param resourcePath * The path to the directory that may contain additional resource * files needed during the generation process. * files needed during the generation process. May be * {@code null}. * @throws IOException * if a problem occurs when initializing */ public TemplateFile(Schema schema, String resourcePath) { this(schema, resourcePath, new Random()); TemplateFile(Schema schema, Map<String, String> constants, String resourcePath) throws IOException { this(schema, constants, resourcePath, new Random()); } /** * Creates a new, empty template file structure. * * @param schema * used to create attributes * LDAP Schema to use. * @param constants * Constants to use, override any constant defined in the * template file. May be {@code null}. * @param resourcePath * The path to the directory that may contain additional resource * files needed during the generation process. * files needed during the generation process. May be * {@code null}. * @param random * The random number generator for this template file. * @throws IOException * if a problem occurs when initializing */ public TemplateFile(Schema schema, String resourcePath, Random random) { TemplateFile(Schema schema, Map<String, String> constants, String resourcePath, Random random) throws IOException { Validator.ensureNotNull(schema, random); this.schema = schema; this.constants = constants != null ? constants : new HashMap<String, String>(); this.resourcePath = resourcePath; this.random = random; fileLines = new HashMap<String, String[]>(); branches = new LinkedHashMap<DN, Branch>(); constants = new LinkedHashMap<String, String>(); registeredTags = new LinkedHashMap<String, TemplateTag>(); templates = new LinkedHashMap<String, Template>(); templatePath = null; firstNames = new String[0]; lastNames = new String[0]; firstName = null; lastName = null; firstNameIndex = 0; lastNameIndex = 0; nameLoopCounter = 0; nameUniquenessCounter = 1; registerDefaultTags(); readNames(); retrieveFirstAndLastNames(); } /** * Retrieves the set of tags that have been registered. They will be in the * form of a mapping between the name of the tag (in all lowercase * characters) and the corresponding tag implementation. * * @return The set of tags that have been registered. */ public Map<String, TemplateTag> getTags() { return registeredTags; } /** * Retrieves the tag with the specified name. * * @param lowerName * The name of the tag to retrieve, in all lowercase characters. * @return The requested tag, or <CODE>null</CODE> if no such tag has been * registered. */ public TemplateTag getTag(String lowerName) { TemplateTag getTag(String lowerName) { return registeredTags.get(lowerName); } /** * Registers the specified class as a tag that may be used in templates. * * @param tagClass * The fully-qualified name of the class to register as a tag. * @throws DecodeException * If a problem occurs while attempting to register the * specified tag. */ public void registerTag(String tagClass) throws DecodeException { Class<?> c; try { c = Class.forName(tagClass); } catch (Exception e) { final LocalizableMessage message = ERR_ENTRY_GENERATOR_CANNOT_LOAD_TAG_CLASS.get(tagClass); throw DecodeException.fatalError(message, e); } TemplateTag t; try { t = (TemplateTag) c.newInstance(); } catch (Exception e) { final LocalizableMessage message = ERR_ENTRY_GENERATOR_CANNOT_INSTANTIATE_TAG.get(tagClass); throw DecodeException.fatalError(message, e); } String lowerName = t.getName().toLowerCase(); if (registeredTags.containsKey(lowerName)) { final LocalizableMessage message = ERR_ENTRY_GENERATOR_CONFLICTING_TAG_NAME.get(tagClass, t.getName()); throw DecodeException.fatalError(message); } else { registeredTags.put(lowerName, t); } } /** * Registers the set of tags that will always be available for use in * templates. */ @@ -278,182 +225,45 @@ ListTag.class, ParentDNTag.class, PresenceTag.class, RandomTag.class, RDNTag.class, SequentialTag.class, StaticTextTag.class, UnderscoreDNTag.class, UnderscoreParentDNTag.class }; for (Class<?> c : defaultTagClasses) { for (final Class<?> c : defaultTagClasses) { try { TemplateTag t = (TemplateTag) c.newInstance(); final TemplateTag t = (TemplateTag) c.newInstance(); registeredTags.put(t.getName().toLowerCase(), t); } catch (Exception e) { // this should never happen StaticUtils.DEFAULT_LOG.error(ERR_ENTRY_GENERATOR_CANNOT_INSTANTIATE_TAG.get(c.getName()).toString()); // this is a programming error throw new RuntimeException(ERR_ENTRY_GENERATOR_CANNOT_INSTANTIATE_TAG.get(c.getName()).toString(), e); } } } /** * Retrieves the set of constants defined for this template file. * * @return The set of constants defined for this template file. */ public Map<String, String> getConstants() { return constants; } /** * Retrieves the value of the constant with the specified name. * * @param lowerName * The name of the constant to retrieve, in all lowercase * characters. * @return The value of the constant with the specified name, or * <CODE>null</CODE> if there is no such constant. */ public String getConstant(String lowerName) { return constants.get(lowerName); } /** * Registers the provided constant for use in the template. * * @param name * The name for the constant. * @param value * The value for the constant. */ public void registerConstant(String name, String value) { constants.put(name.toLowerCase(), value); } /** * Retrieves the set of branches defined in this template file. * * @return The set of branches defined in this template file. */ public Map<DN, Branch> getBranches() { return branches; } /** * Retrieves the branch registered with the specified DN. * * @param branchDN * The DN for which to retrieve the corresponding branch. * @return The requested branch, or <CODE>null</CODE> if no such branch has * been registered. */ public Branch getBranch(DN branchDN) { return branches.get(branchDN); } /** * Registers the provided branch in this template file. * * @param branch * The branch to be registered. */ public void registerBranch(Branch branch) { branches.put(branch.getBranchDN(), branch); } /** * Retrieves the set of templates defined in this template file. * * @return The set of templates defined in this template file. */ public Map<String, Template> getTemplates() { return templates; } /** * Retrieves the template with the specified name. * * @param lowerName * The name of the template to retrieve, in all lowercase * characters. * @return The requested template, or <CODE>null</CODE> if there is no such * template. */ public Template getTemplate(String lowerName) { return templates.get(lowerName); } /** * Registers the provided template for use in this template file. * * @param template * The template to be registered. */ public void registerTemplate(Template template) { templates.put(template.getName().toLowerCase(), template); } /** * Retrieves the random number generator for this template file. * * @return The random number generator for this template file. */ public Random getRandom() { Random getRandom() { return random; } /** * Reads the first and last names in standard files or use default values if * files can't be read. */ private void readNames() { firstNames = readNamesFromFile(FIRST_NAME_FILE); if (firstNames == null) { firstNames = new String[] { "Christophe", "Gael", "Gary", "Jean-Noel", "Laurent", "Ludovic", "Mark", "Matthew", "Nicolas", "Violette" }; } lastNames = readNamesFromFile(LAST_NAME_FILE); if (lastNames == null) { lastNames = new String[] { "Maahs", "Maas", "Mabes", "Mabson", "Mabuchi", "Mac", "Mac Maid", "MacAdams", "MacArthur", "MacCarthy" }; } } /** * Returns an array of names read in the provided file, or null if a problem * occurs. */ private String[] readNamesFromFile(String fileName) { String[] names = null; File file = getFile(fileName); if (file != null) { try { List<String> nameList = readDataFile(file); names = new String[nameList.size()]; nameList.toArray(names); } catch (IOException e) { // TODO : I18N StaticUtils.DEFAULT_LOG.error("Unable to read names file {}", fileName); } } return names; } /** * Read a file of data, and return a list containing one item per line. */ private List<String> readDataFile(File file) throws FileNotFoundException, IOException { List<String> data = new ArrayList<String>(); BufferedReader reader = null; private void retrieveFirstAndLastNames() throws IOException { BufferedReader first = null; try { reader = new BufferedReader(new FileReader(file)); while (true) { String line = reader.readLine(); if (line == null) { break; } else { data.add(line); } first = getReader(FIRST_NAME_FILE); if (first == null) { throw DecodeException.fatalError(ERR_ENTRY_GENERATOR_COULD_NOT_FIND_NAME_FILE.get(FIRST_NAME_FILE)); } final List<String> names = readLines(first); firstNames = names.toArray(new String[names.size()]); } finally { if (reader != null) { reader.close(); } StaticUtils.closeSilently(first); } return data; BufferedReader last = null; try { last = getReader(LAST_NAME_FILE); if (last == null) { throw DecodeException.fatalError(ERR_ENTRY_GENERATOR_COULD_NOT_FIND_NAME_FILE.get(LAST_NAME_FILE)); } final List<String> names = readLines(last); lastNames = names.toArray(new String[names.size()]); } finally { StaticUtils.closeSilently(first); } } /** @@ -463,22 +273,21 @@ * names and the number of last names being relatively prime. This method * should be called before beginning generation of each template entry. */ public void nextFirstAndLastNames() { void nextFirstAndLastNames() { firstName = firstNames[firstNameIndex++]; lastName = lastNames[lastNameIndex++]; // If we've already exhausted every possible combination, then append an // integer to the last name. // If we've already exhausted every possible combination // then append an integer to the last name. if (nameUniquenessCounter > 1) { lastName += nameUniquenessCounter; } if (firstNameIndex >= firstNames.length) { // We're at the end of the first name list, so start over. If the // first // name list is larger than the last name list, then we'll also need // to // set the last name index to the next loop counter position. // We're at the end of the first name list, so start over. // If the first name list is larger than the last name list, // then we'll also need to set the last name index // to the next loop counter position. firstNameIndex = 0; if (firstNames.length > lastNames.length) { lastNameIndex = ++nameLoopCounter; @@ -490,11 +299,10 @@ } if (lastNameIndex >= lastNames.length) { // We're at the end of the last name list, so start over. If the // last // name list is larger than the first name list, then we'll also // need to // set the first name index to the next loop counter position. // We're at the end of the last name list, so start over. // If the last name list is larger than the first name list, // then we'll also need to set the first name index // to the next loop counter position. lastNameIndex = 0; if (lastNames.length > firstNames.length) { firstNameIndex = ++nameLoopCounter; @@ -506,29 +314,35 @@ } } /** * Retrieves the first name value that should be used for the current entry. * * @return The first name value that should be used for the current entry. */ public String getFirstName() { String getFirstName() { return firstName; } /** * Retrieves the last name value that should be used for the current entry. * * @return The last name value that should be used for the current entry. */ public String getLastName() { String getLastName() { return lastName; } /** * Parses the contents of the specified file as a MakeLDIF template file * definition. * Parses the contents of the default template file definition, that will be * used to generate entries. * * @param filename * @param warnings * A list into which any warnings identified may be placed. * @throws IOException * If a problem occurs while attempting to read data from the * default template file. * @throws DecodeException * If any other problem occurs while parsing the template file. */ void parse(List<LocalizableMessage> warnings) throws IOException, DecodeException { parse(DEFAULT_TEMPLATE_PATH, warnings); } /** * Parses the contents of the provided file as an entry generator template * file definition. * * @param templateFilename * The name of the file containing the template data. * @param warnings * A list into which any warnings identified may be placed. @@ -538,37 +352,31 @@ * @throws DecodeException * If any other problem occurs while parsing the template file. */ public void parse(String filename, List<LocalizableMessage> warnings) throws IOException, DecodeException { ArrayList<String> fileLines = new ArrayList<String>(); templatePath = null; File f = getFile(filename); if ((f == null) || (!f.exists())) { LocalizableMessage message = ERR_ENTRY_GENERATOR_COULD_NOT_FIND_TEMPLATE_FILE.get(filename); throw new IOException(message.toString()); } else { templatePath = f.getParentFile().getAbsolutePath(); } BufferedReader reader = new BufferedReader(new FileReader(f)); while (true) { String line = reader.readLine(); if (line == null) { break; } else { fileLines.add(line); void parse(String templateFilename, List<LocalizableMessage> warnings) throws IOException, DecodeException { BufferedReader templateReader = null; try { templateReader = getReader(templateFilename); if (templateReader == null) { throw DecodeException.fatalError( ERR_ENTRY_GENERATOR_COULD_NOT_FIND_TEMPLATE_FILE.get(templateFilename)); } if (resourcePath == null) { // Use the template file directory as resource path final File file = getFile(templateFilename); if (file != null) { resourcePath = file.getParentFile().getAbsolutePath(); } } final List<String> fileLines = readLines(templateReader); final String[] lines = fileLines.toArray(new String[fileLines.size()]); parse(lines, warnings); } finally { StaticUtils.closeSilently(templateReader); } reader.close(); String[] lines = new String[fileLines.size()]; fileLines.toArray(lines); parse(lines, warnings); } /** * Parses the data read from the provided input stream as a MakeLDIF * Parses the contents of the provided input stream as an entry generator * template file definition. * * @param inputStream @@ -581,28 +389,48 @@ * @throws DecodeException * If any other problem occurs while parsing the template. */ public void parse(InputStream inputStream, List<LocalizableMessage> warnings) throws IOException, DecodeException { ArrayList<String> fileLines = new ArrayList<String>(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); while (true) { String line = reader.readLine(); if (line == null) { break; } else { fileLines.add(line); } void parse(InputStream inputStream, List<LocalizableMessage> warnings) throws IOException, DecodeException { BufferedReader reader = null; try { reader = new BufferedReader(new InputStreamReader(inputStream)); final List<String> fileLines = readLines(reader); final String[] lines = fileLines.toArray(new String[fileLines.size()]); parse(lines, warnings); } finally { StaticUtils.closeSilently(reader); } } reader.close(); private static final String INCLUDE_LABEL = "include "; private static final String DEFINE_LABEL = "define "; private static final String BRANCH_LABEL = "branch: "; private static final String TEMPLATE_LABEL = "template: "; private static final String SUBORDINATE_TEMPLATE_LABEL = "subordinatetemplate: "; private static final String RDNATTR_LABEL = "rdnattr: "; private static final String EXTENDS_LABEL = "extends: "; String[] lines = new String[fileLines.size()]; fileLines.toArray(lines); parse(lines, warnings); /** * Structure to hold template data during parsing of the template. */ private static class TemplateData { final Map<String, TemplateTag> tags = new LinkedHashMap<String, TemplateTag>(); final Map<DN, Branch> branches = new LinkedHashMap<DN, Branch>(); final Map<String, Template> templates = new LinkedHashMap<String, Template>(); } /** * Parses the provided data as a MakeLDIF template file definition. * Enumeration of elements that act as "container" of other elements. */ private enum Element { BRANCH, TEMPLATE; String getLabel() { return toString().toLowerCase(); } } /** * Parses the provided lines as an entry generator template file definition. * * @param lines * The lines that make up the template file. @@ -611,168 +439,183 @@ * @throws DecodeException * If any other problem occurs while parsing the template lines. */ public void parse(String[] lines, List<LocalizableMessage> warnings) throws DecodeException { // Create temporary variables that will be used to hold the data read. LinkedHashMap<String, TemplateTag> templateFileIncludeTags = new LinkedHashMap<String, TemplateTag>(); LinkedHashMap<String, String> templateFileConstants = new LinkedHashMap<String, String>(); LinkedHashMap<DN, Branch> templateFileBranches = new LinkedHashMap<DN, Branch>(); LinkedHashMap<String, Template> templateFileTemplates = new LinkedHashMap<String, Template>(); void parse(final String[] lines, final List<LocalizableMessage> warnings) throws DecodeException { TemplateData templateData = new TemplateData(); for (int lineNumber = 0; lineNumber < lines.length; lineNumber++) { String line = lines[lineNumber]; final String line = replaceConstants(lines[lineNumber], lineNumber, constants, warnings); line = replaceConstants(line, lineNumber, templateFileConstants, warnings); String lowerLine = line.toLowerCase(); final String lowerLine = line.toLowerCase(); if ((line.length() == 0) || line.startsWith("#")) { // This is a comment or a blank line, so we'll ignore it. continue; } else if (lowerLine.startsWith("include ")) { // This should be an include definition. The next element should // be the // name of the class. Load and instantiate it and make sure // there are // no conflicts. String className = line.substring(8).trim(); Class<?> tagClass; try { tagClass = Class.forName(className); } catch (Exception e) { LocalizableMessage message = ERR_ENTRY_GENERATOR_CANNOT_LOAD_TAG_CLASS.get(className); throw DecodeException.fatalError(message, e); } TemplateTag tag; try { tag = (TemplateTag) tagClass.newInstance(); } catch (Exception e) { LocalizableMessage message = ERR_ENTRY_GENERATOR_CANNOT_INSTANTIATE_TAG.get(className); throw DecodeException.fatalError(message, e); } String lowerName = tag.getName().toLowerCase(); if (registeredTags.containsKey(lowerName) || templateFileIncludeTags.containsKey(lowerName)) { LocalizableMessage message = ERR_ENTRY_GENERATOR_CONFLICTING_TAG_NAME.get(className, tag.getName()); throw DecodeException.fatalError(message); } templateFileIncludeTags.put(lowerName, tag); } else if (lowerLine.startsWith("define ")) { // This should be a constant definition. The rest of the line // should // contain the constant name, an equal sign, and the constant // value. int equalPos = line.indexOf('=', 7); if (equalPos < 0) { LocalizableMessage message = ERR_ENTRY_GENERATOR_DEFINE_MISSING_EQUALS.get(lineNumber); throw DecodeException.fatalError(message); } String name = line.substring(7, equalPos).trim(); if (name.length() == 0) { LocalizableMessage message = ERR_ENTRY_GENERATOR_DEFINE_NAME_EMPTY.get(lineNumber); throw DecodeException.fatalError(message); } String lowerName = name.toLowerCase(); if (templateFileConstants.containsKey(lowerName)) { LocalizableMessage message = ERR_ENTRY_GENERATOR_CONFLICTING_CONSTANT_NAME.get(name, lineNumber); throw DecodeException.fatalError(message); } String value = line.substring(equalPos + 1); if (value.length() == 0) { LocalizableMessage message = ERR_ENTRY_GENERATOR_WARNING_DEFINE_VALUE_EMPTY.get(name, lineNumber); warnings.add(message); } templateFileConstants.put(lowerName, value); } else if (lowerLine.startsWith("branch: ")) { int startLineNumber = lineNumber; ArrayList<String> lineList = new ArrayList<String>(); lineList.add(line); while (true) { lineNumber++; if (lineNumber >= lines.length) { break; } line = lines[lineNumber]; if (line.length() == 0) { break; } else { line = replaceConstants(line, lineNumber, templateFileConstants, warnings); lineList.add(line); } } String[] branchLines = new String[lineList.size()]; lineList.toArray(branchLines); Branch b = parseBranchDefinition(branchLines, lineNumber, templateFileIncludeTags, warnings); DN branchDN = b.getBranchDN(); if (templateFileBranches.containsKey(branchDN)) { LocalizableMessage message = ERR_ENTRY_GENERATOR_CONFLICTING_BRANCH_DN.get( String.valueOf(branchDN), startLineNumber); throw DecodeException.fatalError(message); } else { templateFileBranches.put(branchDN, b); } } else if (lowerLine.startsWith("template: ")) { int startLineNumber = lineNumber; ArrayList<String> lineList = new ArrayList<String>(); lineList.add(line); while (true) { lineNumber++; if (lineNumber >= lines.length) { break; } line = lines[lineNumber]; if (line.length() == 0) { break; } else { line = replaceConstants(line, lineNumber, templateFileConstants, warnings); lineList.add(line); } } String[] templateLines = new String[lineList.size()]; lineList.toArray(templateLines); Template t = parseTemplateDefinition(templateLines, startLineNumber, templateFileIncludeTags, templateFileTemplates, warnings); String lowerName = t.getName().toLowerCase(); if (templateFileTemplates.containsKey(lowerName)) { LocalizableMessage message = ERR_ENTRY_GENERATOR_CONFLICTING_TEMPLATE_NAME.get( String.valueOf(t.getName()), startLineNumber); throw DecodeException.fatalError(message); } else { templateFileTemplates.put(lowerName, t); } } else if (lowerLine.startsWith(INCLUDE_LABEL)) { parseInclude(line, templateData.tags); } else if (lowerLine.startsWith(DEFINE_LABEL)) { parseDefine(lineNumber, line, constants, warnings); } else if (lowerLine.startsWith(BRANCH_LABEL)) { lineNumber = parseBranch(lineNumber, line, lines, templateData, warnings); } else if (lowerLine.startsWith(TEMPLATE_LABEL)) { lineNumber = parseTemplate(lineNumber, line, lines, templateData, warnings); } else { LocalizableMessage message = ERR_ENTRY_GENERATOR_UNEXPECTED_TEMPLATE_FILE_LINE.get(line, lineNumber); throw DecodeException.fatalError(message); throw DecodeException.fatalError( ERR_ENTRY_GENERATOR_UNEXPECTED_TEMPLATE_FILE_LINE.get(line, lineNumber)); } } // If we've gotten here, then we're almost done. We just need to // finalize // the branch and template definitions and then update the template file // variables. for (Branch b : templateFileBranches.values()) { b.completeBranchInitialization(templateFileTemplates); // Finalize the branch and template definitions // and then update the template file variables. for (Branch b : templateData.branches.values()) { b.completeBranchInitialization(templateData.templates); } for (Template t : templateFileTemplates.values()) { t.completeTemplateInitialization(templateFileTemplates); for (Template t : templateData.templates.values()) { t.completeTemplateInitialization(templateData.templates); } registeredTags.putAll(templateFileIncludeTags); constants.putAll(templateFileConstants); branches.putAll(templateFileBranches); templates.putAll(templateFileTemplates); registeredTags.putAll(templateData.tags); branches.putAll(templateData.branches); templates.putAll(templateData.templates); // Initialize iterator on branches and current branch used // to read entries if (branchesIterator == null) { branchesIterator = branches.values().iterator(); if (branchesIterator.hasNext()) { currentBranch = branchesIterator.next(); } } } private void parseInclude(final String line, final Map<String, TemplateTag> templateFileIncludeTags) throws DecodeException { // The next element should be the name of the class. // Load and instantiate it and make sure there are no conflicts. final String className = line.substring(INCLUDE_LABEL.length()).trim(); Class<?> tagClass = null; try { tagClass = Class.forName(className); } catch (Exception e) { final LocalizableMessage message = ERR_ENTRY_GENERATOR_CANNOT_LOAD_TAG_CLASS.get(className); throw DecodeException.fatalError(message, e); } TemplateTag tag; try { tag = (TemplateTag) tagClass.newInstance(); } catch (Exception e) { final LocalizableMessage message = ERR_ENTRY_GENERATOR_CANNOT_INSTANTIATE_TAG.get(className); throw DecodeException.fatalError(message, e); } String lowerName = tag.getName().toLowerCase(); if (registeredTags.containsKey(lowerName) || templateFileIncludeTags.containsKey(lowerName)) { final LocalizableMessage message = ERR_ENTRY_GENERATOR_CONFLICTING_TAG_NAME.get(className, tag.getName()); throw DecodeException.fatalError(message); } templateFileIncludeTags.put(lowerName, tag); } private void parseDefine(final int lineNumber, final String line, final Map<String, String> templateFileConstants, final List<LocalizableMessage> warnings) throws DecodeException { // The rest of the line should contain the constant name, // an equal sign, and the constant value. final int equalPos = line.indexOf('=', DEFINE_LABEL.length()); if (equalPos < 0) { throw DecodeException.fatalError(ERR_ENTRY_GENERATOR_DEFINE_MISSING_EQUALS.get(lineNumber)); } final String name = line.substring(DEFINE_LABEL.length(), equalPos).trim(); if (name.length() == 0) { throw DecodeException.fatalError(ERR_ENTRY_GENERATOR_DEFINE_NAME_EMPTY.get(lineNumber)); } final String value = line.substring(equalPos + 1); if (value.length() == 0) { warnings.add(ERR_ENTRY_GENERATOR_WARNING_DEFINE_VALUE_EMPTY.get(name, lineNumber)); } final String lowerName = name.toLowerCase(); if (!templateFileConstants.containsKey(lowerName)) { templateFileConstants.put(lowerName, value); } } /** * Parses the complete branch and returns the current line number at the * end. */ private int parseBranch(final int startLineNumber, final String startLine, final String[] lines, final TemplateData templateData, final List<LocalizableMessage> warnings) throws DecodeException { final String[] branchLines = parseLinesUntilEndOfBlock(startLineNumber, startLine, lines, warnings); final Branch branch = parseBranchDefinition(branchLines, startLineNumber, templateData.tags, warnings); final DN branchDN = branch.getBranchDN(); if (templateData.branches.containsKey(branchDN)) { throw DecodeException.fatalError( ERR_ENTRY_GENERATOR_CONFLICTING_BRANCH_DN.get(String.valueOf(branchDN), startLineNumber)); } templateData.branches.put(branchDN, branch); // position to next line after end of branch return startLineNumber + branchLines.length; } /** * Parses the complete template and returns the current line number at the * end. */ private int parseTemplate(final int startLineNumber, final String startLine, final String[] lines, final TemplateData templateData, final List<LocalizableMessage> warnings) throws DecodeException { final String[] templateLines = parseLinesUntilEndOfBlock(startLineNumber, startLine, lines, warnings); final Template template = parseTemplateDefinition(startLineNumber, templateLines, templateData, warnings); final String lowerName = template.getName().toLowerCase(); if (templateData.templates.containsKey(lowerName)) { throw DecodeException.fatalError(ERR_ENTRY_GENERATOR_CONFLICTING_TEMPLATE_NAME.get( String.valueOf(template.getName()), startLineNumber)); } templateData.templates.put(lowerName, template); // position to next line after end of template return startLineNumber + templateLines.length; } /** * Parses lines of a block until the block ends (with an empty line) or * lines ends. * * @param startLineNumber * Line number at beginning of block. * @param startLine * First line of block. * @param lines * The list of all lines in the template. * @param warnings * A list into which any warnings identified may be placed. * @return The lines of the block */ private String[] parseLinesUntilEndOfBlock(final int startLineNumber, final String startLine, final String[] lines, final List<LocalizableMessage> warnings) { final List<String> lineList = new ArrayList<String>(); String line = startLine; lineList.add(line); int lineNumber = startLineNumber; while (true) { lineNumber++; if (lineNumber >= lines.length) { break; } line = lines[lineNumber]; if (line.length() == 0) { break; } line = replaceConstants(line, lineNumber, constants, warnings); lineList.add(line); } return lineList.toArray(new String[lineList.size()]); } /** @@ -789,27 +632,26 @@ * @return The line in which all constant variables have been replaced with * their value */ private String replaceConstants(String line, int lineNumber, Map<String, String> constants, List<LocalizableMessage> warnings) { private String replaceConstants(final String line, final int lineNumber, final Map<String, String> constants, final List<LocalizableMessage> warnings) { String newLine = line; int closePos = line.lastIndexOf(']'); // Loop until we've scanned all closing brackets do { // Skip escaped closing brackets while (closePos > 0 && line.charAt(closePos - 1) == '\\') { closePos = line.lastIndexOf(']', closePos - 1); while (closePos > 0 && newLine.charAt(closePos - 1) == '\\') { closePos = newLine.lastIndexOf(']', closePos - 1); } if (closePos > 0) { StringBuilder lineBuffer = new StringBuilder(line); int openPos = line.lastIndexOf('[', closePos); // Find the opening bracket. If it's escaped, then it's not a // constant if ((openPos > 0 && line.charAt(openPos - 1) != '\\') || (openPos == 0)) { String constantName = line.substring(openPos + 1, closePos).toLowerCase(); String constantValue = constants.get(constantName); final StringBuilder lineBuffer = new StringBuilder(newLine); int openPos = newLine.lastIndexOf('[', closePos); // Find the opening bracket. // If it's escaped, then it's not a constant if ((openPos > 0 && newLine.charAt(openPos - 1) != '\\') || (openPos == 0)) { final String constantName = newLine.substring(openPos + 1, closePos).toLowerCase(); final String constantValue = constants.get(constantName); if (constantValue == null) { LocalizableMessage message = WARN_ENTRY_GENERATOR_WARNING_UNDEFINED_CONSTANT.get(constantName, lineNumber); warnings.add(message); warnings.add(WARN_ENTRY_GENERATOR_WARNING_UNDEFINED_CONSTANT.get(constantName, lineNumber)); } else { lineBuffer.replace(openPos, closePos + 1, constantValue); } @@ -817,16 +659,16 @@ if (openPos >= 0) { closePos = openPos; } line = lineBuffer.toString(); closePos = line.lastIndexOf(']', closePos); newLine = lineBuffer.toString(); closePos = newLine.lastIndexOf(']', closePos); } } while (closePos > 0); return line; return newLine; } /** * Parses the information contained in the provided set of lines as a * MakeLDIF branch definition. * Parses the information contained in the provided set of lines as a branch * definition. * * @param branchLines * The set of lines containing the branch definition. @@ -844,80 +686,52 @@ * If a problem occurs during initializing any of the branch * elements or during processing. */ private Branch parseBranchDefinition(String[] branchLines, int startLineNumber, Map<String, TemplateTag> tags, List<LocalizableMessage> warnings) throws DecodeException { private Branch parseBranchDefinition(final String[] branchLines, final int startLineNumber, final Map<String, TemplateTag> tags, final List<LocalizableMessage> warnings) throws DecodeException { // The first line must be "branch: " followed by the branch DN. String dnString = branchLines[0].substring(8).trim(); final String dnString = branchLines[0].substring(BRANCH_LABEL.length()).trim(); DN branchDN; try { branchDN = DN.valueOf(dnString, schema); } catch (Exception e) { LocalizableMessage message = ERR_ENTRY_GENERATOR_CANNOT_DECODE_BRANCH_DN.get(dnString, startLineNumber); throw DecodeException.fatalError(message); throw DecodeException.fatalError(ERR_ENTRY_GENERATOR_CANNOT_DECODE_BRANCH_DN.get( dnString, startLineNumber)); } // Create a new branch that will be used for the verification process. Branch branch = new Branch(this, branchDN, null); final Branch branch = new Branch(this, branchDN, schema); for (int i = 1; i < branchLines.length; i++) { String line = branchLines[i]; String lowerLine = line.toLowerCase(); int lineNumber = startLineNumber + i; final String line = branchLines[i]; final String lowerLine = line.toLowerCase(); final int lineNumber = startLineNumber + i; if (lowerLine.startsWith("#")) { // It's a comment, so we should ignore it. continue; } else if (lowerLine.startsWith("subordinatetemplate: ")) { // It's a subordinate template, so we'll want to parse the name // and the // number of entries. int colonPos = line.indexOf(':', 21); if (colonPos <= 21) { LocalizableMessage message = ERR_ENTRY_GENERATOR_BRANCH_SUBORDINATE_TEMPLATE_NO_COLON.get( lineNumber, dnString); throw DecodeException.fatalError(message); } String templateName = line.substring(21, colonPos).trim(); int numEntries; try { numEntries = Integer.parseInt(line.substring(colonPos + 1).trim()); if (numEntries < 0) { LocalizableMessage message = ERR_ENTRY_GENERATOR_BRANCH_SUBORDINATE_INVALID_NUM_ENTRIES.get( lineNumber, dnString, numEntries, templateName); throw DecodeException.fatalError(message); } else if (numEntries == 0) { LocalizableMessage message = WARN_ENTRY_GENERATOR_BRANCH_SUBORDINATE_ZERO_ENTRIES.get( lineNumber, dnString, templateName); warnings.add(message); } branch.addSubordinateTemplate(templateName, numEntries); } catch (NumberFormatException nfe) { LocalizableMessage message = ERR_ENTRY_GENERATOR_BRANCH_SUBORDINATE_CANT_PARSE_NUMENTRIES.get( templateName, lineNumber, dnString); throw DecodeException.fatalError(message); } } else if (lowerLine.startsWith(SUBORDINATE_TEMPLATE_LABEL)) { final Pair<String, Integer> pair = parseSubordinateTemplate(lineNumber, line, Element.BRANCH, dnString, warnings); final String templateName = pair.getFirst(); final int numEntries = pair.getSecond(); branch.addSubordinateTemplate(templateName, numEntries); } else { TemplateLine templateLine = parseTemplateLine(line, lowerLine, lineNumber, branch, null, tags, warnings); final TemplateLine templateLine = parseTemplateLine(line, lineNumber, branch, null, Element.BRANCH, tags, warnings); branch.addExtraLine(templateLine); } } return branch; } /** * Parses the information contained in the provided set of lines as a * MakeLDIF template definition. * template definition. * * @param templateLines * The set of lines containing the template definition. * @param startLineNumber * The line number in the template file on which the first of the * template lines appears. * @param templateLines * The set of lines containing the template definition. * @param tags * The set of defined tags from the template file. Note that this * does not include the tags that are always registered by @@ -931,121 +745,75 @@ * If a problem occurs during initializing any of the template * elements or during processing. */ private Template parseTemplateDefinition(String[] templateLines, int startLineNumber, Map<String, TemplateTag> tags, Map<String, Template> definedTemplates, List<LocalizableMessage> warnings) throws DecodeException { // The first line must be "template: " followed by the template name. String templateName = templateLines[0].substring(10).trim(); private Template parseTemplateDefinition(final int startLineNumber, final String[] templateLines, final TemplateData templateData, final List<LocalizableMessage> warnings) throws DecodeException { final Map<String, TemplateTag> tags = templateData.tags; final Map<String, Template> definedTemplates = templateData.templates; // The next line may start with either "extends: ", "rdnAttr: ", or // "subordinateTemplate: ". Keep reading until we find something that's // not one of those. int arrayLineNumber = 1; // The first line must be "template: " followed by the template name. final String templateName = templateLines[0].substring(TEMPLATE_LABEL.length()).trim(); // The next line may be with an "extends", a rdn attribute, or // a subordinate template. Keep reading until we find something // that's not one of those. int lineCount = 1; Template parentTemplate = null; AttributeType[] rdnAttributes = null; ArrayList<String> subTemplateNames = new ArrayList<String>(); ArrayList<Integer> entriesPerTemplate = new ArrayList<Integer>(); for (; arrayLineNumber < templateLines.length; arrayLineNumber++) { int lineNumber = startLineNumber + arrayLineNumber; String line = templateLines[arrayLineNumber]; String lowerLine = line.toLowerCase(); final List<AttributeType> rdnAttributes = new ArrayList<AttributeType>(); final List<String> subordinatesTemplateNames = new ArrayList<String>(); final List<Integer> numberOfentriesPerTemplate = new ArrayList<Integer>(); for (; lineCount < templateLines.length; lineCount++) { final int lineNumber = startLineNumber + lineCount; final String line = templateLines[lineCount]; final String lowerLine = line.toLowerCase(); if (lowerLine.startsWith("#")) { // It's a comment. Ignore it. continue; } else if (lowerLine.startsWith("extends: ")) { String parentTemplateName = line.substring(9).trim(); } else if (lowerLine.startsWith(EXTENDS_LABEL)) { final String parentTemplateName = line.substring(EXTENDS_LABEL.length()).trim(); parentTemplate = definedTemplates.get(parentTemplateName.toLowerCase()); if (parentTemplate == null) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TEMPLATE_INVALID_PARENT_TEMPLATE.get( parentTemplateName, lineNumber, templateName); throw DecodeException.fatalError(message); throw DecodeException.fatalError(ERR_ENTRY_GENERATOR_TEMPLATE_INVALID_PARENT_TEMPLATE.get( parentTemplateName, lineNumber, templateName)); } } else if (lowerLine.startsWith("rdnattr: ")) { } else if (lowerLine.startsWith(RDNATTR_LABEL)) { // This is the set of RDN attributes. If there are multiple, // they may // be separated by plus signs. ArrayList<AttributeType> attrList = new ArrayList<AttributeType>(); String rdnAttrNames = lowerLine.substring(9).trim(); StringTokenizer tokenizer = new StringTokenizer(rdnAttrNames, "+"); // they may be separated by plus signs. final String rdnAttrNames = lowerLine.substring(RDNATTR_LABEL.length()).trim(); final StringTokenizer tokenizer = new StringTokenizer(rdnAttrNames, "+"); while (tokenizer.hasMoreTokens()) { attrList.add(schema.getAttributeType(tokenizer.nextToken())); rdnAttributes.add(schema.getAttributeType(tokenizer.nextToken())); } rdnAttributes = new AttributeType[attrList.size()]; attrList.toArray(rdnAttributes); } else if (lowerLine.startsWith("subordinatetemplate: ")) { // It's a subordinate template, so we'll want to parse the name // and the // number of entries. int colonPos = line.indexOf(':', 21); if (colonPos <= 21) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TEMPLATE_SUBORDINATE_TEMPLATE_NO_COLON.get( lineNumber, templateName); throw DecodeException.fatalError(message); } String subTemplateName = line.substring(21, colonPos).trim(); int numEntries; try { numEntries = Integer.parseInt(line.substring(colonPos + 1).trim()); if (numEntries < 0) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TEMPLATE_SUBORDINATE_INVALID_NUM_ENTRIES.get( lineNumber, templateName, numEntries, subTemplateName); throw DecodeException.fatalError(message); } else if (numEntries == 0) { LocalizableMessage message = WARN_ENTRY_GENERATOR_TEMPLATE_SUBORDINATE_ZERO_ENTRIES.get( lineNumber, templateName, subTemplateName); warnings.add(message); } subTemplateNames.add(subTemplateName); entriesPerTemplate.add(numEntries); } catch (NumberFormatException nfe) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TEMPLATE_SUBORDINATE_CANT_PARSE_NUMENTRIES.get( subTemplateName, lineNumber, templateName); throw DecodeException.fatalError(message); } } else if (lowerLine.startsWith(SUBORDINATE_TEMPLATE_LABEL)) { final Pair<String, Integer> pair = parseSubordinateTemplate(lineNumber, line, Element.BRANCH, templateName, warnings); subordinatesTemplateNames.add(pair.getFirst()); numberOfentriesPerTemplate.add(pair.getSecond()); } else { // It's something we don't recognize, so it must be a template // line. // Not recognized, it must be a template line. break; } } // Create a new template that will be used for the verification process. String[] subordinateTemplateNames = new String[subTemplateNames.size()]; subTemplateNames.toArray(subordinateTemplateNames); final List<TemplateLine> parentLines = (parentTemplate == null) ? new ArrayList<TemplateLine>() : parentTemplate.getTemplateLines(); int[] numEntriesPerTemplate = new int[entriesPerTemplate.size()]; for (int i = 0; i < numEntriesPerTemplate.length; i++) { numEntriesPerTemplate[i] = entriesPerTemplate.get(i); } final Template template = new Template(this, templateName, rdnAttributes, subordinatesTemplateNames, numberOfentriesPerTemplate, parentLines); TemplateLine[] parsedLines; if (parentTemplate == null) { parsedLines = new TemplateLine[0]; } else { TemplateLine[] parentLines = parentTemplate.getTemplateLines(); parsedLines = new TemplateLine[parentLines.length]; System.arraycopy(parentLines, 0, parsedLines, 0, parentLines.length); } Template template = new Template(this, templateName, rdnAttributes, subordinateTemplateNames, numEntriesPerTemplate, parsedLines); for (; arrayLineNumber < templateLines.length; arrayLineNumber++) { String line = templateLines[arrayLineNumber]; String lowerLine = line.toLowerCase(); int lineNumber = startLineNumber + arrayLineNumber; // Add lines to template for (; lineCount < templateLines.length; lineCount++) { final String line = templateLines[lineCount]; final String lowerLine = line.toLowerCase(); if (lowerLine.startsWith("#")) { // It's a comment, so we should ignore it. // It's a comment, ignore it. continue; } else { TemplateLine templateLine = parseTemplateLine(line, lowerLine, lineNumber, null, template, tags, warnings); final int lineNumber = startLineNumber + lineCount; final TemplateLine templateLine = parseTemplateLine(line, lineNumber, null, template, Element.TEMPLATE, tags, warnings); template.addTemplateLine(templateLine); } } @@ -1053,6 +821,52 @@ return template; } /** * Parses a subordinate template for a template or a branch. * <p> * A subordinate template has a name and a number of entries. * * @param lineNumber * Line number of definition. * @param line * Line containing the definition. * @param element * indicates the kind of element to use in error messages. * @param elementName * Name of the branch or template. * @param warnings * A list into which any warnings identified may be placed. * @return the pair (template name, number of entries in template) */ private Pair<String, Integer> parseSubordinateTemplate(final int lineNumber, final String line, final Element element, final String elementName, final List<LocalizableMessage> warnings) throws DecodeException { // It's a subordinate template, so we'll want to parse // the template name and the number of entries. final int colonPos = line.indexOf(':', SUBORDINATE_TEMPLATE_LABEL.length()); if (colonPos <= SUBORDINATE_TEMPLATE_LABEL.length()) { throw DecodeException.fatalError(ERR_ENTRY_GENERATOR_SUBORDINATE_TEMPLATE_NO_COLON.get( lineNumber, element.getLabel(), elementName)); } final String templateName = line.substring(SUBORDINATE_TEMPLATE_LABEL.length(), colonPos).trim(); try { final int numEntries = Integer.parseInt(line.substring(colonPos + 1).trim()); if (numEntries < 0) { throw DecodeException.fatalError(ERR_ENTRY_GENERATOR_SUBORDINATE_INVALID_NUM_ENTRIES.get( lineNumber, element.getLabel(), elementName, numEntries, templateName)); } else if (numEntries == 0) { warnings.add(WARN_ENTRY_GENERATOR_SUBORDINATE_ZERO_ENTRIES.get( lineNumber, element.getLabel(), elementName, templateName)); } return Pair.of(templateName, numEntries); } catch (NumberFormatException nfe) { throw DecodeException.fatalError(ERR_ENTRY_GENERATOR_SUBORDINATE_CANT_PARSE_NUMENTRIES.get( templateName, lineNumber, element.getLabel(), elementName)); } } private static final int PARSING_STATIC_TEXT = 0; private static final int PARSING_REPLACEMENT_TAG = 1; private static final int PARSING_ATTRIBUTE_TAG = 2; @@ -1064,8 +878,6 @@ * * @param line * The text of the template line. * @param lowerLine * The template line in all lowercase characters. * @param lineNumber * The line number on which the template line appears. * @param branch @@ -1083,37 +895,26 @@ * If a problem occurs during initializing any of the template * elements or during processing. */ private TemplateLine parseTemplateLine(String line, String lowerLine, int lineNumber, Branch branch, Template template, Map<String, TemplateTag> tags, List<LocalizableMessage> warnings) throws DecodeException { private TemplateLine parseTemplateLine(final String line, final int lineNumber, final Branch branch, final Template template, final Element element, final Map<String, TemplateTag> tags, final List<LocalizableMessage> warnings) throws DecodeException { final String elementName = element == Element.BRANCH ? branch.getBranchDN().toString() : template.getName(); // The first component must be the attribute type, followed by a colon. int colonPos = lowerLine.indexOf(':'); final String lowerLine = line.toLowerCase(); final int colonPos = lowerLine.indexOf(':'); if (colonPos < 0) { if (branch == null) { LocalizableMessage message = ERR_ENTRY_GENERATOR_NO_COLON_IN_TEMPLATE_LINE.get(lineNumber, template.getName()); throw DecodeException.fatalError(message); } else { LocalizableMessage message = ERR_ENTRY_GENERATOR_NO_COLON_IN_BRANCH_EXTRA_LINE.get(lineNumber, String.valueOf(branch.getBranchDN())); throw DecodeException.fatalError(message); } throw DecodeException.fatalError(ERR_ENTRY_GENERATOR_NO_COLON_IN_TEMPLATE_LINE.get( lineNumber, element.getLabel(), elementName)); } else if (colonPos == 0) { if (branch == null) { LocalizableMessage message = ERR_ENTRY_GENERATOR_NO_ATTR_IN_TEMPLATE_LINE.get(lineNumber, template.getName()); throw DecodeException.fatalError(message); } else { LocalizableMessage message = ERR_ENTRY_GENERATOR_NO_ATTR_IN_BRANCH_EXTRA_LINE.get(lineNumber, String.valueOf(branch.getBranchDN())); throw DecodeException.fatalError(message); } throw DecodeException.fatalError(ERR_ENTRY_GENERATOR_NO_ATTR_IN_TEMPLATE_LINE.get( lineNumber, element.getLabel(), elementName)); } AttributeType attributeType = schema.getAttributeType(lowerLine.substring(0, colonPos)); final AttributeType attributeType = schema.getAttributeType(lowerLine.substring(0, colonPos)); // First, check whether the value is an URL value: <attrName>:< <url> int length = line.length(); final int length = line.length(); int pos = colonPos + 1; boolean valueIsURL = false; boolean valueIsBase64 = false; @@ -1132,24 +933,16 @@ } if (pos >= length) { // We've hit the end of the line with no value. We'll allow it, but // add a // warning. if (branch == null) { LocalizableMessage message = WARN_ENTRY_GENERATOR_NO_VALUE_IN_TEMPLATE_LINE.get(lineNumber, template.getName()); warnings.add(message); } else { LocalizableMessage message = WARN_ENTRY_GENERATOR_NO_VALUE_IN_BRANCH_EXTRA_LINE.get(lineNumber, String.valueOf(branch.getBranchDN())); warnings.add(message); } // We've hit the end of the line with no value. // We'll allow it, but add a warning. warnings.add(WARN_ENTRY_GENERATOR_NO_VALUE_IN_TEMPLATE_LINE.get( lineNumber, element.getLabel(), elementName)); } int phase = PARSING_STATIC_TEXT; int previousPhase = PARSING_STATIC_TEXT; ArrayList<TemplateTag> tagList = new ArrayList<TemplateTag>(); final List<TemplateTag> tagList = new ArrayList<TemplateTag>(); StringBuilder buffer = new StringBuilder(); for (; pos < length; pos++) { @@ -1199,7 +992,6 @@ parseReplacementTag(buffer.toString(), branch, template, lineNumber, tags, warnings); tagList.add(t); buffer = new StringBuilder(); phase = PARSING_STATIC_TEXT; break; default: @@ -1242,13 +1034,10 @@ tagList.add(t); } } else { LocalizableMessage message = ERR_ENTRY_GENERATOR_INCOMPLETE_TAG.get(lineNumber); throw DecodeException.fatalError(message); throw DecodeException.fatalError(ERR_ENTRY_GENERATOR_INCOMPLETE_TAG.get(lineNumber)); } TemplateTag[] tagArray = new TemplateTag[tagList.size()]; tagList.toArray(tagArray); return new TemplateLine(attributeType, lineNumber, tagArray, valueIsURL, valueIsBase64); return new TemplateLine(attributeType, lineNumber, tagList, valueIsURL, valueIsBase64); } /** @@ -1274,53 +1063,45 @@ * @throws DecodeException * If some problem occurs during processing. */ private TemplateTag parseReplacementTag(String tagString, Branch branch, Template template, int lineNumber, Map<String, TemplateTag> tags, List<LocalizableMessage> warnings) throws DecodeException { private TemplateTag parseReplacementTag(final String tagString, final Branch branch, final Template template, final int lineNumber, final Map<String, TemplateTag> tags, final List<LocalizableMessage> warnings) throws DecodeException { // The components of the replacement tag will be separated by colons, // with // the first being the tag name and the remainder being arguments. StringTokenizer tokenizer = new StringTokenizer(tagString, ":"); String tagName = tokenizer.nextToken().trim(); String lowerTagName = tagName.toLowerCase(); // with the first being the tag name and the remainder being arguments. final StringTokenizer tokenizer = new StringTokenizer(tagString, ":"); final String tagName = tokenizer.nextToken().trim(); final String lowerTagName = tagName.toLowerCase(); TemplateTag t = getTag(lowerTagName); if (t == null) { t = tags.get(lowerTagName); if (t == null) { LocalizableMessage message = ERR_ENTRY_GENERATOR_NO_SUCH_TAG.get(tagName, lineNumber); throw DecodeException.fatalError(message); TemplateTag tag = getTag(lowerTagName); if (tag == null) { tag = tags.get(lowerTagName); if (tag == null) { throw DecodeException.fatalError(ERR_ENTRY_GENERATOR_NO_SUCH_TAG.get(tagName, lineNumber)); } } ArrayList<String> argList = new ArrayList<String>(); final List<String> args = new ArrayList<String>(); while (tokenizer.hasMoreTokens()) { argList.add(tokenizer.nextToken().trim()); args.add(tokenizer.nextToken().trim()); } String[] args = new String[argList.size()]; argList.toArray(args); final String[] arguments = args.toArray(new String[args.size()]); TemplateTag newTag; try { newTag = t.getClass().newInstance(); newTag = tag.getClass().newInstance(); } catch (Exception e) { LocalizableMessage message = ERR_ENTRY_GENERATOR_CANNOT_INSTANTIATE_NEW_TAG.get(tagName, lineNumber, String.valueOf(e)); throw DecodeException.fatalError(message, e); throw DecodeException.fatalError(ERR_ENTRY_GENERATOR_CANNOT_INSTANTIATE_NEW_TAG.get( tagName, lineNumber, String.valueOf(e)), e); } if (branch == null) { newTag.initializeForTemplate(schema, this, template, args, lineNumber, warnings); newTag.initializeForTemplate(schema, this, template, arguments, lineNumber, warnings); } else if (newTag.allowedInBranch()) { newTag.initializeForBranch(schema, this, branch, arguments, lineNumber, warnings); } else { if (newTag.allowedInBranch()) { newTag.initializeForBranch(schema, this, branch, args, lineNumber, warnings); } else { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_NOT_ALLOWED_IN_BRANCH.get(newTag.getName(), lineNumber); throw DecodeException.fatalError(message); } throw DecodeException.fatalError(ERR_ENTRY_GENERATOR_TAG_NOT_ALLOWED_IN_BRANCH.get(newTag.getName(), lineNumber)); } return newTag; } @@ -1343,197 +1124,234 @@ * @throws DecodeException * If some other problem occurs during processing. */ private TemplateTag parseAttributeTag(String tagString, Branch branch, Template template, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { private TemplateTag parseAttributeTag(final String tagString, final Branch branch, final Template template, final int lineNumber, final List<LocalizableMessage> warnings) throws DecodeException { // The attribute tag must have at least one argument, which is the name // of // the attribute to reference. It may have a second argument, which is // the // number of characters to use from the attribute value. The arguments // will // be delimited by colons. StringTokenizer tokenizer = new StringTokenizer(tagString, ":"); ArrayList<String> argList = new ArrayList<String>(); // of the attribute to reference. It may have a second argument, which // is the number of characters to use from the attribute value. The // arguments will be delimited by colons. final StringTokenizer tokenizer = new StringTokenizer(tagString, ":"); final List<String> args = new ArrayList<String>(); while (tokenizer.hasMoreTokens()) { argList.add(tokenizer.nextToken()); args.add(tokenizer.nextToken()); } final String[] arguments = args.toArray(new String[args.size()]); String[] args = new String[argList.size()]; argList.toArray(args); AttributeValueTag tag = new AttributeValueTag(); final AttributeValueTag tag = new AttributeValueTag(); if (branch == null) { tag.initializeForTemplate(schema, this, template, args, lineNumber, warnings); tag.initializeForTemplate(schema, this, template, arguments, lineNumber, warnings); } else { tag.initializeForBranch(schema, this, branch, args, lineNumber, warnings); tag.initializeForBranch(schema, this, branch, arguments, lineNumber, warnings); } return tag; } /** * Retrieves a File object based on the provided path. If the given path is * absolute, then that absolute path will be used. If it is relative, then * it will first be evaluated relative to the current working directory. If * that path doesn't exist, then it will be evaluated relative to the * resource path. If that path doesn't exist, then it will be evaluated * relative to the directory containing the template file. * Retrieves a file based on the provided path. * <p> * To allow retrieval of a file located in a jar, you must use * {@code getReader()} method instead of this one. * <p> * File is searched successively in two locations : * <ul> * <li>Using the provided path as is.</li> * <li>Using resource path + provided path.</li> * </ul> * * @param path * The path provided for the file. * @return The File object for the specified path, or <CODE>null</CODE> if * the specified file could not be found. * @param filePath * The path provided for the file, which can be absolute or * relative. * @return the file, or <code>null</code> if it could not be found. */ public File getFile(String path) { // First, see if the file exists using the given path. This will work if // the file is absolute, or it's relative to the current working // directory. File f = new File(path); if (f.exists()) { return f; private File getFile(final String filePath) { File file = new File(filePath); // try raw path first if (file.exists()) { return file; } // If the provided path was absolute, then use it anyway, even though we // couldn't find the file. if (f.isAbsolute()) { return f; } // Try a path relative to the resource directory. String newPath = resourcePath + File.separator + path; f = new File(newPath); if (f.exists()) { return f; } // Try a path relative to the template directory, if it's available. if (templatePath != null) { newPath = templatePath = File.separator + path; f = new File(newPath); if (f.exists()) { return f; // try using resource path if (resourcePath != null) { file = new File(resourcePath + File.separator + filePath); if (file.exists()) { return file; } } return null; } /** * Retrieves the lines of the specified file as a string array. If the * result is already cached, then it will be used. If the result is not * cached, then the file data will be cached so that the contents can be * re-used if there are multiple references to the same file. * Retrieves a reader based on the provided path. * <p> * The path represent a file path either on the file system or in a jar. * File is searched successively in three locations : * <ul> * <li>Using the provided path on the file system.</li> * <li>Using resource path + provided path on the file system.</li> * <li>Using default resources path + provided path on the file system or in * a jar.</li> * </ul> * * @param file * The file for which to retrieve the contents. * @return An array containing the lines of the specified file. * @param filePath * The path provided for the file, which can be absolute or * relative. * @return A reader on the file, or <code>null</code> if it could not be * found. It is the responsability of caller to close the returned * reader. */ @SuppressWarnings("resource") BufferedReader getReader(final String filePath) { BufferedReader reader = null; File file = new File(filePath); try { if (file.exists()) { // try raw path first reader = new BufferedReader(new FileReader(file)); } else if (resourcePath != null) { // try using resource path file = new File(resourcePath + File.separator + filePath); if (file.exists()) { reader = new BufferedReader(new FileReader(file)); } } if (reader == null) { // try to find in default resources provided final InputStream stream = TemplateFile.class.getClassLoader().getResourceAsStream( new File(DEFAULT_RESOURCES_PATH, filePath).getPath()); if (stream != null) { reader = new BufferedReader(new InputStreamReader(stream)); } } } catch (FileNotFoundException e) { // Should never happen as we test file existence first. // In any case, nothing to do as we want to return null } return reader; } /** * Retrieves the lines of the provided reader, possibly reading them from * memory cache. * <p> * Lines are retrieved from reader at the first call, then cached in memory * for next calls, using the provided identifier. * <p> * Use {@code readFile()} method to avoid caching. * * @param label * Label used as identifier to cache the line read. * @param reader * Reader to parse for lines. * @return a list of lines * @throws IOException * If a problem occurs while reading the file. */ public String[] getFileLines(File file) throws IOException { String absolutePath = file.getAbsolutePath(); String[] lines = fileLines.get(absolutePath); String[] getLines(String identifier, final BufferedReader reader) throws IOException { String[] lines = fileLines.get(identifier); if (lines == null) { ArrayList<String> lineList = new ArrayList<String>(); BufferedReader reader = new BufferedReader(new FileReader(file)); while (true) { String line = reader.readLine(); if (line == null) { break; } else { lineList.add(line); } } reader.close(); lines = new String[lineList.size()]; lineList.toArray(lines); lineList.clear(); fileLines.put(absolutePath, lines); lines = readLines(reader).toArray(new String[] {}); fileLines.put(identifier, lines); } return lines; } /** * Generates the entries and writes them to the provided entry writer. * Retrieves the lines from the provided reader. * * @param entryWriter * The entry writer that should be used to write the entries. * @return The result that indicates whether processing should continue. * @param reader * The reader containing the lines. * @return a list of lines * @throws IOException * If an error occurs while writing the entry. * @throws DecodeException * If some other problem occurs. * If a problem occurs while reading the lines. */ public TagResult generateEntries(EntryWriter entryWriter) throws IOException, DecodeException { for (Branch b : branches.values()) { TagResult result = b.writeEntries(entryWriter); if (!(result.keepProcessingTemplateFile())) { return result; private List<String> readLines(final BufferedReader reader) throws IOException { final List<String> lines = new ArrayList<String>(); while (true) { final String line = reader.readLine(); if (line == null) { break; } lines.add(line); } return lines; } entryWriter.closeEntryWriter(); return TagResult.SUCCESS_RESULT; /** Iterator on branches that are used to read entries. */ private Iterator<Branch> branchesIterator; /** Branch from which entries are currently read. */ private Branch currentBranch; /** Entry to return when calling {@code nextEntry} method. */ private TemplateEntry nextEntry; /** * Returns {@code true} if there is another generated entry * to return. * * @return {@code true} if another entry can be returned. */ boolean hasNext() { if (nextEntry != null) { return true; } while (currentBranch != null) { if (currentBranch.hasNext()) { nextEntry = currentBranch.nextEntry(); return true; } currentBranch = branchesIterator.hasNext() ? branchesIterator.next() : null; } return false; } /** * Writer of generated entries. * Returns the next generated entry. * * @return The next entry. * @throws NoSuchElementException * If this reader does not contain any more entries. */ public interface EntryWriter { /** * Writes the provided entry to the appropriate target. * * @param entry * The entry to be written. * @return <CODE>true</CODE> if the entry writer will accept additional * entries, or <CODE>false</CODE> if no more entries should be * written. * @throws IOException * If a problem occurs while writing the entry to its * intended destination. * @throws DecodeException * If some other problem occurs. */ public boolean writeEntry(TemplateEntry entry) throws IOException, DecodeException; /** * Notifies the entry writer that no more entries will be provided and * that any associated cleanup may be performed. */ public void closeEntryWriter(); Entry nextEntry() { if (!hasNext()) { throw new NoSuchElementException(); } final Entry entry = nextEntry.toEntry(); nextEntry = null; return entry; } /** * Represents a branch that should be included in the generated results. A * branch may or may not have subordinate entries. */ static class Branch { static final class Branch { /** The DN for this branch entry. */ private DN branchDN; private final DN branchDN; /** * The number of entries that should be created below this branch for * each subordinate template. */ private int[] numEntriesPerTemplate; private final List<Integer> numEntriesPerTemplate; /** The names of the subordinate templates for this branch. */ private String[] subordinateTemplateNames; private final List<String> subordinateTemplateNames; /** The set of subordinate templates for this branch. */ private Template[] subordinateTemplates; private List<Template> subordinateTemplates; /** The set of template lines that correspond to the RDN components. */ private TemplateLine[] rdnLines; private final List<TemplateLine> rdnLines; /** The set of extra lines that should be included in this branch entry. */ private TemplateLine[] extraLines; private final List<TemplateLine> extraLines; private Schema schema; /** Entry to return when calling {@code nextEntry} method. */ private TemplateEntry nextEntry; /** Index of subordinate template currently read. */ private int currentSubTemplateIndex; /** * Creates a new branch with the provided information. @@ -1544,9 +1362,12 @@ * The DN for this branch entry. * @param schema * schema used to create attribute * @throws DecodeException * if a problem occurs during initialization */ public Branch(TemplateFile templateFile, DN branchDN, Schema schema) { this(templateFile, branchDN, schema, new String[0], new int[0], new TemplateLine[0]); Branch(final TemplateFile templateFile, final DN branchDN, final Schema schema) throws DecodeException { this(templateFile, branchDN, schema, new ArrayList<String>(), new ArrayList<Integer>(), new ArrayList<TemplateLine>()); } /** @@ -1567,56 +1388,37 @@ * @param extraLines * The set of extra lines that should be included in this * branch entry. * @throws DecodeException * if a problem occurs during initialization */ public Branch(TemplateFile templateFile, DN branchDN, Schema schema, String[] subordinateTemplateNames, int[] numEntriesPerTemplate, TemplateLine[] extraLines) { Branch(final TemplateFile templateFile, final DN branchDN, final Schema schema, final List<String> subordinateTemplateNames, final List<Integer> numEntriesPerTemplate, final List<TemplateLine> extraLines) throws DecodeException { this.branchDN = branchDN; this.schema = schema; this.subordinateTemplateNames = subordinateTemplateNames; this.numEntriesPerTemplate = numEntriesPerTemplate; this.extraLines = extraLines; subordinateTemplates = null; // Get the RDN template lines based just on the entry DN. Entry entry = LinkedHashMapEntry.FACTORY.newEntry(branchDN); ArrayList<LocalizableMessage> warnings = new ArrayList<LocalizableMessage>(); ArrayList<TemplateLine> lineList = new ArrayList<TemplateLine>(); for (ObjectClass objectClass : Entries.getObjectClasses(entry, schema)) { try { String[] valueStrings = new String[] { objectClass.getNameOrOID() }; TemplateTag[] tags = new TemplateTag[1]; tags[0] = new StaticTextTag(); tags[0].initializeForBranch(schema, templateFile, this, valueStrings, 0, warnings); TemplateLine l = new TemplateLine(CoreSchema.getObjectClassAttributeType(), 0, tags); lineList.add(l); } catch (Exception e) { // This should never happen. e.printStackTrace(); // The RDN template lines are based on the DN. final List<LocalizableMessage> warnings = new ArrayList<LocalizableMessage>(); rdnLines = new ArrayList<TemplateLine>(); for (final AVA ava : branchDN.rdn()) { final Attribute attribute = ava.toAttribute(); for (final ByteString value : attribute.toArray()) { final List<TemplateTag> tags = buildTagListForValue(value.toString(), templateFile, schema, warnings); rdnLines.add(new TemplateLine(attribute.getAttributeDescription().getAttributeType(), 0, tags)); } } } for (Attribute attribute : entry.getAllAttributes()) { for (String value : attribute.toArray(new String[attribute.size()])) { try { String[] valueStrings = new String[] { value }; TemplateTag[] tags = new TemplateTag[1]; tags[0] = new StaticTextTag(); tags[0].initializeForBranch(schema, templateFile, this, valueStrings, 0, warnings); lineList.add( new TemplateLine(attribute.getAttributeDescription().getAttributeType(), 0, tags)); } catch (Exception e) { // This should never happen. e.printStackTrace(); } } } rdnLines = new TemplateLine[lineList.size()]; lineList.toArray(rdnLines); private List<TemplateTag> buildTagListForValue(final String value, final TemplateFile templateFile, final Schema schema, final List<LocalizableMessage> warnings) throws DecodeException { final StaticTextTag tag = new StaticTextTag(); tag.initializeForBranch(schema, templateFile, this, new String[] { value }, 0, warnings); final List<TemplateTag> tags = new ArrayList<TemplateTag>(); tags.add(tag); return tags; } /** @@ -1631,66 +1433,24 @@ * If any of the subordinate templates are not defined in * the template file. */ public void completeBranchInitialization(Map<String, Template> templates) throws DecodeException { if (subordinateTemplateNames == null) { subordinateTemplateNames = new String[0]; subordinateTemplates = new Template[0]; } else { subordinateTemplates = new Template[subordinateTemplateNames.length]; for (int i = 0; i < subordinateTemplates.length; i++) { subordinateTemplates[i] = templates.get(subordinateTemplateNames[i].toLowerCase()); if (subordinateTemplates[i] == null) { LocalizableMessage message = ERR_ENTRY_GENERATOR_UNDEFINED_BRANCH_SUBORDINATE.get( branchDN.toString(), subordinateTemplateNames[i]); throw DecodeException.fatalError(message); } private void completeBranchInitialization(final Map<String, Template> templates) throws DecodeException { subordinateTemplates = new ArrayList<Template>(); for (int i = 0; i < subordinateTemplateNames.size(); i++) { subordinateTemplates.add(templates.get(subordinateTemplateNames.get(i).toLowerCase())); if (subordinateTemplates.get(i) == null) { throw DecodeException.fatalError(ERR_ENTRY_GENERATOR_UNDEFINED_BRANCH_SUBORDINATE.get( branchDN.toString(), subordinateTemplateNames.get(i))); } } nextEntry = buildBranchEntry(); } /** * Retrieves the DN for this branch entry. * * @return The DN for this branch entry. */ public DN getBranchDN() { DN getBranchDN() { return branchDN; } /** * Retrieves the names of the subordinate templates for this branch. * * @return The names of the subordinate templates for this branch. */ public String[] getSubordinateTemplateNames() { return subordinateTemplateNames; } /** * Retrieves the set of subordinate templates used to generate entries * below this branch. Note that the subordinate templates will not be * available until the <CODE>completeBranchInitialization</CODE> method * has been called. * * @return The set of subordinate templates used to generate entries * below this branch. */ public Template[] getSubordinateTemplates() { return subordinateTemplates; } /** * Retrieves the number of entries that should be created below this * branch for each subordinate template. * * @return The number of entries that should be created below this * branch for each subordinate template. */ public int[] getNumEntriesPerTemplate() { return numEntriesPerTemplate; } /** * Adds a new subordinate template to this branch. Note that this should * not be used after <CODE>completeBranchInitialization</CODE> has been * called. @@ -1700,29 +1460,9 @@ * @param numEntries * The number of entries to create based on the template. */ public void addSubordinateTemplate(String name, int numEntries) { String[] newNames = new String[subordinateTemplateNames.length + 1]; int[] newCounts = new int[numEntriesPerTemplate.length + 1]; System.arraycopy(subordinateTemplateNames, 0, newNames, 0, subordinateTemplateNames.length); System.arraycopy(numEntriesPerTemplate, 0, newCounts, 0, numEntriesPerTemplate.length); newNames[subordinateTemplateNames.length] = name; newCounts[numEntriesPerTemplate.length] = numEntries; subordinateTemplateNames = newNames; numEntriesPerTemplate = newCounts; } /** * Retrieves the set of extra lines that should be included in this * branch entry. * * @return The set of extra lines that should be included in this branch * entry. */ public TemplateLine[] getExtraLines() { return extraLines; void addSubordinateTemplate(final String name, final int numEntries) { subordinateTemplateNames.add(name); numEntriesPerTemplate.add(numEntries); } /** @@ -1732,12 +1472,8 @@ * @param line * The line to add to the set of extra lines for this branch. */ public void addExtraLine(TemplateLine line) { TemplateLine[] newExtraLines = new TemplateLine[extraLines.length + 1]; System.arraycopy(extraLines, 0, newExtraLines, 0, extraLines.length); newExtraLines[extraLines.length] = line; extraLines = newExtraLines; void addExtraLine(final TemplateLine line) { extraLines.add(line); } /** @@ -1747,73 +1483,76 @@ * * @param attributeType * The attribute type for which to make the determination. * @return <CODE>true</CODE> if the branch does contain the specified * attribute type, or <CODE>false</CODE> if it does not. * @return <code>true</code> if the branch does contain the specified * attribute type, or <code>false</code> if it does not. */ public boolean hasAttribute(AttributeType attributeType) { boolean hasAttribute(final AttributeType attributeType) { if (branchDN.rdn().getAttributeValue(attributeType) != null) { return true; } for (TemplateLine l : extraLines) { if (l.getAttributeType().equals(attributeType)) { for (final TemplateLine line : extraLines) { if (line.getAttributeType().equals(attributeType)) { return true; } } return false; } /** * Writes the entry for this branch, as well as all appropriate * subordinate entries. * Returns the entry corresponding to this branch. * * @param entryWriter * The entry writer to which the entries should be written. * @return The result that indicates whether processing should continue. * @throws IOException * If a problem occurs while attempting to write to the LDIF * writer. * @throws DecodeException * If some other problem occurs. * @return the entry, or null if it can't be generated */ public TagResult writeEntries(EntryWriter entryWriter) throws IOException, DecodeException { // Create a new template entry and populate it based on the RDN // attributes and extra lines. TemplateEntry entry = new TemplateEntry(this); for (TemplateLine l : rdnLines) { TagResult r = l.generateLine(entry); if (!(r.keepProcessingEntry() && r.keepProcessingParent() && r.keepProcessingTemplateFile())) { return r; } private TemplateEntry buildBranchEntry() { final TemplateEntry entry = new TemplateEntry(this); final List<TemplateLine> lines = new ArrayList<TemplateLine>(rdnLines); lines.addAll(extraLines); for (final TemplateLine line : lines) { line.generateLine(entry); } for (TemplateLine l : extraLines) { TagResult r = l.generateLine(entry); if (!(r.keepProcessingEntry() && r.keepProcessingParent() && r.keepProcessingTemplateFile())) { return r; } for (int i = 0; i < subordinateTemplates.size(); i++) { subordinateTemplates.get(i).reset(entry.getDN(), numEntriesPerTemplate.get(i)); } return entry; } if (!entryWriter.writeEntry(entry)) { return TagResult.STOP_PROCESSING; /** * Returns {@code true} if there is another generated entry to return. * * @return {@code true} if another entry can be returned. */ boolean hasNext() { if (nextEntry != null) { return true; } for (int i = 0; i < subordinateTemplates.length; i++) { TagResult r = subordinateTemplates[i].writeEntries(entryWriter, branchDN, numEntriesPerTemplate[i]); if (!(r.keepProcessingParent() && r.keepProcessingTemplateFile())) { if (r.keepProcessingTemplateFile()) { // We don't want to propagate a "stop processing parent" // all the way up the chain. return TagResult.SUCCESS_RESULT; // get the next entry from current subtemplate if (nextEntry == null) { for (; currentSubTemplateIndex < subordinateTemplates.size(); currentSubTemplateIndex++) { if (subordinateTemplates.get(currentSubTemplateIndex).hasNext()) { nextEntry = subordinateTemplates.get(currentSubTemplateIndex).nextEntry(); if (nextEntry != null) { return true; } } return r; } } return false; } return TagResult.SUCCESS_RESULT; /** * Returns the next generated entry. * * @return The next entry. * @throws NoSuchElementException * If this reader does not contain any more entries. */ TemplateEntry nextEntry() { if (!hasNext()) { throw new NoSuchElementException(); } final TemplateEntry entry = nextEntry; nextEntry = null; return entry; } } @@ -1827,54 +1566,25 @@ * The attribute types that are used in the RDN for entries generated * using this template. */ private org.forgerock.opendj.ldap.schema.AttributeType[] rdnAttributes; private final List<AttributeType> rdnAttributes; /** The number of entries to create for each subordinate template. */ private int[] numEntriesPerTemplate; private final List<Integer> numEntriesPerTemplate; /** The name for this template. */ private String name; private final String name; /** The names of the subordinate templates below this template. */ private String[] subordinateTemplateNames; private final List<String> subTemplateNames; /** The subordinate templates below this template. */ private Template[] subordinateTemplates; private List<Template> subTemplates; /** The template file that contains this template. */ private TemplateFile templateFile; private final TemplateFile templateFile; /** The set of template lines for this template. */ private TemplateLine[] templateLines; /** * Creates a new template with the provided information. * * @param templateFile * The template file that contains this template. * @param name * The name for this template. * @param rdnAttributes * The set of attribute types that are used in the RDN for * entries generated using this template. * @param subordinateTemplateNames * The names of the subordinate templates below this * template. * @param numEntriesPerTemplate * The number of entries to create below each subordinate * template. */ public Template(TemplateFile templateFile, String name, AttributeType[] rdnAttributes, String[] subordinateTemplateNames, int[] numEntriesPerTemplate) { this.templateFile = templateFile; this.name = name; this.rdnAttributes = rdnAttributes; this.subordinateTemplateNames = subordinateTemplateNames; this.numEntriesPerTemplate = numEntriesPerTemplate; templateLines = new TemplateLine[0]; subordinateTemplates = null; } private final List<TemplateLine> templateLines; /** * Creates a new template with the provided information. @@ -1895,16 +1605,15 @@ * @param templateLines * The set of template lines for this template. */ public Template(TemplateFile templateFile, String name, AttributeType[] rdnAttributes, String[] subordinateTemplateNames, int[] numEntriesPerTemplate, TemplateLine[] templateLines) { Template(final TemplateFile templateFile, final String name, final List<AttributeType> rdnAttributes, final List<String> subordinateTemplateNames, final List<Integer> numEntriesPerTemplate, final List<TemplateLine> templateLines) { this.templateFile = templateFile; this.name = name; this.rdnAttributes = rdnAttributes; this.subordinateTemplateNames = subordinateTemplateNames; this.subTemplateNames = subordinateTemplateNames; this.numEntriesPerTemplate = numEntriesPerTemplate; this.templateLines = templateLines; subordinateTemplates = null; } /** @@ -1920,117 +1629,47 @@ * If any of the subordinate templates are not defined in * the template file. */ public void completeTemplateInitialization(Map<String, Template> templates) throws DecodeException { // Make sure that all of the specified subordinate templates exist. if (subordinateTemplateNames == null) { subordinateTemplateNames = new String[0]; subordinateTemplates = new Template[0]; } else { subordinateTemplates = new Template[subordinateTemplateNames.length]; for (int i = 0; i < subordinateTemplates.length; i++) { subordinateTemplates[i] = templates.get(subordinateTemplateNames[i].toLowerCase()); if (subordinateTemplates[i] == null) { LocalizableMessage message = ERR_ENTRY_GENERATOR_UNDEFINED_TEMPLATE_SUBORDINATE.get( subordinateTemplateNames[i], name); throw DecodeException.fatalError(message); } void completeTemplateInitialization(final Map<String, Template> templates) throws DecodeException { subTemplates = new ArrayList<Template>(); for (final String subordinateName : subTemplateNames) { final Template template = templates.get(subordinateName.toLowerCase()); if (template == null) { throw DecodeException.fatalError(ERR_ENTRY_GENERATOR_UNDEFINED_TEMPLATE_SUBORDINATE.get( this.name, subordinateName)); } subTemplates.add(template); } ensureAllRDNAttributesAreDefined(); } // Make sure that all of the RDN attributes are defined. HashSet<AttributeType> rdnAttrs = new HashSet<AttributeType>(rdnAttributes.length); for (AttributeType t : rdnAttributes) { rdnAttrs.add(t); private void ensureAllRDNAttributesAreDefined() throws DecodeException { Set<AttributeType> rdnAttrs = new HashSet<AttributeType>(rdnAttributes); List<AttributeType> templateAttrs = new ArrayList<AttributeType>(); for (TemplateLine line : templateLines) { templateAttrs.add(line.getAttributeType()); } for (TemplateLine l : templateLines) { if (rdnAttrs.remove(l.getAttributeType())) { if (rdnAttrs.isEmpty()) { break; } } } rdnAttrs.removeAll(templateAttrs); if (!rdnAttrs.isEmpty()) { AttributeType t = rdnAttrs.iterator().next(); LocalizableMessage message = ERR_ENTRY_GENERATOR_TEMPLATE_MISSING_RDN_ATTR.get(name, t.getNameOrOID()); throw DecodeException.fatalError(message); throw DecodeException.fatalError(ERR_ENTRY_GENERATOR_TEMPLATE_MISSING_RDN_ATTR.get( name, t.getNameOrOID())); } } /** * Retrieves the name for this template. * * @return The name for this template. */ public String getName() { String getName() { return name; } /** * Retrieves the set of attribute types that are used in the RDN for * entries generated using this template. * * @return The set of attribute types that are used in the RDN for * entries generated using this template. */ public AttributeType[] getRDNAttributes() { List<AttributeType> getRDNAttributes() { return rdnAttributes; } /** * Retrieves the names of the subordinate templates used to generate * entries below entries created by this template. * * @return The names of the subordinate templates used to generate * entries below entries created by this template. */ public String[] getSubordinateTemplateNames() { return subordinateTemplateNames; } /** * Retrieves the subordinate templates used to generate entries below * entries created by this template. * * @return The subordinate templates used to generate entries below * entries created by this template. */ public Template[] getSubordinateTemplates() { return subordinateTemplates; } /** * Retrieves the number of entries that should be created for each * subordinate template. * * @return The number of entries that should be created for each * subordinate template. */ public int[] getNumEntriesPerTemplate() { return numEntriesPerTemplate; } /** * Retrieves the set of template lines for this template. * * @return The set of template lines for this template. */ public TemplateLine[] getTemplateLines() { List<TemplateLine> getTemplateLines() { return templateLines; } /** * Adds the provided template line to this template. * * @param line * The template line to add to this template. */ public void addTemplateLine(TemplateLine line) { TemplateLine[] newTemplateLines = new TemplateLine[templateLines.length + 1]; System.arraycopy(templateLines, 0, newTemplateLines, 0, templateLines.length); newTemplateLines[templateLines.length] = line; templateLines = newTemplateLines; void addTemplateLine(final TemplateLine line) { templateLines.add(line); } /** @@ -2043,68 +1682,124 @@ * template lines that reference the provided attribute type, or * <CODE>false</CODE> if not. */ public boolean hasAttribute(AttributeType attributeType) { for (TemplateLine l : templateLines) { if (l.getAttributeType().equals(attributeType)) { boolean hasAttribute(final AttributeType attributeType) { for (final TemplateLine line : templateLines) { if (line.getAttributeType().equals(attributeType)) { return true; } } return false; } /** parent DN of entries to generate for this template. */ private DN parentDN; /** Number of entries to generate for this template. */ private int numberOfEntries; /** Current count of generated entries for this template. */ private int entriesCount; /** Indicates if current entry has been initialized. */ private boolean currentEntryIsInitialized; /** Index of current subordinate template to use for current entry. */ private int subTemplateIndex; /** Entry to return when calling {@code nextEntry} method. */ private TemplateEntry nextEntry; /** * Reset this template with provided parentDN and number of entries to * generate. * <p> * After a reset, the template can be used again to generate some * entries with a different parent DN and number of entries. * * @param parentDN * The parent DN of entires to generate for this template. * @param numberOfEntries * The number of entries to generate for this template. */ void reset(final DN parentDN, final int numberOfEntries) { this.parentDN = parentDN; this.numberOfEntries = numberOfEntries; entriesCount = 0; currentEntryIsInitialized = false; subTemplateIndex = 0; nextEntry = null; } /** * Returns an entry for this template. * * @return the entry, or null if it can't be generated */ private TemplateEntry buildTemplateEntry() { templateFile.nextFirstAndLastNames(); final TemplateEntry templateEntry = new TemplateEntry(this, parentDN); for (final TemplateLine line : templateLines) { line.generateLine(templateEntry); } for (int i = 0; i < subTemplates.size(); i++) { subTemplates.get(i).reset(templateEntry.getDN(), numEntriesPerTemplate.get(i)); } return templateEntry; } /** * Returns {@code true} if there is another generated entry to return. * * @return {@code true} if another entry can be returned. */ boolean hasNext() { if (nextEntry != null) { return true; } while (entriesCount < numberOfEntries) { // get the template entry if (!currentEntryIsInitialized) { nextEntry = buildTemplateEntry(); if (nextEntry != null) { currentEntryIsInitialized = true; return true; } return false; } // get the next entry from current subtemplate if (nextEntry == null) { for (; subTemplateIndex < subTemplates.size(); subTemplateIndex++) { if (subTemplates.get(subTemplateIndex).hasNext()) { nextEntry = subTemplates.get(subTemplateIndex).nextEntry(); if (nextEntry != null) { return true; } } } } // reset for next template entry entriesCount++; currentEntryIsInitialized = false; subTemplateIndex = 0; } return false; } /** * Writes the entry for this template, as well as all appropriate * subordinate entries. * Returns the next generated entry. * * @param entryWriter * The entry writer that will be used to write the entries. * @param parentDN * The DN of the entry below which the subordinate entries * should be generated. * @param count * The number of entries to generate based on this template. * @return The result that indicates whether processing should continue. * @throws IOException * If a problem occurs while attempting to write to the LDIF * writer. * @throws DecodeException * If some other problem occurs. * @return The next entry. * @throws NoSuchElementException * If this reader does not contain any more entries. */ public TagResult writeEntries(EntryWriter entryWriter, DN parentDN, int count) throws IOException, DecodeException { for (int i = 0; i < count; i++) { templateFile.nextFirstAndLastNames(); TemplateEntry templateEntry = new TemplateEntry(this, parentDN); for (TemplateLine l : templateLines) { TagResult r = l.generateLine(templateEntry); if (!(r.keepProcessingEntry() && r.keepProcessingParent() && r.keepProcessingTemplateFile())) { return r; } } if (!entryWriter.writeEntry(templateEntry)) { return TagResult.STOP_PROCESSING; } for (int j = 0; j < subordinateTemplates.length; j++) { TagResult r = subordinateTemplates[j].writeEntries(entryWriter, templateEntry.getDN(), numEntriesPerTemplate[j]); if (!(r.keepProcessingParent() && r.keepProcessingTemplateFile())) { if (r.keepProcessingTemplateFile()) { // We don't want to propagate a // "stop processing parent" // all the way up the chain. return TagResult.SUCCESS_RESULT; } return r; } } TemplateEntry nextEntry() { if (!hasNext()) { throw new NoSuchElementException(); } return TagResult.SUCCESS_RESULT; final TemplateEntry entry = nextEntry; nextEntry = null; return entry; } } @@ -2116,12 +1811,6 @@ /** Template entry that represents a null object. */ static final TemplateEntry NULL_TEMPLATE_ENTRY = new TemplateEntry(null, null); /** * The branch used to generate this entry (if it is associated with a * branch). */ private Branch branch; /** The DN for this template entry, if it is known. */ private DN dn; @@ -2129,20 +1818,22 @@ * The DN of the parent entry for this template entry, if it is * available. */ private DN parentDN; private final DN parentDN; /** * The set of attributes associated with this template entry, mapped * from the lowercase name of the attribute to the list of generated * values. * A list of template values is never empty in the map, it always has * at least one element. */ private LinkedHashMap<AttributeType, ArrayList<TemplateValue>> attributes; private final LinkedHashMap<AttributeType, List<TemplateValue>> attributes; /** * The template used to generate this entry (if it is associated with a * template). * The template used to generate this entry if it is associated with a * template. */ private Template template; private final Template template; /** * Creates a new template entry that will be associated with the @@ -2151,13 +1842,11 @@ * @param branch * The branch to use when creating this template entry. */ public TemplateEntry(Branch branch) { this.branch = branch; TemplateEntry(final Branch branch) { dn = branch.getBranchDN(); attributes = new LinkedHashMap<AttributeType, List<TemplateValue>>(); template = null; parentDN = null; attributes = new LinkedHashMap<AttributeType, ArrayList<TemplateValue>>(); } /** @@ -2169,43 +1858,13 @@ * @param parentDN * The DN of the parent entry for this template entry. */ public TemplateEntry(Template template, DN parentDN) { TemplateEntry(final Template template, final DN parentDN) { this.template = template; this.parentDN = parentDN; dn = null; branch = null; attributes = new LinkedHashMap<AttributeType, ArrayList<TemplateValue>>(); attributes = new LinkedHashMap<AttributeType, List<TemplateValue>>(); } /** * Retrieves the branch used to generate this entry. * * @return The branch used to generate this entry, or <CODE>null</CODE> * if it is associated with a template instead of a branch. */ public Branch getBranch() { return branch; } /** * Retrieves the template used to generate this entry. * * @return The template used to generate this entry, or * <CODE>null</CODE> if it is associated with a branch instead * of a template. */ public Template getTemplate() { return template; } /** * Retrieves the DN of the parent entry for this template entry. * * @return The DN of the parent entry for this template entry, or * <CODE>null</CODE> if there is no parent DN. */ public DN getParentDN() { DN getParentDN() { return parentDN; } @@ -2215,55 +1874,22 @@ * @return The DN for this template entry if it is known, or * <CODE>null</CODE> if it cannot yet be determined. */ public DN getDN() { // TODO : building to review, particularly building RN with multiple // AVA // using StringBuilder because no facility using other way DN getDN() { if (dn == null) { RDN rdn; AttributeType[] rdnAttrs = template.getRDNAttributes(); if (rdnAttrs.length == 1) { AttributeType type = rdnAttrs[0]; TemplateValue templateValue = getValue(type); final Collection<AVA> avas = new ArrayList<AVA>(); for (final AttributeType attrType : template.getRDNAttributes()) { final TemplateValue templateValue = getValue(attrType); if (templateValue == null) { return null; } rdn = new RDN(type, templateValue.getValueAsString()); } else { StringBuilder rdnString = new StringBuilder(); for (int i = 0; i < rdnAttrs.length; i++) { AttributeType type = rdnAttrs[i]; TemplateValue templateValue = getValue(type); if (templateValue == null) { return null; } if (i > 0) { rdnString.append("+"); } rdnString.append(new AVA(type, templateValue.getValueAsString()).toString()); } rdn = RDN.valueOf(rdnString.toString()); avas.add(new AVA(attrType, templateValue.getValueAsString())); } dn = parentDN.child(rdn); dn = parentDN.child(new RDN(avas)); } return dn; } /** * Indicates whether this entry contains one or more values for the * specified attribute type. * * @param attributeType * The attribute type for which to make the determination. * @return <CODE>true</CODE> if this entry contains one or more values * for the specified attribute type, or <CODE>false</CODE> if * not. */ public boolean hasAttribute(AttributeType attributeType) { return attributes.containsKey(attributeType); } /** * Retrieves the value for the specified attribute, if defined. If the * specified attribute has multiple values, then the first will be * returned. @@ -2273,13 +1899,12 @@ * @return The value for the specified attribute, or <CODE>null</CODE> * if there are no values for that attribute type. */ public TemplateValue getValue(AttributeType attributeType) { ArrayList<TemplateValue> valueList = attributes.get(attributeType); if ((valueList == null) || valueList.isEmpty()) { return null; } else { return valueList.get(0); TemplateValue getValue(final AttributeType attributeType) { final List<TemplateValue> values = attributes.get(attributeType); if ((values != null)) { return values.get(0); } return null; } /** @@ -2292,41 +1917,32 @@ * <CODE>null</CODE> if there are no values for that attribute * type. */ public List<TemplateValue> getValues(AttributeType attributeType) { ArrayList<TemplateValue> valueList = attributes.get(attributeType); return valueList; List<TemplateValue> getValues(AttributeType attributeType) { return attributes.get(attributeType); } /** * Adds the provided template value to this entry. * * @param value * The value to add to this entry. */ public void addValue(TemplateValue value) { ArrayList<TemplateValue> valueList = attributes.get(value.getAttributeType()); if (valueList == null) { valueList = new ArrayList<TemplateValue>(); valueList.add(value); attributes.put(value.getAttributeType(), valueList); } else { valueList.add(value); void addValue(TemplateValue value) { List<TemplateValue> values = attributes.get(value.getAttributeType()); if (values == null) { values = new ArrayList<TemplateValue>(); attributes.put(value.getAttributeType(), values); } values.add(value); } /** * Returns an entry from this template entry. * Returns an entry built from this template entry. * * @return an entry */ public Entry toEntry() { Entry entry = LinkedHashMapEntry.FACTORY.newEntry(getDN()); AttributeFactory attributeFactory = LinkedAttribute.FACTORY; Entry toEntry() { final Entry entry = new LinkedHashMapEntry(getDN()); for (AttributeType attributeType : attributes.keySet()) { ArrayList<TemplateValue> valueList = attributes.get(attributeType); Attribute newAttribute = attributeFactory.newAttribute(AttributeDescription.create(attributeType)); for (TemplateValue value : valueList) { for (final AttributeType attributeType : attributes.keySet()) { final List<TemplateValue> valueList = attributes.get(attributeType); final Attribute newAttribute = new LinkedAttribute(AttributeDescription.create(attributeType)); for (final TemplateValue value : valueList) { newAttribute.add(value.getValueAsString()); } entry.addAttribute(newAttribute); @@ -2340,69 +1956,27 @@ * any number of tags to be evaluated. */ static class TemplateLine { /** The attribute type for this template line. */ private AttributeType attributeType; /** The attribute type to which this template line corresponds. */ private final AttributeType attributeType; /** * The line number on which this template line appears in the template * file. */ private int lineNumber; private final int lineNumber; /** The set of tags for this template line. */ private TemplateTag[] tags; private final List<TemplateTag> tags; /** Whether this line corresponds to an URL value or not. */ private boolean isURL; private final boolean isURL; /** Whether this line corresponds to a base64 encoded value or not. */ private boolean isBase64; private final boolean isBase64; /** * Retrieves the attribute type for this template line. * * @return The attribute type for this template line. */ public AttributeType getAttributeType() { return attributeType; } /** * Retrieves the line number on which this template line appears in the * template file. * * @return The line number on which this template line appears in the * template file. */ public int getLineNumber() { return lineNumber; } /** * Returns whether the value of this template line corresponds to an URL * or not. * * @return <CODE>true</CODE> if the value of this template line * corresponds to an URL and <CODE>false</CODE> otherwise. */ public boolean isURL() { return isURL; } /** * Returns whether the value of this template line corresponds to a * Base64 encoded value or not. * * @return <CODE>true</CODE> if the value of this template line * corresponds to a Base64 encoded value and <CODE>false</CODE> * otherwise. */ public boolean isBase64() { return isBase64; } /** * Creates a new template line with the provided information. * Creates a new template line. * * @param attributeType * The attribute type for this template line. @@ -2412,12 +1986,12 @@ * @param tags * The set of tags for this template line. */ public TemplateLine(AttributeType attributeType, int lineNumber, TemplateTag[] tags) { TemplateLine(final AttributeType attributeType, final int lineNumber, final List<TemplateTag> tags) { this(attributeType, lineNumber, tags, false, false); } /** * Creates a new template line with the provided information. * Creates a new template line with URL and base64 flags. * * @param attributeType * The attribute type for this template line. @@ -2432,8 +2006,8 @@ * Whether this template line's value is Base64 encoded or * not. */ public TemplateLine(AttributeType attributeType, int lineNumber, TemplateTag[] tags, boolean isURL, boolean isBase64) { TemplateLine(final AttributeType attributeType, final int lineNumber, final List<TemplateTag> tags, final boolean isURL, final boolean isBase64) { this.attributeType = attributeType; this.lineNumber = lineNumber; this.tags = tags; @@ -2441,6 +2015,10 @@ this.isBase64 = isBase64; } AttributeType getAttributeType() { return attributeType; } /** * Generates the content for this template line and places it in the * provided template entry. @@ -2449,19 +2027,16 @@ * The template entry being generated. * @return The result of generating the template line. */ public TagResult generateLine(TemplateEntry templateEntry) { TemplateValue value = new TemplateValue(this); for (TemplateTag t : tags) { TagResult result = t.generateValue(templateEntry, value); if (!(result.keepProcessingLine() && result.keepProcessingEntry() && result.keepProcessingParent() && result.keepProcessingTemplateFile())) { TagResult generateLine(final TemplateEntry templateEntry) { final TemplateValue value = new TemplateValue(this); for (final TemplateTag tag : tags) { final TagResult result = tag.generateValue(templateEntry, value); if (result != TagResult.SUCCESS) { return result; } } templateEntry.addValue(value); return TagResult.SUCCESS_RESULT; return TagResult.SUCCESS; } } @@ -2469,77 +2044,37 @@ * Represents a value generated from a template line. */ static class TemplateValue { /** The generated template value. */ private StringBuilder templateValue; private final StringBuilder templateValue; /** The template line used to generate this value. */ private TemplateLine templateLine; private final TemplateLine templateLine; /** * Creates a new template value with the provided information. * * @param templateLine * The template line used to generate this value. */ public TemplateValue(TemplateLine templateLine) { TemplateValue(final TemplateLine templateLine) { this.templateLine = templateLine; templateValue = new StringBuilder(); } /** * Retrieves the template line used to generate this value. * * @return The template line used to generate this value. */ public TemplateLine getTemplateLine() { return templateLine; } /** * Retrieves the attribute type for this template value. * * @return The attribute type for this template value. */ public AttributeType getAttributeType() { AttributeType getAttributeType() { return templateLine.getAttributeType(); } /** * Retrieves the generated value. * * @return The generated value. */ public StringBuilder getValue() { return templateValue; } /** * Retrieves the generated value as String. * * @return The generated value. */ public String getValueAsString() { /** Returns the generated value as String. */ String getValueAsString() { return templateValue.toString(); } /** * Appends the provided string to this template value. * * @param s * The string to append. */ public void append(String s) { /** Appends the provided string to this template value. */ void append(final String s) { templateValue.append(s); } /** * Appends the string representation of the provided object to this * template value. * * @param o * The object to append. */ public void append(Object o) { void append(final Object o) { templateValue.append(String.valueOf(o)); } } opendj3/opendj-core/src/main/java/org/forgerock/opendj/ldif/TemplateTag.java
@@ -28,7 +28,7 @@ import static com.forgerock.opendj.ldap.CoreMessages.*; import java.io.File; import java.io.BufferedReader; import java.io.IOException; import java.text.DecimalFormat; import java.util.List; @@ -45,6 +45,8 @@ import org.forgerock.opendj.ldif.TemplateFile.TemplateEntry; import org.forgerock.opendj.ldif.TemplateFile.TemplateValue; import com.forgerock.opendj.util.StaticUtils; /** * Represents a tag that may be used in a template line when generating entries. * It can be used to generate content. @@ -56,26 +58,21 @@ /** * Retrieves the name for this tag. * * @return The name for this tag. */ public abstract String getName(); abstract String getName(); /** * Indicates whether this tag is allowed for use in the extra lines for * branches. * * @return <CODE>true</CODE> if this tag may be used in branch definitions, * or <CODE>false</CODE> if not. */ public abstract boolean allowedInBranch(); abstract boolean allowedInBranch(); /** * Performs any initialization for this tag that may be needed while parsing * a branch definition. * * @param schema * schema used to create attributes * The schema used to create attributes. * @param templateFile * The template file in which this tag is used. * @param branch @@ -88,10 +85,8 @@ * @param warnings * A list into which any appropriate warning messages may be * placed. * @throws DecodeException * if a problem occurs */ public void initializeForBranch(Schema schema, TemplateFile templateFile, Branch branch, String[] arguments, void initializeForBranch(Schema schema, TemplateFile templateFile, Branch branch, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { // No implementation required by default. } @@ -101,12 +96,12 @@ * a template definition. * * @param schema * schema used to create attributes * The schema used to create attributes. * @param templateFile * The template file in which this tag is used. * @param template * The template in which this tag is used. * @param arguments * @param tagArguments * The set of arguments provided for this tag. * @param lineNumber * The line number on which this tag appears in the template @@ -114,11 +109,9 @@ * @param warnings * A list into which any appropriate warning messages may be * placed. * @throws DecodeException * if a problem occurs */ public abstract void initializeForTemplate(Schema schema, TemplateFile templateFile, Template template, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException; abstract void initializeForTemplate(Schema schema, TemplateFile templateFile, Template template, String[] tagArguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException; /** * Performs any initialization for this tag that may be needed when starting @@ -127,11 +120,29 @@ * @param parentEntry * The entry below which the new entries will be generated. */ public void initializeForParent(TemplateEntry parentEntry) { void initializeForParent(TemplateEntry parentEntry) { // No implementation required by default. } /** * Check for an attribute type in a branch or in a template. * * @param attrType * The attribute type to check for. * @param branch * The branch that contains the type, or {@code null} * @param template * The template that contains the type, or {@code null} * @return true if either the branch or the template has the provided * attribute */ final boolean hasAttributeTypeInBranchOrTemplate(AttributeType attrType, Branch branch, Template template) { return (branch != null && branch.hasAttribute(attrType)) || (template != null && template.hasAttribute(attrType)); } /** * Generates the content for this tag by appending it to the provided tag. * * @param templateEntry @@ -141,242 +152,64 @@ * appended. * @return The result of generating content for this tag. */ public abstract TagResult generateValue(TemplateEntry templateEntry, TemplateValue templateValue); abstract TagResult generateValue(TemplateEntry templateEntry, TemplateValue templateValue); /** * Provides information about the result of tag processing. * Represents the result of tag generation. */ static final class TagResult { /** * A tag result in which all components have a value of * <CODE>true</CODE>. */ public static final TagResult SUCCESS_RESULT = new TagResult(true, true, true, true); /** * A tag result that indicates the value should not be included in the * entry, but all other processing should continue. */ public static final TagResult OMIT_FROM_ENTRY = new TagResult(false, true, true, true); /** * A tag result in whihc all components have a value of * <CODE>false</CODE>. */ public static final TagResult STOP_PROCESSING = new TagResult(false, false, false, false); /** Indicates whether to keep processing the associated line. */ private boolean keepProcessingLine; /** Indicates whether to keep processing the associated entry. */ private boolean keepProcessingEntry; /** * Indicates whether to keep processing entries below the associated * parent. */ private boolean keepProcessingParent; /** Indicates whether to keep processing entries for the template file. */ private boolean keepProcessingTemplateFile; /** * Creates a new tag result object with the provided information. * * @param keepProcessingLine * Indicates whether to continue processing for the current * line. If not, then the line will not be included in the * entry. * @param keepProcessingEntry * Indicates whether to continue processing for the current * entry. If not, then the entry will not be included in the * data. * @param keepProcessingParent * Indicates whether to continue processing entries below the * current parent in the template file. * @param keepProcessingTemplateFile * Indicates whether to continue processing entries for the * template file. */ private TagResult(boolean keepProcessingLine, boolean keepProcessingEntry, boolean keepProcessingParent, boolean keepProcessingTemplateFile) { this.keepProcessingLine = keepProcessingLine; this.keepProcessingEntry = keepProcessingEntry; this.keepProcessingParent = keepProcessingParent; this.keepProcessingTemplateFile = keepProcessingTemplateFile; } /** * Indicates whether to continue processing for the current line. If * this is <CODE>false</CODE>, then the current line will not be * included in the entry. It will have no impact on whehter the entry * itself is included in the generated LDIF. * * @return <CODE>true</CODE> if the line should be included in the * entry, or <CODE>false</CODE> if not. */ public boolean keepProcessingLine() { return keepProcessingLine; } /** * Indicates whether to continue processing for the current entry. If * this is <CODE>false</CODE>, then the current entry will not be * included in the generated LDIF, and processing will resume with the * next entry below the current parent. * * @return <CODE>true</CODE> if the entry should be included in the * generated LDIF, or <CODE>false</CODE> if not. */ public boolean keepProcessingEntry() { return keepProcessingEntry; } /** * Indicates whether to continue processing entries below the current * parent. If this is <CODE>false</CODE>, then the current entry will * not be included, and processing will resume below the next parent in * the template file. * * @return <CODE>true</CODE> if processing for the current parent should * continue, or <CODE>false</CODE> if not. */ public boolean keepProcessingParent() { return keepProcessingParent; } /** * Indicates whether to keep processing entries for the template file. * If this is <CODE>false</CODE>, then LDIF processing will end * immediately (and the current entry will not be included). * * @return <CODE>true</CODE> if processing for the template file should * continue, or <CODE>false</CODE> if not. */ public boolean keepProcessingTemplateFile() { return keepProcessingTemplateFile; } static enum TagResult { SUCCESS, FAILURE } /** * This class defines a tag that is used to reference the value of a * specified attribute already defined in the entry. * Tag used to reference the value of a specified attribute * already defined in the entry. */ static class AttributeValueTag extends TemplateTag { /** The attribute type that specifies which value should be used. */ private AttributeType attributeType; /** The maximum number of characters to include from the value. */ private int numCharacters; /** * Creates a new instance of this attribute value tag. */ public AttributeValueTag() { AttributeValueTag() { attributeType = null; numCharacters = 0; } /** * Retrieves the name for this tag. * * @return The name for this tag. */ public String getName() { @Override String getName() { return "AttributeValue"; } /** * Indicates whether this tag is allowed for use in the extra lines for * branches. * * @return <CODE>true</CODE> if this tag may be used in branch * definitions, or <CODE>false</CODE> if not. */ public boolean allowedInBranch() { @Override boolean allowedInBranch() { return true; } /** * Performs any initialization for this tag that may be needed while * parsing a branch definition. * * @param templateFile * The template file in which this tag is used. * @param branch * The branch in which this tag is used. * @param arguments * The set of arguments provided for this tag. * @param lineNumber * The line number on which this tag appears in the template * file. * @param warnings * A list into which any appropriate warning messages may be * placed. */ @Override public void initializeForBranch(Schema schema, TemplateFile templateFile, Branch branch, String[] arguments, void initializeForBranch(Schema schema, TemplateFile templateFile, Branch branch, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { if ((arguments.length < 1) || (arguments.length > 2)) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_INVALID_ARGUMENT_RANGE_COUNT.get(getName(), lineNumber, 1, 2, arguments.length); throw DecodeException.fatalError(message); } String lowerName = arguments[0].toLowerCase(); attributeType = schema.getAttributeType(lowerName); if (!branch.hasAttribute(attributeType)) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_UNDEFINED_ATTRIBUTE.get(arguments[0], lineNumber); throw DecodeException.fatalError(message); } if (arguments.length == 2) { try { numCharacters = Integer.parseInt(arguments[1]); if (numCharacters < 0) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_INTEGER_BELOW_LOWER_BOUND.get( numCharacters, 0, getName(), lineNumber); throw DecodeException.fatalError(message); } } catch (NumberFormatException nfe) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_CANNOT_PARSE_AS_INTEGER.get(arguments[1], getName(), lineNumber); throw DecodeException.fatalError(message); } } else { numCharacters = 0; } initialize(schema, branch, null, arguments, lineNumber); } /** * Performs any initialization for this tag that may be needed while * parsing a template definition. * * @param templateFile * The template file in which this tag is used. * @param template * The template in which this tag is used. * @param arguments * The set of arguments provided for this tag. * @param lineNumber * The line number on which this tag appears in the template * file. * @param warnings * A list into which any appropriate warning messages may be * placed. */ @Override public void initializeForTemplate(Schema schema, TemplateFile templateFile, Template template, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { void initializeForTemplate(Schema schema, TemplateFile templateFile, Template template, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { initialize(schema, null, template, arguments, lineNumber); } private void initialize(Schema schema, Branch branch, Template template, String[] arguments, int lineNumber) throws DecodeException { if ((arguments.length < 1) || (arguments.length > 2)) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_INVALID_ARGUMENT_RANGE_COUNT.get(getName(), lineNumber, 1, 2, arguments.length); throw DecodeException.fatalError(message); } String lowerName = arguments[0].toLowerCase(); attributeType = schema.getAttributeType(lowerName); if (!template.hasAttribute(attributeType)) { attributeType = schema.getAttributeType(arguments[0].toLowerCase()); if (!hasAttributeTypeInBranchOrTemplate(attributeType, branch, template)) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_UNDEFINED_ATTRIBUTE.get(arguments[0], lineNumber); throw DecodeException.fatalError(message); } @@ -399,135 +232,60 @@ } } /** * Generates the content for this tag by appending it to the provided * tag. * * @param templateEntry * The entry for which this tag is being generated. * @param templateValue * The template value to which the generated content should * be appended. * @return The result of generating content for this tag. */ public TagResult generateValue(TemplateEntry templateEntry, TemplateValue templateValue) { TemplateValue v = templateEntry.getValue(attributeType); if (v == null) { @Override TagResult generateValue(TemplateEntry templateEntry, TemplateValue templateValue) { TemplateValue value = templateEntry.getValue(attributeType); if (value == null) { // This is fine -- we just won't append anything. return TagResult.SUCCESS_RESULT; return TagResult.SUCCESS; } if (numCharacters > 0) { String valueString = v.getValueAsString(); String valueString = value.getValueAsString(); if (valueString.length() > numCharacters) { templateValue.append(valueString.substring(0, numCharacters)); } else { templateValue.append(valueString); } } else { templateValue.append(v.getValue()); templateValue.append(value.getValueAsString()); } return TagResult.SUCCESS_RESULT; return TagResult.SUCCESS; } } /** * This class defines a tag that is used to include the DN of the current * entry in the attribute value. * Tag used to include the DN of the current entry in the attribute value. */ static class DNTag extends TemplateTag { /** The number of DN components to include. */ private int numComponents; /** * Creates a new instance of this DN tag. */ public DNTag() { numComponents = 0; } /** * Retrieves the name for this tag. * * @return The name for this tag. */ public String getName() { @Override String getName() { return "DN"; } /** * Indicates whether this tag is allowed for use in the extra lines for * branches. * * @return <CODE>true</CODE> if this tag may be used in branch * definitions, or <CODE>false</CODE> if not. */ public boolean allowedInBranch() { @Override final boolean allowedInBranch() { return true; } /** * Performs any initialization for this tag that may be needed while * parsing a branch definition. * * @param templateFile * The template file in which this tag is used. * @param branch * The branch in which this tag is used. * @param arguments * The set of arguments provided for this tag. * @param lineNumber * The line number on which this tag appears in the template * file. * @param warnings * A list into which any appropriate warning messages may be * placed. */ @Override public void initializeForBranch(Schema schema, TemplateFile templateFile, Branch branch, String[] arguments, final void initializeForBranch(Schema schema, TemplateFile templateFile, Branch branch, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { initializeInternal(templateFile, arguments, lineNumber); initialize(arguments, lineNumber); } /** * Performs any initialization for this tag that may be needed while * parsing a template definition. * * @param templateFile * The template file in which this tag is used. * @param template * The template in which this tag is used. * @param arguments * The set of arguments provided for this tag. * @param lineNumber * The line number on which this tag appears in the template * file. * @param warnings * A list into which any appropriate warning messages may be * placed. */ @Override public void initializeForTemplate(Schema schema, TemplateFile templateFile, Template template, final void initializeForTemplate(Schema schema, TemplateFile templateFile, Template template, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { initializeInternal(templateFile, arguments, lineNumber); initialize(arguments, lineNumber); } /** * Performs any initialization for this tag that may be needed for this * tag. * * @param templateFile * The template file in which this tag is used. * @param arguments * The set of arguments provided for this tag. * @param lineNumber * The line number on which this tag appears in the template * file. * @throws DecodeException * If a problem occurs while initializing this tag. */ private void initializeInternal(TemplateFile templateFile, String[] arguments, int lineNumber) private void initialize(String[] arguments, int lineNumber) throws DecodeException { if (arguments.length == 0) { numComponents = 0; @@ -546,61 +304,52 @@ } } /** * Generates the content for this tag by appending it to the provided * tag. * * @param templateEntry * The entry for which this tag is being generated. * @param templateValue * The template value to which the generated content should * be appended. * @return The result of generating content for this tag. */ public TagResult generateValue(TemplateEntry templateEntry, TemplateValue templateValue) { @Override TagResult generateValue(TemplateEntry templateEntry, TemplateValue templateValue) { return generateValue(templateEntry, templateValue, ","); } final TagResult generateValue(TemplateEntry templateEntry, TemplateValue templateValue, String separator) { DN dn = templateEntry.getDN(); if ((dn == null) || dn.isRootDN()) { return TagResult.SUCCESS_RESULT; return TagResult.SUCCESS; } String dnAsString = ""; if (numComponents == 0) { templateValue.append(dn.toNormalizedString()); // Return the DN of the entry dnAsString = dn.toString(); } else if (numComponents > 0) { int count = Math.min(numComponents, dn.size()); templateValue.append(dn.rdn()); for (int i = 1; i < count; i++) { templateValue.append(","); templateValue.append(dn.parent(i).rdn()); } // Return the first numComponents RDNs of the DN dnAsString = dn.localName(numComponents).toString(); } else { int size = dn.size(); int count = Math.min(Math.abs(numComponents), size); templateValue.append(dn.parent(size - count).rdn()); for (int i = 1; i < count; i++) { templateValue.append(","); templateValue.append(dn.parent(size - count + i).rdn()); } // numComponents is negative // Return the last numComponents RDNs of the DN dnAsString = dn.parent(dn.size() - Math.abs(numComponents)).toString(); } // If expected separator is not standard separator // Then substitute expected to standard if (!separator.equals(",")) { dnAsString = dnAsString.replaceAll(",", separator); } templateValue.append(dnAsString); return TagResult.SUCCESS_RESULT; return TagResult.SUCCESS; } } /** * This class defines a tag that is used provide values from a text file. * The file should have one value per line. Access to the values may be * either at random or in sequential order. * Tag used to provide values from a text file. The file should have one * value per line. Access to the values may be either at random or in * sequential order. */ static class FileTag extends TemplateTag { /** * Indicates whether the values should be selected sequentially or at * random. */ private boolean sequential; /** The file containing the data. */ private File dataFile; private boolean isSequential = false; /** The index used for sequential access. */ private int nextIndex; @@ -608,104 +357,33 @@ /** The random number generator for this tag. */ private Random random; /** The array of lines read from the file. */ /** The lines read from the file. */ private String[] fileLines; /** * Creates a new instance of this file tag. */ public FileTag() { sequential = false; dataFile = null; nextIndex = 0; random = null; fileLines = null; } /** * Retrieves the name for this tag. * * @return The name for this tag. */ public String getName() { @Override String getName() { return "File"; } /** * Indicates whether this tag is allowed for use in the extra lines for * branches. * * @return <CODE>true</CODE> if this tag may be used in branch * definitions, or <CODE>false</CODE> if not. */ public boolean allowedInBranch() { @Override boolean allowedInBranch() { return true; } /** * Performs any initialization for this tag that may be needed while * parsing a branch definition. * * @param templateFile * The template file in which this tag is used. * @param branch * The branch in which this tag is used. * @param arguments * The set of arguments provided for this tag. * @param lineNumber * The line number on which this tag appears in the template * file. * @param warnings * A list into which any appropriate warning messages may be * placed. */ @Override public void initializeForBranch(Schema schema, TemplateFile templateFile, Branch branch, String[] arguments, void initializeForBranch(Schema schema, TemplateFile templateFile, Branch branch, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { initializeInternal(templateFile, arguments, lineNumber, warnings); initialize(templateFile, arguments, lineNumber); } /** * Performs any initialization for this tag that may be needed while * parsing a template definition. * * @param templateFile * The template file in which this tag is used. * @param template * The template in which this tag is used. * @param arguments * The set of arguments provided for this tag. * @param lineNumber * The line number on which this tag appears in the template * file. * @param warnings * A list into which any appropriate warning messages may be * placed. */ @Override public void initializeForTemplate(Schema schema, TemplateFile templateFile, Template template, void initializeForTemplate(Schema schema, TemplateFile templateFile, Template template, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { initializeInternal(templateFile, arguments, lineNumber, warnings); initialize(templateFile, arguments, lineNumber); } /** * Performs any initialization for this tag that may be needed. * * @param templateFile * The template file in which this tag is used. * @param arguments * The set of arguments provided for this tag. * @param lineNumber * The line number on which this tag appears in the template * file. * @param warnings * A list into which any appropriate warning messages may be * placed. * @throws DecodeException * If a problem occurs while initializing this tag. */ private void initializeInternal(TemplateFile templateFile, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { private void initialize(TemplateFile templateFile, String[] arguments, int lineNumber) throws DecodeException { random = templateFile.getRandom(); // There must be at least one argument, and possibly two. @@ -716,11 +394,27 @@ } // The first argument should be the path to the file. dataFile = templateFile.getFile(arguments[0]); if ((dataFile == null) || (!dataFile.exists())) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_CANNOT_FIND_FILE.get(arguments[0], getName(), lineNumber); throw DecodeException.fatalError(message); final String filePath = arguments[0]; BufferedReader dataReader = null; try { dataReader = templateFile.getReader(filePath); if (dataReader == null) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_CANNOT_FIND_FILE.get(filePath, getName(), lineNumber); throw DecodeException.fatalError(message); } // See if the file has already been read into memory. If not, then // read it. try { fileLines = templateFile.getLines(filePath, dataReader); } catch (IOException ioe) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_CANNOT_READ_FILE.get(filePath, getName(), lineNumber, String.valueOf(ioe)); throw DecodeException.fatalError(message, ioe); } } finally { StaticUtils.closeSilently(dataReader); } // If there is a second argument, then it should be either @@ -728,43 +422,23 @@ // assume "random". if (arguments.length == 2) { if (arguments[1].equalsIgnoreCase("sequential")) { sequential = true; isSequential = true; nextIndex = 0; } else if (arguments[1].equalsIgnoreCase("random")) { sequential = false; isSequential = false; } else { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_INVALID_FILE_ACCESS_MODE.get(arguments[1], getName(), lineNumber); throw DecodeException.fatalError(message); } } else { sequential = false; } // See if the file has already been read into memory. If not, then // read it. try { fileLines = templateFile.getFileLines(dataFile); } catch (IOException ioe) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_CANNOT_READ_FILE.get(arguments[0], getName(), lineNumber, String.valueOf(ioe)); throw DecodeException.fatalError(message, ioe); isSequential = false; } } /** * Generates the content for this tag by appending it to the provided * tag. * * @param templateEntry * The entry for which this tag is being generated. * @param templateValue * The template value to which the generated content should * be appended. * @return The result of generating content for this tag. */ public TagResult generateValue(TemplateEntry templateEntry, TemplateValue templateValue) { if (sequential) { @Override TagResult generateValue(TemplateEntry templateEntry, TemplateValue templateValue) { if (isSequential) { templateValue.append(fileLines[nextIndex++]); if (nextIndex >= fileLines.length) { nextIndex = 0; @@ -773,170 +447,55 @@ templateValue.append(fileLines[random.nextInt(fileLines.length)]); } return TagResult.SUCCESS_RESULT; return TagResult.SUCCESS; } } /** * This class defines a tag that is used to include a first name in the * attribute value. * Tag used to include a first name in the attribute value. */ static class FirstNameTag extends TemplateTag { /** The template file with which this tag is associated. */ private TemplateFile templateFile; /** * Creates a new instance of this first name tag. */ public FirstNameTag() { // No implementation required. } /** * Retrieves the name for this tag. * * @return The name for this tag. */ public String getName() { static class FirstNameTag extends NameTag { @Override String getName() { return "First"; } /** * Indicates whether this tag is allowed for use in the extra lines for * branches. * * @return <CODE>true</CODE> if this tag may be used in branch * definitions, or <CODE>false</CODE> if not. */ public boolean allowedInBranch() { return false; } /** * Performs any initialization for this tag that may be needed while * parsing a template definition. * * @param templateFile * The template file in which this tag is used. * @param template * The template in which this tag is used. * @param arguments * The set of arguments provided for this tag. * @param lineNumber * The line number on which this tag appears in the template * file. * @param warnings * A list into which any appropriate warning messages may be * placed. */ @Override public void initializeForTemplate(Schema schema, TemplateFile templateFile, Template template, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { this.templateFile = templateFile; if (arguments.length != 0) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_INVALID_ARGUMENT_COUNT.get(getName(), lineNumber, 0, arguments.length); throw DecodeException.fatalError(message); } } /** * Generates the content for this tag by appending it to the provided * tag. * * @param templateEntry * The entry for which this tag is being generated. * @param templateValue * The template value to which the generated content should * be appended. * @return The result of generating content for this tag. */ public TagResult generateValue(TemplateEntry templateEntry, TemplateValue templateValue) { TagResult generateValue(TemplateEntry templateEntry, TemplateValue templateValue) { templateValue.append(templateFile.getFirstName()); return TagResult.SUCCESS_RESULT; return TagResult.SUCCESS; } } /** * This class defines a tag that is used to include a GUID in the attribute * value. * Tag used to include a GUID in the attribute value. */ static class GUIDTag extends TemplateTag { /** * Creates a new instance of this GUID tag. */ public GUIDTag() { // No implementation required. } /** * Retrieves the name for this tag. * * @return The name for this tag. */ public String getName() { @Override String getName() { return "GUID"; } /** * Indicates whether this tag is allowed for use in the extra lines for * branches. * * @return <CODE>true</CODE> if this tag may be used in branch * definitions, or <CODE>false</CODE> if not. */ public boolean allowedInBranch() { @Override boolean allowedInBranch() { return true; } /** * Performs any initialization for this tag that may be needed while * parsing a branch definition. * * @param templateFile * The template file in which this tag is used. * @param branch * The branch in which this tag is used. * @param arguments * The set of arguments provided for this tag. * @param lineNumber * The line number on which this tag appears in the template * file. * @param warnings * A list into which any appropriate warning messages may be * placed. */ @Override public void initializeForBranch(Schema schema, TemplateFile templateFile, Branch branch, String[] arguments, void initializeForBranch(Schema schema, TemplateFile templateFile, Branch branch, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { if (arguments.length != 0) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_INVALID_ARGUMENT_COUNT.get(getName(), lineNumber, 0, arguments.length); throw DecodeException.fatalError(message); } initialize(arguments, lineNumber); } /** * Performs any initialization for this tag that may be needed while * parsing a template definition. * * @param templateFile * The template file in which this tag is used. * @param template * The template in which this tag is used. * @param arguments * The set of arguments provided for this tag. * @param lineNumber * The line number on which this tag appears in the template * file. * @param warnings * A list into which any appropriate warning messages may be * placed. */ @Override public void initializeForTemplate(Schema schema, TemplateFile templateFile, Template template, void initializeForTemplate(Schema schema, TemplateFile templateFile, Template template, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { initialize(arguments, lineNumber); } private void initialize(String[] arguments, int lineNumber) throws DecodeException { if (arguments.length != 0) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_INVALID_ARGUMENT_COUNT.get(getName(), lineNumber, 0, arguments.length); @@ -944,408 +503,140 @@ } } /** * Generates the content for this tag by appending it to the provided * tag. * * @param templateEntry * The entry for which this tag is being generated. * @param templateValue * The template value to which the generated content should * be appended. * @return The result of generating content for this tag. */ public TagResult generateValue(TemplateEntry templateEntry, TemplateValue templateValue) { @Override TagResult generateValue(TemplateEntry templateEntry, TemplateValue templateValue) { templateValue.append(UUID.randomUUID().toString()); return TagResult.SUCCESS_RESULT; return TagResult.SUCCESS; } } /** * This class defines a tag that is used to base presence of one attribute * on the absence of another attribute and/or attribute value. * Base tag to use to base presence of one attribute on the absence/presence * of another attribute and/or attribute value. */ static class IfAbsentTag extends TemplateTag { abstract static class IfTag extends TemplateTag { /** The attribute type for which to make the determination. */ private AttributeType attributeType; AttributeType attributeType; /** The value for which to make the determination. */ private String assertionValue; String assertionValue; /** * Creates a new instance of this ifabsent tag. */ public IfAbsentTag() { attributeType = null; assertionValue = null; @Override final boolean allowedInBranch() { return true; } /** * Retrieves the name for this tag. * * @return The name for this tag. */ public String getName() { @Override final void initializeForBranch(Schema schema, TemplateFile templateFile, Branch branch, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { initialize(schema, branch, null, arguments, lineNumber); } @Override final void initializeForTemplate(Schema schema, TemplateFile templateFile, Template template, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { initialize(schema, null, template, arguments, lineNumber); } private void initialize(Schema schema, Branch branch, Template template, String[] arguments, int lineNumber) throws DecodeException { if ((arguments.length < 1) || (arguments.length > 2)) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_INVALID_ARGUMENT_RANGE_COUNT.get(getName(), lineNumber, 1, 2, arguments.length); throw DecodeException.fatalError(message); } attributeType = schema.getAttributeType(arguments[0].toLowerCase()); if (!hasAttributeTypeInBranchOrTemplate(attributeType, branch, template)) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_UNDEFINED_ATTRIBUTE.get(arguments[0], lineNumber); throw DecodeException.fatalError(message); } if (arguments.length == 2) { assertionValue = arguments[1]; } else { assertionValue = null; } } } /** * Tag used to base presence of one attribute on the absence of another * attribute and/or attribute value. */ static class IfAbsentTag extends IfTag { @Override String getName() { return "IfAbsent"; } /** * Indicates whether this tag is allowed for use in the extra lines for * branches. * * @return <CODE>true</CODE> if this tag may be used in branch * definitions, or <CODE>false</CODE> if not. */ public boolean allowedInBranch() { return true; } /** * Performs any initialization for this tag that may be needed while * parsing a branch definition. * * @param templateFile * The template file in which this tag is used. * @param branch * The branch in which this tag is used. * @param arguments * The set of arguments provided for this tag. * @param lineNumber * The line number on which this tag appears in the template * file. * @param warnings * A list into which any appropriate warning messages may be * placed. */ @Override public void initializeForBranch(Schema schema, TemplateFile templateFile, Branch branch, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { if ((arguments.length < 1) || (arguments.length > 2)) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_INVALID_ARGUMENT_RANGE_COUNT.get(getName(), lineNumber, 1, 2, arguments.length); throw DecodeException.fatalError(message); } String lowerName = arguments[0].toLowerCase(); AttributeType t = schema.getAttributeType(lowerName); if (!branch.hasAttribute(t)) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_UNDEFINED_ATTRIBUTE.get(arguments[0], lineNumber); throw DecodeException.fatalError(message); } if (arguments.length == 2) { assertionValue = arguments[1]; } else { assertionValue = null; } } /** * Performs any initialization for this tag that may be needed while * parsing a template definition. * * @param templateFile * The template file in which this tag is used. * @param template * The template in which this tag is used. * @param arguments * The set of arguments provided for this tag. * @param lineNumber * The line number on which this tag appears in the template * file. * @param warnings * A list into which any appropriate warning messages may be * placed. */ @Override public void initializeForTemplate(Schema schema, TemplateFile templateFile, Template template, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { if ((arguments.length < 1) || (arguments.length > 2)) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_INVALID_ARGUMENT_RANGE_COUNT.get(getName(), lineNumber, 1, 2, arguments.length); throw DecodeException.fatalError(message); } String lowerName = arguments[0].toLowerCase(); attributeType = schema.getAttributeType(lowerName); if (!template.hasAttribute(attributeType)) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_UNDEFINED_ATTRIBUTE.get(arguments[0], lineNumber); throw DecodeException.fatalError(message); } if (arguments.length == 2) { assertionValue = arguments[1]; } else { assertionValue = null; } } /** * Generates the content for this tag by appending it to the provided * tag. * * @param templateEntry * The entry for which this tag is being generated. * @param templateValue * The template value to which the generated content should * be appended. * @return The result of generating content for this tag. */ public TagResult generateValue(TemplateEntry templateEntry, TemplateValue templateValue) { TagResult generateValue(TemplateEntry templateEntry, TemplateValue templateValue) { List<TemplateValue> values = templateEntry.getValues(attributeType); if ((values == null) || values.isEmpty()) { return TagResult.SUCCESS_RESULT; if (values == null) { return TagResult.SUCCESS; } if (assertionValue == null) { return TagResult.OMIT_FROM_ENTRY; } else { for (TemplateValue v : values) { if (assertionValue.equals(v.getValueAsString())) { return TagResult.OMIT_FROM_ENTRY; } } return TagResult.SUCCESS_RESULT; return TagResult.FAILURE; } for (TemplateValue v : values) { if (assertionValue.equals(v.getValueAsString())) { return TagResult.FAILURE; } } return TagResult.SUCCESS; } } /** * This class defines a tag that is used to base presence of one attribute * on the presence of another attribute and/or attribute value. * Tag used to base presence of one attribute on the presence of another * attribute and/or attribute value. */ static class IfPresentTag extends TemplateTag { /** The attribute type for which to make the determination. */ private AttributeType attributeType; /** The value for which to make the determination. */ private String assertionValue; /** * Creates a new instance of this ifpresent tag. */ public IfPresentTag() { attributeType = null; assertionValue = null; } /** * Retrieves the name for this tag. * * @return The name for this tag. */ public String getName() { static class IfPresentTag extends IfTag { @Override String getName() { return "IfPresent"; } /** * Indicates whether this tag is allowed for use in the extra lines for * branches. * * @return <CODE>true</CODE> if this tag may be used in branch * definitions, or <CODE>false</CODE> if not. */ public boolean allowedInBranch() { return true; } /** * Performs any initialization for this tag that may be needed while * parsing a branch definition. * * @param templateFile * The template file in which this tag is used. * @param branch * The branch in which this tag is used. * @param arguments * The set of arguments provided for this tag. * @param lineNumber * The line number on which this tag appears in the template * file. * @param warnings * A list into which any appropriate warning messages may be * placed. */ @Override public void initializeForBranch(Schema schema, TemplateFile templateFile, Branch branch, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { if ((arguments.length < 1) || (arguments.length > 2)) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_INVALID_ARGUMENT_RANGE_COUNT.get(getName(), lineNumber, 1, 2, arguments.length); throw DecodeException.fatalError(message); } String lowerName = arguments[0].toLowerCase(); AttributeType t = schema.getAttributeType(lowerName); if (!branch.hasAttribute(t)) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_UNDEFINED_ATTRIBUTE.get(arguments[0], lineNumber); throw DecodeException.fatalError(message); } if (arguments.length == 2) { assertionValue = arguments[1]; } else { assertionValue = null; } } /** * Performs any initialization for this tag that may be needed while * parsing a template definition. * * @param templateFile * The template file in which this tag is used. * @param template * The template in which this tag is used. * @param arguments * The set of arguments provided for this tag. * @param lineNumber * The line number on which this tag appears in the template * file. * @param warnings * A list into which any appropriate warning messages may be * placed. */ @Override public void initializeForTemplate(Schema schema, TemplateFile templateFile, Template template, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { if ((arguments.length < 1) || (arguments.length > 2)) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_INVALID_ARGUMENT_RANGE_COUNT.get(getName(), lineNumber, 1, 2, arguments.length); throw DecodeException.fatalError(message); } String lowerName = arguments[0].toLowerCase(); attributeType = schema.getAttributeType(lowerName); if (!template.hasAttribute(attributeType)) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_UNDEFINED_ATTRIBUTE.get(arguments[0], lineNumber); throw DecodeException.fatalError(message); } if (arguments.length == 2) { assertionValue = arguments[1]; } else { assertionValue = null; } } /** * Generates the content for this tag by appending it to the provided * tag. * * @param templateEntry * The entry for which this tag is being generated. * @param templateValue * The template value to which the generated content should * be appended. * @return The result of generating content for this tag. */ public TagResult generateValue(TemplateEntry templateEntry, TemplateValue templateValue) { TagResult generateValue(TemplateEntry templateEntry, TemplateValue templateValue) { List<TemplateValue> values = templateEntry.getValues(attributeType); if ((values == null) || values.isEmpty()) { return TagResult.OMIT_FROM_ENTRY; return TagResult.FAILURE; } if (assertionValue == null) { return TagResult.SUCCESS_RESULT; } else { for (TemplateValue v : values) { if (assertionValue.equals(v.getValueAsString())) { return TagResult.SUCCESS_RESULT; } } return TagResult.OMIT_FROM_ENTRY; return TagResult.SUCCESS; } for (TemplateValue v : values) { if (assertionValue.equals(v.getValueAsString())) { return TagResult.SUCCESS; } } return TagResult.FAILURE; } } /** * This class defines a tag that is used to include a last name in the * attribute value. * Tag used to include a last name in the attribute value. */ static class LastNameTag extends TemplateTag { /** The template file with which this tag is associated. */ private TemplateFile templateFile; /** * Creates a new instance of this last name tag. */ public LastNameTag() { // No implementation required. } /** * Retrieves the name for this tag. * * @return The name for this tag. */ public String getName() { static class LastNameTag extends NameTag { @Override String getName() { return "Last"; } /** * Indicates whether this tag is allowed for use in the extra lines for * branches. * * @return <CODE>true</CODE> if this tag may be used in branch * definitions, or <CODE>false</CODE> if not. */ public boolean allowedInBranch() { return false; } /** * Performs any initialization for this tag that may be needed while * parsing a template definition. * * @param templateFile * The template file in which this tag is used. * @param template * The template in which this tag is used. * @param arguments * The set of arguments provided for this tag. * @param lineNumber * The line number on which this tag appears in the template * file. * @param warnings * A list into which any appropriate warning messages may be * placed. */ @Override public void initializeForTemplate(Schema schema, TemplateFile templateFile, Template template, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { this.templateFile = templateFile; if (arguments.length != 0) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_INVALID_ARGUMENT_COUNT.get(getName(), lineNumber, 0, arguments.length); throw DecodeException.fatalError(message); } } /** * Generates the content for this tag by appending it to the provided * tag. * * @param templateEntry * The entry for which this tag is being generated. * @param templateValue * The template value to which the generated content should * be appended. * @return The result of generating content for this tag. */ public TagResult generateValue(TemplateEntry templateEntry, TemplateValue templateValue) { TagResult generateValue(TemplateEntry templateEntry, TemplateValue templateValue) { templateValue.append(templateFile.getLastName()); return TagResult.SUCCESS_RESULT; return TagResult.SUCCESS; } } /** * This class defines a tag that may be used to select a value from a * pre-defined list, optionally defining weights for each value that can * impact the likelihood of a given item being selected. * Tag used to select a value from a pre-defined list, optionally defining * weights for each value that can impact the likelihood of a given item * being selected. * <p> * The items to include in the list should be specified as arguments to the * tag. If the argument ends with a semicolon followed by an integer, then @@ -1365,139 +656,58 @@ /** The random number generator for this tag. */ private Random random; /** * Creates a new instance of this list tag. */ public ListTag() { // No implementation required. } /** * Retrieves the name for this tag. * * @return The name for this tag. */ public String getName() { @Override String getName() { return "List"; } /** * Indicates whether this tag is allowed for use in the extra lines for * branches. * * @return <CODE>true</CODE> if this tag may be used in branch * definitions, or <CODE>false</CODE> if not. */ public boolean allowedInBranch() { @Override boolean allowedInBranch() { return true; } /** * Performs any initialization for this tag that may be needed while * parsing a branch definition. * * @param templateFile * The template file in which this tag is used. * @param branch * The branch in which this tag is used. * @param arguments * The set of arguments provided for this tag. * @param lineNumber * The line number on which this tag appears in the template * file. * @param warnings * A list into which any appropriate warning messages may be * placed. */ @Override public void initializeForBranch(Schema schema, TemplateFile templateFile, Branch branch, String[] arguments, void initializeForBranch(Schema schema, TemplateFile templateFile, Branch branch, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { initializeInternal(templateFile, arguments, lineNumber, warnings); initialize(templateFile, arguments, lineNumber, warnings); } /** * Performs any initialization for this tag that may be needed while * parsing a template definition. * * @param templateFile * The template file in which this tag is used. * @param template * The template in which this tag is used. * @param arguments * The set of arguments provided for this tag. * @param lineNumber * The line number on which this tag appears in the template * file. * @param warnings * A list into which any appropriate warning messages may be * placed. */ @Override public void initializeForTemplate(Schema schema, TemplateFile templateFile, Template template, void initializeForTemplate(Schema schema, TemplateFile templateFile, Template template, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { initializeInternal(templateFile, arguments, lineNumber, warnings); initialize(templateFile, arguments, lineNumber, warnings); } /** * Performs any initialization for this tag that may be needed for this * tag. * * @param templateFile * The template file in which this tag is used. * @param arguments * The set of arguments provided for this tag. * @param lineNumber * The line number on which this tag appears in the template * file. * @param warnings * A list into which any appropriate warning messages may be * placed. * @throws DecodeException * If a problem occurs while initializing this tag. */ private void initializeInternal(TemplateFile templateFile, String[] arguments, int lineNumber, private void initialize(TemplateFile templateFile, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { if (arguments.length == 0) { throw DecodeException.fatalError(ERR_ENTRY_GENERATOR_TAG_LIST_NO_ARGUMENTS.get(lineNumber)); } valueStrings = new String[arguments.length]; valueWeights = new int[arguments.length]; cumulativeWeight = 0; random = templateFile.getRandom(); for (int i = 0; i < arguments.length; i++) { String s = arguments[i]; String value = arguments[i]; int weight = 1; int semicolonPos = s.lastIndexOf(';'); int semicolonPos = value.lastIndexOf(';'); if (semicolonPos >= 0) { try { weight = Integer.parseInt(s.substring(semicolonPos + 1)); s = s.substring(0, semicolonPos); } catch (Exception e) { warnings.add(WARN_ENTRY_GENERATOR_TAG_LIST_INVALID_WEIGHT.get(lineNumber, s)); weight = Integer.parseInt(value.substring(semicolonPos + 1)); value = value.substring(0, semicolonPos); } catch (NumberFormatException e) { warnings.add(WARN_ENTRY_GENERATOR_TAG_LIST_INVALID_WEIGHT.get(lineNumber, value)); } } cumulativeWeight += weight; valueStrings[i] = s; valueStrings[i] = value; valueWeights[i] = cumulativeWeight; } } /** * Generates the content for this tag by appending it to the provided * tag. * * @param templateEntry * The entry for which this tag is being generated. * @param templateValue * The template value to which the generated content should * be appended. * @return The result of generating content for this tag. */ public TagResult generateValue(TemplateEntry templateEntry, TemplateValue templateValue) { @Override TagResult generateValue(TemplateEntry templateEntry, TemplateValue templateValue) { int selectedWeight = random.nextInt(cumulativeWeight) + 1; for (int i = 0; i < valueWeights.length; i++) { if (selectedWeight <= valueWeights[i]) { @@ -1505,62 +715,48 @@ break; } } return TagResult.SUCCESS_RESULT; return TagResult.SUCCESS; } } /** * This class defines a tag that is used to include the DN of the parent * entry in the attribute value. * Base tag to use to include a first name or last name in the attribute * value. */ static class ParentDNTag extends TemplateTag { /** * Creates a new instance of this parent DN tag. */ public ParentDNTag() { // No implementation required. } static abstract class NameTag extends TemplateTag { /** The template file with which this tag is associated. */ TemplateFile templateFile; /** * Retrieves the name for this tag. * * @return The name for this tag. */ public String getName() { return "ParentDN"; } /** * Indicates whether this tag is allowed for use in the extra lines for * branches. * * @return <CODE>true</CODE> if this tag may be used in branch * definitions, or <CODE>false</CODE> if not. */ public boolean allowedInBranch() { @Override final boolean allowedInBranch() { return false; } /** * Performs any initialization for this tag that may be needed while * parsing a template definition. * * @param templateFile * The template file in which this tag is used. * @param template * The template in which this tag is used. * @param arguments * The set of arguments provided for this tag. * @param lineNumber * The line number on which this tag appears in the template * file. * @param warnings * A list into which any appropriate warning messages may be * placed. */ @Override public void initializeForTemplate(Schema schema, TemplateFile templateFile, Template template, final void initializeForTemplate(Schema schema, TemplateFile templateFile, Template template, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { this.templateFile = templateFile; if (arguments.length != 0) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_INVALID_ARGUMENT_COUNT.get(getName(), lineNumber, 0, arguments.length); throw DecodeException.fatalError(message); } } } /** * Base tag to use to include the DN of the parent entry in the attribute value. */ static abstract class ParentTag extends TemplateTag { @Override final boolean allowedInBranch() { return false; } @Override final void initializeForTemplate(Schema schema, TemplateFile templateFile, Template template, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { if (arguments.length != 0) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_INVALID_ARGUMENT_COUNT.get(getName(), lineNumber, @@ -1568,129 +764,66 @@ throw DecodeException.fatalError(message); } } } /** * Generates the content for this tag by appending it to the provided * tag. * * @param templateEntry * The entry for which this tag is being generated. * @param templateValue * The template value to which the generated content should * be appended. * @return The result of generating content for this tag. */ public TagResult generateValue(TemplateEntry templateEntry, TemplateValue templateValue) { /** * Tag used to include the DN of the parent entry in the attribute value. */ static class ParentDNTag extends ParentTag { @Override String getName() { return "ParentDN"; } @Override TagResult generateValue(TemplateEntry templateEntry, TemplateValue templateValue) { DN parentDN = templateEntry.getParentDN(); if ((parentDN == null) || parentDN.isRootDN()) { return TagResult.SUCCESS_RESULT; return TagResult.SUCCESS; } templateValue.append(parentDN); return TagResult.SUCCESS_RESULT; return TagResult.SUCCESS; } } /** * This class defines a tag that is used to indicate that a value should * only be included in a percentage of the entries. * Tag used to indicate that a value should only be included in a percentage * of the entries. */ static class PresenceTag extends TemplateTag { /** The percentage of the entries in which this attribute value should */ /** appear. */ /** * The percentage of the entries in which this attribute value should * appear. */ private int percentage; /** The random number generator for this tag. */ private Random random; /** * Creates a new instance of this presence tag. */ public PresenceTag() { percentage = 100; } /** * Retrieves the name for this tag. * * @return The name for this tag. */ public String getName() { @Override String getName() { return "Presence"; } /** * Indicates whether this tag is allowed for use in the extra lines for * branches. * * @return <CODE>true</CODE> if this tag may be used in branch * definitions, or <CODE>false</CODE> if not. */ public boolean allowedInBranch() { @Override boolean allowedInBranch() { return true; } /** * Performs any initialization for this tag that may be needed while * parsing a branch definition. * * @param templateFile * The template file in which this tag is used. * @param branch * The branch in which this tag is used. * @param arguments * The set of arguments provided for this tag. * @param lineNumber * The line number on which this tag appears in the template * file. * @param warnings * A list into which any appropriate warning messages may be * placed. */ @Override public void initializeForBranch(Schema schema, TemplateFile templateFile, Branch branch, String[] arguments, void initializeForBranch(Schema schema, TemplateFile templateFile, Branch branch, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { initializeInternal(templateFile, arguments, lineNumber); initialize(templateFile, arguments, lineNumber); } /** * Performs any initialization for this tag that may be needed while * parsing a template definition. * * @param templateFile * The template file in which this tag is used. * @param template * The template in which this tag is used. * @param arguments * The set of arguments provided for this tag. * @param lineNumber * The line number on which this tag appears in the template * file. * @param warnings * A list into which any appropriate warning messages may be * placed. */ @Override public void initializeForTemplate(Schema schema, TemplateFile templateFile, Template template, void initializeForTemplate(Schema schema, TemplateFile templateFile, Template template, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { initializeInternal(templateFile, arguments, lineNumber); initialize(templateFile, arguments, lineNumber); } /** * Performs any initialization for this tag that may be needed for this * tag. * * @param templateFile * The template file in which this tag is used. * @param arguments * The set of arguments provided for this tag. * @param lineNumber * The line number on which this tag appears in the template * file. * @throws DecodeException * If a problem occurs while initializing this tag. */ private void initializeInternal(TemplateFile templateFile, String[] arguments, int lineNumber) private void initialize(TemplateFile templateFile, String[] arguments, int lineNumber) throws DecodeException { random = templateFile.getRandom(); @@ -1702,14 +835,14 @@ try { percentage = Integer.parseInt(arguments[0]); if (percentage < 0) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_INTEGER_BELOW_LOWER_BOUND.get(percentage, 0, getName(), lineNumber); LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_INTEGER_BELOW_LOWER_BOUND.get(percentage, 0, getName(), lineNumber); throw DecodeException.fatalError(message); } else if (percentage > 100) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_INTEGER_ABOVE_UPPER_BOUND.get(percentage, 100, getName(), lineNumber); } if (percentage > 100) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_INTEGER_ABOVE_UPPER_BOUND.get(percentage, 100, getName(), lineNumber); throw DecodeException.fatalError(message); } } catch (NumberFormatException nfe) { @@ -1719,31 +852,20 @@ } } /** * Generates the content for this tag by appending it to the provided * tag. * * @param templateEntry * The entry for which this tag is being generated. * @param templateValue * The template value to which the generated content should * be appended. * @return The result of generating content for this tag. */ public TagResult generateValue(TemplateEntry templateEntry, TemplateValue templateValue) { @Override TagResult generateValue(TemplateEntry templateEntry, TemplateValue templateValue) { int intValue = random.nextInt(100); if (intValue < percentage) { return TagResult.SUCCESS_RESULT; return TagResult.SUCCESS; } else { return TagResult.OMIT_FROM_ENTRY; return TagResult.FAILURE; } } } /** * This class defines a tag that may be used to generate random values. It * has a number of subtypes based on the type of information that should be * generated, including: * Tag used to generate random values. It has a number of subtypes based on * the type of information that should be generated, including: * <UL> * <LI>alpha:length</LI> * <LI>alpha:minlength:maxlength</LI> @@ -1764,32 +886,31 @@ * </UL> */ static class RandomTag extends TemplateTag { /** * The value that indicates that the value is to be generated from a * fixed number of characters from a given character set. */ public static final int RANDOM_TYPE_CHARS_FIXED = 1; /** * The value that indicates that the value is to be generated from a * variable number of characters from a given character set. */ public static final int RANDOM_TYPE_CHARS_VARIABLE = 2; /** * The value that indicates that the value should be a random number. */ public static final int RANDOM_TYPE_NUMERIC = 3; /** * The value that indicates that the value should be a random month. */ public static final int RANDOM_TYPE_MONTH = 4; /** * The value that indicates that the value should be a telephone number. */ public static final int RANDOM_TYPE_TELEPHONE = 5; static enum RandomType { /** * Generates values from a fixed number of characters from a given * character set. */ CHARS_FIXED, /** * Generates values from a variable number of characters from a given * character set. */ CHARS_VARIABLE, /** * Generates numbers. */ NUMERIC, /** * Generates months (as text). */ MONTH, /** * Generates telephone numbers. */ TELEPHONE } /** * The character set that will be used for alphabetic characters. @@ -1831,7 +952,7 @@ /** The number of characters between the minimum and maximum length */ /** (inclusive). */ private int lengthRange; private int lengthRange = 1; /** The maximum number of characters to include in the value. */ private int maxLength; @@ -1840,7 +961,7 @@ private int minLength; /** The type of random value that should be generated. */ private int randomType; private RandomType randomType; /** The maximum numeric value that should be generated. */ private long maxValue; @@ -1852,110 +973,34 @@ * The number of values between the minimum and maximum value * (inclusive). */ private long valueRange; private long valueRange = 1L; /** The random number generator for this tag. */ private Random random; /** * Creates a new instance of this random tag. */ public RandomTag() { characterSet = null; decimalFormat = null; lengthRange = 1; maxLength = 0; minLength = 0; randomType = 0; maxValue = 0L; minValue = 0L; valueRange = 1L; } /** * Retrieves the name for this tag. * * @return The name for this tag. */ public String getName() { @Override String getName() { return "Random"; } /** * Indicates whether this tag is allowed for use in the extra lines for * branches. * * @return <CODE>true</CODE> if this tag may be used in branch * definitions, or <CODE>false</CODE> if not. */ public boolean allowedInBranch() { @Override boolean allowedInBranch() { return true; } /** * Performs any initialization for this tag that may be needed while * parsing a branch definition. * * @param templateFile * The template file in which this tag is used. * @param branch * The branch in which this tag is used. * @param arguments * The set of arguments provided for this tag. * @param lineNumber * The line number on which this tag appears in the template * file. * @param warnings * A list into which any appropriate warning messages may be * placed. */ @Override public void initializeForBranch(Schema schema, TemplateFile templateFile, Branch branch, String[] arguments, void initializeForBranch(Schema schema, TemplateFile templateFile, Branch branch, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { initializeInternal(templateFile, arguments, lineNumber, warnings); initialize(templateFile, arguments, lineNumber, warnings); } /** * Performs any initialization for this tag that may be needed while * parsing a template definition. * * @param templateFile * The template file in which this tag is used. * @param template * The template in which this tag is used. * @param arguments * The set of arguments provided for this tag. * @param lineNumber * The line number on which this tag appears in the template * file. * @param warnings * A list into which any appropriate warning messages may be * placed. */ @Override public void initializeForTemplate(Schema schema, TemplateFile templateFile, Template template, void initializeForTemplate(Schema schema, TemplateFile templateFile, Template template, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { initializeInternal(templateFile, arguments, lineNumber, warnings); initialize(templateFile, arguments, lineNumber, warnings); } /** * Performs any initialization for this tag that may be needed while * parsing either a branch or template definition. * * @param templateFile * The template file in which this tag is used. * @param arguments * The set of arguments provided for this tag. * @param lineNumber * The line number on which this tag appears in the template * file. * @param warnings * A list into which any appropriate warning messages may be * placed. * @throws DecodeException * If a problem occurs while initializing this tag. */ private void initializeInternal(TemplateFile templateFile, String[] arguments, int lineNumber, private void initialize(TemplateFile templateFile, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { random = templateFile.getRandom(); @@ -1974,7 +1019,7 @@ decodeLength(arguments, 1, lineNumber, warnings); } else if (randomTypeString.equals("numeric")) { if (numArgs == 2) { randomType = RANDOM_TYPE_CHARS_FIXED; randomType = RandomType.CHARS_FIXED; characterSet = NUMERIC_CHARS; try { @@ -1994,7 +1039,7 @@ throw DecodeException.fatalError(message, nfe); } } else if ((numArgs == 3) || (numArgs == 4)) { randomType = RANDOM_TYPE_NUMERIC; randomType = RandomType.NUMERIC; if (numArgs == 4) { try { @@ -2054,7 +1099,7 @@ characterSet = BASE64_CHARS; decodeLength(arguments, 1, lineNumber, warnings); } else if (randomTypeString.equals("month")) { randomType = RANDOM_TYPE_MONTH; randomType = RandomType.MONTH; if (numArgs == 1) { maxLength = 0; @@ -2077,7 +1122,7 @@ throw DecodeException.fatalError(message); } } else if (randomTypeString.equals("telephone")) { randomType = RANDOM_TYPE_TELEPHONE; randomType = RandomType.TELEPHONE; } else { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_UNKNOWN_RANDOM_TYPE.get(lineNumber, randomTypeString); @@ -2108,7 +1153,7 @@ if (numArgs == 2) { // There is a fixed number of characters in the value. randomType = RANDOM_TYPE_CHARS_FIXED; randomType = RandomType.CHARS_FIXED; try { minLength = Integer.parseInt(arguments[startPos]); @@ -2128,7 +1173,7 @@ } } else if (numArgs == 3) { // There are minimum and maximum lengths. randomType = RANDOM_TYPE_CHARS_VARIABLE; randomType = RandomType.CHARS_VARIABLE; try { minLength = Integer.parseInt(arguments[startPos]); @@ -2168,33 +1213,23 @@ } } /** * Generates the content for this tag by appending it to the provided * tag. * * @param templateEntry * The entry for which this tag is being generated. * @param templateValue * The template value to which the generated content should * be appended. * @return The result of generating content for this tag. */ public TagResult generateValue(TemplateEntry templateEntry, TemplateValue templateValue) { @Override TagResult generateValue(TemplateEntry templateEntry, TemplateValue templateValue) { switch (randomType) { case RANDOM_TYPE_CHARS_FIXED: case CHARS_FIXED: for (int i = 0; i < minLength; i++) { templateValue.append(characterSet[random.nextInt(characterSet.length)]); } break; case RANDOM_TYPE_CHARS_VARIABLE: case CHARS_VARIABLE: int numChars = random.nextInt(lengthRange) + minLength; for (int i = 0; i < numChars; i++) { templateValue.append(characterSet[random.nextInt(characterSet.length)]); } break; case RANDOM_TYPE_NUMERIC: case NUMERIC: long randomValue = ((random.nextLong() & 0x7FFFFFFFFFFFFFFFL) % valueRange) + minValue; if (decimalFormat == null) { templateValue.append(randomValue); @@ -2203,7 +1238,7 @@ } break; case RANDOM_TYPE_MONTH: case MONTH: String month = MONTHS[random.nextInt(MONTHS.length)]; if ((maxLength == 0) || (month.length() <= maxLength)) { templateValue.append(month); @@ -2212,7 +1247,7 @@ } break; case RANDOM_TYPE_TELEPHONE: case TELEPHONE: templateValue.append("+1 "); for (int i = 0; i < 3; i++) { templateValue.append(NUMERIC_CHARS[random.nextInt(NUMERIC_CHARS.length)]); @@ -2228,89 +1263,38 @@ break; } return TagResult.SUCCESS_RESULT; return TagResult.SUCCESS; } } /** * This class defines a tag that is used to include the RDN of the current * entry in the attribute value. * Tag used to include the RDN of the current entry in the attribute value. */ static class RDNTag extends TemplateTag { /** * Creates a new instance of this RDN tag. */ public RDNTag() { // No implementation required. } /** * Retrieves the name for this tag. * * @return The name for this tag. */ public String getName() { @Override String getName() { return "RDN"; } /** * Indicates whether this tag is allowed for use in the extra lines for * branches. * * @return <CODE>true</CODE> if this tag may be used in branch * definitions, or <CODE>false</CODE> if not. */ public boolean allowedInBranch() { @Override boolean allowedInBranch() { return true; } /** * Performs any initialization for this tag that may be needed while * parsing a branch definition. * * @param templateFile * The template file in which this tag is used. * @param branch * The branch in which this tag is used. * @param arguments * The set of arguments provided for this tag. * @param lineNumber * The line number on which this tag appears in the template * file. * @param warnings * A list into which any appropriate warning messages may be * placed. */ @Override public void initializeForBranch(Schema schema, TemplateFile templateFile, Branch branch, String[] arguments, void initializeForBranch(Schema schema, TemplateFile templateFile, Branch branch, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { if (arguments.length != 0) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_INVALID_ARGUMENT_COUNT.get(getName(), lineNumber, 0, arguments.length); throw DecodeException.fatalError(message); } initialize(arguments, lineNumber); } /** * Performs any initialization for this tag that may be needed while * parsing a template definition. * * @param templateFile * The template file in which this tag is used. * @param template * The template in which this tag is used. * @param arguments * The set of arguments provided for this tag. * @param lineNumber * The line number on which this tag appears in the template * file. * @param warnings * A list into which any appropriate warning messages may be * placed. */ @Override public void initializeForTemplate(Schema schema, TemplateFile templateFile, Template template, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { void initializeForTemplate(Schema schema, TemplateFile templateFile, Template template, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { initialize(arguments, lineNumber); } private void initialize(String[] arguments, int lineNumber) throws DecodeException { if (arguments.length != 0) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_INVALID_ARGUMENT_COUNT.get(getName(), lineNumber, 0, arguments.length); @@ -2318,35 +1302,25 @@ } } /** * Generates the content for this tag by appending it to the provided * tag. * * @param templateEntry * The entry for which this tag is being generated. * @param templateValue * The template value to which the generated content should * be appended. * @return The result of generating content for this tag. */ public TagResult generateValue(TemplateEntry templateEntry, TemplateValue templateValue) { @Override TagResult generateValue(TemplateEntry templateEntry, TemplateValue templateValue) { DN dn = templateEntry.getDN(); if ((dn == null) || dn.isRootDN()) { return TagResult.SUCCESS_RESULT; return TagResult.SUCCESS; } else { templateValue.append(dn.rdn()); return TagResult.SUCCESS_RESULT; return TagResult.SUCCESS; } } } /** * This class defines a tag that is used to include a * sequentially-incrementing integer in the generated values. * Tag that is used to include a sequentially-incrementing integer in the * generated values. */ static class SequentialTag extends TemplateTag { /** Indicates whether to reset for each parent. */ private boolean resetOnNewParents; private boolean resetOnNewParents = true; /** The initial value in the sequence. */ private int initialValue; @@ -2354,515 +1328,156 @@ /** The next value in the sequence. */ private int nextValue; /** * Creates a new instance of this sequential tag. */ public SequentialTag() { // No implementation required. } /** * Retrieves the name for this tag. * * @return The name for this tag. */ public String getName() { @Override String getName() { return "Sequential"; } /** * Indicates whether this tag is allowed for use in the extra lines for * branches. * * @return <CODE>true</CODE> if this tag may be used in branch * definitions, or <CODE>false</CODE> if not. */ public boolean allowedInBranch() { @Override boolean allowedInBranch() { return true; } /** * Performs any initialization for this tag that may be needed while * parsing a branch definition. * * @param templateFile * The template file in which this tag is used. * @param branch * The branch in which this tag is used. * @param arguments * The set of arguments provided for this tag. * @param lineNumber * The line number on which this tag appears in the template * file. * @param warnings * A list into which any appropriate warning messages may be * placed. */ @Override public void initializeForBranch(Schema schema, TemplateFile templateFile, Branch branch, String[] arguments, void initializeForBranch(Schema schema, TemplateFile templateFile, Branch branch, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { initializeInternal(templateFile, arguments, lineNumber); initialize(arguments, lineNumber); } /** * Performs any initialization for this tag that may be needed while * parsing a template definition. * * @param templateFile * The template file in which this tag is used. * @param template * The template in which this tag is used. * @param arguments * The set of arguments provided for this tag. * @param lineNumber * The line number on which this tag appears in the template * file. * @param warnings * A list into which any appropriate warning messages may be * placed. */ @Override public void initializeForTemplate(Schema schema, TemplateFile templateFile, Template template, void initializeForTemplate(Schema schema, TemplateFile templateFile, Template template, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { initializeInternal(templateFile, arguments, lineNumber); initialize(arguments, lineNumber); } /** * Performs any initialization for this tag that may be needed for this * tag. * * @param templateFile * The template file in which this tag is used. * @param arguments * The set of arguments provided for this tag. * @param lineNumber * The line number on which this tag appears in the template * file. * @throws DecodeException * If a problem occurs while initializing this tag. */ private void initializeInternal(TemplateFile templateFile, String[] arguments, int lineNumber) throws DecodeException { switch (arguments.length) { case 0: initialValue = 0; nextValue = 0; resetOnNewParents = true; break; case 1: try { initialValue = Integer.parseInt(arguments[0]); } catch (NumberFormatException nfe) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_CANNOT_PARSE_AS_INTEGER.get(arguments[0], getName(), lineNumber); throw DecodeException.fatalError(message); private void initialize(String[] arguments, int lineNumber) throws DecodeException { if (arguments.length < 0 || arguments.length > 2) { throw DecodeException.fatalError(ERR_ENTRY_GENERATOR_TAG_INVALID_ARGUMENT_RANGE_COUNT.get( getName(), lineNumber, 0, 2, arguments.length)); } if (arguments.length > 0) { initializeValue(arguments[0], lineNumber); if (arguments.length > 1) { initializeReset(arguments[1], lineNumber); } nextValue = initialValue; resetOnNewParents = true; break; case 2: try { initialValue = Integer.parseInt(arguments[0]); } catch (NumberFormatException nfe) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_CANNOT_PARSE_AS_INTEGER.get(arguments[0], getName(), lineNumber); throw DecodeException.fatalError(message); } if (arguments[1].equalsIgnoreCase("true")) { resetOnNewParents = true; } else if (arguments[1].equalsIgnoreCase("false")) { resetOnNewParents = false; } else { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_CANNOT_PARSE_AS_BOOLEAN.get(arguments[1], getName(), lineNumber); throw DecodeException.fatalError(message); } nextValue = initialValue; break; default: LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_INVALID_ARGUMENT_RANGE_COUNT.get(getName(), lineNumber, 0, 2, arguments.length); throw DecodeException.fatalError(message); } } /** * Performs any initialization for this tag that may be needed when * starting to generate entries below a new parent. * * @param parentEntry * The entry below which the new entries will be generated. */ public void initializeForParent(TemplateEntry parentEntry) { private void initializeReset(String resetValue, int lineNumber) throws DecodeException { if (resetValue.equalsIgnoreCase("true")) { resetOnNewParents = true; } else if (resetValue.equalsIgnoreCase("false")) { resetOnNewParents = false; } else { throw DecodeException.fatalError(ERR_ENTRY_GENERATOR_TAG_CANNOT_PARSE_AS_BOOLEAN.get( resetValue, getName(), lineNumber)); } } private void initializeValue(String value, int lineNumber) throws DecodeException { try { initialValue = Integer.parseInt(value); } catch (NumberFormatException nfe) { throw DecodeException.fatalError(ERR_ENTRY_GENERATOR_TAG_CANNOT_PARSE_AS_INTEGER.get( value, getName(), lineNumber)); } nextValue = initialValue; } @Override void initializeForParent(TemplateEntry parentEntry) { if (resetOnNewParents) { nextValue = initialValue; } } /** * Generates the content for this tag by appending it to the provided * tag. * * @param templateEntry * The entry for which this tag is being generated. * @param templateValue * The template value to which the generated content should * be appended. * @return The result of generating content for this tag. */ public TagResult generateValue(TemplateEntry templateEntry, TemplateValue templateValue) { @Override TagResult generateValue(TemplateEntry templateEntry, TemplateValue templateValue) { templateValue.append(nextValue++); return TagResult.SUCCESS_RESULT; return TagResult.SUCCESS; } } /** * This class defines a tag that is used to hold static text (i.e., text * that appears outside of any tag). * Tag that is used to hold static text (i.e., text that appears outside of * any tag). */ static class StaticTextTag extends TemplateTag { /** The static text to include in the LDIF. */ private String text; /** The static text to include. */ private String text = ""; /** * Creates a new instance of this static text tag. */ public StaticTextTag() { text = ""; } /** * Retrieves the name for this tag. * * @return The name for this tag. */ public String getName() { @Override String getName() { return "StaticText"; } /** * Indicates whether this tag is allowed for use in the extra lines for * branches. * * @return <CODE>true</CODE> if this tag may be used in branch * definitions, or <CODE>false</CODE> if not. */ public boolean allowedInBranch() { @Override boolean allowedInBranch() { return true; } /** * Performs any initialization for this tag that may be needed while * parsing a branch definition. * * @param templateFile * The template file in which this tag is used. * @param branch * The branch in which this tag is used. * @param arguments * The set of arguments provided for this tag. * @param lineNumber * The line number on which this tag appears in the template * file. * @param warnings * A list into which any appropriate warning messages may be * placed. */ @Override public void initializeForBranch(Schema schema, TemplateFile templateFile, Branch branch, String[] arguments, void initializeForBranch(Schema schema, TemplateFile templateFile, Branch branch, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { if (arguments.length != 1) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_INVALID_ARGUMENT_COUNT.get(getName(), lineNumber, 1, arguments.length); throw DecodeException.fatalError(message); } text = arguments[0]; initialize(arguments, lineNumber); } /** * Performs any initialization for this tag that may be needed while * parsing a template definition. * * @param templateFile * The template file in which this tag is used. * @param template * The template in which this tag is used. * @param arguments * The set of arguments provided for this tag. * @param lineNumber * The line number on which this tag appears in the template * file. * @param warnings * A list into which any appropriate warning messages may be * placed. */ @Override public void initializeForTemplate(Schema schema, TemplateFile templateFile, Template template, void initializeForTemplate(Schema schema, TemplateFile templateFile, Template template, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { initialize(arguments, lineNumber); } private void initialize(String[] arguments, int lineNumber) throws DecodeException { if (arguments.length != 1) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_INVALID_ARGUMENT_COUNT.get(getName(), lineNumber, 1, arguments.length); throw DecodeException.fatalError(message); } text = arguments[0]; } /** * Generates the content for this tag by appending it to the provided * tag. * * @param templateEntry * The entry for which this tag is being generated. * @param templateValue * The template value to which the generated content should * be appended. * @return The result of generating content for this tag. */ public TagResult generateValue(TemplateEntry templateEntry, TemplateValue templateValue) { @Override TagResult generateValue(TemplateEntry templateEntry, TemplateValue templateValue) { templateValue.append(text); return TagResult.SUCCESS_RESULT; return TagResult.SUCCESS; } } /** * This class defines a tag that is used to include the DN of the current * entry in the attribute value, with underscores in place of the commas. * Tag used to include the DN of the current entry in the attribute value, * with underscores in place of the commas. */ static class UnderscoreDNTag extends TemplateTag { /** The number of DN components to include. */ private int numComponents; static class UnderscoreDNTag extends DNTag { /** * Creates a new instance of this DN tag. */ public UnderscoreDNTag() { numComponents = 0; } /** * Retrieves the name for this tag. * * @return The name for this tag. */ public String getName() { @Override String getName() { return "_DN"; } /** * Indicates whether this tag is allowed for use in the extra lines for * branches. * * @return <CODE>true</CODE> if this tag may be used in branch * definitions, or <CODE>false</CODE> if not. */ public boolean allowedInBranch() { return true; } /** * Performs any initialization for this tag that may be needed while * parsing a branch definition. * * @param templateFile * The template file in which this tag is used. * @param branch * The branch in which this tag is used. * @param arguments * The set of arguments provided for this tag. * @param lineNumber * The line number on which this tag appears in the template * file. * @param warnings * A list into which any appropriate warning messages may be * placed. */ @Override public void initializeForBranch(Schema schema, TemplateFile templateFile, Branch branch, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { initializeInternal(templateFile, arguments, lineNumber); } /** * Performs any initialization for this tag that may be needed while * parsing a template definition. * * @param templateFile * The template file in which this tag is used. * @param template * The template in which this tag is used. * @param arguments * The set of arguments provided for this tag. * @param lineNumber * The line number on which this tag appears in the template * file. * @param warnings * A list into which any appropriate warning messages may be * placed. */ @Override public void initializeForTemplate(Schema schema, TemplateFile templateFile, Template template, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { initializeInternal(templateFile, arguments, lineNumber); } /** * Performs any initialization for this tag that may be needed for this * tag. * * @param templateFile * The template file in which this tag is used. * @param arguments * The set of arguments provided for this tag. * @param lineNumber * The line number on which this tag appears in the template * file. * @throws DecodeException * TODO */ private void initializeInternal(TemplateFile templateFile, String[] arguments, int lineNumber) throws DecodeException { if (arguments.length == 0) { numComponents = 0; } else if (arguments.length == 1) { try { numComponents = Integer.parseInt(arguments[0]); } catch (NumberFormatException nfe) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_CANNOT_PARSE_AS_INTEGER.get(arguments[0], getName(), lineNumber); throw DecodeException.fatalError(message); } } else { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_INVALID_ARGUMENT_RANGE_COUNT.get(getName(), lineNumber, 0, 1, arguments.length); throw DecodeException.fatalError(message); } } /** * Generates the content for this tag by appending it to the provided * tag. * * @param templateEntry * The entry for which this tag is being generated. * @param templateValue * The template value to which the generated content should * be appended. * @return The result of generating content for this tag. */ public TagResult generateValue(TemplateEntry templateEntry, TemplateValue templateValue) { DN dn = templateEntry.getDN(); if ((dn == null) || dn.isRootDN()) { return TagResult.SUCCESS_RESULT; } if (numComponents == 0) { templateValue.append(dn.rdn()); for (int i = 1; i < dn.size(); i++) { templateValue.append("_"); templateValue.append(dn.parent(i).rdn()); } } else if (numComponents > 0) { int count = Math.min(numComponents, dn.size()); templateValue.append(dn.rdn()); for (int i = 1; i < count; i++) { templateValue.append(","); templateValue.append(dn.parent(i).rdn()); } } else { int size = dn.size(); int count = Math.min(Math.abs(numComponents), size); templateValue.append(dn.parent(size - count).rdn()); for (int i = 1; i < count; i++) { templateValue.append(","); templateValue.append(dn.parent(size - count + i).rdn()); } } return TagResult.SUCCESS_RESULT; TagResult generateValue(TemplateEntry templateEntry, TemplateValue templateValue) { return generateValue(templateEntry, templateValue, "_"); } } /** * This class defines a tag that is used to include the DN of the parent * entry in the attribute value, with underscores in place of commas. * Tag used to include the DN of the parent entry in the attribute value, * with underscores in place of commas. */ static class UnderscoreParentDNTag extends TemplateTag { /** * Creates a new instance of this underscore parent DN tag. */ public UnderscoreParentDNTag() { // No implementation required. } static class UnderscoreParentDNTag extends ParentTag { /** * Retrieves the name for this tag. * * @return The name for this tag. */ public String getName() { @Override String getName() { return "_ParentDN"; } /** * Indicates whether this tag is allowed for use in the extra lines for * branches. * * @return <CODE>true</CODE> if this tag may be used in branch * definitions, or <CODE>false</CODE> if not. */ public boolean allowedInBranch() { return false; } /** * Performs any initialization for this tag that may be needed while * parsing a template definition. * * @param templateFile * The template file in which this tag is used. * @param template * The template in which this tag is used. * @param arguments * The set of arguments provided for this tag. * @param lineNumber * The line number on which this tag appears in the template * file. * @param warnings * A list into which any appropriate warning messages may be * placed. */ @Override public void initializeForTemplate(Schema schema, TemplateFile templateFile, Template template, String[] arguments, int lineNumber, List<LocalizableMessage> warnings) throws DecodeException { if (arguments.length != 0) { LocalizableMessage message = ERR_ENTRY_GENERATOR_TAG_INVALID_ARGUMENT_COUNT.get(getName(), lineNumber, 0, arguments.length); throw DecodeException.fatalError(message); } } /** * Generates the content for this tag by appending it to the provided * tag. * * @param templateEntry * The entry for which this tag is being generated. * @param templateValue * The template value to which the generated content should * be appended. * @return The result of generating content for this tag. */ public TagResult generateValue(TemplateEntry templateEntry, TemplateValue templateValue) { TagResult generateValue(TemplateEntry templateEntry, TemplateValue templateValue) { DN parentDN = templateEntry.getParentDN(); if ((parentDN == null) || parentDN.isRootDN()) { return TagResult.SUCCESS_RESULT; return TagResult.SUCCESS; } templateValue.append(parentDN.rdn()); for (int i = 1; i < parentDN.size(); i++) { @@ -2870,7 +1485,7 @@ templateValue.append(parentDN.parent(i).rdn()); } return TagResult.SUCCESS_RESULT; return TagResult.SUCCESS; } } } opendj3/opendj-core/src/main/resources/com/forgerock/opendj/ldap/core.properties
@@ -1434,9 +1434,6 @@ ERR_ENTRY_GENERATOR_TAG_CANNOT_PARSE_AS_BOOLEAN=Cannot parse value "%s" as \ a Boolean value for tag %s on line %d of the template file. The value must \ be either 'true' or 'false' ERR_ENTRY_GENERATOR_UNDEFINED_BRANCH_SUBORDINATE=The branch with entry DN \ '%s' references a subordinate template named '%s' which is not defined in the \ template file ERR_ENTRY_GENERATOR_CANNOT_LOAD_TAG_CLASS=Unable to load class %s for use \ as a MakeLDIF tag ERR_ENTRY_GENERATOR_CANNOT_INSTANTIATE_TAG=Cannot instantiate class %s as a \ @@ -1450,9 +1447,6 @@ %d is missing an equal sign to delimit the constant name from the value ERR_ENTRY_GENERATOR_DEFINE_NAME_EMPTY=The constant definition on line %d \ does not include a name for the constant ERR_ENTRY_GENERATOR_CONFLICTING_CONSTANT_NAME=The definition for constant \ %s on line %d conflicts with an earlier constant definition included in the \ template ERR_ENTRY_GENERATOR_WARNING_DEFINE_VALUE_EMPTY=Constant %s defined on line \ %d has not been assigned a value ERR_ENTRY_GENERATOR_CONFLICTING_BRANCH_DN=The branch definition %s starting \ @@ -1468,18 +1462,21 @@ template file ERR_ENTRY_GENERATOR_CANNOT_DECODE_BRANCH_DN=Unable to decode branch DN "%s" \ on line %d of the template file ERR_ENTRY_GENERATOR_BRANCH_SUBORDINATE_TEMPLATE_NO_COLON=Subordinate \ template definition on line %d for branch %s is missing a colon to separate \ ERR_ENTRY_GENERATOR_UNDEFINED_BRANCH_SUBORDINATE=The branch with entry DN \ '%s' references a subordinate template named '%s' which is not defined in the \ template file ERR_ENTRY_GENERATOR_SUBORDINATE_TEMPLATE_NO_COLON=Subordinate \ template definition on line %d for %s %s is missing a colon to separate \ the template name from the number of entries ERR_ENTRY_GENERATOR_BRANCH_SUBORDINATE_INVALID_NUM_ENTRIES=Subordinate \ template definition on line %d for branch %s specified invalid number of \ ERR_ENTRY_GENERATOR_SUBORDINATE_INVALID_NUM_ENTRIES=Subordinate \ template definition on line %d for %s %s specified invalid number of \ entries %d for template %s WARN_ENTRY_GENERATOR_BRANCH_SUBORDINATE_ZERO_ENTRIES=Subordinate template \ definition on line %d for branch %s specifies that zero entries of type %s \ WARN_ENTRY_GENERATOR_SUBORDINATE_ZERO_ENTRIES=Subordinate template \ definition on line %d for %s %s specifies that zero entries of type %s \ should be generated ERR_ENTRY_GENERATOR_BRANCH_SUBORDINATE_CANT_PARSE_NUMENTRIES=Unable to \ ERR_ENTRY_GENERATOR_SUBORDINATE_CANT_PARSE_NUMENTRIES=Unable to \ parse the number of entries for template %s as an integer for the subordinate \ template definition on line %d for branch %s template definition on line %d for %s %s ERR_ENTRY_GENERATOR_TEMPLATE_SUBORDINATE_TEMPLATE_NO_COLON=Subordinate \ template definition on line %d for template %s is missing a colon to separate \ the template name from the number of entries @@ -1494,22 +1491,14 @@ template definition on line %d for template %s ERR_ENTRY_GENERATOR_TEMPLATE_MISSING_RDN_ATTR=The template named %s \ includes RDN attribute %s that is not assigned a value in that template ERR_ENTRY_GENERATOR_NO_COLON_IN_BRANCH_EXTRA_LINE=There is no colon to \ separate the attribute name from the value pattern on line %d of the template \ file in the definition for branch %s ERR_ENTRY_GENERATOR_NO_ATTR_IN_BRANCH_EXTRA_LINE=There is no attribute name \ before the colon on line %d of the template file in the definition for branch \ %s WARN_ENTRY_GENERATOR_NO_VALUE_IN_BRANCH_EXTRA_LINE=The value pattern for \ line %d of the template file in the definition for branch %s is empty ERR_ENTRY_GENERATOR_NO_COLON_IN_TEMPLATE_LINE=There is no colon to separate \ the attribute name from the value pattern on line %d of the template file in \ the definition for template %s the definition for %s %s ERR_ENTRY_GENERATOR_NO_ATTR_IN_TEMPLATE_LINE=There is no attribute name \ before the colon on line %d of the template file in the definition for \ template %s template %s %s WARN_ENTRY_GENERATOR_NO_VALUE_IN_TEMPLATE_LINE=The value pattern for line \ %d of the template file in the definition for template %s is empty %d of the template file in the definition for %s %s is empty ERR_ENTRY_GENERATOR_NO_SUCH_TAG=An undefined tag %s is referenced on line \ %d of the template file ERR_ENTRY_GENERATOR_CANNOT_INSTANTIATE_NEW_TAG=An unexpected error occurred \ @@ -1526,6 +1515,8 @@ the template file references an unknown random type of %s ERR_ENTRY_GENERATOR_COULD_NOT_FIND_TEMPLATE_FILE=Could not find template \ file %s ERR_ENTRY_GENERATOR_COULD_NOT_FIND_NAME_FILE=Could not find names resource \ file %s ERR_ENTRY_GENERATOR_TAG_CANNOT_FIND_FILE=Cannot find file %s referenced by \ tag %s on line %d of the template file ERR_ENTRY_GENERATOR_TAG_INVALID_FILE_ACCESS_MODE=Invalid file access mode \ opendj3/opendj-core/src/main/resources/org/forgerock/opendj/ldif/example.template
@@ -3,8 +3,12 @@ define numusers=10000 branch: [suffix] objectClass: top objectClass: domainComponent branch: ou=People,[suffix] objectClass: top objectClass: organizationalUnit subordinateTemplate: person:[numusers] template: person opendj3/opendj-core/src/main/resources/org/forgerock/opendj/ldif/people_and_groups.template
New file @@ -0,0 +1,62 @@ define suffix=dc=example,dc=com define maildomain=example.com define numusers=10 define numous=10 define numgroup=5 branch: [suffix] subordinateTemplate: ous:[numous] template: ous subordinateTemplate: People:1 subordinateTemplate: Groups:1 rdnAttr: ou objectclass: top objectclass: organizationalUnit ou: Organization_<sequential:1> description: This is {ou} template: People rdnAttr: ou subordinateTemplate: person:[numusers] objectclass: top objectclass: organizationalUnit ou: People template: Groups subordinateTemplate: groupOfName:[numgroup] rdnAttr: ou objectclass: top objectclass: organizationalUnit ou: Groups template: person rdnAttr: uid objectClass: top objectClass: person objectClass: organizationalPerson objectClass: inetOrgPerson givenName: <first> sn: <last> cn: {givenName} {sn} initials: {givenName:1}<random:chars:ABCDEFGHIJKLMNOPQRSTUVWXYZ:1>{sn:1} employeeNumber: <sequential:0> uid: user.{employeeNumber} mail: {uid}@[maildomain] userPassword: password telephoneNumber: <random:telephone> homePhone: <random:telephone> pager: <random:telephone> mobile: <random:telephone> street: <random:numeric:5> <file:streets> Street l: <file:cities> st: <file:states> postalCode: <random:numeric:5> postalAddress: {cn}${street}${l}, {st} {postalCode} description: This is the description for {cn}. template: groupOfName rdnAttr: cn objectClass: top objectClass: groupOfNames cn: Group_<sequential:1> opendj3/opendj-core/src/test/java/org/forgerock/opendj/ldap/RDNTestCase.java
@@ -32,8 +32,8 @@ import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; import java.util.Arrays; import java.util.Iterator; import org.forgerock.i18n.LocalizedIllegalArgumentException; import org.forgerock.opendj.ldap.schema.AttributeType; import org.forgerock.opendj.ldap.schema.Schema; @@ -48,19 +48,19 @@ public final class RDNTestCase extends TypesTestCase { // Domain component attribute type. private static final AttributeType AT_DC; private static final AttributeType ATTR_TYPE_DC; // Common name attribute type. private static final AttributeType AT_CN; private static final AttributeType ATTR_TYPE_CN; // Test attribute value. private static final AVA AV_DC_ORG; private static final AVA ATTR_VALUE_DC_ORG; static { AT_DC = Schema.getCoreSchema().getAttributeType("dc"); AT_CN = Schema.getCoreSchema().getAttributeType("cn"); ATTR_TYPE_DC = Schema.getCoreSchema().getAttributeType("dc"); ATTR_TYPE_CN = Schema.getCoreSchema().getAttributeType("cn"); // Set the avas. AV_DC_ORG = new AVA(AT_DC, ByteString.valueOf("org")); ATTR_VALUE_DC_ORG = new AVA(ATTR_TYPE_DC, ByteString.valueOf("org")); } // org bytestring. @@ -211,13 +211,13 @@ */ @Test public void testConstructor() throws Exception { final RDN rdn = new RDN(AT_DC, ORG); final RDN rdn = new RDN(ATTR_TYPE_DC, ORG); assertEquals(rdn.size(), 1); assertEquals(rdn.isMultiValued(), false); assertEquals(rdn.getFirstAVA().getAttributeType(), AT_DC); assertEquals(rdn.getFirstAVA().getAttributeType().getNameOrOID(), AT_DC.getNameOrOID()); assertEquals(rdn.getFirstAVA(), AV_DC_ORG); assertEquals(rdn.getFirstAVA().getAttributeType(), ATTR_TYPE_DC); assertEquals(rdn.getFirstAVA().getAttributeType().getNameOrOID(), ATTR_TYPE_DC.getNameOrOID()); assertEquals(rdn.getFirstAVA(), ATTR_VALUE_DC_ORG); } /** @@ -230,9 +230,51 @@ public void testConstructorWithString() throws Exception { final RDN rdn = new RDN("dc", "org"); assertEquals(rdn.size(), 1); assertEquals(rdn.getFirstAVA().getAttributeType(), AT_DC); assertEquals(rdn.getFirstAVA().getAttributeType(), ATTR_TYPE_DC); assertEquals(rdn.getFirstAVA().getAttributeType().getNameOrOID(), "dc"); assertEquals(rdn.getFirstAVA(), AV_DC_ORG); assertEquals(rdn.getFirstAVA(), ATTR_VALUE_DC_ORG); } @Test public void testConstructorWithAVA() throws Exception { final RDN rdn = new RDN(new AVA("dc", "org")); assertEquals(rdn.size(), 1); assertEquals(rdn.getFirstAVA().getAttributeType(), ATTR_TYPE_DC); assertEquals(rdn.getFirstAVA(), ATTR_VALUE_DC_ORG); } @Test public void testConstructorWithMultipleAVAs() throws Exception { AVA example = new AVA("dc", "example"); AVA org = new AVA("dc", "org"); final RDN rdn = new RDN(example, org); assertEquals(rdn.size(), 2); Iterator<AVA> rdnIt = rdn.iterator(); AVA firstAva = rdnIt.next(); assertEquals(firstAva.getAttributeType(), ATTR_TYPE_DC); assertEquals(firstAva, example); AVA secondAva = rdnIt.next(); assertEquals(secondAva.getAttributeType(), ATTR_TYPE_DC); assertEquals(secondAva, org); } @Test public void testConstructorWithCollectionOfAVAs() throws Exception { AVA example = new AVA("dc", "example"); AVA org = new AVA("dc", "org"); final RDN rdn = new RDN(Arrays.asList(example, org)); assertEquals(rdn.size(), 2); Iterator<AVA> rdnIt = rdn.iterator(); AVA firstAva = rdnIt.next(); assertEquals(firstAva.getAttributeType(), ATTR_TYPE_DC); assertEquals(firstAva, example); AVA secondAva = rdnIt.next(); assertEquals(secondAva.getAttributeType(), ATTR_TYPE_DC); assertEquals(secondAva, org); } /** @@ -298,7 +340,7 @@ */ @Test public void testDuplicateSingle() { final RDN rdn1 = new RDN(AT_DC, ORG); final RDN rdn1 = new RDN(ATTR_TYPE_DC, ORG); final RDN rdn2 = RDN.valueOf("dc=org"); assertFalse(rdn1 == rdn2); @@ -338,7 +380,7 @@ */ @Test public void testEqualityNonRDN() { final RDN rdn = new RDN(AT_DC, ORG); final RDN rdn = new RDN(ATTR_TYPE_DC, ORG); assertFalse(rdn.equals("this isn't an RDN")); } @@ -351,7 +393,7 @@ */ @Test public void testEqualityNull() { final RDN rdn = new RDN(AT_DC, ORG); final RDN rdn = new RDN(ATTR_TYPE_DC, ORG); assertFalse(rdn.equals(null)); } @@ -368,8 +410,8 @@ assertTrue(rdn.isMultiValued()); assertEquals(rdn.size(), 2); final Iterator<AVA> it = rdn.iterator(); assertEquals(it.next().getAttributeType().getNameOrOID(), AT_DC.getNameOrOID()); assertEquals(it.next().getAttributeType().getNameOrOID(), AT_CN.getNameOrOID()); assertEquals(it.next().getAttributeType().getNameOrOID(), ATTR_TYPE_DC.getNameOrOID()); assertEquals(it.next().getAttributeType().getNameOrOID(), ATTR_TYPE_CN.getNameOrOID()); } /** opendj3/opendj-core/src/test/java/org/forgerock/opendj/ldif/EntryGeneratorTestCase.java
@@ -29,16 +29,18 @@ import static org.fest.assertions.Assertions.*; import static org.forgerock.opendj.ldap.TestCaseUtils.getTestFilePath; import static org.forgerock.opendj.ldif.EntryGenerator.*; import static org.forgerock.opendj.ldap.schema.CoreSchema.*; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.forgerock.i18n.LocalizableMessage; import org.forgerock.opendj.ldap.Attribute; import org.forgerock.opendj.ldap.ByteString; import org.forgerock.opendj.ldap.DecodeException; import org.forgerock.opendj.ldap.Entry; import org.forgerock.opendj.ldap.SdkTestCase; @@ -47,10 +49,13 @@ import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import com.forgerock.opendj.util.StaticUtils; @SuppressWarnings("javadoc") public class EntryGeneratorTestCase extends SdkTestCase { private static final String TEMPLATE_FILE_PATH = "org/forgerock/opendj/ldif/example.template"; private static final String BASIC_TEMPLATE_PATH = "org/forgerock/opendj/ldif/example.template"; private static final String SUBTEMPLATES_TEMPLATE_PATH = "org/forgerock/opendj/ldif/people_and_groups.template"; private String resourcePath; private Schema schema; @@ -58,40 +63,92 @@ public void setUp() throws Exception { // path of directory in src/main/resources must be obtained from a file // otherwise it may search in the wrong directory resourcePath = new File(getTestFilePath(TEMPLATE_FILE_PATH)).getParent(); resourcePath = new File(getTestFilePath(BASIC_TEMPLATE_PATH)).getParent(); schema = Schema.getDefaultSchema(); } @Test public void testReaderWithTemplateFile() throws Exception { String templatePath = getTestFilePath(TEMPLATE_FILE_PATH); EntryGenerator reader = newReader(templatePath).setResourcePath(resourcePath).build(); /** * This test is a facility to print generated entries to stdout and should * always be disabled. * Turn it on locally if you need to see the output. */ @Test(enabled = false) public void printEntriesToStdOut() throws Exception { String path = SUBTEMPLATES_TEMPLATE_PATH; EntryGenerator generator = null; try { generator = new EntryGenerator(getTestFilePath(path)).setResourcePath(resourcePath); while (generator.hasNext()) { System.out.println(generator.readEntry()); } } finally { StaticUtils.closeSilently(generator); } checkReader(reader, 10000); reader.close(); } @Test public void testReaderWithTemplateStream() throws Exception { public void testCreateWithDefaultTemplateFile() throws Exception { EntryGenerator generator = null; try { generator = new EntryGenerator(); assertThat(generator.hasNext()).isTrue(); } finally { StaticUtils.closeSilently(generator); } } @Test(expectedExceptions = DecodeException.class, expectedExceptionsMessageRegExp = ".*Could not find template file unknown.*") public void testCreateWithMissingTemplateFile() throws Exception { EntryGenerator generator = null; try { generator = new EntryGenerator("unknown/path"); generator.hasNext(); } finally { StaticUtils.closeSilently(generator); } } @Test public void testCreateWithSetConstants() throws Exception { EntryGenerator generator = null; try { generator = new EntryGenerator().setConstant("numusers", 1); generator.readEntry(); generator.readEntry(); assertThat(generator.readEntry().getName().toString()).isEqualTo("uid=user.0,ou=People,dc=example,dc=com"); assertThat(generator.hasNext()).as("should have no more entries").isFalse(); } finally { StaticUtils.closeSilently(generator); } } @DataProvider(name = "generators") public Object[][] createGenerators() throws Exception { Object[][] generators = new Object[3][2]; String templatePath = getTestFilePath(BASIC_TEMPLATE_PATH); generators[0][0] = new EntryGenerator(templatePath).setResourcePath(resourcePath); generators[0][1] = 10000; InputStream stream = new FileInputStream( new File(getTestFilePath(TEMPLATE_FILE_PATH))); EntryGenerator reader = newReader(stream).setResourcePath(resourcePath).build(); new File(templatePath)); generators[1][0] = new EntryGenerator(stream).setResourcePath(resourcePath); generators[1][1] = 10000; checkReader(reader, 10000); reader.close(); } @Test public void testReaderWithTemplateLines() throws Exception { EntryGenerator reader = newReader( generators[2][0] = new EntryGenerator( "define suffix=dc=example,dc=com", "define maildomain=example.com", "define numusers=2", "", "branch: [suffix]", "objectClass: top", "objectClass: domainComponent", "", "branch: ou=People,[suffix]", "objectClass: top", "objectClass: organizationalUnit", "subordinateTemplate: person:[numusers]", "", "template: person", @@ -118,41 +175,196 @@ "postalCode: <random:numeric:5>", "postalAddress: {cn}${street}${l}, {st} {postalCode}", "description: This is the description for {cn}.") .setResourcePath(resourcePath).build(); .setResourcePath(resourcePath); generators[2][1] = 2; checkReader(reader, 2); reader.close(); return generators; } /** * Check the content of the reader for basic case. * Test the generated DNs. * * Expecting 2 entries and then numberOfUsers entries. */ private void checkReader(EntryGenerator reader, int numberOfUsers) throws Exception { assertThat(reader.hasNext()).isTrue(); assertThat(reader.readEntry().getName().toString()).isEqualTo("dc=example,dc=com"); assertThat(reader.hasNext()).isTrue(); assertThat(reader.readEntry().getName().toString()).isEqualTo("ou=People,dc=example,dc=com"); for (int i = 0; i < numberOfUsers; i++) { assertThat(reader.hasNext()).isTrue(); assertThat(reader.readEntry().getName().toString()). isEqualTo("uid=user." + i + ",ou=People,dc=example,dc=com"); @Test(dataProvider = "generators") public void testGeneratedDNs(EntryGenerator generator, int numberOfUsers) throws Exception { try { assertThat(generator.hasNext()).isTrue(); assertThat(generator.readEntry().getName().toString()).isEqualTo("dc=example,dc=com"); assertThat(generator.hasNext()).isTrue(); assertThat(generator.readEntry().getName().toString()).isEqualTo("ou=People,dc=example,dc=com"); for (int i = 0; i < numberOfUsers; i++) { assertThat(generator.hasNext()).isTrue(); assertThat(generator.readEntry().getName().toString()). isEqualTo("uid=user." + i + ",ou=People,dc=example,dc=com"); } assertThat(generator.hasNext()).as("should have no more entries").isFalse(); } finally { StaticUtils.closeSilently(generator); } assertThat(reader.hasNext()).as("should have no more entries").isFalse(); } @Test(expectedExceptions = IOException.class, expectedExceptionsMessageRegExp = ".*Could not find template file unknown.*") public void testMissingTemplateFile() throws Exception { newReader("unknown").setResourcePath(resourcePath).build(); /** * Test the complete content of top entry. */ @Test(dataProvider = "generators") public void testTopEntry(EntryGenerator generator, int numberOfUsers) throws Exception { try { Entry topEntry = generator.readEntry(); assertThat(topEntry.getName().toString()).isEqualTo("dc=example,dc=com"); Attribute dcAttribute = topEntry.getAttribute(getDCAttributeType().getNameOrOID()); assertThat(dcAttribute).isNotNull(); assertThat(dcAttribute.firstValueAsString()).isEqualTo("example"); checkEntryObjectClasses(topEntry, "top", "domainComponent"); } finally { StaticUtils.closeSilently(generator); } } @Test(expectedExceptions = DecodeException.class, expectedExceptionsMessageRegExp = ".*Cannot find file streets.*") public void testMissingResourceFile() throws Exception { // fail to find first resource file which is 'streets' newReader(getTestFilePath(TEMPLATE_FILE_PATH)).setResourcePath("unknown").build(); /** * Test the complete content of second entry. */ @Test(dataProvider = "generators") public void testSecondEntry(EntryGenerator generator, int numberOfUsers) throws Exception { try { generator.readEntry(); // skip top entry Entry entry = generator.readEntry(); assertThat(entry.getName().toString()).isEqualTo("ou=People,dc=example,dc=com"); Attribute dcAttribute = entry.getAttribute(getOUAttributeType().getNameOrOID()); assertThat(dcAttribute).isNotNull(); assertThat(dcAttribute.firstValueAsString()).isEqualTo("People"); checkEntryObjectClasses(entry, "top", "organizationalUnit"); } finally { StaticUtils.closeSilently(generator); } } /** * Test the complete content of first user entry. */ @Test(dataProvider = "generators") public void testFirstUserEntry(EntryGenerator generator, int numberOfUsers) throws Exception { try { generator.readEntry(); // skip top entry generator.readEntry(); // skip ou entry Entry entry = generator.readEntry(); assertThat(entry.getName().toString()).isEqualTo("uid=user.0,ou=People,dc=example,dc=com"); checkPresenceOfAttributes(entry, "givenName", "sn", "cn", "initials", "employeeNumber", "uid", "mail", "userPassword", "telephoneNumber", "homePhone", "pager", "mobile", "street", "l", "st", "postalCode", "postalAddress", "description"); assertThat(entry.getAttribute("cn").firstValueAsString()).isEqualTo( entry.getAttribute("givenName").firstValueAsString() + " " + entry.getAttribute("sn").firstValueAsString()); checkEntryObjectClasses(entry, "top", "person", "organizationalPerson", "inetOrgPerson"); } finally { StaticUtils.closeSilently(generator); } } private void checkEntryObjectClasses(Entry entry, String...objectClasses) { Attribute ocAttribute = entry.getAttribute(getObjectClassAttributeType().getNameOrOID()); assertThat(ocAttribute).isNotNull(); Iterator<ByteString> it = ocAttribute.iterator(); for (int i = 0; i < objectClasses.length; i++) { assertThat(it.next().toString()).isEqualTo(objectClasses[i]); } assertThat(it.hasNext()).isFalse(); } private void checkPresenceOfAttributes(Entry entry, String... attributes) { for (int i = 0; i < attributes.length; i++) { assertThat(entry.getAttribute(attributes[i])).isNotNull(); } } /** * Test a template with subtemplates, ensuring all expected DNs are generated. */ @Test public void testTemplateWithSubTemplates() throws Exception { int numberOfUsers = 10; int numberOfGroups = 5; int numberOfOUs = 10; EntryGenerator generator = new EntryGenerator( "define suffix=dc=example,dc=com", "define maildomain=example.com", "define numusers=" + numberOfUsers, "define numous=" + numberOfOUs, "define numgroup=" + numberOfGroups, "", "branch: [suffix]", "subordinateTemplate: ous:[numous]", "", "template: ous", "subordinateTemplate: People:1", "subordinateTemplate: Groups:1", "rdnAttr: ou", "objectclass: top", "objectclass: organizationalUnit", "ou: Organization_<sequential:1>", "", "template: People", "rdnAttr: ou", "subordinateTemplate: person:[numusers]", "objectclass: top", "objectclass: organizationalUnit", "ou: People", "", "template: Groups", "subordinateTemplate: groupOfName:[numgroup]", "rdnAttr: ou", "objectclass: top", "objectclass: organizationalUnit", "ou: Groups", "", "template: person", "rdnAttr: uid", "objectClass: top", "objectClass: inetOrgPerson", "cn: <first> <last>", "employeeNumber: <sequential:0>", "uid: user.{employeeNumber}", "", "template: groupOfName", "rdnAttr: cn", "objectClass: top", "objectClass: groupOfNames", "cn: Group_<sequential:1>" ).setResourcePath(resourcePath); try { assertThat(generator.readEntry().getName().toString()).isEqualTo("dc=example,dc=com"); int countUsers = 0; int countGroups = 1; for (int i = 1; i <= numberOfOUs; i++) { String dnOU = "ou=Organization_" + i + ",dc=example,dc=com"; assertThat(generator.readEntry().getName().toString()).isEqualTo(dnOU); assertThat(generator.readEntry().getName().toString()).isEqualTo("ou=People," + dnOU); for (int j = countUsers; j < countUsers + numberOfUsers; j++) { assertThat(generator.readEntry().getName().toString()).isEqualTo( "uid=user." + j + ",ou=People," + dnOU); } countUsers += numberOfUsers; assertThat(generator.readEntry().getName().toString()).isEqualTo("ou=Groups," + dnOU); for (int j = countGroups; j < countGroups + numberOfGroups; j++) { assertThat(generator.readEntry().getName().toString()).isEqualTo( "cn=Group_" + j + ",ou=Groups," + dnOU); } countGroups += numberOfGroups; } assertThat(generator.hasNext()).isFalse(); } finally { StaticUtils.closeSilently(generator); } } /** @@ -160,7 +372,7 @@ * generating templates reports the correct line. */ @Test() public void testParseFileTemplate() throws Exception { public void testMissingVariableErrorReport() throws Exception { String[] lines = { /* 0 */"template: template", /* 1 */"a: {missingVar}", @@ -172,7 +384,7 @@ // Test must show "missingVar" missing on line 1. // Previous behaviour showed "missingVar" on line 5. TemplateFile templateFile = new TemplateFile(schema, resourcePath); TemplateFile templateFile = new TemplateFile(schema, null, resourcePath); List<LocalizableMessage> warns = new ArrayList<LocalizableMessage>(); try { @@ -218,7 +430,7 @@ */ @Test(dataProvider = "validTemplates") public void testParsingEscapeCharInTemplate(String testName, String[] lines) throws Exception { TemplateFile templateFile = new TemplateFile(schema, resourcePath); TemplateFile templateFile = new TemplateFile(schema, null, resourcePath); List<LocalizableMessage> warns = new ArrayList<LocalizableMessage>(); templateFile.parse(lines, warns); assertThat(warns).isEmpty(); @@ -367,14 +579,18 @@ @Test(dataProvider = "templatesToTestEscapeChars", dependsOnMethods = { "testParsingEscapeCharInTemplate" }) public void testEscapeCharsFromTemplate(String testName, String[] lines, String attrName, String expectedValue) throws Exception { EntryGenerator reader = newReader(lines).setResourcePath(resourcePath).build(); Entry topEntry = reader.readEntry(); Entry entry = reader.readEntry(); reader.close(); EntryGenerator generator = null; try { generator = new EntryGenerator(lines).setResourcePath(resourcePath); Entry topEntry = generator.readEntry(); Entry entry = generator.readEntry(); assertThat(topEntry).isNotNull(); assertThat(entry).isNotNull(); assertThat(entry.getAttribute(attrName).firstValueAsString()).isEqualTo(expectedValue); assertThat(topEntry).isNotNull(); assertThat(entry).isNotNull(); assertThat(entry.getAttribute(attrName).firstValueAsString()).isEqualTo(expectedValue); } finally { StaticUtils.closeSilently(generator); } } /** @@ -394,15 +610,19 @@ // The value below combines variable, randoms and escaped chars. // The resulting value is "Foo <?>{1}Bar" where ? is a letter // from [A-Z]. "cn: Foo \\<<random:chars:ABCDEFGHIJKLMNOPQRSTUVWXYZ:1>\\>\\{1\\}{sn}", "", }; "cn: Foo \\<<random:chars:ABCDEFGHIJKLMNOPQRSTUVWXYZ:1>\\>\\{1\\}{sn}", "" }; EntryGenerator generator = null; try { generator = new EntryGenerator(lines).setResourcePath(resourcePath); Entry topEntry = generator.readEntry(); Entry entry = generator.readEntry(); EntryGenerator reader = newReader(lines).setResourcePath(resourcePath).build(); Entry topEntry = reader.readEntry(); Entry entry = reader.readEntry(); reader.close(); assertThat(topEntry).isNotNull(); assertThat(entry).isNotNull(); assertThat(entry.getAttribute("cn").firstValueAsString()).matches("Foo <[A-Z]>\\{1\\}Bar"); assertThat(topEntry).isNotNull(); assertThat(entry).isNotNull(); assertThat(entry.getAttribute("cn").firstValueAsString()).matches("Foo <[A-Z]>\\{1\\}Bar"); } finally { StaticUtils.closeSilently(generator); } } } opendj3/opendj-core/src/test/java/org/forgerock/opendj/ldif/TemplateTagTestcase.java
New file @@ -0,0 +1,293 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt * or http://forgerock.org/license/CDDLv1.0.html. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at legal-notices/CDDLv1_0.txt. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2013 ForgeRock AS. */ package org.forgerock.opendj.ldif; import static org.fest.assertions.Assertions.*; import static org.mockito.Matchers.*; import static org.mockito.Mockito.*; import java.util.ArrayList; import java.util.List; import org.forgerock.i18n.LocalizableMessage; import org.forgerock.opendj.ldap.DN; import org.forgerock.opendj.ldap.DecodeException; import org.forgerock.opendj.ldap.SdkTestCase; import org.forgerock.opendj.ldap.schema.AttributeType; import org.forgerock.opendj.ldap.schema.Schema; import org.forgerock.opendj.ldif.TemplateFile.Template; import org.forgerock.opendj.ldif.TemplateFile.TemplateEntry; import org.forgerock.opendj.ldif.TemplateFile.TemplateLine; import org.forgerock.opendj.ldif.TemplateFile.TemplateValue; import org.forgerock.opendj.ldif.TemplateTag.AttributeValueTag; import org.forgerock.opendj.ldif.TemplateTag.IfAbsentTag; import org.forgerock.opendj.ldif.TemplateTag.IfPresentTag; import org.forgerock.opendj.ldif.TemplateTag.TagResult; import org.testng.annotations.Test; @SuppressWarnings("javadoc") public class TemplateTagTestcase extends SdkTestCase { private static final int LINE_NUMBER = 10; private static final TemplateFile NULL_TEMPLATE_FILE = null; private static final List<LocalizableMessage> NULL_WARNINGS = null; private static final TemplateValue NULL_VALUE = null; private static final TemplateLine NULL_LINE = null; @Test public void testIfAbsentTag() throws Exception { TemplateTag tag = new IfAbsentTag(); String org = "org"; tagWithArguments(tag, "dc", org); // dc=org should be absent // org value is absent assertThat(tag.generateValue(templateEntry("v1", "v2"), NULL_VALUE)).isEqualTo(TagResult.SUCCESS); // org value is present assertThat(tag.generateValue(templateEntry(org, "v"), NULL_VALUE)).isEqualTo(TagResult.FAILURE); assertThat(tag.generateValue(templateEntry("v", org), NULL_VALUE)).isEqualTo(TagResult.FAILURE); assertThat(tag.generateValue(templateEntry(org), NULL_VALUE)).isEqualTo(TagResult.FAILURE); } @Test public void testIfAbsentTagWithNoValue() throws Exception { TemplateTag tag = new IfAbsentTag(); tagWithArguments(tag, "dc"); // dc should be absent assertThat(tag.generateValue(templateEntry("v"), NULL_VALUE)).isEqualTo(TagResult.FAILURE); } @Test(expectedExceptions = DecodeException.class, expectedExceptionsMessageRegExp = ".*Invalid number of arguments.*") public void testIfAbsentTagTooManyArguments() throws Exception { tagWithArguments(new IfAbsentTag(), "dc", "org1", "org2"); // too many args } @Test(expectedExceptions = DecodeException.class, expectedExceptionsMessageRegExp = ".*Invalid number of arguments.*") public void testIfAbsentTagNotEnoughArguments() throws Exception { tagWithArguments(new IfAbsentTag()); // zero args } @Test(expectedExceptions = DecodeException.class, expectedExceptionsMessageRegExp = ".*Undefined attribute.*") public void testIfAbsentTagNoAttribute() throws Exception { tagWithArguments(new IfAbsentTag(), templateWithNoAttribute(), "dc"); } @Test public void testDNTagRootDN() throws Exception { TemplateTag tag = new TemplateTag.DNTag(); tagWithArguments(tag); TemplateValue value = new TemplateValue(NULL_LINE); tag.generateValue(templateEntry(DN.rootDN()), value); assertThat(value.getValueAsString()).isEqualTo(""); } @Test public void testDNTagZeroComponent() throws Exception { TemplateTag tag = new TemplateTag.DNTag(); tagWithArguments(tag); TemplateValue value = new TemplateValue(NULL_LINE); tag.generateValue(templateEntry(DN.valueOf("ou=users,dc=example,dc=test")), value); assertThat(value.getValueAsString()).isEqualTo("ou=users,dc=example,dc=test"); } @Test public void testUnderscoreDNTagZeroComponent() throws Exception { TemplateTag tag = new TemplateTag.UnderscoreDNTag(); tagWithArguments(tag); TemplateValue value = new TemplateValue(NULL_LINE); tag.generateValue(templateEntry(DN.valueOf("ou=users,dc=example,dc=test")), value); assertThat(value.getValueAsString()).isEqualTo("ou=users_dc=example_dc=test"); } @Test public void testDNTagOneComponent() throws Exception { TemplateTag tag = new TemplateTag.DNTag(); tagWithArguments(tag, "1"); TemplateValue value = new TemplateValue(NULL_LINE); tag.generateValue(templateEntry(DN.valueOf("ou=users,dc=example,dc=test")), value); assertThat(value.getValueAsString()).isEqualTo("ou=users"); } @Test public void testDNTagTwoComponent() throws Exception { TemplateTag tag = new TemplateTag.DNTag(); tagWithArguments(tag, "2"); TemplateValue value = new TemplateValue(NULL_LINE); tag.generateValue(templateEntry(DN.valueOf("ou=users,dc=example,dc=test")), value); assertThat(value.getValueAsString()).isEqualTo("ou=users,dc=example"); } @Test public void testDNTagMinusOneComponent() throws Exception { TemplateTag tag = new TemplateTag.DNTag(); tagWithArguments(tag, "-1"); TemplateValue value = new TemplateValue(NULL_LINE); tag.generateValue(templateEntry(DN.valueOf("ou=users,dc=example,dc=test")), value); assertThat(value.getValueAsString()).isEqualTo("dc=test"); } @Test public void testDNTagMinusTwoComponents() throws Exception { TemplateTag tag = new TemplateTag.DNTag(); tagWithArguments(tag, "-2"); TemplateValue value = new TemplateValue(NULL_LINE); tag.generateValue(templateEntry(DN.valueOf("ou=users,dc=example,dc=test")), value); assertThat(value.getValueAsString()).isEqualTo("dc=example,dc=test"); } @Test public void testIfPresentTag() throws Exception { TemplateTag tag = new TemplateTag.IfPresentTag(); String org = "org"; tagWithArguments(tag, "dc", org); // dc=org should be present // org value is absent assertThat(tag.generateValue(templateEntry("v1", "v2"), NULL_VALUE)).isEqualTo(TagResult.FAILURE); // org value is present assertThat(tag.generateValue(templateEntry(org, "v"), NULL_VALUE)).isEqualTo(TagResult.SUCCESS); assertThat(tag.generateValue(templateEntry("v", org), NULL_VALUE)).isEqualTo(TagResult.SUCCESS); assertThat(tag.generateValue(templateEntry(org), NULL_VALUE)).isEqualTo(TagResult.SUCCESS); } @Test public void testIfPresentTagWithNoValue() throws Exception { TemplateTag tag = new TemplateTag.IfPresentTag(); tagWithArguments(tag, "dc"); // dc=org should be present assertThat(tag.generateValue(templateEntry("org"), NULL_VALUE)).isEqualTo(TagResult.SUCCESS); } @Test(expectedExceptions = DecodeException.class, expectedExceptionsMessageRegExp = ".*Invalid number of arguments.*") public void testIfPresentTagTooManyArguments() throws Exception { tagWithArguments(new IfPresentTag(), "1", "2", "3"); // too many args } @Test(expectedExceptions = DecodeException.class, expectedExceptionsMessageRegExp = ".*Invalid number of arguments.*") public void testIfPresentTagNotEnoughArguments() throws Exception { tagWithArguments(new IfPresentTag()); // zero args } @Test(expectedExceptions = DecodeException.class, expectedExceptionsMessageRegExp = ".*Undefined attribute.*") public void testIfPresentTagNoAttribute() throws Exception { tagWithArguments(new IfPresentTag(), templateWithNoAttribute(), "dc"); } @Test(expectedExceptions = DecodeException.class, expectedExceptionsMessageRegExp = ".*Invalid number of arguments.*") public void testAttributeValueTagTooManyArguments() throws Exception { tagWithArguments(new AttributeValueTag(), "dc", "2", "3"); // too many args } @Test(expectedExceptions = DecodeException.class, expectedExceptionsMessageRegExp = ".*below the lowest allowed value.*") public void testAttributeValueTagBelowLowerBound() throws Exception { tagWithArguments(new AttributeValueTag(), "dc", "-1"); } @Test(expectedExceptions = DecodeException.class, expectedExceptionsMessageRegExp = ".*Cannot parse value.*") public void testAttributeValueTagNotANumber() throws Exception { tagWithArguments(new AttributeValueTag(), "dc", "notanumber"); } @Test(expectedExceptions = DecodeException.class, expectedExceptionsMessageRegExp = ".*Undefined attribute.*") public void testAttributeValueTagNoAttribute() throws Exception { tagWithArguments(new AttributeValueTag(), templateWithNoAttribute(), "dc"); } /** Helper method to initialize tags with template having any attribute and some arguments*/ private void tagWithArguments(TemplateTag tag, String... arguments) throws DecodeException { tagWithArguments(tag, templateWithAnyAttribute(), arguments); } /** Helper method to initialize tags with template and some arguments*/ private void tagWithArguments(TemplateTag tag, Template template, String... arguments) throws DecodeException { tag.initializeForTemplate(Schema.getDefaultSchema(), NULL_TEMPLATE_FILE, template, arguments, LINE_NUMBER, NULL_WARNINGS); } /** Helper method to build a template entry containing the provided values. */ private TemplateEntry templateEntry(String... values) { TemplateEntry templateEntry = mock(TemplateEntry.class); List<TemplateValue> templateValues = new ArrayList<TemplateValue>(); for (String value : values) { templateValues.add(templateValue(value)); } when(templateEntry.getValues(any(AttributeType.class))).thenReturn(templateValues); return templateEntry; } /** Helper method to build a template entry with the provided DN. */ private TemplateEntry templateEntry(DN dn) { TemplateEntry templateEntry = mock(TemplateEntry.class); when(templateEntry.getDN()).thenReturn(dn); return templateEntry; } /** Helper method to build a template value from provided string. */ private TemplateValue templateValue(String value) { TemplateValue templateVal = new TemplateFile.TemplateValue(null); templateVal.append(value); return templateVal; } /** Helper method to build a template that always return true on attribute type check */ private Template templateWithAnyAttribute() { Template template = mock(Template.class); when(template.hasAttribute(any(AttributeType.class))).thenReturn(true); return template; } /** Helper method to build a template that always return false on attribute type check */ private Template templateWithNoAttribute() { Template template = mock(Template.class); when(template.hasAttribute(any(AttributeType.class))).thenReturn(false); return template; } }