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