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.Map;
28  import java.util.Set;
29  
30  import org.apache.directory.api.ldap.model.exception.LdapException;
31  import org.apache.directory.api.ldap.model.exception.LdapNoSuchAttributeException;
32  import org.apache.directory.api.ldap.model.schema.AttributeType;
33  import org.apache.directory.api.ldap.model.schema.MatchingRule;
34  import org.apache.directory.api.ldap.model.schema.SchemaObjectType;
35  import org.apache.directory.api.ldap.model.schema.normalizers.NoOpNormalizer;
36  import org.apache.directory.api.ldap.model.schema.normalizers.OidNormalizer;
37  import org.apache.directory.api.util.Strings;
38  import org.slf4j.Logger;
39  import org.slf4j.LoggerFactory;
40  
41  
42  /**
43   * An AttributeType registry service default implementation.
44   *
45   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
46   */
47  public class DefaultAttributeTypeRegistry extends DefaultSchemaObjectRegistry<AttributeType> implements
48      AttributeTypeRegistry
49  {
50      /** static class logger */
51      private static final Logger LOG = LoggerFactory.getLogger( DefaultAttributeTypeRegistry.class );
52  
53      /** cached Oid/normalizer mapping */
54      private Map<String, OidNormalizer> oidNormalizerMap;
55  
56      /** maps OIDs to a Set of descendants for that OID */
57      private Map<String, Set<AttributeType>> oidToDescendantSet;
58  
59  
60      /**
61       * Creates a new default AttributeTypeRegistry instance.
62       */
63      public DefaultAttributeTypeRegistry()
64      {
65          super( SchemaObjectType.ATTRIBUTE_TYPE, new OidRegistry<AttributeType>() );
66          oidNormalizerMap = new HashMap<>();
67          oidToDescendantSet = new HashMap<>();
68      }
69  
70  
71      /**
72       * {@inheritDoc}
73       */
74      @Override
75      public Map<String, OidNormalizer> getNormalizerMapping()
76      {
77          return Collections.unmodifiableMap( oidNormalizerMap );
78      }
79  
80  
81      /**
82       * {@inheritDoc}
83       */
84      @Override
85      public boolean hasDescendants( String ancestorId ) throws LdapException
86      {
87          try
88          {
89              String oid = getOidByName( ancestorId );
90              Set<AttributeType> descendants = oidToDescendantSet.get( oid );
91              return ( descendants != null ) && !descendants.isEmpty();
92          }
93          catch ( LdapException ne )
94          {
95              throw new LdapNoSuchAttributeException( ne.getMessage(), ne );
96          }
97      }
98  
99  
100     /**
101      * {@inheritDoc}
102      */
103     @Override
104     public boolean hasDescendants( AttributeType ancestor ) throws LdapException
105     {
106         String oid = ancestor.getOid();
107         Set<AttributeType> descendants = oidToDescendantSet.get( oid );
108         return ( descendants != null ) && !descendants.isEmpty();
109     }
110 
111 
112     /**
113      * {@inheritDoc}
114      */
115     @SuppressWarnings("unchecked")
116     @Override
117     public Iterator<AttributeType> descendants( String ancestorId ) throws LdapException
118     {
119         try
120         {
121             String oid = getOidByName( ancestorId );
122             Set<AttributeType> descendants = oidToDescendantSet.get( oid );
123 
124             if ( descendants == null )
125             {
126                 return Collections.EMPTY_SET.iterator();
127             }
128 
129             return descendants.iterator();
130         }
131         catch ( LdapException ne )
132         {
133             throw new LdapNoSuchAttributeException( ne.getMessage(), ne );
134         }
135     }
136 
137 
138     /**
139      * {@inheritDoc}
140      */
141     @SuppressWarnings("unchecked")
142     @Override
143     public Iterator<AttributeType> descendants( AttributeType ancestor ) throws LdapException
144     {
145         String oid = ancestor.getOid();
146         Set<AttributeType> descendants = oidToDescendantSet.get( oid );
147 
148         if ( descendants == null )
149         {
150             return Collections.EMPTY_SET.iterator();
151         }
152 
153         return descendants.iterator();
154     }
155 
156 
157     /**
158      * {@inheritDoc}
159      */
160     @Override
161     public void registerDescendants( AttributeType attributeType, AttributeType ancestor ) throws LdapException
162     {
163         // add this attribute to descendant list of other attributes in superior chain
164         if ( ancestor == null )
165         {
166             return;
167         }
168 
169         // Get the ancestor's descendant, if any
170         Set<AttributeType> descendants = oidToDescendantSet.get( ancestor.getOid() );
171 
172         // Initialize the descendant Set to store the descendants for the attributeType
173         if ( descendants == null )
174         {
175             descendants = new HashSet<>( 1 );
176             oidToDescendantSet.put( ancestor.getOid(), descendants );
177         }
178 
179         // Add the current type as a descendant
180         descendants.add( attributeType );
181     }
182 
183 
184     /**
185      * {@inheritDoc}
186      */
187     @Override
188     public void unregisterDescendants( AttributeType attributeType, AttributeType ancestor ) throws LdapException
189     {
190         // add this attribute to descendant list of other attributes in superior chain
191         if ( ancestor == null )
192         {
193             return;
194         }
195 
196         // Get the ancestor's descendant, if any
197         Set<AttributeType> descendants = oidToDescendantSet.get( ancestor.getOid() );
198 
199         if ( descendants != null )
200         {
201             descendants.remove( attributeType );
202 
203             if ( descendants.isEmpty() )
204             {
205                 oidToDescendantSet.remove( ancestor.getOid() );
206             }
207         }
208     }
209 
210 
211     /**
212      * {@inheritDoc}
213      */
214     @Override
215     public AttributeType unregister( String numericOid ) throws LdapException
216     {
217         try
218         {
219             AttributeType removed = super.unregister( numericOid );
220 
221             removeMappingFor( removed );
222 
223             // Deleting an AT which might be used as a superior means we have
224             // to recursively update the descendant map. We also have to remove
225             // the at.oid -> descendant relation
226             oidToDescendantSet.remove( numericOid );
227 
228             // Now recurse if needed
229             unregisterDescendants( removed, removed.getSuperior() );
230 
231             return removed;
232         }
233         catch ( LdapException ne )
234         {
235             throw new LdapNoSuchAttributeException( ne.getMessage(), ne );
236         }
237     }
238 
239 
240     /**
241      * {@inheritDoc}
242      */
243     @Override
244     public void addMappingFor( AttributeType attributeType ) throws LdapException
245     {
246         MatchingRule equality = attributeType.getEquality();
247         OidNormalizer oidNormalizer;
248         String oid = attributeType.getOid();
249 
250         if ( equality == null )
251         {
252             LOG.debug( "Attribute {} does not have an EQUALITY MatchingRule : using NoopNormalizer", attributeType
253                 .getName() );
254             oidNormalizer = new OidNormalizer( oid, new NoOpNormalizer( attributeType.getOid() ) );
255         }
256         else
257         {
258             oidNormalizer = new OidNormalizer( oid, equality.getNormalizer() );
259         }
260 
261         oidNormalizerMap.put( oid, oidNormalizer );
262 
263         // Also inject the attributeType's short names in the map
264         for ( String name : attributeType.getNames() )
265         {
266             oidNormalizerMap.put( Strings.toLowerCaseAscii( name ), oidNormalizer );
267         }
268     }
269 
270 
271     /**
272      * Remove the AttributeType normalizer from the OidNormalizer map 
273      */
274     @Override
275     public void removeMappingFor( AttributeType attributeType ) throws LdapException
276     {
277         if ( attributeType == null )
278         {
279             return;
280         }
281 
282         oidNormalizerMap.remove( attributeType.getOid() );
283 
284         // We also have to remove all the short names for this attribute
285         for ( String name : attributeType.getNames() )
286         {
287             oidNormalizerMap.remove( Strings.toLowerCaseAscii( name ) );
288         }
289     }
290 
291 
292     /**
293      * {@inheritDoc}
294      */
295     @Override
296     public AttributeType lookup( String oid ) throws LdapException
297     {
298         try
299         {
300             return super.lookup( oid );
301         }
302         catch ( LdapException ne )
303         {
304             throw new LdapNoSuchAttributeException( ne.getMessage(), ne );
305         }
306     }
307 
308 
309     /**
310      * {@inheritDoc}
311      */
312     @Override
313     public DefaultAttributeTypeRegistry copy()
314     {
315         DefaultAttributeTypeRegistry copy = new DefaultAttributeTypeRegistry();
316 
317         // Copy the base data
318         copy.copy( this );
319 
320         return copy;
321     }
322 
323 
324     /**
325      * {@inheritDoc}
326      */
327     @Override
328     public void clear()
329     {
330         // First clear the shared elements
331         super.clear();
332 
333         // clear the OidNormalizer map
334         oidNormalizerMap.clear();
335 
336         // and clear the descendant
337         for ( Map.Entry<String, Set<AttributeType>> entry : oidToDescendantSet.entrySet() )
338         {
339             Set<AttributeType> descendants = entry.getValue();
340 
341             if ( descendants != null )
342             {
343                 descendants.clear();
344             }
345         }
346 
347         oidToDescendantSet.clear();
348     }
349 }