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.partition;
21
22
23 import org.apache.directory.server.constants.ServerDNConstants;
24 import org.apache.directory.server.core.CoreSession;
25 import org.apache.directory.server.core.DefaultCoreSession;
26 import org.apache.directory.server.core.DirectoryService;
27 import org.apache.directory.server.core.authn.LdapPrincipal;
28 import org.apache.directory.server.core.cursor.SingletonCursor;
29 import org.apache.directory.server.core.entry.ClonedServerEntry;
30 import org.apache.directory.server.core.entry.DefaultServerAttribute;
31 import org.apache.directory.server.core.entry.DefaultServerEntry;
32 import org.apache.directory.server.core.entry.ServerEntry;
33 import org.apache.directory.server.core.filtering.EntryFilteringCursor;
34 import org.apache.directory.server.core.filtering.BaseEntryFilteringCursor;
35 import org.apache.directory.server.core.interceptor.context.AddContextPartitionOperationContext;
36 import org.apache.directory.server.core.interceptor.context.AddOperationContext;
37 import org.apache.directory.server.core.interceptor.context.BindOperationContext;
38 import org.apache.directory.server.core.interceptor.context.CompareOperationContext;
39 import org.apache.directory.server.core.interceptor.context.DeleteOperationContext;
40 import org.apache.directory.server.core.interceptor.context.EntryOperationContext;
41 import org.apache.directory.server.core.interceptor.context.GetMatchedNameOperationContext;
42 import org.apache.directory.server.core.interceptor.context.GetRootDSEOperationContext;
43 import org.apache.directory.server.core.interceptor.context.GetSuffixOperationContext;
44 import org.apache.directory.server.core.interceptor.context.ListOperationContext;
45 import org.apache.directory.server.core.interceptor.context.ListSuffixOperationContext;
46 import org.apache.directory.server.core.interceptor.context.LookupOperationContext;
47 import org.apache.directory.server.core.interceptor.context.ModifyOperationContext;
48 import org.apache.directory.server.core.interceptor.context.MoveAndRenameOperationContext;
49 import org.apache.directory.server.core.interceptor.context.MoveOperationContext;
50 import org.apache.directory.server.core.interceptor.context.RemoveContextPartitionOperationContext;
51 import org.apache.directory.server.core.interceptor.context.RenameOperationContext;
52 import org.apache.directory.server.core.interceptor.context.SearchOperationContext;
53 import org.apache.directory.server.core.interceptor.context.UnbindOperationContext;
54 import org.apache.directory.server.xdbm.Index;
55 import org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmIndex;
56 import org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmPartition;
57 import org.apache.directory.server.core.partition.tree.BranchNode;
58 import org.apache.directory.server.core.partition.tree.LeafNode;
59 import org.apache.directory.server.core.partition.tree.Node;
60 import org.apache.directory.server.schema.registries.AttributeTypeRegistry;
61 import org.apache.directory.server.schema.registries.OidRegistry;
62 import org.apache.directory.server.schema.registries.Registries;
63 import org.apache.directory.shared.ldap.MultiException;
64 import org.apache.directory.shared.ldap.NotImplementedException;
65 import org.apache.directory.shared.ldap.constants.AuthenticationLevel;
66 import org.apache.directory.shared.ldap.constants.SchemaConstants;
67 import org.apache.directory.shared.ldap.entry.EntryAttribute;
68 import org.apache.directory.shared.ldap.entry.Value;
69 import org.apache.directory.shared.ldap.exception.LdapInvalidAttributeIdentifierException;
70 import org.apache.directory.shared.ldap.exception.LdapNameNotFoundException;
71 import org.apache.directory.shared.ldap.exception.LdapNoSuchAttributeException;
72 import org.apache.directory.shared.ldap.filter.ExprNode;
73 import org.apache.directory.shared.ldap.filter.PresenceNode;
74 import org.apache.directory.shared.ldap.message.CascadeControl;
75 import org.apache.directory.shared.ldap.message.EntryChangeControl;
76 import org.apache.directory.shared.ldap.message.ManageDsaITControl;
77 import org.apache.directory.shared.ldap.message.PersistentSearchControl;
78 import org.apache.directory.shared.ldap.message.SubentriesControl;
79 import org.apache.directory.shared.ldap.message.extended.NoticeOfDisconnect;
80 import org.apache.directory.shared.ldap.name.LdapDN;
81 import org.apache.directory.shared.ldap.schema.AttributeType;
82 import org.apache.directory.shared.ldap.schema.Normalizer;
83 import org.apache.directory.shared.ldap.schema.UsageEnum;
84 import org.apache.directory.shared.ldap.util.DateUtils;
85 import org.apache.directory.shared.ldap.util.NamespaceTools;
86 import org.apache.directory.shared.ldap.util.StringTools;
87
88 import org.slf4j.Logger;
89 import org.slf4j.LoggerFactory;
90
91 import javax.naming.ConfigurationException;
92 import javax.naming.NameNotFoundException;
93 import javax.naming.directory.SearchControls;
94 import javax.naming.ldap.LdapContext;
95 import java.io.IOException;
96 import java.util.ArrayList;
97 import java.util.Arrays;
98 import java.util.Collections;
99 import java.util.Enumeration;
100 import java.util.HashMap;
101 import java.util.HashSet;
102 import java.util.Iterator;
103 import java.util.List;
104 import java.util.Map;
105 import java.util.Properties;
106 import java.util.Set;
107
108
109
110
111
112
113
114
115
116 public class DefaultPartitionNexus extends PartitionNexus
117 {
118 private static final Logger LOG = LoggerFactory.getLogger( DefaultPartitionNexus.class );
119
120
121 private static final boolean IS_DEBUG = LOG.isDebugEnabled();
122
123
124 private static final String ASF = "Apache Software Foundation";
125
126
127 private boolean initialized;
128
129 private DirectoryService directoryService;
130
131
132 private Partition system;
133
134
135 private Map<String, Partition> partitions = new HashMap<String, Partition>();
136
137
138 private BranchNode partitionLookupTree = new BranchNode();
139
140
141 private final ServerEntry rootDSE;
142
143
144 private Registries registries;
145
146
147 private AttributeTypeRegistry atRegistry;
148
149
150 private OidRegistry oidRegistry;
151
152
153
154
155
156
157
158
159
160
161
162
163 public DefaultPartitionNexus( ServerEntry rootDSE ) throws Exception
164 {
165
166 this.rootDSE = rootDSE;
167
168
169 rootDSE.put( SchemaConstants.SUBSCHEMA_SUBENTRY_AT, ServerDNConstants.CN_SCHEMA_DN );
170 rootDSE.put( SchemaConstants.SUPPORTED_LDAP_VERSION_AT, "3" );
171 rootDSE.put( SchemaConstants.SUPPORTED_FEATURES_AT, SchemaConstants.FEATURE_ALL_OPERATIONAL_ATTRIBUTES );
172 rootDSE.put( SchemaConstants.SUPPORTED_EXTENSION_AT, NoticeOfDisconnect.EXTENSION_OID );
173
174
175 rootDSE.put( SchemaConstants.SUPPORTED_CONTROL_AT,
176 PersistentSearchControl.CONTROL_OID,
177 EntryChangeControl.CONTROL_OID,
178 SubentriesControl.CONTROL_OID,
179 ManageDsaITControl.CONTROL_OID,
180 CascadeControl.CONTROL_OID );
181
182
183 rootDSE.put( SchemaConstants.OBJECT_CLASS_AT,
184 SchemaConstants.TOP_OC,
185 SchemaConstants.EXTENSIBLE_OBJECT_OC );
186
187
188 rootDSE.put( SchemaConstants.VENDOR_NAME_AT, ASF );
189
190 Properties props = new Properties();
191
192 try
193 {
194 props.load( getClass().getResourceAsStream( "version.properties" ) );
195 }
196 catch ( IOException e )
197 {
198 LOG.error( "failed to LOG version properties" );
199 }
200
201 rootDSE.put( SchemaConstants.VENDOR_VERSION_AT, props.getProperty( "apacheds.version", "UNKNOWN" ) );
202 }
203
204
205
206
207
208
209
210 public String getId()
211 {
212 return "NEXUS";
213 }
214
215
216
217
218
219
220
221
222
223
224
225
226 public void setId( String id )
227 {
228 throw new UnsupportedOperationException( "The id cannot be set for the partition nexus." );
229 }
230
231
232
233
234
235
236 public String getSuffix()
237 {
238 return "";
239 }
240
241
242
243
244
245
246 public void setSuffix( String suffix )
247 {
248 throw new UnsupportedOperationException();
249 }
250
251
252
253
254
255 public void setCacheSize( int cacheSize )
256 {
257 throw new UnsupportedOperationException( "You cannot set the cache size of the nexus" );
258 }
259
260
261
262
263
264
265
266 public int getCacheSize()
267 {
268 throw new UnsupportedOperationException( "There is no cache size associated with the nexus" );
269 }
270
271
272
273 public void init( DirectoryService directoryService )
274 throws Exception
275 {
276
277 if ( initialized )
278 {
279 return;
280 }
281
282 this.directoryService = directoryService;
283 registries = directoryService.getRegistries();
284 atRegistry = registries.getAttributeTypeRegistry();
285 oidRegistry = registries.getOidRegistry();
286
287 initializeSystemPartition();
288 List<Partition> initializedPartitions = new ArrayList<Partition>();
289 initializedPartitions.add( 0, this.system );
290
291
292 Iterator<? extends Partition> partitions = ( Iterator<? extends Partition> ) directoryService.getPartitions().iterator();
293 try
294 {
295 while ( partitions.hasNext() )
296 {
297 Partition partition = partitions.next();
298 LdapDN adminDn = new LdapDN( ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
299 adminDn.normalize( registries.getAttributeTypeRegistry().getNormalizerMapping() );
300 CoreSession adminSession = new DefaultCoreSession(
301 new LdapPrincipal( adminDn, AuthenticationLevel.STRONG ), directoryService );
302
303 AddContextPartitionOperationContext opCtx =
304 new AddContextPartitionOperationContext( adminSession, partition );
305 addContextPartition( opCtx );
306 initializedPartitions.add( opCtx.getPartition() );
307 }
308 initialized = true;
309 }
310 finally
311 {
312 if ( !initialized )
313 {
314 Iterator<Partition> i = initializedPartitions.iterator();
315 while ( i.hasNext() )
316 {
317 Partition partition = i.next();
318 i.remove();
319 try
320 {
321 partition.destroy();
322 }
323 catch ( Exception e )
324 {
325 LOG.warn( "Failed to destroy a partition: " + partition.getSuffixDn(), e );
326 }
327 finally
328 {
329 unregister( partition );
330 }
331 }
332 }
333 }
334 }
335
336
337 private Partition initializeSystemPartition() throws Exception
338 {
339
340 Partition override = directoryService.getSystemPartition();
341
342 if ( override != null )
343 {
344
345
346
347
348
349 if ( ! override.getId().equals( "system" ) )
350 {
351 throw new ConfigurationException( "System partition has wrong name: should be 'system' not '"
352 + override.getId() + "'." );
353 }
354
355
356 if ( override instanceof JdbmPartition )
357 {
358 Set<Index<?,ServerEntry>> indices = ( ( JdbmPartition ) override ).getIndexedAttributes();
359 Set<String> indexOids = new HashSet<String>();
360 OidRegistry registry = registries.getOidRegistry();
361
362 for ( Index<?,ServerEntry> index : indices )
363 {
364 indexOids.add( registry.getOid( index.getAttributeId() ) );
365 }
366
367 if ( ! indexOids.contains( registry.getOid( SchemaConstants.OBJECT_CLASS_AT ) ) )
368 {
369 LOG.warn( "CAUTION: You have not included objectClass as an indexed attribute" +
370 "in the system partition configuration. This will lead to poor " +
371 "performance. The server is automatically adding this index for you." );
372 JdbmIndex<?,ServerEntry> index = new JdbmIndex<Object,ServerEntry>();
373 index.setAttributeId( SchemaConstants.OBJECT_CLASS_AT );
374 indices.add( index );
375 }
376
377 ( ( JdbmPartition ) override ).setIndexedAttributes( indices );
378 }
379
380 system = override;
381 }
382 else
383 {
384 system = new JdbmPartition();
385 system.setId( "system" );
386 system.setCacheSize( 500 );
387 system.setSuffix( ServerDNConstants.SYSTEM_DN );
388
389
390 Set<Index<?,ServerEntry>> indexedAttrs = new HashSet<Index<?,ServerEntry>>();
391 indexedAttrs.add( new JdbmIndex<Object,ServerEntry>( SchemaConstants.OBJECT_CLASS_AT ) );
392 ( ( JdbmPartition ) system ).setIndexedAttributes( indexedAttrs );
393 }
394
395 system.init( directoryService );
396
397
398
399 LdapDN systemSuffixDn = new LdapDN( ServerDNConstants.SYSTEM_DN );
400 systemSuffixDn.normalize( registries.getAttributeTypeRegistry().getNormalizerMapping() );
401 ServerEntry systemEntry = new DefaultServerEntry( registries, systemSuffixDn );
402
403
404 systemEntry.put( SchemaConstants.OBJECT_CLASS_AT,
405 SchemaConstants.TOP_OC,
406 SchemaConstants.ORGANIZATIONAL_UNIT_OC,
407 SchemaConstants.EXTENSIBLE_OBJECT_OC
408 );
409
410
411 systemEntry.put( SchemaConstants.CREATORS_NAME_AT, ServerDNConstants.ADMIN_SYSTEM_DN );
412 systemEntry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
413 systemEntry.put( NamespaceTools.getRdnAttribute( ServerDNConstants.SYSTEM_DN ),
414 NamespaceTools.getRdnValue( ServerDNConstants.SYSTEM_DN ) );
415 LdapDN adminDn = new LdapDN( ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
416 adminDn.normalize( registries.getAttributeTypeRegistry().getNormalizerMapping() );
417 CoreSession adminSession = new DefaultCoreSession(
418 new LdapPrincipal( adminDn, AuthenticationLevel.STRONG ), directoryService );
419 AddOperationContext addOperationContext = new AddOperationContext( adminSession, systemEntry );
420 system.add( addOperationContext );
421
422 String key = system.getSuffixDn().toString();
423
424 if ( partitions.containsKey( key ) )
425 {
426 throw new ConfigurationException( "Duplicate partition suffix: " + key );
427 }
428
429 synchronized ( partitionLookupTree )
430 {
431 partitions.put( key, system );
432 partitionLookupTree.recursivelyAddPartition( partitionLookupTree, system.getSuffixDn(), 0, system );
433 EntryAttribute namingContexts = rootDSE.get( SchemaConstants.NAMING_CONTEXTS_AT );
434
435 if ( namingContexts == null )
436 {
437 namingContexts = new DefaultServerAttribute(
438 registries.getAttributeTypeRegistry().lookup( SchemaConstants.NAMING_CONTEXTS_AT ),
439 system.getUpSuffixDn().getUpName() );
440 rootDSE.put( namingContexts );
441 }
442 else
443 {
444 namingContexts.add( system.getUpSuffixDn().getUpName() );
445 }
446 }
447
448 return system;
449 }
450
451
452 public boolean isInitialized()
453 {
454 return initialized;
455 }
456
457
458 public synchronized void destroy()
459 {
460 if ( !initialized )
461 {
462 return;
463 }
464
465
466
467 for ( String suffix : new HashSet<String>( this.partitions.keySet() ) )
468 {
469 try
470 {
471 LdapDN adminDn = new LdapDN( ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
472 adminDn.normalize( registries.getAttributeTypeRegistry().getNormalizerMapping() );
473 CoreSession adminSession = new DefaultCoreSession(
474 new LdapPrincipal( adminDn, AuthenticationLevel.STRONG ), directoryService );
475 removeContextPartition( new RemoveContextPartitionOperationContext(
476 adminSession, new LdapDN( suffix ) ) );
477 }
478 catch ( Exception e )
479 {
480 LOG.warn( "Failed to destroy a partition: " + suffix, e );
481 }
482 }
483
484 initialized = false;
485 }
486
487
488
489
490
491 public void sync() throws Exception
492 {
493 MultiException error = null;
494
495 for ( Partition partition : this.partitions.values() )
496 {
497 try
498 {
499 partition.sync();
500 }
501 catch ( Exception e )
502 {
503 LOG.warn( "Failed to flush partition data out.", e );
504 if ( error == null )
505 {
506
507 error = new MultiException( "Grouping many exceptions on root nexus sync()" );
508 }
509
510
511 error.addThrowable( e );
512 }
513 }
514
515 if ( error != null )
516 {
517 throw error;
518 }
519 }
520
521
522
523
524
525
526
527 public boolean compare( CompareOperationContext compareContext ) throws Exception
528 {
529 Partition partition = getPartition( compareContext.getDn() );
530 AttributeTypeRegistry registry = registries.getAttributeTypeRegistry();
531
532
533 if ( !registry.hasAttributeType( compareContext.getOid() ) )
534 {
535 throw new LdapInvalidAttributeIdentifierException( compareContext.getOid() + " not found within the attributeType registry" );
536 }
537
538 AttributeType attrType = registry.lookup( compareContext.getOid() );
539
540 EntryAttribute attr = partition.lookup( compareContext.newLookupContext(
541 compareContext.getDn() ) ).get( attrType.getName() );
542
543
544 if ( attr == null )
545 {
546 throw new LdapNoSuchAttributeException();
547 }
548
549
550 if ( attr.contains( (Value<?>)compareContext.getValue() ) )
551 {
552 return true;
553 }
554
555
556
557
558
559
560
561
562 Normalizer normalizer = attrType.getEquality().getNormalizer();
563 Object reqVal = normalizer.normalize( ((Value<?>)compareContext.getValue()).get() );
564
565 for ( Value<?> value:attr )
566 {
567 Object attrValObj = normalizer.normalize( value.get() );
568
569 if ( attrValObj instanceof String )
570 {
571 String attrVal = ( String ) attrValObj;
572 if ( ( reqVal instanceof String ) && attrVal.equals( reqVal ) )
573 {
574 return true;
575 }
576 }
577 else
578 {
579 byte[] attrVal = ( byte[] ) attrValObj;
580 if ( reqVal instanceof byte[] )
581 {
582 return Arrays.equals( attrVal, ( byte[] ) reqVal );
583 }
584 else if ( reqVal instanceof String )
585 {
586 return Arrays.equals( attrVal, StringTools.getBytesUtf8( ( String ) reqVal ) );
587 }
588 }
589 }
590
591 return false;
592 }
593
594
595 public synchronized void addContextPartition( AddContextPartitionOperationContext opContext ) throws Exception
596 {
597 Partition partition = opContext.getPartition();
598
599
600 String key = partition.getSuffix();
601
602 if ( partitions.containsKey( key ) )
603 {
604 throw new ConfigurationException( "Duplicate partition suffix: " + key );
605 }
606
607 if ( ! partition.isInitialized() )
608 {
609 partition.init( directoryService );
610 }
611
612 synchronized ( partitionLookupTree )
613 {
614 LdapDN partitionSuffix = partition.getSuffixDn();
615
616 if ( partitionSuffix == null )
617 {
618 throw new ConfigurationException( "The current partition does not have any suffix: " + partition.getId() );
619 }
620
621 partitions.put( partitionSuffix.toString(), partition );
622 partitionLookupTree.recursivelyAddPartition( partitionLookupTree, partition.getSuffixDn(), 0, partition );
623
624 EntryAttribute namingContexts = rootDSE.get( SchemaConstants.NAMING_CONTEXTS_AT );
625
626 LdapDN partitionUpSuffix = partition.getUpSuffixDn();
627
628 if ( partitionUpSuffix == null )
629 {
630 throw new ConfigurationException( "The current partition does not have any user provided suffix: " + partition.getId() );
631 }
632
633 if ( namingContexts == null )
634 {
635 namingContexts = new DefaultServerAttribute(
636 registries.getAttributeTypeRegistry().lookup( SchemaConstants.NAMING_CONTEXTS_AT ), partitionUpSuffix.getUpName() );
637 rootDSE.put( namingContexts );
638 }
639 else
640 {
641 namingContexts.add( partitionUpSuffix.getUpName() );
642 }
643 }
644 }
645
646
647 public synchronized void removeContextPartition( RemoveContextPartitionOperationContext removeContextPartition ) throws Exception
648 {
649 String key = removeContextPartition.getDn().getNormName();
650 Partition partition = partitions.get( key );
651
652 if ( partition == null )
653 {
654 throw new NameNotFoundException( "No partition with suffix: " + key );
655 }
656
657 EntryAttribute namingContexts = rootDSE.get( SchemaConstants.NAMING_CONTEXTS_AT );
658
659 if ( namingContexts != null )
660 {
661 namingContexts.remove( partition.getUpSuffixDn().getUpName() );
662 }
663
664
665
666
667
668 synchronized ( partitionLookupTree )
669 {
670 partitions.remove( key );
671 partitionLookupTree = new BranchNode();
672
673 for ( Partition part : partitions.values() )
674 {
675 partitionLookupTree.recursivelyAddPartition( partitionLookupTree, part.getSuffixDn(), 0, partition );
676 }
677
678 partition.sync();
679 partition.destroy();
680 }
681 }
682
683
684 public Partition getSystemPartition()
685 {
686 return system;
687 }
688
689
690
691
692
693 public LdapContext getLdapContext()
694 {
695 throw new NotImplementedException();
696 }
697
698
699
700
701
702 public LdapDN getMatchedName ( GetMatchedNameOperationContext matchedNameContext ) throws Exception
703 {
704 LdapDN dn = ( LdapDN ) matchedNameContext.getDn().clone();
705
706 while ( dn.size() > 0 )
707 {
708 if ( hasEntry( new EntryOperationContext( matchedNameContext.getSession(), dn ) ) )
709 {
710 return dn;
711 }
712
713 dn.remove( dn.size() - 1 );
714 }
715
716 return dn;
717 }
718
719
720 public LdapDN getSuffixDn()
721 {
722 return LdapDN.EMPTY_LDAPDN;
723 }
724
725 public LdapDN getUpSuffixDn()
726 {
727 return LdapDN.EMPTY_LDAPDN;
728 }
729
730
731
732
733
734 public LdapDN getSuffix ( GetSuffixOperationContext getSuffixContext ) throws Exception
735 {
736 Partition backend = getPartition( getSuffixContext.getDn() );
737 return backend.getSuffixDn();
738 }
739
740
741
742
743
744 public Iterator<String> listSuffixes ( ListSuffixOperationContext emptyContext ) throws Exception
745 {
746 return Collections.unmodifiableSet( partitions.keySet() ).iterator();
747 }
748
749
750 public ClonedServerEntry getRootDSE( GetRootDSEOperationContext getRootDSEContext )
751 {
752 return new ClonedServerEntry( rootDSE );
753 }
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769 private void unregister( Partition partition ) throws Exception
770 {
771 EntryAttribute namingContexts = rootDSE.get( SchemaConstants.NAMING_CONTEXTS_AT );
772
773 if ( namingContexts != null )
774 {
775 namingContexts.remove( partition.getSuffixDn().getUpName() );
776 }
777
778 partitions.remove( partition.getSuffixDn().toString() );
779 }
780
781
782
783
784
785 public void bind( BindOperationContext bindContext ) throws Exception
786 {
787 Partition partition = getPartition( bindContext.getDn() );
788 partition.bind( bindContext );
789 }
790
791 public void unbind( UnbindOperationContext unbindContext ) throws Exception
792 {
793 Partition partition = getPartition( unbindContext.getDn() );
794 partition.unbind( unbindContext );
795 }
796
797
798
799
800
801 public void delete( DeleteOperationContext deleteContext ) throws Exception
802 {
803 Partition backend = getPartition( deleteContext.getDn() );
804 backend.delete( deleteContext );
805 }
806
807
808
809
810
811
812
813
814
815
816
817 public void add( AddOperationContext addContext ) throws Exception
818 {
819 Partition backend = getPartition( addContext.getDn() );
820 backend.add( addContext );
821 }
822
823
824 public void modify( ModifyOperationContext modifyContext ) throws Exception
825 {
826 Partition backend = getPartition( modifyContext.getDn() );
827 backend.modify( modifyContext );
828 }
829
830
831
832
833
834 public EntryFilteringCursor list( ListOperationContext opContext ) throws Exception
835 {
836 Partition backend = getPartition( opContext.getDn() );
837 return backend.list( opContext );
838 }
839
840
841 public EntryFilteringCursor search( SearchOperationContext opContext )
842 throws Exception
843 {
844 LdapDN base = opContext.getDn();
845 SearchControls searchCtls = opContext.getSearchControls();
846 ExprNode filter = opContext.getFilter();
847
848
849
850
851 if ( base.size() == 0 )
852 {
853 boolean isObjectScope = searchCtls.getSearchScope() == SearchControls.OBJECT_SCOPE;
854
855
856 boolean isSearchAll = false;
857
858
859 if ( filter instanceof PresenceNode )
860 {
861 isSearchAll = ( ( PresenceNode ) filter ).getAttribute().equals( SchemaConstants.OBJECT_CLASS_AT_OID );
862 }
863
864
865
866
867
868 if ( filter instanceof PresenceNode && isObjectScope && isSearchAll )
869 {
870 String[] ids = searchCtls.getReturningAttributes();
871
872
873
874
875
876 if ( ( ids == null ) || ( ids.length == 0 ) )
877 {
878 ServerEntry rootDSE = (ServerEntry)getRootDSE( null ).clone();
879 return new BaseEntryFilteringCursor( new SingletonCursor<ServerEntry>( rootDSE ), opContext );
880 }
881
882
883
884
885
886
887 Set<String> realIds = new HashSet<String>();
888 boolean containsAsterisk = false;
889 boolean containsPlus = false;
890 boolean containsOneDotOne = false;
891
892 for ( String id:ids )
893 {
894 String idTrimmed = id.trim();
895
896 if ( idTrimmed.equals( SchemaConstants.ALL_USER_ATTRIBUTES ) )
897 {
898 containsAsterisk = true;
899 }
900 else if ( idTrimmed.equals( SchemaConstants.ALL_OPERATIONAL_ATTRIBUTES ) )
901 {
902 containsPlus = true;
903 }
904 else if ( idTrimmed.equals( SchemaConstants.NO_ATTRIBUTE ) )
905 {
906 containsOneDotOne = true;
907 }
908 else
909 {
910 try
911 {
912 realIds.add( oidRegistry.getOid( idTrimmed ) );
913 }
914 catch ( Exception e )
915 {
916 realIds.add( idTrimmed );
917 }
918 }
919 }
920
921
922 if ( containsOneDotOne )
923 {
924 ServerEntry serverEntry = new DefaultServerEntry( registries, base );
925 return new BaseEntryFilteringCursor( new SingletonCursor<ServerEntry>( serverEntry ), opContext );
926 }
927
928
929 if ( containsAsterisk && containsPlus )
930 {
931 ServerEntry rootDSE = (ServerEntry)getRootDSE( null ).clone();
932 return new BaseEntryFilteringCursor( new SingletonCursor<ServerEntry>( rootDSE ), opContext );
933 }
934
935 ServerEntry serverEntry = new DefaultServerEntry( registries, opContext.getDn() );
936
937 ServerEntry rootDSE = getRootDSE( new GetRootDSEOperationContext( opContext.getSession() ) );
938
939 for ( EntryAttribute attribute:rootDSE )
940 {
941 AttributeType type = atRegistry.lookup( attribute.getUpId() );
942
943 if ( realIds.contains( type.getOid() ) )
944 {
945 serverEntry.put( attribute );
946 }
947 else if ( containsAsterisk && ( type.getUsage() == UsageEnum.USER_APPLICATIONS ) )
948 {
949 serverEntry.put( attribute );
950 }
951 else if ( containsPlus && ( type.getUsage() != UsageEnum.USER_APPLICATIONS ) )
952 {
953 serverEntry.put( attribute );
954 }
955 }
956
957 return new BaseEntryFilteringCursor( new SingletonCursor<ServerEntry>( serverEntry ), opContext );
958 }
959
960
961 throw new LdapNameNotFoundException();
962 }
963
964 Partition backend = getPartition( base );
965 return backend.search( opContext );
966 }
967
968
969 public ClonedServerEntry lookup( LookupOperationContext opContext ) throws Exception
970 {
971 LdapDN dn = opContext.getDn();
972
973 if ( dn.size() == 0 )
974 {
975 ClonedServerEntry retval = new ClonedServerEntry( rootDSE );
976 Set<AttributeType> attributeTypes = rootDSE.getAttributeTypes();
977
978 if ( opContext.getAttrsId() != null && ! opContext.getAttrsId().isEmpty() )
979 {
980 for ( AttributeType attributeType:attributeTypes )
981 {
982 String oid = attributeType.getOid();
983
984 if ( ! opContext.getAttrsId().contains( oid ) )
985 {
986 retval.removeAttributes( attributeType );
987 }
988 }
989 return retval;
990 }
991 else
992 {
993 return new ClonedServerEntry( rootDSE );
994 }
995 }
996
997 Partition backend = getPartition( dn );
998 return backend.lookup( opContext );
999 }
1000
1001
1002
1003
1004
1005 public boolean hasEntry( EntryOperationContext opContext ) throws Exception
1006 {
1007 LdapDN dn = opContext.getDn();
1008
1009 if ( IS_DEBUG )
1010 {
1011 LOG.debug( "Check if DN '" + dn + "' exists." );
1012 }
1013
1014 if ( dn.size() == 0 )
1015 {
1016 return true;
1017 }
1018
1019 Partition backend = getPartition( dn );
1020 return backend.hasEntry( opContext );
1021 }
1022
1023
1024
1025
1026
1027 public void rename( RenameOperationContext opContext ) throws Exception
1028 {
1029 Partition backend = getPartition( opContext.getDn() );
1030 backend.rename( opContext );
1031 }
1032
1033
1034
1035
1036
1037 public void move( MoveOperationContext opContext ) throws Exception
1038 {
1039 Partition backend = getPartition( opContext.getDn() );
1040 backend.move( opContext );
1041 }
1042
1043
1044 public void moveAndRename( MoveAndRenameOperationContext opContext ) throws Exception
1045 {
1046 Partition backend = getPartition( opContext.getDn() );
1047 backend.moveAndRename( opContext );
1048 }
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058 public Partition getPartition( LdapDN dn ) throws Exception
1059 {
1060 Enumeration<String> rdns = dn.getAll();
1061
1062
1063
1064 synchronized ( partitionLookupTree )
1065 {
1066 Node currentNode = partitionLookupTree;
1067
1068
1069 while ( rdns.hasMoreElements() )
1070 {
1071 String rdn = rdns.nextElement();
1072
1073 if ( currentNode == null )
1074 {
1075 break;
1076 }
1077
1078 if ( currentNode instanceof LeafNode )
1079 {
1080 return ( ( LeafNode ) currentNode ).getPartition();
1081 }
1082
1083 BranchNode currentBranch = ( BranchNode ) currentNode;
1084
1085 if ( currentBranch.contains( rdn ) )
1086 {
1087 currentNode = currentBranch.getChild( rdn );
1088
1089 if ( currentNode instanceof LeafNode )
1090 {
1091 return ( ( LeafNode ) currentNode ).getPartition();
1092 }
1093 }
1094 }
1095 }
1096
1097 throw new LdapNameNotFoundException( dn.getUpName() );
1098 }
1099
1100
1101 public void registerSupportedExtensions( Set<String> extensionOids ) throws Exception
1102 {
1103 EntryAttribute supportedExtension = rootDSE.get( SchemaConstants.SUPPORTED_EXTENSION_AT );
1104
1105 if ( supportedExtension == null )
1106 {
1107 rootDSE.set( SchemaConstants.SUPPORTED_EXTENSION_AT );
1108 supportedExtension = rootDSE.get( SchemaConstants.SUPPORTED_EXTENSION_AT );
1109 }
1110
1111 for ( String extensionOid : extensionOids )
1112 {
1113 supportedExtension.add( extensionOid );
1114 }
1115 }
1116
1117
1118 public void registerSupportedSaslMechanisms( Set<String> supportedSaslMechanisms ) throws Exception
1119 {
1120 EntryAttribute supportedSaslMechanismsAttribute = rootDSE.get( SchemaConstants.SUPPORTED_SASL_MECHANISMS_AT );
1121
1122 if ( supportedSaslMechanismsAttribute == null )
1123 {
1124 rootDSE.set( SchemaConstants.SUPPORTED_SASL_MECHANISMS_AT );
1125 supportedSaslMechanismsAttribute = rootDSE.get( SchemaConstants.SUPPORTED_SASL_MECHANISMS_AT );
1126 }
1127
1128 for ( String saslMechanism : supportedSaslMechanisms )
1129 {
1130 supportedSaslMechanismsAttribute.add( saslMechanism );
1131 }
1132 }
1133
1134
1135 public ClonedServerEntry lookup( Long id ) throws Exception
1136 {
1137
1138
1139 throw new NotImplementedException();
1140 }
1141 }