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 }