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