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-2010 Sun Microsystems, Inc.
025 *      Portions Copyright 2014-2015 ForgeRock AS
026 */
027package org.opends.server.tools.makeldif;
028
029import static org.opends.messages.ToolMessages.*;
030import static org.opends.server.util.StaticUtils.*;
031
032import java.io.IOException;
033import java.util.ArrayList;
034import java.util.List;
035import java.util.Map;
036
037import org.forgerock.i18n.LocalizableMessage;
038import org.forgerock.opendj.ldap.ByteString;
039import org.opends.server.core.DirectoryServer;
040import org.opends.server.types.Attribute;
041import org.opends.server.types.AttributeType;
042import org.opends.server.types.DN;
043import org.opends.server.types.Entry;
044
045/**
046 * This class defines a branch that should be included in the resulting LDIF.  A
047 * branch may or may not have subordinate entries.
048 */
049public class Branch
050{
051  /** The DN for this branch entry. */
052  private DN branchDN;
053
054  /**
055   * The number of entries that should be created below this branch for each
056   * subordinate template.
057   */
058  private int[] numEntriesPerTemplate;
059
060  /** The names of the subordinate templates for this branch. */
061  private String[] subordinateTemplateNames;
062
063  /** The set of subordinate templates for this branch. */
064  private Template[] subordinateTemplates;
065
066  /** The set of template lines that correspond to the RDN components. */
067  private TemplateLine[] rdnLines;
068
069  /** The set of extra lines that should be included in this branch entry. */
070  private TemplateLine[] extraLines;
071
072
073
074  /**
075   * Creates a new branch with the provided information.
076   *
077   * @param  templateFile  The template file in which this branch appears.
078   * @param  branchDN      The DN for this branch entry.
079   */
080  public Branch(TemplateFile templateFile, DN branchDN)
081  {
082    this(templateFile, branchDN, new String[0], new int[0],
083         new TemplateLine[0]);
084  }
085
086
087
088  /**
089   * Creates a new branch with the provided information.
090   *
091   * @param  templateFile              The template file in which this branch
092   *                                   appears.
093   * @param  branchDN                  The DN for this branch entry.
094   * @param  subordinateTemplateNames  The names of the subordinate templates
095   *                                   used to generate entries below this
096   *                                   branch.
097   * @param  numEntriesPerTemplate     The number of entries that should be
098   *                                   created below this branch for each
099   *                                   subordinate template.
100   * @param  extraLines                The set of extra lines that should be
101   *                                   included in this branch entry.
102   */
103  public Branch(TemplateFile templateFile, DN branchDN,
104                String[] subordinateTemplateNames, int[] numEntriesPerTemplate,
105                TemplateLine[] extraLines)
106  {
107    this.branchDN                 = branchDN;
108    this.subordinateTemplateNames = subordinateTemplateNames;
109    this.numEntriesPerTemplate    = numEntriesPerTemplate;
110    this.extraLines               = extraLines;
111
112    subordinateTemplates = null;
113
114
115    // Get the RDN template lines based just on the entry DN.
116    Entry entry = createEntry(branchDN);
117
118    ArrayList<LocalizableMessage> warnings = new ArrayList<>();
119    ArrayList<TemplateLine> lineList = new ArrayList<>();
120
121    for (String ocName : entry.getObjectClasses().values())
122    {
123      try
124      {
125        String[] valueStrings = new String[] { ocName };
126        Tag[] tags = new Tag[1];
127        tags[0] = new StaticTextTag();
128        tags[0].initializeForBranch(templateFile, this, valueStrings, 0,
129                                    warnings);
130
131        TemplateLine l =
132             new TemplateLine(DirectoryServer.getObjectClassAttributeType(), 0,
133                              tags);
134        lineList.add(l);
135      }
136      catch (Exception e)
137      {
138        // This should never happen.
139        e.printStackTrace();
140      }
141    }
142
143    for (List<Attribute> attrList : entry.getUserAttributes().values())
144    {
145      for (Attribute a : attrList)
146      {
147        for (ByteString v : a)
148        {
149          try
150          {
151            String[] valueStrings = new String[] { v.toString() };
152            Tag[] tags = new Tag[] { new StaticTextTag() };
153            tags[0].initializeForBranch(templateFile, this, valueStrings, 0, warnings);
154            lineList.add(new TemplateLine(a.getAttributeType(), 0, tags));
155          }
156          catch (Exception e)
157          {
158            // This should never happen.
159            e.printStackTrace();
160          }
161        }
162      }
163    }
164
165    for (List<Attribute> attrList : entry.getOperationalAttributes().values())
166    {
167      for (Attribute a : attrList)
168      {
169        for (ByteString v : a)
170        {
171          try
172          {
173            String[] valueStrings = new String[] { v.toString() };
174            Tag[] tags = new Tag[] { new StaticTextTag() };
175            tags[0].initializeForBranch(templateFile, this, valueStrings, 0, warnings);
176            lineList.add(new TemplateLine(a.getAttributeType(), 0, tags));
177          }
178          catch (Exception e)
179          {
180            // This should never happen.
181            e.printStackTrace();
182          }
183        }
184      }
185    }
186
187    rdnLines = new TemplateLine[lineList.size()];
188    lineList.toArray(rdnLines);
189  }
190
191
192
193  /**
194   * Performs any necessary processing to ensure that the branch initialization
195   * is completed.  In particular, it should make sure that all referenced
196   * subordinate templates actually exist in the template file.
197   *
198   * @param  templates  The set of templates defined in the template file.
199   *
200   * @throws  MakeLDIFException  If any of the subordinate templates are not
201   *                             defined in the template file.
202   */
203  public void completeBranchInitialization(Map<String,Template> templates)
204         throws MakeLDIFException
205  {
206    if (subordinateTemplateNames == null)
207    {
208      subordinateTemplateNames = new String[0];
209      subordinateTemplates     = new Template[0];
210    }
211    else
212    {
213      subordinateTemplates = new Template[subordinateTemplateNames.length];
214      for (int i=0; i < subordinateTemplates.length; i++)
215      {
216        subordinateTemplates[i] =
217             templates.get(toLowerCase(subordinateTemplateNames[i]));
218        if (subordinateTemplates[i] == null)
219        {
220          throw new MakeLDIFException(ERR_MAKELDIF_UNDEFINED_BRANCH_SUBORDINATE.get(
221              branchDN, subordinateTemplateNames[i]));
222        }
223      }
224    }
225  }
226
227
228
229  /**
230   * Retrieves the DN for this branch entry.
231   *
232   * @return  The DN for this branch entry.
233   */
234  public DN getBranchDN()
235  {
236    return branchDN;
237  }
238
239
240
241  /**
242   * Retrieves the names of the subordinate templates for this branch.
243   *
244   * @return  The names of the subordinate templates for this branch.
245   */
246  public String[] getSubordinateTemplateNames()
247  {
248    return subordinateTemplateNames;
249  }
250
251
252
253  /**
254   * Retrieves the set of subordinate templates used to generate entries below
255   * this branch.  Note that the subordinate templates will not be available
256   * until the <CODE>completeBranchInitialization</CODE> method has been called.
257   *
258   * @return  The set of subordinate templates used to generate entries below
259   *          this branch.
260   */
261  public Template[] getSubordinateTemplates()
262  {
263    return subordinateTemplates;
264  }
265
266
267
268  /**
269   * Retrieves the number of entries that should be created below this branch
270   * for each subordinate template.
271   *
272   * @return  The number of entries that should be created below this branch for
273   *          each subordinate template.
274   */
275  public int[] getNumEntriesPerTemplate()
276  {
277    return numEntriesPerTemplate;
278  }
279
280
281
282  /**
283   * Adds a new subordinate template to this branch.  Note that this should not
284   * be used after <CODE>completeBranchInitialization</CODE> has been called.
285   *
286   * @param  name        The name of the template to use to generate the
287   *                     entries.
288   * @param  numEntries  The number of entries to create based on the template.
289   */
290  public void addSubordinateTemplate(String name, int numEntries)
291  {
292    String[] newNames  = new String[subordinateTemplateNames.length+1];
293    int[]    newCounts = new int[numEntriesPerTemplate.length+1];
294
295    System.arraycopy(subordinateTemplateNames, 0, newNames, 0,
296                     subordinateTemplateNames.length);
297    System.arraycopy(numEntriesPerTemplate, 0, newCounts, 0,
298                     numEntriesPerTemplate.length);
299
300    newNames[subordinateTemplateNames.length] = name;
301    newCounts[numEntriesPerTemplate.length]   = numEntries;
302
303    subordinateTemplateNames = newNames;
304    numEntriesPerTemplate    = newCounts;
305  }
306
307
308
309  /**
310   * Retrieves the set of extra lines that should be included in this branch
311   * entry.
312   *
313   * @return  The set of extra lines that should be included in this branch
314   *          entry.
315   */
316  public TemplateLine[] getExtraLines()
317  {
318    return extraLines;
319  }
320
321
322
323  /**
324   * Adds the provided template line to the set of extra lines for this branch.
325   *
326   * @param  line  The line to add to the set of extra lines for this branch.
327   */
328  public void addExtraLine(TemplateLine line)
329  {
330    TemplateLine[] newExtraLines = new TemplateLine[extraLines.length+1];
331    System.arraycopy(extraLines, 0, newExtraLines, 0, extraLines.length);
332    newExtraLines[extraLines.length] = line;
333
334    extraLines = newExtraLines;
335  }
336
337
338
339  /**
340   * Indicates whether this branch contains a reference to the specified
341   * attribute type, either in the RDN components of the DN or in the extra
342   * lines.
343   *
344   * @param  attributeType  The attribute type for which to make the
345   *                        determination.
346   *
347   * @return  <CODE>true</CODE> if the branch does contain the specified
348   *          attribute type, or <CODE>false</CODE> if it does not.
349   */
350  public boolean hasAttribute(AttributeType attributeType)
351  {
352    if (branchDN.rdn().hasAttributeType(attributeType))
353    {
354      return true;
355    }
356
357    for (TemplateLine l : extraLines)
358    {
359      if (l.getAttributeType().equals(attributeType))
360      {
361        return true;
362      }
363    }
364
365    return false;
366  }
367
368
369
370  /**
371   * Writes the entry for this branch, as well as all appropriate subordinate
372   * entries.
373   *
374   * @param  entryWriter  The entry writer to which the entries should be
375   *                      written.
376   *
377   * @return  The result that indicates whether processing should continue.
378   *
379   * @throws  IOException  If a problem occurs while attempting to write to the
380   *                       LDIF writer.
381   *
382   * @throws  MakeLDIFException  If some other problem occurs.
383   */
384  public TagResult writeEntries(EntryWriter entryWriter)
385         throws IOException, MakeLDIFException
386  {
387    // Create a new template entry and populate it based on the RDN attributes
388    // and extra lines.
389    TemplateEntry entry = new TemplateEntry(this);
390
391    for (TemplateLine l : rdnLines)
392    {
393      TagResult r = l.generateLine(entry);
394      if (!r.keepProcessingEntry()
395          || !r.keepProcessingParent()
396          || !r.keepProcessingTemplateFile())
397      {
398        return r;
399      }
400    }
401
402    for (TemplateLine l : extraLines)
403    {
404      TagResult r = l.generateLine(entry);
405      if (!r.keepProcessingEntry()
406          || !r.keepProcessingParent()
407          || !r.keepProcessingTemplateFile())
408      {
409        return r;
410      }
411    }
412
413    if (! entryWriter.writeEntry(entry))
414    {
415      return TagResult.STOP_PROCESSING;
416    }
417
418
419    for (int i=0; i < subordinateTemplates.length; i++)
420    {
421      TagResult r =
422           subordinateTemplates[i].writeEntries(entryWriter, branchDN,
423                                                numEntriesPerTemplate[i]);
424      if (!r.keepProcessingParent()
425          || !r.keepProcessingTemplateFile())
426      {
427        if (r.keepProcessingTemplateFile())
428        {
429          // We don't want to propagate a "stop processing parent" all the way
430          // up the chain.
431          return TagResult.SUCCESS_RESULT;
432        }
433
434        return r;
435      }
436    }
437
438    return TagResult.SUCCESS_RESULT;
439  }
440}
441