1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.directory.server.core.subtree;
21
22
23 import java.util.ArrayList;
24 import java.util.HashSet;
25 import java.util.List;
26 import java.util.Set;
27
28 import javax.naming.directory.SearchControls;
29
30 import org.apache.directory.api.ldap.model.constants.SchemaConstants;
31 import org.apache.directory.api.ldap.model.entry.Attribute;
32 import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
33 import org.apache.directory.api.ldap.model.entry.DefaultEntry;
34 import org.apache.directory.api.ldap.model.entry.DefaultModification;
35 import org.apache.directory.api.ldap.model.entry.Entry;
36 import org.apache.directory.api.ldap.model.entry.Modification;
37 import org.apache.directory.api.ldap.model.entry.ModificationOperation;
38 import org.apache.directory.api.ldap.model.entry.Value;
39 import org.apache.directory.api.ldap.model.exception.LdapException;
40 import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
41 import org.apache.directory.api.ldap.model.exception.LdapNoSuchAttributeException;
42 import org.apache.directory.api.ldap.model.exception.LdapOperationErrorException;
43 import org.apache.directory.api.ldap.model.exception.LdapOperationException;
44 import org.apache.directory.api.ldap.model.exception.LdapOtherException;
45 import org.apache.directory.api.ldap.model.exception.LdapSchemaViolationException;
46 import org.apache.directory.api.ldap.model.filter.EqualityNode;
47 import org.apache.directory.api.ldap.model.filter.ExprNode;
48 import org.apache.directory.api.ldap.model.filter.ObjectClassNode;
49 import org.apache.directory.api.ldap.model.filter.PresenceNode;
50 import org.apache.directory.api.ldap.model.message.AliasDerefMode;
51 import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
52 import org.apache.directory.api.ldap.model.message.SearchScope;
53 import org.apache.directory.api.ldap.model.message.controls.Subentries;
54 import org.apache.directory.api.ldap.model.name.Dn;
55 import org.apache.directory.api.ldap.model.schema.AttributeType;
56 import org.apache.directory.api.ldap.model.subtree.AdministrativeRole;
57 import org.apache.directory.api.ldap.model.subtree.Subentry;
58 import org.apache.directory.api.ldap.model.subtree.SubtreeSpecification;
59 import org.apache.directory.api.ldap.model.subtree.SubtreeSpecificationParser;
60 import org.apache.directory.server.constants.ApacheSchemaConstants;
61 import org.apache.directory.server.core.api.CoreSession;
62 import org.apache.directory.server.core.api.DirectoryService;
63 import org.apache.directory.server.core.api.InterceptorEnum;
64 import org.apache.directory.server.core.api.entry.ClonedServerEntry;
65 import org.apache.directory.server.core.api.filtering.EntryFilter;
66 import org.apache.directory.server.core.api.filtering.EntryFilteringCursor;
67 import org.apache.directory.server.core.api.interceptor.BaseInterceptor;
68 import org.apache.directory.server.core.api.interceptor.context.AddOperationContext;
69 import org.apache.directory.server.core.api.interceptor.context.DeleteOperationContext;
70 import org.apache.directory.server.core.api.interceptor.context.LookupOperationContext;
71 import org.apache.directory.server.core.api.interceptor.context.ModifyOperationContext;
72 import org.apache.directory.server.core.api.interceptor.context.MoveAndRenameOperationContext;
73 import org.apache.directory.server.core.api.interceptor.context.MoveOperationContext;
74 import org.apache.directory.server.core.api.interceptor.context.OperationContext;
75 import org.apache.directory.server.core.api.interceptor.context.RenameOperationContext;
76 import org.apache.directory.server.core.api.interceptor.context.SearchOperationContext;
77 import org.apache.directory.server.core.api.partition.Partition;
78 import org.apache.directory.server.core.api.partition.PartitionNexus;
79 import org.apache.directory.server.core.api.subtree.SubentryCache;
80 import org.apache.directory.server.core.api.subtree.SubtreeEvaluator;
81 import org.apache.directory.server.i18n.I18n;
82 import org.slf4j.Logger;
83 import org.slf4j.LoggerFactory;
84
85
86
87
88
89
90
91
92 public class SubentryInterceptor extends BaseInterceptor
93 {
94
95 private static final Logger LOG = LoggerFactory.getLogger( SubentryInterceptor.class );
96
97
98 private static final String SUBENTRY_CONTROL = Subentries.OID;
99
100 private Value subentryOC;
101
102
103 private SubtreeSpecificationParser ssParser;
104
105
106 private PartitionNexus nexus;
107
108
109 private enum OperationEnum
110 {
111 ADD,
112 REMOVE,
113 REPLACE
114 }
115
116
117
118
119
120 public SubentryInterceptor()
121 {
122 super( InterceptorEnum.SUBENTRY_INTERCEPTOR );
123 }
124
125
126
127
128
129
130
131 private class HideSubentriesFilter implements EntryFilter
132 {
133
134
135
136 @Override
137 public boolean accept( SearchOperationContext searchContext, Entry entry ) throws LdapException
138 {
139
140 if ( directoryService.getSubentryCache().hasSubentry( entry.getDn() ) )
141 {
142 return false;
143 }
144
145
146 return !entry.contains( directoryService.getAtProvider().getObjectClass(), subentryOC );
147 }
148
149
150
151
152
153 @Override
154 public String toString( String tabs )
155 {
156 return tabs + "HideSubentriesFilter";
157 }
158 }
159
160
161
162
163
164 private class HideEntriesFilter implements EntryFilter
165 {
166
167
168
169 @Override
170 public boolean accept( SearchOperationContext searchContext, Entry entry ) throws LdapException
171 {
172
173 if ( directoryService.getSubentryCache().hasSubentry( entry.getDn() ) )
174 {
175 return true;
176 }
177
178
179 return entry.contains( directoryService.getAtProvider().getObjectClass(), SchemaConstants.SUBENTRY_OC );
180 }
181
182
183
184
185
186 @Override
187 public String toString( String tabs )
188 {
189 return tabs + "HideEntriesFilter";
190 }
191 }
192
193
194
195
196
197
198
199
200
201
202 @Override
203 public void init( DirectoryService directoryService ) throws LdapException
204 {
205 super.init( directoryService );
206
207 nexus = directoryService.getPartitionNexus();
208
209 ssParser = new SubtreeSpecificationParser( schemaManager );
210 AttributeType ocAt = directoryService.getAtProvider().getObjectClass();
211
212
213 Set<String> suffixes = nexus.listSuffixes();
214 ExprNode filter = new EqualityNode<String>( ocAt, new Value( ocAt, SchemaConstants.SUBENTRY_OC ) );
215 SearchControls controls = new SearchControls();
216 controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
217 controls.setReturningAttributes( new String[]
218 { SchemaConstants.SUBTREE_SPECIFICATION_AT, SchemaConstants.OBJECT_CLASS_AT } );
219
220 subentryOC = new Value( ocAt, SchemaConstants.SUBENTRY_OC );
221
222
223 for ( String suffix : suffixes )
224 {
225 CoreSession adminSession = directoryService.getAdminSession();
226
227 Dn suffixDn = dnFactory.create( suffix );
228 Partition partition = nexus.getPartition( suffixDn );
229
230 SearchOperationContextxt/SearchOperationContext.html#SearchOperationContext">SearchOperationContext searchOperationContext = new SearchOperationContext( adminSession, suffixDn, filter,
231 controls );
232 searchOperationContext.setAliasDerefMode( AliasDerefMode.NEVER_DEREF_ALIASES );
233 searchOperationContext.setPartition( partition );
234 searchOperationContext.setTransaction( partition.beginReadTransaction() );
235
236 EntryFilteringCursor subentries = nexus.search( searchOperationContext );
237
238
239
240 try
241 {
242 while ( subentries.next() )
243 {
244 Entry subentry = subentries.get();
245 Dn subentryDn = subentry.getDn();
246
247 String subtree = subentry.get( directoryService.getAtProvider().getSubtreeSpecification() )
248 .getString();
249 SubtreeSpecification ss;
250
251 try
252 {
253 ss = ssParser.parse( subtree );
254 }
255 catch ( Exception e )
256 {
257 LOG.warn( "Failed while parsing subtreeSpecification for {}", subentryDn );
258 continue;
259 }
260
261 Subentry newSubentry = new Subentry();
262
263 newSubentry.setAdministrativeRoles( getSubentryAdminRoles( subentry ) );
264 newSubentry.setSubtreeSpecification( ss );
265
266 directoryService.getSubentryCache().addSubentry( subentryDn, newSubentry );
267 }
268 }
269 catch ( Exception e )
270 {
271 throw new LdapOperationException( e.getMessage(), e );
272 }
273 finally
274 {
275 try
276 {
277 subentries.close();
278 }
279 catch ( Exception e )
280 {
281 LOG.error( I18n.err( I18n.ERR_168 ), e );
282 }
283 }
284 }
285 }
286
287
288
289
290
291
292
293
294 private Set<AdministrativeRole> getSubentryAdminRoles( Entry subentry ) throws LdapException
295 {
296 Set<AdministrativeRole> adminRoles = new HashSet<>();
297
298 Attribute oc = subentry.get( directoryService.getAtProvider().getObjectClass() );
299
300 if ( oc == null )
301 {
302 throw new LdapSchemaViolationException( ResultCodeEnum.OBJECT_CLASS_VIOLATION, I18n.err( I18n.ERR_305 ) );
303 }
304
305 if ( oc.contains( SchemaConstants.ACCESS_CONTROL_SUBENTRY_OC ) )
306 {
307 adminRoles.add( AdministrativeRole.AccessControlInnerArea );
308 }
309
310 if ( oc.contains( SchemaConstants.SUBSCHEMA_OC ) )
311 {
312 adminRoles.add( AdministrativeRole.SubSchemaSpecificArea );
313 }
314
315 if ( oc.contains( SchemaConstants.COLLECTIVE_ATTRIBUTE_SUBENTRY_OC ) )
316 {
317 adminRoles.add( AdministrativeRole.CollectiveAttributeSpecificArea );
318 }
319
320 if ( oc.contains( ApacheSchemaConstants.TRIGGER_EXECUTION_SUBENTRY_OC ) )
321 {
322 adminRoles.add( AdministrativeRole.TriggerExecutionInnerArea );
323 }
324
325 return adminRoles;
326 }
327
328
329
330
331
332
333
334
335
336 private boolean isSubentryVisible( OperationContext opContext )
337 {
338 if ( !opContext.hasRequestControls() )
339 {
340 return false;
341 }
342
343
344 if ( opContext.hasRequestControl( SUBENTRY_CONTROL ) )
345 {
346 Subentries subentries = ( Subentries ) opContext.getRequestControl( SUBENTRY_CONTROL );
347 return subentries.isVisible();
348 }
349
350 return false;
351 }
352
353
354
355
356
357 private void updateEntries( OperationContext opContext, OperationEnum operation,
358 Dn apDn, SubtreeSpecification ss, Dn baseDn, List<Attribute> operationalAttributes ) throws LdapException
359 {
360 ExprNode filter = ObjectClassNode.OBJECT_CLASS_NODE;
361 SearchControls controls = new SearchControls();
362 controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
363 controls.setReturningAttributes( new String[]
364 { SchemaConstants.ALL_OPERATIONAL_ATTRIBUTES, SchemaConstants.ALL_USER_ATTRIBUTES } );
365
366 SearchOperationContextxt/SearchOperationContext.html#SearchOperationContext">SearchOperationContext searchOperationContext = new SearchOperationContext( opContext.getSession(),
367 baseDn, filter, controls );
368 searchOperationContext.setAliasDerefMode( AliasDerefMode.NEVER_DEREF_ALIASES );
369 searchOperationContext.setPartition( opContext.getPartition() );
370 searchOperationContext.setTransaction( opContext.getTransaction() );
371
372 EntryFilteringCursor subentries = nexus.search( searchOperationContext );
373
374 try
375 {
376 while ( subentries.next() )
377 {
378 Entry candidate = subentries.get();
379 Dn candidateDn = candidate.getDn();
380
381 if ( directoryService.getEvaluator().evaluate( ss, apDn, candidateDn, candidate ) )
382 {
383 List<Modification> modifications = null;
384
385 switch ( operation )
386 {
387 case ADD:
388 modifications = getOperationalModsForAdd( candidate, operationalAttributes );
389 break;
390
391 case REMOVE:
392 modifications = getOperationalModsForRemove( opContext.getDn(), candidate );
393 break;
394
395 case REPLACE:
396
397
398 break;
399
400 default:
401 throw new IllegalArgumentException( "Unexpected operation " + operation );
402 }
403
404 LOG.debug( "The entry {} has been evaluated to true for subentry {}", candidate.getDn(), opContext.getDn() );
405 ModifyOperationContexttor/context/ModifyOperationContext.html#ModifyOperationContext">ModifyOperationContext modifyContext = new ModifyOperationContext( opContext.getSession(), candidateDn, modifications );
406 modifyContext.setPartition( opContext.getPartition() );
407 modifyContext.setTransaction( opContext.getTransaction() );
408
409 nexus.modify( modifyContext );
410 }
411 }
412
413 subentries.close();
414 }
415 catch ( Exception e )
416 {
417 throw new LdapOtherException( e.getMessage(), e );
418 }
419 finally
420 {
421 try
422 {
423 subentries.close();
424 }
425 catch ( Exception e )
426 {
427 LOG.error( I18n.err( I18n.ERR_168 ), e );
428 }
429 }
430 }
431
432
433
434
435
436 private boolean isNamingContext( Dn dn ) throws LdapException
437 {
438 Dn namingContext = nexus.getSuffixDn( dn );
439
440 return dn.equals( namingContext );
441 }
442
443
444
445
446
447 private void checkAdministrativeRole( OperationContext opContext, Dn apDn ) throws LdapException
448 {
449 CoreSession session = opContext.getSession();
450 LookupOperationContexttor/context/LookupOperationContext.html#LookupOperationContext">LookupOperationContext lookupContext = new LookupOperationContext( session, apDn,
451 SchemaConstants.ALL_ATTRIBUTES_ARRAY );
452 lookupContext.setPartition( opContext.getPartition() );
453 lookupContext.setTransaction( opContext.getTransaction() );
454
455 Entry administrationPoint = directoryService.getPartitionNexus().lookup( lookupContext );
456
457
458 Attribute administrativeRole = administrationPoint.get( directoryService.getAtProvider()
459 .getAdministrativeRole() );
460
461
462 if ( ( administrativeRole == null ) || ( administrativeRole.size() <= 0 ) )
463 {
464 LOG.error( "The entry on {} is not an AdministrativePoint", apDn );
465 throw new LdapNoSuchAttributeException( I18n.err( I18n.ERR_306, apDn ) );
466 }
467 }
468
469
470
471
472
473 private void setSubtreeSpecification( Subentry subentry, Entry entry ) throws LdapException
474 {
475 String subtree = entry.get( directoryService.getAtProvider().getSubtreeSpecification() ).getString();
476 SubtreeSpecification ss;
477
478 try
479 {
480 ss = ssParser.parse( subtree );
481 }
482 catch ( Exception e )
483 {
484 String msg = I18n.err( I18n.ERR_307, entry.getDn() );
485 LOG.warn( msg );
486 throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, msg );
487 }
488
489 subentry.setSubtreeSpecification( ss );
490 }
491
492
493
494
495
496
497
498
499
500
501
502 private boolean hasAdministrativeDescendant( OperationContext opContext, Dn name ) throws LdapException
503 {
504 ExprNode filter = new PresenceNode( directoryService.getAtProvider().getAdministrativeRole() );
505 SearchControls controls = new SearchControls();
506 controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
507
508 SearchOperationContextxt/SearchOperationContext.html#SearchOperationContext">SearchOperationContext searchOperationContext = new SearchOperationContext( opContext.getSession(), name,
509 filter, controls );
510 searchOperationContext.setAliasDerefMode( AliasDerefMode.NEVER_DEREF_ALIASES );
511 searchOperationContext.setTransaction( opContext.getTransaction() );
512 searchOperationContext.setPartition( opContext.getPartition() );
513
514 EntryFilteringCursor aps = nexus.search( searchOperationContext );
515
516 try
517 {
518 if ( aps.next() )
519 {
520 return true;
521 }
522 }
523 catch ( Exception e )
524 {
525 throw new LdapOperationException( e.getMessage(), e );
526 }
527 finally
528 {
529 try
530 {
531 aps.close();
532 }
533 catch ( Exception e )
534 {
535 LOG.error( I18n.err( I18n.ERR_168 ), e );
536 }
537 }
538
539 return false;
540 }
541
542
543 private List<Modification> getModsOnEntryRdnChange( Dn oldName, Dn newName, Entry entry ) throws LdapException
544 {
545 List<Modification> modifications = new ArrayList<>();
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560 SubentryCache subentryCache = directoryService.getSubentryCache();
561 SubtreeEvaluator evaluator = directoryService.getEvaluator();
562
563 for ( Dn subentryDn : subentryCache )
564 {
565 Dn apDn = subentryDn.getParent();
566 SubtreeSpecification ss = subentryCache.getSubentry( subentryDn ).getSubtreeSpecification();
567 boolean isOldNameSelected = evaluator.evaluate( ss, apDn, oldName, entry );
568 boolean isNewNameSelected = evaluator.evaluate( ss, apDn, newName, entry );
569
570 if ( isOldNameSelected == isNewNameSelected )
571 {
572 continue;
573 }
574
575
576 if ( isOldNameSelected && !isNewNameSelected )
577 {
578 for ( AttributeType operationalAttribute : directoryService.getAtProvider()
579 .getSubentryOperationalAttributes() )
580 {
581 ModificationOperation op = ModificationOperation.REPLACE_ATTRIBUTE;
582 Attribute opAttr = entry.get( operationalAttribute );
583
584 if ( opAttr != null )
585 {
586 opAttr = opAttr.clone();
587 opAttr.remove( subentryDn.getName() );
588
589 if ( opAttr.size() < 1 )
590 {
591 op = ModificationOperation.REMOVE_ATTRIBUTE;
592 }
593
594 modifications.add( new DefaultModification( op, opAttr ) );
595 }
596 }
597 }
598
599 else if ( isNewNameSelected && !isOldNameSelected )
600 {
601 for ( AttributeType operationalAttribute : directoryService.getAtProvider()
602 .getSubentryOperationalAttributes() )
603 {
604 ModificationOperation op = ModificationOperation.ADD_ATTRIBUTE;
605 Attribute opAttr = new DefaultAttribute( operationalAttribute );
606 opAttr.add( subentryDn.getName() );
607 modifications.add( new DefaultModification( op, opAttr ) );
608 }
609 }
610 }
611
612 return modifications;
613 }
614
615
616
617
618
619
620 private Set<AdministrativeRole> getSubentryTypes( Entry entry, List<Modification> mods ) throws LdapException
621 {
622 Attribute ocFinalState = entry.get( directoryService.getAtProvider().getObjectClass() ).clone();
623
624 for ( Modification mod : mods )
625 {
626 if ( mod.getAttribute().getId().equalsIgnoreCase( SchemaConstants.OBJECT_CLASS_AT )
627 || mod.getAttribute().getId().equalsIgnoreCase( SchemaConstants.OBJECT_CLASS_AT_OID ) )
628 {
629 switch ( mod.getOperation() )
630 {
631 case ADD_ATTRIBUTE:
632 for ( Value value : mod.getAttribute() )
633 {
634 ocFinalState.add( value.getString() );
635 }
636
637 break;
638
639 case REMOVE_ATTRIBUTE:
640 for ( Value value : mod.getAttribute() )
641 {
642 ocFinalState.remove( value.getString() );
643 }
644
645 break;
646
647 case REPLACE_ATTRIBUTE:
648 ocFinalState = mod.getAttribute();
649 break;
650
651 default:
652 throw new IllegalArgumentException( "Unexpected modify operatoin " + mod.getOperation() );
653 }
654 }
655 }
656
657 Entry attrs = new DefaultEntry( schemaManager, Dn.ROOT_DSE );
658 attrs.put( ocFinalState );
659 return getSubentryAdminRoles( attrs );
660 }
661
662
663
664
665
666
667 private void getOperationalModForReplace( boolean hasRole, AttributeType attributeType, Entry entry, Dn oldDn,
668 Dn newDn, List<Modification> modifications ) throws LdapInvalidAttributeValueException
669 {
670 String oldDnStr = oldDn.getName();
671 String newDnStr = newDn.getName();
672
673 if ( hasRole )
674 {
675 Attribute operational = entry.get( attributeType ).clone();
676
677 if ( operational == null )
678 {
679 operational = new DefaultAttribute( attributeType, newDnStr );
680 }
681 else
682 {
683 operational.remove( oldDnStr );
684 operational.add( newDnStr );
685 }
686
687 modifications.add( new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, operational ) );
688 }
689 }
690
691
692
693
694
695
696 private List<Modification> getOperationalModsForReplace( Dn oldDn, Dn newDn, Subentry subentry, Entry entry )
697 throws LdapException
698 {
699 List<Modification> modifications = new ArrayList<>();
700
701 getOperationalModForReplace( subentry.isAccessControlAdminRole(), directoryService.getAtProvider()
702 .getAccessControlSubentries(), entry, oldDn, newDn, modifications );
703 getOperationalModForReplace( subentry.isSchemaAdminRole(), directoryService.getAtProvider()
704 .getSubschemaSubentry(), entry, oldDn, newDn, modifications );
705 getOperationalModForReplace( subentry.isCollectiveAdminRole(), directoryService.getAtProvider()
706 .getCollectiveAttributeSubentries(), entry, oldDn, newDn, modifications );
707 getOperationalModForReplace( subentry.isTriggersAdminRole(), directoryService.getAtProvider()
708 .getTriggerExecutionSubentries(), entry, oldDn, newDn, modifications );
709
710 return modifications;
711 }
712
713
714
715
716
717
718 private List<Attribute> getSubentryOperationalAttributes( Dn dn, Subentry subentry ) throws LdapException
719 {
720 List<Attribute> attributes = new ArrayList<>();
721
722 if ( subentry.isAccessControlAdminRole() )
723 {
724 Attribute accessControlSubentries = new DefaultAttribute( directoryService.getAtProvider()
725 .getAccessControlSubentries(), dn.getName() );
726 attributes.add( accessControlSubentries );
727 }
728
729 if ( subentry.isSchemaAdminRole() )
730 {
731 Attribute subschemaSubentry = new DefaultAttribute(
732 directoryService.getAtProvider().getSubschemaSubentry(), dn.getName() );
733 attributes.add( subschemaSubentry );
734 }
735
736 if ( subentry.isCollectiveAdminRole() )
737 {
738 Attribute collectiveAttributeSubentries = new DefaultAttribute( directoryService.getAtProvider()
739 .getCollectiveAttributeSubentries(), dn.getName() );
740 attributes.add( collectiveAttributeSubentries );
741 }
742
743 if ( subentry.isTriggersAdminRole() )
744 {
745 Attribute tiggerExecutionSubentries = new DefaultAttribute( directoryService.getAtProvider()
746 .getTriggerExecutionSubentries(), dn.getName() );
747 attributes.add( tiggerExecutionSubentries );
748 }
749
750 return attributes;
751 }
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767 private List<Modification> getOperationalModsForRemove( Dn subentryDn, Entry candidate ) throws LdapException
768 {
769 List<Modification> modifications = new ArrayList<>();
770 String dn = subentryDn.getName();
771
772 for ( AttributeType operationalAttribute : directoryService.getAtProvider().getSubentryOperationalAttributes() )
773 {
774 Attribute opAttr = candidate.get( operationalAttribute );
775
776 if ( ( opAttr != null ) && opAttr.contains( dn ) )
777 {
778 Attribute attr = new DefaultAttribute( operationalAttribute, dn );
779 modifications.add( new DefaultModification( ModificationOperation.REMOVE_ATTRIBUTE, attr ) );
780 }
781 }
782
783 return modifications;
784 }
785
786
787
788
789
790
791
792
793
794
795
796 private List<Modification> getOperationalModsForAdd( Entry entry, List<Attribute> operationalAttributes )
797 throws LdapException
798 {
799 List<Modification> modifications = new ArrayList<>();
800
801 for ( Attribute operationalAttribute : operationalAttributes )
802 {
803 Attribute opAttrInEntry = entry.get( operationalAttribute.getAttributeType() );
804
805 if ( ( opAttrInEntry != null ) && ( opAttrInEntry.size() > 0 ) )
806 {
807 Attribute newOperationalAttribute = operationalAttribute.clone();
808
809 for ( Value value : opAttrInEntry )
810 {
811 newOperationalAttribute.add( value );
812 }
813
814 modifications.add( new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE,
815 newOperationalAttribute ) );
816 }
817 else
818 {
819 modifications
820 .add( new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, operationalAttribute ) );
821 }
822 }
823
824 return modifications;
825 }
826
827
828
829
830
831 private List<Modification> getModsOnEntryModification( Dn name, Entry oldEntry, Entry newEntry )
832 throws LdapException
833 {
834 List<Modification> modList = new ArrayList<>();
835
836 for ( Dn subentryDn : directoryService.getSubentryCache() )
837 {
838 Dn apDn = subentryDn.getParent();
839 SubtreeSpecification ss = directoryService.getSubentryCache().getSubentry( subentryDn )
840 .getSubtreeSpecification();
841 boolean isOldEntrySelected = directoryService.getEvaluator().evaluate( ss, apDn, name, oldEntry );
842 boolean isNewEntrySelected = directoryService.getEvaluator().evaluate( ss, apDn, name, newEntry );
843
844 if ( isOldEntrySelected == isNewEntrySelected )
845 {
846 continue;
847 }
848
849
850 if ( isOldEntrySelected && !isNewEntrySelected )
851 {
852 for ( AttributeType operationalAttribute : directoryService.getAtProvider()
853 .getSubentryOperationalAttributes() )
854 {
855 ModificationOperation op = ModificationOperation.REPLACE_ATTRIBUTE;
856 Attribute opAttr = oldEntry.get( operationalAttribute );
857
858 if ( opAttr != null )
859 {
860 opAttr = opAttr.clone();
861 opAttr.remove( subentryDn.getName() );
862
863 if ( opAttr.size() < 1 )
864 {
865 op = ModificationOperation.REMOVE_ATTRIBUTE;
866 }
867
868 modList.add( new DefaultModification( op, opAttr ) );
869 }
870 }
871 }
872
873 else if ( isNewEntrySelected && !isOldEntrySelected )
874 {
875 for ( AttributeType operationalAttribute : directoryService.getAtProvider()
876 .getSubentryOperationalAttributes() )
877 {
878 ModificationOperation op = ModificationOperation.ADD_ATTRIBUTE;
879 Attribute opAttr = new DefaultAttribute( operationalAttribute );
880 opAttr.add( subentryDn.getName() );
881 modList.add( new DefaultModification( op, opAttr ) );
882 }
883 }
884 }
885
886 return modList;
887 }
888
889
890
891
892
893 private void setOperationalAttribute( Entry entry, Dn subentryDn, AttributeType opAttr ) throws LdapException
894 {
895 Attribute operational = entry.get( opAttr );
896
897 if ( operational == null )
898 {
899 operational = new DefaultAttribute( opAttr );
900 entry.put( operational );
901 }
902
903 operational.add( subentryDn.getName() );
904 }
905
906
907
908
909
910
911
912
913 @Override
914 public void add( AddOperationContext addContext ) throws LdapException
915 {
916 Dn dn = addContext.getDn();
917 Entry entry = addContext.getEntry();
918
919
920 if ( entry.contains( directoryService.getAtProvider().getObjectClass(), SchemaConstants.SUBENTRY_OC ) )
921 {
922
923
924
925 if ( dn.isRootDse() || isNamingContext( dn ) )
926 {
927
928 throw new LdapOtherException( "Cannot find an AdministrativePoint for " + dn );
929 }
930
931
932
933 Dn apDn = dn.getParent();
934 checkAdministrativeRole( addContext, apDn );
935
936
937
938
939
940
941
942
943
944 Subentry subentry = new Subentry();
945 subentry.setAdministrativeRoles( getSubentryAdminRoles( entry ) );
946 List<Attribute> operationalAttributes = getSubentryOperationalAttributes( dn, subentry );
947
948
949
950
951
952
953
954
955 setSubtreeSpecification( subentry, entry );
956 directoryService.getSubentryCache().addSubentry( dn, subentry );
957
958
959 next( addContext );
960
961
962
963
964
965
966
967
968
969 Dn baseDn = apDn;
970 baseDn = baseDn.add( subentry.getSubtreeSpecification().getBase() );
971
972 updateEntries( addContext, OperationEnum.ADD, apDn, subentry.getSubtreeSpecification(),
973 baseDn, operationalAttributes );
974
975
976
977 addContext.setEntry( entry );
978 }
979 else
980 {
981
982
983
984
985
986
987 for ( Dn subentryDn : directoryService.getSubentryCache() )
988 {
989 Dn apDn = subentryDn.getParent();
990
991
992 if ( dn.isDescendantOf( apDn ) )
993 {
994 Subentry subentry = directoryService.getSubentryCache().getSubentry( subentryDn );
995 SubtreeSpecification ss = subentry.getSubtreeSpecification();
996
997
998
999 if ( directoryService.getEvaluator().evaluate( ss, apDn, dn, entry ) )
1000 {
1001
1002 if ( subentry.isAccessControlAdminRole() )
1003 {
1004 setOperationalAttribute( entry, subentryDn, directoryService.getAtProvider()
1005 .getAccessControlSubentries() );
1006 }
1007
1008 if ( subentry.isSchemaAdminRole() )
1009 {
1010 setOperationalAttribute( entry, subentryDn, directoryService.getAtProvider()
1011 .getSubschemaSubentry() );
1012 }
1013
1014 if ( subentry.isCollectiveAdminRole() )
1015 {
1016 setOperationalAttribute( entry, subentryDn, directoryService.getAtProvider()
1017 .getCollectiveAttributeSubentries() );
1018 }
1019
1020 if ( subentry.isTriggersAdminRole() )
1021 {
1022 setOperationalAttribute( entry, subentryDn, directoryService.getAtProvider()
1023 .getTriggerExecutionSubentries() );
1024 }
1025 }
1026 }
1027 }
1028
1029
1030
1031 addContext.setEntry( entry );
1032
1033
1034 next( addContext );
1035 }
1036 }
1037
1038
1039
1040
1041
1042 @Override
1043 public void delete( DeleteOperationContext deleteContext ) throws LdapException
1044 {
1045 Dn dn = deleteContext.getDn();
1046 Entry entry = deleteContext.getEntry();
1047
1048
1049
1050 if ( entry.contains( directoryService.getAtProvider().getObjectClass(), SchemaConstants.SUBENTRY_OC ) )
1051 {
1052 Subentry removedSubentry = directoryService.getSubentryCache().getSubentry( dn );
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062 Dn apDn = dn.getParent();
1063 Dn baseDn = apDn;
1064 baseDn = baseDn.add( removedSubentry.getSubtreeSpecification().getBase() );
1065
1066
1067 updateEntries( deleteContext, OperationEnum.REMOVE, apDn,
1068 removedSubentry.getSubtreeSpecification(), baseDn, null );
1069
1070
1071 directoryService.getSubentryCache().removeSubentry( dn );
1072
1073
1074 next( deleteContext );
1075 }
1076 else
1077 {
1078
1079 next( deleteContext );
1080 }
1081 }
1082
1083
1084
1085
1086
1087 @Override
1088 public void modify( ModifyOperationContext modifyContext ) throws LdapException
1089 {
1090 Dn dn = modifyContext.getDn();
1091 List<Modification> modifications = modifyContext.getModItems();
1092
1093 Entry entry = modifyContext.getEntry();
1094
1095
1096
1097
1098
1099
1100
1101
1102 boolean isSubtreeSpecificationModification = false;
1103 Modification subtreeMod = null;
1104
1105
1106 for ( Modification mod : modifications )
1107 {
1108 if ( mod.getAttribute().getAttributeType()
1109 .equals( directoryService.getAtProvider().getSubtreeSpecification() ) )
1110 {
1111 isSubtreeSpecificationModification = true;
1112 subtreeMod = mod;
1113 break;
1114 }
1115 }
1116
1117 boolean containsSubentryOC = entry.contains( directoryService.getAtProvider().getObjectClass(),
1118 SchemaConstants.SUBENTRY_OC );
1119
1120
1121 if ( containsSubentryOC && isSubtreeSpecificationModification )
1122 {
1123 Subentry subentry = directoryService.getSubentryCache().removeSubentry( dn );
1124 SubtreeSpecification ssOld = subentry.getSubtreeSpecification();
1125 SubtreeSpecification ssNew;
1126
1127 try
1128 {
1129 ssNew = ssParser.parse( subtreeMod.getAttribute().getString() );
1130 }
1131 catch ( Exception e )
1132 {
1133 String msg = I18n.err( I18n.ERR_71 );
1134 LOG.error( msg, e );
1135 throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, msg );
1136 }
1137
1138 subentry.setSubtreeSpecification( ssNew );
1139 subentry.setAdministrativeRoles( getSubentryTypes( entry, modifications ) );
1140 directoryService.getSubentryCache().addSubentry( dn, subentry );
1141
1142 next( modifyContext );
1143
1144
1145 Dn apName = dn.getParent();
1146 Dn oldBaseDn = apName;
1147 oldBaseDn = oldBaseDn.add( ssOld.getBase() );
1148
1149 ExprNode filter = new PresenceNode( directoryService.getAtProvider().getObjectClass() );
1150 SearchControls controls = new SearchControls();
1151 controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
1152 controls.setReturningAttributes( new String[]
1153 { SchemaConstants.ALL_OPERATIONAL_ATTRIBUTES, SchemaConstants.ALL_USER_ATTRIBUTES } );
1154
1155 SearchOperationContextxt/SearchOperationContext.html#SearchOperationContext">SearchOperationContext searchOperationContext = new SearchOperationContext( modifyContext.getSession(),
1156 oldBaseDn, filter, controls );
1157 searchOperationContext.setAliasDerefMode( AliasDerefMode.NEVER_DEREF_ALIASES );
1158 searchOperationContext.setPartition( modifyContext.getPartition() );
1159 searchOperationContext.setTransaction( modifyContext.getTransaction() );
1160
1161 EntryFilteringCursor subentries = nexus.search( searchOperationContext );
1162
1163 try
1164 {
1165 while ( subentries.next() )
1166 {
1167 Entry candidate = subentries.get();
1168 Dn candidateDn = candidate.getDn();
1169
1170 if ( directoryService.getEvaluator().evaluate( ssOld, apName, candidateDn, candidate ) )
1171 {
1172 ModifyOperationContext/context/ModifyOperationContext.html#ModifyOperationContext">ModifyOperationContext newModifyContext = new ModifyOperationContext( modifyContext.getSession(), candidateDn,
1173 getOperationalModsForRemove( dn, candidate ) );
1174 newModifyContext.setPartition( modifyContext.getPartition() );
1175 newModifyContext.setTransaction( modifyContext.getTransaction() );
1176
1177 nexus.modify( newModifyContext );
1178 }
1179 }
1180
1181 subentries.close();
1182 }
1183 catch ( Exception e )
1184 {
1185 throw new LdapOperationErrorException( e.getMessage(), e );
1186 }
1187 finally
1188 {
1189 try
1190 {
1191 subentries.close();
1192 }
1193 catch ( Exception e )
1194 {
1195 LOG.error( I18n.err( I18n.ERR_168 ), e );
1196 }
1197 }
1198
1199
1200 subentry = directoryService.getSubentryCache().getSubentry( dn );
1201 List<Attribute> operationalAttributes = getSubentryOperationalAttributes( dn, subentry );
1202 Dn newBaseDn = apName;
1203 newBaseDn = newBaseDn.add( ssNew.getBase() );
1204
1205 searchOperationContext = new SearchOperationContext( modifyContext.getSession(), newBaseDn, filter,
1206 controls );
1207 searchOperationContext.setAliasDerefMode( AliasDerefMode.NEVER_DEREF_ALIASES );
1208 searchOperationContext.setPartition( modifyContext.getPartition() );
1209 searchOperationContext.setTransaction( modifyContext.getTransaction() );
1210
1211 subentries = nexus.search( searchOperationContext );
1212
1213 try
1214 {
1215 while ( subentries.next() )
1216 {
1217 Entry candidate = subentries.get();
1218 Dn candidateDn = candidate.getDn();
1219
1220 if ( directoryService.getEvaluator().evaluate( ssNew, apName, candidateDn, candidate ) )
1221 {
1222 nexus.modify( new ModifyOperationContext( modifyContext.getSession(), candidateDn,
1223 getOperationalModsForAdd( candidate, operationalAttributes ) ) );
1224 }
1225 }
1226 subentries.close();
1227 }
1228 catch ( Exception e )
1229 {
1230 throw new LdapOperationErrorException( e.getMessage(), e );
1231 }
1232 finally
1233 {
1234 try
1235 {
1236 subentries.close();
1237 }
1238 catch ( Exception e )
1239 {
1240 LOG.error( I18n.err( I18n.ERR_168 ), e );
1241 }
1242 }
1243 }
1244 else
1245 {
1246 next( modifyContext );
1247
1248 if ( !containsSubentryOC )
1249 {
1250 Entry newEntry = modifyContext.getAlteredEntry();
1251
1252 List<Modification> subentriesOpAttrMods = getModsOnEntryModification( dn, entry, newEntry );
1253
1254 if ( !subentriesOpAttrMods.isEmpty() )
1255 {
1256 ModifyOperationContext/context/ModifyOperationContext.html#ModifyOperationContext">ModifyOperationContext newModifyContext = new ModifyOperationContext( modifyContext.getSession(), dn, subentriesOpAttrMods );
1257 newModifyContext.setPartition( modifyContext.getPartition() );
1258 newModifyContext.setTransaction( modifyContext.getTransaction() );
1259 nexus.modify( newModifyContext );
1260 }
1261 }
1262 }
1263 }
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293 @Override
1294 public void move( MoveOperationContext moveContext ) throws LdapException
1295 {
1296 Dn oldDn = moveContext.getDn();
1297 Dn newSuperiorDn = moveContext.getNewSuperior();
1298
1299 Entry entry = moveContext.getOriginalEntry();
1300
1301 if ( entry.contains( directoryService.getAtProvider().getObjectClass(), SchemaConstants.SUBENTRY_OC ) )
1302 {
1303
1304
1305
1306
1307
1308
1309
1310 checkAdministrativeRole( moveContext, newSuperiorDn );
1311
1312 Subentry subentry = directoryService.getSubentryCache().removeSubentry( oldDn );
1313 SubtreeSpecification ss = subentry.getSubtreeSpecification();
1314 Dn apName = oldDn.getParent();
1315 Dn baseDn = apName;
1316 baseDn = baseDn.add( ss.getBase() );
1317 Dn newName = newSuperiorDn;
1318 newName = newName.add( oldDn.getRdn() );
1319
1320 if ( !newName.isSchemaAware() )
1321 {
1322 newName = new Dn( schemaManager, newName );
1323 }
1324
1325 directoryService.getSubentryCache().addSubentry( newName, subentry );
1326
1327 next( moveContext );
1328
1329 subentry = directoryService.getSubentryCache().getSubentry( newName );
1330
1331 ExprNode filter = new PresenceNode( directoryService.getAtProvider().getObjectClass() );
1332 SearchControls controls = new SearchControls();
1333 controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
1334 controls.setReturningAttributes( new String[]
1335 { SchemaConstants.ALL_OPERATIONAL_ATTRIBUTES, SchemaConstants.ALL_USER_ATTRIBUTES } );
1336
1337 SearchOperationContextxt/SearchOperationContext.html#SearchOperationContext">SearchOperationContext searchOperationContext = new SearchOperationContext( moveContext.getSession(),
1338 baseDn,
1339 filter, controls );
1340 searchOperationContext.setAliasDerefMode( AliasDerefMode.NEVER_DEREF_ALIASES );
1341 searchOperationContext.setPartition( moveContext.getPartition() );
1342 searchOperationContext.setTransaction( moveContext.getTransaction() );
1343
1344 EntryFilteringCursor subentries = nexus.search( searchOperationContext );
1345
1346 try
1347 {
1348
1349 while ( subentries.next() )
1350 {
1351 Entry candidate = subentries.get();
1352 Dn dn = candidate.getDn();
1353
1354 if ( !dn.isSchemaAware() )
1355 {
1356 dn = new Dn( schemaManager, dn );
1357 }
1358
1359 if ( directoryService.getEvaluator().evaluate( ss, apName, dn, candidate ) )
1360 {
1361 ModifyOperationContext/context/ModifyOperationContext.html#ModifyOperationContext">ModifyOperationContext newModifyContext = new ModifyOperationContext( moveContext.getSession(), dn,
1362 getOperationalModsForReplace( oldDn, newName, subentry, candidate ) );
1363 newModifyContext.setPartition( moveContext.getPartition() );
1364 newModifyContext.setTransaction( moveContext.getTransaction() );
1365 nexus.modify( newModifyContext );
1366 }
1367 }
1368 }
1369 catch ( Exception e )
1370 {
1371 throw new LdapOperationException( e.getMessage(), e );
1372 }
1373 finally
1374 {
1375 try
1376 {
1377 subentries.close();
1378 }
1379 catch ( Exception e )
1380 {
1381 LOG.error( I18n.err( I18n.ERR_168 ), e );
1382 }
1383 }
1384 }
1385 else
1386 {
1387
1388
1389
1390
1391
1392
1393 if ( hasAdministrativeDescendant( moveContext, oldDn ) )
1394 {
1395 String msg = I18n.err( I18n.ERR_308 );
1396 LOG.warn( msg );
1397 throw new LdapSchemaViolationException( ResultCodeEnum.NOT_ALLOWED_ON_RDN, msg );
1398 }
1399
1400
1401 next( moveContext );
1402
1403
1404
1405 Dn newDn = moveContext.getNewDn();
1406 List<Modification> mods = getModsOnEntryRdnChange( oldDn, newDn, entry );
1407
1408
1409 if ( !mods.isEmpty() )
1410 {
1411 ModifyOperationContext/context/ModifyOperationContext.html#ModifyOperationContext">ModifyOperationContext newModifyContext = new ModifyOperationContext( moveContext.getSession(), newDn, mods );
1412 newModifyContext.setPartition( moveContext.getPartition() );
1413 newModifyContext.setTransaction( moveContext.getTransaction() );
1414 nexus.modify( newModifyContext );
1415 }
1416 }
1417 }
1418
1419
1420
1421
1422
1423 @Override
1424 public void moveAndRename( MoveAndRenameOperationContext moveAndRenameContext ) throws LdapException
1425 {
1426 Dn oldDn = moveAndRenameContext.getDn();
1427 Dn newSuperiorDn = moveAndRenameContext.getNewSuperiorDn();
1428
1429 Entry entry = moveAndRenameContext.getOriginalEntry();
1430
1431 if ( entry.contains( directoryService.getAtProvider().getObjectClass(), SchemaConstants.SUBENTRY_OC ) )
1432 {
1433 Subentry subentry = directoryService.getSubentryCache().removeSubentry( oldDn );
1434 SubtreeSpecification ss = subentry.getSubtreeSpecification();
1435 Dn apName = oldDn.getParent();
1436 Dn baseDn = apName;
1437 baseDn = baseDn.add( ss.getBase() );
1438 Dn newName = newSuperiorDn.getParent();
1439
1440 newName = newName.add( moveAndRenameContext.getNewRdn() );
1441
1442 if ( !newName.isSchemaAware() )
1443 {
1444 newName = new Dn( schemaManager, newName );
1445 }
1446
1447 directoryService.getSubentryCache().addSubentry( newName, subentry );
1448
1449 next( moveAndRenameContext );
1450
1451 subentry = directoryService.getSubentryCache().getSubentry( newName );
1452
1453 ExprNode filter = new PresenceNode( directoryService.getAtProvider().getObjectClass() );
1454 SearchControls controls = new SearchControls();
1455 controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
1456 controls.setReturningAttributes( new String[]
1457 { SchemaConstants.ALL_OPERATIONAL_ATTRIBUTES, SchemaConstants.ALL_USER_ATTRIBUTES } );
1458
1459 SearchOperationContextxt/SearchOperationContext.html#SearchOperationContext">SearchOperationContext searchOperationContext = new SearchOperationContext(
1460 moveAndRenameContext.getSession(), baseDn,
1461 filter, controls );
1462 searchOperationContext.setAliasDerefMode( AliasDerefMode.NEVER_DEREF_ALIASES );
1463 searchOperationContext.setPartition( moveAndRenameContext.getPartition() );
1464 searchOperationContext.setTransaction( moveAndRenameContext.getTransaction() );
1465
1466 EntryFilteringCursor subentries = nexus.search( searchOperationContext );
1467
1468 try
1469 {
1470 while ( subentries.next() )
1471 {
1472 Entry candidate = subentries.get();
1473 Dn dn = candidate.getDn();
1474
1475 if ( !dn.isSchemaAware() )
1476 {
1477 dn = new Dn( schemaManager, dn );
1478 }
1479
1480 if ( directoryService.getEvaluator().evaluate( ss, apName, dn, candidate ) )
1481 {
1482 ModifyOperationContext/context/ModifyOperationContext.html#ModifyOperationContext">ModifyOperationContext newModifyContext = new ModifyOperationContext( moveAndRenameContext.getSession(), dn,
1483 getOperationalModsForReplace( oldDn, newName, subentry, candidate ) );
1484 newModifyContext.setPartition( moveAndRenameContext.getPartition() );
1485 newModifyContext.setTransaction( moveAndRenameContext.getTransaction() );
1486 nexus.modify( newModifyContext );
1487 }
1488 }
1489 }
1490 catch ( Exception e )
1491 {
1492 throw new LdapOperationException( e.getMessage(), e );
1493 }
1494 finally
1495 {
1496 try
1497 {
1498 subentries.close();
1499 }
1500 catch ( Exception e )
1501 {
1502 LOG.error( I18n.err( I18n.ERR_168 ), e );
1503 }
1504 }
1505 }
1506 else
1507 {
1508 if ( hasAdministrativeDescendant( moveAndRenameContext, oldDn ) )
1509 {
1510 String msg = I18n.err( I18n.ERR_308 );
1511 LOG.warn( msg );
1512 throw new LdapSchemaViolationException( ResultCodeEnum.NOT_ALLOWED_ON_RDN, msg );
1513 }
1514
1515 next( moveAndRenameContext );
1516
1517
1518
1519 Dn newDn = moveAndRenameContext.getNewDn();
1520 List<Modification> mods = getModsOnEntryRdnChange( oldDn, newDn, entry );
1521
1522 if ( !mods.isEmpty() )
1523 {
1524 nexus.modify( new ModifyOperationContext( moveAndRenameContext.getSession(), newDn, mods ) );
1525 }
1526 }
1527 }
1528
1529
1530
1531
1532
1533 @Override
1534 public void rename( RenameOperationContext renameContext ) throws LdapException
1535 {
1536 Dn oldDn = renameContext.getDn();
1537
1538 Entry entry = ( ( ClonedServerEntry ) renameContext.getEntry() ).getClonedEntry();
1539
1540 if ( entry.contains( directoryService.getAtProvider().getObjectClass(), SchemaConstants.SUBENTRY_OC ) )
1541 {
1542
1543 Subentry subentry = directoryService.getSubentryCache().removeSubentry( oldDn );
1544 SubtreeSpecification ss = subentry.getSubtreeSpecification();
1545 Dn apName = oldDn.getParent();
1546 Dn baseDn = apName;
1547 baseDn = baseDn.add( ss.getBase() );
1548 Dn newName = oldDn.getParent();
1549
1550 newName = newName.add( renameContext.getNewRdn() );
1551
1552 if ( !newName.isSchemaAware() )
1553 {
1554 newName = new Dn( schemaManager, newName );
1555 }
1556
1557 directoryService.getSubentryCache().addSubentry( newName, subentry );
1558 next( renameContext );
1559
1560 subentry = directoryService.getSubentryCache().getSubentry( newName );
1561 ExprNode filter = new PresenceNode( directoryService.getAtProvider().getObjectClass() );
1562 SearchControls controls = new SearchControls();
1563 controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
1564 controls.setReturningAttributes( new String[]
1565 { SchemaConstants.ALL_OPERATIONAL_ATTRIBUTES, SchemaConstants.ALL_USER_ATTRIBUTES } );
1566
1567 SearchOperationContextxt/SearchOperationContext.html#SearchOperationContext">SearchOperationContext searchOperationContext = new SearchOperationContext( renameContext.getSession(),
1568 baseDn,
1569 filter, controls );
1570 searchOperationContext.setAliasDerefMode( AliasDerefMode.NEVER_DEREF_ALIASES );
1571 searchOperationContext.setPartition( renameContext.getPartition() );
1572 searchOperationContext.setTransaction( renameContext.getTransaction() );
1573
1574 EntryFilteringCursor subentries = nexus.search( searchOperationContext );
1575
1576 try
1577 {
1578 while ( subentries.next() )
1579 {
1580 Entry candidate = subentries.get();
1581 Dn dn = candidate.getDn();
1582
1583 if ( !dn.isSchemaAware() )
1584 {
1585 dn = new Dn( schemaManager, dn );
1586 }
1587
1588 if ( directoryService.getEvaluator().evaluate( ss, apName, dn, candidate ) )
1589 {
1590 nexus.modify( new ModifyOperationContext( renameContext.getSession(), dn,
1591 getOperationalModsForReplace(
1592 oldDn, newName, subentry, candidate ) ) );
1593 }
1594 }
1595 }
1596 catch ( Exception e )
1597 {
1598 throw new LdapOperationException( e.getMessage(), e );
1599 }
1600 finally
1601 {
1602 try
1603 {
1604 subentries.close();
1605 }
1606 catch ( Exception e )
1607 {
1608 LOG.error( I18n.err( I18n.ERR_168 ), e );
1609 }
1610 }
1611 }
1612 else
1613 {
1614 if ( hasAdministrativeDescendant( renameContext, oldDn ) )
1615 {
1616 String msg = I18n.err( I18n.ERR_308 );
1617 LOG.warn( msg );
1618 throw new LdapSchemaViolationException( ResultCodeEnum.NOT_ALLOWED_ON_RDN, msg );
1619 }
1620
1621 next( renameContext );
1622
1623
1624
1625 Dn newName = renameContext.getNewDn();
1626
1627 List<Modification> mods = getModsOnEntryRdnChange( oldDn, newName, entry );
1628
1629 if ( !mods.isEmpty() )
1630 {
1631 ModifyOperationContext/context/ModifyOperationContext.html#ModifyOperationContext">ModifyOperationContext newModifyContext = new ModifyOperationContext( renameContext.getSession(), newName, mods );
1632 newModifyContext.setPartition( renameContext.getPartition() );
1633 newModifyContext.setTransaction( renameContext.getTransaction() );
1634 nexus.modify( newModifyContext );
1635 }
1636 }
1637 }
1638
1639
1640
1641
1642
1643 @Override
1644 public EntryFilteringCursor search( SearchOperationContext searchContext ) throws LdapException
1645 {
1646 EntryFilteringCursor cursor = next( searchContext );
1647
1648
1649 if ( searchContext.getScope() == SearchScope.OBJECT )
1650 {
1651 return cursor;
1652 }
1653
1654
1655 if ( searchContext.isSyncreplSearch() )
1656 {
1657 return cursor;
1658 }
1659
1660
1661 if ( !isSubentryVisible( searchContext ) )
1662 {
1663 cursor.addEntryFilter( new HideSubentriesFilter() );
1664 }
1665 else
1666 {
1667 cursor.addEntryFilter( new HideEntriesFilter() );
1668 }
1669
1670 return cursor;
1671 }
1672 }