View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *
10   *    https://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   *
19   */
20  package org.apache.directory.api.ldap.model.ldif;
21  
22  
23  import java.io.BufferedReader;
24  import java.io.IOException;
25  import java.io.StringReader;
26  import java.util.ArrayList;
27  
28  import javax.naming.directory.Attributes;
29  import javax.naming.directory.BasicAttributes;
30  
31  import org.apache.directory.api.i18n.I18n;
32  import org.apache.directory.api.ldap.model.entry.Attribute;
33  import org.apache.directory.api.ldap.model.entry.DefaultEntry;
34  import org.apache.directory.api.ldap.model.entry.Entry;
35  import org.apache.directory.api.ldap.model.exception.LdapException;
36  import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
37  import org.apache.directory.api.ldap.model.schema.AttributeType;
38  import org.apache.directory.api.ldap.model.schema.SchemaManager;
39  import org.apache.directory.api.util.Strings;
40  import org.slf4j.Logger;
41  import org.slf4j.LoggerFactory;
42  
43  
44  /**
45   * <pre>
46   *  &lt;ldif-file&gt; ::= &quot;version:&quot; &lt;fill&gt; &lt;number&gt; &lt;seps&gt; &lt;dn-spec&gt; &lt;sep&gt;
47   *  &lt;ldif-content-change&gt;
48   *
49   *  &lt;ldif-content-change&gt; ::=
50   *    &lt;number&gt; &lt;oid&gt; &lt;options-e&gt; &lt;value-spec&gt; &lt;sep&gt; &lt;attrval-specs-e&gt;
51   *    &lt;ldif-attrval-record-e&gt; |
52   *    &lt;alpha&gt; &lt;chars-e&gt; &lt;options-e&gt; &lt;value-spec&gt; &lt;sep&gt; &lt;attrval-specs-e&gt;
53   *    &lt;ldif-attrval-record-e&gt; |
54   *    &quot;control:&quot; &lt;fill&gt; &lt;number&gt; &lt;oid&gt; &lt;spaces-e&gt; &lt;criticality&gt;
55   *    &lt;value-spec-e&gt; &lt;sep&gt; &lt;controls-e&gt;
56   *        &quot;changetype:&quot; &lt;fill&gt; &lt;changerecord-type&gt; &lt;ldif-change-record-e&gt; |
57   *    &quot;changetype:&quot; &lt;fill&gt; &lt;changerecord-type&gt; &lt;ldif-change-record-e&gt;
58   *
59   *  &lt;ldif-attrval-record-e&gt; ::= &lt;seps&gt; &lt;dn-spec&gt; &lt;sep&gt; &lt;attributeType&gt;
60   *    &lt;options-e&gt; &lt;value-spec&gt; &lt;sep&gt; &lt;attrval-specs-e&gt;
61   *    &lt;ldif-attrval-record-e&gt; | e
62   *
63   *  &lt;ldif-change-record-e&gt; ::= &lt;seps&gt; &lt;dn-spec&gt; &lt;sep&gt; &lt;controls-e&gt;
64   *    &quot;changetype:&quot; &lt;fill&gt; &lt;changerecord-type&gt; &lt;ldif-change-record-e&gt; | e
65   *
66   *  &lt;dn-spec&gt; ::= &quot;dn:&quot; &lt;fill&gt; &lt;safe-string&gt; | &quot;dn::&quot; &lt;fill&gt; &lt;base64-string&gt;
67   *
68   *  &lt;controls-e&gt; ::= &quot;control:&quot; &lt;fill&gt; &lt;number&gt; &lt;oid&gt; &lt;spaces-e&gt; &lt;criticality&gt;
69   *    &lt;value-spec-e&gt; &lt;sep&gt; &lt;controls-e&gt; | e
70   *
71   *  &lt;criticality&gt; ::= &quot;true&quot; | &quot;false&quot; | e
72   *
73   *  &lt;oid&gt; ::= '.' &lt;number&gt; &lt;oid&gt; | e
74   *
75   *  &lt;attrval-specs-e&gt; ::= &lt;number&gt; &lt;oid&gt; &lt;options-e&gt; &lt;value-spec&gt; &lt;sep&gt;
76   *  &lt;attrval-specs-e&gt; |
77   *    &lt;alpha&gt; &lt;chars-e&gt; &lt;options-e&gt; &lt;value-spec&gt; &lt;sep&gt; &lt;attrval-specs-e&gt; | e
78   *
79   *  &lt;value-spec-e&gt; ::= &lt;value-spec&gt; | e
80   *
81   *  &lt;value-spec&gt; ::= ':' &lt;fill&gt; &lt;safe-string-e&gt; |
82   *    &quot;::&quot; &lt;fill&gt; &lt;base64-chars&gt; |
83   *    &quot;:&lt;&quot; &lt;fill&gt; &lt;url&gt;
84   *
85   *  &lt;attributeType&gt; ::= &lt;number&gt; &lt;oid&gt; | &lt;alpha&gt; &lt;chars-e&gt;
86   *
87   *  &lt;options-e&gt; ::= ';' &lt;char&gt; &lt;chars-e&gt; &lt;options-e&gt; |e
88   *
89   *  &lt;chars-e&gt; ::= &lt;char&gt; &lt;chars-e&gt; |  e
90   *
91   *  &lt;changerecord-type&gt; ::= &quot;add&quot; &lt;sep&gt; &lt;attributeType&gt; &lt;options-e&gt; &lt;value-spec&gt;
92   *  &lt;sep&gt; &lt;attrval-specs-e&gt; |
93   *    &quot;delete&quot; &lt;sep&gt; |
94   *    &quot;modify&quot; &lt;sep&gt; &lt;mod-type&gt; &lt;fill&gt; &lt;attributeType&gt; &lt;options-e&gt; &lt;sep&gt;
95   *    &lt;attrval-specs-e&gt; &lt;sep&gt; '-' &lt;sep&gt; &lt;mod-specs-e&gt; |
96   *    &quot;moddn&quot; &lt;sep&gt; &lt;newrdn&gt; &lt;sep&gt; &quot;deleteoldrdn:&quot; &lt;fill&gt; &lt;0-1&gt; &lt;sep&gt;
97   *    &lt;newsuperior-e&gt; &lt;sep&gt; |
98   *    &quot;modrdn&quot; &lt;sep&gt; &lt;newrdn&gt; &lt;sep&gt; &quot;deleteoldrdn:&quot; &lt;fill&gt; &lt;0-1&gt; &lt;sep&gt;
99   *    &lt;newsuperior-e&gt; &lt;sep&gt;
100  *
101  *  &lt;newrdn&gt; ::= ':' &lt;fill&gt; &lt;safe-string&gt; | &quot;::&quot; &lt;fill&gt; &lt;base64-chars&gt;
102  *
103  *  &lt;newsuperior-e&gt; ::= &quot;newsuperior&quot; &lt;newrdn&gt; | e
104  *
105  *  &lt;mod-specs-e&gt; ::= &lt;mod-type&gt; &lt;fill&gt; &lt;attributeType&gt; &lt;options-e&gt;
106  *    &lt;sep&gt; &lt;attrval-specs-e&gt; &lt;sep&gt; '-' &lt;sep&gt; &lt;mod-specs-e&gt; | e
107  *
108  *  &lt;mod-type&gt; ::= &quot;add:&quot; | &quot;delete:&quot; | &quot;replace:&quot;
109  *
110  *  &lt;url&gt; ::= &lt;a Uniform Resource Locator, as defined in [6]&gt;
111  *
112  *
113  *
114  *  LEXICAL
115  *  -------
116  *
117  *  &lt;fill&gt;           ::= ' ' &lt;fill&gt; | e
118  *  &lt;char&gt;           ::= &lt;alpha&gt; | &lt;digit&gt; | '-'
119  *  &lt;number&gt;         ::= &lt;digit&gt; &lt;digits&gt;
120  *  &lt;0-1&gt;            ::= '0' | '1'
121  *  &lt;digits&gt;         ::= &lt;digit&gt; &lt;digits&gt; | e
122  *  &lt;digit&gt;          ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
123  *  &lt;seps&gt;           ::= &lt;sep&gt; &lt;seps-e&gt;
124  *  &lt;seps-e&gt;         ::= &lt;sep&gt; &lt;seps-e&gt; | e
125  *  &lt;sep&gt;            ::= 0x0D 0x0A | 0x0A
126  *  &lt;spaces&gt;         ::= ' ' &lt;spaces-e&gt;
127  *  &lt;spaces-e&gt;       ::= ' ' &lt;spaces-e&gt; | e
128  *  &lt;safe-string-e&gt;  ::= &lt;safe-string&gt; | e
129  *  &lt;safe-string&gt;    ::= &lt;safe-init-char&gt; &lt;safe-chars&gt;
130  *  &lt;safe-init-char&gt; ::= [0x01-0x09] | 0x0B | 0x0C | [0x0E-0x1F] | [0x21-0x39] | 0x3B | [0x3D-0x7F]
131  *  &lt;safe-chars&gt;     ::= &lt;safe-char&gt; &lt;safe-chars&gt; | e
132  *  &lt;safe-char&gt;      ::= [0x01-0x09] | 0x0B | 0x0C | [0x0E-0x7F]
133  *  &lt;base64-string&gt;  ::= &lt;base64-char&gt; &lt;base64-chars&gt;
134  *  &lt;base64-chars&gt;   ::= &lt;base64-char&gt; &lt;base64-chars&gt; | e
135  *  &lt;base64-char&gt;    ::= 0x2B | 0x2F | [0x30-0x39] | 0x3D | [0x41-9x5A] | [0x61-0x7A]
136  *  &lt;alpha&gt;          ::= [0x41-0x5A] | [0x61-0x7A]
137  *
138  *  COMMENTS
139  *  --------
140  *  - The ldap-oid VN is not correct in the RFC-2849. It has been changed from 1*DIGIT 0*1(&quot;.&quot; 1*DIGIT) to
141  *  DIGIT+ (&quot;.&quot; DIGIT+)*
142  *  - The mod-spec lacks a sep between *attrval-spec and &quot;-&quot;.
143  *  - The BASE64-UTF8-STRING should be BASE64-CHAR BASE64-STRING
144  *  - The ValueSpec rule must accept multilines values. In this case, we have a LF followed by a
145  *  single space before the continued value.
146  * </pre>
147  *
148  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
149  */
150 public class LdifAttributesReader extends LdifReader
151 {
152     /** A logger */
153     private static final Logger LOG = LoggerFactory.getLogger( LdifAttributesReader.class );
154 
155 
156     /**
157      * Constructors
158      */
159     public LdifAttributesReader()
160     {
161         super();
162         lines = new ArrayList<String>();
163         position = 0;
164         version = DEFAULT_VERSION;
165     }
166 
167 
168     /**
169      * Parse an AttributeType/AttributeValue
170      *
171      * @param attributes The entry where to store the value
172      * @param line The line to parse
173      * @param lowerLine The same line, lowercased
174      * @throws LdapLdifException If anything goes wrong
175      */
176     private void parseAttribute( Attributes attributes, String line, String lowerLine ) throws LdapLdifException
177     {
178         int colonIndex = line.indexOf( ':' );
179 
180         String attributeType = lowerLine.substring( 0, colonIndex );
181 
182         // We should *not* have a Dn twice
183         if ( "dn".equals( attributeType ) )
184         {
185             LOG.error( I18n.err( I18n.ERR_13400_ENTRY_WITH_TWO_DNS ) );
186             throw new LdapLdifException( I18n.err( I18n.ERR_13439_LDIF_ENTRY_WITH_TWO_DNS ) );
187         }
188 
189         Object attributeValue = parseValue( attributeType, line, colonIndex );
190 
191         // Update the entry
192         javax.naming.directory.Attribute attribute = attributes.get( attributeType );
193 
194         if ( attribute == null )
195         {
196             attributes.put( attributeType, attributeValue );
197         }
198         else
199         {
200             attribute.add( attributeValue );
201         }
202     }
203 
204 
205     /**
206      * Parse an AttributeType/AttributeValue
207      *
208      * @param schemaManager The SchemaManager
209      * @param entry The entry where to store the value
210      * @param line The line to parse
211      * @param lowerLine The same line, lowercased
212      * @throws LdapLdifException If anything goes wrong
213      */
214     private void parseEntryAttribute( SchemaManager schemaManager, Entry entry, String line, String lowerLine )
215         throws LdapLdifException
216     {
217         int colonIndex = line.indexOf( ':' );
218 
219         String attributeName = lowerLine.substring( 0, colonIndex );
220         AttributeType attributeType = null;
221 
222         // We should *not* have a Dn twice
223         if ( "dn".equals( attributeName ) )
224         {
225             LOG.error( I18n.err( I18n.ERR_13400_ENTRY_WITH_TWO_DNS ) );
226             throw new LdapLdifException( I18n.err( I18n.ERR_13439_LDIF_ENTRY_WITH_TWO_DNS ) );
227         }
228 
229         if ( schemaManager != null )
230         {
231             attributeType = schemaManager.getAttributeType( attributeName );
232 
233             if ( attributeType == null )
234             {
235                 String msg = I18n.err( I18n.ERR_13475_UNKNOWN_ATTRIBUTETYPE,  attributeName );
236                 LOG.error( msg );
237                 throw new LdapLdifException( msg );
238             }
239         }
240 
241         Object attributeValue = parseValue( attributeName, line, colonIndex );
242 
243         // Update the entry
244         Attribute attribute;
245 
246         if ( schemaManager == null )
247         {
248             attribute = entry.get( attributeName );
249         }
250         else
251         {
252             attribute = entry.get( attributeType );
253         }
254 
255         if ( attribute == null )
256         {
257             if ( schemaManager == null )
258             {
259                 if ( attributeValue instanceof String )
260                 {
261                     entry.put( attributeName, ( String ) attributeValue );
262                 }
263                 else
264                 {
265                     entry.put( attributeName, ( byte[] ) attributeValue );
266                 }
267             }
268             else
269             {
270                 try
271                 {
272                     if ( attributeValue instanceof String )
273                     {
274                         entry.put( attributeName, attributeType, ( String ) attributeValue );
275                     }
276                     else
277                     {
278                         entry.put( attributeName, attributeType, ( byte[] ) attributeValue );
279                     }
280                 }
281                 catch ( LdapException le )
282                 {
283                     throw new LdapLdifException( I18n.err( I18n.ERR_13460_BAD_ATTRIBUTE ), le );
284                 }
285             }
286         }
287         else
288         {
289             try
290             {
291                 if ( attributeValue instanceof String )
292                 {
293                     attribute.add( ( String ) attributeValue );
294                 }
295                 else
296                 {
297                     attribute.add( ( byte[] ) attributeValue );
298                 }
299             }
300             catch ( LdapInvalidAttributeValueException liave )
301             {
302                 throw new LdapLdifException( liave.getMessage(), liave );
303             }
304         }
305     }
306 
307 
308     /**
309      * Parse a ldif file. The following rules are processed :
310      *
311      * &lt;ldif-file&gt; ::= &lt;ldif-attrval-record&gt; &lt;ldif-attrval-records&gt; |
312      * &lt;ldif-change-record&gt; &lt;ldif-change-records&gt; &lt;ldif-attrval-record&gt; ::=
313      * &lt;dn-spec&gt; &lt;sep&gt; &lt;attrval-spec&gt; &lt;attrval-specs&gt; &lt;ldif-change-record&gt; ::=
314      * &lt;dn-spec&gt; &lt;sep&gt; &lt;controls-e&gt; &lt;changerecord&gt; &lt;dn-spec&gt; ::= "dn:" &lt;fill&gt;
315      * &lt;distinguishedName&gt; | "dn::" &lt;fill&gt; &lt;base64-distinguishedName&gt;
316      * &lt;changerecord&gt; ::= "changetype:" &lt;fill&gt; &lt;change-op&gt;
317      *
318      * @param schemaManager The SchemaManager
319      * @return The read entry
320      * @throws LdapLdifException If the entry can't be read or is invalid
321      */
322     private Entry parseEntry( SchemaManager schemaManager ) throws LdapLdifException
323     {
324         if ( ( lines == null ) || lines.isEmpty() )
325         {
326             if ( LOG.isDebugEnabled() )
327             {
328                 LOG.debug( I18n.msg( I18n.MSG_13408_END_OF_LDIF ) );
329             }
330             
331             return null;
332         }
333 
334         Entry entry = new DefaultEntry( schemaManager );
335 
336         // Now, let's iterate through the other lines
337         for ( String line : lines )
338         {
339             // Each line could start either with an OID, an attribute type, with
340             // "control:" or with "changetype:"
341             String lowerLine = Strings.toLowerCaseAscii( line );
342 
343             // We have three cases :
344             // 1) The first line after the Dn is a "control:" -> this is an error
345             // 2) The first line after the Dn is a "changeType:" -> this is an error
346             // 3) The first line after the Dn is anything else
347             if ( lowerLine.startsWith( "control:" ) )
348             {
349                 LOG.error( I18n.err( I18n.ERR_13401_CHANGE_NOT_ALLOWED ) );
350                 throw new LdapLdifException( I18n.err( I18n.ERR_13440_NO_CHANGE ) );
351             }
352             else if ( lowerLine.startsWith( "changetype:" ) )
353             {
354                 LOG.error( I18n.err( I18n.ERR_13401_CHANGE_NOT_ALLOWED ) );
355                 throw new LdapLdifException( I18n.err( I18n.ERR_13440_NO_CHANGE ) );
356             }
357             else if ( line.indexOf( ':' ) > 0 )
358             {
359                 parseEntryAttribute( schemaManager, entry, line, lowerLine );
360             }
361             else
362             {
363                 // Invalid attribute Value
364                 LOG.error( I18n.err( I18n.ERR_13402_EXPECTING_ATTRIBUTE_TYPE ) );
365                 throw new LdapLdifException( I18n.err( I18n.ERR_13441_BAD_ATTRIBUTE ) );
366             }
367         }
368 
369         if ( LOG.isDebugEnabled() )
370         {
371             LOG.debug( I18n.msg( I18n.MSG_13405_READ_ATTR, entry ) );
372         }
373 
374         return entry;
375     }
376 
377 
378     /**
379      * Parse a ldif file. The following rules are processed :
380      *
381      * <pre>
382      * &lt;ldif-file&gt; ::= &lt;ldif-attrval-record&gt; &lt;ldif-attrval-records&gt; |
383      * &lt;ldif-change-record&gt; &lt;ldif-change-records&gt; &lt;ldif-attrval-record&gt; ::=
384      * &lt;dn-spec&gt; &lt;sep&gt; &lt;attrval-spec&gt; &lt;attrval-specs&gt; &lt;ldif-change-record&gt; ::=
385      * &lt;dn-spec&gt; &lt;sep&gt; &lt;controls-e&gt; &lt;changerecord&gt; &lt;dn-spec&gt; ::= "dn:" &lt;fill&gt;
386      * &lt;distinguishedName&gt; | "dn::" &lt;fill&gt; &lt;base64-distinguishedName&gt;
387      * &lt;changerecord&gt; ::= "changetype:" &lt;fill&gt; &lt;change-op&gt;
388      * </pre>
389      * 
390      * @return The read entry
391      * @throws LdapLdifException If the entry can't be read or is invalid
392      */
393     private Attributes parseAttributes() throws LdapLdifException
394     {
395         if ( ( lines == null ) || lines.isEmpty() )
396         {
397             if ( LOG.isDebugEnabled() )
398             {
399                 LOG.debug( I18n.msg( I18n.MSG_13408_END_OF_LDIF ) );
400             }
401 
402             return null;
403         }
404 
405         Attributes attributes = new BasicAttributes( true );
406 
407         // Now, let's iterate through the other lines
408         for ( String line : lines )
409         {
410             // Each line could start either with an OID, an attribute type, with
411             // "control:" or with "changetype:"
412             String lowerLine = Strings.toLowerCaseAscii( line );
413 
414             // We have three cases :
415             // 1) The first line after the Dn is a "control:" -> this is an error
416             // 2) The first line after the Dn is a "changeType:" -> this is an error
417             // 3) The first line after the Dn is anything else
418             if ( lowerLine.startsWith( "control:" ) )
419             {
420                 LOG.error( I18n.err( I18n.ERR_13401_CHANGE_NOT_ALLOWED ) );
421                 throw new LdapLdifException( I18n.err( I18n.ERR_13440_NO_CHANGE ) );
422             }
423             else if ( lowerLine.startsWith( "changetype:" ) )
424             {
425                 LOG.error( I18n.err( I18n.ERR_13401_CHANGE_NOT_ALLOWED ) );
426                 throw new LdapLdifException( I18n.err( I18n.ERR_13440_NO_CHANGE ) );
427             }
428             else if ( line.indexOf( ':' ) > 0 )
429             {
430                 parseAttribute( attributes, line, lowerLine );
431             }
432             else
433             {
434                 // Invalid attribute Value
435                 LOG.error( I18n.err( I18n.ERR_13402_EXPECTING_ATTRIBUTE_TYPE ) );
436                 throw new LdapLdifException( I18n.err( I18n.ERR_13441_BAD_ATTRIBUTE ) );
437             }
438         }
439 
440         if ( LOG.isDebugEnabled() )
441         {
442             LOG.debug( I18n.msg( I18n.MSG_13405_READ_ATTR, attributes ) );
443         }
444 
445         return attributes;
446     }
447 
448 
449     /**
450      * A method which parses a ldif string and returns a list of Attributes.
451      *
452      * @param ldif The ldif string
453      * @return A list of Attributes, or an empty List
454      * @throws LdapLdifException If something went wrong
455      */
456     public Attributes parseAttributes( String ldif ) throws LdapLdifException
457     {
458         lines = new ArrayList<String>();
459         position = 0;
460 
461         if ( LOG.isDebugEnabled() )
462         {
463             LOG.debug( I18n.msg( I18n.MSG_13407_STARTS_PARSING_LDIF ) );
464         }
465 
466         if ( Strings.isEmpty( ldif ) )
467         {
468             return new BasicAttributes( true );
469         }
470 
471         StringReader strIn = new StringReader( ldif );
472         reader = new BufferedReader( strIn );
473 
474         try
475         {
476             readLines();
477 
478             Attributes attributes = parseAttributes();
479 
480             if ( LOG.isDebugEnabled() )
481             {
482                 if ( attributes == null )
483                 {
484                     LOG.debug( I18n.msg( I18n.MSG_13401_PARSED_NO_ENTRY ) );
485                 }
486                 else
487                 {
488                     LOG.debug( I18n.msg( I18n.MSG_13402_PARSED_ONE_ENTRY ) );
489                 }
490             }
491 
492             return attributes;
493         }
494         catch ( LdapLdifException ne )
495         {
496             LOG.error( I18n.err( I18n.ERR_13403_CANNOT_PARSE_LDIF_BUFFER, ne.getLocalizedMessage() ) );
497             throw new LdapLdifException( I18n.err( I18n.ERR_13442_ERROR_PARSING_LDIF_BUFFER ), ne );
498         }
499         finally
500         {
501             try
502             {
503                 reader.close();
504             }
505             catch ( IOException ioe )
506             {
507                 throw new LdapLdifException( I18n.err( I18n.ERR_13450_CANNOT_CLOSE_FILE ), ioe );
508             }
509         }
510     }
511 
512 
513     /**
514      * A method which parses a ldif string and returns an Entry.
515      *
516      * @param ldif The ldif string
517      * @return An entry
518      * @throws LdapLdifException If something went wrong
519      */
520     public Entry parseEntry( String ldif ) throws LdapLdifException
521     {
522         lines = new ArrayList<String>();
523         position = 0;
524 
525         if ( LOG.isDebugEnabled() )
526         {
527             LOG.debug( I18n.msg( I18n.MSG_13407_STARTS_PARSING_LDIF ) );
528         }
529 
530         if ( Strings.isEmpty( ldif ) )
531         {
532             return new DefaultEntry();
533         }
534 
535         StringReader strIn = new StringReader( ldif );
536         reader = new BufferedReader( strIn );
537 
538         try
539         {
540             readLines();
541 
542             Entry entry = parseEntry( ( SchemaManager ) null );
543 
544             if ( LOG.isDebugEnabled() )
545             {
546                 if ( entry == null )
547                 {
548                     LOG.debug( I18n.msg( I18n.MSG_13401_PARSED_NO_ENTRY ) );
549                 }
550                 else
551                 {
552                     LOG.debug( I18n.msg( I18n.MSG_13402_PARSED_ONE_ENTRY ) );
553                 }
554             }
555 
556             return entry;
557         }
558         catch ( LdapLdifException ne )
559         {
560             LOG.error( I18n.err( I18n.ERR_13403_CANNOT_PARSE_LDIF_BUFFER, ne.getLocalizedMessage() ) );
561             throw new LdapLdifException( I18n.err( I18n.ERR_13442_ERROR_PARSING_LDIF_BUFFER ), ne );
562         }
563         finally
564         {
565             try
566             {
567                 reader.close();
568             }
569             catch ( IOException ioe )
570             {
571                 throw new LdapLdifException( I18n.err( I18n.ERR_13450_CANNOT_CLOSE_FILE ), ioe );
572             }
573         }
574     }
575 
576 
577     /**
578      * A method which parses a ldif string and returns an Entry.
579      *
580      * @param schemaManager The SchemaManager
581      * @param ldif The ldif string
582      * @return An entry
583      * @throws LdapLdifException If something went wrong
584      */
585     public Entry parseEntry( SchemaManager schemaManager, String ldif ) throws LdapLdifException
586     {
587         lines = new ArrayList<String>();
588         position = 0;
589 
590         if ( LOG.isDebugEnabled() )
591         {
592             LOG.debug( I18n.msg( I18n.MSG_13407_STARTS_PARSING_LDIF ) );
593         }
594 
595         if ( Strings.isEmpty( ldif ) )
596         {
597             return new DefaultEntry( schemaManager );
598         }
599 
600         StringReader strIn = new StringReader( ldif );
601         reader = new BufferedReader( strIn );
602 
603         try
604         {
605             readLines();
606 
607             Entry entry = parseEntry( schemaManager );
608 
609             if ( LOG.isDebugEnabled() )
610             {
611                 if ( entry == null )
612                 {
613                     LOG.debug( I18n.msg( I18n.MSG_13401_PARSED_NO_ENTRY ) );
614                 }
615                 else
616                 {
617                     LOG.debug( I18n.msg( I18n.MSG_13402_PARSED_ONE_ENTRY ) );
618                 }
619 
620             }
621 
622             return entry;
623         }
624         catch ( LdapLdifException ne )
625         {
626             LOG.error( I18n.err( I18n.ERR_13403_CANNOT_PARSE_LDIF_BUFFER, ne.getLocalizedMessage() ) );
627             throw new LdapLdifException( I18n.err( I18n.ERR_13442_ERROR_PARSING_LDIF_BUFFER ), ne );
628         }
629         finally
630         {
631             try
632             {
633                 reader.close();
634             }
635             catch ( IOException ioe )
636             {
637                 throw new LdapLdifException( I18n.err( I18n.ERR_13450_CANNOT_CLOSE_FILE ), ioe );
638             }
639         }
640     }
641 }