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.List; 028 import java.util.Map; 029 import java.util.Set; 030 031 import org.apache.directory.shared.ldap.exception.LdapException; 032 import org.apache.directory.shared.ldap.exception.LdapNoSuchAttributeException; 033 import org.apache.directory.shared.ldap.schema.ObjectClass; 034 import org.apache.directory.shared.ldap.schema.SchemaObject; 035 import org.apache.directory.shared.ldap.schema.SchemaObjectType; 036 import org.slf4j.Logger; 037 import org.slf4j.LoggerFactory; 038 039 040 /** 041 * An ObjectClass registry's service default implementation. 042 * 043 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 044 * @version $Rev: 828111 $ 045 */ 046 public class DefaultObjectClassRegistry extends DefaultSchemaObjectRegistry<ObjectClass> 047 implements ObjectClassRegistry 048 { 049 /** static class logger */ 050 private static final Logger LOG = LoggerFactory.getLogger( DefaultObjectClassRegistry.class ); 051 052 /** Speedup for DEBUG mode */ 053 private static final boolean IS_DEBUG = LOG.isDebugEnabled(); 054 055 /** maps OIDs to a Set of descendants for that OID */ 056 private Map<String,Set<ObjectClass>> oidToDescendants; 057 058 /** 059 * Creates a new default ObjectClassRegistry instance. 060 */ 061 public DefaultObjectClassRegistry() 062 { 063 super( SchemaObjectType.OBJECT_CLASS, new OidRegistry() ); 064 oidToDescendants = new HashMap<String,Set<ObjectClass>>(); 065 } 066 067 068 /** 069 * {@inheritDoc} 070 */ 071 public boolean hasDescendants( String ancestorId ) throws LdapException 072 { 073 try 074 { 075 String oid = getOidByName( ancestorId ); 076 Set<ObjectClass> descendants = oidToDescendants.get( oid ); 077 return (descendants != null) && !descendants.isEmpty(); 078 } 079 catch ( LdapException ne ) 080 { 081 throw new LdapNoSuchAttributeException( ne.getMessage() ); 082 } 083 } 084 085 086 /** 087 * {@inheritDoc} 088 */ 089 @SuppressWarnings("unchecked") 090 public Iterator<ObjectClass> descendants( String ancestorId ) throws LdapException 091 { 092 try 093 { 094 String oid = getOidByName( ancestorId ); 095 Set<ObjectClass> descendants = oidToDescendants.get( oid ); 096 097 if ( descendants == null ) 098 { 099 return Collections.EMPTY_SET.iterator(); 100 } 101 102 return descendants.iterator(); 103 } 104 catch ( LdapException ne ) 105 { 106 throw new LdapNoSuchAttributeException( ne.getMessage() ); 107 } 108 } 109 110 111 /** 112 * {@inheritDoc} 113 */ 114 public void registerDescendants( ObjectClass objectClass, List<ObjectClass> ancestors ) 115 throws LdapException 116 { 117 // add this attribute to descendant list of other attributes in superior chain 118 if ( ( ancestors == null ) || ( ancestors.size() == 0 ) ) 119 { 120 return; 121 } 122 123 for ( ObjectClass ancestor : ancestors ) 124 { 125 // Get the ancestor's descendant, if any 126 Set<ObjectClass> descendants = oidToDescendants.get( ancestor.getOid() ); 127 128 // Initialize the descendant Set to store the descendants for the attributeType 129 if ( descendants == null ) 130 { 131 descendants = new HashSet<ObjectClass>( 1 ); 132 oidToDescendants.put( ancestor.getOid(), descendants ); 133 } 134 135 // Add the current ObjectClass as a descendant 136 descendants.add( objectClass ); 137 138 try 139 { 140 // And recurse until we reach the top of the hierarchy 141 registerDescendants( objectClass, ancestor.getSuperiors() ); 142 } 143 catch ( LdapException ne ) 144 { 145 throw new LdapNoSuchAttributeException( ne.getMessage() ); 146 } 147 } 148 } 149 150 151 /** 152 * {@inheritDoc} 153 */ 154 public void unregisterDescendants( ObjectClass attributeType, List<ObjectClass> ancestors ) 155 throws LdapException 156 { 157 // add this attribute to descendant list of other attributes in superior chain 158 if ( ( ancestors == null ) || ( ancestors.size() == 0 ) ) 159 { 160 return; 161 } 162 163 for ( ObjectClass ancestor : ancestors ) 164 { 165 // Get the ancestor's descendant, if any 166 Set<ObjectClass> descendants = oidToDescendants.get( ancestor.getOid() ); 167 168 if ( descendants != null ) 169 { 170 descendants.remove( attributeType ); 171 172 if ( descendants.size() == 0 ) 173 { 174 oidToDescendants.remove( descendants ); 175 } 176 } 177 178 try 179 { 180 // And recurse until we reach the top of the hierarchy 181 unregisterDescendants( attributeType, ancestor.getSuperiors() ); 182 } 183 catch ( LdapException ne ) 184 { 185 throw new LdapNoSuchAttributeException( ne.getMessage() ); 186 } 187 } 188 } 189 190 191 /** 192 * {@inheritDoc} 193 */ 194 public ObjectClass unregister( String numericOid ) throws LdapException 195 { 196 try 197 { 198 ObjectClass removed = super.unregister( numericOid ); 199 200 // Deleting an ObjectClass which might be used as a superior means we have 201 // to recursively update the descendant map. We also have to remove 202 // the at.oid -> descendant relation 203 oidToDescendants.remove( numericOid ); 204 205 // Now recurse if needed 206 unregisterDescendants( removed, removed.getSuperiors() ); 207 208 return removed; 209 } 210 catch ( LdapException ne ) 211 { 212 throw new LdapNoSuchAttributeException( ne.getMessage() ); 213 } 214 } 215 216 217 /** 218 * {@inheritDoc} 219 */ 220 public DefaultObjectClassRegistry copy() 221 { 222 DefaultObjectClassRegistry copy = new DefaultObjectClassRegistry(); 223 224 // Copy the base data 225 copy.copy( this ); 226 227 return copy; 228 } 229 230 231 /** 232 * {@inheritDoc} 233 */ 234 public void clear() 235 { 236 // Clear the contained SchemaObjects 237 for ( SchemaObject objectClass : oidRegistry ) 238 { 239 objectClass.clear(); 240 } 241 242 // First clear the shared elements 243 super.clear(); 244 245 // and clear the descendant 246 for ( String oid : oidToDescendants.keySet() ) 247 { 248 Set<ObjectClass> descendants = oidToDescendants.get( oid ); 249 250 if ( descendants != null ) 251 { 252 descendants.clear(); 253 } 254 } 255 256 oidToDescendants.clear(); 257 } 258 }