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.server.core.schema;
021
022
023 import java.util.HashMap;
024 import java.util.HashSet;
025 import java.util.Map;
026 import java.util.Set;
027
028 import javax.naming.directory.DirContext;
029
030 import org.apache.directory.server.core.interceptor.context.ModifyOperationContext;
031 import org.apache.directory.server.i18n.I18n;
032 import org.apache.directory.shared.ldap.constants.SchemaConstants;
033 import org.apache.directory.shared.ldap.entry.EntryAttribute;
034 import org.apache.directory.shared.ldap.entry.Modification;
035 import org.apache.directory.shared.ldap.entry.ServerEntry;
036 import org.apache.directory.shared.ldap.exception.LdapUnwillingToPerformException;
037 import org.apache.directory.shared.ldap.message.ResultCodeEnum;
038 import org.apache.directory.shared.ldap.name.DN;
039 import org.apache.directory.shared.ldap.schema.AttributeType;
040 import org.apache.directory.shared.ldap.schema.DITContentRule;
041 import org.apache.directory.shared.ldap.schema.DITStructureRule;
042 import org.apache.directory.shared.ldap.schema.LdapSyntax;
043 import org.apache.directory.shared.ldap.schema.MatchingRule;
044 import org.apache.directory.shared.ldap.schema.MatchingRuleUse;
045 import org.apache.directory.shared.ldap.schema.NameForm;
046 import org.apache.directory.shared.ldap.schema.ObjectClass;
047 import org.apache.directory.shared.ldap.schema.SchemaManager;
048 import org.apache.directory.shared.ldap.schema.parsers.LdapComparatorDescription;
049 import org.apache.directory.shared.ldap.schema.parsers.NormalizerDescription;
050 import org.apache.directory.shared.ldap.schema.parsers.SyntaxCheckerDescription;
051 import org.apache.directory.shared.ldap.schema.registries.SchemaLoader;
052 import org.slf4j.Logger;
053 import org.slf4j.LoggerFactory;
054
055
056 /**
057 *
058 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
059 * @version $Rev$, $Date$
060 */
061 public class SchemaSubentryManager
062 {
063 /** A logger for this class */
064 private static final Logger LOG = LoggerFactory.getLogger( SchemaSubentryManager.class );
065
066 // indices of handlers and object ids into arrays
067 private static final int COMPARATOR_INDEX = 0;
068 private static final int NORMALIZER_INDEX = 1;
069 private static final int SYNTAX_CHECKER_INDEX = 2;
070 private static final int SYNTAX_INDEX = 3;
071 private static final int MATCHING_RULE_INDEX = 4;
072 private static final int ATTRIBUTE_TYPE_INDEX = 5;
073 private static final int OBJECT_CLASS_INDEX = 6;
074 private static final int MATCHING_RULE_USE_INDEX = 7;
075 private static final int DIT_STRUCTURE_RULE_INDEX = 8;
076 private static final int DIT_CONTENT_RULE_INDEX = 9;
077 private static final int NAME_FORM_INDEX = 10;
078
079 private static final Set<String> VALID_OU_VALUES = new HashSet<String>();
080
081 /** The schemaManager */
082 private final SchemaManager schemaManager;
083
084 private final SchemaSubentryModifier subentryModifier;
085
086 /** The description parsers */
087 private final DescriptionParsers parsers;
088
089 /**
090 * Maps the OID of a subschemaSubentry operational attribute to the index of
091 * the handler in the schemaObjectHandlers array.
092 */
093 private final Map<String, Integer> opAttr2handlerIndex = new HashMap<String, Integer>( 11 );
094 private static final String CASCADING_ERROR =
095 "Cascading has not yet been implemented: standard operation is in effect.";
096
097 static
098 {
099 VALID_OU_VALUES.add( SchemaConstants.NORMALIZERS_AT.toLowerCase() );
100 VALID_OU_VALUES.add( SchemaConstants.COMPARATORS_AT.toLowerCase() );
101 VALID_OU_VALUES.add( SchemaConstants.SYNTAX_CHECKERS_AT.toLowerCase() );
102 VALID_OU_VALUES.add( "syntaxes".toLowerCase() );
103 VALID_OU_VALUES.add( SchemaConstants.MATCHING_RULES_AT.toLowerCase() );
104 VALID_OU_VALUES.add( SchemaConstants.MATCHING_RULE_USE_AT.toLowerCase() );
105 VALID_OU_VALUES.add( SchemaConstants.ATTRIBUTE_TYPES_AT.toLowerCase() );
106 VALID_OU_VALUES.add( SchemaConstants.OBJECT_CLASSES_AT.toLowerCase() );
107 VALID_OU_VALUES.add( SchemaConstants.NAME_FORMS_AT.toLowerCase() );
108 VALID_OU_VALUES.add( SchemaConstants.DIT_CONTENT_RULES_AT.toLowerCase() );
109 VALID_OU_VALUES.add( SchemaConstants.DIT_STRUCTURE_RULES_AT.toLowerCase() );
110 }
111
112
113 public SchemaSubentryManager( SchemaManager schemaManager, SchemaLoader loader )
114 throws Exception
115 {
116 this.schemaManager = schemaManager;
117 this.subentryModifier = new SchemaSubentryModifier( schemaManager );
118 this.parsers = new DescriptionParsers( schemaManager );
119
120 String comparatorsOid = schemaManager.getAttributeTypeRegistry().getOidByName( SchemaConstants.COMPARATORS_AT );
121 opAttr2handlerIndex.put( comparatorsOid, COMPARATOR_INDEX );
122
123 String normalizersOid = schemaManager.getAttributeTypeRegistry().getOidByName( SchemaConstants.NORMALIZERS_AT );
124 opAttr2handlerIndex.put( normalizersOid, NORMALIZER_INDEX );
125
126 String syntaxCheckersOid = schemaManager.getAttributeTypeRegistry().getOidByName( SchemaConstants.SYNTAX_CHECKERS_AT );
127 opAttr2handlerIndex.put( syntaxCheckersOid, SYNTAX_CHECKER_INDEX );
128
129 String ldapSyntaxesOid = schemaManager.getAttributeTypeRegistry().getOidByName( SchemaConstants.LDAP_SYNTAXES_AT );
130 opAttr2handlerIndex.put( ldapSyntaxesOid, SYNTAX_INDEX );
131
132 String matchingRulesOid = schemaManager.getAttributeTypeRegistry().getOidByName( SchemaConstants.MATCHING_RULES_AT );
133 opAttr2handlerIndex.put( matchingRulesOid, MATCHING_RULE_INDEX );
134
135 String attributeTypesOid = schemaManager.getAttributeTypeRegistry().getOidByName( SchemaConstants.ATTRIBUTE_TYPES_AT );
136 opAttr2handlerIndex.put( attributeTypesOid, ATTRIBUTE_TYPE_INDEX );
137
138 String objectClassesOid = schemaManager.getAttributeTypeRegistry().getOidByName( SchemaConstants.OBJECT_CLASSES_AT );
139 opAttr2handlerIndex.put( objectClassesOid, OBJECT_CLASS_INDEX );
140
141 String matchingRuleUseOid = schemaManager.getAttributeTypeRegistry().getOidByName( SchemaConstants.MATCHING_RULE_USE_AT );
142 opAttr2handlerIndex.put( matchingRuleUseOid, MATCHING_RULE_USE_INDEX );
143
144 String ditStructureRulesOid = schemaManager.getAttributeTypeRegistry().getOidByName( SchemaConstants.DIT_STRUCTURE_RULES_AT );
145 opAttr2handlerIndex.put( ditStructureRulesOid, DIT_STRUCTURE_RULE_INDEX );
146
147 String ditContentRulesOid = schemaManager.getAttributeTypeRegistry().getOidByName( SchemaConstants.DIT_CONTENT_RULES_AT );
148 opAttr2handlerIndex.put( ditContentRulesOid, DIT_CONTENT_RULE_INDEX );
149
150 String nameFormsOid = schemaManager.getAttributeTypeRegistry().getOidByName( SchemaConstants.NAME_FORMS_AT );
151 opAttr2handlerIndex.put( nameFormsOid, NAME_FORM_INDEX );
152 }
153
154
155 /* (non-Javadoc)
156 * @see org.apache.directory.server.core.schema.SchemaChangeManager#modifySchemaSubentry(org.apache.directory.server.core.interceptor.context.ModifyOperationContext, org.apache.directory.server.core.entry.ServerEntry, org.apache.directory.server.core.entry.ServerEntry, boolean)
157 */
158 public void modifySchemaSubentry( ModifyOperationContext opContext, boolean doCascadeModify ) throws Exception
159 {
160 for ( Modification mod : opContext.getModItems() )
161 {
162 String opAttrOid = schemaManager.getAttributeTypeRegistry().getOidByName( mod.getAttribute().getId() );
163
164 EntryAttribute serverAttribute = mod.getAttribute();
165
166 switch ( mod.getOperation() )
167 {
168 case ADD_ATTRIBUTE :
169 modifyAddOperation( opContext, opAttrOid, serverAttribute, doCascadeModify );
170 break;
171
172 case REMOVE_ATTRIBUTE :
173 modifyRemoveOperation( opContext, opAttrOid, serverAttribute, doCascadeModify );
174 break;
175
176 case REPLACE_ATTRIBUTE :
177 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM,
178 I18n.err( I18n.ERR_283 ) );
179
180 default:
181 throw new IllegalStateException( I18n.err( I18n.ERR_284, mod.getOperation() ) );
182 }
183 }
184 }
185
186
187 /* (non-Javadoc)
188 * @see org.apache.directory.server.core.schema.SchemaChangeManager#modifySchemaSubentry(org.apache.directory.server.core.interceptor.context.ModifyOperationContext, org.apache.directory.shared.ldap.name.DN, int, org.apache.directory.server.core.entry.ServerEntry, org.apache.directory.server.core.entry.ServerEntry, org.apache.directory.server.core.entry.ServerEntry, boolean)
189 */
190 public void modifySchemaSubentry( ModifyOperationContext opContext, DN name, int modOp, ServerEntry mods,
191 ServerEntry subentry, ServerEntry targetSubentry, boolean doCascadeModify ) throws Exception
192 {
193 Set<AttributeType> attributeTypes = mods.getAttributeTypes();
194
195 switch ( modOp )
196 {
197 case( DirContext.ADD_ATTRIBUTE ):
198 for ( AttributeType attributeType:attributeTypes )
199 {
200 modifyAddOperation( opContext, attributeType.getOid(),
201 mods.get( attributeType ), doCascadeModify );
202 }
203
204 break;
205
206 case( DirContext.REMOVE_ATTRIBUTE ):
207 for ( AttributeType attributeType:attributeTypes )
208 {
209 modifyRemoveOperation( opContext, attributeType.getOid(),
210 mods.get( attributeType ), doCascadeModify );
211 }
212
213 break;
214
215 case( DirContext.REPLACE_ATTRIBUTE ):
216 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM,
217 I18n.err( I18n.ERR_283 ) );
218
219 default:
220 throw new IllegalStateException( I18n.err( I18n.ERR_284, modOp ) );
221 }
222 }
223
224
225 /**
226 * Handles the modify remove operation on the subschemaSubentry for schema entities.
227 *
228 * @param opAttrOid the numeric id of the operational attribute modified
229 * @param mods the attribute with the modifications
230 * @param doCascadeModify determines if a cascading operation should be performed
231 * to effect all dependents on the changed entity
232 * @throws Exception if there are problems updating the registries and the
233 * schema partition
234 */
235 private void modifyRemoveOperation( ModifyOperationContext opContext, String opAttrOid,
236 EntryAttribute mods, boolean doCascadeModify ) throws Exception
237 {
238 int index = opAttr2handlerIndex.get( opAttrOid );
239
240 switch( index )
241 {
242 case( COMPARATOR_INDEX ):
243 LdapComparatorDescription[] comparatorDescriptions = parsers.parseComparators( mods );
244
245 for ( LdapComparatorDescription comparatorDescription : comparatorDescriptions )
246 {
247 subentryModifier.delete( opContext, comparatorDescription );
248 }
249 break;
250 case( NORMALIZER_INDEX ):
251 NormalizerDescription[] normalizerDescriptions = parsers.parseNormalizers( mods );
252
253 for ( NormalizerDescription normalizerDescription : normalizerDescriptions )
254 {
255 subentryModifier.delete( opContext, normalizerDescription );
256 }
257 break;
258 case( SYNTAX_CHECKER_INDEX ):
259 SyntaxCheckerDescription[] syntaxCheckerDescriptions = parsers.parseSyntaxCheckers( mods );
260
261 for ( SyntaxCheckerDescription syntaxCheckerDescription : syntaxCheckerDescriptions )
262 {
263 subentryModifier.delete( opContext, syntaxCheckerDescription );
264 }
265 break;
266 case( SYNTAX_INDEX ):
267 LdapSyntax[] syntaxes = parsers.parseLdapSyntaxes( mods );
268
269 for ( LdapSyntax syntax : syntaxes )
270 {
271 subentryModifier.deleteSchemaObject( opContext, syntax );
272 }
273 break;
274 case( MATCHING_RULE_INDEX ):
275 MatchingRule[] mrs = parsers.parseMatchingRules( mods );
276
277 for ( MatchingRule mr : mrs )
278 {
279 subentryModifier.deleteSchemaObject( opContext, mr );
280 }
281 break;
282 case( ATTRIBUTE_TYPE_INDEX ):
283 AttributeType[] ats = parsers.parseAttributeTypes( mods );
284
285 for ( AttributeType at : ats )
286 {
287 subentryModifier.deleteSchemaObject( opContext, at );
288 }
289 break;
290 case( OBJECT_CLASS_INDEX ):
291 ObjectClass[] ocs = parsers.parseObjectClasses( mods );
292
293 for ( ObjectClass oc : ocs )
294 {
295 subentryModifier.deleteSchemaObject( opContext, oc );
296 }
297 break;
298 case( MATCHING_RULE_USE_INDEX ):
299 MatchingRuleUse[] mrus = parsers.parseMatchingRuleUses( mods );
300
301 for ( MatchingRuleUse mru : mrus )
302 {
303 subentryModifier.deleteSchemaObject( opContext, mru );
304 }
305 break;
306 case( DIT_STRUCTURE_RULE_INDEX ):
307 DITStructureRule[] dsrs = parsers.parseDitStructureRules( mods );
308
309 for ( DITStructureRule dsr : dsrs )
310 {
311 subentryModifier.deleteSchemaObject( opContext, dsr );
312 }
313 break;
314 case( DIT_CONTENT_RULE_INDEX ):
315 DITContentRule[] dcrs = parsers.parseDitContentRules( mods );
316
317 for ( DITContentRule dcr : dcrs )
318 {
319 subentryModifier.deleteSchemaObject( opContext, dcr );
320 }
321 break;
322 case( NAME_FORM_INDEX ):
323 NameForm[] nfs = parsers.parseNameForms( mods );
324
325 for ( NameForm nf : nfs )
326 {
327 subentryModifier.deleteSchemaObject( opContext, nf );
328 }
329 break;
330 default:
331 throw new IllegalStateException( I18n.err( I18n.ERR_285, index ) );
332 }
333 }
334
335
336 /**
337 * Handles the modify add operation on the subschemaSubentry for schema entities.
338 *
339 * @param opAttrOid the numeric id of the operational attribute modified
340 * @param mods the attribute with the modifications
341 * @param doCascadeModify determines if a cascading operation should be performed
342 * to effect all dependents on the changed entity
343 * @throws Exception if there are problems updating the registries and the
344 * schema partition
345 */
346 private void modifyAddOperation( ModifyOperationContext opContext, String opAttrOid,
347 EntryAttribute mods, boolean doCascadeModify ) throws Exception
348 {
349 if ( doCascadeModify )
350 {
351 LOG.error( CASCADING_ERROR );
352 }
353
354 int index = opAttr2handlerIndex.get( opAttrOid );
355
356 switch( index )
357 {
358 case( COMPARATOR_INDEX ):
359 LdapComparatorDescription[] comparatorDescriptions = parsers.parseComparators( mods );
360
361 for ( LdapComparatorDescription comparatorDescription : comparatorDescriptions )
362 {
363 subentryModifier.add( opContext, comparatorDescription );
364 }
365
366 break;
367
368 case( NORMALIZER_INDEX ):
369 NormalizerDescription[] normalizerDescriptions = parsers.parseNormalizers( mods );
370
371 for ( NormalizerDescription normalizerDescription : normalizerDescriptions )
372 {
373 subentryModifier.add( opContext, normalizerDescription );
374 }
375
376 break;
377
378 case( SYNTAX_CHECKER_INDEX ):
379 SyntaxCheckerDescription[] syntaxCheckerDescriptions = parsers.parseSyntaxCheckers( mods );
380
381 for ( SyntaxCheckerDescription syntaxCheckerDescription : syntaxCheckerDescriptions )
382 {
383 subentryModifier.add( opContext, syntaxCheckerDescription );
384 }
385
386 break;
387
388 case( SYNTAX_INDEX ):
389 LdapSyntax[] syntaxes = parsers.parseLdapSyntaxes( mods );
390
391 for ( LdapSyntax syntax : syntaxes )
392 {
393 subentryModifier.addSchemaObject( opContext, syntax );
394 }
395
396 break;
397
398 case( MATCHING_RULE_INDEX ):
399 MatchingRule[] mrs = parsers.parseMatchingRules( mods );
400
401 for ( MatchingRule mr : mrs )
402 {
403 subentryModifier.addSchemaObject( opContext, mr );
404 }
405
406 break;
407
408 case( ATTRIBUTE_TYPE_INDEX ):
409 AttributeType[] ats = parsers.parseAttributeTypes( mods );
410
411 for ( AttributeType at : ats )
412 {
413 subentryModifier.addSchemaObject( opContext, at );
414 }
415
416 break;
417
418 case( OBJECT_CLASS_INDEX ):
419 ObjectClass[] ocs = parsers.parseObjectClasses( mods );
420
421 for ( ObjectClass oc : ocs )
422 {
423 subentryModifier.addSchemaObject( opContext, oc );
424 }
425
426 break;
427
428 case( MATCHING_RULE_USE_INDEX ):
429 MatchingRuleUse[] mrus = parsers.parseMatchingRuleUses( mods );
430
431 for ( MatchingRuleUse mru : mrus )
432 {
433 subentryModifier.addSchemaObject( opContext, mru );
434 }
435
436 break;
437
438 case( DIT_STRUCTURE_RULE_INDEX ):
439 DITStructureRule[] dsrs = parsers.parseDitStructureRules( mods );
440
441 for ( DITStructureRule dsr : dsrs )
442 {
443 subentryModifier.addSchemaObject( opContext, dsr );
444 }
445
446 break;
447
448 case( DIT_CONTENT_RULE_INDEX ):
449 DITContentRule[] dcrs = parsers.parseDitContentRules( mods );
450
451 for ( DITContentRule dcr : dcrs )
452 {
453 subentryModifier.addSchemaObject( opContext, dcr );
454 }
455
456 break;
457
458 case( NAME_FORM_INDEX ):
459 NameForm[] nfs = parsers.parseNameForms( mods );
460
461 for ( NameForm nf : nfs )
462 {
463 subentryModifier.addSchemaObject( opContext, nf );
464 }
465
466 break;
467
468 default:
469 throw new IllegalStateException( I18n.err( I18n.ERR_285, index ) );
470 }
471 }
472 }