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<String, Set<ObjectClass>>();
57      }
58  
59  
60      /**
61       * {@inheritDoc}
62       */
63      public boolean hasDescendants( String ancestorId ) throws LdapException
64      {
65          try
66          {
67              String oid = getOidByName( ancestorId );
68              Set<ObjectClass> descendants = oidToDescendants.get( oid );
69              return ( descendants != null ) && !descendants.isEmpty();
70          }
71          catch ( LdapException ne )
72          {
73              throw new LdapNoSuchAttributeException( ne.getMessage(), ne );
74          }
75      }
76  
77  
78      /**
79       * {@inheritDoc}
80       */
81      @SuppressWarnings("unchecked")
82      public Iterator<ObjectClass> descendants( String ancestorId ) throws LdapException
83      {
84          try
85          {
86              String oid = getOidByName( ancestorId );
87              Set<ObjectClass> descendants = oidToDescendants.get( oid );
88  
89              if ( descendants == null )
90              {
91                  return Collections.EMPTY_SET.iterator();
92              }
93  
94              return descendants.iterator();
95          }
96          catch ( LdapException ne )
97          {
98              throw new LdapNoSuchAttributeException( ne.getMessage(), ne );
99          }
100     }
101 
102 
103     /**
104      * {@inheritDoc}
105      */
106     public void registerDescendants( ObjectClass objectClass, List<ObjectClass> ancestors )
107         throws LdapException
108     {
109         // add this attribute to descendant list of other attributes in superior chain
110         if ( ( ancestors == null ) || ( ancestors.size() == 0 ) )
111         {
112             return;
113         }
114 
115         for ( ObjectClass ancestor : ancestors )
116         {
117             // Get the ancestor's descendant, if any
118             Set<ObjectClass> descendants = oidToDescendants.get( ancestor.getOid() );
119 
120             // Initialize the descendant Set to store the descendants for the attributeType
121             if ( descendants == null )
122             {
123                 descendants = new HashSet<ObjectClass>( 1 );
124                 oidToDescendants.put( ancestor.getOid(), descendants );
125             }
126 
127             // Add the current ObjectClass as a descendant
128             descendants.add( objectClass );
129 
130             try
131             {
132                 // And recurse until we reach the top of the hierarchy
133                 registerDescendants( objectClass, ancestor.getSuperiors() );
134             }
135             catch ( LdapException ne )
136             {
137                 throw new LdapNoSuchAttributeException( ne.getMessage(), ne );
138             }
139         }
140     }
141 
142 
143     /**
144      * {@inheritDoc}
145      */
146     public void unregisterDescendants( ObjectClass attributeType, List<ObjectClass> ancestors )
147         throws LdapException
148     {
149         // add this attribute to descendant list of other attributes in superior chain
150         if ( ( ancestors == null ) || ( ancestors.size() == 0 ) )
151         {
152             return;
153         }
154 
155         for ( ObjectClass ancestor : ancestors )
156         {
157             // Get the ancestor's descendant, if any
158             Set<ObjectClass> descendants = oidToDescendants.get( ancestor.getOid() );
159 
160             if ( descendants != null )
161             {
162                 descendants.remove( attributeType );
163 
164                 if ( descendants.size() == 0 )
165                 {
166                     oidToDescendants.remove( ancestor.getOid() );
167                 }
168             }
169 
170             try
171             {
172                 // And recurse until we reach the top of the hierarchy
173                 unregisterDescendants( attributeType, ancestor.getSuperiors() );
174             }
175             catch ( LdapException ne )
176             {
177                 throw new LdapNoSuchAttributeException( ne.getMessage(), ne );
178             }
179         }
180     }
181 
182 
183     /**
184      * {@inheritDoc}
185      */
186     public ObjectClass unregister( String numericOid ) throws LdapException
187     {
188         try
189         {
190             ObjectClass removed = super.unregister( numericOid );
191 
192             // Deleting an ObjectClass which might be used as a superior means we have
193             // to recursively update the descendant map. We also have to remove
194             // the at.oid -> descendant relation
195             oidToDescendants.remove( numericOid );
196 
197             // Now recurse if needed
198             unregisterDescendants( removed, removed.getSuperiors() );
199 
200             return removed;
201         }
202         catch ( LdapException ne )
203         {
204             throw new LdapNoSuchAttributeException( ne.getMessage(), ne );
205         }
206     }
207 
208 
209     /**
210      * {@inheritDoc}
211      */
212     public DefaultObjectClassRegistry copy()
213     {
214         DefaultObjectClassRegistry copy = new DefaultObjectClassRegistry();
215 
216         // Copy the base data
217         copy.copy( this );
218 
219         return copy;
220     }
221 
222 
223     /**
224      * {@inheritDoc}
225      */
226     public void clear()
227     {
228         // Clear the contained SchemaObjects
229         for ( SchemaObject objectClass : oidRegistry )
230         {
231             objectClass.clear();
232         }
233 
234         // First clear the shared elements
235         super.clear();
236 
237         // and clear the descendant
238         for ( String oid : oidToDescendants.keySet() )
239         {
240             Set<ObjectClass> descendants = oidToDescendants.get( oid );
241 
242             if ( descendants != null )
243             {
244                 descendants.clear();
245             }
246         }
247 
248         oidToDescendants.clear();
249     }
250 }