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 org.apache.directory.server.core.interceptor.BaseInterceptor;
24
25 import org.apache.directory.server.constants.ApacheSchemaConstants;
26 import org.apache.directory.server.constants.ServerDNConstants;
27 import org.apache.directory.server.core.CoreSession;
28 import org.apache.directory.server.core.DefaultCoreSession;
29 import org.apache.directory.server.core.DirectoryService;
30 import org.apache.directory.server.core.authn.LdapPrincipal;
31 import org.apache.directory.server.core.entry.ClonedServerEntry;
32 import org.apache.directory.server.core.entry.DefaultServerAttribute;
33 import org.apache.directory.server.core.entry.DefaultServerEntry;
34 import org.apache.directory.server.core.entry.ServerAttribute;
35 import org.apache.directory.server.core.entry.ServerEntry;
36 import org.apache.directory.server.core.entry.ServerModification;
37 import org.apache.directory.server.core.filtering.EntryFilter;
38 import org.apache.directory.server.core.filtering.EntryFilteringCursor;
39 import org.apache.directory.server.core.interceptor.NextInterceptor;
40 import org.apache.directory.server.core.interceptor.context.AddOperationContext;
41 import org.apache.directory.server.core.interceptor.context.DeleteOperationContext;
42 import org.apache.directory.server.core.interceptor.context.ListOperationContext;
43 import org.apache.directory.server.core.interceptor.context.ModifyOperationContext;
44 import org.apache.directory.server.core.interceptor.context.MoveAndRenameOperationContext;
45 import org.apache.directory.server.core.interceptor.context.MoveOperationContext;
46 import org.apache.directory.server.core.interceptor.context.OperationContext;
47 import org.apache.directory.server.core.interceptor.context.RenameOperationContext;
48 import org.apache.directory.server.core.interceptor.context.SearchOperationContext;
49 import org.apache.directory.server.core.interceptor.context.SearchingOperationContext;
50 import org.apache.directory.server.core.partition.ByPassConstants;
51 import org.apache.directory.server.core.partition.PartitionNexus;
52 import org.apache.directory.server.schema.registries.AttributeTypeRegistry;
53 import org.apache.directory.server.schema.registries.OidRegistry;
54 import org.apache.directory.server.schema.registries.Registries;
55 import org.apache.directory.shared.ldap.constants.AuthenticationLevel;
56 import org.apache.directory.shared.ldap.constants.SchemaConstants;
57 import org.apache.directory.shared.ldap.entry.EntryAttribute;
58 import org.apache.directory.shared.ldap.entry.Modification;
59 import org.apache.directory.shared.ldap.entry.ModificationOperation;
60 import org.apache.directory.shared.ldap.entry.Value;
61 import org.apache.directory.shared.ldap.entry.client.ClientStringValue;
62 import org.apache.directory.shared.ldap.exception.LdapInvalidAttributeValueException;
63 import org.apache.directory.shared.ldap.exception.LdapNoSuchAttributeException;
64 import org.apache.directory.shared.ldap.exception.LdapSchemaViolationException;
65 import org.apache.directory.shared.ldap.filter.EqualityNode;
66 import org.apache.directory.shared.ldap.filter.ExprNode;
67 import org.apache.directory.shared.ldap.filter.PresenceNode;
68 import org.apache.directory.shared.ldap.filter.SearchScope;
69 import org.apache.directory.shared.ldap.message.AliasDerefMode;
70 import org.apache.directory.shared.ldap.message.ResultCodeEnum;
71 import org.apache.directory.shared.ldap.message.SubentriesControl;
72 import org.apache.directory.shared.ldap.name.LdapDN;
73 import org.apache.directory.shared.ldap.schema.AttributeType;
74 import org.apache.directory.shared.ldap.schema.NormalizerMappingResolver;
75 import org.apache.directory.shared.ldap.schema.OidNormalizer;
76 import org.apache.directory.shared.ldap.subtree.SubtreeSpecification;
77 import org.apache.directory.shared.ldap.subtree.SubtreeSpecificationParser;
78 import org.slf4j.Logger;
79 import org.slf4j.LoggerFactory;
80
81 import javax.naming.Name;
82 import javax.naming.directory.SearchControls;
83 import java.util.ArrayList;
84 import java.util.Iterator;
85 import java.util.List;
86 import java.util.Map;
87
88
89
90
91
92
93
94
95
96
97
98 public class SubentryInterceptor extends BaseInterceptor
99 {
100
101 private static final String SUBENTRY_CONTROL = SubentriesControl.CONTROL_OID;
102
103 public static final String AC_AREA = "accessControlSpecificArea";
104 public static final String AC_INNERAREA = "accessControlInnerArea";
105
106 public static final String SCHEMA_AREA = "subschemaAdminSpecificArea";
107
108 public static final String COLLECTIVE_AREA = "collectiveAttributeSpecificArea";
109 public static final String COLLECTIVE_INNERAREA = "collectiveAttributeInnerArea";
110
111 public static final String TRIGGER_AREA = "triggerExecutionSpecificArea";
112 public static final String TRIGGER_INNERAREA = "triggerExecutionInnerArea";
113
114 public static final String[] SUBENTRY_OPATTRS =
115 { SchemaConstants.ACCESS_CONTROL_SUBENTRIES_AT, SchemaConstants.SUBSCHEMA_SUBENTRY_AT,
116 SchemaConstants.COLLECTIVE_ATTRIBUTE_SUBENTRIES_AT, SchemaConstants.TRIGGER_EXECUTION_SUBENTRIES_AT };
117
118 private static final Logger LOG = LoggerFactory.getLogger( SubentryInterceptor.class );
119
120
121 private final SubentryCache subentryCache = new SubentryCache();
122
123 private SubtreeSpecificationParser ssParser;
124 private SubtreeEvaluator evaluator;
125 private PartitionNexus nexus;
126
127
128 private Registries registries;
129
130
131 private AttributeTypeRegistry atRegistry;
132
133
134 private OidRegistry oidRegistry;
135
136 private AttributeType objectClassType;
137
138
139 public void init( DirectoryService directoryService ) throws Exception
140 {
141 super.init( directoryService );
142 nexus = directoryService.getPartitionNexus();
143 registries = directoryService.getRegistries();
144 atRegistry = registries.getAttributeTypeRegistry();
145 oidRegistry = registries.getOidRegistry();
146
147
148 objectClassType = atRegistry.lookup( oidRegistry.getOid( SchemaConstants.OBJECT_CLASS_AT ) );
149
150 ssParser = new SubtreeSpecificationParser( new NormalizerMappingResolver()
151 {
152 public Map<String, OidNormalizer> getNormalizerMapping() throws Exception
153 {
154 return atRegistry.getNormalizerMapping();
155 }
156 }, atRegistry.getNormalizerMapping() );
157 evaluator = new SubtreeEvaluator( oidRegistry, atRegistry );
158
159
160 Iterator<String> suffixes = this.nexus.listSuffixes( null );
161 ExprNode filter = new EqualityNode<String>( SchemaConstants.OBJECT_CLASS_AT, new ClientStringValue(
162 SchemaConstants.SUBENTRY_OC ) );
163 SearchControls controls = new SearchControls();
164 controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
165 controls.setReturningAttributes( new String[]
166 { SchemaConstants.SUBTREE_SPECIFICATION_AT, SchemaConstants.OBJECT_CLASS_AT } );
167
168
169 while ( suffixes.hasNext() )
170 {
171 LdapDN suffix = new LdapDN( suffixes.next() );
172
173 suffix.normalize( atRegistry.getNormalizerMapping() );
174
175 LdapDN adminDn = new LdapDN( ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
176 adminDn.normalize( registries.getAttributeTypeRegistry().getNormalizerMapping() );
177 CoreSession adminSession = new DefaultCoreSession(
178 new LdapPrincipal( adminDn, AuthenticationLevel.STRONG ), directoryService );
179
180 EntryFilteringCursor subentries = nexus.search( new SearchOperationContext( adminSession,
181 suffix, AliasDerefMode.NEVER_DEREF_ALIASES, filter, controls ) );
182
183 while ( subentries.next() )
184 {
185 ServerEntry subentry = subentries.get();
186 LdapDN dnName = subentry.getDn();
187
188 String subtree = subentry.get( SchemaConstants.SUBTREE_SPECIFICATION_AT ).getString();
189 SubtreeSpecification ss;
190
191 try
192 {
193 ss = ssParser.parse( subtree );
194 }
195 catch ( Exception e )
196 {
197 LOG.warn( "Failed while parsing subtreeSpecification for " + dnName );
198 continue;
199 }
200
201 dnName.normalize( atRegistry.getNormalizerMapping() );
202 subentryCache.setSubentry( dnName.toString(), ss, getSubentryTypes( subentry ) );
203 }
204 }
205 }
206
207
208 private int getSubentryTypes( ServerEntry subentry ) throws Exception
209 {
210 int types = 0;
211
212 EntryAttribute oc = subentry.get( SchemaConstants.OBJECT_CLASS_AT );
213
214 if ( oc == null )
215 {
216 throw new LdapSchemaViolationException( "A subentry must have an objectClass attribute",
217 ResultCodeEnum.OBJECT_CLASS_VIOLATION );
218 }
219
220 if ( oc.contains( SchemaConstants.ACCESS_CONTROL_SUBENTRY_OC ) )
221 {
222 types |= Subentry.ACCESS_CONTROL_SUBENTRY;
223 }
224
225 if ( oc.contains( "subschema" ) )
226 {
227 types |= Subentry.SCHEMA_SUBENTRY;
228 }
229
230 if ( oc.contains( SchemaConstants.COLLECTIVE_ATTRIBUTE_SUBENTRY_OC ) )
231 {
232 types |= Subentry.COLLECTIVE_SUBENTRY;
233 }
234
235 if ( oc.contains( ApacheSchemaConstants.TRIGGER_EXECUTION_SUBENTRY_OC ) )
236 {
237 types |= Subentry.TRIGGER_SUBENTRY;
238 }
239
240 return types;
241 }
242
243
244
245
246
247
248
249 public EntryFilteringCursor list( NextInterceptor nextInterceptor, ListOperationContext opContext )
250 throws Exception
251 {
252 EntryFilteringCursor cursor = nextInterceptor.list( opContext );
253
254 if ( !isSubentryVisible( opContext ) )
255 {
256 cursor.addEntryFilter( new HideSubentriesFilter() );
257 }
258
259 return cursor;
260 }
261
262
263 public EntryFilteringCursor search( NextInterceptor nextInterceptor, SearchOperationContext opContext )
264 throws Exception
265 {
266 EntryFilteringCursor cursor = nextInterceptor.search( opContext );
267
268
269 if ( opContext.getScope() == SearchScope.OBJECT )
270 {
271 return cursor;
272 }
273
274
275 if ( !isSubentryVisible( opContext ) )
276 {
277 cursor.addEntryFilter( new HideSubentriesFilter() );
278 }
279 else
280 {
281 cursor.addEntryFilter( new HideEntriesFilter() );
282 }
283
284 return cursor;
285 }
286
287
288
289
290
291
292
293
294
295
296 private boolean isSubentryVisible( OperationContext opContext ) throws Exception
297 {
298 if ( !opContext.hasRequestControls() )
299 {
300 return false;
301 }
302
303
304 if ( opContext.hasRequestControl( SUBENTRY_CONTROL ) )
305 {
306 SubentriesControl subentriesControl = ( SubentriesControl ) opContext.getRequestControl( SUBENTRY_CONTROL );
307 return subentriesControl.isVisible();
308 }
309
310 return false;
311 }
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328 public ServerEntry getSubentryAttributes( LdapDN dn, ServerEntry entryAttrs ) throws Exception
329 {
330 ServerEntry subentryAttrs = new DefaultServerEntry( registries, dn );
331 Iterator<String> list = subentryCache.nameIterator();
332
333 while ( list.hasNext() )
334 {
335 String subentryDnStr = list.next();
336 LdapDN subentryDn = new LdapDN( subentryDnStr );
337 LdapDN apDn = ( LdapDN ) subentryDn.clone();
338 apDn.remove( apDn.size() - 1 );
339 Subentry subentry = subentryCache.getSubentry( subentryDnStr );
340 SubtreeSpecification ss = subentry.getSubtreeSpecification();
341
342 if ( evaluator.evaluate( ss, apDn, dn, entryAttrs ) )
343 {
344 EntryAttribute operational;
345
346 if ( subentry.isAccessControlSubentry() )
347 {
348 operational = subentryAttrs.get( SchemaConstants.ACCESS_CONTROL_SUBENTRIES_AT );
349
350 if ( operational == null )
351 {
352 operational = new DefaultServerAttribute( SchemaConstants.ACCESS_CONTROL_SUBENTRIES_AT,
353 atRegistry.lookup( SchemaConstants.ACCESS_CONTROL_SUBENTRIES_AT ) );
354 subentryAttrs.put( operational );
355 }
356
357 operational.add( subentryDn.toString() );
358 }
359 if ( subentry.isSchemaSubentry() )
360 {
361 operational = subentryAttrs.get( SchemaConstants.SUBSCHEMA_SUBENTRY_AT );
362
363 if ( operational == null )
364 {
365 operational = new DefaultServerAttribute( SchemaConstants.SUBSCHEMA_SUBENTRY_AT, atRegistry
366 .lookup( SchemaConstants.SUBSCHEMA_SUBENTRY_AT ) );
367 subentryAttrs.put( operational );
368 }
369
370 operational.add( subentryDn.toString() );
371 }
372 if ( subentry.isCollectiveSubentry() )
373 {
374 operational = subentryAttrs.get( SchemaConstants.COLLECTIVE_ATTRIBUTE_SUBENTRIES_AT );
375
376 if ( operational == null )
377 {
378 operational = new DefaultServerAttribute( SchemaConstants.COLLECTIVE_ATTRIBUTE_SUBENTRIES_AT,
379 atRegistry.lookup( SchemaConstants.COLLECTIVE_ATTRIBUTE_SUBENTRIES_AT ) );
380 subentryAttrs.put( operational );
381 }
382
383 operational.add( subentryDn.toString() );
384 }
385 if ( subentry.isTriggerSubentry() )
386 {
387 operational = subentryAttrs.get( SchemaConstants.TRIGGER_EXECUTION_SUBENTRIES_AT );
388
389 if ( operational == null )
390 {
391 operational = new DefaultServerAttribute( SchemaConstants.TRIGGER_EXECUTION_SUBENTRIES_AT,
392 atRegistry.lookup( SchemaConstants.TRIGGER_EXECUTION_SUBENTRIES_AT ) );
393 subentryAttrs.put( operational );
394 }
395
396 operational.add( subentryDn.toString() );
397 }
398 }
399 }
400
401 return subentryAttrs;
402 }
403
404
405 public void add( NextInterceptor next, AddOperationContext addContext ) throws Exception
406 {
407 LdapDN name = addContext.getDn();
408 ClonedServerEntry entry = addContext.getEntry();
409
410 EntryAttribute objectClasses = entry.get( SchemaConstants.OBJECT_CLASS_AT );
411
412 if ( objectClasses.contains( SchemaConstants.SUBENTRY_OC ) )
413 {
414
415 LdapDN apName = ( LdapDN ) name.clone();
416 apName.remove( name.size() - 1 );
417 ServerEntry ap = addContext.lookup( apName, ByPassConstants.LOOKUP_BYPASS );
418 EntryAttribute administrativeRole = ap.get( "administrativeRole" );
419
420
421 if ( administrativeRole == null || administrativeRole.size() <= 0 )
422 {
423 throw new LdapNoSuchAttributeException( "Administration point " + apName
424 + " does not contain an administrativeRole attribute! An"
425 + " administrativeRole attribute in the administrative point is"
426 + " required to add a subordinate subentry." );
427 }
428
429
430
431
432
433
434
435
436
437 Subentry subentry = new Subentry();
438 subentry.setTypes( getSubentryTypes( entry ) );
439 ServerEntry operational = getSubentryOperatationalAttributes( name, subentry );
440
441
442
443
444
445
446
447
448 String subtree = entry.get( SchemaConstants.SUBTREE_SPECIFICATION_AT ).getString();
449 SubtreeSpecification ss;
450
451 try
452 {
453 ss = ssParser.parse( subtree );
454 }
455 catch ( Exception e )
456 {
457 String msg = "Failed while parsing subtreeSpecification for " + name.getUpName();
458 LOG.warn( msg );
459 throw new LdapInvalidAttributeValueException( msg, ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
460 }
461
462 subentryCache.setSubentry( name.getNormName(), ss, getSubentryTypes( entry ) );
463
464 next.add( addContext );
465
466
467
468
469
470
471
472
473
474 LdapDN baseDn = ( LdapDN ) apName.clone();
475 baseDn.addAll( ss.getBase() );
476
477 ExprNode filter = new PresenceNode( SchemaConstants.OBJECT_CLASS_AT_OID );
478 SearchControls controls = new SearchControls();
479 controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
480 controls.setReturningAttributes( new String[]
481 { SchemaConstants.ALL_OPERATIONAL_ATTRIBUTES, SchemaConstants.ALL_USER_ATTRIBUTES } );
482
483 EntryFilteringCursor subentries = nexus.search( new SearchOperationContext( addContext.getSession(),
484 baseDn, AliasDerefMode.NEVER_DEREF_ALIASES, filter, controls ) );
485
486 while ( subentries.next() )
487 {
488 ServerEntry candidate = subentries.get();
489 LdapDN dn = candidate.getDn();
490 dn.normalize( atRegistry.getNormalizerMapping() );
491
492 if ( evaluator.evaluate( ss, apName, dn, candidate ) )
493 {
494 nexus.modify( new ModifyOperationContext( addContext.getSession(), dn,
495 getOperationalModsForAdd( candidate, operational ) ) );
496 }
497 }
498
499
500
501 addContext.setEntry( entry );
502 }
503 else
504 {
505 Iterator<String> list = subentryCache.nameIterator();
506
507 while ( list.hasNext() )
508 {
509 String subentryDnStr = list.next();
510 LdapDN subentryDn = new LdapDN( subentryDnStr );
511 LdapDN apDn = ( LdapDN ) subentryDn.clone();
512 apDn.remove( apDn.size() - 1 );
513 Subentry subentry = subentryCache.getSubentry( subentryDnStr );
514 SubtreeSpecification ss = subentry.getSubtreeSpecification();
515
516 if ( evaluator.evaluate( ss, apDn, name, entry ) )
517 {
518 EntryAttribute operational;
519
520 if ( subentry.isAccessControlSubentry() )
521 {
522 operational = entry.get( SchemaConstants.ACCESS_CONTROL_SUBENTRIES_AT );
523
524 if ( operational == null )
525 {
526 operational = new DefaultServerAttribute( atRegistry
527 .lookup( SchemaConstants.ACCESS_CONTROL_SUBENTRIES_AT ) );
528 entry.put( operational );
529 }
530
531 operational.add( subentryDn.toString() );
532 }
533
534 if ( subentry.isSchemaSubentry() )
535 {
536 operational = entry.get( SchemaConstants.SUBSCHEMA_SUBENTRY_AT );
537
538 if ( operational == null )
539 {
540 operational = new DefaultServerAttribute( atRegistry
541 .lookup( SchemaConstants.SUBSCHEMA_SUBENTRY_AT ) );
542 entry.put( operational );
543 }
544
545 operational.add( subentryDn.toString() );
546 }
547
548 if ( subentry.isCollectiveSubentry() )
549 {
550 operational = entry.get( SchemaConstants.COLLECTIVE_ATTRIBUTE_SUBENTRIES_AT );
551
552 if ( operational == null )
553 {
554 operational = new DefaultServerAttribute( atRegistry
555 .lookup( SchemaConstants.COLLECTIVE_ATTRIBUTE_SUBENTRIES_AT ) );
556 entry.put( operational );
557 }
558
559 operational.add( subentryDn.toString() );
560 }
561
562 if ( subentry.isTriggerSubentry() )
563 {
564 operational = entry.get( SchemaConstants.TRIGGER_EXECUTION_SUBENTRIES_AT );
565
566 if ( operational == null )
567 {
568 operational = new DefaultServerAttribute( atRegistry
569 .lookup( SchemaConstants.TRIGGER_EXECUTION_SUBENTRIES_AT ) );
570 entry.put( operational );
571 }
572
573 operational.add( subentryDn.toString() );
574 }
575 }
576 }
577
578
579
580 addContext.setEntry( entry );
581
582 next.add( addContext );
583 }
584 }
585
586
587
588
589
590
591 public void delete( NextInterceptor next, DeleteOperationContext opContext ) throws Exception
592 {
593 LdapDN name = opContext.getDn();
594 ServerEntry entry = opContext.lookup( name, ByPassConstants.LOOKUP_BYPASS );
595 EntryAttribute objectClasses = entry.get( objectClassType );
596
597 if ( objectClasses.contains( SchemaConstants.SUBENTRY_OC ) )
598 {
599 SubtreeSpecification ss = subentryCache.removeSubentry( name.toNormName() ).getSubtreeSpecification();
600 next.delete( opContext );
601
602
603
604
605
606
607
608
609
610 LdapDN apName = ( LdapDN ) name.clone();
611 apName.remove( name.size() - 1 );
612 LdapDN baseDn = ( LdapDN ) apName.clone();
613 baseDn.addAll( ss.getBase() );
614
615 ExprNode filter = new PresenceNode( oidRegistry.getOid( SchemaConstants.OBJECT_CLASS_AT ) );
616 SearchControls controls = new SearchControls();
617 controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
618 controls.setReturningAttributes( new String[]
619 { SchemaConstants.ALL_OPERATIONAL_ATTRIBUTES, SchemaConstants.ALL_USER_ATTRIBUTES } );
620
621 EntryFilteringCursor subentries = nexus.search( new SearchOperationContext( opContext.getSession(),
622 baseDn, AliasDerefMode.NEVER_DEREF_ALIASES, filter, controls ) );
623
624 while ( subentries.next() )
625 {
626 ServerEntry candidate = subentries.get();
627 LdapDN dn = new LdapDN( candidate.getDn() );
628 dn.normalize( atRegistry.getNormalizerMapping() );
629
630 if ( evaluator.evaluate( ss, apName, dn, candidate ) )
631 {
632 nexus.modify( new ModifyOperationContext( opContext.getSession(), dn,
633 getOperationalModsForRemove( name, candidate ) ) );
634 }
635 }
636 }
637 else
638 {
639 next.delete( opContext );
640 }
641 }
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657 private boolean hasAdministrativeDescendant( OperationContext opContext, LdapDN name ) throws Exception
658 {
659 ExprNode filter = new PresenceNode( "administrativeRole" );
660 SearchControls controls = new SearchControls();
661 controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
662 EntryFilteringCursor aps = nexus.search( new SearchOperationContext( opContext.getSession(), name,
663 AliasDerefMode.NEVER_DEREF_ALIASES, filter, controls ) );
664
665 if ( aps.next() )
666 {
667 aps.close();
668 return true;
669 }
670
671 return false;
672 }
673
674
675 private List<Modification> getModsOnEntryRdnChange( Name oldName, Name newName, ServerEntry entry )
676 throws Exception
677 {
678 List<Modification> modList = new ArrayList<Modification>();
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693 Iterator<String> subentries = subentryCache.nameIterator();
694
695 while ( subentries.hasNext() )
696 {
697 String subentryDn = subentries.next();
698 Name apDn = new LdapDN( subentryDn );
699 apDn.remove( apDn.size() - 1 );
700 SubtreeSpecification ss = subentryCache.getSubentry( subentryDn ).getSubtreeSpecification();
701 boolean isOldNameSelected = evaluator.evaluate( ss, apDn, oldName, entry );
702 boolean isNewNameSelected = evaluator.evaluate( ss, apDn, newName, entry );
703
704 if ( isOldNameSelected == isNewNameSelected )
705 {
706 continue;
707 }
708
709
710 if ( isOldNameSelected && !isNewNameSelected )
711 {
712 for ( String aSUBENTRY_OPATTRS : SUBENTRY_OPATTRS )
713 {
714 ModificationOperation op = ModificationOperation.REPLACE_ATTRIBUTE;
715 EntryAttribute opAttr = entry.get( aSUBENTRY_OPATTRS );
716
717 if ( opAttr != null )
718 {
719 opAttr = ( ServerAttribute ) opAttr.clone();
720 opAttr.remove( subentryDn );
721
722 if ( opAttr.size() < 1 )
723 {
724 op = ModificationOperation.REMOVE_ATTRIBUTE;
725 }
726
727 modList.add( new ServerModification( op, opAttr ) );
728 }
729 }
730 }
731
732 else if ( isNewNameSelected && !isOldNameSelected )
733 {
734 for ( String aSUBENTRY_OPATTRS : SUBENTRY_OPATTRS )
735 {
736 ModificationOperation op = ModificationOperation.ADD_ATTRIBUTE;
737 ServerAttribute opAttr = new DefaultServerAttribute( aSUBENTRY_OPATTRS, atRegistry
738 .lookup( aSUBENTRY_OPATTRS ) );
739 opAttr.add( subentryDn );
740 modList.add( new ServerModification( op, opAttr ) );
741 }
742 }
743 }
744
745 return modList;
746 }
747
748
749 public void rename( NextInterceptor next, RenameOperationContext opContext ) throws Exception
750 {
751 LdapDN name = opContext.getDn();
752
753 ServerEntry entry = opContext.lookup( name, ByPassConstants.LOOKUP_BYPASS );
754
755 EntryAttribute objectClasses = entry.get( objectClassType );
756
757 if ( objectClasses.contains( SchemaConstants.SUBENTRY_OC ) )
758 {
759 Subentry subentry = subentryCache.getSubentry( name.toNormName() );
760 SubtreeSpecification ss = subentry.getSubtreeSpecification();
761 LdapDN apName = ( LdapDN ) name.clone();
762 apName.remove( apName.size() - 1 );
763 LdapDN baseDn = ( LdapDN ) apName.clone();
764 baseDn.addAll( ss.getBase() );
765 LdapDN newName = ( LdapDN ) name.clone();
766 newName.remove( newName.size() - 1 );
767
768 newName.add( opContext.getNewRdn() );
769
770 String newNormName = newName.toNormName();
771 subentryCache.setSubentry( newNormName, ss, subentry.getTypes() );
772 next.rename( opContext );
773
774 subentry = subentryCache.getSubentry( newNormName );
775 ExprNode filter = new PresenceNode( oidRegistry.getOid( SchemaConstants.OBJECT_CLASS_AT ) );
776 SearchControls controls = new SearchControls();
777 controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
778 controls.setReturningAttributes( new String[]
779 { SchemaConstants.ALL_OPERATIONAL_ATTRIBUTES, SchemaConstants.ALL_USER_ATTRIBUTES } );
780 EntryFilteringCursor subentries = nexus.search( new SearchOperationContext( opContext.getSession(),
781 baseDn, AliasDerefMode.NEVER_DEREF_ALIASES, filter, controls ) );
782
783 while ( subentries.next() )
784 {
785 ServerEntry candidate = subentries.get();
786 LdapDN dn = candidate.getDn();
787 dn.normalize( atRegistry.getNormalizerMapping() );
788
789
790 if ( evaluator.evaluate( ss, apName, dn, candidate ) )
791 {
792 nexus.modify( new ModifyOperationContext( opContext.getSession(), dn,
793 getOperationalModsForReplace( name, newName, subentry, candidate ) ) );
794 }
795 }
796 }
797 else
798 {
799 if ( hasAdministrativeDescendant( opContext, name ) )
800 {
801 String msg = "Will not allow rename operation on entries with administrative descendants.";
802 LOG.warn( msg );
803 throw new LdapSchemaViolationException( msg, ResultCodeEnum.NOT_ALLOWED_ON_RDN );
804 }
805
806 next.rename( opContext );
807
808
809
810 LdapDN newName = ( LdapDN ) name.clone();
811 newName.remove( newName.size() - 1 );
812 newName.add( opContext.getNewRdn() );
813 newName.normalize( atRegistry.getNormalizerMapping() );
814 List<Modification> mods = getModsOnEntryRdnChange( name, newName, entry );
815
816 if ( mods.size() > 0 )
817 {
818 nexus.modify( new ModifyOperationContext( opContext.getSession(), newName, mods ) );
819 }
820 }
821 }
822
823
824 public void moveAndRename( NextInterceptor next, MoveAndRenameOperationContext opContext ) throws Exception
825 {
826 LdapDN oriChildName = opContext.getDn();
827 LdapDN parent = opContext.getParent();
828
829 ServerEntry entry = opContext.lookup( oriChildName, ByPassConstants.LOOKUP_BYPASS );
830
831 EntryAttribute objectClasses = entry.get( objectClassType );
832
833 if ( objectClasses.contains( SchemaConstants.SUBENTRY_OC ) )
834 {
835 Subentry subentry = subentryCache.getSubentry( oriChildName.toNormName() );
836 SubtreeSpecification ss = subentry.getSubtreeSpecification();
837 LdapDN apName = ( LdapDN ) oriChildName.clone();
838 apName.remove( apName.size() - 1 );
839 LdapDN baseDn = ( LdapDN ) apName.clone();
840 baseDn.addAll( ss.getBase() );
841 LdapDN newName = ( LdapDN ) parent.clone();
842 newName.remove( newName.size() - 1 );
843
844 newName.add( opContext.getNewRdn() );
845
846 String newNormName = newName.toNormName();
847 subentryCache.setSubentry( newNormName, ss, subentry.getTypes() );
848 next.moveAndRename( opContext );
849
850 subentry = subentryCache.getSubentry( newNormName );
851
852 ExprNode filter = new PresenceNode( oidRegistry.getOid( SchemaConstants.OBJECT_CLASS_AT ) );
853 SearchControls controls = new SearchControls();
854 controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
855 controls.setReturningAttributes( new String[]
856 { SchemaConstants.ALL_OPERATIONAL_ATTRIBUTES, SchemaConstants.ALL_USER_ATTRIBUTES } );
857 EntryFilteringCursor subentries = nexus.search( new SearchOperationContext( opContext.getSession(),
858 baseDn, AliasDerefMode.NEVER_DEREF_ALIASES, filter, controls ) );
859
860 while ( subentries.next() )
861 {
862 ServerEntry candidate = subentries.get();
863 LdapDN dn = candidate.getDn();
864 dn.normalize( atRegistry.getNormalizerMapping() );
865
866 if ( evaluator.evaluate( ss, apName, dn, candidate ) )
867 {
868 nexus.modify( new ModifyOperationContext( opContext.getSession(), dn,
869 getOperationalModsForReplace( oriChildName, newName, subentry, candidate ) ) );
870 }
871 }
872 }
873 else
874 {
875 if ( hasAdministrativeDescendant( opContext, oriChildName ) )
876 {
877 String msg = "Will not allow rename operation on entries with administrative descendants.";
878 LOG.warn( msg );
879 throw new LdapSchemaViolationException( msg, ResultCodeEnum.NOT_ALLOWED_ON_RDN );
880 }
881
882 next.moveAndRename( opContext );
883
884
885
886 LdapDN newName = ( LdapDN ) parent.clone();
887 newName.add( opContext.getNewRdn() );
888 newName.normalize( atRegistry.getNormalizerMapping() );
889 List<Modification> mods = getModsOnEntryRdnChange( oriChildName, newName, entry );
890
891 if ( mods.size() > 0 )
892 {
893 nexus.modify( new ModifyOperationContext( opContext.getSession(), newName, mods ) );
894 }
895 }
896 }
897
898
899 public void move( NextInterceptor next, MoveOperationContext opContext ) throws Exception
900 {
901 LdapDN oriChildName = opContext.getDn();
902 LdapDN newParentName = opContext.getParent();
903
904 ServerEntry entry = opContext.lookup( oriChildName, ByPassConstants.LOOKUP_BYPASS );
905
906 EntryAttribute objectClasses = entry.get( SchemaConstants.OBJECT_CLASS_AT );
907
908 if ( objectClasses.contains( SchemaConstants.SUBENTRY_OC ) )
909 {
910 Subentry subentry = subentryCache.getSubentry( oriChildName.toString() );
911 SubtreeSpecification ss = subentry.getSubtreeSpecification();
912 LdapDN apName = ( LdapDN ) oriChildName.clone();
913 apName.remove( apName.size() - 1 );
914 LdapDN baseDn = ( LdapDN ) apName.clone();
915 baseDn.addAll( ss.getBase() );
916 LdapDN newName = ( LdapDN ) newParentName.clone();
917 newName.remove( newName.size() - 1 );
918 newName.add( newParentName.get( newParentName.size() - 1 ) );
919
920 String newNormName = newName.toNormName();
921 subentryCache.setSubentry( newNormName, ss, subentry.getTypes() );
922 next.move( opContext );
923
924 subentry = subentryCache.getSubentry( newNormName );
925
926 ExprNode filter = new PresenceNode( SchemaConstants.OBJECT_CLASS_AT );
927 SearchControls controls = new SearchControls();
928 controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
929 controls.setReturningAttributes( new String[]
930 { SchemaConstants.ALL_OPERATIONAL_ATTRIBUTES, SchemaConstants.ALL_USER_ATTRIBUTES } );
931 EntryFilteringCursor subentries = nexus.search( new SearchOperationContext( opContext.getSession(),
932 baseDn, AliasDerefMode.NEVER_DEREF_ALIASES, filter, controls ) );
933
934 while ( subentries.next() )
935 {
936 ServerEntry candidate = subentries.get();
937 LdapDN dn = candidate.getDn();
938 dn.normalize( atRegistry.getNormalizerMapping() );
939
940 if ( evaluator.evaluate( ss, apName, dn, candidate ) )
941 {
942 nexus.modify( new ModifyOperationContext( opContext.getSession(), dn,
943 getOperationalModsForReplace( oriChildName, newName, subentry, candidate ) ) );
944 }
945 }
946 }
947 else
948 {
949 if ( hasAdministrativeDescendant( opContext, oriChildName ) )
950 {
951 String msg = "Will not allow rename operation on entries with administrative descendants.";
952 LOG.warn( msg );
953 throw new LdapSchemaViolationException( msg, ResultCodeEnum.NOT_ALLOWED_ON_RDN );
954 }
955
956 next.move( opContext );
957
958
959
960 LdapDN newName = ( LdapDN ) newParentName.clone();
961 newName.add( oriChildName.get( oriChildName.size() - 1 ) );
962 List<Modification> mods = getModsOnEntryRdnChange( oriChildName, newName, entry );
963
964 if ( mods.size() > 0 )
965 {
966 nexus.modify( new ModifyOperationContext( opContext.getSession(), newName, mods ) );
967 }
968 }
969 }
970
971
972
973
974
975
976 private int getSubentryTypes( ServerEntry entry, List<Modification> mods ) throws Exception
977 {
978 ServerAttribute ocFinalState = ( ServerAttribute ) entry.get( SchemaConstants.OBJECT_CLASS_AT ).clone();
979
980 for ( Modification mod : mods )
981 {
982 if ( mod.getAttribute().getId().equalsIgnoreCase( SchemaConstants.OBJECT_CLASS_AT ) )
983 {
984 switch ( mod.getOperation() )
985 {
986 case ADD_ATTRIBUTE:
987 for ( Value<?> value : ( ServerAttribute ) mod.getAttribute() )
988 {
989 ocFinalState.add( ( String ) value.get() );
990 }
991
992 break;
993
994 case REMOVE_ATTRIBUTE:
995 for ( Value<?> value : ( ServerAttribute ) mod.getAttribute() )
996 {
997 ocFinalState.remove( ( String ) value.get() );
998 }
999
1000 break;
1001
1002 case REPLACE_ATTRIBUTE:
1003 ocFinalState = ( ServerAttribute ) mod.getAttribute();
1004 break;
1005 }
1006 }
1007 }
1008
1009 ServerEntry attrs = new DefaultServerEntry( registries, LdapDN.EMPTY_LDAPDN );
1010 attrs.put( ocFinalState );
1011 return getSubentryTypes( attrs );
1012 }
1013
1014
1015 public void modify( NextInterceptor next, ModifyOperationContext opContext ) throws Exception
1016 {
1017 LdapDN name = opContext.getDn();
1018 List<Modification> mods = opContext.getModItems();
1019
1020 ServerEntry entry = opContext.lookup( name, ByPassConstants.LOOKUP_BYPASS );
1021
1022 ServerEntry oldEntry = ( ServerEntry ) entry.clone();
1023 EntryAttribute objectClasses = entry.get( objectClassType );
1024 boolean isSubtreeSpecificationModification = false;
1025 Modification subtreeMod = null;
1026
1027 for ( Modification mod : mods )
1028 {
1029 if ( SchemaConstants.SUBTREE_SPECIFICATION_AT.equalsIgnoreCase( mod.getAttribute().getId() ) )
1030 {
1031 isSubtreeSpecificationModification = true;
1032 subtreeMod = mod;
1033 }
1034 }
1035
1036 if ( objectClasses.contains( SchemaConstants.SUBENTRY_OC ) && isSubtreeSpecificationModification )
1037 {
1038 SubtreeSpecification ssOld = subentryCache.removeSubentry( name.toString() ).getSubtreeSpecification();
1039 SubtreeSpecification ssNew;
1040
1041 try
1042 {
1043 ssNew = ssParser.parse( ( ( ServerAttribute ) subtreeMod.getAttribute() ).getString() );
1044 }
1045 catch ( Exception e )
1046 {
1047 String msg = "failed to parse the new subtreeSpecification";
1048 LOG.error( msg, e );
1049 throw new LdapInvalidAttributeValueException( msg, ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
1050 }
1051
1052 subentryCache.setSubentry( name.toNormName(), ssNew, getSubentryTypes( entry, mods ) );
1053 next.modify( opContext );
1054
1055
1056 LdapDN apName = ( LdapDN ) name.clone();
1057 apName.remove( apName.size() - 1 );
1058 LdapDN oldBaseDn = ( LdapDN ) apName.clone();
1059 oldBaseDn.addAll( ssOld.getBase() );
1060 ExprNode filter = new PresenceNode( oidRegistry.getOid( SchemaConstants.OBJECT_CLASS_AT ) );
1061 SearchControls controls = new SearchControls();
1062 controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
1063 controls.setReturningAttributes( new String[]
1064 { SchemaConstants.ALL_OPERATIONAL_ATTRIBUTES, SchemaConstants.ALL_USER_ATTRIBUTES } );
1065 EntryFilteringCursor subentries = nexus.search( new SearchOperationContext( opContext.getSession(),
1066 oldBaseDn, AliasDerefMode.NEVER_DEREF_ALIASES, filter, controls ) );
1067
1068 while ( subentries.next() )
1069 {
1070 ServerEntry candidate = subentries.get();
1071 LdapDN dn = candidate.getDn();
1072 dn.normalize( atRegistry.getNormalizerMapping() );
1073
1074 if ( evaluator.evaluate( ssOld, apName, dn, candidate ) )
1075 {
1076 nexus.modify( new ModifyOperationContext( opContext.getSession(), dn,
1077 getOperationalModsForRemove( name, candidate ) ) );
1078 }
1079 }
1080
1081
1082 Subentry subentry = subentryCache.getSubentry( name.toNormName() );
1083 ServerEntry operational = getSubentryOperatationalAttributes( name, subentry );
1084 LdapDN newBaseDn = ( LdapDN ) apName.clone();
1085 newBaseDn.addAll( ssNew.getBase() );
1086 subentries = nexus.search( new SearchOperationContext( opContext.getSession(), newBaseDn,
1087 AliasDerefMode.NEVER_DEREF_ALIASES, filter, controls ) );
1088
1089 while ( subentries.next() )
1090 {
1091 ServerEntry candidate = subentries.get();
1092 LdapDN dn = candidate.getDn();
1093 dn.normalize( atRegistry.getNormalizerMapping() );
1094
1095 if ( evaluator.evaluate( ssNew, apName, dn, candidate ) )
1096 {
1097 nexus.modify( new ModifyOperationContext( opContext.getSession(), dn,
1098 getOperationalModsForAdd( candidate, operational ) ) );
1099 }
1100 }
1101 }
1102 else
1103 {
1104 next.modify( opContext );
1105
1106 if ( !objectClasses.contains( SchemaConstants.SUBENTRY_OC ) )
1107 {
1108 ServerEntry newEntry = opContext.lookup( name, ByPassConstants.LOOKUP_BYPASS );
1109
1110 List<Modification> subentriesOpAttrMods = getModsOnEntryModification( name, oldEntry, newEntry );
1111
1112 if ( subentriesOpAttrMods.size() > 0 )
1113 {
1114 nexus.modify( new ModifyOperationContext( opContext.getSession(), name, subentriesOpAttrMods ) );
1115 }
1116 }
1117 }
1118 }
1119
1120
1121
1122
1123
1124
1125 private List<Modification> getOperationalModsForReplace( Name oldName, Name newName, Subentry subentry,
1126 ServerEntry entry ) throws Exception
1127 {
1128 List<Modification> modList = new ArrayList<Modification>();
1129
1130 ServerAttribute operational;
1131
1132 if ( subentry.isAccessControlSubentry() )
1133 {
1134 operational = ( ServerAttribute ) entry.get( SchemaConstants.ACCESS_CONTROL_SUBENTRIES_AT ).clone();
1135
1136 if ( operational == null )
1137 {
1138 operational = new DefaultServerAttribute( SchemaConstants.ACCESS_CONTROL_SUBENTRIES_AT, atRegistry
1139 .lookup( SchemaConstants.ACCESS_CONTROL_SUBENTRIES_AT ) );
1140 operational.add( newName.toString() );
1141 }
1142 else
1143 {
1144 operational.remove( oldName.toString() );
1145 operational.add( newName.toString() );
1146 }
1147
1148 modList.add( new ServerModification( ModificationOperation.REPLACE_ATTRIBUTE, operational ) );
1149 }
1150
1151 if ( subentry.isSchemaSubentry() )
1152 {
1153 operational = ( ServerAttribute ) entry.get( SchemaConstants.SUBSCHEMA_SUBENTRY_AT ).clone();
1154
1155 if ( operational == null )
1156 {
1157 operational = new DefaultServerAttribute( SchemaConstants.SUBSCHEMA_SUBENTRY_AT, atRegistry
1158 .lookup( SchemaConstants.SUBSCHEMA_SUBENTRY_AT ) );
1159 operational.add( newName.toString() );
1160 }
1161 else
1162 {
1163 operational.remove( oldName.toString() );
1164 operational.add( newName.toString() );
1165 }
1166
1167 modList.add( new ServerModification( ModificationOperation.REPLACE_ATTRIBUTE, operational ) );
1168 }
1169
1170 if ( subentry.isCollectiveSubentry() )
1171 {
1172 operational = ( ServerAttribute ) entry.get( SchemaConstants.COLLECTIVE_ATTRIBUTE_SUBENTRIES_AT ).clone();
1173
1174 if ( operational == null )
1175 {
1176 operational = new DefaultServerAttribute( SchemaConstants.COLLECTIVE_ATTRIBUTE_SUBENTRIES_AT,
1177 atRegistry.lookup( SchemaConstants.COLLECTIVE_ATTRIBUTE_SUBENTRIES_AT ) );
1178 operational.add( newName.toString() );
1179 }
1180 else
1181 {
1182 operational.remove( oldName.toString() );
1183 operational.add( newName.toString() );
1184 }
1185
1186 modList.add( new ServerModification( ModificationOperation.REPLACE_ATTRIBUTE, operational ) );
1187 }
1188
1189 if ( subentry.isTriggerSubentry() )
1190 {
1191 operational = ( ServerAttribute ) entry.get( SchemaConstants.TRIGGER_EXECUTION_SUBENTRIES_AT ).clone();
1192
1193 if ( operational == null )
1194 {
1195 operational = new DefaultServerAttribute( SchemaConstants.TRIGGER_EXECUTION_SUBENTRIES_AT, atRegistry
1196 .lookup( SchemaConstants.TRIGGER_EXECUTION_SUBENTRIES_AT ) );
1197 operational.add( newName.toString() );
1198 }
1199 else
1200 {
1201 operational.remove( oldName.toString() );
1202 operational.add( newName.toString() );
1203 }
1204
1205 modList.add( new ServerModification( ModificationOperation.REPLACE_ATTRIBUTE, operational ) );
1206 }
1207
1208 return modList;
1209 }
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220 private ServerEntry getSubentryOperatationalAttributes( LdapDN name, Subentry subentry ) throws Exception
1221 {
1222 ServerEntry operational = new DefaultServerEntry( registries, name );
1223
1224 if ( subentry.isAccessControlSubentry() )
1225 {
1226 if ( operational.get( SchemaConstants.ACCESS_CONTROL_SUBENTRIES_AT ) == null )
1227 {
1228 operational.put( SchemaConstants.ACCESS_CONTROL_SUBENTRIES_AT, name.toString() );
1229 }
1230 else
1231 {
1232 operational.get( SchemaConstants.ACCESS_CONTROL_SUBENTRIES_AT ).add( name.toString() );
1233 }
1234 }
1235 if ( subentry.isSchemaSubentry() )
1236 {
1237 if ( operational.get( SchemaConstants.SUBSCHEMA_SUBENTRY_AT ) == null )
1238 {
1239 operational.put( SchemaConstants.SUBSCHEMA_SUBENTRY_AT, name.toString() );
1240 }
1241 else
1242 {
1243 operational.get( SchemaConstants.SUBSCHEMA_SUBENTRY_AT ).add( name.toString() );
1244 }
1245 }
1246 if ( subentry.isCollectiveSubentry() )
1247 {
1248 if ( operational.get( SchemaConstants.COLLECTIVE_ATTRIBUTE_SUBENTRIES_AT ) == null )
1249 {
1250 operational.put( SchemaConstants.COLLECTIVE_ATTRIBUTE_SUBENTRIES_AT, name.toString() );
1251 }
1252 else
1253 {
1254 operational.get( SchemaConstants.COLLECTIVE_ATTRIBUTE_SUBENTRIES_AT ).add( name.toString() );
1255 }
1256 }
1257 if ( subentry.isTriggerSubentry() )
1258 {
1259 if ( operational.get( SchemaConstants.TRIGGER_EXECUTION_SUBENTRIES_AT ) == null )
1260 {
1261 operational.put( SchemaConstants.TRIGGER_EXECUTION_SUBENTRIES_AT, name.toString() );
1262 }
1263 else
1264 {
1265 operational.get( SchemaConstants.TRIGGER_EXECUTION_SUBENTRIES_AT ).add( name.toString() );
1266 }
1267 }
1268
1269 return operational;
1270 }
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286 private List<Modification> getOperationalModsForRemove( LdapDN subentryDn, ServerEntry candidate )
1287 throws Exception
1288 {
1289 List<Modification> modList = new ArrayList<Modification>();
1290 String dn = subentryDn.toNormName();
1291
1292 for ( String opAttrId : SUBENTRY_OPATTRS )
1293 {
1294 EntryAttribute opAttr = candidate.get( opAttrId );
1295
1296 if ( ( opAttr != null ) && opAttr.contains( dn ) )
1297 {
1298 AttributeType attributeType = atRegistry.lookup( opAttrId );
1299 ServerAttribute attr = new DefaultServerAttribute( opAttrId, attributeType, dn );
1300 modList.add( new ServerModification( ModificationOperation.REMOVE_ATTRIBUTE, attr ) );
1301 }
1302 }
1303
1304 return modList;
1305 }
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323 public List<Modification> getOperationalModsForAdd( ServerEntry entry, ServerEntry operational )
1324 throws Exception
1325 {
1326 List<Modification> modList = new ArrayList<Modification>();
1327
1328 for ( AttributeType attributeType : operational.getAttributeTypes() )
1329 {
1330 ModificationOperation op = ModificationOperation.REPLACE_ATTRIBUTE;
1331 EntryAttribute result = new DefaultServerAttribute( attributeType );
1332 EntryAttribute opAttrAdditions = operational.get( attributeType );
1333 EntryAttribute opAttrInEntry = entry.get( attributeType );
1334
1335 for ( Value<?> value : opAttrAdditions )
1336 {
1337 result.add( value );
1338 }
1339
1340 if ( opAttrInEntry != null && opAttrInEntry.size() > 0 )
1341 {
1342 for ( Value<?> value : opAttrInEntry )
1343 {
1344 result.add( value );
1345 }
1346 }
1347 else
1348 {
1349 op = ModificationOperation.ADD_ATTRIBUTE;
1350 }
1351
1352 modList.add( new ServerModification( op, result ) );
1353 }
1354
1355 return modList;
1356 }
1357
1358
1359
1360
1361 public class HideSubentriesFilter implements EntryFilter
1362 {
1363 public boolean accept( SearchingOperationContext operation, ClonedServerEntry entry )
1364 throws Exception
1365 {
1366 String dn = entry.getDn().getNormName();
1367
1368
1369 if ( subentryCache.hasSubentry( dn ) )
1370 {
1371 return false;
1372 }
1373
1374
1375 EntryAttribute objectClasses = entry.get( SchemaConstants.OBJECT_CLASS_AT );
1376
1377 if ( objectClasses != null )
1378 {
1379 return !objectClasses.contains( SchemaConstants.SUBENTRY_OC );
1380 }
1381
1382 LdapDN ndn = new LdapDN( dn );
1383 ndn.normalize( atRegistry.getNormalizerMapping() );
1384 String normalizedDn = ndn.toString();
1385 return !subentryCache.hasSubentry( normalizedDn );
1386 }
1387 }
1388
1389
1390
1391
1392
1393 public class HideEntriesFilter implements EntryFilter
1394 {
1395 public boolean accept( SearchingOperationContext operation, ClonedServerEntry entry )
1396 throws Exception
1397 {
1398 String dn = entry.getDn().getNormName();
1399
1400
1401 if ( subentryCache.hasSubentry( dn ) )
1402 {
1403 return true;
1404 }
1405
1406
1407 EntryAttribute objectClasses = entry.get( SchemaConstants.OBJECT_CLASS_AT );
1408
1409 if ( objectClasses != null )
1410 {
1411 return objectClasses.contains( SchemaConstants.SUBENTRY_OC );
1412 }
1413
1414 LdapDN ndn = new LdapDN( dn );
1415 ndn.normalize( atRegistry.getNormalizerMapping() );
1416 return subentryCache.hasSubentry( ndn.toNormName() );
1417 }
1418 }
1419
1420
1421 private List<Modification> getModsOnEntryModification( LdapDN name, ServerEntry oldEntry, ServerEntry newEntry )
1422 throws Exception
1423 {
1424 List<Modification> modList = new ArrayList<Modification>();
1425
1426 Iterator<String> subentries = subentryCache.nameIterator();
1427
1428 while ( subentries.hasNext() )
1429 {
1430 String subentryDn = subentries.next();
1431 Name apDn = new LdapDN( subentryDn );
1432 apDn.remove( apDn.size() - 1 );
1433 SubtreeSpecification ss = subentryCache.getSubentry( subentryDn ).getSubtreeSpecification();
1434 boolean isOldEntrySelected = evaluator.evaluate( ss, apDn, name, oldEntry );
1435 boolean isNewEntrySelected = evaluator.evaluate( ss, apDn, name, newEntry );
1436
1437 if ( isOldEntrySelected == isNewEntrySelected )
1438 {
1439 continue;
1440 }
1441
1442
1443 if ( isOldEntrySelected && !isNewEntrySelected )
1444 {
1445 for ( String aSUBENTRY_OPATTRS : SUBENTRY_OPATTRS )
1446 {
1447 ModificationOperation op = ModificationOperation.REPLACE_ATTRIBUTE;
1448 EntryAttribute opAttr = oldEntry.get( aSUBENTRY_OPATTRS );
1449
1450 if ( opAttr != null )
1451 {
1452 opAttr = ( ServerAttribute ) opAttr.clone();
1453 opAttr.remove( subentryDn );
1454
1455 if ( opAttr.size() < 1 )
1456 {
1457 op = ModificationOperation.REMOVE_ATTRIBUTE;
1458 }
1459
1460 modList.add( new ServerModification( op, opAttr ) );
1461 }
1462 }
1463 }
1464
1465 else if ( isNewEntrySelected && !isOldEntrySelected )
1466 {
1467 for ( String attribute : SUBENTRY_OPATTRS )
1468 {
1469 ModificationOperation op = ModificationOperation.ADD_ATTRIBUTE;
1470 AttributeType type = atRegistry.lookup( attribute );
1471 ServerAttribute opAttr = new DefaultServerAttribute( attribute, type );
1472 opAttr.add( subentryDn );
1473 modList.add( new ServerModification( op, opAttr ) );
1474 }
1475 }
1476 }
1477
1478 return modList;
1479 }
1480
1481 }