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.Iterator;
26  import java.util.List;
27  import java.util.Map;
28  
29  import org.apache.commons.lang.ArrayUtils;
30  import org.apache.directory.api.asn1.util.Oid;
31  import org.apache.directory.api.i18n.I18n;
32  import org.apache.directory.api.ldap.model.exception.LdapException;
33  import org.apache.directory.api.ldap.model.schema.SchemaObject;
34  import org.slf4j.Logger;
35  import org.slf4j.LoggerFactory;
36  
37  
38  /**
39   * Object identifier registry. It stores the OIDs for AT, OC, MR, LS, MRU, DSR, DCR and NF.
40   * An OID is unique, and associated with a SO.
41   * 
42   * @param <T> The type of SchemaObject
43   * 
44   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
45   */
46  public class OidRegistry<T extends SchemaObject> implements Iterable<T>
47  {
48      /** static class logger */
49      private static final Logger LOG = LoggerFactory.getLogger( OidRegistry.class );
50  
51      /** Speedup for DEBUG mode */
52      private static final boolean IS_DEBUG = LOG.isDebugEnabled();
53  
54      /** Maps OID to a type of SchemaObject */
55      private Map<String, T> byOid = new HashMap<>();
56      
57      /** A flag indicating that the Registry is relaxed or not */
58      private boolean isRelaxed = Registries.STRICT;
59  
60  
61      /**
62       * Tells if the given OID is present on this registry
63       * 
64       * @param oid The OID to lookup
65       * @return true if the OID already exists
66       */
67      public boolean contains( String oid )
68      {
69          return byOid.containsKey( oid );
70      }
71  
72  
73      /**
74       * Gets the primary name associated with an OID.  The primary name is the
75       * first name specified for the OID.
76       * 
77       * @param oid the object identifier
78       * @return the primary name
79       * @throws LdapException if oid does not exist
80       */
81      public String getPrimaryName( String oid ) throws LdapException
82      {
83          SchemaObject schemaObject = byOid.get( oid );
84  
85          if ( schemaObject != null )
86          {
87              return schemaObject.getName();
88          }
89          else
90          {
91              String msg = I18n.err( I18n.ERR_04286, oid );
92              LOG.error( msg );
93              throw new LdapException( msg );
94          }
95      }
96  
97  
98      /**
99       * Gets the SchemaObject associated with an OID. 
100      * 
101      * @param oid the object identifier
102      * @return the associated SchemaObject
103      * @throws LdapException if oid does not exist
104      */
105     public T getSchemaObject( String oid ) throws LdapException
106     {
107         T schemaObject = byOid.get( oid );
108 
109         if ( schemaObject != null )
110         {
111             return schemaObject;
112         }
113         else
114         {
115             String msg = I18n.err( I18n.ERR_04287, oid );
116             LOG.error( msg );
117             throw new LdapException( msg );
118         }
119     }
120 
121 
122     /**
123      * Gets the names associated with an OID.  An OID is unique however it may 
124      * have many names used to refer to it.  A good example is the cn and
125      * commonName attribute names for OID 2.5.4.3.  Within a server one name 
126      * within the set must be chosen as the primary name.  This is used to
127      * name certain things within the server internally.  If there is more than
128      * one name then the first name is taken to be the primary.
129      * 
130      * @param oid the OID for which we return the set of common names
131      * @return a sorted set of names
132      * @throws org.apache.directory.api.ldap.model.exception.LdapException if oid does not exist
133      */
134     public List<String> getNameSet( String oid ) throws LdapException
135     {
136         SchemaObject schemaObject = byOid.get( oid );
137 
138         if ( null == schemaObject )
139         {
140             String msg = I18n.err( I18n.ERR_04288, oid );
141             LOG.error( msg );
142             throw new LdapException( msg );
143         }
144 
145         List<String> names = schemaObject.getNames();
146 
147         if ( IS_DEBUG )
148         {
149             LOG.debug( "looked up names '{}' for OID '{}'", ArrayUtils.toString( names ), oid );
150         }
151 
152         return names;
153     }
154 
155 
156     /**
157      * Lists all the OIDs within the registry.  This may be a really big list.
158      * 
159      * @return all the OIDs registered
160      */
161     public Iterator<String> iteratorOids()
162     {
163         return Collections.unmodifiableSet( byOid.keySet() ).iterator();
164     }
165 
166 
167     /**
168      * Lists all the SchemaObjects within the registry.  This may be a really big list.
169      * 
170      * @return all the SchemaObject registered
171      */
172     @Override
173     public Iterator<T> iterator()
174     {
175         return byOid.values().iterator();
176     }
177 
178     
179     /**
180      * Tells if the Registry is permissive or if it must be checked
181      * against inconsistencies.
182      *
183      * @return True if SchemaObjects can be added even if they break the consistency
184      */
185     public boolean isRelaxed()
186     {
187         return isRelaxed;
188     }
189 
190 
191     /**
192      * Tells if the Registry is strict.
193      *
194      * @return True if SchemaObjects cannot be added if they break the consistency
195      */
196     public boolean isStrict()
197     {
198         return !isRelaxed;
199     }
200 
201 
202     /**
203      * Change the Registry to a relaxed mode, where invalid SchemaObjects
204      * can be registered.
205      */
206     public void setRelaxed()
207     {
208         isRelaxed = Registries.RELAXED;
209     }
210 
211 
212     /**
213      * Change the Registry to a strict mode, where invalid SchemaObjects
214      * cannot be registered.
215      */
216     public void setStrict()
217     {
218         isRelaxed = Registries.STRICT;
219     }
220 
221     /**
222      * Adds an OID name pair to the registry.
223      * 
224      * @param schemaObject The SchemaObject the oid belongs to
225      * @throws LdapException If something went wrong
226      */
227     public void register( T schemaObject ) throws LdapException
228     {
229         if ( schemaObject == null )
230         {
231             String message = I18n.err( I18n.ERR_04289 );
232 
233             LOG.debug( message );
234             throw new LdapException( message );
235         }
236 
237         String oid = schemaObject.getOid();
238 
239         if ( isStrict() )
240         {
241             if ( !Oid.isOid( oid ) )
242             {
243                 String message = I18n.err( I18n.ERR_04290 );
244 
245                 LOG.debug( message );
246                 throw new LdapException( message );
247             }
248         }
249         else
250         {
251             if ( ( oid == null ) || oid.isEmpty() )
252             {
253                 throw new LdapException( I18n.err( I18n.ERR_00033_INVALID_OID, "" ) );
254             }
255         }
256 
257         /*
258          * Update OID Map if it does not already exist
259          */
260         if ( byOid.containsKey( oid ) )
261         {
262             String message = I18n.err( I18n.ERR_04291, oid );
263             LOG.info( message );
264             return;
265         }
266         else
267         {
268             byOid.put( oid, schemaObject );
269 
270             if ( IS_DEBUG )
271             {
272                 LOG.debug( "registed SchemaObject '" + schemaObject + "' with OID: " + oid );
273             }
274         }
275     }
276 
277 
278     /**
279      * Store the given SchemaObject into the OidRegistry. Available only to 
280      * the current package. A weak form (no check is done) of the register 
281      * method, define for clone methods.
282      *
283      * @param schemaObject The SchemaObject to inject into the OidRegistry
284      */
285     /* No qualifier */void put( T schemaObject )
286     {
287         byOid.put( schemaObject.getOid(), schemaObject );
288     }
289 
290 
291     /**
292      * Removes an oid from this registry.
293      *
294      * @param oid the numeric identifier for the object
295      * @throws LdapException if the identifier is not numeric
296      */
297     public void unregister( String oid ) throws LdapException
298     {
299         // Removes the <OID, names> from the byOID map
300         SchemaObject removed = byOid.remove( oid );
301 
302         if ( IS_DEBUG )
303         {
304             LOG.debug( "Unregisted SchemaObject '{}' with OID: {}", removed, oid );
305         }
306     }
307 
308 
309     /**
310      * Copy the OidRegistry, without the contained values
311      * 
312      * @return A new OidRegistry instance
313      */
314     public OidRegistry<T> copy()
315     {
316         OidRegistry<T> copy = new OidRegistry<>();
317 
318         // Clone the map
319         copy.byOid = new HashMap<>();
320 
321         return copy;
322     }
323 
324 
325     /**
326      * @return The number of stored OIDs
327      */
328     public int size()
329     {
330         return byOid.size();
331     }
332 
333 
334     /**
335      * Empty the byOid map
336      */
337     public void clear()
338     {
339         // remove all the OID
340         byOid.clear();
341     }
342 
343 
344     /**
345      * @see Object#toString()
346      */
347     @Override
348     public String toString()
349     {
350         StringBuilder sb = new StringBuilder();
351 
352         if ( byOid != null )
353         {
354             boolean isFirst = true;
355 
356             for ( Map.Entry<String, T> entry : byOid.entrySet() )
357             {
358                 if ( isFirst )
359                 {
360                     isFirst = false;
361                 }
362                 else
363                 {
364                     sb.append( ", " );
365                 }
366 
367                 sb.append( "<" );
368 
369                 SchemaObject schemaObject = entry.getValue();
370 
371                 if ( schemaObject != null )
372                 {
373                     sb.append( schemaObject.getObjectType() );
374                     sb.append( ", " );
375                     sb.append( schemaObject.getOid() );
376                     sb.append( ", " );
377                     sb.append( schemaObject.getName() );
378                 }
379 
380                 sb.append( ">" );
381             }
382         }
383 
384         return sb.toString();
385     }
386 }