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 javax.naming.NamingException;
032    import javax.naming.directory.NoSuchAttributeException;
033    
034    import org.apache.directory.shared.ldap.schema.ObjectClass;
035    import org.apache.directory.shared.ldap.schema.SchemaObject;
036    import org.apache.directory.shared.ldap.schema.SchemaObjectType;
037    import org.slf4j.Logger;
038    import org.slf4j.LoggerFactory;
039    
040    
041    /**
042     * An ObjectClass registry's service default implementation.
043     *
044     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
045     * @version $Rev: 828111 $
046     */
047    public class DefaultObjectClassRegistry extends DefaultSchemaObjectRegistry<ObjectClass> 
048        implements ObjectClassRegistry
049    {
050        /** static class logger */
051        private static final Logger LOG = LoggerFactory.getLogger( DefaultObjectClassRegistry.class );
052    
053        /** Speedup for DEBUG mode */
054        private static final boolean IS_DEBUG = LOG.isDebugEnabled();
055    
056        /** maps OIDs to a Set of descendants for that OID */
057        private Map<String,Set<ObjectClass>> oidToDescendants;
058    
059        /**
060         * Creates a new default ObjectClassRegistry instance.
061         */
062        public DefaultObjectClassRegistry()
063        {
064            super( SchemaObjectType.OBJECT_CLASS, new OidRegistry() );
065            oidToDescendants = new HashMap<String,Set<ObjectClass>>();
066        }
067        
068        
069        /**
070         * {@inheritDoc}
071         */
072        public boolean hasDescendants( String ancestorId ) throws NamingException
073        {
074            try
075            {
076                String oid = getOidByName( ancestorId );
077                Set<ObjectClass> descendants = oidToDescendants.get( oid );
078                return (descendants != null) && !descendants.isEmpty();
079            }
080            catch ( NamingException ne )
081            {
082                throw new NoSuchAttributeException( ne.getMessage() );
083            }
084        }
085        
086        
087        /**
088         * {@inheritDoc}
089         */
090        @SuppressWarnings("unchecked")
091        public Iterator<ObjectClass> descendants( String ancestorId ) throws NamingException
092        {
093            try
094            {
095                String oid = getOidByName( ancestorId );
096                Set<ObjectClass> descendants = oidToDescendants.get( oid );
097                
098                if ( descendants == null )
099                {
100                    return Collections.EMPTY_SET.iterator();
101                }
102                
103                return descendants.iterator();
104            }
105            catch ( NamingException ne )
106            {
107                throw new NoSuchAttributeException( ne.getMessage() );
108            }
109        }
110    
111        
112        /**
113         * {@inheritDoc}
114         */
115        public void registerDescendants( ObjectClass objectClass, List<ObjectClass> ancestors ) 
116            throws NamingException
117        {
118            // add this attribute to descendant list of other attributes in superior chain
119            if ( ( ancestors == null ) || ( ancestors.size() == 0 ) ) 
120            {
121                return;
122            }
123            
124            for ( ObjectClass ancestor : ancestors )
125            {
126                // Get the ancestor's descendant, if any
127                Set<ObjectClass> descendants = oidToDescendants.get( ancestor.getOid() );
128        
129                // Initialize the descendant Set to store the descendants for the attributeType
130                if ( descendants == null )
131                {
132                    descendants = new HashSet<ObjectClass>( 1 );
133                    oidToDescendants.put( ancestor.getOid(), descendants );
134                }
135                
136                // Add the current ObjectClass as a descendant
137                descendants.add( objectClass );
138                
139                try
140                {
141                    // And recurse until we reach the top of the hierarchy
142                    registerDescendants( objectClass, ancestor.getSuperiors() );
143                }
144                catch ( NamingException ne )
145                {
146                    throw new NoSuchAttributeException( ne.getMessage() );
147                }
148            }
149        }
150        
151        
152        /**
153         * {@inheritDoc}
154         */
155        public void unregisterDescendants( ObjectClass attributeType, List<ObjectClass> ancestors ) 
156            throws NamingException
157        {
158            // add this attribute to descendant list of other attributes in superior chain
159            if ( ( ancestors == null ) || ( ancestors.size() == 0 ) ) 
160            {
161                return;
162            }
163            
164            for ( ObjectClass ancestor : ancestors )
165            {
166                // Get the ancestor's descendant, if any
167                Set<ObjectClass> descendants = oidToDescendants.get( ancestor.getOid() );
168        
169                if ( descendants != null )
170                {
171                    descendants.remove( attributeType );
172                    
173                    if ( descendants.size() == 0 )
174                    {
175                        oidToDescendants.remove( descendants );
176                    }
177                }
178                
179                try
180                {
181                    // And recurse until we reach the top of the hierarchy
182                    unregisterDescendants( attributeType, ancestor.getSuperiors() );
183                }
184                catch ( NamingException ne )
185                {
186                    throw new NoSuchAttributeException( ne.getMessage() );
187                }
188            }
189        }
190        
191        
192        /**
193         * {@inheritDoc}
194         */
195        public ObjectClass unregister( String numericOid ) throws NamingException
196        {
197            try
198            {
199                ObjectClass removed = super.unregister( numericOid );
200        
201                // Deleting an ObjectClass which might be used as a superior means we have
202                // to recursively update the descendant map. We also have to remove
203                // the at.oid -> descendant relation
204                oidToDescendants.remove( numericOid );
205                
206                // Now recurse if needed
207                unregisterDescendants( removed, removed.getSuperiors() );
208                
209                return removed;
210            }
211            catch ( NamingException ne )
212            {
213                throw new NoSuchAttributeException( ne.getMessage() );
214            }
215        }
216        
217        
218        /**
219         * {@inheritDoc}
220         */
221        public DefaultObjectClassRegistry copy()
222        {
223            DefaultObjectClassRegistry copy = new DefaultObjectClassRegistry();
224            
225            // Copy the base data
226            copy.copy( this );
227            
228            return copy;
229        }
230    
231    
232        /**
233         * {@inheritDoc}
234         */
235        public void clear()
236        {
237            // Clear the contained SchemaObjects
238            for ( SchemaObject objectClass : oidRegistry )
239            {
240                objectClass.clear();
241            }
242            
243            // First clear the shared elements
244            super.clear();
245            
246            // and clear the descendant
247            for ( String oid : oidToDescendants.keySet() )
248            {
249                Set<ObjectClass> descendants = oidToDescendants.get( oid );
250                
251                if ( descendants != null )
252                {
253                    descendants.clear();
254                }
255            }
256            
257            oidToDescendants.clear();
258        }
259    }