001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2006-2009 Sun Microsystems, Inc.
025 *      Portions Copyright 2014-2015 ForgeRock AS
026 */
027package org.opends.server.tools.makeldif;
028
029import org.forgerock.i18n.LocalizableMessage;
030
031import java.io.IOException;
032import java.util.Collections;
033import java.util.HashSet;
034import java.util.Map;
035
036import org.opends.server.types.AttributeType;
037import org.opends.server.types.DN;
038
039import static org.opends.messages.ToolMessages.*;
040import static org.opends.server.util.StaticUtils.*;
041
042/**
043 * This class defines a template, which is a pattern that may be used to
044 * generate entries.  A template may be used either below a branch or below
045 * another template.
046 */
047public class Template
048{
049  /**
050   * The attribute types that are used in the RDN for entries generated using
051   * this template.
052   */
053  private AttributeType[] rdnAttributes;
054
055  /** The number of entries to create for each subordinate template. */
056  private int[] numEntriesPerTemplate;
057
058  /** The name for this template. */
059  private String name;
060
061  /** The names of the subordinate templates below this template. */
062  private String[] subordinateTemplateNames;
063
064  /** The subordinate templates below this template. */
065  private Template[] subordinateTemplates;
066
067  /** The template file that contains this template. */
068  private TemplateFile templateFile;
069
070  /** The set of template lines for this template. */
071  private TemplateLine[] templateLines;
072
073
074
075  /**
076   * Creates a new template with the provided information.
077   *
078   * @param  templateFile              The template file that contains this
079   *                                   template.
080   * @param  name                      The name for this template.
081   * @param  rdnAttributes             The set of attribute types that are used
082   *                                   in the RDN for entries generated using
083   *                                   this template.
084   * @param  subordinateTemplateNames  The names of the subordinate templates
085   *                                   below this template.
086   * @param  numEntriesPerTemplate     The number of entries to create below
087   *                                   each subordinate template.
088   */
089  public Template(TemplateFile templateFile, String name,
090                  AttributeType[] rdnAttributes,
091                  String[] subordinateTemplateNames,
092                  int[] numEntriesPerTemplate)
093  {
094    this.templateFile             = templateFile;
095    this.name                     = name;
096    this.rdnAttributes            = rdnAttributes;
097    this.subordinateTemplateNames = subordinateTemplateNames;
098    this.numEntriesPerTemplate    = numEntriesPerTemplate;
099
100    templateLines        = new TemplateLine[0];
101    subordinateTemplates = null;
102  }
103
104
105
106  /**
107   * Creates a new template with the provided information.
108   *
109   * @param  templateFile              The template file that contains this
110   *                                   template.
111   * @param  name                      The name for this template.
112   * @param  rdnAttributes             The set of attribute types that are used
113   *                                   in the RDN for entries generated using
114   *                                   this template.
115   * @param  subordinateTemplateNames  The names of the subordinate templates
116   *                                   below this template.
117   * @param  numEntriesPerTemplate     The number of entries to create below
118   *                                   each subordinate template.
119   * @param  templateLines             The set of template lines for this
120   *                                   template.
121   */
122  public Template(TemplateFile templateFile, String name,
123                  AttributeType[] rdnAttributes,
124                  String[] subordinateTemplateNames,
125                  int[] numEntriesPerTemplate, TemplateLine[] templateLines)
126  {
127    this.templateFile             = templateFile;
128    this.name                     = name;
129    this.rdnAttributes            = rdnAttributes;
130    this.subordinateTemplateNames = subordinateTemplateNames;
131    this.numEntriesPerTemplate    = numEntriesPerTemplate;
132    this.templateLines            = templateLines;
133
134    subordinateTemplates = null;
135  }
136
137
138
139  /**
140   * Performs any necessary processing to ensure that the template
141   * initialization is completed.  In particular, it should make sure that all
142   * referenced subordinate templates actually exist in the template file, and
143   * that all of the RDN attributes are contained in the template lines.
144   *
145   * @param  templates  The set of templates defined in the template file.
146   *
147   * @throws  MakeLDIFException  If any of the subordinate templates are not
148   *                             defined in the template file.
149   */
150  public void completeTemplateInitialization(Map<String,Template> templates)
151         throws MakeLDIFException
152  {
153    // Make sure that all of the specified subordinate templates exist.
154    if (subordinateTemplateNames == null)
155    {
156      subordinateTemplateNames = new String[0];
157      subordinateTemplates     = new Template[0];
158    }
159    else
160    {
161      subordinateTemplates = new Template[subordinateTemplateNames.length];
162      for (int i=0; i < subordinateTemplates.length; i++)
163      {
164        subordinateTemplates[i] =
165             templates.get(toLowerCase(subordinateTemplateNames[i]));
166        if (subordinateTemplates[i] == null)
167        {
168          LocalizableMessage message = ERR_MAKELDIF_UNDEFINED_TEMPLATE_SUBORDINATE.get(
169              subordinateTemplateNames[i], name);
170          throw new MakeLDIFException(message);
171        }
172      }
173    }
174
175
176    // Make sure that all of the RDN attributes are defined.
177    HashSet<AttributeType> rdnAttrs = new HashSet<>(rdnAttributes.length);
178    Collections.addAll(rdnAttrs, rdnAttributes);
179
180    for (TemplateLine l : templateLines)
181    {
182      if (rdnAttrs.remove(l.getAttributeType())
183          && rdnAttrs.isEmpty())
184      {
185        break;
186      }
187    }
188
189    if (! rdnAttrs.isEmpty())
190    {
191      AttributeType t       = rdnAttrs.iterator().next();
192      LocalizableMessage message =
193          ERR_MAKELDIF_TEMPLATE_MISSING_RDN_ATTR.get(name, t.getNameOrOID());
194      throw new MakeLDIFException(message);
195    }
196  }
197
198
199
200  /**
201   * Retrieves the name for this template.
202   *
203   * @return  The name for this template.
204   */
205  public String getName()
206  {
207    return name;
208  }
209
210
211
212  /**
213   * Retrieves the set of attribute types that are used in the RDN for entries
214   * generated using this template.
215   *
216   * @return  The set of attribute types that are used in the RDN for entries
217   *          generated using this template.
218   */
219  public AttributeType[] getRDNAttributes()
220  {
221    return rdnAttributes;
222  }
223
224
225
226  /**
227   * Retrieves the names of the subordinate templates used to generate entries
228   * below entries created by this template.
229   *
230   * @return  The names of the subordinate templates used to generate entries
231   *          below entries created by this template.
232   */
233  public String[] getSubordinateTemplateNames()
234  {
235    return subordinateTemplateNames;
236  }
237
238
239
240  /**
241   * Retrieves the subordinate templates used to generate entries below entries
242   * created by this template.
243   *
244   * @return  The subordinate templates used to generate entries below entries
245   *          created by this template.
246   */
247  public Template[] getSubordinateTemplates()
248  {
249    return subordinateTemplates;
250  }
251
252
253
254  /**
255   * Retrieves the number of entries that should be created for each subordinate
256   * template.
257   *
258   * @return  The number of entries that should be created for each subordinate
259   *          template.
260   */
261  public int[] getNumEntriesPerTemplate()
262  {
263    return numEntriesPerTemplate;
264  }
265
266
267
268  /**
269   * Retrieves the set of template lines for this template.
270   *
271   * @return  The set of template lines for this template.
272   */
273  public TemplateLine[] getTemplateLines()
274  {
275    return templateLines;
276  }
277
278
279
280  /**
281   * Adds the provided template line to this template.
282   *
283   * @param  line  The template line to add to this template.
284   */
285  public void addTemplateLine(TemplateLine line)
286  {
287    TemplateLine[] newTemplateLines = new TemplateLine[templateLines.length+1];
288    System.arraycopy(templateLines, 0, newTemplateLines, 0,
289                     templateLines.length);
290    newTemplateLines[templateLines.length] = line;
291    templateLines = newTemplateLines;
292  }
293
294
295
296  /**
297   * Indicates whether this template contains any template lines that reference
298   * the provided attribute type.
299   *
300   * @param  attributeType  The attribute type for which to make the
301   *                        determination.
302   *
303   * @return  <CODE>true</CODE> if this template contains one or more template
304   *          lines that reference the provided attribute type, or
305   *          <CODE>false</CODE> if not.
306   */
307  public boolean hasAttribute(AttributeType attributeType)
308  {
309    for (TemplateLine l : templateLines)
310    {
311      if (l.getAttributeType().equals(attributeType))
312      {
313        return true;
314      }
315    }
316
317    return false;
318  }
319
320
321
322  /**
323   * Writes the entry for this template, as well as all appropriate subordinate
324   * entries.
325   *
326   * @param  entryWriter  The entry writer that will be used to write the
327   *                      entries.
328   * @param  parentDN     The DN of the entry below which the subordinate
329   *                      entries should be generated.
330   * @param  count        The number of entries to generate based on this
331   *                      template.
332   *
333   * @return  The result that indicates whether processing should continue.
334   *
335   * @throws  IOException  If a problem occurs while attempting to write to the
336   *                       LDIF writer.
337   *
338   * @throws  MakeLDIFException  If some other problem occurs.
339   */
340  public TagResult writeEntries(EntryWriter entryWriter, DN parentDN, int count)
341         throws IOException, MakeLDIFException
342  {
343    for (int i=0; i < count; i++)
344    {
345      templateFile.nextFirstAndLastNames();
346      TemplateEntry templateEntry = new TemplateEntry(this, parentDN);
347
348      for (TemplateLine l : templateLines)
349      {
350        TagResult r = l.generateLine(templateEntry);
351        if (!r.keepProcessingEntry()
352            || !r.keepProcessingParent()
353            || !r.keepProcessingTemplateFile())
354        {
355          return r;
356        }
357      }
358
359      if (! entryWriter.writeEntry(templateEntry))
360      {
361        return TagResult.STOP_PROCESSING;
362      }
363
364      for (int j=0; j < subordinateTemplates.length; j++)
365      {
366        TagResult r =
367             subordinateTemplates[j].writeEntries(entryWriter,
368                 templateEntry.getDN(), numEntriesPerTemplate[j]);
369        if (!r.keepProcessingParent()
370            || !r.keepProcessingTemplateFile())
371        {
372          if (r.keepProcessingTemplateFile())
373          {
374            // We don't want to propagate a "stop processing parent" all the
375            // way up the chain.
376            return TagResult.SUCCESS_RESULT;
377          }
378
379          return r;
380        }
381      }
382    }
383
384    return TagResult.SUCCESS_RESULT;
385  }
386}
387