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.server.util.LDIFWriter.*;
020
021import java.io.BufferedWriter;
022import java.io.IOException;
023import java.util.ArrayList;
024import java.util.LinkedHashMap;
025import java.util.List;
026
027import org.forgerock.opendj.ldap.AVA;
028import org.forgerock.opendj.ldap.ByteString;
029import org.forgerock.opendj.ldap.DN;
030import org.forgerock.opendj.ldap.RDN;
031import org.forgerock.opendj.ldap.schema.AttributeType;
032import org.forgerock.opendj.ldap.schema.ObjectClass;
033import org.opends.server.core.DirectoryServer;
034import org.opends.server.types.Attribute;
035import org.opends.server.types.AttributeBuilder;
036import org.opends.server.types.LDIFExportConfig;
037import org.opends.server.util.LDIFException;
038
039/**
040 * This class defines an entry that is generated using a MakeLDIF branch or
041 * template.
042 */
043public class TemplateEntry
044{
045  /** The branch used to generate this entry (if it is associated with a branch). */
046  private final Branch branch;
047  /** The DN for this template entry, if it is known. */
048  private DN dn;
049  /** The DN of the parent entry for this template entry, if it is available. */
050  private final DN parentDN;
051
052  /**
053   * The set of attributes associated with this template entry, mapped from the
054   * lowercase name of the attribute to the list of generated values.
055   */
056  private final LinkedHashMap<AttributeType, ArrayList<TemplateValue>> attributes = new LinkedHashMap<>();
057
058  /** The template used to generate this entry (if it is associated with a template). */
059  private final Template template;
060
061
062  /**
063   * Creates a new template entry that will be associated with the provided
064   * branch.
065   *
066   * @param  branch  The branch to use when creating this template entry.
067   */
068  public TemplateEntry(Branch branch)
069  {
070    this.branch = branch;
071    dn         = branch.getBranchDN();
072    template = null;
073    parentDN = null;
074  }
075
076
077
078  /**
079   * Creates a new template entry that will be associated with the provided
080   * template.
081   *
082   * @param  template  The template used to generate this entry.
083   * @param  parentDN  The DN of the parent entry for this template entry.
084   */
085  public TemplateEntry(Template template, DN parentDN)
086  {
087    this.branch = null;
088    dn = null;
089    this.template = template;
090    this.parentDN = parentDN;
091  }
092
093
094
095  /**
096   * Retrieves the branch used to generate this entry.
097   *
098   * @return  The branch used to generate this entry, or <CODE>null</CODE> if it
099   *          is associated with a template instead of a branch.
100   */
101  public Branch getBranch()
102  {
103    return branch;
104  }
105
106
107
108  /**
109   * Retrieves the template used to generate this entry.
110   *
111   * @return  The template used to generate this entry, or <CODE>null</CODE> if
112   *          it is associated with a branch instead of a template.
113   */
114  public Template getTemplate()
115  {
116    return template;
117  }
118
119
120
121  /**
122   * Retrieves the DN of the parent entry for this template entry.
123   *
124   * @return  The DN of the parent entry for this template entry, or
125   *          <CODE>null</CODE> if there is no parent DN.
126   */
127  public DN getParentDN()
128  {
129    return parentDN;
130  }
131
132
133
134  /**
135   * Retrieves the DN for this template entry, if it is known.
136   *
137   * @return  The DN for this template entry if it is known, or
138   *          <CODE>null</CODE> if it cannot yet be determined.
139   */
140  public DN getDN()
141  {
142    if (dn == null)
143    {
144      AttributeType[] rdnAttrs = template.getRDNAttributes();
145      AVA[] avas = new AVA[rdnAttrs.length];
146      for (int i = 0; i < rdnAttrs.length; i++)
147      {
148        AttributeType t = rdnAttrs[i];
149        TemplateValue v = getValue(t);
150        if (v == null)
151        {
152          return null;
153        }
154        avas[i] = new AVA(t, v.getValue());
155      }
156
157      dn = parentDN.child(new RDN(avas));
158    }
159
160    return dn;
161  }
162
163  /**
164   * Retrieves the value for the specified attribute, if defined.  If the
165   * specified attribute has multiple values, then the first will be returned.
166   *
167   * @param  attributeType  The attribute type for which to retrieve the value.
168   *
169   * @return  The value for the specified attribute, or <CODE>null</CODE> if
170   *          there are no values for that attribute type.
171   */
172  public TemplateValue getValue(AttributeType attributeType)
173  {
174    ArrayList<TemplateValue> valueList = attributes.get(attributeType);
175    if (valueList != null && !valueList.isEmpty())
176    {
177      return valueList.get(0);
178    }
179    return null;
180  }
181
182
183
184  /**
185   * Retrieves the set of values for the specified attribute, if defined.
186   *
187   * @param  attributeType  The attribute type for which to retrieve the set of
188   *                        values.
189   *
190   * @return  The set of values for the specified attribute, or
191   *          <CODE>null</CODE> if there are no values for that attribute type.
192   */
193  public List<TemplateValue> getValues(AttributeType attributeType)
194  {
195    return attributes.get(attributeType);
196  }
197
198
199
200  /**
201   * Adds the provided template value to this entry.
202   *
203   * @param  value  The value to add to this entry.
204   */
205  public void addValue(TemplateValue value)
206  {
207    ArrayList<TemplateValue> valueList = attributes.get(value.getAttributeType());
208    if (valueList == null)
209    {
210      valueList = new ArrayList<>();
211      attributes.put(value.getAttributeType(), valueList);
212    }
213    valueList.add(value);
214  }
215
216
217  /**
218   * Writes this entry in LDIF form.  No filtering will be
219   * performed for this entry, nor will any export plugins be invoked.
220   *
221   * @param  exportConfig  The configuration that specifies how the
222   *                       entry should be written.
223   *
224   * @return  <CODE>true</CODE> if the entry is actually written, or
225   *          <CODE>false</CODE> if it is not for some reason.
226   *
227   * @throws  IOException  If a problem occurs while writing the
228   *                       information.
229   *
230   * @throws  LDIFException  If a problem occurs while trying to
231   *                         determine whether to write the entry.
232   */
233  public boolean toLDIF(LDIFExportConfig exportConfig)
234         throws IOException, LDIFException
235  {
236    // Process all of the attributes for this entry.
237    LinkedHashMap<ObjectClass,String> objectClasses = new LinkedHashMap<>();
238    LinkedHashMap<AttributeType,List<Attribute>> userAttributes = new LinkedHashMap<>();
239    LinkedHashMap<AttributeType,List<Attribute>> operationalAttributes = new LinkedHashMap<>();
240    LinkedHashMap<AttributeType, List<Attribute>> urlAttributes = new LinkedHashMap<>();
241    LinkedHashMap<AttributeType, List<Attribute>> base64Attributes = new LinkedHashMap<>();
242
243    for (AttributeType t : attributes.keySet())
244    {
245      ArrayList<TemplateValue> valueList = attributes.get(t);
246      if (t.isObjectClass())
247      {
248        for (TemplateValue v : valueList)
249        {
250          String ocName = v.getValue().toString();
251          objectClasses.put(DirectoryServer.getSchema().getObjectClass(ocName), ocName);
252        }
253      }
254      else if (t.isOperational())
255      {
256        AttributeBuilder builder = new AttributeBuilder(t);
257        for (TemplateValue v : valueList)
258        {
259          builder.add(v.getValue().toString());
260        }
261
262        operationalAttributes.put(t, builder.toAttributeList());
263      }
264      else
265      {
266        AttributeBuilder builder = new AttributeBuilder(t);
267        AttributeBuilder urlBuilder = null;
268        AttributeBuilder base64Builder = null;
269        for (TemplateValue v : valueList)
270        {
271          ByteString value = ByteString.valueOfUtf8(v.getValue().toString());
272          builder.add(value);
273          if (v.getTemplateLine().isURL())
274          {
275            if (urlBuilder == null)
276            {
277              urlBuilder = new AttributeBuilder(t);
278            }
279            urlBuilder.add(value);
280          }
281          else if (v.getTemplateLine().isBase64())
282          {
283            if (base64Builder == null)
284            {
285              base64Builder = new AttributeBuilder(t);
286            }
287            base64Builder.add(value);
288          }
289        }
290
291        userAttributes.put(t, builder.toAttributeList());
292        if (urlBuilder != null)
293        {
294          urlAttributes.put(t, urlBuilder.toAttributeList());
295        }
296        if (base64Builder != null)
297        {
298          base64Attributes.put(t, base64Builder.toAttributeList());
299        }
300      }
301    }
302
303    // Get the information necessary to write the LDIF.
304    BufferedWriter writer     = exportConfig.getWriter();
305    int            wrapColumn = exportConfig.getWrapColumn();
306    boolean        wrapLines  = wrapColumn > 1;
307
308
309    // First, write the DN.  It will always be included.
310    StringBuilder dnLine = new StringBuilder("dn");
311    appendLDIFSeparatorAndValue(dnLine,
312        ByteString.valueOfUtf8(getDN().toString()));
313    writeLDIFLine(dnLine, writer, wrapLines, wrapColumn);
314
315
316    // Next, the set of objectclasses.
317    final boolean typesOnly = exportConfig.typesOnly();
318    if (exportConfig.includeObjectClasses())
319    {
320      if (typesOnly)
321      {
322        StringBuilder ocLine = new StringBuilder("objectClass:");
323        writeLDIFLine(ocLine, writer, wrapLines, wrapColumn);
324      }
325      else
326      {
327        for (String s : objectClasses.values())
328        {
329          StringBuilder ocLine = new StringBuilder("objectClass: ").append(s);
330          writeLDIFLine(ocLine, writer, wrapLines, wrapColumn);
331        }
332      }
333    }
334
335
336    // Now the set of user attributes.
337    for (AttributeType attrType : userAttributes.keySet())
338    {
339      if (exportConfig.includeAttribute(attrType))
340      {
341        for (Attribute a : userAttributes.get(attrType))
342        {
343          if (a.isVirtual() && !exportConfig.includeVirtualAttributes())
344          {
345            continue;
346          }
347
348          String attrName = a.getAttributeDescription().toString();
349          if (typesOnly)
350          {
351            StringBuilder attrLine = new StringBuilder(attrName);
352            attrLine.append(":");
353
354            writeLDIFLine(attrLine, writer, wrapLines, wrapColumn);
355          }
356          else
357          {
358            List<Attribute> urlAttrList = urlAttributes.get(attrType);
359            List<Attribute> base64AttrList = base64Attributes.get(attrType);
360
361            for (ByteString v : a)
362            {
363              StringBuilder attrLine = new StringBuilder(attrName);
364              boolean isURLValue = contains(urlAttrList, v);
365              boolean isBase64Value = contains(base64AttrList, v);
366              appendLDIFSeparatorAndValue(attrLine,
367                                          v,
368                                          isURLValue,
369                                          isBase64Value);
370              writeLDIFLine(attrLine, writer, wrapLines, wrapColumn);
371            }
372          }
373        }
374      }
375    }
376
377
378    // Next, the set of operational attributes.
379    if (exportConfig.includeOperationalAttributes())
380    {
381      for (AttributeType attrType : operationalAttributes.keySet())
382      {
383        if (exportConfig.includeAttribute(attrType))
384        {
385          for (Attribute a : operationalAttributes.get(attrType))
386          {
387            if (a.isVirtual() && !exportConfig.includeVirtualAttributes())
388            {
389              continue;
390            }
391
392            String attrName = a.getAttributeDescription().toString();
393            if (typesOnly)
394            {
395              StringBuilder attrLine = new StringBuilder(attrName);
396              attrLine.append(":");
397
398              writeLDIFLine(attrLine, writer, wrapLines, wrapColumn);
399            }
400            else
401            {
402              for (ByteString v : a)
403              {
404                StringBuilder attrLine = new StringBuilder(attrName);
405                appendLDIFSeparatorAndValue(attrLine, v);
406                writeLDIFLine(attrLine, writer, wrapLines, wrapColumn);
407              }
408            }
409          }
410        }
411      }
412    }
413
414    // Make sure there is a blank line after the entry.
415    writer.newLine();
416
417    return true;
418  }
419
420  private boolean contains(List<Attribute> urlAttrList, ByteString v)
421  {
422    if (urlAttrList != null)
423    {
424      for (Attribute urlAttr : urlAttrList)
425      {
426        for (ByteString urlValue : urlAttr)
427        {
428          if (urlValue.equals(v))
429          {
430            return true;
431          }
432        }
433      }
434    }
435    return false;
436  }
437}