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