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