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 * http://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.lang.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.SchemaObject; 034import org.slf4j.Logger; 035import org.slf4j.LoggerFactory; 036 037 038/** 039 * Object identifier registry. It stores the OIDs for AT, OC, MR, LS, MRU, DSR, DCR and NF. 040 * An OID is unique, and associated with a SO. 041 * 042 * @param <T> The type of SchemaObject 043 * 044 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 045 */ 046public class OidRegistry<T extends SchemaObject> implements Iterable<T> 047{ 048 /** static class logger */ 049 private static final Logger LOG = LoggerFactory.getLogger( OidRegistry.class ); 050 051 /** Speedup for DEBUG mode */ 052 private static final boolean IS_DEBUG = LOG.isDebugEnabled(); 053 054 /** Maps OID to a type of SchemaObject */ 055 private Map<String, T> byOid = new HashMap<>(); 056 057 /** A flag indicating that the Registry is relaxed or not */ 058 private boolean isRelaxed = Registries.STRICT; 059 060 061 /** 062 * Tells if the given OID is present on this registry 063 * 064 * @param oid The OID to lookup 065 * @return true if the OID already exists 066 */ 067 public boolean contains( String oid ) 068 { 069 return byOid.containsKey( oid ); 070 } 071 072 073 /** 074 * Gets the primary name associated with an OID. The primary name is the 075 * first name specified for the OID. 076 * 077 * @param oid the object identifier 078 * @return the primary name 079 * @throws LdapException if oid does not exist 080 */ 081 public String getPrimaryName( String oid ) throws LdapException 082 { 083 SchemaObject schemaObject = byOid.get( oid ); 084 085 if ( schemaObject != null ) 086 { 087 return schemaObject.getName(); 088 } 089 else 090 { 091 String msg = I18n.err( I18n.ERR_04286, oid ); 092 LOG.error( msg ); 093 throw new LdapException( msg ); 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_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}