001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one
003 *  or more contributor license agreements.  See the NOTICE file
004 *  distributed with this work for additional information
005 *  regarding copyright ownership.  The ASF licenses this file
006 *  to you under the Apache License, Version 2.0 (the
007 *  "License"); you may not use this file except in compliance
008 *  with the License.  You may obtain a copy of the License at
009 * 
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 * 
012 *  Unless required by applicable law or agreed to in writing,
013 *  software distributed under the License is distributed on an
014 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *  KIND, either express or implied.  See the License for the
016 *  specific language governing permissions and limitations
017 *  under the License.
018 * 
019 */
020package org.apache.directory.server.core.api.interceptor;
021
022
023import java.util.HashSet;
024import java.util.Set;
025
026import org.apache.directory.api.ldap.model.entry.Entry;
027import org.apache.directory.api.ldap.model.exception.LdapException;
028import org.apache.directory.api.ldap.model.schema.AttributeType;
029import org.apache.directory.api.ldap.model.schema.SchemaManager;
030import org.apache.directory.server.core.api.DirectoryService;
031import org.apache.directory.server.core.api.DnFactory;
032import org.apache.directory.server.core.api.InterceptorEnum;
033import org.apache.directory.server.core.api.LdapPrincipal;
034import org.apache.directory.server.core.api.filtering.EntryFilteringCursor;
035import org.apache.directory.server.core.api.interceptor.context.AddOperationContext;
036import org.apache.directory.server.core.api.interceptor.context.BindOperationContext;
037import org.apache.directory.server.core.api.interceptor.context.CompareOperationContext;
038import org.apache.directory.server.core.api.interceptor.context.DeleteOperationContext;
039import org.apache.directory.server.core.api.interceptor.context.GetRootDseOperationContext;
040import org.apache.directory.server.core.api.interceptor.context.HasEntryOperationContext;
041import org.apache.directory.server.core.api.interceptor.context.LookupOperationContext;
042import org.apache.directory.server.core.api.interceptor.context.ModifyOperationContext;
043import org.apache.directory.server.core.api.interceptor.context.MoveAndRenameOperationContext;
044import org.apache.directory.server.core.api.interceptor.context.MoveOperationContext;
045import org.apache.directory.server.core.api.interceptor.context.OperationContext;
046import org.apache.directory.server.core.api.interceptor.context.RenameOperationContext;
047import org.apache.directory.server.core.api.interceptor.context.SearchOperationContext;
048import org.apache.directory.server.core.api.interceptor.context.UnbindOperationContext;
049import org.apache.directory.server.core.api.partition.PartitionNexus;
050
051
052/**
053 * A easy-to-use implementation of {@link Interceptor}.  All methods are
054 * implemented to pass the flow of control to next interceptor by defaults.
055 * Please override the methods you have concern in.
056 *
057 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
058 */
059public abstract class BaseInterceptor implements Interceptor
060{
061    /** The interceptor's name. Default to the class name */
062    private String name;
063
064    /** A reference to the DirectoryService instance */
065    protected DirectoryService directoryService;
066
067    /** A reference to the SchemaManager instance */
068    protected SchemaManager schemaManager;
069
070    /** The DN factory */
071    protected DnFactory dnFactory;
072
073    /** set of operational attribute types used for representing the password policy state of a user entry */
074    protected static final Set<AttributeType> PWD_POLICY_STATE_ATTRIBUTE_TYPES = new HashSet<>();
075
076    /**
077     * The final interceptor which acts as a proxy in charge to dialog with the nexus partition.
078     */
079    private final Interceptor finalInterceptor = new Interceptor()
080    {
081        private PartitionNexus nexus;
082
083
084        public String getName()
085        {
086            return "FINAL";
087        }
088
089
090        public void init( DirectoryService directoryService )
091        {
092            this.nexus = directoryService.getPartitionNexus();
093        }
094
095
096        public void destroy()
097        {
098            // unused
099        }
100
101
102        /**
103         * {@inheritDoc}
104         */
105        public void add( AddOperationContext addContext ) throws LdapException
106        {
107            nexus.add( addContext );
108        }
109
110
111        /**
112         * {@inheritDoc}
113         */
114        public void bind( BindOperationContext bindContext ) throws LdapException
115        {
116            // Do nothing here : there is no support for the Bind operation in Partition
117        }
118
119
120        /**
121         * {@inheritDoc}
122         */
123        public boolean compare( CompareOperationContext compareContext ) throws LdapException
124        {
125            return nexus.compare( compareContext );
126        }
127
128
129        /**
130         * {@inheritDoc}
131         */
132        public void delete( DeleteOperationContext deleteContext ) throws LdapException
133        {
134            nexus.delete( deleteContext );
135        }
136
137
138        /**
139         * {@inheritDoc}
140         */
141        public Entry getRootDse( GetRootDseOperationContext getRootDseContext ) throws LdapException
142        {
143            return nexus.getRootDse( getRootDseContext );
144        }
145
146
147        /**
148         * {@inheritDoc}
149         */
150        public boolean hasEntry( HasEntryOperationContext hasEntryContext ) throws LdapException
151        {
152            return nexus.hasEntry( hasEntryContext );
153        }
154
155
156        /**
157         * {@inheritDoc}
158         */
159        public Entry lookup( LookupOperationContext lookupContext ) throws LdapException
160        {
161            return nexus.lookup( lookupContext );
162        }
163
164
165        /**
166         * {@inheritDoc}
167         */
168        public void modify( ModifyOperationContext modifyContext ) throws LdapException
169        {
170            nexus.modify( modifyContext );
171        }
172
173
174        /**
175         * {@inheritDoc}
176         */
177        public void move( MoveOperationContext moveContext ) throws LdapException
178        {
179            nexus.move( moveContext );
180        }
181
182
183        /**
184         * {@inheritDoc}
185         */
186        public void moveAndRename( MoveAndRenameOperationContext moveAndRenameContext ) throws LdapException
187        {
188            nexus.moveAndRename( moveAndRenameContext );
189        }
190
191
192        /**
193         * {@inheritDoc}
194         */
195        public void rename( RenameOperationContext renameContext ) throws LdapException
196        {
197            nexus.rename( renameContext );
198        }
199
200
201        /**
202         * {@inheritDoc}
203         */
204        public EntryFilteringCursor search( SearchOperationContext searchContext ) throws LdapException
205        {
206            return nexus.search( searchContext );
207        }
208
209
210        /**
211         * {@inheritDoc}
212         */
213        public void unbind( UnbindOperationContext unbindContext ) throws LdapException
214        {
215            nexus.unbind( unbindContext );
216        }
217    };
218
219
220    /**
221     * default interceptor name is its class, preventing accidental duplication of interceptors by naming
222     * instances differently
223     * @return (default, class name) interceptor name
224     */
225    public String getName()
226    {
227        return name;
228    }
229
230
231    /**
232     * Returns {@link LdapPrincipal} of current context.
233     * 
234     * @param opContext TODO
235     * @return the authenticated principal
236     */
237    public static LdapPrincipal getPrincipal( OperationContext opContext )
238    {
239        return opContext.getSession().getEffectivePrincipal();
240    }
241
242
243    /**
244     * Creates a new instance with a default name : the class name itself.
245     */
246    protected BaseInterceptor()
247    {
248        name = getClass().getSimpleName();
249    }
250
251
252    /**
253     * Creates a new instance with a given name.
254     * 
255     * @param name the Interceptor name
256     */
257    protected BaseInterceptor( String name )
258    {
259        this.name = name;
260    }
261
262
263    /**
264     * Creates a new instance with a given name.
265     * 
266     * @param interceptor the Interceptor type
267     */
268    protected BaseInterceptor( InterceptorEnum interceptor )
269    {
270        this.name = interceptor.getName();
271    }
272
273
274    /**
275     * This method does nothing by default.
276     * 
277     * @param directoryService The DirectoryService instance
278     * @throws LdapException If the initialization failed
279     */
280    public void init( DirectoryService directoryService ) throws LdapException
281    {
282        // Initialize the fields that will be used by all the interceptors
283        this.directoryService = directoryService;
284        schemaManager = directoryService.getSchemaManager();
285        dnFactory = directoryService.getDnFactory();
286
287        finalInterceptor.init( directoryService );
288    }
289
290
291    /**
292     * This method does nothing by default.
293     */
294    public void destroy()
295    {
296    }
297
298
299    /**
300     * Computes the next interceptor to call for a given operation. If we find none,
301     * we return the proxy to the nexus.
302     * 
303     * @param operationContext The operation context
304     * @return The next interceptor in the list for this operation
305     */
306    protected Interceptor getNextInterceptor( OperationContext operationContext )
307    {
308        String currentInterceptor = operationContext.getNextInterceptor();
309
310        if ( currentInterceptor.equals( "FINAL" ) )
311        {
312            return finalInterceptor;
313        }
314
315        return directoryService.getInterceptor( currentInterceptor );
316    }
317
318
319    // ------------------------------------------------------------------------
320    // Interceptor's Invoke Method
321    // ------------------------------------------------------------------------
322    /**
323     * {@inheritDoc}
324     */
325    public void add( AddOperationContext addContext ) throws LdapException
326    {
327        // Do nothing
328    }
329
330
331    /**
332     * Calls the next interceptor for the add operation.
333     * 
334     * @param addContext The context in which we are executing this operation
335     * @throws LdapException If something went wrong
336     */
337    protected final void next( AddOperationContext addContext ) throws LdapException
338    {
339        Interceptor interceptor = getNextInterceptor( addContext );
340
341        interceptor.add( addContext );
342    }
343
344
345    /**
346     * {@inheritDoc}
347     */
348    public void bind( BindOperationContext bindContext ) throws LdapException
349    {
350        // Do nothing
351    }
352
353
354    /**
355     * Calls the next interceptor for the bind operation.
356     * 
357     * @param bindContext The context in which we are executing this operation
358     * @throws LdapException If something went wrong
359     */
360    protected final void next( BindOperationContext bindContext ) throws LdapException
361    {
362        Interceptor interceptor = getNextInterceptor( bindContext );
363
364        interceptor.bind( bindContext );
365    }
366
367
368    public boolean compare( CompareOperationContext compareContext ) throws LdapException
369    {
370        // Return false in any case
371        return false;
372    }
373
374
375    /**
376     * Calls the next interceptor for the compare operation.
377     * 
378     * @param compareContext The context in which we are executing this operation
379     * @return a boolean indicating if the comparison is successfull
380     * @throws LdapException If something went wrong
381     */
382    protected final boolean next( CompareOperationContext compareContext ) throws LdapException
383    {
384        Interceptor interceptor = getNextInterceptor( compareContext );
385
386        return interceptor.compare( compareContext );
387    }
388
389
390    /**
391     * {@inheritDoc}
392     */
393    public void delete( DeleteOperationContext deleteContext ) throws LdapException
394    {
395        // Do nothing
396    }
397
398
399    /**
400     * Calls the next interceptor for the delete operation.
401     * 
402     * @param deleteContext The context in which we are executing this operation
403     * @throws LdapException If something went wrong
404     */
405    protected final void next( DeleteOperationContext deleteContext ) throws LdapException
406    {
407        Interceptor interceptor = getNextInterceptor( deleteContext );
408
409        interceptor.delete( deleteContext );
410    }
411
412
413    /**
414     * {@inheritDoc}
415     */
416    public Entry getRootDse( GetRootDseOperationContext getRootDseContext ) throws LdapException
417    {
418        // Nothing to do
419        return null;
420    }
421
422
423    /**
424     * Calls the next interceptor for the getRootDse operation.
425     * 
426     * @param getRootDseContext The context in which we are executing this operation
427     * @return the rootDSE
428     * @throws LdapException If something went wrong
429     */
430    protected final Entry next( GetRootDseOperationContext getRootDseContext ) throws LdapException
431    {
432        Interceptor interceptor = getNextInterceptor( getRootDseContext );
433
434        return interceptor.getRootDse( getRootDseContext );
435    }
436
437
438    /**
439     * {@inheritDoc}
440     */
441    public boolean hasEntry( HasEntryOperationContext hasEntryContext ) throws LdapException
442    {
443        // Return false in any case
444        return false;
445    }
446
447
448    /**
449     * Calls the next interceptor for the hasEntry operation.
450     * 
451     * @param hasEntryContext The context in which we are executing this operation
452     * @return a boolean indicating if the entry exists on the server
453     * @throws LdapException If something went wrong
454     */
455    protected final boolean next( HasEntryOperationContext hasEntryContext ) throws LdapException
456    {
457        Interceptor interceptor = getNextInterceptor( hasEntryContext );
458
459        return interceptor.hasEntry( hasEntryContext );
460    }
461
462
463    /**
464     * {@inheritDoc}
465     */
466    public Entry lookup( LookupOperationContext lookupContext ) throws LdapException
467    {
468        return next( lookupContext );
469    }
470
471
472    /**
473     * Calls the next interceptor for the lookup operation.
474     * 
475     * @param lookupContext The context in which we are executing this operation
476     * @return the Entry containing the found entry
477     * @throws LdapException If something went wrong
478     */
479    protected final Entry next( LookupOperationContext lookupContext ) throws LdapException
480    {
481        Interceptor interceptor = getNextInterceptor( lookupContext );
482
483        return interceptor.lookup( lookupContext );
484    }
485
486
487    /**
488     * {@inheritDoc}
489     */
490    public void modify( ModifyOperationContext modifyContext ) throws LdapException
491    {
492        // Nothing to do
493    }
494
495
496    /**
497     * Calls the next interceptor for the modify operation.
498     * 
499     * @param modifyContext The context in which we are executing this operation
500     * @throws LdapException If something went wrong
501     */
502    protected final void next( ModifyOperationContext modifyContext ) throws LdapException
503    {
504        Interceptor interceptor = getNextInterceptor( modifyContext );
505
506        interceptor.modify( modifyContext );
507    }
508
509
510    /**
511     * {@inheritDoc}
512     */
513    public void move( MoveOperationContext moveContext ) throws LdapException
514    {
515        // Do nothing
516    }
517
518
519    /**
520     * Calls the next interceptor for the move operation.
521     * 
522     * @param moveContext The context in which we are executing this operation
523     * @throws LdapException If something went wrong
524     */
525    protected final void next( MoveOperationContext moveContext ) throws LdapException
526    {
527        Interceptor interceptor = getNextInterceptor( moveContext );
528
529        interceptor.move( moveContext );
530    }
531
532
533    public void moveAndRename( MoveAndRenameOperationContext moveAndRenameContext ) throws LdapException
534    {
535        // Do nothing
536    }
537
538
539    /**
540     * Calls the next interceptor for the moveAndRename operation.
541     * 
542     * @param moveAndRenameContext The context in which we are executing this operation
543     * @throws LdapException If something went wrong
544     */
545    protected final void next( MoveAndRenameOperationContext moveAndRenameContext ) throws LdapException
546    {
547        Interceptor interceptor = getNextInterceptor( moveAndRenameContext );
548
549        interceptor.moveAndRename( moveAndRenameContext );
550    }
551
552
553    /**
554     * {@inheritDoc}
555     */
556    public void rename( RenameOperationContext renameContext ) throws LdapException
557    {
558        // Nothing to do
559    }
560
561
562    /**
563     * Calls the next interceptor for the rename operation.
564     * 
565     * @param renameContext The context in which we are executing this operation
566     * @throws LdapException If something went wrong
567     */
568    protected final void next( RenameOperationContext renameContext ) throws LdapException
569    {
570        Interceptor interceptor = getNextInterceptor( renameContext );
571
572        interceptor.rename( renameContext );
573    }
574
575
576    /**
577     * {@inheritDoc}
578     */
579    public EntryFilteringCursor search( SearchOperationContext searchContext ) throws LdapException
580    {
581        return null;
582    }
583
584
585    /**
586     * Calls the next interceptor for the search operation.
587     * 
588     * @param searchContext The context in which we are executing this operation
589     * @return the cursor containing the found entries
590     * @throws LdapException If something went wrong
591     */
592    protected final EntryFilteringCursor next( SearchOperationContext searchContext ) throws LdapException
593    {
594        Interceptor interceptor = getNextInterceptor( searchContext );
595
596        return interceptor.search( searchContext );
597    }
598
599
600    /**
601     * {@inheritDoc}
602     */
603    public void unbind( UnbindOperationContext unbindContext ) throws LdapException
604    {
605        // Nothing to do
606    }
607
608
609    /**
610     * Compute the next interceptor for the unbind operation.
611     * 
612     * @param unbindContext The context in which we are executing this operation
613     * @throws LdapException If something went wrong
614     */
615    protected final void next( UnbindOperationContext unbindContext ) throws LdapException
616    {
617        Interceptor interceptor = getNextInterceptor( unbindContext );
618
619        interceptor.unbind( unbindContext );
620    }
621}