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