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<String, OidNormalizer>(); 067 oidToDescendantSet = new HashMap<String, Set<AttributeType>>(); 068 } 069 070 071 /** 072 * {@inheritDoc} 073 */ 074 public Map<String, OidNormalizer> getNormalizerMapping() 075 { 076 return Collections.unmodifiableMap( oidNormalizerMap ); 077 } 078 079 080 /** 081 * {@inheritDoc} 082 */ 083 public boolean hasDescendants( String ancestorId ) throws LdapException 084 { 085 try 086 { 087 String oid = getOidByName( ancestorId ); 088 Set<AttributeType> descendants = oidToDescendantSet.get( oid ); 089 return ( descendants != null ) && !descendants.isEmpty(); 090 } 091 catch ( LdapException ne ) 092 { 093 throw new LdapNoSuchAttributeException( ne.getMessage(), ne ); 094 } 095 } 096 097 098 /** 099 * {@inheritDoc} 100 */ 101 public boolean hasDescendants( AttributeType ancestor ) throws LdapException 102 { 103 String oid = ancestor.getOid(); 104 Set<AttributeType> descendants = oidToDescendantSet.get( oid ); 105 return ( descendants != null ) && !descendants.isEmpty(); 106 } 107 108 109 /** 110 * {@inheritDoc} 111 */ 112 @SuppressWarnings("unchecked") 113 public Iterator<AttributeType> descendants( String ancestorId ) throws LdapException 114 { 115 try 116 { 117 String oid = getOidByName( ancestorId ); 118 Set<AttributeType> descendants = oidToDescendantSet.get( oid ); 119 120 if ( descendants == null ) 121 { 122 return Collections.EMPTY_SET.iterator(); 123 } 124 125 return descendants.iterator(); 126 } 127 catch ( LdapException ne ) 128 { 129 throw new LdapNoSuchAttributeException( ne.getMessage(), ne ); 130 } 131 } 132 133 134 /** 135 * {@inheritDoc} 136 */ 137 @SuppressWarnings("unchecked") 138 public Iterator<AttributeType> descendants( AttributeType ancestor ) throws LdapException 139 { 140 String oid = ancestor.getOid(); 141 Set<AttributeType> descendants = oidToDescendantSet.get( oid ); 142 143 if ( descendants == null ) 144 { 145 return Collections.EMPTY_SET.iterator(); 146 } 147 148 return descendants.iterator(); 149 } 150 151 152 /** 153 * {@inheritDoc} 154 */ 155 public void registerDescendants( AttributeType attributeType, AttributeType ancestor ) throws LdapException 156 { 157 // add this attribute to descendant list of other attributes in superior chain 158 if ( ancestor == null ) 159 { 160 return; 161 } 162 163 // Get the ancestor's descendant, if any 164 Set<AttributeType> descendants = oidToDescendantSet.get( ancestor.getOid() ); 165 166 // Initialize the descendant Set to store the descendants for the attributeType 167 if ( descendants == null ) 168 { 169 descendants = new HashSet<AttributeType>( 1 ); 170 oidToDescendantSet.put( ancestor.getOid(), descendants ); 171 } 172 173 // Add the current type as a descendant 174 descendants.add( attributeType ); 175 } 176 177 178 /** 179 * {@inheritDoc} 180 */ 181 public void unregisterDescendants( AttributeType attributeType, AttributeType ancestor ) throws LdapException 182 { 183 // add this attribute to descendant list of other attributes in superior chain 184 if ( ancestor == null ) 185 { 186 return; 187 } 188 189 // Get the ancestor's descendant, if any 190 Set<AttributeType> descendants = oidToDescendantSet.get( ancestor.getOid() ); 191 192 if ( descendants != null ) 193 { 194 descendants.remove( attributeType ); 195 196 if ( descendants.size() == 0 ) 197 { 198 oidToDescendantSet.remove( ancestor.getOid() ); 199 } 200 } 201 } 202 203 204 /** 205 * {@inheritDoc} 206 */ 207 public AttributeType unregister( String numericOid ) throws LdapException 208 { 209 try 210 { 211 AttributeType removed = super.unregister( numericOid ); 212 213 removeMappingFor( removed ); 214 215 // Deleting an AT which might be used as a superior means we have 216 // to recursively update the descendant map. We also have to remove 217 // the at.oid -> descendant relation 218 oidToDescendantSet.remove( numericOid ); 219 220 // Now recurse if needed 221 unregisterDescendants( removed, removed.getSuperior() ); 222 223 return removed; 224 } 225 catch ( LdapException ne ) 226 { 227 throw new LdapNoSuchAttributeException( ne.getMessage(), ne ); 228 } 229 } 230 231 232 /** 233 * {@inheritDoc} 234 */ 235 public void addMappingFor( AttributeType attributeType ) throws LdapException 236 { 237 MatchingRule equality = attributeType.getEquality(); 238 OidNormalizer oidNormalizer; 239 String oid = attributeType.getOid(); 240 241 if ( equality == null ) 242 { 243 LOG.debug( "Attribute {} does not have an EQUALITY MatchingRule : using NoopNormalizer", attributeType 244 .getName() ); 245 oidNormalizer = new OidNormalizer( oid, new NoOpNormalizer( attributeType.getOid() ) ); 246 } 247 else 248 { 249 oidNormalizer = new OidNormalizer( oid, equality.getNormalizer() ); 250 } 251 252 oidNormalizerMap.put( oid, oidNormalizer ); 253 254 // Also inject the attributeType's short names in the map 255 for ( String name : attributeType.getNames() ) 256 { 257 oidNormalizerMap.put( Strings.toLowerCase( name ), oidNormalizer ); 258 } 259 } 260 261 262 /** 263 * Remove the AttributeType normalizer from the OidNormalizer map 264 */ 265 public void removeMappingFor( AttributeType attributeType ) throws LdapException 266 { 267 if ( attributeType == null ) 268 { 269 return; 270 } 271 272 oidNormalizerMap.remove( attributeType.getOid() ); 273 274 // We also have to remove all the short names for this attribute 275 for ( String name : attributeType.getNames() ) 276 { 277 oidNormalizerMap.remove( Strings.toLowerCase( name ) ); 278 } 279 } 280 281 282 /** 283 * {@inheritDoc} 284 */ 285 public AttributeType lookup( String oid ) throws LdapException 286 { 287 try 288 { 289 return super.lookup( oid ); 290 } 291 catch ( LdapException ne ) 292 { 293 throw new LdapNoSuchAttributeException( ne.getMessage(), ne ); 294 } 295 } 296 297 298 /** 299 * {@inheritDoc} 300 */ 301 public AttributeTypeRegistry copy() 302 { 303 DefaultAttributeTypeRegistry copy = new DefaultAttributeTypeRegistry(); 304 305 // Copy the base data 306 copy.copy( this ); 307 308 return copy; 309 } 310 311 312 /** 313 * {@inheritDoc} 314 */ 315 public void clear() 316 { 317 // First clear the shared elements 318 super.clear(); 319 320 // clear the OidNormalizer map 321 oidNormalizerMap.clear(); 322 323 // and clear the descendant 324 for ( String oid : oidToDescendantSet.keySet() ) 325 { 326 Set<AttributeType> descendants = oidToDescendantSet.get( oid ); 327 328 if ( descendants != null ) 329 { 330 descendants.clear(); 331 } 332 } 333 334 oidToDescendantSet.clear(); 335 } 336}