View Javadoc

1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.server.core.partition;
21  
22  
23  import java.util.Collection;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.Set;
27  
28  import javax.naming.Context;
29  import javax.naming.ServiceUnavailableException;
30  import javax.naming.directory.SearchControls;
31  import javax.naming.ldap.LdapContext;
32  
33  import org.apache.directory.server.core.DirectoryService;
34  import org.apache.directory.server.core.entry.ClonedServerEntry;
35  import org.apache.directory.server.core.entry.ServerEntry;
36  import org.apache.directory.server.core.filtering.EntryFilter;
37  import org.apache.directory.server.core.filtering.EntryFilteringCursor;
38  import org.apache.directory.server.core.interceptor.InterceptorChain;
39  import org.apache.directory.server.core.interceptor.context.AddContextPartitionOperationContext;
40  import org.apache.directory.server.core.interceptor.context.AddOperationContext;
41  import org.apache.directory.server.core.interceptor.context.BindOperationContext;
42  import org.apache.directory.server.core.interceptor.context.CompareOperationContext;
43  import org.apache.directory.server.core.interceptor.context.DeleteOperationContext;
44  import org.apache.directory.server.core.interceptor.context.EntryOperationContext;
45  import org.apache.directory.server.core.interceptor.context.GetMatchedNameOperationContext;
46  import org.apache.directory.server.core.interceptor.context.GetRootDSEOperationContext;
47  import org.apache.directory.server.core.interceptor.context.GetSuffixOperationContext;
48  import org.apache.directory.server.core.interceptor.context.ListOperationContext;
49  import org.apache.directory.server.core.interceptor.context.ListSuffixOperationContext;
50  import org.apache.directory.server.core.interceptor.context.LookupOperationContext;
51  import org.apache.directory.server.core.interceptor.context.ModifyOperationContext;
52  import org.apache.directory.server.core.interceptor.context.MoveAndRenameOperationContext;
53  import org.apache.directory.server.core.interceptor.context.MoveOperationContext;
54  import org.apache.directory.server.core.interceptor.context.OperationContext;
55  import org.apache.directory.server.core.interceptor.context.RemoveContextPartitionOperationContext;
56  import org.apache.directory.server.core.interceptor.context.RenameOperationContext;
57  import org.apache.directory.server.core.interceptor.context.SearchOperationContext;
58  import org.apache.directory.server.core.interceptor.context.SearchingOperationContext;
59  import org.apache.directory.server.core.interceptor.context.UnbindOperationContext;
60  import org.apache.directory.server.core.invocation.InvocationStack;
61  import org.apache.directory.shared.ldap.NotImplementedException;
62  import org.apache.directory.shared.ldap.constants.SchemaConstants;
63  import org.apache.directory.shared.ldap.exception.LdapSizeLimitExceededException;
64  import org.apache.directory.shared.ldap.exception.LdapTimeLimitExceededException;
65  import org.apache.directory.shared.ldap.name.LdapDN;
66  
67  
68  /**
69   * A decorator that wraps other {@link PartitionNexus} to enable
70   * {@link InterceptorChain} and {@link InvocationStack} support.
71   * All {@link Invocation}s made to this nexus is automatically pushed to
72   * {@link InvocationStack} of the current thread, and popped when
73   * the operation ends.  All invocations are filtered by {@link InterceptorChain}.
74   *
75   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
76   * @version $Rev: 669073 $, $Date: 2008-06-18 05:49:58 +0200 (Mi, 18 Jun 2008) $
77   */
78  public class PartitionNexusProxy extends PartitionNexus
79  {
80  
81      /**
82       * A static object to store the rootDSE entry with all the attributes
83       */
84      private static ServerEntry ROOT_DSE_ALL;
85  
86      /**
87       * A static object to store the rootDSE entry without operationnal attributes
88       */
89      private static ServerEntry ROOT_DSE_NO_OPERATIONNAL;
90  
91      /**
92       * A mutex to protect the rootDSE construction
93       */
94      private static final Object ROOT_DSE_ALL_MUTEX = new Object();
95  
96      /**
97       * A mutex to protect the rootDSE construction
98       */
99      private static final Object ROOT_DSE_NOOP_MUTEX = new Object();
100 
101     private final DirectoryService service;
102 
103 
104     /**
105      * Creates a new instance.
106      *
107      * @param caller  a JNDI {@link Context} object that will call this proxy
108      * @param service a JNDI service
109      */
110     public PartitionNexusProxy( DirectoryService service ) throws Exception
111     {
112         this.service = service;
113     }
114 
115 
116     public LdapContext getLdapContext()
117     {
118         return service.getPartitionNexus().getLdapContext();
119     }
120 
121 
122     public String getId()
123     {
124         throw new UnsupportedOperationException( "Nexus partition proxy objects do not have an Id." );
125     }
126 
127 
128     public void setId( String id )
129     {
130         throw new UnsupportedOperationException( "Not supported by PartitionNexusProxy" );
131     }
132 
133 
134     public ClonedServerEntry getContextEntry()
135     {
136         throw new UnsupportedOperationException( "Not supported by PartitionNexusProxy" );
137     }
138 
139 
140     public void setContextEntry( ServerEntry contextEntry )
141     {
142         throw new UnsupportedOperationException( "Not supported by PartitionNexusProxy" );
143     }
144 
145 
146     public String getSuffix()
147     {
148         throw new UnsupportedOperationException( "Not supported by PartitionNexusProxy" );
149     }
150 
151 
152     public void setSuffix( String suffix )
153     {
154         throw new UnsupportedOperationException( "Not supported by PartitionNexusProxy" );
155     }
156 
157 
158     public void setCacheSize( int cacheSize )
159     {
160         throw new UnsupportedOperationException( "Not supported by PartitionNexusProxy" );
161     }
162 
163 
164     public int getCacheSize()
165     {
166         throw new UnsupportedOperationException( "Not supported by PartitionNexusProxy" );
167     }
168 
169 
170     public void init( DirectoryService core ) throws Exception
171     {
172     }
173 
174 
175     public void destroy()
176     {
177     }
178 
179 
180     public Partition getSystemPartition()
181     {
182         return service.getPartitionNexus().getSystemPartition();
183     }
184 
185 
186     public Partition getPartition( LdapDN dn ) throws Exception
187     {
188         return service.getPartitionNexus().getPartition( dn );
189     }
190 
191 
192     public LdapDN getSuffixDn() throws Exception
193     {
194         return service.getPartitionNexus().getSuffixDn();
195     }
196 
197     public LdapDN getUpSuffixDn() throws Exception
198     {
199         return service.getPartitionNexus().getUpSuffixDn();
200     }
201 
202 
203     public void sync() throws Exception
204     {
205         this.service.sync();
206     }
207 
208 
209     public void close() throws Exception
210     {
211         this.service.shutdown();
212     }
213 
214 
215     public boolean isInitialized()
216     {
217         return this.service.isStarted();
218     }
219 
220 
221     public LdapDN getMatchedName( GetMatchedNameOperationContext opContext ) throws Exception
222     {
223         return getMatchedName( opContext, null );
224     }
225     
226     
227     private void push( OperationContext opContext )
228     {
229         InvocationStack.getInstance().push( opContext );
230     }
231     
232     
233     private OperationContext pop()
234     {
235         return InvocationStack.getInstance().pop();
236     }
237 
238 
239     public LdapDN getMatchedName( GetMatchedNameOperationContext opContext, Collection<String> byPassed ) throws Exception
240     {
241         ensureStarted();
242         opContext.setByPassed( byPassed );
243         push( opContext );
244         
245         try
246         {
247             return service.getInterceptorChain().getMatchedName( opContext );
248         }
249         finally
250         {
251             pop();
252         }
253     }
254 
255 
256     public LdapDN getSuffix( GetSuffixOperationContext opContext ) throws Exception
257     {
258         return getSuffix( opContext, null );
259     }
260 
261 
262     public LdapDN getSuffix( GetSuffixOperationContext opContext, Collection<String> byPassed ) throws Exception
263     {
264         ensureStarted();
265         opContext.setByPassed( byPassed );
266         push( opContext );
267         
268         try
269         {
270             return service.getInterceptorChain().getSuffix( opContext );
271         }
272         finally
273         {
274             pop();
275         }
276     }
277 
278 
279     public Iterator<String> listSuffixes( ListSuffixOperationContext opContext ) throws Exception
280     {
281         return listSuffixes( opContext, null );
282     }
283 
284 
285     public Iterator<String> listSuffixes( ListSuffixOperationContext opContext, Collection<String> byPassed ) throws Exception
286     {
287         ensureStarted();
288         opContext.setByPassed( byPassed );
289         push( opContext );
290         
291         try
292         {
293             return service.getInterceptorChain().listSuffixes( opContext );
294         }
295         finally
296         {
297             pop();
298         }
299     }
300 
301 
302     public boolean compare( CompareOperationContext opContext ) throws Exception
303     {
304         return compare( opContext, null );
305     }
306 
307 
308     public boolean compare( CompareOperationContext opContext, Collection<String> byPassed ) throws Exception
309     {
310         ensureStarted();
311         opContext.setByPassed( byPassed );
312         push( opContext );
313         
314         try
315         {
316             return service.getInterceptorChain().compare( opContext );
317         }
318         finally
319         {
320             pop();
321         }
322     }
323 
324 
325     public void delete( DeleteOperationContext opContext ) throws Exception
326     {
327         delete( opContext, null );
328     }
329 
330 
331     public void delete( DeleteOperationContext opContext, Collection<String> byPassed ) throws Exception
332     {
333         ensureStarted();
334         opContext.setByPassed( byPassed );
335         push( opContext );
336         
337         try
338         {
339             service.getInterceptorChain().delete( opContext );
340         }
341         finally
342         {
343             pop();
344         }
345     }
346 
347 
348     public void add( AddOperationContext opContext ) throws Exception
349     {
350         add( opContext, null );
351     }
352 
353 
354     public void add( AddOperationContext opContext, Collection<String> byPassed ) throws Exception
355     {
356         ensureStarted();
357         opContext.setByPassed( byPassed );
358         push( opContext );
359         
360         try
361         {
362             service.getInterceptorChain().add( opContext );
363         }
364         finally
365         {
366             pop();
367         }
368     }
369 
370 
371     public void modify( ModifyOperationContext opContext ) throws Exception
372     {
373         modify( opContext, null );
374     }
375 
376 
377     public void modify( ModifyOperationContext opContext, Collection<String> byPassed ) throws Exception
378     {
379         ensureStarted();
380         opContext.setByPassed( byPassed );
381         push( opContext );
382         
383         try
384         {
385             service.getInterceptorChain().modify( opContext );
386         }
387         finally
388         {
389             pop();
390         }
391     }
392 
393 
394     public EntryFilteringCursor list( ListOperationContext opContext ) throws Exception
395     {
396         return list( opContext, null );
397     }
398 
399 
400     public EntryFilteringCursor list( ListOperationContext opContext, Collection<String> byPassed ) throws Exception
401     {
402         ensureStarted();
403         opContext.setByPassed( byPassed );
404         push( opContext );
405         
406         try
407         {
408             return service.getInterceptorChain().list( opContext );
409         }
410         finally
411         {
412             pop();
413         }
414     }
415 
416 
417     public EntryFilteringCursor search( SearchOperationContext opContext ) throws Exception
418     {
419         EntryFilteringCursor cursor = search( opContext, null );
420         final SearchControls searchCtls = opContext.getSearchControls();
421 
422         if ( searchCtls.getTimeLimit() + searchCtls.getCountLimit() > 0 )
423         {
424             // this will be the last filter added so other filters before it must
425             // have passed/approved of the entry to be returned back to the client
426             // so the candidate we have is going to be returned for sure
427             cursor.addEntryFilter( new EntryFilter()
428             {
429                 final long startTime = System.currentTimeMillis();
430                 int count = 0; // with prefetch we've missed one which is ok since 1 is the minimum
431 
432                 public boolean accept( SearchingOperationContext operation, ClonedServerEntry entry )
433                         throws Exception
434                 {
435                     if ( searchCtls.getTimeLimit() > 0 )
436                     {
437                         long runtime = System.currentTimeMillis() - startTime;
438                         if ( runtime > searchCtls.getTimeLimit() )
439                         {
440                             throw new LdapTimeLimitExceededException();
441                         }
442                     }
443 
444                     if ( searchCtls.getCountLimit() > 0 )
445                     {
446                         if ( count > searchCtls.getCountLimit() )
447                         {
448                             throw new LdapSizeLimitExceededException();
449                         }
450                     }
451 
452                     count++;
453                     return true;
454                 }
455             } );
456         }
457 
458         return cursor;
459     }
460 
461 
462     public EntryFilteringCursor search( SearchOperationContext opContext, Collection<String> byPassed )
463             throws Exception
464     {
465         ensureStarted();
466         opContext.setByPassed( byPassed );
467         push( opContext );
468         
469         try
470         {
471             return service.getInterceptorChain().search( opContext );
472         }
473         finally
474         {
475             pop();
476         }
477     }
478 
479 
480     public ClonedServerEntry lookup( LookupOperationContext opContext ) throws Exception
481     {
482         if ( opContext.getDn().size() == 0 )
483         {
484             List<String> attrs = opContext.getAttrsId();
485 
486             if ( ( attrs == null ) || ( attrs.size() == 0 ) )
487             {
488                 synchronized ( ROOT_DSE_NOOP_MUTEX )
489                 {
490                     if ( ROOT_DSE_NO_OPERATIONNAL == null )
491                     {
492                         ROOT_DSE_NO_OPERATIONNAL = lookup( opContext, null );
493                     }
494                 }
495 
496                 return new ClonedServerEntry( ROOT_DSE_NO_OPERATIONNAL );
497             } 
498             else if ( ( attrs.size() == 1 ) && ( attrs.contains( SchemaConstants.ALL_OPERATIONAL_ATTRIBUTES ) ) )
499             {
500                 synchronized ( ROOT_DSE_ALL_MUTEX )
501                 {
502                     if ( ROOT_DSE_ALL == null )
503                     {
504                         ROOT_DSE_ALL = lookup( opContext, null );
505                     }
506                 }
507 
508                 return new ClonedServerEntry( ROOT_DSE_ALL );
509             }
510 
511         }
512 
513         return lookup( opContext, null );
514     }
515 
516 
517     public ClonedServerEntry lookup( LookupOperationContext opContext, Collection<String> byPassed ) throws Exception
518     {
519         ensureStarted();
520         opContext.setByPassed( byPassed );
521         push( opContext );
522         
523         try
524         {
525             return service.getInterceptorChain().lookup( opContext );
526         }
527         finally
528         {
529             pop();
530         }
531     }
532 
533     public boolean hasEntry( EntryOperationContext opContext ) throws Exception
534     {
535         return hasEntry( opContext, null );
536     }
537 
538 
539     public boolean hasEntry( EntryOperationContext opContext, Collection<String> byPassed ) throws Exception
540     {
541         ensureStarted();
542         opContext.setByPassed( byPassed );
543         push( opContext );
544         
545         try
546         {
547             return service.getInterceptorChain().hasEntry( opContext );
548         }
549         finally
550         {
551             pop();
552         }
553     }
554 
555 
556     public void rename( RenameOperationContext opContext ) throws Exception
557     {
558         rename( opContext, null );
559     }
560 
561 
562     public void rename( RenameOperationContext opContext, Collection<String> byPassed ) throws Exception
563     {
564         ensureStarted();
565         opContext.setByPassed( byPassed );
566         push( opContext );
567         
568         try
569         {
570             service.getInterceptorChain().rename( opContext );
571         }
572         finally
573         {
574             pop();
575         }
576     }
577 
578 
579     public void move( MoveOperationContext opContext ) throws Exception
580     {
581         move( opContext, null );
582     }
583 
584 
585     public void move( MoveOperationContext opContext, Collection<String> byPassed ) throws Exception
586     {
587         ensureStarted();
588         opContext.setByPassed( byPassed );
589         push( opContext );
590         
591         try
592         {
593             service.getInterceptorChain().move( opContext );
594         }
595         finally
596         {
597             pop();
598         }
599     }
600 
601 
602     public void moveAndRename( MoveAndRenameOperationContext opContext ) throws Exception
603     {
604         moveAndRename( opContext, null );
605     }
606 
607 
608     public void moveAndRename( MoveAndRenameOperationContext opContext, Collection<String> byPassed )
609             throws Exception
610     {
611         ensureStarted();
612         opContext.setByPassed( byPassed );
613         push( opContext );
614         
615         try
616         {
617             service.getInterceptorChain().moveAndRename( opContext );
618         }
619         finally
620         {
621             pop();
622         }
623     }
624 
625     /**
626      * TODO : check if we can find another way to protect ourselves from recursion.
627      *
628      * @param opContext The operation context
629      * @param byPassed bypass instructions to skip interceptors
630      * @throws Exception if bind fails
631      */
632     public void bind( BindOperationContext opContext, Collection<String> byPassed )
633             throws Exception
634     {
635         ensureStarted();
636         opContext.setByPassed( byPassed );
637         push( opContext );
638         
639         try
640         {
641             service.getInterceptorChain().bind( opContext );
642         }
643         finally
644         {
645             pop();
646         }
647     }
648 
649 
650     public void unbind( UnbindOperationContext opContext, Collection<String> byPassed ) throws Exception
651     {
652         ensureStarted();
653         opContext.setByPassed( byPassed );
654         push( opContext );
655         
656         try
657         {
658             service.getInterceptorChain().unbind( opContext );
659         }
660         finally
661         {
662             pop();
663         }
664     }
665 
666 
667     public void bind( BindOperationContext opContext ) throws Exception
668     {
669         bind( opContext, null );
670     }
671 
672 
673     public void unbind( UnbindOperationContext opContext ) throws Exception
674     {
675         unbind( opContext, null );
676     }
677 
678 
679     public ClonedServerEntry getRootDSE( GetRootDSEOperationContext opContext ) throws Exception
680     {
681         if ( opContext.getDn().size() == 0 )
682         {
683             synchronized ( ROOT_DSE_ALL_MUTEX )
684             {
685                 if ( ROOT_DSE_ALL == null )
686                 {
687                     ROOT_DSE_ALL = getRootDSE( opContext, null );
688                 }
689             }
690 
691             return new ClonedServerEntry( ROOT_DSE_ALL );
692         }
693 
694         return getRootDSE( opContext, null );
695     }
696 
697 
698     public ClonedServerEntry getRootDSE( GetRootDSEOperationContext opContext, Collection<String> byPassed )
699             throws Exception
700     {
701         ensureStarted();
702         opContext.setByPassed( byPassed );
703         push( opContext );
704         
705         try
706         {
707             return service.getInterceptorChain().getRootDSE( opContext );
708         }
709         finally
710         {
711             pop();
712         }
713     }
714 
715 
716     public void addContextPartition( AddContextPartitionOperationContext opContext ) throws Exception
717     {
718         addContextPartition( opContext, null );
719     }
720 
721 
722     public void addContextPartition( AddContextPartitionOperationContext opContext, Collection<String> byPassed )
723             throws Exception
724     {
725         ensureStarted();
726         opContext.setByPassed( byPassed );
727         push( opContext );
728         
729         try
730         {
731             service.getInterceptorChain().addContextPartition( opContext );
732         }
733         finally
734         {
735             pop();
736         }
737     }
738 
739 
740     public void removeContextPartition( RemoveContextPartitionOperationContext opContext ) throws Exception
741     {
742         removeContextPartition( opContext, null );
743     }
744 
745 
746     public void removeContextPartition( RemoveContextPartitionOperationContext opContext, Collection<String> byPassed )
747             throws Exception
748     {
749         ensureStarted();
750         opContext.setByPassed( byPassed );
751         push( opContext );
752         
753         try
754         {
755             service.getInterceptorChain().removeContextPartition( opContext );
756         }
757         finally
758         {
759             pop();
760         }
761     }
762 
763 
764     private void ensureStarted() throws ServiceUnavailableException
765     {
766         if ( !service.isStarted() )
767         {
768             throw new ServiceUnavailableException( "Directory service is not started." );
769         }
770     }
771 
772 
773     public void registerSupportedExtensions( Set<String> extensionOids ) throws Exception
774     {
775         service.getPartitionNexus().registerSupportedExtensions( extensionOids );
776     }
777 
778 
779     public void registerSupportedSaslMechanisms( Set<String> supportedSaslMechanisms ) throws Exception
780     {
781         service.getPartitionNexus().registerSupportedSaslMechanisms( supportedSaslMechanisms );
782     }
783 
784 
785     public ClonedServerEntry lookup( Long id ) throws Exception
786     {
787         // TODO not implemented until we can lookup partition using the 
788         // partition id component of the 64 bit identifier
789         throw new NotImplementedException();
790     }
791 }