001    /*
002     *  Licensed to the Apache Software Foundation (ASF) under one
003     *  or more contributor license agreements.  See the NOTICE file
004     *  distributed with this work for additional information
005     *  regarding copyright ownership.  The ASF licenses this file
006     *  to you under the Apache License, Version 2.0 (the
007     *  "License"); you may not use this file except in compliance
008     *  with the License.  You may obtain a copy of the License at
009     *  
010     *    http://www.apache.org/licenses/LICENSE-2.0
011     *  
012     *  Unless required by applicable law or agreed to in writing,
013     *  software distributed under the License is distributed on an
014     *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     *  KIND, either express or implied.  See the License for the
016     *  specific language governing permissions and limitations
017     *  under the License. 
018     *  
019     */
020    package org.apache.directory.shared.ldap.schema.registries;
021    
022    
023    import java.util.Collections;
024    import java.util.HashMap;
025    import java.util.HashSet;
026    import java.util.Iterator;
027    import java.util.List;
028    import java.util.Map;
029    import java.util.Set;
030    
031    import org.apache.directory.shared.ldap.exception.LdapException;
032    import org.apache.directory.shared.ldap.exception.LdapNoSuchAttributeException;
033    import org.apache.directory.shared.ldap.schema.ObjectClass;
034    import org.apache.directory.shared.ldap.schema.SchemaObject;
035    import org.apache.directory.shared.ldap.schema.SchemaObjectType;
036    import org.slf4j.Logger;
037    import org.slf4j.LoggerFactory;
038    
039    
040    /**
041     * An ObjectClass registry's service default implementation.
042     *
043     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
044     * @version $Rev: 828111 $
045     */
046    public class DefaultObjectClassRegistry extends DefaultSchemaObjectRegistry<ObjectClass> 
047        implements ObjectClassRegistry
048    {
049        /** static class logger */
050        private static final Logger LOG = LoggerFactory.getLogger( DefaultObjectClassRegistry.class );
051    
052        /** Speedup for DEBUG mode */
053        private static final boolean IS_DEBUG = LOG.isDebugEnabled();
054    
055        /** maps OIDs to a Set of descendants for that OID */
056        private Map<String,Set<ObjectClass>> oidToDescendants;
057    
058        /**
059         * Creates a new default ObjectClassRegistry instance.
060         */
061        public DefaultObjectClassRegistry()
062        {
063            super( SchemaObjectType.OBJECT_CLASS, new OidRegistry() );
064            oidToDescendants = new HashMap<String,Set<ObjectClass>>();
065        }
066        
067        
068        /**
069         * {@inheritDoc}
070         */
071        public boolean hasDescendants( String ancestorId ) throws LdapException
072        {
073            try
074            {
075                String oid = getOidByName( ancestorId );
076                Set<ObjectClass> descendants = oidToDescendants.get( oid );
077                return (descendants != null) && !descendants.isEmpty();
078            }
079            catch ( LdapException ne )
080            {
081                throw new LdapNoSuchAttributeException( ne.getMessage() );
082            }
083        }
084        
085        
086        /**
087         * {@inheritDoc}
088         */
089        @SuppressWarnings("unchecked")
090        public Iterator<ObjectClass> descendants( String ancestorId ) throws LdapException
091        {
092            try
093            {
094                String oid = getOidByName( ancestorId );
095                Set<ObjectClass> descendants = oidToDescendants.get( oid );
096                
097                if ( descendants == null )
098                {
099                    return Collections.EMPTY_SET.iterator();
100                }
101                
102                return descendants.iterator();
103            }
104            catch ( LdapException ne )
105            {
106                throw new LdapNoSuchAttributeException( ne.getMessage() );
107            }
108        }
109    
110        
111        /**
112         * {@inheritDoc}
113         */
114        public void registerDescendants( ObjectClass objectClass, List<ObjectClass> ancestors ) 
115            throws LdapException
116        {
117            // add this attribute to descendant list of other attributes in superior chain
118            if ( ( ancestors == null ) || ( ancestors.size() == 0 ) ) 
119            {
120                return;
121            }
122            
123            for ( ObjectClass ancestor : ancestors )
124            {
125                // Get the ancestor's descendant, if any
126                Set<ObjectClass> descendants = oidToDescendants.get( ancestor.getOid() );
127        
128                // Initialize the descendant Set to store the descendants for the attributeType
129                if ( descendants == null )
130                {
131                    descendants = new HashSet<ObjectClass>( 1 );
132                    oidToDescendants.put( ancestor.getOid(), descendants );
133                }
134                
135                // Add the current ObjectClass as a descendant
136                descendants.add( objectClass );
137                
138                try
139                {
140                    // And recurse until we reach the top of the hierarchy
141                    registerDescendants( objectClass, ancestor.getSuperiors() );
142                }
143                catch ( LdapException ne )
144                {
145                    throw new LdapNoSuchAttributeException( ne.getMessage() );
146                }
147            }
148        }
149        
150        
151        /**
152         * {@inheritDoc}
153         */
154        public void unregisterDescendants( ObjectClass attributeType, List<ObjectClass> ancestors ) 
155            throws LdapException
156        {
157            // add this attribute to descendant list of other attributes in superior chain
158            if ( ( ancestors == null ) || ( ancestors.size() == 0 ) ) 
159            {
160                return;
161            }
162            
163            for ( ObjectClass ancestor : ancestors )
164            {
165                // Get the ancestor's descendant, if any
166                Set<ObjectClass> descendants = oidToDescendants.get( ancestor.getOid() );
167        
168                if ( descendants != null )
169                {
170                    descendants.remove( attributeType );
171                    
172                    if ( descendants.size() == 0 )
173                    {
174                        oidToDescendants.remove( descendants );
175                    }
176                }
177                
178                try
179                {
180                    // And recurse until we reach the top of the hierarchy
181                    unregisterDescendants( attributeType, ancestor.getSuperiors() );
182                }
183                catch ( LdapException ne )
184                {
185                    throw new LdapNoSuchAttributeException( ne.getMessage() );
186                }
187            }
188        }
189        
190        
191        /**
192         * {@inheritDoc}
193         */
194        public ObjectClass unregister( String numericOid ) throws LdapException
195        {
196            try
197            {
198                ObjectClass removed = super.unregister( numericOid );
199        
200                // Deleting an ObjectClass which might be used as a superior means we have
201                // to recursively update the descendant map. We also have to remove
202                // the at.oid -> descendant relation
203                oidToDescendants.remove( numericOid );
204                
205                // Now recurse if needed
206                unregisterDescendants( removed, removed.getSuperiors() );
207                
208                return removed;
209            }
210            catch ( LdapException ne )
211            {
212                throw new LdapNoSuchAttributeException( ne.getMessage() );
213            }
214        }
215        
216        
217        /**
218         * {@inheritDoc}
219         */
220        public DefaultObjectClassRegistry copy()
221        {
222            DefaultObjectClassRegistry copy = new DefaultObjectClassRegistry();
223            
224            // Copy the base data
225            copy.copy( this );
226            
227            return copy;
228        }
229    
230    
231        /**
232         * {@inheritDoc}
233         */
234        public void clear()
235        {
236            // Clear the contained SchemaObjects
237            for ( SchemaObject objectClass : oidRegistry )
238            {
239                objectClass.clear();
240            }
241            
242            // First clear the shared elements
243            super.clear();
244            
245            // and clear the descendant
246            for ( String oid : oidToDescendants.keySet() )
247            {
248                Set<ObjectClass> descendants = oidToDescendants.get( oid );
249                
250                if ( descendants != null )
251                {
252                    descendants.clear();
253                }
254            }
255            
256            oidToDescendants.clear();
257        }
258    }