directory-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From akaras...@apache.org
Subject svn commit: r291027 - in /directory/apacheds/trunk/core/src: main/java/org/apache/ldap/server/schema/SchemaChecker.java main/java/org/apache/ldap/server/schema/SchemaService.java test/resources/log4j.properties
Date Thu, 22 Sep 2005 22:43:53 GMT
Author: akarasulu
Date: Thu Sep 22 15:43:47 2005
New Revision: 291027

URL: http://svn.apache.org/viewcvs?rev=291027&view=rev
Log:
moved schema checking functionality from the modify handler of the ldap p-p into the schema
checking interceptor

Modified:
    directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/schema/SchemaChecker.java
    directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/schema/SchemaService.java
    directory/apacheds/trunk/core/src/test/resources/log4j.properties

Modified: directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/schema/SchemaChecker.java
URL: http://svn.apache.org/viewcvs/directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/schema/SchemaChecker.java?rev=291027&r1=291026&r2=291027&view=diff
==============================================================================
--- directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/schema/SchemaChecker.java
(original)
+++ directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/schema/SchemaChecker.java
Thu Sep 22 15:43:47 2005
@@ -48,7 +48,6 @@
     /** the SLF4J logger for this class */
     private static Logger log = LoggerFactory.getLogger( SchemaChecker.class );
 
-
     /**
      * Makes sure modify operations do not leave the entry without a STRUCTURAL
      * objectClass.  At least one STRUCTURAL objectClass must be specified for

Modified: directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/schema/SchemaService.java
URL: http://svn.apache.org/viewcvs/directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/schema/SchemaService.java?rev=291027&r1=291026&r2=291027&view=diff
==============================================================================
--- directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/schema/SchemaService.java
(original)
+++ directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/schema/SchemaService.java
Thu Sep 22 15:43:47 2005
@@ -34,6 +34,7 @@
 import org.apache.ldap.common.filter.SimpleNode;
 import org.apache.ldap.common.message.LockableAttributeImpl;
 import org.apache.ldap.common.message.LockableAttributesImpl;
+import org.apache.ldap.common.message.ResultCodeEnum;
 import org.apache.ldap.common.name.LdapName;
 import org.apache.ldap.common.schema.AttributeType;
 import org.apache.ldap.common.schema.DITContentRule;
@@ -46,6 +47,10 @@
 import org.apache.ldap.common.schema.Syntax;
 import org.apache.ldap.common.util.SingletonEnumeration;
 import org.apache.ldap.common.util.DateUtils;
+import org.apache.ldap.common.util.AttributeUtils;
+import org.apache.ldap.common.exception.LdapSchemaViolationException;
+import org.apache.ldap.common.exception.LdapInvalidAttributeIdentifierException;
+import org.apache.ldap.common.exception.LdapNoSuchAttributeException;
 import org.apache.ldap.server.configuration.InterceptorConfiguration;
 import org.apache.ldap.server.enumeration.SearchResultFilteringEnumeration;
 import org.apache.ldap.server.enumeration.SearchResultFilter;
@@ -88,12 +93,14 @@
      */
     private GlobalRegistries globalRegistries;
 
-    private AttributeTypeRegistry attributeRegistry;
-
     /**
      * subschemaSubentry attribute's value from Root DSE
      */
     private String subentryDn;
+
+    /**
+     * The time when the server started up.
+     */
     private String startUpTimeStamp;
 
     /**
@@ -109,7 +116,6 @@
     {
         this.nexus = factoryCfg.getPartitionNexus();
         this.globalRegistries = factoryCfg.getGlobalRegistries();
-        attributeRegistry = globalRegistries.getAttributeTypeRegistry();
         binaryAttributeFilter = new BinaryAttributeFilter();
 
         // stuff for dealing with subentries (garbage for now)
@@ -388,15 +394,151 @@
     }
 
 
+    /**
+     * Checks to see if an attribute is required by as determined from an entry's
+     * set of objectClass attribute values.
+     *
+     * @param attrId the attribute to test if required by a set of objectClass values
+     * @param objectClass the objectClass values
+     * @return true if the objectClass values require the attribute, false otherwise
+     * @throws NamingException if the attribute is not recognized
+     */
+    private boolean isRequired( String attrId, Attribute objectClass ) throws NamingException
+    {
+        OidRegistry oidRegistry = globalRegistries.getOidRegistry();
+        ObjectClassRegistry registry = globalRegistries.getObjectClassRegistry();
+
+        if ( ! oidRegistry.hasOid( attrId ) )
+        {
+            return false;
+        }
+
+        String attrOid = oidRegistry.getOid( attrId );
+        for ( int ii = 0; ii < objectClass.size(); ii++ )
+        {
+            ObjectClass ocSpec = registry.lookup( ( String ) objectClass.get( ii ) );
+            AttributeType[] mustList = ocSpec.getMustList();
+            for ( int jj = 0; jj < mustList.length; jj++ )
+            {
+                if ( mustList[jj].getOid().equals( attrOid ) )
+                {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+
+    /**
+     * Checks to see if removing a set of attributes from an entry completely removes
+     * that attribute's values.  If change has zero size then all attributes are
+     * presumed to be removed.
+     *
+     * @param change
+     * @param entry
+     * @return
+     * @throws NamingException
+     */
+    private boolean isCompleteRemoval( Attribute change, Attributes entry ) throws NamingException
+    {
+        // if change size is 0 then all values are deleted then we're screwed
+        if ( change.size() == 0 )
+        {
+            return true;
+        }
+
+        // can't do math to figure our if all values are removed since some
+        // values in the modify request may not be in the entry.  we need to
+        // remove the values from a cloned version of the attribute and see
+        // if nothing is left.
+        Attribute changedEntryAttr = entry.get( change.getID() );
+        for ( int jj = 0; jj < change.size(); jj++ )
+        {
+            changedEntryAttr.remove( change.get( jj ) );
+        }
+        if ( changedEntryAttr.size() == 0 )
+        {
+            return true;
+        }
+
+        return false;
+    }
+
+
+    Attribute getResultantObjectClasses( int modOp, Attribute changes, Attribute existing
) throws NamingException
+    {
+        if ( changes == null && existing == null )
+        {
+            return new LockableAttributeImpl( "objectClass" );
+        }
+
+        if ( changes == null )
+        {
+            return existing;
+        }
+
+        if ( existing == null && modOp == DirContext.ADD_ATTRIBUTE )
+        {
+            return changes;
+        }
+        else if ( existing == null )
+        {
+            return new LockableAttributeImpl( "objectClasses" );
+        }
+
+        switch( modOp )
+        {
+            case( DirContext.ADD_ATTRIBUTE ):
+                return AttributeUtils.getUnion( existing, changes );
+            case( DirContext.REPLACE_ATTRIBUTE ):
+                return ( Attribute ) changes.clone();
+            case( DirContext.REMOVE_ATTRIBUTE ):
+                return AttributeUtils.getDifference( existing, changes );
+            default:
+                throw new InternalError( "" );
+        }
+    }
+
+
     public void modify( NextInterceptor next, Name name, int modOp, Attributes mods ) throws
NamingException
     {
+        Attributes entry = nexus.lookup( name );
+        Attribute objectClass = getResultantObjectClasses( modOp, mods.get( "objectClass"),
entry.get( "objectClass" ) );
         ObjectClassRegistry ocRegistry = this.globalRegistries.getObjectClassRegistry();
+        AttributeTypeRegistry atRegistry = this.globalRegistries.getAttributeTypeRegistry();
+
+        NamingEnumeration changes = mods.getIDs();
+        while ( changes.hasMore() )
+        {
+            String id = ( String ) changes.next();
+            Attribute change = mods.get( id );
+
+            if ( ! atRegistry.hasAttributeType( change.getID() ) && ! objectClass.contains(
"extensibleObject" ) )
+            {
+                throw new LdapInvalidAttributeIdentifierException();
+            }
+
+            if ( modOp == DirContext.REMOVE_ATTRIBUTE && entry.get( change.getID()
) == null )
+            {
+                throw new LdapNoSuchAttributeException();
+            }
+
+            // for required attributes we need to check if all values are removed
+            // if so then we have a schema violation that must be thrown
+            if ( modOp == DirContext.REMOVE_ATTRIBUTE &&
+                 isRequired( change.getID(), objectClass ) &&
+                 isCompleteRemoval( change, entry ) )
+            {
+                throw new LdapSchemaViolationException( ResultCodeEnum.OBJECTCLASSVIOLATION
);
+            }
+        }
 
         if ( modOp == DirContext.REMOVE_ATTRIBUTE )
         {
             SchemaChecker.preventRdnChangeOnModifyRemove( name, modOp, mods );
-            Attribute ocAttr = this.nexus.lookup( name ).get( "objectClass" );
-            SchemaChecker.preventStructuralClassRemovalOnModifyRemove( ocRegistry, name,
modOp, mods, ocAttr );
+            SchemaChecker.preventStructuralClassRemovalOnModifyRemove( ocRegistry, name,
modOp, mods, objectClass );
         }
 
         if ( modOp == DirContext.REPLACE_ATTRIBUTE )
@@ -411,18 +553,56 @@
 
     public void modify( NextInterceptor next, Name name, ModificationItem[] mods ) throws
NamingException
     {
+        Attributes entry = nexus.lookup( name );
+
+        ModificationItem objectClassMod = null;
+        for ( int ii = 0; ii < mods.length; ii++ )
+        {
+            if ( ( ( String ) mods[ii].getAttribute().getID() ).equalsIgnoreCase( "objectclass"
) )
+            {
+                objectClassMod = mods[ii];
+            }
+        }
+        Attribute objectClass = null;
+
+        if ( objectClassMod == null )
+        {
+            objectClass = entry.get( "objectClass" );
+        }
+        else
+        {
+            objectClass = getResultantObjectClasses( objectClassMod.getModificationOp(),
+                    objectClassMod.getAttribute(), entry.get( "objectClass" ) );
+        }
+
         ObjectClassRegistry ocRegistry = this.globalRegistries.getObjectClassRegistry();
+        AttributeTypeRegistry atRegistry = this.globalRegistries.getAttributeTypeRegistry();
 
         for ( int ii = 0; ii < mods.length; ii++ )
         {
             int modOp = mods[ii].getModificationOp();
             Attribute change = mods[ii].getAttribute();
 
+            if ( ! atRegistry.hasAttributeType( change.getID() ) && ! objectClass.contains(
"extensibleObject" ) )
+            {
+                throw new LdapInvalidAttributeIdentifierException();
+            }
+
+            if ( modOp == DirContext.REMOVE_ATTRIBUTE && entry.get( change.getID()
) == null )
+            {
+                throw new LdapNoSuchAttributeException();
+            }
+
             if ( modOp == DirContext.REMOVE_ATTRIBUTE )
             {
+                // for required attributes we need to check if all values are removed
+                // if so then we have a schema violation that must be thrown
+                if ( isRequired( change.getID(), objectClass ) && isCompleteRemoval(
change, entry ) )
+                {
+                    throw new LdapSchemaViolationException( ResultCodeEnum.OBJECTCLASSVIOLATION
);
+                }
                 SchemaChecker.preventRdnChangeOnModifyRemove( name, modOp, change );
-                Attribute ocAttr = this.nexus.lookup( name ).get( "objectClass" );
-                SchemaChecker.preventStructuralClassRemovalOnModifyRemove( ocRegistry, name,
modOp, change, ocAttr );
+                SchemaChecker.preventStructuralClassRemovalOnModifyRemove( ocRegistry, name,
modOp, change, objectClass );
             }
 
             if ( modOp == DirContext.REPLACE_ATTRIBUTE )
@@ -457,7 +637,7 @@
 
             for ( int ii = 0; ii < binaryArray.length; ii++ )
             {
-                AttributeType type = attributeRegistry.lookup( binaryArray[ii] );
+                AttributeType type = globalRegistries.getAttributeTypeRegistry().lookup(
binaryArray[ii] );
 
                 binaries.add( type );
             }
@@ -477,9 +657,9 @@
 
             boolean asBinary = false;
 
-            if ( attributeRegistry.hasAttributeType( id ) )
+            if ( globalRegistries.getAttributeTypeRegistry().hasAttributeType( id ) )
             {
-                type = attributeRegistry.lookup( id );
+                type = globalRegistries.getAttributeTypeRegistry().lookup( id );
             }
 
             if ( type != null )

Modified: directory/apacheds/trunk/core/src/test/resources/log4j.properties
URL: http://svn.apache.org/viewcvs/directory/apacheds/trunk/core/src/test/resources/log4j.properties?rev=291027&r1=291026&r2=291027&view=diff
==============================================================================
--- directory/apacheds/trunk/core/src/test/resources/log4j.properties (original)
+++ directory/apacheds/trunk/core/src/test/resources/log4j.properties Thu Sep 22 15:43:47
2005
@@ -1,4 +1,4 @@
-log4j.rootCategory=DEBUG, stdout
+log4j.rootCategory=INFO, stdout
 
 log4j.appender.stdout=org.apache.log4j.ConsoleAppender
 log4j.appender.stdout.layout=org.apache.log4j.PatternLayout



Mime
View raw message