View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.api.ldap.model.schema.registries;
21  
22  
23  import java.util.Collections;
24  import java.util.HashMap;
25  import java.util.HashSet;
26  import java.util.Iterator;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.Set;
30  
31  import org.apache.directory.api.ldap.model.exception.LdapException;
32  import org.apache.directory.api.ldap.model.exception.LdapNoSuchAttributeException;
33  import org.apache.directory.api.ldap.model.schema.ObjectClass;
34  import org.apache.directory.api.ldap.model.schema.SchemaObject;
35  import org.apache.directory.api.ldap.model.schema.SchemaObjectType;
36  
37  
38  /**
39   * An ObjectClass registry's service default implementation.
40   *
41   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
42   */
43  public class DefaultObjectClassRegistry extends DefaultSchemaObjectRegistry<ObjectClass>
44      implements ObjectClassRegistry
45  {
46      /** maps OIDs to a Set of descendants for that OID */
47      private Map<String, Set<ObjectClass>> oidToDescendants;
48  
49  
50      /**
51       * Creates a new default ObjectClassRegistry instance.
52       */
53      public DefaultObjectClassRegistry()
54      {
55          super( SchemaObjectType.OBJECT_CLASS, new OidRegistry<ObjectClass>() );
56          oidToDescendants = new HashMap<>();
57      }
58  
59  
60      /**
61       * {@inheritDoc}
62       */
63      @Override
64      public boolean hasDescendants( String ancestorId ) throws LdapException
65      {
66          try
67          {
68              String oid = getOidByName( ancestorId );
69              Set<ObjectClass> descendants = oidToDescendants.get( oid );
70              return ( descendants != null ) && !descendants.isEmpty();
71          }
72          catch ( LdapException ne )
73          {
74              throw new LdapNoSuchAttributeException( ne.getMessage(), ne );
75          }
76      }
77  
78  
79      /**
80       * {@inheritDoc}
81       */
82      @SuppressWarnings("unchecked")
83      @Override
84      public Iterator<ObjectClass> descendants( String ancestorId ) throws LdapException
85      {
86          try
87          {
88              String oid = getOidByName( ancestorId );
89              Set<ObjectClass> descendants = oidToDescendants.get( oid );
90  
91              if ( descendants == null )
92              {
93                  return Collections.EMPTY_SET.iterator();
94              }
95  
96              return descendants.iterator();
97          }
98          catch ( LdapException ne )
99          {
100             throw new LdapNoSuchAttributeException( ne.getMessage(), ne );
101         }
102     }
103 
104 
105     /**
106      * {@inheritDoc}
107      */
108     @Override
109     public void registerDescendants( ObjectClass objectClass, List<ObjectClass> ancestors )
110         throws LdapException
111     {
112         // add this attribute to descendant list of other attributes in superior chain
113         if ( ( ancestors == null ) || ancestors.isEmpty() )
114         {
115             return;
116         }
117 
118         for ( ObjectClass ancestor : ancestors )
119         {
120             // Get the ancestor's descendant, if any
121             Set<ObjectClass> descendants = oidToDescendants.get( ancestor.getOid() );
122 
123             // Initialize the descendant Set to store the descendants for the attributeType
124             if ( descendants == null )
125             {
126                 descendants = new HashSet<>( 1 );
127                 oidToDescendants.put( ancestor.getOid(), descendants );
128             }
129 
130             // Add the current ObjectClass as a descendant
131             descendants.add( objectClass );
132 
133             try
134             {
135                 // And recurse until we reach the top of the hierarchy
136                 registerDescendants( objectClass, ancestor.getSuperiors() );
137             }
138             catch ( LdapException ne )
139             {
140                 throw new LdapNoSuchAttributeException( ne.getMessage(), ne );
141             }
142         }
143     }
144 
145 
146     /**
147      * {@inheritDoc}
148      */
149     @Override
150     public void unregisterDescendants( ObjectClass attributeType, List<ObjectClass> ancestors )
151         throws LdapException
152     {
153         // add this attribute to descendant list of other attributes in superior chain
154         if ( ( ancestors == null ) || ancestors.isEmpty() )
155         {
156             return;
157         }
158 
159         for ( ObjectClass ancestor : ancestors )
160         {
161             // Get the ancestor's descendant, if any
162             Set<ObjectClass> descendants = oidToDescendants.get( ancestor.getOid() );
163 
164             if ( descendants != null )
165             {
166                 descendants.remove( attributeType );
167 
168                 if ( descendants.isEmpty() )
169                 {
170                     oidToDescendants.remove( ancestor.getOid() );
171                 }
172             }
173 
174             try
175             {
176                 // And recurse until we reach the top of the hierarchy
177                 unregisterDescendants( attributeType, ancestor.getSuperiors() );
178             }
179             catch ( LdapException ne )
180             {
181                 throw new LdapNoSuchAttributeException( ne.getMessage(), ne );
182             }
183         }
184     }
185 
186 
187     /**
188      * {@inheritDoc}
189      */
190     @Override
191     public ObjectClass unregister( String numericOid ) throws LdapException
192     {
193         try
194         {
195             ObjectClass removed = super.unregister( numericOid );
196 
197             // Deleting an ObjectClass which might be used as a superior means we have
198             // to recursively update the descendant map. We also have to remove
199             // the at.oid -> descendant relation
200             oidToDescendants.remove( numericOid );
201 
202             // Now recurse if needed
203             unregisterDescendants( removed, removed.getSuperiors() );
204 
205             return removed;
206         }
207         catch ( LdapException ne )
208         {
209             throw new LdapNoSuchAttributeException( ne.getMessage(), ne );
210         }
211     }
212 
213 
214     /**
215      * {@inheritDoc}
216      */
217     @Override
218     public DefaultObjectClassRegistry copy()
219     {
220         DefaultObjectClassRegistry copy = new DefaultObjectClassRegistry();
221 
222         // Copy the base data
223         copy.copy( this );
224 
225         return copy;
226     }
227 
228 
229     /**
230      * {@inheritDoc}
231      */
232     @Override
233     public void clear()
234     {
235         // Clear the contained SchemaObjects
236         for ( SchemaObject objectClass : oidRegistry )
237         {
238             objectClass.clear();
239         }
240 
241         // First clear the shared elements
242         super.clear();
243 
244         // and clear the descendant
245         for ( Map.Entry<String, Set<ObjectClass>> entry : oidToDescendants.entrySet() )
246         {
247             Set<ObjectClass> descendants = entry.getValue();
248 
249             if ( descendants != null )
250             {
251                 descendants.clear();
252             }
253         }
254 
255         oidToDescendants.clear();
256     }
257 }