directory-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From elecha...@apache.org
Subject svn commit: r903465 [3/5] - in /directory/shared/trunk/ldap-ldif: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/directory/ src/main/java/org/apache/directory/shared/ src/main/java/org/apache/dire...
Date Tue, 26 Jan 2010 22:43:29 GMT
Added: directory/shared/trunk/ldap-ldif/src/main/java/org/apache/directory/shared/ldap/ldif/LdifUtils.java
URL: http://svn.apache.org/viewvc/directory/shared/trunk/ldap-ldif/src/main/java/org/apache/directory/shared/ldap/ldif/LdifUtils.java?rev=903465&view=auto
==============================================================================
--- directory/shared/trunk/ldap-ldif/src/main/java/org/apache/directory/shared/ldap/ldif/LdifUtils.java (added)
+++ directory/shared/trunk/ldap-ldif/src/main/java/org/apache/directory/shared/ldap/ldif/LdifUtils.java Tue Jan 26 22:43:27 2010
@@ -0,0 +1,653 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.shared.ldap.ldif;
+
+import java.io.UnsupportedEncodingException;
+
+import javax.naming.NamingException;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.InvalidAttributeValueException;
+
+import org.apache.directory.shared.ldap.entry.Entry;
+import org.apache.directory.shared.ldap.entry.EntryAttribute;
+import org.apache.directory.shared.ldap.entry.Modification;
+import org.apache.directory.shared.ldap.entry.Value;
+import org.apache.directory.shared.ldap.entry.client.DefaultClientAttribute;
+import org.apache.directory.shared.ldap.name.LdapDN;
+import org.apache.directory.shared.ldap.util.AttributeUtils;
+import org.apache.directory.shared.ldap.util.Base64;
+import org.apache.directory.shared.ldap.util.StringTools;
+
+
+
+/**
+ * Some LDIF useful methods
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class LdifUtils
+{
+    /** The array that will be used to match the first char.*/
+    private static boolean[] LDIF_SAFE_STARTING_CHAR_ALPHABET = new boolean[128];
+    
+    /** The array that will be used to match the other chars.*/
+    private static boolean[] LDIF_SAFE_OTHER_CHARS_ALPHABET = new boolean[128];
+    
+    /** The default length for a line in a ldif file */
+    private static final int DEFAULT_LINE_LENGTH = 80;
+    
+    static
+    {
+        // Initialization of the array that will be used to match the first char.
+        for (int i = 0; i < 128; i++) 
+        {
+            LDIF_SAFE_STARTING_CHAR_ALPHABET[i] = true;
+        }
+        
+        LDIF_SAFE_STARTING_CHAR_ALPHABET[0] = false; // 0 (NUL)
+        LDIF_SAFE_STARTING_CHAR_ALPHABET[10] = false; // 10 (LF)
+        LDIF_SAFE_STARTING_CHAR_ALPHABET[13] = false; // 13 (CR)
+        LDIF_SAFE_STARTING_CHAR_ALPHABET[32] = false; // 32 (SPACE)
+        LDIF_SAFE_STARTING_CHAR_ALPHABET[58] = false; // 58 (:)
+        LDIF_SAFE_STARTING_CHAR_ALPHABET[60] = false; // 60 (>)
+        
+        // Initialization of the array that will be used to match the other chars.
+        for (int i = 0; i < 128; i++) 
+        {
+            LDIF_SAFE_OTHER_CHARS_ALPHABET[i] = true;
+        }
+        
+        LDIF_SAFE_OTHER_CHARS_ALPHABET[0] = false; // 0 (NUL)
+        LDIF_SAFE_OTHER_CHARS_ALPHABET[10] = false; // 10 (LF)
+        LDIF_SAFE_OTHER_CHARS_ALPHABET[13] = false; // 13 (CR)
+    }
+
+    
+    /**
+     * Checks if the input String contains only safe values, that is, the data
+     * does not need to be encoded for use with LDIF. The rules for checking safety
+     * are based on the rules for LDIF (LDAP Data Interchange Format) per RFC 2849.
+     * The data does not need to be encoded if all the following are true:
+     * 
+     * The data cannot start with the following char values:
+     *         00 (NUL)
+     *         10 (LF)
+     *         13 (CR)
+     *         32 (SPACE)
+     *         58 (:)
+     *         60 (<)
+     *         Any character with value greater than 127
+     * 
+     * The data cannot contain any of the following char values:
+     *         00 (NUL)
+     *         10 (LF)
+     *         13 (CR)
+     *         Any character with value greater than 127
+     * 
+     * The data cannot end with a space.
+     * 
+     * @param str the String to be checked
+     * @return true if encoding not required for LDIF
+     */
+    public static boolean isLDIFSafe( String str )
+    {
+        if ( StringTools.isEmpty( str ) )
+        {
+            // A null string is LDIF safe
+            return true;
+        }
+        
+        // Checking the first char
+        char currentChar = str.charAt(0);
+        
+        if ( ( currentChar > 127 ) || !LDIF_SAFE_STARTING_CHAR_ALPHABET[currentChar] )
+        {
+            return false;
+        }
+        
+        // Checking the other chars
+        for (int i = 1; i < str.length(); i++)
+        {
+            currentChar = str.charAt(i);
+            
+            if ( ( currentChar > 127 ) || !LDIF_SAFE_OTHER_CHARS_ALPHABET[currentChar] )
+            {
+                return false;
+            }
+        }
+        
+        // The String cannot end with a space
+        return ( currentChar != ' ' );
+    }
+    
+    
+    /**
+     * Convert an Attributes as LDIF
+     * @param attrs the Attributes to convert
+     * @return the corresponding LDIF code as a String
+     * @throws NamingException If a naming exception is encountered.
+     */
+    public static String convertToLdif( Attributes attrs ) throws NamingException
+    {
+        return convertAttributesToLdif( AttributeUtils.toClientEntry( attrs, null ), DEFAULT_LINE_LENGTH );
+    }
+    
+    
+    /**
+     * Convert an Attributes as LDIF
+     * @param attrs the Attributes to convert
+     * @return the corresponding LDIF code as a String
+     * @throws NamingException If a naming exception is encountered.
+     */
+    public static String convertToLdif( Attributes attrs, int length ) throws NamingException
+    {
+        return convertAttributesToLdif( AttributeUtils.toClientEntry( attrs, null ), length );
+    }
+    
+    
+    /**
+     * Convert an Attributes as LDIF. The DN is written.
+     * @param attrs the Attributes to convert
+     * @return the corresponding LDIF code as a String
+     * @throws NamingException If a naming exception is encountered.
+     */
+    public static String convertToLdif( Attributes attrs, LdapDN dn, int length ) throws NamingException
+    {
+        return convertEntryToLdif( AttributeUtils.toClientEntry( attrs, dn ), length );
+    }
+    
+    
+    /**
+     * Convert an Attributes as LDIF. The DN is written.
+     * @param attrs the Attributes to convert
+     * @return the corresponding LDIF code as a String
+     * @throws NamingException If a naming exception is encountered.
+     */
+    public static String convertToLdif( Attributes attrs, LdapDN dn ) throws NamingException
+    {
+        return convertEntryToLdif( AttributeUtils.toClientEntry( attrs, dn ), DEFAULT_LINE_LENGTH );
+    }
+    
+    
+    /**
+     * Convert an Entry to LDIF
+     * @param entry the Entry to convert
+     * @return the corresponding LDIF code as a String
+     * @throws NamingException If a naming exception is encountered.
+     */
+    public static String convertEntryToLdif( Entry entry ) throws NamingException
+    {
+        return convertEntryToLdif( entry, DEFAULT_LINE_LENGTH );
+    }
+    
+    
+    /**
+     * Convert all the Entry's attributes to LDIF. The DN is not written
+     * @param entry the Entry to convert
+     * @return the corresponding LDIF code as a String
+     * @throws NamingException If a naming exception is encountered.
+     */
+    public static String convertAttributesToLdif( Entry entry ) throws NamingException
+    {
+        return convertAttributesToLdif( entry, DEFAULT_LINE_LENGTH );
+    }
+    
+    
+    /**
+     * Convert a LDIF String to an attributes.
+     * 
+     * @param ldif The LDIF string containing an attribute value
+     * @return An Attributes instance
+     * @exception NamingException If the LDIF String cannot be converted to an Attributes
+     */
+    public static Attributes convertAttributesFromLdif( String ldif ) throws NamingException
+    {
+        LdifAttributesReader reader = new  LdifAttributesReader();
+        
+        return reader.parseAttributes( ldif );
+    }
+    
+    
+    /**
+     * Convert an Entry as LDIF
+     * @param entry the Entry to convert
+     * @param length the expected line length
+     * @return the corresponding LDIF code as a String
+     * @throws NamingException If a naming exception is encountered.
+     */
+    public static String convertEntryToLdif( Entry entry, int length ) throws NamingException
+    {
+        StringBuilder sb = new StringBuilder();
+        
+        if ( entry.getDn() != null )
+        {
+            // First, dump the DN
+            if ( isLDIFSafe( entry.getDn().getName() ) )
+            {
+                sb.append( stripLineToNChars( "dn: " + entry.getDn().getName(), length ) );
+            }
+            else
+            {
+                sb.append( stripLineToNChars( "dn:: " + encodeBase64( entry.getDn().getName() ), length ) );
+            }
+        
+            sb.append( '\n' );
+        }
+
+        // Then all the attributes
+        for ( EntryAttribute attribute:entry )
+        {
+            sb.append( convertToLdif( attribute, length ) );
+        }
+        
+        return sb.toString();
+    }
+    
+    
+    /**
+     * Convert the Entry's attributes to LDIF. The DN is not written.
+     * @param entry the Entry to convert
+     * @param length the expected line length
+     * @return the corresponding LDIF code as a String
+     * @throws NamingException If a naming exception is encountered.
+     */
+    public static String convertAttributesToLdif( Entry entry, int length ) throws NamingException
+    {
+        StringBuilder sb = new StringBuilder();
+        
+        // Then all the attributes
+        for ( EntryAttribute attribute:entry )
+        {
+            sb.append( convertToLdif( attribute, length ) );
+        }
+        
+        return sb.toString();
+    }
+
+    
+    /**
+     * Convert an LdifEntry to LDIF
+     * @param entry the LdifEntry to convert
+     * @return the corresponding LDIF as a String
+     * @throws NamingException If a naming exception is encountered.
+     */
+    public static String convertToLdif( LdifEntry entry ) throws NamingException
+    {
+        return convertToLdif( entry, DEFAULT_LINE_LENGTH );
+    }
+
+    
+    /**
+     * Convert an LdifEntry to LDIF
+     * @param entry the LdifEntry to convert
+     * @param length The maximum line's length 
+     * @return the corresponding LDIF as a String
+     * @throws NamingException If a naming exception is encountered.
+     */
+    public static String convertToLdif( LdifEntry entry, int length ) throws NamingException
+    {
+        StringBuilder sb = new StringBuilder();
+        
+        // First, dump the DN
+        if ( isLDIFSafe( entry.getDn().getName() ) )
+        {
+            sb.append( stripLineToNChars( "dn: " + entry.getDn(), length ) );
+        }
+        else
+        {
+            sb.append( stripLineToNChars( "dn:: " + encodeBase64( entry.getDn().getName() ), length ) );
+        }
+        
+        sb.append( '\n' );
+        
+        // Dump the ChangeType
+        String changeType = entry.getChangeType().toString().toLowerCase();
+        sb.append( stripLineToNChars( "changetype: " + changeType, length ) );
+        
+        sb.append( '\n' );
+
+        switch ( entry.getChangeType() )
+        {
+            case Delete :
+                if ( entry.getEntry() != null )
+                {
+                    throw new NamingException( "Invalid Entry : a deleted entry should not contain attributes" );
+                }
+                
+                break;
+                
+            case Add :
+                if ( ( entry.getEntry() == null ) )
+                {
+                    throw new NamingException( "Invalid Entry : a added or modified entry should contain attributes" );
+                }
+
+                // Now, iterate through all the attributes
+                for ( EntryAttribute attribute:entry.getEntry() )
+                {
+                    sb.append( convertToLdif( attribute, length ) );
+                }
+                
+                break;
+                
+            case ModDn :
+            case ModRdn :
+                if ( entry.getEntry() != null )
+                {
+                    throw new NamingException( "Invalid Entry : a modifyDN operation entry should not contain attributes" );
+                }
+                
+                
+                // Stores the new RDN
+                EntryAttribute newRdn = new DefaultClientAttribute( "newrdn", entry.getNewRdn() );
+                sb.append( convertToLdif( newRdn, length ) );
+
+                // Stores the deleteoldrdn flag
+                sb.append( "deleteoldrdn: " );
+                
+                if ( entry.isDeleteOldRdn() )
+                {
+                    sb.append( "1" );
+                }
+                else
+                {
+                    sb.append( "0" );
+                }
+                
+                sb.append( '\n' );
+                
+                // Stores the optional newSuperior
+                if ( ! StringTools.isEmpty( entry.getNewSuperior() ) )
+                {
+                    EntryAttribute newSuperior = new DefaultClientAttribute( "newsuperior", entry.getNewSuperior() );
+                    sb.append( convertToLdif( newSuperior, length ) );
+                }
+                
+                break;
+                
+            case Modify :
+                for ( Modification modification:entry.getModificationItems() )
+                {
+                    switch ( modification.getOperation() )
+                    {
+                        case ADD_ATTRIBUTE :
+                            sb.append( "add: " );
+                            break;
+                            
+                        case REMOVE_ATTRIBUTE :
+                            sb.append( "delete: " );
+                            break;
+                            
+                        case REPLACE_ATTRIBUTE :
+                            sb.append( "replace: " );
+                            break;
+                            
+                        default :
+                            break; // Do nothing
+                            
+                    }
+                    
+                    sb.append( modification.getAttribute().getId() );
+                    sb.append( '\n' );
+                    
+                    sb.append( convertToLdif( modification.getAttribute() ) );
+                    sb.append( "-\n" );
+                }
+                break;
+                
+            default :
+                break; // Do nothing
+                
+        }
+        
+        sb.append( '\n' );
+        
+        return sb.toString();
+    }
+    
+    /**
+     * Base64 encode a String
+     * @param str The string to encode
+     * @return the base 64 encoded string
+     */
+    private static String encodeBase64( String str )
+    {
+        char[] encoded =null;
+        
+        try
+        {
+            // force encoding using UTF-8 charset, as required in RFC2849 note 7
+            encoded = Base64.encode( str.getBytes( "UTF-8" ) );
+        }
+        catch ( UnsupportedEncodingException e )
+        {
+            encoded = Base64.encode( str.getBytes() );
+        }
+        
+        return new String( encoded );
+    }
+    
+
+    /**
+     * Converts an EntryAttribute to LDIF
+     * @param attr the >EntryAttribute to convert
+     * @return the corresponding LDIF code as a String
+     * @throws NamingException If a naming exception is encountered.
+     */
+    public static String convertToLdif( EntryAttribute attr ) throws NamingException
+    {
+        return convertToLdif( attr, DEFAULT_LINE_LENGTH );
+    }
+    
+    
+    /**
+     * Converts an EntryAttribute as LDIF
+     * @param attr the EntryAttribute to convert
+     * @param length the expected line length
+     * @return the corresponding LDIF code as a String
+     * @throws NamingException If a naming exception is encountered.
+     */
+    public static String convertToLdif( EntryAttribute attr, int length ) throws NamingException
+    {
+        StringBuilder sb = new StringBuilder();
+        
+        for ( Value<?> value:attr )
+        {
+            StringBuilder lineBuffer = new StringBuilder();
+            
+            lineBuffer.append( attr.getId() );
+            
+            // First, deal with null value (which is valid)
+            if ( value.isNull() )
+            {
+                lineBuffer.append( ':' );
+            }
+            else if ( value.isBinary() )
+            {
+                // It is binary, so we have to encode it using Base64 before adding it
+                char[] encoded = Base64.encode( value.getBytes() );
+                
+                lineBuffer.append( ":: " + new String( encoded ) );                            
+            }
+            else if ( !value.isBinary() )
+            {
+                // It's a String but, we have to check if encoding isn't required
+                String str = value.getString();
+                
+                if ( !LdifUtils.isLDIFSafe( str ) )
+                {
+                    lineBuffer.append( ":: " + encodeBase64( str ) );
+                }
+                else
+                {
+                    lineBuffer.append( ":" );
+                    
+                    if ( str != null) 
+                    {
+                        lineBuffer.append( " " ).append( str );
+                    }
+                }
+            }
+            
+            lineBuffer.append( "\n" );
+            sb.append( stripLineToNChars( lineBuffer.toString(), length ) );
+        }
+        
+        return sb.toString();
+    }
+    
+    
+    /**
+     * Strips the String every n specified characters
+     * @param str the string to strip
+     * @param nbChars the number of characters
+     * @return the stripped String
+     */
+    public static String stripLineToNChars( String str, int nbChars)
+    {
+        int strLength = str.length();
+
+        if ( strLength <= nbChars )
+        {
+            return str;
+        }
+        
+        if ( nbChars < 2 )
+        {
+            throw new IllegalArgumentException( "The length of each line must be at least 2 chars long" );
+        }
+        
+        // We will first compute the new size of the LDIF result
+        // It's at least nbChars chars plus one for \n
+        int charsPerLine = nbChars - 1;
+
+        int remaining = ( strLength - nbChars ) % charsPerLine;
+
+        int nbLines = 1 + ( ( strLength - nbChars ) / charsPerLine ) +
+                        ( remaining == 0 ? 0 : 1 );
+
+        int nbCharsTotal = strLength + nbLines + nbLines - 2;
+
+        char[] buffer = new char[ nbCharsTotal ];
+        char[] orig = str.toCharArray();
+        
+        int posSrc = 0;
+        int posDst = 0;
+        
+        System.arraycopy( orig, posSrc, buffer, posDst, nbChars );
+        posSrc += nbChars;
+        posDst += nbChars;
+        
+        for ( int i = 0; i < nbLines - 2; i ++ )
+        {
+            buffer[posDst++] = '\n';
+            buffer[posDst++] = ' ';
+            
+            System.arraycopy( orig, posSrc, buffer, posDst, charsPerLine );
+            posSrc += charsPerLine;
+            posDst += charsPerLine;
+        }
+
+        buffer[posDst++] = '\n';
+        buffer[posDst++] = ' ';
+        System.arraycopy( orig, posSrc, buffer, posDst, remaining == 0 ? charsPerLine : remaining );
+        
+        return new String( buffer );
+    }
+
+
+    /**
+     * Build a new Attributes instance from a LDIF list of lines. The values can be 
+     * either a complete AVA, or a couple of AttributeType ID and a value (a String or 
+     * a byte[]). The following sample shows the three cases :
+     * 
+     * <pre>
+     * Attribute attr = AttributeUtils.createAttributes(
+     *     "objectclass: top",
+     *     "cn", "My name",
+     *     "jpegPhoto", new byte[]{0x01, 0x02} );
+     * </pre>
+     * 
+     * @param avas The AttributeType and Values, using a ldif format, or a couple of 
+     * Attribute ID/Value
+     * @return An Attributes instance
+     * @throws NamingException If the data are invalid
+     */
+    public static Attributes createAttributes( Object... avas ) throws NamingException
+    {
+        StringBuilder sb = new StringBuilder();
+        int pos = 0;
+        boolean valueExpected = false;
+        
+        for ( Object ava : avas)
+        {
+            if ( !valueExpected )
+            {
+                if ( !(ava instanceof String) )
+                {
+                    throw new InvalidAttributeValueException( "The Attribute ID #" + (pos+1) + " must be a String" );
+                }
+                
+                String attribute = (String)ava;
+                sb.append( attribute );
+                
+                if ( attribute.indexOf( ':' ) != -1 )
+                {
+                    sb.append( '\n' );
+                }
+                else
+                {
+                    valueExpected = true;
+                }
+            }
+            else
+            {
+                if ( ava instanceof String )
+                {
+                    sb.append( ": " ).append( (String)ava ).append( '\n' );
+                }
+                else if ( ava instanceof byte[] )
+                {
+                    sb.append( ":: " );
+                    sb.append( new String( Base64.encode( (byte[] )ava ) ) );
+                    sb.append( '\n' );
+                }
+                else
+                {
+                    throw new InvalidAttributeValueException( "The Attribute value #" + (pos+1) + " must be a String or a byte[]" );
+                }
+                
+                valueExpected = false;
+            }
+        }
+        
+        if ( valueExpected )
+        {
+            throw new InvalidAttributeValueException( "A value is missing at the end" );
+        }
+        
+        LdifAttributesReader reader = new LdifAttributesReader();
+        Attributes attributes = reader.parseAttributes( sb.toString() );
+
+        return attributes;
+    }
+}
+

Added: directory/shared/trunk/ldap-ldif/src/test/java/org/apache/directory/shared/ldap/ldif/LdifAttributesReaderTest.java
URL: http://svn.apache.org/viewvc/directory/shared/trunk/ldap-ldif/src/test/java/org/apache/directory/shared/ldap/ldif/LdifAttributesReaderTest.java?rev=903465&view=auto
==============================================================================
--- directory/shared/trunk/ldap-ldif/src/test/java/org/apache/directory/shared/ldap/ldif/LdifAttributesReaderTest.java (added)
+++ directory/shared/trunk/ldap-ldif/src/test/java/org/apache/directory/shared/ldap/ldif/LdifAttributesReaderTest.java Tue Jan 26 22:43:27 2010
@@ -0,0 +1,774 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.shared.ldap.ldif;
+
+
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.NamingException;
+
+import org.apache.directory.shared.ldap.constants.SchemaConstants;
+import org.apache.directory.shared.ldap.util.StringTools;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertNotNull;
+
+
+/**
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev: 379008 $
+ */
+public class LdifAttributesReaderTest
+{
+    private byte[] data;
+    
+    private File HJENSEN_JPEG_FILE = null;
+    
+    private File createFile( String name, byte[] data ) throws IOException
+    {
+        File jpeg = File.createTempFile( name, "jpg" );
+        
+        jpeg.createNewFile();
+
+        DataOutputStream os = new DataOutputStream( new FileOutputStream( jpeg ) );
+
+        os.write( data );
+        os.close();
+
+        // This file will be deleted when the JVM
+        // will exit.
+        jpeg.deleteOnExit();
+
+        return jpeg;
+    }
+
+    /**
+     * Create a file to be used by ":<" values
+     */
+    @Before public void setUp() throws Exception
+    {
+        data = new byte[256];
+
+        for ( int i = 0; i < 256; i++ )
+        {
+            data[i] = (byte) i;
+        }
+
+        HJENSEN_JPEG_FILE = createFile( "hjensen", data );
+    }
+
+    @Test public void testLdifNull() throws NamingException
+    {
+        String ldif = null;
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+        Attributes attributes = reader.parseAttributes( ldif );
+
+        assertEquals( 0, attributes.size() );
+    }
+    
+
+    @Test public void testLdifEmpty() throws NamingException
+    {
+        String ldif = "";
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+        Attributes attributes = reader.parseAttributes( ldif );
+
+        assertEquals( 0, attributes.size() );
+    }
+
+    
+    @Test public void testLdifEmptyLines() throws NamingException
+    {
+        String ldif = "\n\n\r\r\n";
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+        Attributes attributes = reader.parseAttributes( ldif );
+        assertNull( attributes );
+    }
+
+    
+    @Test public void testLdifComments() throws NamingException
+    {
+        String ldif = 
+            "#Comment 1\r" + 
+            "#\r" + 
+            " th\n" + 
+            " is is still a comment\n" + 
+            "\n";
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+        Attributes attributes = reader.parseAttributes( ldif );
+
+        assertNull( attributes );
+    }
+
+    
+    @Test public void testLdifVersionStart() throws NamingException
+    {
+        String ldif = 
+            "cn: app1\n" + 
+            "objectClass: top\n" + 
+            "objectClass: apApplication\n" + 
+            "displayName:   app1   \n" + 
+            "dependencies:\n" + 
+            "envVars:";
+
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+        Attributes attributes = reader.parseAttributes( ldif );
+
+        assertEquals( 1, reader.getVersion() );
+        assertNotNull( attributes );
+
+        Attribute attr = attributes.get( "displayname" );
+        assertTrue( attr.contains( "app1" ) );
+    }
+
+
+    /**
+     * Spaces at the end of values should not be included into values.
+     * 
+     * @throws NamingException
+     */
+    @Test public void testLdifParserEndSpaces() throws NamingException
+    {
+        String ldif = 
+            "cn: app1\n" + 
+            "objectClass: top\n" + 
+            "objectClass: apApplication\n" + 
+            "displayName:   app1   \n" + 
+            "dependencies:\n" + 
+            "envVars:";
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+
+        Attributes attributes = reader.parseAttributes( ldif );
+        assertNotNull( attributes );
+
+        Attribute attr = attributes.get( "displayname" );
+        assertTrue( attr.contains( "app1" ) );
+
+    }
+
+
+    @Test public void testLdifParser() throws NamingException
+    {
+        String ldif = 
+            "cn: app1\n" + 
+            "objectClass: top\n" + 
+            "objectClass: apApplication\n" + 
+            "displayName: app1   \n" + 
+            "dependencies:\n" + 
+            "envVars:";
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+        Attributes attributes = reader.parseAttributes( ldif );
+
+        assertNotNull( attributes );
+
+        Attribute attr = attributes.get( "cn" );
+        assertTrue( attr.contains( "app1" ) );
+
+        attr = attributes.get( "objectclass" );
+        assertTrue( attr.contains( "top" ) );
+        assertTrue( attr.contains( "apApplication" ) );
+
+        attr = attributes.get( "displayname" );
+        assertTrue( attr.contains( "app1" ) );
+
+        attr = attributes.get( "dependencies" );
+        assertNull( attr.get() );
+
+        attr = attributes.get( "envvars" );
+        assertNull( attr.get() );
+    }
+
+    
+    @Test public void testLdifParserMuiltiLineComments() throws NamingException
+    {
+        String ldif = 
+            "#comment\n" + 
+            " still a comment\n" + 
+            "cn: app1#another comment\n" + 
+            "objectClass: top\n" + 
+            "objectClass: apApplication\n" + 
+            "displayName: app1\n" + 
+            "serviceType: http\n" + 
+            "dependencies:\n" + 
+            "httpHeaders:\n" + 
+            "startupOptions:\n" + 
+            "envVars:";
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+        Attributes attributes = reader.parseAttributes( ldif );
+
+        assertNotNull( attributes );
+
+        Attribute attr = attributes.get( "cn" );
+        assertTrue( attr.contains( "app1#another comment" ) );
+
+        attr = attributes.get( "objectclass" );
+        assertTrue( attr.contains( "top" ) );
+        assertTrue( attr.contains( "apApplication" ) );
+
+        attr = attributes.get( "displayname" );
+        assertTrue( attr.contains( "app1" ) );
+
+        attr = attributes.get( "dependencies" );
+        assertNull( attr.get() );
+
+        attr = attributes.get( "envvars" );
+        assertNull( attr.get() );
+    }
+
+    
+    @Test public void testLdifParserMultiLineEntries() throws NamingException
+    {
+        String ldif = 
+            "#comment\n" + 
+            "cn: app1#another comment\n" + 
+            "objectClass: top\n" + 
+            "objectClass: apAppli\n" +
+            " cation\n" + 
+            "displayName: app1\n" + 
+            "serviceType: http\n" + 
+            "dependencies:\n" + 
+            "httpHeaders:\n" + 
+            "startupOptions:\n" + 
+            "envVars:";
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+        Attributes attributes = reader.parseAttributes( ldif );
+
+        assertNotNull( attributes );
+
+        Attribute attr = attributes.get( "cn" );
+        assertTrue( attr.contains( "app1#another comment" ) );
+
+        attr = attributes.get( "objectclass" );
+        assertTrue( attr.contains( "top" ) );
+        assertTrue( attr.contains( "apApplication" ) );
+
+        attr = attributes.get( "displayname" );
+        assertTrue( attr.contains( "app1" ) );
+
+        attr = attributes.get( "dependencies" );
+        assertNull( attr.get() );
+
+        attr = attributes.get( "envvars" );
+        assertNull( attr.get() );
+    }
+
+    
+    @Test public void testLdifParserBase64() throws NamingException, UnsupportedEncodingException
+    {
+        String ldif = 
+            "#comment\n" + 
+            "cn:: RW1tYW51ZWwgTMOpY2hhcm55\n" + 
+            "objectClass: top\n" + 
+            "objectClass: apApplication\n" + 
+            "displayName: app1\n" + 
+            "serviceType: http\n" + 
+            "dependencies:\n" + 
+            "httpHeaders:\n" + 
+            "startupOptions:\n" + 
+            "envVars:";
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+        Attributes attributes = reader.parseAttributes( ldif );
+
+        assertNotNull( attributes );
+
+        Attribute attr = attributes.get( "cn" );
+        assertTrue( attr.contains( "Emmanuel L\u00e9charny".getBytes( "UTF-8" ) ) );
+
+        attr = attributes.get( "objectclass" );
+        assertTrue( attr.contains( "top" ) );
+        assertTrue( attr.contains( "apApplication" ) );
+
+        attr = attributes.get( "displayname" );
+        assertTrue( attr.contains( "app1" ) );
+
+        attr = attributes.get( "dependencies" );
+        assertNull( attr.get() );
+
+        attr = attributes.get( "envvars" );
+        assertNull( attr.get() );
+    }
+
+    
+    @Test public void testLdifParserBase64MultiLine() throws NamingException, UnsupportedEncodingException
+    {
+        String ldif = 
+            "#comment\n" + 
+            "cn:: RW1tYW51ZWwg\n" + 
+            " TMOpY2hhcm55ICA=\n" + 
+            "objectClass: top\n" + 
+            "objectClass: apApplication\n" + 
+            "displayName: app1\n" + 
+            "serviceType: http\n" + 
+            "dependencies:\n" + 
+            "httpHeaders:\n" + 
+            "startupOptions:\n" + 
+            "envVars:";
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+        Attributes attributes = reader.parseAttributes( ldif );
+
+        assertNotNull( attributes );
+
+        Attribute attr = attributes.get( "cn" );
+        assertTrue( attr.contains( "Emmanuel L\u00e9charny  ".getBytes( "UTF-8" ) ) );
+
+        attr = attributes.get( "objectclass" );
+        assertTrue( attr.contains( "top" ) );
+        assertTrue( attr.contains( "apApplication" ) );
+
+        attr = attributes.get( "displayname" );
+        assertTrue( attr.contains( "app1" ) );
+
+        attr = attributes.get( "dependencies" );
+        assertNull( attr.get() );
+
+        attr = attributes.get( "envvars" );
+        assertNull( attr.get() );
+    }
+
+    
+    @Test public void testLdifParserRFC2849Sample1() throws NamingException
+    {
+        String ldif = 
+            "objectclass: top\n" + 
+            "objectclass: person\n" + 
+            "objectclass: organizationalPerson\n" + 
+            "cn: Barbara Jensen\n" + 
+            "cn: Barbara J Jensen\n" + 
+            "cn: Babs Jensen\n" + 
+            "sn: Jensen\n" + 
+            "uid: bjensen\n" + 
+            "telephonenumber: +1 408 555 1212\n" + 
+            "description: A big sailing fan.\n"; 
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+        Attributes attributes = reader.parseAttributes( ldif );
+
+        Attribute attr = attributes.get( "objectclass" );
+        assertTrue( attr.contains( "top" ) );
+        assertTrue( attr.contains( "person" ) );
+        assertTrue( attr.contains( "organizationalPerson" ) );
+
+        attr = attributes.get( "cn" );
+        assertTrue( attr.contains( "Barbara Jensen" ) );
+        assertTrue( attr.contains( "Barbara J Jensen" ) );
+        assertTrue( attr.contains( "Babs Jensen" ) );
+
+        attr = attributes.get( "sn" );
+        assertTrue( attr.contains( "Jensen" ) );
+
+        attr = attributes.get( "uid" );
+        assertTrue( attr.contains( "bjensen" ) );
+
+        attr = attributes.get( "telephonenumber" );
+        assertTrue( attr.contains( "+1 408 555 1212" ) );
+
+        attr = attributes.get( "description" );
+        assertTrue( attr.contains( "A big sailing fan." ) );
+
+    }
+
+    
+    @Test public void testLdifParserRFC2849Sample2() throws NamingException
+    {
+        String ldif = 
+            "objectclass: top\n" + 
+            "objectclass: person\n" + 
+            "objectclass: organizationalPerson\n" + 
+            "cn: Barbara Jensen\n" + 
+            "cn: Barbara J Jensen\n" + 
+            "cn: Babs Jensen\n" + 
+            "sn: Jensen\n" + 
+            "uid: bjensen\n" + 
+            "telephonenumber: +1 408 555 1212\n" + 
+            "description:Babs is a big sailing fan, and travels extensively in sea\n" + 
+            " rch of perfect sailing conditions.\n" + 
+            "title:Product Manager, Rod and Reel Division";
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+        Attributes attributes = reader.parseAttributes( ldif );
+
+        Attribute attr = attributes.get( "objectclass" );
+        assertTrue( attr.contains( "top" ) );
+        assertTrue( attr.contains( "person" ) );
+        assertTrue( attr.contains( "organizationalPerson" ) );
+
+        attr = attributes.get( "cn" );
+        assertTrue( attr.contains( "Barbara Jensen" ) );
+        assertTrue( attr.contains( "Barbara J Jensen" ) );
+        assertTrue( attr.contains( "Babs Jensen" ) );
+
+        attr = attributes.get( "sn" );
+        assertTrue( attr.contains( "Jensen" ) );
+
+        attr = attributes.get( "uid" );
+        assertTrue( attr.contains( "bjensen" ) );
+
+        attr = attributes.get( "telephonenumber" );
+        assertTrue( attr.contains( "+1 408 555 1212" ) );
+
+        attr = attributes.get( "description" );
+        assertTrue( attr
+                .contains( "Babs is a big sailing fan, and travels extensively in search of perfect sailing conditions." ) );
+
+        attr = attributes.get( "title" );
+        assertTrue( attr.contains( "Product Manager, Rod and Reel Division" ) );
+
+    }
+
+    
+    @Test public void testLdifParserRFC2849Sample3() throws NamingException, Exception
+    {
+        String ldif = 
+            "objectclass: top\n" + 
+            "objectclass: person\n" + 
+            "objectclass: organizationalPerson\n" + 
+            "cn: Gern Jensen\n" + 
+            "cn: Gern O Jensen\n" + 
+            "sn: Jensen\n" + 
+            "uid: gernj\n" + 
+            "telephonenumber: +1 408 555 1212\n" + 
+            "description:: V2hhdCBhIGNhcmVmdWwgcmVhZGVyIHlvdSBhcmUhICBUaGlzIHZhbHVl\n" + 
+            " IGlzIGJhc2UtNjQtZW5jb2RlZCBiZWNhdXNlIGl0IGhhcyBhIGNvbnRyb2wgY2hhcmFjdG\n" + 
+            " VyIGluIGl0IChhIENSKS4NICBCeSB0aGUgd2F5LCB5b3Ugc2hvdWxkIHJlYWxseSBnZXQg\n" + 
+            " b3V0IG1vcmUu";
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+        Attributes attributes = reader.parseAttributes( ldif );
+
+        Attribute attr = attributes.get( "objectclass" );
+        assertTrue( attr.contains( "top" ) );
+        assertTrue( attr.contains( "person" ) );
+        assertTrue( attr.contains( "organizationalPerson" ) );
+
+        attr = attributes.get( "cn" );
+        assertTrue( attr.contains( "Gern Jensen" ) );
+        assertTrue( attr.contains( "Gern O Jensen" ) );
+
+        attr = attributes.get( "sn" );
+        assertTrue( attr.contains( "Jensen" ) );
+
+        attr = attributes.get( "uid" );
+        assertTrue( attr.contains( "gernj" ) );
+
+        attr = attributes.get( "telephonenumber" );
+        assertTrue( attr.contains( "+1 408 555 1212" ) );
+
+        attr = attributes.get( "description" );
+        assertTrue( attr
+                .contains( "What a careful reader you are!  This value is base-64-encoded because it has a control character in it (a CR).\r  By the way, you should really get out more."
+                        .getBytes( "UTF-8" ) ) );
+    }
+
+    
+    @Test public void testLdifParserRFC2849Sample3VariousSpacing() throws NamingException, Exception
+    {
+        String ldif = 
+            "objectclass:top\n" + 
+            "objectclass:   person   \n" + 
+            "objectclass:organizationalPerson\n" + 
+            "cn:Gern Jensen\n"  + 
+            "cn:Gern O Jensen\n" + 
+            "sn:Jensen\n" + 
+            "uid:gernj\n" + 
+            "telephonenumber:+1 408 555 1212  \n" + 
+            "description::  V2hhdCBhIGNhcmVmdWwgcmVhZGVyIHlvdSBhcmUhICBUaGlzIHZhbHVl\n" + 
+            " IGlzIGJhc2UtNjQtZW5jb2RlZCBiZWNhdXNlIGl0IGhhcyBhIGNvbnRyb2wgY2hhcmFjdG\n" + 
+            " VyIGluIGl0IChhIENSKS4NICBCeSB0aGUgd2F5LCB5b3Ugc2hvdWxkIHJlYWxseSBnZXQg\n" + 
+            " b3V0IG1vcmUu  ";
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+        Attributes attributes = reader.parseAttributes( ldif );
+
+        Attribute attr = attributes.get( "objectclass" );
+        assertTrue( attr.contains( "top" ) );
+        assertTrue( attr.contains( "person" ) );
+        assertTrue( attr.contains( "organizationalPerson" ) );
+
+        attr = attributes.get( "cn" );
+        assertTrue( attr.contains( "Gern Jensen" ) );
+        assertTrue( attr.contains( "Gern O Jensen" ) );
+
+        attr = attributes.get( "sn" );
+        assertTrue( attr.contains( "Jensen" ) );
+
+        attr = attributes.get( "uid" );
+        assertTrue( attr.contains( "gernj" ) );
+
+        attr = attributes.get( "telephonenumber" );
+        assertTrue( attr.contains( "+1 408 555 1212" ) );
+
+        attr = attributes.get( "description" );
+        assertTrue( attr
+                .contains( "What a careful reader you are!  This value is base-64-encoded because it has a control character in it (a CR).\r  By the way, you should really get out more."
+                        .getBytes( "UTF-8" ) ) );
+    }
+
+    
+    @Test public void testLdifParserRFC2849Sample4() throws NamingException, Exception
+    {
+        String ldif = 
+            "# dn:: ou=営業部,o=Airius\n" + 
+            "objectclass: top\n" + 
+            "objectclass: organizationalUnit\n" + 
+            "ou:: 5Za25qWt6YOo\n" + 
+            "# ou:: 営業部\n" + 
+            "ou;lang-ja:: 5Za25qWt6YOo\n" + 
+            "# ou;lang-ja:: 営業部\n" + 
+            "ou;lang-ja;phonetic:: 44GI44GE44GO44KH44GG44G2\n" + 
+            "# ou;lang-ja:: えいぎょうぶ\n" + 
+            "ou;lang-en: Sales\n" + 
+            "description: Japanese office\n";
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+        Attributes attributes = reader.parseAttributes( ldif );
+
+        String[][] values =
+            {
+                { "objectclass", "top" },
+                { "objectclass", "organizationalUnit" },
+                { "ou", "\u55b6\u696d\u90e8" },
+                { "ou;lang-ja", "\u55b6\u696d\u90e8" },
+                { "ou;lang-ja;phonetic", "\u3048\u3044\u304e\u3087\u3046\u3076" }, // 3048 = え, 3044 = い, 304e = ぎ
+                                                                                // 3087 = ょ, 3046 = う, 3076 = ぶ
+                { "ou;lang-en", "Sales" },
+                { "description", "Japanese office" }
+            }; 
+
+        for ( int j = 0; j < values.length; j++ )
+        {
+            Attribute attr = attributes.get( values[j][0] );
+
+            if ( attr.contains( values[j][1] ) )
+            {
+                assertTrue( true );
+            }
+            else
+            {
+                assertTrue( attr.contains( values[j][1].getBytes( "UTF-8" ) ) );
+            }
+        }
+    }
+
+    
+    @Test public void testLdifParserRFC2849Sample5() throws NamingException, Exception
+    {
+        String ldif = 
+            "objectclass: top\n" + 
+            "objectclass: person\n" + 
+            "objectclass: organizationalPerson\n" + 
+            "cn: Horatio Jensen\n" + 
+            "cn: Horatio N Jensen\n" + 
+            "sn: Jensen\n" + 
+            "uid: hjensen\n" + 
+            "telephonenumber: +1 408 555 1212\n" + 
+            "jpegphoto:< file:" + HJENSEN_JPEG_FILE.getAbsolutePath() + "\n";
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+        Attributes attributes = reader.parseAttributes( ldif );
+
+        String[][] values =
+            {
+                { "objectclass", "top" },
+                { "objectclass", "person" },
+                { "objectclass", "organizationalPerson" },
+                { "cn", "Horatio Jensen" },
+                { "cn", "Horatio N Jensen" },
+                { "sn", "Jensen" },
+                { "uid", "hjensen" },
+                { "telephonenumber", "+1 408 555 1212" },
+                { "jpegphoto", null } 
+            };
+
+        for ( int i = 0; i < values.length; i++ )
+        {
+            if ( "jpegphoto".equalsIgnoreCase( values[i][0] ) )
+            {
+                Attribute attr = attributes.get( values[i][0] );
+                assertEquals( StringTools.dumpBytes( data ), StringTools.dumpBytes( (byte[]) attr.get() ) );
+            }
+            else
+            {
+                Attribute attr = attributes.get( values[i][0] );
+
+                if ( attr.contains( values[i][1] ) )
+                {
+                    assertTrue( true );
+                }
+                else
+                {
+                    assertTrue( attr.contains( values[i][1].getBytes( "UTF-8" ) ) );
+                }
+            }
+        }
+    }
+
+    
+    @Test public void testLdifParserRFC2849Sample5WithSizeLimit() throws Exception
+    {
+        String ldif = 
+            "objectclass: top\n" + 
+            "objectclass: person\n" + 
+            "objectclass: organizationalPerson\n" + 
+            "cn: Horatio Jensen\n" + 
+            "cn: Horatio N Jensen\n" + 
+            "sn: Jensen\n" + 
+            "uid: hjensen\n" + 
+            "telephonenumber: +1 408 555 1212\n" + 
+            "jpegphoto:< file:" + HJENSEN_JPEG_FILE.getAbsolutePath() + "\n";
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+        reader.setSizeLimit( 128 );
+
+        try
+        {
+            reader.parseAttributes( ldif );
+            fail();
+        }
+        catch (NamingException ne)
+        {
+            assertEquals( "Error while parsing the ldif buffer", ne.getMessage() );
+        }
+    }
+
+    
+    @Test public void testLdifAttributesReaderDirServer() throws NamingException, Exception
+    {
+        String ldif = 
+            "# -------------------------------------------------------------------\n" +
+            "#\n" +
+            "#  Licensed to the Apache Software Foundation (ASF) under one\n" +
+            "#  or more contributor license agreements.  See the NOTICE file\n" +
+            "#  distributed with this work for additional information\n" +
+            "#  regarding copyright ownership.  The ASF licenses this file\n" +
+            "#  to you under the Apache License, Version 2.0 (the\n" +
+            "#  \"License\"); you may not use this file except in compliance\n" +
+            "#  with the License.  You may obtain a copy of the License at\n" +
+            "#  \n" +
+            "#    http://www.apache.org/licenses/LICENSE-2.0\n" +
+            "#  \n" +
+            "#  Unless required by applicable law or agreed to in writing,\n" +
+            "#  software distributed under the License is distributed on an\n" +
+            "#  \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n" +
+            "#  KIND, either express or implied.  See the License for the\n" +
+            "#  specific language governing permissions and limitations\n" +
+            "#  under the License. \n" +
+            "#  \n" +
+            "#\n" +
+            "# EXAMPLE.COM is freely and reserved for testing according to this RFC:\n" +
+            "#\n" +
+            "# http://www.rfc-editor.org/rfc/rfc2606.txt\n" +
+            "#\n" +
+            "# -------------------------------------------------------------------\n" +
+            "\n" +
+            "objectclass: top\n" +
+            "objectclass: organizationalunit\n" +
+            "ou: Users";
+            
+        LdifAttributesReader reader = new LdifAttributesReader();
+
+        Attributes attributes = reader.parseAttributes( ldif );
+
+        Attribute attr = attributes.get( "objectclass" );
+        assertTrue( attr.contains( "top" ) );
+        assertTrue( attr.contains( "organizationalunit" ) );
+
+        attr = attributes.get( "ou" );
+        assertTrue( attr.contains( "Users" ) );
+    }
+
+    
+    @Test public void testLdifParserCommentsEmptyLines() throws NamingException, Exception
+    {
+        String ldif = 
+            "#\n" +
+            "#  Licensed to the Apache Software Foundation (ASF) under one\n" +
+            "#  or more contributor license agreements.  See the NOTICE file\n" +
+            "#  distributed with this work for additional information\n" +
+            "#  regarding copyright ownership.  The ASF licenses this file\n" +
+            "#  to you under the Apache License, Version 2.0 (the\n" +
+            "#  \"License\"); you may not use this file except in compliance\n" +
+            "#  with the License.  You may obtain a copy of the License at\n" +
+            "#  \n" +
+            "#    http://www.apache.org/licenses/LICENSE-2.0\n" +
+            "#  \n" +
+            "#  Unless required by applicable law or agreed to in writing,\n" +
+            "#  software distributed under the License is distributed on an\n" +
+            "#  \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n" +
+            "#  KIND, either express or implied.  See the License for the\n" +
+            "#  specific language governing permissions and limitations\n" +
+            "#  under the License. \n" +
+            "#  \n" +
+            "#\n" +
+            "#\n" +
+            "#   EXAMPLE.COM is freely and reserved for testing according to this RFC:\n" +
+            "#\n" +
+            "#   http://www.rfc-editor.org/rfc/rfc2606.txt\n" +
+            "#\n" +
+            "#\n" +
+            "\n" +
+            "#\n" +
+            "# This ACI allows brouse access to the root suffix and one level below that to anyone.\n" +
+            "# At this level there is nothing critical exposed.  Everything that matters is one or\n" +
+            "# more levels below this.\n" +
+            "#\n" +
+            "\n" +
+            "objectClass: top\n" +
+            "objectClass: subentry\n" +
+            "objectClass: accessControlSubentry\n" +
+            "subtreeSpecification: { maximum 1 }\n" +
+            "prescriptiveACI: { identificationTag \"browseRoot\", precedence 100, authenticationLevel none, itemOrUserFirst userFirst: { userClasses { allUsers }, userPermissions { { protectedItems {entry}, grantsAndDenials { grantReturnDN, grantBrowse } } } } }\n";
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+        Attributes attributes = reader.parseAttributes( ldif );
+
+        Attribute attr = attributes.get( "objectClass" );
+        assertTrue( attr.contains( "top" ) );
+        assertTrue( attr.contains( SchemaConstants.SUBENTRY_OC ) );
+        assertTrue( attr.contains( "accessControlSubentry" ) );
+
+        attr = attributes.get( "subtreeSpecification" );
+        assertTrue( attr.contains( "{ maximum 1 }" ) );
+
+        attr = attributes.get( "prescriptiveACI" );
+        assertTrue( attr.contains( "{ identificationTag \"browseRoot\", precedence 100, authenticationLevel none, itemOrUserFirst userFirst: { userClasses { allUsers }, userPermissions { { protectedItems {entry}, grantsAndDenials { grantReturnDN, grantBrowse } } } } }" ) );
+    }
+}



Mime
View raw message