001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020package org.apache.directory.api.ldap.model.schema.registries; 021 022 023import java.util.Collections; 024import java.util.HashMap; 025import java.util.Iterator; 026import java.util.List; 027import java.util.Map; 028 029import org.apache.commons.lang3.ArrayUtils; 030import org.apache.directory.api.asn1.util.Oid; 031import org.apache.directory.api.i18n.I18n; 032import org.apache.directory.api.ldap.model.exception.LdapException; 033import org.apache.directory.api.ldap.model.schema.SchemaErrorHandler; 034import org.apache.directory.api.ldap.model.schema.SchemaObject; 035import org.slf4j.Logger; 036import org.slf4j.LoggerFactory; 037 038 039/** 040 * Object identifier registry. It stores the OIDs for AT, OC, MR, LS, MRU, DSR, DCR and NF. 041 * An OID is unique, and associated with a SO. 042 * 043 * @param <T> The type of SchemaObject 044 * 045 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 046 */ 047public class OidRegistry<T extends SchemaObject> implements Iterable<T> 048{ 049 /** static class logger */ 050 private static final Logger LOG = LoggerFactory.getLogger( OidRegistry.class ); 051 052 /** Maps OID to a type of SchemaObject */ 053 private Map<String, T> byOid = new HashMap<>(); 054 055 /** A flag indicating that the Registry is relaxed or not */ 056 private boolean isRelaxed = Registries.STRICT; 057 058 private SchemaErrorHandler errorHandler; 059 060 /** 061 * Tells if the given OID is present on this registry 062 * 063 * @param oid The OID to lookup 064 * @return true if the OID already exists 065 */ 066 public boolean contains( String oid ) 067 { 068 return byOid.containsKey( oid ); 069 } 070 071 072 /** 073 * Gets the primary name associated with an OID. The primary name is the 074 * first name specified for the OID. 075 * 076 * @param oid the object identifier 077 * @return the primary name 078 * @throws LdapException if oid does not exist 079 */ 080 public String getPrimaryName( String oid ) throws LdapException 081 { 082 SchemaObject schemaObject = byOid.get( oid ); 083 084 if ( schemaObject != null ) 085 { 086 return schemaObject.getName(); 087 } 088 else 089 { 090 String msg = I18n.err( I18n.ERR_13741_OID_NOT_FOUND_IN_REGISTRY, oid ); 091 LdapException error = new LdapException( msg ); 092 errorHandler.handle( LOG, msg, error ); 093 throw error; 094 } 095 } 096 097 098 /** 099 * 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}