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<String, OidNormalizer>();
67          oidToDescendantSet = new HashMap<String, Set<AttributeType>>();
68      }
69  
70  
71      /**
72       * {@inheritDoc}
73       */
74      public Map<String, OidNormalizer> getNormalizerMapping()
75      {
76          return Collections.unmodifiableMap( oidNormalizerMap );
77      }
78  
79  
80      /**
81       * {@inheritDoc}
82       */
83      public boolean hasDescendants( String ancestorId ) throws LdapException
84      {
85          try
86          {
87              String oid = getOidByName( ancestorId );
88              Set<AttributeType> descendants = oidToDescendantSet.get( oid );
89              return ( descendants != null ) && !descendants.isEmpty();
90          }
91          catch ( LdapException ne )
92          {
93              throw new LdapNoSuchAttributeException( ne.getMessage(), ne );
94          }
95      }
96  
97  
98      /**
99       * {@inheritDoc}
100      */
101     public boolean hasDescendants( AttributeType ancestor ) throws LdapException
102     {
103         String oid = ancestor.getOid();
104         Set<AttributeType> descendants = oidToDescendantSet.get( oid );
105         return ( descendants != null ) && !descendants.isEmpty();
106     }
107 
108 
109     /**
110      * {@inheritDoc}
111      */
112     @SuppressWarnings("unchecked")
113     public Iterator<AttributeType> descendants( String ancestorId ) throws LdapException
114     {
115         try
116         {
117             String oid = getOidByName( ancestorId );
118             Set<AttributeType> descendants = oidToDescendantSet.get( oid );
119 
120             if ( descendants == null )
121             {
122                 return Collections.EMPTY_SET.iterator();
123             }
124 
125             return descendants.iterator();
126         }
127         catch ( LdapException ne )
128         {
129             throw new LdapNoSuchAttributeException( ne.getMessage(), ne );
130         }
131     }
132 
133 
134     /**
135      * {@inheritDoc}
136      */
137     @SuppressWarnings("unchecked")
138     public Iterator<AttributeType> descendants( AttributeType ancestor ) throws LdapException
139     {
140         String oid = ancestor.getOid();
141         Set<AttributeType> descendants = oidToDescendantSet.get( oid );
142 
143         if ( descendants == null )
144         {
145             return Collections.EMPTY_SET.iterator();
146         }
147 
148         return descendants.iterator();
149     }
150 
151 
152     /**
153      * {@inheritDoc}
154      */
155     public void registerDescendants( AttributeType attributeType, AttributeType ancestor ) throws LdapException
156     {
157         // add this attribute to descendant list of other attributes in superior chain
158         if ( ancestor == null )
159         {
160             return;
161         }
162 
163         // Get the ancestor's descendant, if any
164         Set<AttributeType> descendants = oidToDescendantSet.get( ancestor.getOid() );
165 
166         // Initialize the descendant Set to store the descendants for the attributeType
167         if ( descendants == null )
168         {
169             descendants = new HashSet<AttributeType>( 1 );
170             oidToDescendantSet.put( ancestor.getOid(), descendants );
171         }
172 
173         // Add the current type as a descendant
174         descendants.add( attributeType );
175     }
176 
177 
178     /**
179      * {@inheritDoc}
180      */
181     public void unregisterDescendants( AttributeType attributeType, AttributeType ancestor ) throws LdapException
182     {
183         // add this attribute to descendant list of other attributes in superior chain
184         if ( ancestor == null )
185         {
186             return;
187         }
188 
189         // Get the ancestor's descendant, if any
190         Set<AttributeType> descendants = oidToDescendantSet.get( ancestor.getOid() );
191 
192         if ( descendants != null )
193         {
194             descendants.remove( attributeType );
195 
196             if ( descendants.size() == 0 )
197             {
198                 oidToDescendantSet.remove( ancestor.getOid() );
199             }
200         }
201     }
202 
203 
204     /**
205      * {@inheritDoc}
206      */
207     public AttributeType unregister( String numericOid ) throws LdapException
208     {
209         try
210         {
211             AttributeType removed = super.unregister( numericOid );
212 
213             removeMappingFor( removed );
214 
215             // Deleting an AT which might be used as a superior means we have
216             // to recursively update the descendant map. We also have to remove
217             // the at.oid -> descendant relation
218             oidToDescendantSet.remove( numericOid );
219 
220             // Now recurse if needed
221             unregisterDescendants( removed, removed.getSuperior() );
222 
223             return removed;
224         }
225         catch ( LdapException ne )
226         {
227             throw new LdapNoSuchAttributeException( ne.getMessage(), ne );
228         }
229     }
230 
231 
232     /**
233      * {@inheritDoc}
234      */
235     public void addMappingFor( AttributeType attributeType ) throws LdapException
236     {
237         MatchingRule equality = attributeType.getEquality();
238         OidNormalizer oidNormalizer;
239         String oid = attributeType.getOid();
240 
241         if ( equality == null )
242         {
243             LOG.debug( "Attribute {} does not have an EQUALITY MatchingRule : using NoopNormalizer", attributeType
244                 .getName() );
245             oidNormalizer = new OidNormalizer( oid, new NoOpNormalizer( attributeType.getOid() ) );
246         }
247         else
248         {
249             oidNormalizer = new OidNormalizer( oid, equality.getNormalizer() );
250         }
251 
252         oidNormalizerMap.put( oid, oidNormalizer );
253 
254         // Also inject the attributeType's short names in the map
255         for ( String name : attributeType.getNames() )
256         {
257             oidNormalizerMap.put( Strings.toLowerCase( name ), oidNormalizer );
258         }
259     }
260 
261 
262     /**
263      * Remove the AttributeType normalizer from the OidNormalizer map 
264      */
265     public void removeMappingFor( AttributeType attributeType ) throws LdapException
266     {
267         if ( attributeType == null )
268         {
269             return;
270         }
271 
272         oidNormalizerMap.remove( attributeType.getOid() );
273 
274         // We also have to remove all the short names for this attribute
275         for ( String name : attributeType.getNames() )
276         {
277             oidNormalizerMap.remove( Strings.toLowerCase( name ) );
278         }
279     }
280 
281 
282     /**
283      * {@inheritDoc}
284      */
285     public AttributeType lookup( String oid ) throws LdapException
286     {
287         try
288         {
289             return super.lookup( oid );
290         }
291         catch ( LdapException ne )
292         {
293             throw new LdapNoSuchAttributeException( ne.getMessage(), ne );
294         }
295     }
296 
297 
298     /**
299      * {@inheritDoc}
300      */
301     public AttributeTypeRegistry copy()
302     {
303         DefaultAttributeTypeRegistry copy = new DefaultAttributeTypeRegistry();
304 
305         // Copy the base data
306         copy.copy( this );
307 
308         return copy;
309     }
310 
311 
312     /**
313      * {@inheritDoc}
314      */
315     public void clear()
316     {
317         // First clear the shared elements
318         super.clear();
319 
320         // clear the OidNormalizer map
321         oidNormalizerMap.clear();
322 
323         // and clear the descendant
324         for ( String oid : oidToDescendantSet.keySet() )
325         {
326             Set<AttributeType> descendants = oidToDescendantSet.get( oid );
327 
328             if ( descendants != null )
329             {
330                 descendants.clear();
331             }
332         }
333 
334         oidToDescendantSet.clear();
335     }
336 }