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.ArrayList;
024 import java.util.HashSet;
025 import java.util.List;
026 import java.util.Set;
027
028 import org.apache.directory.server.i18n.I18n;
029 import org.apache.directory.shared.ldap.constants.SchemaConstants;
030 import org.apache.directory.shared.ldap.entry.EntryAttribute;
031 import org.apache.directory.shared.ldap.entry.ModificationOperation;
032 import org.apache.directory.shared.ldap.entry.ServerEntry;
033 import org.apache.directory.shared.ldap.entry.Value;
034 import org.apache.directory.shared.ldap.exception.LdapException;
035 import org.apache.directory.shared.ldap.exception.LdapSchemaViolationException;
036 import org.apache.directory.shared.ldap.message.ResultCodeEnum;
037 import org.apache.directory.shared.ldap.name.DN;
038 import org.apache.directory.shared.ldap.schema.AttributeType;
039 import org.apache.directory.shared.ldap.schema.ObjectClass;
040 import org.apache.directory.shared.ldap.schema.ObjectClassTypeEnum;
041 import org.apache.directory.shared.ldap.schema.SchemaManager;
042 import org.apache.directory.shared.ldap.schema.registries.ObjectClassRegistry;
043 import org.apache.directory.shared.ldap.util.NamespaceTools;
044 import org.slf4j.Logger;
045 import org.slf4j.LoggerFactory;
046
047
048 /**
049 * Performs schema checks on behalf of the SchemaInterceptor.
050 *
051 * TODO: we really need to refactor this code since there's much duplication
052 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
053 * @version $Rev: 927839 $, $Date: 2010-03-26 15:25:10 +0200 (Fri, 26 Mar 2010) $
054 */
055 public class SchemaChecker
056 {
057 /** the SLF4J logger for this class */
058 private static Logger log = LoggerFactory.getLogger( SchemaChecker.class );
059
060
061 /**
062 * Makes sure modify operations do not leave the entry without a STRUCTURAL
063 * objectClass. At least one STRUCTURAL objectClass must be specified for
064 * the entry after modifications take effect.
065 *
066 * @param registry the objectClass registry to lookup ObjectClass specifications
067 * @param name the name of the entry being modified
068 * @param mod the type of modification operation being performed (should be
069 * REMOVE_ATTRIBUTE)
070 * @param attribute the attribute being modified
071 * @throws LdapException if modify operations leave the entry inconsistent
072 * without a STRUCTURAL objectClass
073 */
074 public static void preventStructuralClassRemovalOnModifyReplace( SchemaManager schemaManager, DN name, ModificationOperation mod,
075 EntryAttribute attribute ) throws LdapException
076 {
077 if ( mod != ModificationOperation.REPLACE_ATTRIBUTE )
078 {
079 return;
080 }
081
082 if ( !SchemaConstants.OBJECT_CLASS_AT.equalsIgnoreCase( attribute.getUpId() ) )
083 {
084 return;
085 }
086
087 // whoever issued the modify operation is insane they want to delete
088 // all the objectClass values in which case we must throw an exception
089 if ( attribute.size() == 0 )
090 {
091 String msg = I18n.err( I18n.ERR_272, name );
092
093 if ( log.isInfoEnabled() )
094 {
095 log.info( msg + ". Raising LdapSchemaViolationException." );
096 }
097
098 throw new LdapSchemaViolationException( ResultCodeEnum.OBJECT_CLASS_MODS_PROHIBITED, msg );
099 }
100
101 // check that there is at least one structural objectClass in the replacement set
102 for ( Value<?> value:attribute )
103 {
104 ObjectClass ocType = schemaManager.getObjectClassRegistry().lookup( value.getString() );
105
106 if ( ocType.getType() == ObjectClassTypeEnum.STRUCTURAL )
107 {
108 return;
109 }
110 }
111
112 // no structural object classes exist for the entry in the replacement
113 // set for the objectClass attribute so we need to complain about that
114 String msg = I18n.err( I18n.ERR_272, name );
115 if ( log.isInfoEnabled() )
116 {
117 log.info( msg + ". Raising LdapSchemaViolationException." );
118 }
119 throw new LdapSchemaViolationException( ResultCodeEnum.OBJECT_CLASS_MODS_PROHIBITED, msg );
120 }
121
122
123 /**
124 * Makes sure modify operations do not leave the entry without a STRUCTURAL
125 * objectClass. At least one STRUCTURAL objectClass must be specified for
126 * the entry after modifications take effect.
127 *
128 * @param registry the objectClass registry to lookup ObjectClass specifications
129 * @param name the name of the entry being modified
130 * @param mod the type of modification operation being performed (should be
131 * REMOVE_ATTRIBUTE)
132 * @param entry the entry being modified
133 * @throws LdapException if modify operations leave the entry inconsistent
134 * without a STRUCTURAL objectClass
135 */
136 public static void preventStructuralClassRemovalOnModifyReplace(
137 ObjectClassRegistry registry, DN name, ModificationOperation mod, ServerEntry entry ) throws LdapException
138 {
139 if ( mod != ModificationOperation.REPLACE_ATTRIBUTE )
140 {
141 return;
142 }
143
144 EntryAttribute objectClass = entry.get( SchemaConstants.OBJECT_CLASS_AT );
145
146 if ( objectClass == null )
147 {
148 return;
149 }
150
151 // whoever issued the modify operation is insane they want to delete
152 // all the objectClass values in which case we must throw an exception
153 if ( objectClass.size() == 0 )
154 {
155 String msg = I18n.err( I18n.ERR_272, name );
156 if ( log.isInfoEnabled() )
157 {
158 log.info( msg + ". Raising LdapSchemaViolationException." );
159 }
160 throw new LdapSchemaViolationException( ResultCodeEnum.OBJECT_CLASS_MODS_PROHIBITED, msg );
161 }
162
163 // check that there is at least one structural objectClass in the replacement set
164 for ( Value<?> value:objectClass )
165 {
166 ObjectClass ocType = registry.lookup( value.getString() );
167
168 if ( ocType.getType() == ObjectClassTypeEnum.STRUCTURAL )
169 {
170 return;
171 }
172 }
173
174 // no structural object classes exist for the entry in the replacement
175 // set for the objectClass attribute so we need to complain about that
176 String msg = I18n.err( I18n.ERR_272, name );
177 if ( log.isInfoEnabled() )
178 {
179 log.info( msg + ". Raising LdapSchemaViolationException." );
180 }
181 throw new LdapSchemaViolationException( ResultCodeEnum.OBJECT_CLASS_MODS_PROHIBITED, msg );
182 }
183
184
185 /**
186 * Makes sure modify operations do not leave the entry without a STRUCTURAL
187 * objectClass. At least one STRUCTURAL objectClass must be specified for
188 * the entry after modifications take effect.
189 *
190 * @param registry the objectClass registry to lookup ObjectClass specifications
191 * @param name the name of the entry being modified
192 * @param mod the type of modification operation being performed (should be
193 * REMOVE_ATTRIBUTE)
194 * @param attribute the attribute being modified
195 * @param entryObjectClasses the entry being modified
196 * @throws LdapException if modify operations leave the entry inconsistent
197 * without a STRUCTURAL objectClass
198 */
199 public static void preventStructuralClassRemovalOnModifyRemove( SchemaManager schemaManager, DN name, ModificationOperation mod,
200 EntryAttribute attribute, EntryAttribute entryObjectClasses ) throws LdapException
201 {
202 if ( mod != ModificationOperation.REMOVE_ATTRIBUTE )
203 {
204 return;
205 }
206
207 if ( !attribute.instanceOf( SchemaConstants.OBJECT_CLASS_AT ) )
208 {
209 return;
210 }
211
212 // check if there is any attribute value as "".
213 // if there is remove it so that it will be considered as not even provided.
214 List<Value<?>> removed = new ArrayList<Value<?>>();
215
216 // Fist gather the value to remove
217 for ( Value<?> value:attribute )
218 {
219 if ( value.getString().length() == 0 )
220 {
221 removed.add( value );
222 }
223 }
224
225 // Now remove the values from the attribute
226 for ( Value<?> value:removed )
227 {
228 attribute.remove( value );
229 }
230
231 // whoever issued the modify operation is insane they want to delete
232 // all the objectClass values in which case we must throw an exception
233 if ( attribute.size() == 0 )
234 {
235 String msg = I18n.err( I18n.ERR_272, name );
236
237 if ( log.isInfoEnabled() )
238 {
239 log.info( msg + ". Raising LdapSchemaViolationException." );
240 }
241
242 throw new LdapSchemaViolationException( ResultCodeEnum.OBJECT_CLASS_MODS_PROHIBITED, msg );
243 }
244
245 // remove all the objectClass attribute values from a cloned copy and then
246 // we can analyze what remains in this attribute to make sure a structural
247 // objectClass is present for the entry
248
249 EntryAttribute cloned = entryObjectClasses.clone();
250
251 for ( Value<?> value:attribute )
252 {
253 cloned.remove( value );
254 }
255
256 // check resultant set of objectClass values for a structural objectClass
257 for ( Value<?> objectClass:cloned )
258 {
259 ObjectClass oc = schemaManager.getObjectClassRegistry().lookup( objectClass.getString() );
260
261 if ( oc.getType() == ObjectClassTypeEnum.STRUCTURAL )
262 {
263 return;
264 }
265 }
266
267 // no structural object classes exist for the entry after the modifications
268 // to the objectClass attribute so we need to complain about that
269 String msg = I18n.err( I18n.ERR_272, name );
270
271 if ( log.isInfoEnabled() )
272 {
273 log.info( msg + ". Raising LdapSchemaViolationException." );
274 }
275
276 throw new LdapSchemaViolationException( ResultCodeEnum.OBJECT_CLASS_MODS_PROHIBITED, msg );
277 }
278
279
280 /**
281 * Makes sure modify operations do not leave the entry without a STRUCTURAL
282 * objectClass. At least one STRUCTURAL objectClass must be specified for
283 * the entry after modifications take effect.
284 *
285 * @param registry the objectClass registry to lookup ObjectClass specifications
286 * @param name the name of the entry being modified
287 * @param mod the type of modification operation being performed (should be
288 * REMOVE_ATTRIBUTE)
289 * @param attributes the attributes being modified
290 * @param entryObjectClasses the entry being modified
291 * @throws NamingException if modify operations leave the entry inconsistent
292 * without a STRUCTURAL objectClass
293 *
294 public static void preventStructuralClassRemovalOnModifyRemove( ObjectClassRegistry registry, Name name, int mod,
295 Attributes attributes, Attribute entryObjectClasses ) throws NamingException
296 {
297 if ( mod != DirContext.REMOVE_ATTRIBUTE )
298 {
299 return;
300 }
301
302 Attribute objectClass = attributes.get( SchemaConstants.OBJECT_CLASS_AT );
303 if ( objectClass == null )
304 {
305 return;
306 }
307
308 // check if there is any attribute value as "".
309 // if there is remove it so that it will be considered as not even provided.
310 for( int ii = 0; ii < objectClass.size(); ii++ )
311 {
312 Object value = objectClass.get( ii );
313 if ( "".equals( value ) )
314 {
315 objectClass.remove( ii );
316 }
317 }
318
319 // whoever issued the modify operation is insane they want to delete
320 // all the objectClass values in which case we must throw an exception
321 if ( objectClass.size() == 0 )
322 {
323 String msg = "Modify operation leaves no structural objectClass for entry " + name;
324 if ( log.isInfoEnabled() )
325 {
326 log.info( msg + ". Raising LdapSchemaViolationException." );
327 }
328 throw new LdapSchemaViolationException( msg, ResultCodeEnum.OBJECT_CLASS_MODS_PROHIBITED );
329 }
330
331 // remove all the objectClass attribute values from a cloned copy and then
332 // we can analyze what remains in this attribute to make sure a structural
333 // objectClass is present for the entry
334
335 Attribute cloned = ( Attribute ) entryObjectClasses.clone();
336 for ( int ii = 0; ii < objectClass.size(); ii++ )
337 {
338 cloned.remove( objectClass.get( ii ) );
339 }
340
341 // check resultant set of objectClass values for a structural objectClass
342 for ( int ii = 0; ii < cloned.size(); ii++ )
343 {
344 ObjectClass ocType = registry.lookup( ( String ) cloned.get( ii ) );
345 if ( ocType.getType() == ObjectClassTypeEnum.STRUCTURAL )
346 {
347 return;
348 }
349 }
350
351 // no structural object classes exist for the entry after the modifications
352 // to the objectClass attribute so we need to complain about that
353 String msg = "Modify operation leaves no structural objectClass for entry " + name;
354 if ( log.isInfoEnabled() )
355 {
356 log.info( msg + ". Raising LdapSchemaViolationException." );
357 }
358 throw new LdapSchemaViolationException( msg, ResultCodeEnum.OBJECT_CLASS_MODS_PROHIBITED );
359 }
360 */
361
362 /**
363 * Makes sure a modify operation does not replace RDN attributes or their value.
364 * According to section 4.6 of <a href="http://rfc.net/rfc2251.html#s4.6.">
365 * RFC 2251</a> a modify operation cannot be used to remove Rdn attributes as
366 * seen below:
367 * <p/>
368 * <pre>
369 * The Modify Operation cannot be used to remove from an entry any of
370 * its distinguished values, those values which form the entry's
371 * relative distinguished name. An attempt to do so will result in the
372 * server returning the error notAllowedOnRDN. The Modify DN Operation
373 * described in section 4.9 is used to rename an entry.
374 * </pre>
375 *
376 * @param name the distinguished name of the attribute being modified
377 * @param mod the modification operation being performed (should be REPLACE_ATTRIBUTE )
378 * @param attribute the attribute being modified
379 * @param oidRegistry
380 * @throws LdapException if the modify operation is removing an Rdn attribute
381 */
382 public static void preventRdnChangeOnModifyReplace( DN name, ModificationOperation mod,
383 EntryAttribute attribute, SchemaManager schemaManager )
384 throws LdapException
385 {
386 if ( mod != ModificationOperation.REPLACE_ATTRIBUTE )
387 {
388 return;
389 }
390
391 Set<String> rdnAttributes = getRdnAttributes( name );
392 String id = schemaManager.getAttributeTypeRegistry().getOidByName( attribute.getUpId() );
393
394 if ( !rdnAttributes.contains( id ) )
395 {
396 return;
397 }
398
399 // if the attribute values to delete are not specified then all values
400 // for the attribute are to be deleted in which case we must just throw
401 // a schema violation exception with the notAllowedOnRdn result code
402 if ( attribute.size() == 0 )
403 {
404 String msg = I18n.err( I18n.ERR_273, id, name );
405
406 if ( log.isInfoEnabled() )
407 {
408 log.info( msg + ". SchemaChecker is throwing a schema violation exception." );
409 }
410 throw new LdapSchemaViolationException( ResultCodeEnum.NOT_ALLOWED_ON_RDN, msg );
411 }
412
413 // from here on the modify operation replaces specific values
414 // of the Rdn attribute so we must check to make sure all the old
415 // rdn attribute values are present in the replacement set
416 String rdnValue = getRdnValue( id, name, schemaManager );
417
418 for ( int ii = 0; ii < attribute.size(); ii++ )
419 {
420 // if the old rdn value is not in the rdn attribute then
421 // we must complain with a schema violation
422 if ( !attribute.contains( rdnValue ) )
423 {
424 String msg = I18n.err( I18n.ERR_274, id, name );
425
426 if ( log.isInfoEnabled() )
427 {
428 log.info( msg + ". SchemaChecker is throwing a schema violation exception." );
429 }
430 throw new LdapSchemaViolationException( ResultCodeEnum.NOT_ALLOWED_ON_RDN, msg );
431 }
432 }
433 }
434
435
436 /**
437 * Makes sure a modify operation does not replace RDN attributes or their value.
438 * According to section 4.6 of <a href="http://rfc.net/rfc2251.html#s4.6.">
439 * RFC 2251</a> a modify operation cannot be used to remove Rdn attributes as
440 * seen below:
441 * <p/>
442 * <pre>
443 * The Modify Operation cannot be used to remove from an entry any of
444 * its distinguished values, those values which form the entry's
445 * relative distinguished name. An attempt to do so will result in the
446 * server returning the error notAllowedOnRDN. The Modify DN Operation
447 * described in section 4.9 is used to rename an entry.
448 * </pre>
449 *
450 * @param name the distinguished name of the attribute being modified
451 * @param mod the modification operation being performed (should be REPLACE_ATTRIBUTE )
452 * @param entry
453 * @param oidRegistry
454 * @throws LdapException if the modify operation is removing an Rdn attribute
455 */
456 public static void preventRdnChangeOnModifyReplace(
457 DN name, ModificationOperation mod, ServerEntry entry,
458 SchemaManager schemaManager )
459 throws LdapException
460 {
461 if ( mod != ModificationOperation.REPLACE_ATTRIBUTE )
462 {
463 return;
464 }
465
466 Set<String> rdnAttributes = getRdnAttributes( name );
467
468 for ( AttributeType attributeType:entry.getAttributeTypes() )
469 {
470 String id = attributeType.getName();
471
472 if ( rdnAttributes.contains( id ) )
473 {
474 EntryAttribute rdnAttr = entry.get( id );
475
476 // if the attribute values to delete are not specified then all values
477 // for the attribute are to be deleted in which case we must just throw
478 // a schema violation exception with the notAllowedOnRdn result code
479 if ( rdnAttr.size() == 0 )
480 {
481 String msg = I18n.err( I18n.ERR_273, id, name );
482
483 if ( log.isInfoEnabled() )
484 {
485 log.info( msg + ". SchemaChecker is throwing a schema violation exception." );
486 }
487
488 throw new LdapSchemaViolationException( ResultCodeEnum.NOT_ALLOWED_ON_RDN, msg );
489 }
490
491 // from here on the modify operation replaces specific values
492 // of the Rdn attribute so we must check to make sure all the old
493 // rdn attribute values are present in the replacement set
494 String rdnValue = getRdnValue( id, name, schemaManager );
495
496 // if the old rdn value is not in the rdn attribute then
497 // we must complain with a schema violation
498 if ( !rdnAttr.contains( rdnValue ) )
499 {
500 String msg = I18n.err( I18n.ERR_274, id, name );
501
502 if ( log.isInfoEnabled() )
503 {
504 log.info( msg + ". SchemaChecker is throwing a schema violation exception." );
505 }
506
507 throw new LdapSchemaViolationException( ResultCodeEnum.NOT_ALLOWED_ON_RDN, msg );
508 }
509 }
510 }
511 }
512
513
514 /**
515 * Makes sure a modify operation does not delete RDN attributes or their value.
516 * According to section 4.6 of <a href="http://rfc.net/rfc2251.html#s4.6.">
517 * RFC 2251</a> a modify operation cannot be used to remove Rdn attributes as
518 * seen below:
519 * <p/>
520 * <pre>
521 * The Modify Operation cannot be used to remove from an entry any of
522 * its distinguished values, those values which form the entry's
523 * relative distinguished name. An attempt to do so will result in the
524 * server returning the error notAllowedOnRDN. The Modify DN Operation
525 * described in section 4.9 is used to rename an entry.
526 * </pre>
527 *
528 * @param name the distinguished name of the attribute being modified
529 * @param mod the modification operation being performed (should be REMOVE_ATTRIBUTE )
530 * @param attribute the attribute being modified
531 * @throws LdapException if the modify operation is removing an Rdn attribute
532 */
533 public static void preventRdnChangeOnModifyRemove( DN name, ModificationOperation mod, EntryAttribute attribute,
534 SchemaManager schemaManager ) throws LdapException
535 {
536 if ( mod != ModificationOperation.REMOVE_ATTRIBUTE )
537 {
538 return;
539 }
540
541 Set<String> rdnAttributes = getRdnAttributes( name );
542 String id = attribute.getId();
543
544 if ( !rdnAttributes.contains( schemaManager.getAttributeTypeRegistry().getOidByName( id ) ) )
545 {
546 return;
547 }
548
549 // if the attribute values to delete are not specified then all values
550 // for the attribute are to be deleted in which case we must just throw
551 // a schema violation exception with the notAllowedOnRdn result code
552 if ( attribute.size() == 0 )
553 {
554 String msg = I18n.err( I18n.ERR_273, id, name );
555
556 if ( log.isInfoEnabled() )
557 {
558 log.info( msg + ". SchemaChecker is throwing a schema violation exception." );
559 }
560
561 throw new LdapSchemaViolationException( ResultCodeEnum.NOT_ALLOWED_ON_RDN, msg );
562 }
563
564 // from here on the modify operation only deletes specific values
565 // of the Rdn attribute so we must check if one of those values
566 // are used by the Rdn attribute value pair for the name of the entry
567 String rdnValue = getRdnValue( id, name, schemaManager );
568
569 for ( Value<?> value:attribute )
570 {
571 if ( rdnValue.equals( value.getString() ) )
572 {
573 String msg = I18n.err( I18n.ERR_274, id, name );
574
575 if ( log.isInfoEnabled() )
576 {
577 log.info( msg + ". SchemaChecker is throwing a schema violation exception." );
578 }
579
580 throw new LdapSchemaViolationException( ResultCodeEnum.NOT_ALLOWED_ON_RDN, msg );
581 }
582 }
583 }
584
585
586 /**
587 * Makes sure a modify operation does not delete RDN attributes or their value.
588 * According to section 4.6 of <a href="http://rfc.net/rfc2251.html#s4.6.">
589 * RFC 2251</a> a modify operation cannot be used to remove Rdn attributes as
590 * seen below:
591 * <p/>
592 * <pre>
593 * The Modify Operation cannot be used to remove from an entry any of
594 * its distinguished values, those values which form the entry's
595 * relative distinguished name. An attempt to do so will result in the
596 * server returning the error notAllowedOnRDN. The Modify DN Operation
597 * described in section 4.9 is used to rename an entry.
598 * </pre>
599 *
600 * @param name the distinguished name of the attribute being modified
601 * @param mod the modification operation being performed (should be REMOVE_ATTRIBUTE )
602 * @param entry
603 * @param oidRegistry
604 * @throws LdapException if the modify operation is removing an Rdn attribute
605 */
606 public static void preventRdnChangeOnModifyRemove( DN name, ModificationOperation mod,
607 ServerEntry entry, SchemaManager schemaManager )
608 throws LdapException
609 {
610 if ( mod != ModificationOperation.REMOVE_ATTRIBUTE )
611 {
612 return;
613 }
614
615 Set<String> rdnAttributes = getRdnAttributes( name );
616
617 for ( AttributeType attributeType:entry.getAttributeTypes() )
618 {
619 String id = attributeType.getName();
620
621 if ( rdnAttributes.contains( id ) )
622 {
623 // if the attribute values to delete are not specified then all values
624 // for the attribute are to be deleted in which case we must just throw
625 // a schema violation exception with the notAllowedOnRdn result code
626 if ( entry.get( id ).size() == 0 )
627 {
628 String msg = I18n.err( I18n.ERR_273, id, name );
629
630 if ( log.isInfoEnabled() )
631 {
632 log.info( msg + ". SchemaChecker is throwing a schema violation exception." );
633 }
634 throw new LdapSchemaViolationException( ResultCodeEnum.NOT_ALLOWED_ON_RDN, msg );
635 }
636
637 // from here on the modify operation only deletes specific values
638 // of the Rdn attribute so we must check if one of those values
639 // are used by the Rdn attribute value pair for the name of the entry
640 String rdnValue = getRdnValue( id, name, schemaManager );
641 EntryAttribute rdnAttr = entry.get( id );
642
643 for ( Value<?> value:rdnAttr )
644 {
645 if ( rdnValue.equals( value.getString() ) )
646 {
647 String msg = I18n.err( I18n.ERR_274, id, name );
648
649 if ( log.isInfoEnabled() )
650 {
651 log.info( msg + ". SchemaChecker is throwing a schema violation exception." );
652 }
653 throw new LdapSchemaViolationException( ResultCodeEnum.NOT_ALLOWED_ON_RDN, msg );
654 }
655 }
656 }
657 }
658 }
659
660
661 /**
662 * Gets the Rdn attribute value. This method works even if the Rdn is
663 * composed of multiple attributes.
664 *
665 * @param id the attribute id of the Rdn attribute to return
666 * @param name the distinguished name of the entry
667 * @param oidRegistry the OID registry
668 * @return the Rdn attribute value corresponding to the id, or null if the
669 * attribute is not an rdn attribute
670 * @throws LdapException if the name is malformed in any way
671 */
672 private static String getRdnValue( String id, DN name, SchemaManager schemaManager ) throws LdapException
673 {
674 // Transform the rdnAttrId to it's OID counterPart
675 String idOid = schemaManager.getAttributeTypeRegistry().getOidByName( id );
676
677 if ( idOid == null )
678 {
679 log.error( I18n.err( I18n.ERR_43, id ) );
680 throw new LdapException( I18n.err( I18n.ERR_44, id ) );
681 }
682
683 String[] comps = NamespaceTools.getCompositeComponents( name.get( name.size() - 1 ) );
684
685 for ( int ii = 0; ii < comps.length; ii++ )
686 {
687 String rdnAttrId = NamespaceTools.getRdnAttribute( comps[ii] );
688
689 // Transform the rdnAttrId to it's OID counterPart
690 String rdnAttrOid = schemaManager.getAttributeTypeRegistry().getOidByName( rdnAttrId );
691
692 if ( rdnAttrOid == null )
693 {
694 log.error( I18n.err( I18n.ERR_43, rdnAttrOid ) );
695 throw new LdapException( I18n.err( I18n.ERR_44, rdnAttrOid ) );
696 }
697
698 if ( rdnAttrOid.equalsIgnoreCase( idOid ) )
699 {
700 return NamespaceTools.getRdnValue( comps[ii] );
701 }
702 }
703
704 return null;
705 }
706
707
708 /**
709 * Collects the set of Rdn attributes whether or not the Rdn is based on a
710 * single attribute or multiple attributes.
711 *
712 * @param name the distinguished name of an entry
713 * @return the set of attributes composing the Rdn for the name
714 * @throws LdapException if the syntax of the Rdn is incorrect
715 */
716 private static Set<String> getRdnAttributes( DN name ) throws LdapException
717 {
718 String[] comps = NamespaceTools.getCompositeComponents( name.get( name.size() - 1 ) );
719 Set<String> attributes = new HashSet<String>();
720
721 for ( int ii = 0; ii < comps.length; ii++ )
722 {
723 attributes.add( NamespaceTools.getRdnAttribute( comps[ii] ) );
724 }
725
726 return attributes;
727 }
728 }