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