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 2019/04/19 23:52:50 UTC

[directory-server] branch master updated: Implemented RFC 4525 (Modify Increment operation)

This is an automated email from the ASF dual-hosted git repository.

elecharny pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/directory-server.git


The following commit(s) were added to refs/heads/master by this push:
     new 78d65a8  Implemented RFC 4525 (Modify Increment operation)
78d65a8 is described below

commit 78d65a8994ec65e415c86bbdfb5ee18a9268ce0d
Author: emmanuel lecharny <el...@apache.org>
AuthorDate: Sat Apr 20 01:52:42 2019 +0200

    Implemented RFC 4525 (Modify Increment operation)
---
 .../core/operations/getRootDse/GetRootDseIT.java   |  50 ++++++-
 .../shared/partition/DefaultPartitionNexus.java    |   4 +-
 .../server/core/schema/SchemaInterceptor.java      |  43 ++++++
 .../impl/btree/AbstractBTreePartition.java         | 162 +++++++++++++++++++++
 4 files changed, 250 insertions(+), 9 deletions(-)

diff --git a/core-integ/src/test/java/org/apache/directory/server/core/operations/getRootDse/GetRootDseIT.java b/core-integ/src/test/java/org/apache/directory/server/core/operations/getRootDse/GetRootDseIT.java
index 17c601a..fb553d7 100644
--- a/core-integ/src/test/java/org/apache/directory/server/core/operations/getRootDse/GetRootDseIT.java
+++ b/core-integ/src/test/java/org/apache/directory/server/core/operations/getRootDse/GetRootDseIT.java
@@ -25,6 +25,8 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.entry.Attribute;
 import org.apache.directory.api.ldap.model.entry.Entry;
 import org.apache.directory.ldap.client.api.LdapConnection;
 import org.apache.directory.server.core.api.DirectoryService;
@@ -249,11 +251,13 @@ public class GetRootDseIT extends AbstractLdapTestUnit
     {
         DirectoryService service = getService();
         service.setAccessControlEnabled( false );
-        LdapCoreSessionConnection connection = new LdapCoreSessionConnection( service );
-
-        Entry rootDse = connection.getRootDse();
-
-        assertNotNull( rootDse );
+        
+        try ( LdapCoreSessionConnection connection = new LdapCoreSessionConnection( service ) )
+        {
+            Entry rootDse = connection.getRootDse();
+    
+            assertNotNull( rootDse );
+        }
     }
 
 
@@ -266,10 +270,40 @@ public class GetRootDseIT extends AbstractLdapTestUnit
     {
         DirectoryService service = getService();
         service.setAccessControlEnabled( true );
-        LdapCoreSessionConnection connection = new LdapCoreSessionConnection( service );
+        
+        try ( LdapCoreSessionConnection connection = new LdapCoreSessionConnection( service ) )
+        {
+            Entry rootDse = connection.getRootDse();
+    
+            assertNotNull( rootDse );
+        }
+    }
 
-        Entry rootDse = connection.getRootDse();
 
-        assertNotNull( rootDse );
+    /**
+     * Check the supportedFeatures attribute
+     *
+     * @throws Exception
+     */
+    @Test
+    public void testGetSupportedFeatures() throws Exception
+    {
+        DirectoryService service = getService();
+        service.setAccessControlEnabled( true );
+        
+        try ( LdapCoreSessionConnection connection = new LdapCoreSessionConnection( service ) )
+        {
+            Entry rootDse = connection.getRootDse( SchemaConstants.SUPPORTED_FEATURES_AT );
+            
+            assertNotNull( rootDse );
+            assertTrue( rootDse.containsAttribute( SchemaConstants.SUPPORTED_FEATURES_AT ) );
+            
+            Attribute supportedFeatures = rootDse.get( SchemaConstants.SUPPORTED_FEATURES_AT );
+            
+            assertEquals( 2, supportedFeatures.size() );
+            assertTrue( supportedFeatures.contains( 
+                SchemaConstants.FEATURE_ALL_OPERATIONAL_ATTRIBUTES, 
+                SchemaConstants.FEATURE_MODIFY_INCREMENT ) );
+        }
     }
 }
diff --git a/core-shared/src/main/java/org/apache/directory/server/core/shared/partition/DefaultPartitionNexus.java b/core-shared/src/main/java/org/apache/directory/server/core/shared/partition/DefaultPartitionNexus.java
index 2503628..9f40bf5 100644
--- a/core-shared/src/main/java/org/apache/directory/server/core/shared/partition/DefaultPartitionNexus.java
+++ b/core-shared/src/main/java/org/apache/directory/server/core/shared/partition/DefaultPartitionNexus.java
@@ -150,7 +150,9 @@ public class DefaultPartitionNexus extends AbstractPartition implements Partitio
         // Add the basic informations
         rootDse.put( SchemaConstants.SUBSCHEMA_SUBENTRY_AT, ServerDNConstants.CN_SCHEMA_DN );
         rootDse.put( SchemaConstants.SUPPORTED_LDAP_VERSION_AT, "3" );
-        rootDse.put( SchemaConstants.SUPPORTED_FEATURES_AT, SchemaConstants.FEATURE_ALL_OPERATIONAL_ATTRIBUTES );
+        rootDse.put( SchemaConstants.SUPPORTED_FEATURES_AT, 
+            SchemaConstants.FEATURE_ALL_OPERATIONAL_ATTRIBUTES,
+            SchemaConstants.FEATURE_MODIFY_INCREMENT );
         rootDse.put( SchemaConstants.SUPPORTED_EXTENSION_AT, NoticeOfDisconnect.EXTENSION_OID );
 
         // Add the objectClasses
diff --git a/interceptors/schema/src/main/java/org/apache/directory/server/core/schema/SchemaInterceptor.java b/interceptors/schema/src/main/java/org/apache/directory/server/core/schema/SchemaInterceptor.java
index cc688dc..f415ef2 100644
--- a/interceptors/schema/src/main/java/org/apache/directory/server/core/schema/SchemaInterceptor.java
+++ b/interceptors/schema/src/main/java/org/apache/directory/server/core/schema/SchemaInterceptor.java
@@ -813,6 +813,49 @@ public class SchemaInterceptor extends BaseInterceptor
                     }
 
                     break;
+                    
+                case INCREMENT_ATTRIBUTE:
+                    // The incremented attribute might not exist
+                    if ( !tempEntry.containsAttribute( attributeType ) )
+                    {
+                        throw new IllegalArgumentException( "Increment operation on a non existing attribute"
+                            + attributeType );
+                    }
+                    else if ( !SchemaConstants.INTEGER_SYNTAX.equals( attributeType.getSyntax().getOid() ) )
+                    {
+                        throw new IllegalArgumentException( "Increment operation on a non integer attribute"
+                            + attributeType );
+                    }
+                    else
+                    {
+                        Attribute modified = tempEntry.get( attributeType );
+                        Value[] newValues = new Value[ modified.size() ];
+                        int increment = 1;
+                        int i = 0;
+                        
+                        if ( mod.getAttribute().size() != 0 )
+                        {
+                            increment = Integer.parseInt( mod.getAttribute().getString() );
+                        }
+                        
+                        for ( Value value : modified )
+                        {
+                            int intValue = Integer.parseInt( value.getNormalized() );
+                            
+                            if ( intValue >= Integer.MAX_VALUE - increment )
+                            {
+                                throw new IllegalArgumentException( "Increment operation overflow for attribute" 
+                                    + attributeType );
+                            }
+                            
+                            newValues[i++] = new Value( Integer.toString( intValue + increment ) );
+                            modified.remove( value );
+                        }
+                        
+                        modified.add( newValues );
+                    }
+                    
+                    break;
 
                 default:
                     throw new IllegalArgumentException( "Unexpected modify operation " + mod.getOperation() );
diff --git a/xdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/AbstractBTreePartition.java b/xdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/AbstractBTreePartition.java
index 5dcf74c..c67de8b 100644
--- a/xdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/AbstractBTreePartition.java
+++ b/xdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/AbstractBTreePartition.java
@@ -1443,6 +1443,10 @@ public abstract class AbstractBTreePartition extends AbstractPartition implement
                         modifyReplace( partitionTxn, id, entry, attrMods );
                         break;
     
+                    case INCREMENT_ATTRIBUTE:
+                        modifyIncrement( partitionTxn, id, entry, attrMods );
+                        break;
+    
                     default:
                         throw new LdapException( I18n.err( I18n.ERR_221 ) );
                 }
@@ -1718,6 +1722,164 @@ public abstract class AbstractBTreePartition extends AbstractPartition implement
 
 
     /**
+     * Completely replaces the existing set of values for an attribute with the
+     * modified values supplied affecting the appropriate userIndices.  The entry
+     * is not persisted: it is only changed in anticipation for a put into the
+     * master table.
+     *
+     * @param partitionTxn The transaction to use
+     * @param id the primary key of the entry
+     * @param entry the entry to alter
+     * @param mods the replacement attribute and values
+     * @throws Exception if index alteration or attribute modification
+     * fails.
+     */
+    @SuppressWarnings("unchecked")
+    private void modifyIncrement( PartitionTxn partitionTxn, String id, Entry entry, Attribute mods ) 
+        throws LdapException, IndexNotFoundException
+    {
+        if ( entry instanceof ClonedServerEntry )
+        {
+            throw new LdapOtherException( I18n.err( I18n.ERR_215_CANNOT_STORE_CLONED_SERVER_ENTRY ) );
+        }
+
+        String modsOid = schemaManager.getAttributeTypeRegistry().getOidByName( mods.getId() );
+        AttributeType attributeType = mods.getAttributeType();
+
+        // Special case for the ObjectClass index
+        if ( attributeType.equals( objectClassAT ) )
+        {
+            // if the id exists in the index drop all existing attribute
+            // value index entries and add new ones
+            for ( Value value : entry.get( objectClassAT ) )
+            {
+                if ( value.equals( topOCValue ) )
+                {
+                    continue;
+                }
+                
+                String normalizedOc = objectClassNormalizer.normalize( value.getString() );
+
+                objectClassIdx.drop( partitionTxn, normalizedOc, id );
+            }
+
+            for ( Value value : mods )
+            {
+                if ( value.equals( topOCValue ) )
+                {
+                    continue;
+                }
+                
+                String normalizedOc = objectClassNormalizer.normalize( value.getString() );
+
+                objectClassIdx.add( partitionTxn, normalizedOc, id );
+            }
+        }
+        else if ( hasUserIndexOn( attributeType ) )
+        {
+            Index<?, String> userIndex = getUserIndex( attributeType );
+
+            // Drop all the previous values
+            Attribute oldAttribute = entry.get( mods.getAttributeType() );
+
+            if ( oldAttribute != null )
+            {
+                for ( Value value : oldAttribute )
+                {
+                    String normalized = value.getNormalized();
+                    ( ( Index<Object, String> ) userIndex ).drop( partitionTxn, normalized, id );
+                }
+            }
+
+            // And add the new ones
+            for ( Value value : mods )
+            {
+                String normalized = value.getNormalized();
+                ( ( Index ) userIndex ).add( partitionTxn, normalized, id );
+            }
+
+            /*
+             * If we have no new value, we have to drop the AT fro the presence index
+             */
+            if ( mods.size() == 0 )
+            {
+                presenceIdx.drop( partitionTxn, modsOid, id );
+            }
+        }
+        // Special case for the AdministrativeRole index
+        else if ( attributeType.equals( administrativeRoleAT ) )
+        {
+            // Remove the previous values
+            for ( Value value : entry.get( administrativeRoleAT ) )
+            {
+                if ( value.equals( topOCValue ) )
+                {
+                    continue;
+                }
+                
+                String normalizedOc = objectClassNormalizer.normalize( value.getString() );
+
+                objectClassIdx.drop( partitionTxn, normalizedOc, id );
+            }
+
+            // And add the new ones 
+            for ( Value value : mods )
+            {
+                String valueStr = value.getString();
+
+                if ( valueStr.equals( topOCValue ) )
+                {
+                    continue;
+                }
+                
+                adminRoleIdx.add( partitionTxn, valueStr, id );
+            }
+        }
+
+        String aliasAttributeOid = schemaManager.getAttributeTypeRegistry().getOidByName(
+            SchemaConstants.ALIASED_OBJECT_NAME_AT );
+
+        if ( mods.getAttributeType().equals( aliasedObjectNameAT ) )
+        {
+            dropAliasIndices( partitionTxn, id );
+        }
+
+        // replaces old attributes with new modified ones if they exist
+        Attribute attribute = entry.get( mods.getAttributeType() );
+        Value[] newValues = new Value[ attribute.size() ];
+        int increment = 1;
+        int i = 0;
+        
+        if ( mods.size() != 0 )
+        {
+            increment = Integer.parseInt( mods.getString() );
+        }
+
+        for ( Value value : attribute )
+        {
+            int intValue = Integer.parseInt( value.getNormalized() );
+            
+            if ( intValue >= Integer.MAX_VALUE - increment )
+            {
+                throw new IllegalArgumentException( "Increment operation overflow for attribute" 
+                    + attributeType );
+            }
+            
+            newValues[i++] = new Value( Integer.toString( intValue + increment ) );
+            attribute.remove( value );
+        }
+        
+        attribute.add( newValues );
+
+        if ( modsOid.equals( aliasAttributeOid ) && mods.size() > 0 )
+        {
+            Dn entryDn = getEntryDn( partitionTxn, id );
+            addAliasIndices( partitionTxn, id, entryDn, new Dn( schemaManager, mods.getString() ) );
+        }
+    }
+
+
+    /**
      * Completely removes the set of values for an attribute having the values
      * supplied while affecting the appropriate userIndices.  The entry is not
      * persisted: it is only changed in anticipation for a put into the master