View Javadoc

1   /*
2    *   Copyright 2004 The Apache Software Foundation
3    *
4    *   Licensed under the Apache License, Version 2.0 (the "License");
5    *   you may not use this file except in compliance with the License.
6    *   You may obtain a copy of the License at
7    *
8    *       http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *   Unless required by applicable law or agreed to in writing, software
11   *   distributed under the License is distributed on an "AS IS" BASIS,
12   *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *   See the License for the specific language governing permissions and
14   *   limitations under the License.
15   *
16   */
17  package org.apache.ldap.server.partition;
18  
19  
20  import java.util.*;
21  
22  import javax.naming.Context;
23  import javax.naming.Name;
24  import javax.naming.NamingEnumeration;
25  import javax.naming.NamingException;
26  import javax.naming.ServiceUnavailableException;
27  import javax.naming.directory.Attributes;
28  import javax.naming.directory.ModificationItem;
29  import javax.naming.directory.SearchControls;
30  import javax.naming.directory.DirContext;
31  import javax.naming.event.EventContext;
32  import javax.naming.event.NamingListener;
33  import javax.naming.ldap.LdapContext;
34  
35  import org.apache.ldap.common.filter.ExprNode;
36  import org.apache.ldap.server.DirectoryServiceConfiguration;
37  import org.apache.ldap.server.DirectoryService;
38  import org.apache.ldap.server.configuration.DirectoryPartitionConfiguration;
39  import org.apache.ldap.server.event.EventService;
40  import org.apache.ldap.server.interceptor.InterceptorChain;
41  import org.apache.ldap.server.invocation.Invocation;
42  import org.apache.ldap.server.invocation.InvocationStack;
43  
44  
45  /***
46   * A decorator that wraps other {@link DirectoryPartitionNexus} to enable
47   * {@link InterceptorChain} and {@link InvocationStack} support.
48   * All {@link Invocation}s made to this nexus is automatically pushed to
49   * {@link InvocationStack} of the current thread, and popped when
50   * the operation ends.  All invocations are filtered by {@link InterceptorChain}.
51   *
52   * @author The Apache Directory Project
53   * @version $Rev: 326825 $, $Date: 2005-10-20 01:09:43 -0400 (Thu, 20 Oct 2005) $
54   */
55  public class DirectoryPartitionNexusProxy extends DirectoryPartitionNexus
56  {
57      /*** safe to use set of bypass instructions to lookup raw entries */
58      public static final Collection LOOKUP_BYPASS;
59      /*** safe to use set of bypass instructions to getMatchedDn */
60      public static final Collection GETMATCHEDDN_BYPASS;
61      /*** Bypass String to use when ALL interceptors should be skipped */
62      public static final String BYPASS_ALL = "*";
63      /*** Bypass String to use when ALL interceptors should be skipped */
64      public static final Collection BYPASS_ALL_COLLECTION = Collections.singleton( BYPASS_ALL );
65      /*** Integer const for DirContext.ADD_ATTRIBUTE */
66      private static final Integer ADD_MODOP = new Integer( DirContext.ADD_ATTRIBUTE );
67      /*** Integer const for DirContext.REMOVE_ATTRIBUTE */
68      private static final Integer REMOVE_MODOP = new Integer( DirContext.REMOVE_ATTRIBUTE );
69      /*** Integer const for DirContext.REPLACE_ATTRIBUTE */
70      private static final Integer REPLACE_MODOP = new Integer( DirContext.REPLACE_ATTRIBUTE );
71  
72      private final Context caller;
73      private final DirectoryService service;
74      private final DirectoryServiceConfiguration configuration;
75  
76  
77      static
78      {
79          Collection c = new HashSet();
80          c.add( "normalizationService" );
81          c.add( "authenticationService" );
82          c.add( "authorizationService" );
83          c.add( "oldAuthorizationService" );
84          c.add( "schemaService" );
85          c.add( "subentryService" );
86          c.add( "operationalAttributeService" );
87          c.add( "eventService" );
88          LOOKUP_BYPASS = Collections.unmodifiableCollection( c );
89  
90          c = new HashSet();
91          c.add( "authenticationService" );
92          c.add( "authorizationService" );
93          c.add( "oldAuthorizationService" );
94          c.add( "schemaService" );
95          c.add( "subentryService" );
96          c.add( "operationalAttributeService" );
97          c.add( "eventService" );
98          GETMATCHEDDN_BYPASS = Collections.unmodifiableCollection( c );
99      }
100 
101 
102     /***
103      * Creates a new instance.
104      * 
105      * @param caller a JNDI {@link Context} object that will call this proxy
106      * @param service a JNDI service
107      */
108     public DirectoryPartitionNexusProxy( Context caller, DirectoryService service )
109     {
110         this.caller = caller;
111         this.service = service;
112         this.configuration = service.getConfiguration();
113     }
114     
115     public LdapContext getLdapContext() {
116         return this.configuration.getPartitionNexus().getLdapContext();
117     }
118 
119     public void init( DirectoryServiceConfiguration factoryCfg, DirectoryPartitionConfiguration cfg )
120     {
121     }
122 
123     public void destroy()
124     {
125     }
126 
127     public DirectoryPartition getSystemPartition()
128     {
129         return this.configuration.getPartitionNexus().getSystemPartition();
130     }
131 
132     public Name getSuffix( boolean normalized ) throws NamingException
133     {
134         return this.configuration.getPartitionNexus().getSuffix( normalized );
135     }
136 
137     public void sync() throws NamingException {
138         this.service.sync();
139     }
140 
141     public void close() throws NamingException {
142         this.service.shutdown();
143     }
144 
145     public boolean isInitialized() {
146         return this.service.isStarted();
147     }
148 
149 
150     public Name getMatchedName( Name dn, boolean normalized ) throws NamingException
151     {
152         return getMatchedName( dn, normalized, null );
153     }
154 
155 
156     public Name getMatchedName( Name dn, boolean normalized, Collection bypass ) throws NamingException
157     {
158         ensureStarted();
159         InvocationStack stack = InvocationStack.getInstance();
160         Object[] args = new Object[] { dn, normalized? Boolean.TRUE : Boolean.FALSE };
161         stack.push( new Invocation( this, caller, "getMatchedDn", args, bypass ) );
162         try
163         {
164             return this.configuration.getInterceptorChain().getMatchedName( dn, normalized );
165         }
166         finally
167         {
168             stack.pop();
169         }
170     }
171 
172 
173     public Name getSuffix( Name dn, boolean normalized) throws NamingException
174     {
175         return getSuffix( dn, normalized, null );
176     }
177 
178 
179     public Name getSuffix( Name dn, boolean normalized, Collection bypass ) throws NamingException
180     {
181         ensureStarted();
182         InvocationStack stack = InvocationStack.getInstance();
183         Object[] args = new Object[] { dn, normalized? Boolean.TRUE : Boolean.FALSE };
184         stack.push( new Invocation( this, caller, "getSuffix", args, bypass ) );
185         try
186         {
187             return this.configuration.getInterceptorChain().getSuffix( dn, normalized );
188         }
189         finally
190         {
191             stack.pop();
192         }
193     }
194 
195 
196     public Iterator listSuffixes( boolean normalized ) throws NamingException
197     {
198         return listSuffixes( normalized, null );
199     }
200 
201 
202     public Iterator listSuffixes( boolean normalized, Collection bypass ) throws NamingException
203     {
204         ensureStarted();
205         InvocationStack stack = InvocationStack.getInstance();
206         Object[] args = new Object[] { normalized? Boolean.TRUE : Boolean.FALSE };
207         stack.push( new Invocation( this, caller, "listSuffixes", args, bypass ) );
208         try
209         {
210             return this.configuration.getInterceptorChain().listSuffixes( normalized );
211         }
212         finally
213         {
214             stack.pop();
215         }
216     }
217 
218 
219     public boolean compare( Name name, String oid, Object value ) throws NamingException
220     {
221         return compare( name, oid, value, null );
222     }
223 
224 
225     public boolean compare( Name name, String oid, Object value, Collection bypass ) throws NamingException
226     {
227         ensureStarted();
228         InvocationStack stack = InvocationStack.getInstance();
229         stack.push( new Invocation( this, caller, "compare", new Object[] { name, oid, value }, bypass ) );
230         try
231         {
232             return this.configuration.getInterceptorChain().compare( name, oid, value );
233         }
234         finally
235         {
236             stack.pop();
237         }
238     }
239 
240 
241     public void delete( Name name ) throws NamingException
242     {
243         delete( name, null );
244     }
245 
246 
247     public void delete( Name name, Collection bypass ) throws NamingException
248     {
249         ensureStarted();
250         InvocationStack stack = InvocationStack.getInstance();
251         stack.push( new Invocation( this, caller, "delete", new Object[] { name }, bypass ) );
252         try
253         {
254             this.configuration.getInterceptorChain().delete( name );
255         }
256         finally
257         {
258             stack.pop();
259         }
260     }
261 
262 
263     public void add( String upName, Name normName, Attributes entry ) throws NamingException
264     {
265         add( upName, normName, entry, null );
266     }
267 
268 
269     public void add( String upName, Name normName, Attributes entry, Collection bypass ) throws NamingException
270     {
271         ensureStarted();
272         InvocationStack stack = InvocationStack.getInstance();
273         stack.push( new Invocation( this, caller, "add", new Object[] { upName, normName, entry }, bypass ) );
274         try
275         {
276             this.configuration.getInterceptorChain().add( upName, normName, entry );
277         }
278         finally
279         {
280             stack.pop();
281         }
282     }
283 
284 
285     public void modify( Name name, int modOp, Attributes mods ) throws NamingException
286     {
287         modify( name, modOp, mods, null );
288     }
289 
290 
291     public void modify( Name name, int modOp, Attributes mods, Collection bypass ) throws NamingException
292     {
293         ensureStarted();
294         InvocationStack stack = InvocationStack.getInstance();
295         Integer modOpObj;
296 
297         switch( modOp )
298         {
299             case( DirContext.ADD_ATTRIBUTE ):
300                 modOpObj = ADD_MODOP;
301                 break;
302             case( DirContext.REMOVE_ATTRIBUTE ):
303                 modOpObj = REMOVE_MODOP;
304                 break;
305             case( DirContext.REPLACE_ATTRIBUTE ):
306                 modOpObj = REPLACE_MODOP;
307                 break;
308             default:
309                 throw new IllegalArgumentException( "bad modification operation value: " + modOp );
310         }
311 
312         stack.push( new Invocation( this, caller, "modify", new Object[] { name, modOpObj, mods }, bypass ) );
313         try
314         {
315             this.configuration.getInterceptorChain().modify( name, modOp, mods );
316         }
317         finally
318         {
319             stack.pop();
320         }
321     }
322 
323 
324     public void modify( Name name, ModificationItem[] mods ) throws NamingException
325     {
326         modify( name, mods, null );
327     }
328 
329 
330     public void modify( Name name, ModificationItem[] mods, Collection bypass ) throws NamingException
331     {
332         ensureStarted();
333         InvocationStack stack = InvocationStack.getInstance();
334         stack.push( new Invocation( this, caller, "modify", new Object[] { name, mods }, bypass ) );
335         try
336         {
337             this.configuration.getInterceptorChain().modify( name, mods );
338         }
339         finally
340         {
341             stack.pop();
342         }
343     }
344 
345 
346     public NamingEnumeration list( Name base ) throws NamingException
347     {
348         return list( base, null );
349     }
350 
351 
352     public NamingEnumeration list( Name base, Collection bypass ) throws NamingException
353     {
354         ensureStarted();
355         InvocationStack stack = InvocationStack.getInstance();
356         stack.push( new Invocation( this, caller, "list", new Object[] { base }, bypass ) );
357         try
358         {
359             return this.configuration.getInterceptorChain().list( base );
360         }
361         finally
362         {
363             stack.pop();
364         }
365     }
366 
367 
368     public NamingEnumeration search( Name base, Map env, ExprNode filter, SearchControls searchCtls )
369             throws NamingException
370     {
371         return search( base, env, filter, searchCtls, null );
372     }
373 
374 
375     public NamingEnumeration search( Name base, Map env, ExprNode filter, SearchControls searchCtls, Collection bypass )
376             throws NamingException
377     {
378         ensureStarted();
379         InvocationStack stack = InvocationStack.getInstance();
380         stack.push( new Invocation( this, caller, "search", new Object[] { base, env, filter, searchCtls }, bypass ) );
381         try
382         {
383             return this.configuration.getInterceptorChain().search( base, env, filter, searchCtls );
384         }
385         finally
386         {
387             stack.pop();
388         }
389     }
390 
391 
392     public Attributes lookup( Name name ) throws NamingException
393     {
394         return lookup( name, ( Collection ) null );
395     }
396 
397 
398     public Attributes lookup( Name name, Collection bypass ) throws NamingException
399     {
400         ensureStarted();
401         InvocationStack stack = InvocationStack.getInstance();
402         stack.push( new Invocation( this, caller, "lookup", new Object[] { name }, bypass ) );
403         try
404         {
405             return this.configuration.getInterceptorChain().lookup( name );
406         }
407         finally
408         {
409             stack.pop();
410         }
411     }
412 
413 
414     public Attributes lookup( Name dn, String[] attrIds ) throws NamingException
415     {
416         return lookup( dn, attrIds, null );
417     }
418 
419 
420     public Attributes lookup( Name dn, String[] attrIds, Collection bypass ) throws NamingException
421     {
422         ensureStarted();
423         InvocationStack stack = InvocationStack.getInstance();
424         stack.push( new Invocation( this, caller, "lookup", new Object[] { dn, attrIds }, bypass ) );
425         try
426         {
427             return this.configuration.getInterceptorChain().lookup( dn, attrIds );
428         }
429         finally
430         {
431             stack.pop();
432         }
433     }
434 
435 
436     public boolean hasEntry( Name name ) throws NamingException
437     {
438         return hasEntry( name, null );
439     }
440 
441 
442     public boolean hasEntry( Name name, Collection bypass ) throws NamingException
443     {
444         ensureStarted();
445         InvocationStack stack = InvocationStack.getInstance();
446         stack.push( new Invocation( this, caller, "hasEntry", new Object[] { name }, bypass ) );
447         try
448         {
449             return this.configuration.getInterceptorChain().hasEntry( name );
450         }
451         finally
452         {
453             stack.pop();
454         }
455     }
456 
457 
458     public boolean isSuffix( Name name ) throws NamingException
459     {
460         return isSuffix( name, null );
461     }
462 
463 
464     public boolean isSuffix( Name name, Collection bypass ) throws NamingException
465     {
466         ensureStarted();
467         InvocationStack stack = InvocationStack.getInstance();
468         stack.push( new Invocation( this, caller, "isSuffix", new Object[] { name }, bypass ) );
469         try
470         {
471             return this.configuration.getInterceptorChain().isSuffix( name );
472         }
473         finally
474         {
475             stack.pop();
476         }
477     }
478 
479 
480     public void modifyRn( Name name, String newRn, boolean deleteOldRn ) throws NamingException
481     {
482         modifyRn( name, newRn, deleteOldRn, null );
483     }
484 
485 
486     public void modifyRn( Name name, String newRn, boolean deleteOldRn, Collection bypass ) throws NamingException
487     {
488         ensureStarted();
489         InvocationStack stack = InvocationStack.getInstance();
490         Object[] args = new Object[] { name, newRn, deleteOldRn? Boolean.TRUE : Boolean.FALSE };
491         stack.push( new Invocation( this, caller, "modifyRn", args, bypass ) );
492         try
493         {
494             this.configuration.getInterceptorChain().modifyRn( name, newRn, deleteOldRn );
495         }
496         finally
497         {
498             stack.pop();
499         }
500     }
501 
502 
503     public void move( Name oriChildName, Name newParentName ) throws NamingException
504     {
505         move( oriChildName, newParentName, null );
506     }
507 
508 
509     public void move( Name oriChildName, Name newParentName, Collection bypass ) throws NamingException
510     {
511         ensureStarted();
512         InvocationStack stack = InvocationStack.getInstance();
513         stack.push( new Invocation( this, caller, "move", new Object[] { oriChildName, newParentName }, bypass ) );
514         try
515         {
516             this.configuration.getInterceptorChain().move( oriChildName, newParentName );
517         }
518         finally
519         {
520             stack.pop();
521         }
522     }
523 
524 
525     public void move( Name oriChildName, Name newParentName, String newRn, boolean deleteOldRn ) throws NamingException
526     {
527         move( oriChildName, newParentName, newRn, deleteOldRn, null );
528     }
529 
530 
531     public void move( Name oriChildName, Name newParentName, String newRn, boolean deleteOldRn, Collection bypass )
532             throws NamingException
533     {
534         ensureStarted();
535         InvocationStack stack = InvocationStack.getInstance();
536         Object[] args = new Object[] { oriChildName, newParentName, newRn, deleteOldRn? Boolean.TRUE : Boolean.FALSE };
537         stack.push( new Invocation( this, caller, "move", args, bypass ) );
538         try
539         {
540             this.configuration.getInterceptorChain().move( oriChildName, newParentName, newRn, deleteOldRn );
541         }
542         finally
543         {
544             stack.pop();
545         }
546     }
547 
548 
549     public Attributes getRootDSE() throws NamingException
550     {
551         return getRootDSE( null );
552     }
553 
554 
555     public Attributes getRootDSE( Collection bypass ) throws NamingException
556     {
557         ensureStarted();
558         InvocationStack stack = InvocationStack.getInstance();
559         stack.push( new Invocation( this, caller, "getRootDSE", null, bypass ) );
560         try
561         {
562             return this.configuration.getInterceptorChain().getRootDSE();
563         }
564         finally
565         {
566             stack.pop();
567         }
568     }
569 
570 
571     public void addContextPartition( DirectoryPartitionConfiguration config ) throws NamingException
572     {
573         addContextPartition( config, null );
574     }
575 
576 
577     public void addContextPartition( DirectoryPartitionConfiguration config, Collection bypass ) throws NamingException
578     {
579         ensureStarted();
580         InvocationStack stack = InvocationStack.getInstance();
581         stack.push( new Invocation( this, caller, "addContextPartition", new Object[] { config }, bypass ) );
582         try
583         {
584             this.configuration.getInterceptorChain().addContextPartition( config );
585         }
586         finally
587         {
588             stack.pop();
589         }
590     }
591 
592 
593     public void removeContextPartition( Name suffix ) throws NamingException
594     {
595         removeContextPartition( suffix, null );
596     }
597 
598 
599     public void removeContextPartition( Name suffix, Collection bypass ) throws NamingException
600     {
601         ensureStarted();
602         InvocationStack stack = InvocationStack.getInstance();
603         stack.push( new Invocation( this, caller, "removeContextPartition", new Object[] { suffix }, bypass ) );
604         try
605         {
606             this.configuration.getInterceptorChain().removeContextPartition( suffix );
607         }
608         finally
609         {
610             stack.pop();
611         }
612     }
613 
614 
615     private void ensureStarted() throws ServiceUnavailableException
616     {
617         if( !service.isStarted() )
618         {
619             throw new ServiceUnavailableException( "Directory service is not started." );
620         }
621     }
622 
623 
624     // -----------------------------------------------------------------------
625     // EventContext and EventDirContext notification methods
626     // -----------------------------------------------------------------------
627 
628     /*
629      * All listener registration/deregistration methods can be reduced down to
630      * the following methods.  Rather then make these actual intercepted methods
631      * we use them as out of band methods to interface with the notification
632      * interceptor.
633      */
634 
635     public void addNamingListener( EventContext ctx, Name name, ExprNode filter, SearchControls searchControls,
636                                    NamingListener namingListener ) throws NamingException
637     {
638         InterceptorChain chain = this.configuration.getInterceptorChain();
639         EventService interceptor = ( EventService ) chain.get( "eventService" );
640         interceptor.addNamingListener( ctx, name, filter, searchControls, namingListener );
641     }
642 
643 
644     public void removeNamingListener( EventContext ctx, NamingListener namingListener ) throws NamingException
645     {
646         InterceptorChain chain = this.configuration.getInterceptorChain();
647         EventService interceptor = ( EventService ) chain.get( "eventService" );
648         interceptor.removeNamingListener( ctx, namingListener );
649     }
650 }