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