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