You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by el...@apache.org on 2010/01/26 23:43:29 UTC

svn commit: r903465 [1/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...

Author: elecharny
Date: Tue Jan 26 22:43:27 2010
New Revision: 903465

URL: http://svn.apache.org/viewvc?rev=903465&view=rev
Log:
Moved the LDIF part from shared-ldap

Added:
    directory/shared/trunk/ldap-ldif/   (with props)
    directory/shared/trunk/ldap-ldif/pom.xml
    directory/shared/trunk/ldap-ldif/src/
    directory/shared/trunk/ldap-ldif/src/main/
    directory/shared/trunk/ldap-ldif/src/main/java/
    directory/shared/trunk/ldap-ldif/src/main/java/org/
    directory/shared/trunk/ldap-ldif/src/main/java/org/apache/
    directory/shared/trunk/ldap-ldif/src/main/java/org/apache/directory/
    directory/shared/trunk/ldap-ldif/src/main/java/org/apache/directory/shared/
    directory/shared/trunk/ldap-ldif/src/main/java/org/apache/directory/shared/ldap/
    directory/shared/trunk/ldap-ldif/src/main/java/org/apache/directory/shared/ldap/ldif/
    directory/shared/trunk/ldap-ldif/src/main/java/org/apache/directory/shared/ldap/ldif/ChangeType.java   (with props)
    directory/shared/trunk/ldap-ldif/src/main/java/org/apache/directory/shared/ldap/ldif/LdifAttributesReader.java
    directory/shared/trunk/ldap-ldif/src/main/java/org/apache/directory/shared/ldap/ldif/LdifControl.java
    directory/shared/trunk/ldap-ldif/src/main/java/org/apache/directory/shared/ldap/ldif/LdifEntry.java
    directory/shared/trunk/ldap-ldif/src/main/java/org/apache/directory/shared/ldap/ldif/LdifReader.java
    directory/shared/trunk/ldap-ldif/src/main/java/org/apache/directory/shared/ldap/ldif/LdifRevertor.java
    directory/shared/trunk/ldap-ldif/src/main/java/org/apache/directory/shared/ldap/ldif/LdifUtils.java
    directory/shared/trunk/ldap-ldif/src/test/
    directory/shared/trunk/ldap-ldif/src/test/java/
    directory/shared/trunk/ldap-ldif/src/test/java/org/
    directory/shared/trunk/ldap-ldif/src/test/java/org/apache/
    directory/shared/trunk/ldap-ldif/src/test/java/org/apache/directory/
    directory/shared/trunk/ldap-ldif/src/test/java/org/apache/directory/shared/
    directory/shared/trunk/ldap-ldif/src/test/java/org/apache/directory/shared/ldap/
    directory/shared/trunk/ldap-ldif/src/test/java/org/apache/directory/shared/ldap/ldif/
    directory/shared/trunk/ldap-ldif/src/test/java/org/apache/directory/shared/ldap/ldif/LdifAttributesReaderTest.java
    directory/shared/trunk/ldap-ldif/src/test/java/org/apache/directory/shared/ldap/ldif/LdifReaderTest.java
    directory/shared/trunk/ldap-ldif/src/test/java/org/apache/directory/shared/ldap/ldif/LdifRevertorTest.java
    directory/shared/trunk/ldap-ldif/src/test/java/org/apache/directory/shared/ldap/ldif/LdifUtilsTest.java
    directory/shared/trunk/ldap-ldif/src/test/resources/
    directory/shared/trunk/ldap-ldif/src/test/resources/log4j.properties

Propchange: directory/shared/trunk/ldap-ldif/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Tue Jan 26 22:43:27 2010
@@ -0,0 +1,5 @@
+target
+.classpath
+.project
+.settings
+.buildpath

Added: directory/shared/trunk/ldap-ldif/pom.xml
URL: http://svn.apache.org/viewvc/directory/shared/trunk/ldap-ldif/pom.xml?rev=903465&view=auto
==============================================================================
--- directory/shared/trunk/ldap-ldif/pom.xml (added)
+++ directory/shared/trunk/ldap-ldif/pom.xml Tue Jan 26 22:43:27 2010
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.shared</groupId>
+    <artifactId>shared-parent</artifactId>
+    <version>0.9.18-SNAPSHOT</version>
+  </parent>
+  <artifactId>shared-ldif</artifactId>
+  <name>Apache Directory Shared LDIF</name>
+  <inceptionYear>2010</inceptionYear>
+
+  <issueManagement>
+    <system>jira</system>
+    <url>http://issues.apache.org/jira/browse/DIRSHARED</url>
+  </issueManagement>
+
+  <description>
+    Common LDIF packages used by clients and servers.
+  </description>
+
+  <dependencies>
+    <dependency>
+      <groupId>commons-lang</groupId>
+      <artifactId>commons-lang</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>commons-collections</groupId>
+      <artifactId>commons-collections</artifactId>
+    </dependency>
+
+    <dependency>
+      <artifactId>shared-asn1</artifactId>
+      <groupId>${groupId}</groupId>
+      <version>${version}</version>
+    </dependency>
+
+    <dependency>
+      <artifactId>shared-ldap</artifactId>
+      <groupId>${groupId}</groupId>
+      <version>${version}</version>
+    </dependency>
+
+    <dependency>
+      <artifactId>shared-ldap-constants</artifactId>
+      <groupId>${groupId}</groupId>
+      <version>${version}</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-antrun-plugin</artifactId>
+        <executions>
+          <execution>
+            <phase>generate-sources</phase>
+            <configuration />
+            <goals>
+              <goal>run</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <excludes>
+            <exclude>**/Abstract*</exclude>
+            <exclude>**/*RegressionTest*</exclude>
+          </excludes>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
+

Added: directory/shared/trunk/ldap-ldif/src/main/java/org/apache/directory/shared/ldap/ldif/ChangeType.java
URL: http://svn.apache.org/viewvc/directory/shared/trunk/ldap-ldif/src/main/java/org/apache/directory/shared/ldap/ldif/ChangeType.java?rev=903465&view=auto
==============================================================================
--- directory/shared/trunk/ldap-ldif/src/main/java/org/apache/directory/shared/ldap/ldif/ChangeType.java (added)
+++ directory/shared/trunk/ldap-ldif/src/main/java/org/apache/directory/shared/ldap/ldif/ChangeType.java Tue Jan 26 22:43:27 2010
@@ -0,0 +1,95 @@
+/*
+ *   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;
+
+
+/**
+ * A type safe enumeration for an LDIF record's change type.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public enum ChangeType
+{
+    Add( 0 ),
+    Modify( 1 ),
+    ModDn( 2 ),
+    ModRdn( 3 ),
+    Delete( 4 );
+    
+    /** Add ordinal value */
+    public static final int ADD_ORDINAL = 0;
+
+    /** Modify ordinal value */
+    public static final int MODIFY_ORDINAL = 1;
+
+    /** ModDN ordinal value */
+    public static final int MODDN_ORDINAL = 2;
+
+    /** ModRDN ordinal value */
+    public static final int MODRDN_ORDINAL = 3;
+
+    /** Delete ordinal value */
+    public static final int DELETE_ORDINAL = 4;
+
+    /* the ordinal value for a change type */
+    private final int changeType;
+    
+    
+    /**
+     * Creates a new instance of ChangeType.
+     *
+     * @param changeType
+     */
+    private ChangeType( int changeType )
+    {
+        this.changeType = changeType;
+    }
+
+
+    /**
+     * Get's the ordinal value for a ChangeType.
+     * 
+     * @return the changeType
+     */
+    public int getChangeType()
+    {
+        return changeType;
+    }
+    
+    public static ChangeType getChangeType( int val )
+    {
+        switch( val )
+        {
+            case 0: return Add;
+            
+            case 1: return Modify;
+            
+            case 2: return ModDn;
+            
+            case 3: return ModRdn;
+            
+            case 4: return Delete;
+            
+            default:
+                throw new IllegalArgumentException( "Unknown change type value " + val );
+        }
+    }
+}

Propchange: directory/shared/trunk/ldap-ldif/src/main/java/org/apache/directory/shared/ldap/ldif/ChangeType.java
------------------------------------------------------------------------------
    svn:executable = *

Added: directory/shared/trunk/ldap-ldif/src/main/java/org/apache/directory/shared/ldap/ldif/LdifAttributesReader.java
URL: http://svn.apache.org/viewvc/directory/shared/trunk/ldap-ldif/src/main/java/org/apache/directory/shared/ldap/ldif/LdifAttributesReader.java?rev=903465&view=auto
==============================================================================
--- directory/shared/trunk/ldap-ldif/src/main/java/org/apache/directory/shared/ldap/ldif/LdifAttributesReader.java (added)
+++ directory/shared/trunk/ldap-ldif/src/main/java/org/apache/directory/shared/ldap/ldif/LdifAttributesReader.java Tue Jan 26 22:43:27 2010
@@ -0,0 +1,310 @@
+/*
+ *  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.BufferedReader;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.ArrayList;
+
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttributes;
+
+import org.apache.directory.shared.ldap.util.StringTools;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * <pre>
+ *  &lt;ldif-file&gt; ::= &quot;version:&quot; &lt;fill&gt; &lt;number&gt; &lt;seps&gt; &lt;dn-spec&gt; &lt;sep&gt; 
+ *  &lt;ldif-content-change&gt;
+ *  
+ *  &lt;ldif-content-change&gt; ::= 
+ *    &lt;number&gt; &lt;oid&gt; &lt;options-e&gt; &lt;value-spec&gt; &lt;sep&gt; &lt;attrval-specs-e&gt; 
+ *    &lt;ldif-attrval-record-e&gt; | 
+ *    &lt;alpha&gt; &lt;chars-e&gt; &lt;options-e&gt; &lt;value-spec&gt; &lt;sep&gt; &lt;attrval-specs-e&gt; 
+ *    &lt;ldif-attrval-record-e&gt; | 
+ *    &quot;control:&quot; &lt;fill&gt; &lt;number&gt; &lt;oid&gt; &lt;spaces-e&gt; &lt;criticality&gt; 
+ *    &lt;value-spec-e&gt; &lt;sep&gt; &lt;controls-e&gt; 
+ *        &quot;changetype:&quot; &lt;fill&gt; &lt;changerecord-type&gt; &lt;ldif-change-record-e&gt; |
+ *    &quot;changetype:&quot; &lt;fill&gt; &lt;changerecord-type&gt; &lt;ldif-change-record-e&gt;
+ *                              
+ *  &lt;ldif-attrval-record-e&gt; ::= &lt;seps&gt; &lt;dn-spec&gt; &lt;sep&gt; &lt;attributeType&gt; 
+ *    &lt;options-e&gt; &lt;value-spec&gt; &lt;sep&gt; &lt;attrval-specs-e&gt; 
+ *    &lt;ldif-attrval-record-e&gt; | e
+ *                              
+ *  &lt;ldif-change-record-e&gt; ::= &lt;seps&gt; &lt;dn-spec&gt; &lt;sep&gt; &lt;controls-e&gt; 
+ *    &quot;changetype:&quot; &lt;fill&gt; &lt;changerecord-type&gt; &lt;ldif-change-record-e&gt; | e
+ *                              
+ *  &lt;dn-spec&gt; ::= &quot;dn:&quot; &lt;fill&gt; &lt;safe-string&gt; | &quot;dn::&quot; &lt;fill&gt; &lt;base64-string&gt;
+ *                              
+ *  &lt;controls-e&gt; ::= &quot;control:&quot; &lt;fill&gt; &lt;number&gt; &lt;oid&gt; &lt;spaces-e&gt; &lt;criticality&gt; 
+ *    &lt;value-spec-e&gt; &lt;sep&gt; &lt;controls-e&gt; | e
+ *                              
+ *  &lt;criticality&gt; ::= &quot;true&quot; | &quot;false&quot; | e
+ *                              
+ *  &lt;oid&gt; ::= '.' &lt;number&gt; &lt;oid&gt; | e
+ *                              
+ *  &lt;attrval-specs-e&gt; ::= &lt;number&gt; &lt;oid&gt; &lt;options-e&gt; &lt;value-spec&gt; &lt;sep&gt; 
+ *  &lt;attrval-specs-e&gt; | 
+ *    &lt;alpha&gt; &lt;chars-e&gt; &lt;options-e&gt; &lt;value-spec&gt; &lt;sep&gt; &lt;attrval-specs-e&gt; | e
+ *                              
+ *  &lt;value-spec-e&gt; ::= &lt;value-spec&gt; | e
+ *  
+ *  &lt;value-spec&gt; ::= ':' &lt;fill&gt; &lt;safe-string-e&gt; | 
+ *    &quot;::&quot; &lt;fill&gt; &lt;base64-chars&gt; | 
+ *    &quot;:&lt;&quot; &lt;fill&gt; &lt;url&gt;
+ *  
+ *  &lt;attributeType&gt; ::= &lt;number&gt; &lt;oid&gt; | &lt;alpha&gt; &lt;chars-e&gt;
+ *  
+ *  &lt;options-e&gt; ::= ';' &lt;char&gt; &lt;chars-e&gt; &lt;options-e&gt; |e
+ *                              
+ *  &lt;chars-e&gt; ::= &lt;char&gt; &lt;chars-e&gt; |  e
+ *  
+ *  &lt;changerecord-type&gt; ::= &quot;add&quot; &lt;sep&gt; &lt;attributeType&gt; &lt;options-e&gt; &lt;value-spec&gt; 
+ *  &lt;sep&gt; &lt;attrval-specs-e&gt; | 
+ *    &quot;delete&quot; &lt;sep&gt; | 
+ *    &quot;modify&quot; &lt;sep&gt; &lt;mod-type&gt; &lt;fill&gt; &lt;attributeType&gt; &lt;options-e&gt; &lt;sep&gt; 
+ *    &lt;attrval-specs-e&gt; &lt;sep&gt; '-' &lt;sep&gt; &lt;mod-specs-e&gt; | 
+ *    &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; 
+ *    &lt;newsuperior-e&gt; &lt;sep&gt; |
+ *    &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; 
+ *    &lt;newsuperior-e&gt; &lt;sep&gt;
+ *  
+ *  &lt;newrdn&gt; ::= ':' &lt;fill&gt; &lt;safe-string&gt; | &quot;::&quot; &lt;fill&gt; &lt;base64-chars&gt;
+ *  
+ *  &lt;newsuperior-e&gt; ::= &quot;newsuperior&quot; &lt;newrdn&gt; | e
+ *  
+ *  &lt;mod-specs-e&gt; ::= &lt;mod-type&gt; &lt;fill&gt; &lt;attributeType&gt; &lt;options-e&gt; 
+ *    &lt;sep&gt; &lt;attrval-specs-e&gt; &lt;sep&gt; '-' &lt;sep&gt; &lt;mod-specs-e&gt; | e
+ *  
+ *  &lt;mod-type&gt; ::= &quot;add:&quot; | &quot;delete:&quot; | &quot;replace:&quot;
+ *  
+ *  &lt;url&gt; ::= &lt;a Uniform Resource Locator, as defined in [6]&gt;
+ *  
+ *  
+ *  
+ *  LEXICAL
+ *  -------
+ *  
+ *  &lt;fill&gt;           ::= ' ' &lt;fill&gt; | e
+ *  &lt;char&gt;           ::= &lt;alpha&gt; | &lt;digit&gt; | '-'
+ *  &lt;number&gt;         ::= &lt;digit&gt; &lt;digits&gt;
+ *  &lt;0-1&gt;            ::= '0' | '1'
+ *  &lt;digits&gt;         ::= &lt;digit&gt; &lt;digits&gt; | e
+ *  &lt;digit&gt;          ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
+ *  &lt;seps&gt;           ::= &lt;sep&gt; &lt;seps-e&gt; 
+ *  &lt;seps-e&gt;         ::= &lt;sep&gt; &lt;seps-e&gt; | e
+ *  &lt;sep&gt;            ::= 0x0D 0x0A | 0x0A
+ *  &lt;spaces&gt;         ::= ' ' &lt;spaces-e&gt;
+ *  &lt;spaces-e&gt;       ::= ' ' &lt;spaces-e&gt; | e
+ *  &lt;safe-string-e&gt;  ::= &lt;safe-string&gt; | e
+ *  &lt;safe-string&gt;    ::= &lt;safe-init-char&gt; &lt;safe-chars&gt;
+ *  &lt;safe-init-char&gt; ::= [0x01-0x09] | 0x0B | 0x0C | [0x0E-0x1F] | [0x21-0x39] | 0x3B | [0x3D-0x7F]
+ *  &lt;safe-chars&gt;     ::= &lt;safe-char&gt; &lt;safe-chars&gt; | e
+ *  &lt;safe-char&gt;      ::= [0x01-0x09] | 0x0B | 0x0C | [0x0E-0x7F]
+ *  &lt;base64-string&gt;  ::= &lt;base64-char&gt; &lt;base64-chars&gt;
+ *  &lt;base64-chars&gt;   ::= &lt;base64-char&gt; &lt;base64-chars&gt; | e
+ *  &lt;base64-char&gt;    ::= 0x2B | 0x2F | [0x30-0x39] | 0x3D | [0x41-9x5A] | [0x61-0x7A]
+ *  &lt;alpha&gt;          ::= [0x41-0x5A] | [0x61-0x7A]
+ *  
+ *  COMMENTS
+ *  --------
+ *  - 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
+ *  DIGIT+ (&quot;.&quot; DIGIT+)*
+ *  - The mod-spec lacks a sep between *attrval-spec and &quot;-&quot;.
+ *  - The BASE64-UTF8-STRING should be BASE64-CHAR BASE64-STRING
+ *  - The ValueSpec rule must accept multilines values. In this case, we have a LF followed by a 
+ *  single space before the continued value.
+ * </pre>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class LdifAttributesReader extends LdifReader
+{
+    /** A logger */
+    private static final Logger LOG = LoggerFactory.getLogger( LdifAttributesReader.class );
+
+    /**
+     * Constructors
+     */
+    public LdifAttributesReader()
+    {
+        lines = new ArrayList<String>();
+        position = new Position();
+        version = DEFAULT_VERSION;
+    }
+
+
+    /**
+     * Parse an AttributeType/AttributeValue
+     * 
+     * @param attributes The entry where to store the value
+     * @param line The line to parse
+     * @param lowerLine The same line, lowercased
+     * @throws NamingException If anything goes wrong
+     */
+    private void parseAttribute( Attributes attributes, String line, String lowerLine ) throws NamingException
+    {
+        int colonIndex = line.indexOf( ':' );
+
+        String attributeType = lowerLine.substring( 0, colonIndex );
+
+        // We should *not* have a DN twice
+        if ( attributeType.equals( "dn" ) )
+        {
+            LOG.error( "An entry must not have two DNs" );
+            throw new NamingException( "A ldif entry should not have two DNs" );
+        }
+
+        Object attributeValue = parseValue( line, colonIndex );
+
+        // Update the entry
+        Attribute attribute = attributes.get( attributeType );
+        
+        if ( attribute == null )
+        {
+            attributes.put( attributeType, attributeValue );
+        }
+        else
+        {
+            attribute.add( attributeValue );
+        }
+    }
+
+    /**
+     * Parse a ldif file. The following rules are processed :
+     * 
+     * &lt;ldif-file&gt; ::= &lt;ldif-attrval-record&gt; &lt;ldif-attrval-records&gt; |
+     * &lt;ldif-change-record&gt; &lt;ldif-change-records&gt; &lt;ldif-attrval-record&gt; ::=
+     * &lt;dn-spec&gt; &lt;sep&gt; &lt;attrval-spec&gt; &lt;attrval-specs&gt; &lt;ldif-change-record&gt; ::=
+     * &lt;dn-spec&gt; &lt;sep&gt; &lt;controls-e&gt; &lt;changerecord&gt; &lt;dn-spec&gt; ::= "dn:" &lt;fill&gt;
+     * &lt;distinguishedName&gt; | "dn::" &lt;fill&gt; &lt;base64-distinguishedName&gt;
+     * &lt;changerecord&gt; ::= "changetype:" &lt;fill&gt; &lt;change-op&gt;
+     * 
+     * @return The read entry
+     * @throws NamingException If the entry can't be read or is invalid
+     */
+    private Attributes parseAttributes() throws NamingException
+    {
+        if ( ( lines == null ) || ( lines.size() == 0 ) )
+        {
+            LOG.debug( "The entry is empty : end of ldif file" );
+            return null;
+        }
+
+        Attributes attributes = new BasicAttributes( true );
+
+        // Now, let's iterate through the other lines
+        for ( String line:lines )
+        {
+            // Each line could start either with an OID, an attribute type, with
+            // "control:" or with "changetype:"
+            String lowerLine = line.toLowerCase();
+
+            // We have three cases :
+            // 1) The first line after the DN is a "control:" -> this is an error
+            // 2) The first line after the DN is a "changeType:" -> this is an error
+            // 3) The first line after the DN is anything else
+            if ( lowerLine.startsWith( "control:" ) )
+            {
+                LOG.error( "We cannot have changes when reading a file which already contains entries" );
+                throw new NamingException( "No changes withing entries" );
+            }
+            else if ( lowerLine.startsWith( "changetype:" ) )
+            {
+                LOG.error( "We cannot have changes when reading a file which already contains entries" );
+                throw new NamingException( "No changes withing entries" );
+            }
+            else if ( line.indexOf( ':' ) > 0 )
+            {
+                parseAttribute( attributes, line, lowerLine );
+            }
+            else
+            {
+                // Invalid attribute Value
+                LOG.error( "Expecting an attribute type" );
+                throw new NamingException( "Bad attribute" );
+            }
+        }
+
+        LOG.debug( "Read an attributes : {}", attributes );
+        
+        return attributes;
+    }
+
+
+    /**
+     * A method which parses a ldif string and returns a list of entries.
+     * 
+     * @param ldif The ldif string
+     * @return A list of entries, or an empty List
+     * @throws NamingException
+     *             If something went wrong
+     */
+    public Attributes parseAttributes( String ldif ) throws NamingException
+    {
+        lines = new ArrayList<String>();
+        position = new Position();
+
+        LOG.debug( "Starts parsing ldif buffer" );
+
+        if ( StringTools.isEmpty( ldif ) )
+        {
+            return new BasicAttributes( true );
+        }
+
+        StringReader strIn = new StringReader( ldif );
+        reader = new BufferedReader( strIn );
+
+        try
+        {
+            readLines();
+            
+            Attributes attributes = parseAttributes();
+
+            if ( LOG.isDebugEnabled() )
+            {
+                LOG.debug( "Parsed {} entries.", ( attributes == null ? 0 : 1 ) );
+            }
+
+            return attributes;
+        }
+        catch (NamingException ne)
+        {
+            LOG.error( "Cannot parse the ldif buffer : {}", ne.getMessage() );
+            throw new NamingException( "Error while parsing the ldif buffer" );
+        }
+        finally
+        {
+            try
+            {
+                reader.close();
+            }
+            catch ( IOException ioe )
+            {
+                // Do nothing
+            }
+        }
+    }
+}
\ No newline at end of file

Added: directory/shared/trunk/ldap-ldif/src/main/java/org/apache/directory/shared/ldap/ldif/LdifControl.java
URL: http://svn.apache.org/viewvc/directory/shared/trunk/ldap-ldif/src/main/java/org/apache/directory/shared/ldap/ldif/LdifControl.java?rev=903465&view=auto
==============================================================================
--- directory/shared/trunk/ldap-ldif/src/main/java/org/apache/directory/shared/ldap/ldif/LdifControl.java (added)
+++ directory/shared/trunk/ldap-ldif/src/main/java/org/apache/directory/shared/ldap/ldif/LdifControl.java Tue Jan 26 22:43:27 2010
@@ -0,0 +1,52 @@
+/*
+ *  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 org.apache.directory.shared.ldap.message.control.AbstractControl;
+import org.apache.directory.shared.ldap.util.StringTools;
+
+/**
+ * The LdifControl class stores a control defined for an entry found in a ldif
+ * file.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class LdifControl extends AbstractControl
+{
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * Create a new Control
+     * 
+     * @param oid
+     *            OID of the created control
+     */
+    public LdifControl( String oid )
+    {
+        super( oid );
+    }
+
+    public String toString()
+    {
+        return "LdifControl : {" + getOid() + ", " + isCritical() + ", " + StringTools.dumpBytes( getValue() ) + "}";
+    }
+}

Added: directory/shared/trunk/ldap-ldif/src/main/java/org/apache/directory/shared/ldap/ldif/LdifEntry.java
URL: http://svn.apache.org/viewvc/directory/shared/trunk/ldap-ldif/src/main/java/org/apache/directory/shared/ldap/ldif/LdifEntry.java?rev=903465&view=auto
==============================================================================
--- directory/shared/trunk/ldap-ldif/src/main/java/org/apache/directory/shared/ldap/ldif/LdifEntry.java (added)
+++ directory/shared/trunk/ldap-ldif/src/main/java/org/apache/directory/shared/ldap/ldif/LdifEntry.java Tue Jan 26 22:43:27 2010
@@ -0,0 +1,1061 @@
+/*
+ *  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.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import javax.naming.InvalidNameException;
+import javax.naming.NamingException;
+
+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.ModificationOperation;
+import org.apache.directory.shared.ldap.entry.Value;
+import org.apache.directory.shared.ldap.entry.client.ClientEntry;
+import org.apache.directory.shared.ldap.entry.client.ClientModification;
+import org.apache.directory.shared.ldap.entry.client.ClientStringValue;
+import org.apache.directory.shared.ldap.entry.client.DefaultClientAttribute;
+import org.apache.directory.shared.ldap.entry.client.DefaultClientEntry;
+import org.apache.directory.shared.ldap.message.control.Control;
+import org.apache.directory.shared.ldap.name.LdapDN;
+import org.apache.directory.shared.ldap.name.RDN;
+import org.apache.directory.shared.ldap.util.StringTools;
+
+
+/**
+ * A entry to be populated by an ldif parser.
+ * 
+ * We will have different kind of entries : 
+ * - added entries 
+ * - deleted entries 
+ * - modified entries 
+ * - RDN modified entries 
+ * - DN modified entries
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class LdifEntry implements Cloneable, Externalizable
+{
+    private static final long serialVersionUID = 2L;
+    
+    /** Used in toArray() */
+    public static final Modification[] EMPTY_MODS = new Modification[0];
+
+    /** the change type */
+    private ChangeType changeType;
+
+    /** the modification item list */
+    private List<Modification> modificationList;
+
+    private Map<String, Modification> modificationItems;
+
+    /** The new superior */
+    private String newSuperior;
+
+    /** The new rdn */
+    private String newRdn;
+
+    /** The delete old rdn flag */
+    private boolean deleteOldRdn;
+
+    /** the entry */
+    private ClientEntry entry;
+
+    
+    /** The control */
+    private Control control;
+
+    /**
+     * Creates a new Entry object.
+     */
+    public LdifEntry()
+    {
+        changeType = ChangeType.Add; // Default LDIF content
+        modificationList = new LinkedList<Modification>();
+        modificationItems = new HashMap<String, Modification>();
+        entry = new DefaultClientEntry( null );
+        control = null;
+    }
+
+    
+    /**
+     * Set the Distinguished Name
+     * 
+     * @param dn
+     *            The Distinguished Name
+     */
+    public void setDn( LdapDN dn )
+    {
+        entry.setDn( (LdapDN)dn.clone() );
+    }
+
+    
+    /**
+     * Set the Distinguished Name
+     * 
+     * @param dn
+     *            The Distinguished Name
+     */
+    public void setDn( String dn ) throws InvalidNameException
+    {
+        LdapDN ldapDn = new LdapDN( dn );
+        entry.setDn( ldapDn );
+    }
+
+
+    /**
+     * Set the modification type
+     * 
+     * @param changeType
+     *            The change type
+     * 
+     */
+    public void setChangeType( ChangeType changeType )
+    {
+        this.changeType = changeType;
+    }
+
+    /**
+     * Set the change type
+     * 
+     * @param changeType
+     *            The change type
+     */
+    public void setChangeType( String changeType )
+    {
+        if ( "add".equals( changeType ) )
+        {
+            this.changeType = ChangeType.Add;
+        }
+        else if ( "modify".equals( changeType ) )
+        {
+            this.changeType = ChangeType.Modify;
+        }
+        else if ( "moddn".equals( changeType ) )
+        {
+            this.changeType = ChangeType.ModDn;
+        }
+        else if ( "modrdn".equals( changeType ) )
+        {
+            this.changeType = ChangeType.ModRdn;
+        }
+        else if ( "delete".equals( changeType ) )
+        {
+            this.changeType = ChangeType.Delete;
+        }
+    }
+
+    /**
+     * Add a modification item (used by modify operations)
+     * 
+     * @param modification The modification to be added
+     */
+    public void addModificationItem( Modification modification )
+    {
+        if ( changeType == ChangeType.Modify )
+        {
+            modificationList.add( modification );
+            modificationItems.put( modification.getAttribute().getId(), modification );
+        }
+    }
+
+    /**
+     * Add a modification item (used by modify operations)
+     * 
+     * @param modOp The operation. One of : 
+     * - ModificationOperation.ADD_ATTRIBUTE
+     * - ModificationOperation.REMOVE_ATTRIBUTE 
+     * - ModificationOperation.REPLACE_ATTRIBUTE
+     * 
+     * @param attr The attribute to be added
+     */
+    public void addModificationItem( ModificationOperation modOp, EntryAttribute attr )
+    {
+        if ( changeType == ChangeType.Modify )
+        {
+            Modification item = new ClientModification( modOp, attr );
+            modificationList.add( item );
+            modificationItems.put( attr.getId(), item );
+        }
+    }
+
+
+    /**
+     * Add a modification item
+     * 
+     * @param modOp The operation. One of : 
+     *  - ModificationOperation.ADD_ATTRIBUTE
+     *  - ModificationOperation.REMOVE_ATTRIBUTE 
+     *  - ModificationOperation.REPLACE_ATTRIBUTE
+     * 
+     * @param modOp The modification operation value
+     * @param id The attribute's ID
+     * @param value The attribute's value
+     */
+    public void addModificationItem( ModificationOperation modOp, String id, Object value )
+    {
+        if ( changeType == ChangeType.Modify )
+        {
+            EntryAttribute attr =  null;
+            
+            if ( value == null )
+            {
+                value = new ClientStringValue( null );
+                attr = new DefaultClientAttribute( id, (Value<?>)value );
+            }
+            else
+            {
+                attr = (EntryAttribute)value;
+            }
+
+            Modification item = new ClientModification( modOp, attr );
+            modificationList.add( item );
+            modificationItems.put( id, item );
+        }
+    }
+
+
+    /**
+     * Add an attribute to the entry
+     * 
+     * @param attr
+     *            The attribute to be added
+     */
+    public void addAttribute( EntryAttribute attr ) throws NamingException
+    {
+        entry.put( attr );
+    }
+
+    /**
+     * Add an attribute to the entry
+     * 
+     * @param id
+     *            The attribute ID
+     * 
+     * @param value
+     *            The attribute value
+     * 
+     */
+    public void addAttribute( String id, Object value ) throws NamingException
+    {
+        if ( value instanceof String )
+        {
+            entry.add( id, (String)value );
+        }
+        else
+        {
+            entry.add( id, (byte[])value );
+        }
+    }
+    
+    
+    /**
+     * Remove a list of Attributes from the LdifEntry
+     *
+     * @param ids The Attributes to remove
+     * @return The list of removed EntryAttributes
+     */
+    public List<EntryAttribute> removeAttribute( String... ids )
+    {
+        if ( entry.containsAttribute( ids ) )
+        {
+            return entry.removeAttributes( ids );
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+    /**
+     * Add an attribute value to an existing attribute
+     * 
+     * @param id
+     *            The attribute ID
+     * 
+     * @param value
+     *            The attribute value
+     * 
+     */
+    public void putAttribute( String id, Object value ) throws NamingException
+    {
+        if ( value instanceof String )
+        {
+            entry.add( id, (String)value );
+        }
+        else
+        {
+            entry.add( id, (byte[])value );
+        }
+    }
+
+    /**
+     * Get the change type
+     * 
+     * @return The change type. One of : ADD = 0; MODIFY = 1; MODDN = 2; MODRDN =
+     *         3; DELETE = 4;
+     */
+    public ChangeType getChangeType()
+    {
+        return changeType;
+    }
+
+    /**
+     * @return The list of modification items
+     */
+    public List<Modification> getModificationItems()
+    {
+        return modificationList;
+    }
+
+
+    /**
+     * Gets the modification items as an array.
+     *
+     * @return modification items as an array.
+     */
+    public Modification[] getModificationItemsArray()
+    {
+        return modificationList.toArray( EMPTY_MODS );
+    }
+
+
+    /**
+     * @return The entry Distinguished name
+     */
+    public LdapDN getDn()
+    {
+        return entry.getDn();
+    }
+
+    /**
+     * @return The number of entry modifications
+     */
+    public int size()
+    {
+        return modificationList.size();
+    }
+
+    /**
+     * Returns a attribute given it's id
+     * 
+     * @param attributeId
+     *            The attribute Id
+     * @return The attribute if it exists
+     */
+    public EntryAttribute get( String attributeId )
+    {
+        if ( "dn".equalsIgnoreCase( attributeId ) )
+        {
+            return new DefaultClientAttribute( "dn", entry.getDn().getName() );
+        }
+
+        return entry.get( attributeId );
+    }
+
+    /**
+     * Get the entry's entry
+     * 
+     * @return the stored Entry
+     */
+    public Entry getEntry()
+    {
+        if ( isEntry() )
+        {
+            return entry;
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+    /**
+     * @return True, if the old RDN should be deleted.
+     */
+    public boolean isDeleteOldRdn()
+    {
+        return deleteOldRdn;
+    }
+
+    /**
+     * Set the flage deleteOldRdn
+     * 
+     * @param deleteOldRdn
+     *            True if the old RDN should be deleted
+     */
+    public void setDeleteOldRdn( boolean deleteOldRdn )
+    {
+        this.deleteOldRdn = deleteOldRdn;
+    }
+
+    /**
+     * @return The new RDN
+     */
+    public String getNewRdn()
+    {
+        return newRdn;
+    }
+
+    /**
+     * Set the new RDN
+     * 
+     * @param newRdn
+     *            The new RDN
+     */
+    public void setNewRdn( String newRdn )
+    {
+        this.newRdn = newRdn;
+    }
+
+    /**
+     * @return The new superior
+     */
+    public String getNewSuperior()
+    {
+        return newSuperior;
+    }
+
+    /**
+     * Set the new superior
+     * 
+     * @param newSuperior
+     *            The new Superior
+     */
+    public void setNewSuperior( String newSuperior )
+    {
+        this.newSuperior = newSuperior;
+    }
+
+    /**
+     * @return True if the entry is an ADD entry
+     */
+    public boolean isChangeAdd()
+    {
+        return changeType == ChangeType.Add;
+    }
+
+    /**
+     * @return True if the entry is a DELETE entry
+     */
+    public boolean isChangeDelete()
+    {
+        return changeType == ChangeType.Delete;
+    }
+
+    /**
+     * @return True if the entry is a MODDN entry
+     */
+    public boolean isChangeModDn()
+    {
+        return changeType == ChangeType.ModDn;
+    }
+
+    /**
+     * @return True if the entry is a MODRDN entry
+     */
+    public boolean isChangeModRdn()
+    {
+        return changeType == ChangeType.ModRdn;
+    }
+
+    /**
+     * @return True if the entry is a MODIFY entry
+     */
+    public boolean isChangeModify()
+    {
+        return changeType == ChangeType.Modify;
+    }
+
+    /**
+     * Tells if the current entry is a added one
+     *
+     * @return <code>true</code> if the entry is added
+     */
+    public boolean isEntry()
+    {
+        return changeType == ChangeType.Add;
+    }
+
+    /**
+     * @return The associated control, if any
+     */
+    public Control getControl()
+    {
+        return control;
+    }
+
+    /**
+     * Add a control to the entry
+     * 
+     * @param control
+     *            The control
+     */
+    public void setControl( Control control )
+    {
+        this.control = control;
+    }
+
+    /**
+     * Clone method
+     * @return a clone of the current instance
+     * @exception CloneNotSupportedException If there is some problem while cloning the instance
+     */
+    public LdifEntry clone() throws CloneNotSupportedException
+    {
+        LdifEntry clone = (LdifEntry) super.clone();
+
+        if ( modificationList != null )
+        {
+            for ( Modification modif:modificationList )
+            {
+                Modification modifClone = new ClientModification( modif.getOperation(), 
+                    (EntryAttribute) modif.getAttribute().clone() );
+                clone.modificationList.add( modifClone );
+            }
+        }
+
+        if ( modificationItems != null )
+        {
+            for ( String key:modificationItems.keySet() )
+            {
+                Modification modif = modificationItems.get( key );
+                Modification modifClone = new ClientModification( modif.getOperation(), 
+                    (EntryAttribute) modif.getAttribute().clone() );
+                clone.modificationItems.put( key, modifClone );
+            }
+
+        }
+
+        if ( entry != null )
+        {
+            clone.entry = (ClientEntry)entry.clone();
+        }
+
+        return clone;
+    }
+    
+    /**
+     * Dumps the attributes
+     * @return A String representing the attributes
+     */
+    private String dumpAttributes()
+    {
+        StringBuffer sb = new StringBuffer();
+        
+        for ( EntryAttribute attribute:entry )
+        {
+            if ( attribute == null )
+            {
+                sb.append( "        Null attribute\n" );
+                continue;
+            }
+            
+            sb.append( "        ").append( attribute.getId() ).append( ":\n" );
+            
+            for ( Value<?> value:attribute )
+            {
+                if ( !value.isBinary() )
+                {
+                    sb.append(  "            " ).append( value.getString() ).append('\n' );
+                }
+                else
+                {
+                    sb.append(  "            " ).append( StringTools.dumpBytes( value.getBytes() ) ).append('\n' );
+                }
+            }
+        }
+        
+        return sb.toString();
+    }
+    
+    /**
+     * Dumps the modifications
+     * @return A String representing the modifications
+     */
+    private String dumpModificationItems()
+    {
+        StringBuffer sb = new StringBuffer();
+        
+        for ( Modification modif:modificationList )
+        {
+            sb.append( "            Operation: " );
+            
+            switch ( modif.getOperation() )
+            {
+                case ADD_ATTRIBUTE :
+                    sb.append( "ADD\n" );
+                    break;
+                    
+                case REMOVE_ATTRIBUTE :
+                    sb.append( "REMOVE\n" );
+                    break;
+                    
+                case REPLACE_ATTRIBUTE :
+                    sb.append( "REPLACE \n" );
+                    break;
+                    
+                default :
+                    break; // Do nothing
+            }
+            
+            EntryAttribute attribute = modif.getAttribute();
+            
+            sb.append( "                Attribute: " ).append( attribute.getId() ).append( '\n' );
+            
+            if ( attribute.size() != 0 )
+            {
+                for ( Value<?> value:attribute )
+                {
+                    if ( !value.isBinary() )
+                    {
+                        sb.append(  "                " ).append( value.getString() ).append('\n' );
+                    }
+                    else
+                    {
+                        sb.append(  "                " ).append( StringTools.dumpBytes( value.getBytes() ) ).append('\n' );
+                    }
+                }
+            }
+        }
+        
+        return sb.toString();
+    }
+
+    
+    /**
+     * @return a String representing the Entry, as a LDIF 
+     */
+    public String toString()
+    {
+        try
+        {
+            return LdifUtils.convertToLdif( this );
+        }
+        catch ( NamingException ne )
+        {
+            return null;
+        }
+    }
+    
+    
+    /**
+     * @see Object#hashCode()
+     * 
+     * @return the instance's hash code
+     */
+    public int hashCode()
+    {
+        int result = 37;
+
+        if ( entry.getDn() != null )
+        {
+            result = result*17 + entry.getDn().hashCode();
+        }
+        
+        if ( changeType != null )
+        {
+            result = result*17 + changeType.hashCode();
+            
+            // Check each different cases
+            switch ( changeType )
+            {
+                case Add :
+                    // Checks the attributes
+                    if ( entry != null )
+                    {
+                        result = result * 17 + entry.hashCode();
+                    }
+                    
+                    break;
+
+                case Delete :
+                    // Nothing to compute
+                    break;
+                    
+                case Modify :
+                    if ( modificationList != null )
+                    {
+                        result = result * 17 + modificationList.hashCode();
+                        
+                        for ( Modification modification:modificationList )
+                        {
+                            result = result * 17 + modification.hashCode();
+                        }
+                    }
+                    
+                    break;
+                    
+                case ModDn :
+                case ModRdn :
+                    result = result * 17 + ( deleteOldRdn ? 1 : -1 ); 
+                    
+                    if ( newRdn != null )
+                    {
+                        result = result*17 + newRdn.hashCode();
+                    }
+                    
+                    if ( newSuperior != null )
+                    {
+                        result = result*17 + newSuperior.hashCode();
+                    }
+                    
+                    break;
+                    
+                default :
+                    break; // do nothing
+            }
+        }
+
+        if ( control != null )
+        {
+            result = result * 17 + control.hashCode();
+        }
+
+        return result;
+    }
+    
+    /**
+     * @see Object#equals(Object)
+     * @return <code>true</code> if both values are equal
+     */
+    public boolean equals( Object o )
+    {
+        // Basic equals checks
+        if ( this == o )
+        {
+            return true;
+        }
+        
+        if ( o == null )
+        {
+           return false;
+        }
+        
+        if ( ! (o instanceof LdifEntry ) )
+        {
+            return false;
+        }
+        
+        LdifEntry otherEntry = (LdifEntry)o;
+        
+        // Check the DN
+        LdapDN thisDn = entry.getDn();
+        LdapDN dnEntry = otherEntry.getDn();
+        
+        if ( !thisDn.equals( dnEntry ) )
+        {
+            return false;
+        }
+
+        
+        // Check the changeType
+        if ( changeType != otherEntry.changeType )
+        {
+            return false;
+        }
+        
+        // Check each different cases
+        switch ( changeType )
+        {
+            case Add :
+                // Checks the attributes
+                if ( entry == null )
+                {
+                    if ( otherEntry.entry != null )
+                    {
+                        return false;
+                    }
+                    else
+                    {
+                        break;
+                    }
+                }
+                
+                if ( otherEntry.entry == null )
+                {
+                    return false;
+                }
+                
+                if ( entry.size() != otherEntry.entry.size() )
+                {
+                    return false;
+                }
+                
+                if ( !entry.equals( otherEntry.entry ) )
+                {
+                    return false;
+                }
+                
+                break;
+
+            case Delete :
+                // Nothing to do, if the DNs are equals
+                break;
+                
+            case Modify :
+                // Check the modificationItems list
+
+                // First, deal with special cases
+                if ( modificationList == null )
+                {
+                    if ( otherEntry.modificationList != null )
+                    {
+                        return false;
+                    }
+                    else
+                    {
+                        break;
+                    }
+                }
+                
+                if ( otherEntry.modificationList == null )
+                {
+                    return false;
+                }
+                
+                if ( modificationList.size() != otherEntry.modificationList.size() )
+                {
+                    return false;
+                }
+                
+                // Now, compares the contents
+                int i = 0;
+                
+                for ( Modification modification:modificationList )
+                {
+                    if ( ! modification.equals( otherEntry.modificationList.get( i ) ) )
+                    {
+                        return false;
+                    }
+                    
+                    i++;
+                }
+                
+                break;
+                
+            case ModDn :
+            case ModRdn :
+                // Check the deleteOldRdn flag
+                if ( deleteOldRdn != otherEntry.deleteOldRdn )
+                {
+                    return false;
+                }
+                
+                // Check the newRdn value
+                try
+                {
+                    RDN thisNewRdn = new RDN( newRdn );
+                    RDN entryNewRdn = new RDN( otherEntry.newRdn );
+
+                    if ( !thisNewRdn.equals( entryNewRdn ) )
+                    {
+                        return false;
+                    }
+                }
+                catch ( InvalidNameException ine )
+                {
+                    return false;
+                }
+                
+                // Check the newSuperior value
+                try
+                {
+                    LdapDN thisNewSuperior = new LdapDN( newSuperior );
+                    LdapDN entryNewSuperior = new LdapDN( otherEntry.newSuperior );
+                    
+                    if ( ! thisNewSuperior.equals(  entryNewSuperior ) )
+                    {
+                        return false;
+                    }
+                }
+                catch ( InvalidNameException ine )
+                {
+                    return false;
+                }
+                
+                break;
+                
+            default :
+                break; // do nothing
+        }
+        
+        if ( control != null )
+        {
+            return control.equals( otherEntry.control );
+        }
+        else 
+        {
+            return otherEntry.control == null;
+        }
+    }
+
+
+    /**
+     * @see Externalizable#readExternal(ObjectInput)
+     * 
+     * @param in The stream from which the LdifEntry is read
+     * @throws IOException If the stream can't be read
+     * @throws ClassNotFoundException If the LdifEntry can't be created 
+     */
+    public void readExternal( ObjectInput in ) throws IOException , ClassNotFoundException
+    {
+        // Read the changeType
+        int type = in.readInt();
+        changeType = ChangeType.getChangeType( type );
+        entry = (ClientEntry)in.readObject();
+        
+        switch ( changeType )
+        {
+            case Add :
+                // Fallback
+            case Delete :
+                // we don't have anything to read, but the control
+                break;
+
+            case ModDn :
+                // Fallback
+            case ModRdn :
+                deleteOldRdn = in.readBoolean();
+                
+                if ( in.readBoolean() )
+                {
+                    newRdn = in.readUTF();
+                }
+                
+                if ( in.readBoolean() )
+                {
+                    newSuperior = in.readUTF();
+                }
+                
+                break;
+                
+            case Modify :
+                // Read the modification
+                int nbModifs = in.readInt();
+                
+                
+                for ( int i = 0; i < nbModifs; i++ )
+                {
+                    int operation = in.readInt();
+                    String modStr = in.readUTF();
+                    DefaultClientAttribute value = (DefaultClientAttribute)in.readObject();
+                    
+                    addModificationItem( ModificationOperation.getOperation( operation ), modStr, value );
+                }
+                
+                break;
+        }
+        
+        if ( in.available() > 0 )
+        {
+            // We have a control
+            control = (Control)in.readObject();
+        }
+    }
+
+
+    /**
+     * @see Externalizable#readExternal(ObjectInput)<p>
+     *
+     *@param out The stream in which the ChangeLogEvent will be serialized. 
+     *
+     *@throws IOException If the serialization fail
+     */
+    public void writeExternal( ObjectOutput out ) throws IOException
+    {
+        // Write the changeType
+        out.writeInt( changeType.getChangeType() );
+        
+        // Write the entry
+        out.writeObject( entry );
+        
+        // Write the data
+        switch ( changeType )
+        {
+            case Add :
+                // Fallback
+            case Delete :
+                // we don't have anything to write, but the control
+                break;
+
+            case ModDn :
+                // Fallback
+            case ModRdn :
+                out.writeBoolean( deleteOldRdn );
+                
+                if ( newRdn != null )
+                {
+                    out.writeBoolean( true );
+                    out.writeUTF( newRdn );
+                }
+                else
+                {
+                    out.writeBoolean( false );
+                }
+                
+                if ( newSuperior != null )
+                {
+                    out.writeBoolean( true );
+                    out.writeUTF( newSuperior );
+                }
+                else
+                {
+                    out.writeBoolean( false );
+                }
+                break;
+                
+            case Modify :
+                // Read the modification
+                out.writeInt( modificationList.size() );
+                
+                for ( Modification modification:modificationList )
+                {
+                    out.writeInt( modification.getOperation().getValue() );
+                    out.writeUTF( modification.getAttribute().getId() );
+                    
+                    EntryAttribute attribute = modification.getAttribute();
+                    out.writeObject( attribute );
+                }
+                
+                break;
+        }
+        
+        if ( control != null )
+        {
+            // Write the control
+            out.writeObject( control );
+            
+        }
+        
+        // and flush the result
+        out.flush();
+    }
+}