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.shared.ldap.model.schema.registries; 021 022 023import java.util.Collections; 024import java.util.HashMap; 025import java.util.HashSet; 026import java.util.Iterator; 027import java.util.Map; 028import java.util.Set; 029 030import org.apache.directory.shared.ldap.model.exception.LdapException; 031import org.apache.directory.shared.ldap.model.exception.LdapNoSuchAttributeException; 032import org.apache.directory.shared.ldap.model.schema.AttributeType; 033import org.apache.directory.shared.ldap.model.schema.MatchingRule; 034import org.apache.directory.shared.ldap.model.schema.SchemaObjectType; 035import org.apache.directory.shared.ldap.model.schema.normalizers.NoOpNormalizer; 036import org.apache.directory.shared.ldap.model.schema.normalizers.OidNormalizer; 037import org.slf4j.Logger; 038import org.slf4j.LoggerFactory; 039 040 041/** 042 * An AttributeType registry service default implementation. 043 * 044 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 045 */ 046public class DefaultAttributeTypeRegistry extends DefaultSchemaObjectRegistry<AttributeType> implements 047 AttributeTypeRegistry 048{ 049 /** static class logger */ 050 private static final Logger LOG = LoggerFactory.getLogger( DefaultAttributeTypeRegistry.class ); 051 052 /** cached Oid/normalizer mapping */ 053 private Map<String, OidNormalizer> oidNormalizerMap; 054 055 /** maps OIDs to a Set of descendants for that OID */ 056 private Map<String, Set<AttributeType>> oidToDescendantSet; 057 058 059 /** 060 * Creates a new default AttributeTypeRegistry instance. 061 */ 062 public DefaultAttributeTypeRegistry() 063 { 064 super( SchemaObjectType.ATTRIBUTE_TYPE, new OidRegistry<AttributeType>() ); 065 oidNormalizerMap = new HashMap<String, OidNormalizer>(); 066 oidToDescendantSet = new HashMap<String, Set<AttributeType>>(); 067 } 068 069 070 /** 071 * {@inheritDoc} 072 */ 073 public Map<String, OidNormalizer> getNormalizerMapping() 074 { 075 return Collections.unmodifiableMap( oidNormalizerMap ); 076 } 077 078 079 /** 080 * {@inheritDoc} 081 */ 082 public boolean hasDescendants( String ancestorId ) throws LdapException 083 { 084 try 085 { 086 String oid = getOidByName( ancestorId ); 087 Set<AttributeType> descendants = oidToDescendantSet.get( oid ); 088 return ( descendants != null ) && !descendants.isEmpty(); 089 } 090 catch ( LdapException ne ) 091 { 092 throw new LdapNoSuchAttributeException( ne.getMessage(), ne ); 093 } 094 } 095 096 097 /** 098 * {@inheritDoc} 099 */ 100 public boolean hasDescendants( AttributeType ancestor ) throws LdapException 101 { 102 String oid = ancestor.getOid(); 103 Set<AttributeType> descendants = oidToDescendantSet.get( oid ); 104 return ( descendants != null ) && !descendants.isEmpty(); 105 } 106 107 108 /** 109 * {@inheritDoc} 110 */ 111 @SuppressWarnings("unchecked") 112 public Iterator<AttributeType> descendants( String ancestorId ) throws LdapException 113 { 114 try 115 { 116 String oid = getOidByName( ancestorId ); 117 Set<AttributeType> descendants = oidToDescendantSet.get( oid ); 118 119 if ( descendants == null ) 120 { 121 return Collections.EMPTY_SET.iterator(); 122 } 123 124 return descendants.iterator(); 125 } 126 catch ( LdapException ne ) 127 { 128 throw new LdapNoSuchAttributeException( ne.getMessage(), ne ); 129 } 130 } 131 132 133 /** 134 * {@inheritDoc} 135 */ 136 @SuppressWarnings("unchecked") 137 public Iterator<AttributeType> descendants( AttributeType ancestor ) throws LdapException 138 { 139 String oid = ancestor.getOid(); 140 Set<AttributeType> descendants = oidToDescendantSet.get( oid ); 141 142 if ( descendants == null ) 143 { 144 return Collections.EMPTY_SET.iterator(); 145 } 146 147 return descendants.iterator(); 148 } 149 150 151 /** 152 * {@inheritDoc} 153 */ 154 public void registerDescendants( AttributeType attributeType, AttributeType ancestor ) throws LdapException 155 { 156 // add this attribute to descendant list of other attributes in superior chain 157 if ( ancestor == null ) 158 { 159 return; 160 } 161 162 // Get the ancestor's descendant, if any 163 Set<AttributeType> descendants = oidToDescendantSet.get( ancestor.getOid() ); 164 165 // Initialize the descendant Set to store the descendants for the attributeType 166 if ( descendants == null ) 167 { 168 descendants = new HashSet<AttributeType>( 1 ); 169 oidToDescendantSet.put( ancestor.getOid(), descendants ); 170 } 171 172 // Add the current type as a descendant 173 descendants.add( attributeType ); 174 175 /* 176 try 177 { 178 // And recurse until we reach the top of the hierarchy 179 registerDescendants( attributeType, ancestor.getSuperior() ); 180 } 181 catch ( LdapException ne ) 182 { 183 throw new NoSuchAttributeException( ne.getMessage() ); 184 } 185 */ 186 } 187 188 189 /** 190 * {@inheritDoc} 191 */ 192 public void unregisterDescendants( AttributeType attributeType, AttributeType ancestor ) throws LdapException 193 { 194 // add this attribute to descendant list of other attributes in superior chain 195 if ( ancestor == null ) 196 { 197 return; 198 } 199 200 // Get the ancestor's descendant, if any 201 Set<AttributeType> descendants = oidToDescendantSet.get( ancestor.getOid() ); 202 203 if ( descendants != null ) 204 { 205 descendants.remove( attributeType ); 206 207 if ( descendants.size() == 0 ) 208 { 209 oidToDescendantSet.remove( ancestor.getOid() ); 210 } 211 } 212 213 /* 214 try 215 { 216 // And recurse until we reach the top of the hierarchy 217 unregisterDescendants( attributeType, ancestor.getSuperior() ); 218 } 219 catch ( LdapException ne ) 220 { 221 throw new NoSuchAttributeException( ne.getMessage() ); 222 } 223 */ 224 } 225 226 227 /** 228 * {@inheritDoc} 229 */ 230 public AttributeType unregister( String numericOid ) throws LdapException 231 { 232 try 233 { 234 AttributeType removed = super.unregister( numericOid ); 235 236 removeMappingFor( removed ); 237 238 // Deleting an AT which might be used as a superior means we have 239 // to recursively update the descendant map. We also have to remove 240 // the at.oid -> descendant relation 241 oidToDescendantSet.remove( numericOid ); 242 243 // Now recurse if needed 244 unregisterDescendants( removed, removed.getSuperior() ); 245 246 return removed; 247 } 248 catch ( LdapException ne ) 249 { 250 throw new LdapNoSuchAttributeException( ne.getMessage(), ne ); 251 } 252 } 253 254 255 /** 256 * {@inheritDoc} 257 */ 258 public void addMappingFor( AttributeType attributeType ) throws LdapException 259 { 260 MatchingRule equality = attributeType.getEquality(); 261 OidNormalizer oidNormalizer; 262 String oid = attributeType.getOid(); 263 264 if ( equality == null ) 265 { 266 LOG.debug( "Attribute {} does not have an EQUALITY MatchingRule : using NoopNormalizer", attributeType 267 .getName() ); 268 oidNormalizer = new OidNormalizer( oid, new NoOpNormalizer( attributeType.getOid() ) ); 269 } 270 else 271 { 272 oidNormalizer = new OidNormalizer( oid, equality.getNormalizer() ); 273 } 274 275 oidNormalizerMap.put( oid, oidNormalizer ); 276 277 // Also inject the attributeType's short names in the map 278 for ( String name : attributeType.getNames() ) 279 { 280 oidNormalizerMap.put( name.toLowerCase(), oidNormalizer ); 281 } 282 } 283 284 285 /** 286 * Remove the AttributeType normalizer from the OidNormalizer map 287 */ 288 public void removeMappingFor( AttributeType attributeType ) throws LdapException 289 { 290 if ( attributeType == null ) 291 { 292 return; 293 } 294 295 oidNormalizerMap.remove( attributeType.getOid() ); 296 297 // We also have to remove all the short names for this attribute 298 for ( String name : attributeType.getNames() ) 299 { 300 oidNormalizerMap.remove( name.toLowerCase() ); 301 } 302 } 303 304 305 /** 306 * {@inheritDoc} 307 */ 308 public AttributeType lookup( String oid ) throws LdapException 309 { 310 try 311 { 312 return super.lookup( oid ); 313 } 314 catch ( LdapException ne ) 315 { 316 throw new LdapNoSuchAttributeException( ne.getMessage(), ne ); 317 } 318 } 319 320 321 /** 322 * {@inheritDoc} 323 */ 324 public AttributeTypeRegistry copy() 325 { 326 DefaultAttributeTypeRegistry copy = new DefaultAttributeTypeRegistry(); 327 328 // Copy the base data 329 copy.copy( this ); 330 331 return copy; 332 } 333 334 335 /** 336 * {@inheritDoc} 337 */ 338 public void clear() 339 { 340 // First clear the shared elements 341 super.clear(); 342 343 // clear the OidNormalizer map 344 oidNormalizerMap.clear(); 345 346 // and clear the descendant 347 for ( String oid : oidToDescendantSet.keySet() ) 348 { 349 Set<AttributeType> descendants = oidToDescendantSet.get( oid ); 350 351 if ( descendants != null ) 352 { 353 descendants.clear(); 354 } 355 } 356 357 oidToDescendantSet.clear(); 358 } 359}