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