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