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     */
020    package org.apache.directory.server.core;
021    
022    
023    import java.util.ArrayList;
024    import java.util.List;
025    import java.util.Set;
026    
027    import org.apache.directory.server.core.entry.ClonedServerEntry;
028    import org.apache.directory.server.core.filtering.EntryFilteringCursor;
029    import org.apache.directory.server.core.interceptor.InterceptorChain;
030    import org.apache.directory.server.core.interceptor.context.AddOperationContext;
031    import org.apache.directory.server.core.interceptor.context.BindOperationContext;
032    import org.apache.directory.server.core.interceptor.context.CompareOperationContext;
033    import org.apache.directory.server.core.interceptor.context.DeleteOperationContext;
034    import org.apache.directory.server.core.interceptor.context.EntryOperationContext;
035    import org.apache.directory.server.core.interceptor.context.GetMatchedNameOperationContext;
036    import org.apache.directory.server.core.interceptor.context.GetRootDSEOperationContext;
037    import org.apache.directory.server.core.interceptor.context.GetSuffixOperationContext;
038    import org.apache.directory.server.core.interceptor.context.ListOperationContext;
039    import org.apache.directory.server.core.interceptor.context.ListSuffixOperationContext;
040    import org.apache.directory.server.core.interceptor.context.LookupOperationContext;
041    import org.apache.directory.server.core.interceptor.context.ModifyOperationContext;
042    import org.apache.directory.server.core.interceptor.context.MoveAndRenameOperationContext;
043    import org.apache.directory.server.core.interceptor.context.MoveOperationContext;
044    import org.apache.directory.server.core.interceptor.context.OperationContext;
045    import org.apache.directory.server.core.interceptor.context.RenameOperationContext;
046    import org.apache.directory.server.core.interceptor.context.SearchOperationContext;
047    import org.apache.directory.server.core.interceptor.context.UnbindOperationContext;
048    import org.apache.directory.server.core.invocation.InvocationStack;
049    import org.apache.directory.server.i18n.I18n;
050    import org.apache.directory.shared.ldap.codec.util.LdapURLEncodingException;
051    import org.apache.directory.shared.ldap.constants.SchemaConstants;
052    import org.apache.directory.shared.ldap.entry.EntryAttribute;
053    import org.apache.directory.shared.ldap.entry.ServerEntry;
054    import org.apache.directory.shared.ldap.entry.Value;
055    import org.apache.directory.shared.ldap.exception.LdapAffectMultipleDsaException;
056    import org.apache.directory.shared.ldap.exception.LdapInvalidDnException;
057    import org.apache.directory.shared.ldap.exception.LdapPartialResultException;
058    import org.apache.directory.shared.ldap.exception.LdapReferralException;
059    import org.apache.directory.shared.ldap.exception.LdapServiceUnavailableException;
060    import org.apache.directory.shared.ldap.filter.SearchScope;
061    import org.apache.directory.shared.ldap.message.ResultCodeEnum;
062    import org.apache.directory.shared.ldap.name.DN;
063    import org.apache.directory.shared.ldap.util.LdapURL;
064    import org.slf4j.Logger;
065    import org.slf4j.LoggerFactory;
066    
067    
068    /**
069     * The default implementation of an OperationManager.
070     *
071     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
072     * @version $Rev$, $Date$
073     */
074    public class DefaultOperationManager implements OperationManager
075    {
076        /** The logger */
077        private static final Logger LOG = LoggerFactory.getLogger( DefaultOperationManager.class );
078    
079        /** A logger specifically for change operations */
080        private static final Logger LOG_CHANGES = LoggerFactory.getLogger( "LOG_CHANGES" );
081    
082        /** The directory service instance */
083        private final DirectoryService directoryService;
084    
085    
086        public DefaultOperationManager( DirectoryService directoryService )
087        {
088            this.directoryService = directoryService;
089        }
090        
091        
092        private LdapReferralException buildReferralException( ServerEntry parentEntry, DN childDn ) 
093            throws LdapInvalidDnException, LdapURLEncodingException
094        {
095            // Get the Ref attributeType
096            EntryAttribute refs = parentEntry.get( SchemaConstants.REF_AT );
097            
098            List<String> urls = new ArrayList<String>();
099            
100            // manage each Referral, building the correct URL for each of them
101            for ( Value<?> url:refs )
102            {
103                // we have to replace the parent by the referral
104                LdapURL ldapUrl = new LdapURL( url.getString() );
105                
106                // We have a problem with the DN : we can't use the UpName,
107                // as we may have some spaces around the ',' and '+'.
108                // So we have to take the RDN one by one, and create a 
109                // new DN with the type and value UP form
110                
111                DN urlDn = (DN)ldapUrl.getDn().addAll( childDn );
112                
113                ldapUrl.setDn( urlDn );
114                urls.add( ldapUrl.toString() );
115            }
116            
117            // Return with an exception
118            LdapReferralException lre = new LdapReferralException( urls );
119            lre.setRemainingDn( childDn );
120            lre.setResolvedDn( parentEntry.getDn() );
121            lre.setResolvedObject( parentEntry );
122            
123            return lre;
124        }
125        
126        
127        private LdapReferralException buildReferralExceptionForSearch( 
128            ServerEntry parentEntry, DN childDn, SearchScope scope ) 
129            throws LdapInvalidDnException, LdapURLEncodingException
130        {
131            // Get the Ref attributeType
132            EntryAttribute refs = parentEntry.get( SchemaConstants.REF_AT );
133            
134            List<String> urls = new ArrayList<String>();
135            
136            // manage each Referral, building the correct URL for each of them
137            for ( Value<?> url:refs )
138            {
139                // we have to replace the parent by the referral
140                try
141                {
142                    LdapURL ldapUrl = new LdapURL( url.getString() );
143                    
144                    StringBuilder urlString = new StringBuilder();
145        
146                    if ( ( ldapUrl.getDn() == null ) || ( ldapUrl.getDn() == DN.EMPTY_DN) )
147                    {
148                        ldapUrl.setDn( parentEntry.getDn() );
149                    }
150                    else
151                    {
152                        // We have a problem with the DN : we can't use the UpName,
153                        // as we may have some spaces around the ',' and '+'.
154                        // So we have to take the RDN one by one, and create a 
155                        // new DN with the type and value UP form
156                        
157                        DN urlDn = (DN)ldapUrl.getDn().addAll( childDn );
158                        
159                        ldapUrl.setDn( urlDn );
160                    }
161                    
162                    urlString.append( ldapUrl.toString() ).append( "??" );
163                    
164                    switch ( scope )
165                    {
166                        case OBJECT :
167                            urlString.append( "base" );
168                            break;
169                            
170                        case SUBTREE :
171                            urlString.append( "sub" );
172                            break;
173                            
174                        case ONELEVEL :
175                            urlString.append( "one" );
176                            break;
177                    }
178                    
179                    urls.add( urlString.toString() );
180                }
181                catch ( LdapURLEncodingException luee )
182                {
183                    // The URL is not correct, returns it as is
184                    urls.add( url.getString() );
185                }
186            }
187            
188            // Return with an exception
189            LdapReferralException lre = new LdapReferralException( urls );
190            lre.setRemainingDn( childDn );
191            lre.setResolvedDn( parentEntry.getDn() );
192            lre.setResolvedObject( parentEntry );
193            
194            return lre;
195        }
196    
197    
198        private LdapPartialResultException buildLdapPartialResultException( DN childDn )
199        {
200            LdapPartialResultException lpre = new LdapPartialResultException( I18n.err( I18n.ERR_315 ) );
201            
202            lpre.setRemainingDn( childDn );
203            lpre.setResolvedDn( DN.EMPTY_DN );
204            
205            return lpre;
206        }
207        
208        
209        /**
210         * {@inheritDoc}
211         */
212        public void add( AddOperationContext opContext ) throws Exception
213        {
214            LOG.debug( ">> AddOperation : {}", opContext );
215            LOG_CHANGES.debug( ">> AddOperation : {}", opContext );
216            
217            ensureStarted();
218            push( opContext );
219            
220            try
221            {
222                // Normalize the opContext DN
223                DN dn = opContext.getDn();
224                dn.normalize( directoryService.getSchemaManager().getNormalizerMapping() );
225    
226                // We have to deal with the referral first
227                directoryService.getReferralManager().lockRead();
228    
229                if ( directoryService.getReferralManager().hasParentReferral( dn ) )
230                {
231                    ServerEntry parentEntry = directoryService.getReferralManager().getParentReferral( dn );
232                    DN childDn = (DN)dn.getSuffix( parentEntry.getDn().size() );
233    
234                    // Depending on the Context.REFERRAL property value, we will throw
235                    // a different exception.
236                    if ( opContext.isReferralIgnored() )
237                    {
238                        directoryService.getReferralManager().unlock();
239                        
240                        LdapPartialResultException exception = buildLdapPartialResultException( childDn );
241                        throw exception;
242                    }
243                    else
244                    {
245                        // Unlock the referral manager
246                        directoryService.getReferralManager().unlock();
247                        
248                        LdapReferralException exception = buildReferralException( parentEntry, childDn );
249                        throw exception;
250                    }
251                }
252                else
253                {
254                    // Unlock the ReferralManager
255                    directoryService.getReferralManager().unlock();
256    
257                    // Call the Add method
258                    InterceptorChain interceptorChain = directoryService.getInterceptorChain();
259                    interceptorChain.add( opContext );
260                }
261            }
262            finally
263            {
264                pop();
265            }
266    
267            LOG.debug( "<< AddOperation successful" );
268            LOG_CHANGES.debug( "<< AddOperation successful" );
269        }
270    
271    
272        /**
273         * {@inheritDoc}
274         */
275        public void bind( BindOperationContext opContext ) throws Exception
276        {
277            LOG.debug( ">> BindOperation : {}", opContext );
278            
279            ensureStarted();
280            push( opContext );
281            
282            try
283            {
284                directoryService.getInterceptorChain().bind( opContext );
285            }
286            finally
287            {
288                pop();
289    
290                LOG.debug( "<< BindOperation successful" );
291            }
292        }
293    
294    
295        /**
296         * {@inheritDoc}
297         */
298        public boolean compare( CompareOperationContext opContext ) throws Exception
299        {
300            LOG.debug( ">> CompareOperation : {}", opContext );
301            
302            ensureStarted();
303            push( opContext );
304            
305            try
306            {
307                // Normalize the opContext DN
308                DN dn = opContext.getDn();
309                dn.normalize( directoryService.getSchemaManager().getNormalizerMapping() );
310    
311                // We have to deal with the referral first
312                directoryService.getReferralManager().lockRead();
313    
314                // Check if we have an ancestor for this DN
315                ServerEntry parentEntry = directoryService.getReferralManager().getParentReferral( dn );
316                
317                if ( parentEntry != null )
318                {
319                    // We have found a parent referral for the current DN 
320                    DN childDn = (DN)dn.getSuffix( parentEntry.getDn().size() );
321        
322                    if ( directoryService.getReferralManager().isReferral( dn ) )
323                    {
324                        // This is a referral. We can delete it if the ManageDsaIt flag is true
325                        // Otherwise, we just throw a LdapReferralException
326                        if ( !opContext.isReferralIgnored() )
327                        {
328                            // Throw a Referral Exception
329                            // Unlock the referral manager
330                            directoryService.getReferralManager().unlock();
331                            
332                            LdapReferralException exception = buildReferralException( parentEntry, childDn );
333                            throw exception;
334                        }
335                    }
336                    else if ( directoryService.getReferralManager().hasParentReferral( dn ) )
337                    {
338                        // Depending on the Context.REFERRAL property value, we will throw
339                        // a different exception.
340                        if ( opContext.isReferralIgnored() )
341                        {
342                            directoryService.getReferralManager().unlock();
343                            
344                            LdapPartialResultException exception = buildLdapPartialResultException( childDn );
345                            throw exception;
346                        }
347                        else
348                        {
349                            // Unlock the referral manager
350                            directoryService.getReferralManager().unlock();
351                            
352                            LdapReferralException exception = buildReferralException( parentEntry, childDn );
353                            throw exception;
354                        }
355                    }
356                }
357    
358                // Unlock the ReferralManager
359                directoryService.getReferralManager().unlock();
360    
361                // Call the Add method
362                InterceptorChain interceptorChain = directoryService.getInterceptorChain();
363                return interceptorChain.compare( opContext );
364            }
365            finally
366            {
367                pop();
368    
369                LOG.debug( "<< CompareOperation successful" );
370            }
371        }
372    
373    
374        /**
375         * {@inheritDoc}
376         */
377        public void delete( DeleteOperationContext opContext ) throws Exception
378        {
379            LOG.debug( ">> DeleteOperation : {}", opContext );
380            LOG_CHANGES.debug( ">> DeleteOperation : {}", opContext );
381            
382            ensureStarted();
383            push( opContext );
384            
385            try
386            {
387                // Normalize the opContext DN
388                DN dn = opContext.getDn();
389                dn.normalize( directoryService.getSchemaManager().getNormalizerMapping() );
390    
391                // We have to deal with the referral first
392                directoryService.getReferralManager().lockRead();
393    
394                ServerEntry parentEntry = directoryService.getReferralManager().getParentReferral( dn );
395                
396                if ( parentEntry != null )
397                {
398                    // We have found a parent referral for the current DN 
399                    DN childDn = (DN)dn.getSuffix( parentEntry.getDn().size() );
400        
401                    if ( directoryService.getReferralManager().isReferral( dn ) )
402                    {
403                        // This is a referral. We can delete it if the ManageDsaIt flag is true
404                        // Otherwise, we just throw a LdapReferralException
405                        if ( !opContext.isReferralIgnored() )
406                        {
407                            // Throw a Referral Exception
408                            // Unlock the referral manager
409                            directoryService.getReferralManager().unlock();
410                            
411                            LdapReferralException exception = buildReferralException( parentEntry, childDn );
412                            throw exception;
413                        }
414                    }
415                    else if ( directoryService.getReferralManager().hasParentReferral( dn ) )
416                    {
417                        // We can't delete an entry which has an ancestor referral
418        
419                        // Depending on the Context.REFERRAL property value, we will throw
420                        // a different exception.
421                        if ( opContext.isReferralIgnored() )
422                        {
423                            directoryService.getReferralManager().unlock();
424                            
425                            LdapPartialResultException exception = buildLdapPartialResultException( childDn );
426                            throw exception;
427                        }
428                        else
429                        {
430                            // Unlock the referral manager
431                            directoryService.getReferralManager().unlock();
432                            
433                            LdapReferralException exception = buildReferralException( parentEntry, childDn );
434                            throw exception;
435                        }
436                    }
437                }
438    
439                // Unlock the ReferralManager
440                directoryService.getReferralManager().unlock();
441    
442                // Call the Add method
443                InterceptorChain interceptorChain = directoryService.getInterceptorChain();
444                interceptorChain.delete( opContext );
445            }
446            finally
447            {
448                pop();
449            }
450    
451            LOG.debug( "<< DeleteOperation successful" );
452            LOG_CHANGES.debug( "<< DeleteOperation successful" );
453        }
454    
455    
456        /**
457         * {@inheritDoc}
458         */
459        public DN getMatchedName( GetMatchedNameOperationContext opContext ) throws Exception
460        {
461            LOG.debug( ">> GetMatchedNameOperation : {}", opContext );
462            
463            ensureStarted();
464            push( opContext );
465            
466            try
467            {
468                return directoryService.getInterceptorChain().getMatchedName( opContext );
469            }
470            finally
471            {
472                pop();
473    
474                LOG.debug( "<< GetMatchedNameOperation successful" );
475            }
476        }
477    
478    
479        /**
480         * {@inheritDoc}
481         */
482        public ClonedServerEntry getRootDSE( GetRootDSEOperationContext opContext ) 
483            throws Exception
484        {
485            LOG.debug( ">> GetRootDSEOperation : {}", opContext );
486            
487            ensureStarted();
488            push( opContext );
489            
490            try
491            {
492                InterceptorChain chain = directoryService.getInterceptorChain();
493                return chain.getRootDSE( opContext );
494            }
495            finally
496            {
497                pop();
498    
499                LOG.debug( "<< getRootDSEOperation successful" );
500            }
501        }
502    
503    
504        /**
505         * {@inheritDoc}
506         */
507        public DN getSuffix( GetSuffixOperationContext opContext ) throws Exception
508        {
509            LOG.debug( ">> GetSuffixOperation : {}", opContext );
510            
511            ensureStarted();
512            push( opContext );
513            
514            try
515            {
516                return directoryService.getInterceptorChain().getSuffix( opContext );
517            }
518            finally
519            {
520                pop();
521    
522                LOG.debug( "<< GetSuffixOperation successful" );
523            }
524        }
525    
526    
527        /**
528         * {@inheritDoc}
529         */
530        public boolean hasEntry( EntryOperationContext opContext ) throws Exception
531        {
532            LOG.debug( ">> hasEntryOperation : {}", opContext );
533            
534            ensureStarted();
535            push( opContext );
536            
537            try
538            {
539                return directoryService.getInterceptorChain().hasEntry( opContext );
540            }
541            finally
542            {
543                pop();
544    
545                LOG.debug( "<< HasEntryOperation successful" );
546            }
547        }
548    
549    
550        /**
551         * {@inheritDoc}
552         */
553        public EntryFilteringCursor list( ListOperationContext opContext ) throws Exception
554        {
555            LOG.debug( ">> ListOperation : {}", opContext );
556            
557            ensureStarted();
558            push( opContext );
559            
560            try
561            {
562                return directoryService.getInterceptorChain().list( opContext );
563            }
564            finally
565            {
566                pop();
567    
568                LOG.debug( "<< ListOperation successful" );
569            }
570        }
571    
572    
573        /**
574         * {@inheritDoc}
575         */
576        public Set<String> listSuffixes( ListSuffixOperationContext opContext ) 
577            throws Exception
578        {
579            LOG.debug( ">> ListSuffixesOperation : {}", opContext );
580            
581            ensureStarted();
582            push( opContext );
583            
584            try
585            {
586                return directoryService.getInterceptorChain().listSuffixes( opContext );
587            }
588            finally
589            {
590                pop();
591    
592                LOG.debug( "<< ListSuffixesOperation successful" );
593            }
594        }
595    
596    
597        /**
598         * {@inheritDoc}
599         */
600        public ClonedServerEntry lookup( LookupOperationContext opContext ) throws Exception
601        {
602            LOG.debug( ">> LookupOperation : {}", opContext );
603            
604            ensureStarted();
605            push( opContext );
606            
607            try
608            {
609                return directoryService.getInterceptorChain().lookup( opContext );
610            }
611            finally
612            {
613                pop();
614    
615                LOG.debug( "<< LookupOperation successful" );
616            }
617        }
618    
619    
620        /**
621         * {@inheritDoc}
622         */
623        public void modify( ModifyOperationContext opContext ) throws Exception
624        {
625            LOG.debug( ">> ModifyOperation : {}", opContext );
626            LOG_CHANGES.debug( ">> ModifyOperation : {}", opContext );
627            
628            ensureStarted();
629            push( opContext );
630            
631            try
632            {
633                // Normalize the opContext DN
634                DN dn = opContext.getDn();
635                dn.normalize( directoryService.getSchemaManager().getNormalizerMapping() );
636    
637                // We have to deal with the referral first
638                directoryService.getReferralManager().lockRead();
639    
640                // Check if we have an ancestor for this DN
641                ServerEntry parentEntry = directoryService.getReferralManager().getParentReferral( dn );
642                
643                if ( parentEntry != null )
644                {
645                    // We have found a parent referral for the current DN 
646                    DN childDn = (DN)dn.getSuffix( parentEntry.getDn().size() );
647        
648                    if ( directoryService.getReferralManager().isReferral( dn ) )
649                    {
650                        // This is a referral. We can delete it if the ManageDsaIt flag is true
651                        // Otherwise, we just throw a LdapReferralException
652                        if ( !opContext.isReferralIgnored() )
653                        {
654                            // Throw a Referral Exception
655                            // Unlock the referral manager
656                            directoryService.getReferralManager().unlock();
657                            
658                            LdapReferralException exception = buildReferralException( parentEntry, childDn );
659                            throw exception;
660                        }
661                    }
662                    else if ( directoryService.getReferralManager().hasParentReferral( dn ) )
663                    {
664                        // We can't delete an entry which has an ancestor referral
665        
666                        // Depending on the Context.REFERRAL property value, we will throw
667                        // a different exception.
668                        if ( opContext.isReferralIgnored() )
669                        {
670                            directoryService.getReferralManager().unlock();
671                            
672                            LdapPartialResultException exception = buildLdapPartialResultException( childDn );
673                            throw exception;
674                        }
675                        else
676                        {
677                            // Unlock the referral manager
678                            directoryService.getReferralManager().unlock();
679                            
680                            LdapReferralException exception = buildReferralException( parentEntry, childDn );
681                            throw exception;
682                        }
683                    }
684                }
685    
686                // Unlock the ReferralManager
687                directoryService.getReferralManager().unlock();
688    
689                // Call the Add method
690                InterceptorChain interceptorChain = directoryService.getInterceptorChain();
691                interceptorChain.modify( opContext );
692            }
693            finally
694            {
695                pop();
696    
697                LOG.debug( "<< ModifyOperation successful" );
698                LOG_CHANGES.debug( "<< ModifyOperation successful" );
699            }
700        }
701    
702    
703        /**
704         * {@inheritDoc}
705         */
706        public void move( MoveOperationContext opContext ) throws Exception
707        {
708            LOG.debug( ">> MoveOperation : {}", opContext );
709            LOG_CHANGES.debug( ">> MoveOperation : {}", opContext );
710            
711            ensureStarted();
712            push( opContext );
713            
714            try
715            {
716                // Normalize the opContext DN
717                DN dn = opContext.getDn();
718                dn.normalize( directoryService.getSchemaManager().getNormalizerMapping() );
719    
720                // We have to deal with the referral first
721                directoryService.getReferralManager().lockRead();
722    
723                // Check if we have an ancestor for this DN
724                ServerEntry parentEntry = directoryService.getReferralManager().getParentReferral( dn );
725                
726                if ( parentEntry != null )
727                {
728                    // We have found a parent referral for the current DN 
729                    DN childDn = (DN)dn.getSuffix( parentEntry.getDn().size() );
730        
731                    if ( directoryService.getReferralManager().isReferral( dn ) )
732                    {
733                        // This is a referral. We can delete it if the ManageDsaIt flag is true
734                        // Otherwise, we just throw a LdapReferralException
735                        if ( !opContext.isReferralIgnored() )
736                        {
737                            // Throw a Referral Exception
738                            // Unlock the referral manager
739                            directoryService.getReferralManager().unlock();
740                            
741                            LdapReferralException exception = buildReferralException( parentEntry, childDn );
742                            throw exception;
743                        }
744                    }
745                    else if ( directoryService.getReferralManager().hasParentReferral( dn ) )
746                    {
747                        // We can't delete an entry which has an ancestor referral
748        
749                        // Depending on the Context.REFERRAL property value, we will throw
750                        // a different exception.
751                        if ( opContext.isReferralIgnored() )
752                        {
753                            directoryService.getReferralManager().unlock();
754                            
755                            LdapPartialResultException exception = buildLdapPartialResultException( childDn );
756                            throw exception;
757                        }
758                        else
759                        {
760                            // Unlock the referral manager
761                            directoryService.getReferralManager().unlock();
762                            
763                            LdapReferralException exception = buildReferralException( parentEntry, childDn );
764                            throw exception;
765                        }
766                    }
767                }
768                
769                // Now, check the destination
770                // Normalize the opContext DN
771                DN parentDn = opContext.getParent();
772                parentDn.normalize( directoryService.getSchemaManager().getNormalizerMapping() );
773    
774                // If he parent DN is a referral, or has a referral ancestor, we have to issue a AffectMultipleDsas result
775                // as stated by RFC 3296 Section 5.6.2
776                if ( directoryService.getReferralManager().isReferral( parentDn ) ||
777                     directoryService.getReferralManager().hasParentReferral( parentDn ) )
778                {
779                    // Unlock the referral manager
780                    directoryService.getReferralManager().unlock();
781    
782                    LdapAffectMultipleDsaException exception = new LdapAffectMultipleDsaException();
783                    //exception.setRemainingName( dn );
784                    
785                    throw exception;
786                }
787    
788                // Unlock the ReferralManager
789                directoryService.getReferralManager().unlock();
790    
791                // Call the Add method
792                InterceptorChain interceptorChain = directoryService.getInterceptorChain();
793                interceptorChain.move( opContext );
794            }
795            finally
796            {
797                pop();
798    
799                LOG.debug( "<< MoveOperation successful" );
800                LOG_CHANGES.debug( "<< MoveOperation successful" );
801            }
802        }
803    
804    
805        /**
806         * {@inheritDoc}
807         */
808        public void moveAndRename( MoveAndRenameOperationContext opContext ) throws Exception
809        {
810            LOG.debug( ">> MoveAndRenameOperation : {}", opContext );
811            LOG_CHANGES.debug( ">> MoveAndRenameOperation : {}", opContext );
812            
813            ensureStarted();
814            push( opContext );
815            
816            try
817            {
818                // Normalize the opContext DN
819                DN dn = opContext.getDn();
820                dn.normalize( directoryService.getSchemaManager().getNormalizerMapping() );
821    
822                // We have to deal with the referral first
823                directoryService.getReferralManager().lockRead();
824    
825                // Check if we have an ancestor for this DN
826                ServerEntry parentEntry = directoryService.getReferralManager().getParentReferral( dn );
827                
828                if ( parentEntry != null )
829                {
830                    // We have found a parent referral for the current DN 
831                    DN childDn = (DN)dn.getSuffix( parentEntry.getDn().size() );
832        
833                    if ( directoryService.getReferralManager().isReferral( dn ) )
834                    {
835                        // This is a referral. We can delete it if the ManageDsaIt flag is true
836                        // Otherwise, we just throw a LdapReferralException
837                        if ( !opContext.isReferralIgnored() )
838                        {
839                            // Throw a Referral Exception
840                            // Unlock the referral manager
841                            directoryService.getReferralManager().unlock();
842                            
843                            LdapReferralException exception = buildReferralException( parentEntry, childDn );
844                            throw exception;
845                        }
846                    }
847                    else if ( directoryService.getReferralManager().hasParentReferral( dn ) )
848                    {
849                        // We can't delete an entry which has an ancestor referral
850        
851                        // Depending on the Context.REFERRAL property value, we will throw
852                        // a different exception.
853                        if ( opContext.isReferralIgnored() )
854                        {
855                            directoryService.getReferralManager().unlock();
856                            
857                            LdapPartialResultException exception = buildLdapPartialResultException( childDn );
858                            throw exception;
859                        }
860                        else
861                        {
862                            // Unlock the referral manager
863                            directoryService.getReferralManager().unlock();
864                            
865                            LdapReferralException exception = buildReferralException( parentEntry, childDn );
866                            throw exception;
867                        }
868                    }
869                }
870                
871                // Now, check the destination
872                // Normalize the opContext DN
873                DN parentDn = opContext.getParent();
874                parentDn.normalize( directoryService.getSchemaManager().getNormalizerMapping() );
875    
876                // If he parent DN is a referral, or has a referral ancestor, we have to issue a AffectMultipleDsas result
877                // as stated by RFC 3296 Section 5.6.2
878                if ( directoryService.getReferralManager().isReferral( parentDn ) ||
879                     directoryService.getReferralManager().hasParentReferral( parentDn ) )
880                {
881                    // Unlock the referral manager
882                    directoryService.getReferralManager().unlock();
883    
884                    // The parent DN is a referral, we have to issue a AffectMultipleDsas result
885                    // as stated by RFC 3296 Section 5.6.2
886                    LdapAffectMultipleDsaException exception = new LdapAffectMultipleDsaException();
887                    //exception.setRemainingName( dn );
888                    
889                    throw exception;
890                }
891                
892                // Unlock the ReferralManager
893                directoryService.getReferralManager().unlock();
894    
895                // Call the Add method
896                InterceptorChain interceptorChain = directoryService.getInterceptorChain();
897                interceptorChain.moveAndRename( opContext );
898            }
899            finally
900            {
901                pop();
902    
903                LOG.debug( "<< MoveAndRenameOperation successful" );
904                LOG_CHANGES.debug( "<< MoveAndRenameOperation successful" );
905            }
906        }
907    
908    
909        /**
910         * {@inheritDoc} 
911         */
912        public void rename( RenameOperationContext opContext ) throws Exception
913        {
914            LOG.debug( ">> RenameOperation : {}", opContext );
915            LOG_CHANGES.debug( ">> RenameOperation : {}", opContext );
916            
917            ensureStarted();
918            push( opContext );
919            
920            try
921            {
922                // Normalize the opContext DN
923                DN dn = opContext.getDn();
924                dn.normalize( directoryService.getSchemaManager().getNormalizerMapping() );
925    
926                // Inject the newDn into the operation context
927                // Inject the new DN into the context
928                if ( !dn.isEmpty() )
929                {
930                    DN newDn = (DN)dn.clone();
931                    newDn.remove( dn.size() - 1 );
932                    newDn.add( opContext.getNewRdn() );
933                    opContext.setNewDn( newDn );
934                }
935                
936                // We have to deal with the referral first
937                directoryService.getReferralManager().lockRead();
938    
939                // Check if we have an ancestor for this DN
940                ServerEntry parentEntry = directoryService.getReferralManager().getParentReferral( dn );
941                
942                if ( parentEntry != null )
943                {
944                    // We have found a parent referral for the current DN 
945                    DN childDn = (DN)dn.getSuffix( parentEntry.getDn().size() );
946        
947                    if ( directoryService.getReferralManager().isReferral( dn ) )
948                    {
949                        // This is a referral. We can delete it if the ManageDsaIt flag is true
950                        // Otherwise, we just throw a LdapReferralException
951                        if ( !opContext.isReferralIgnored() )
952                        {
953                            // Throw a Referral Exception
954                            // Unlock the referral manager
955                            directoryService.getReferralManager().unlock();
956                            
957                            LdapReferralException exception = buildReferralException( parentEntry, childDn );
958                            throw exception;
959                        }
960                    }
961                    else if ( directoryService.getReferralManager().hasParentReferral( dn ) )
962                    {
963                        // We can't delete an entry which has an ancestor referral
964        
965                        // Depending on the Context.REFERRAL property value, we will throw
966                        // a different exception.
967                        if ( opContext.isReferralIgnored() )
968                        {
969                            directoryService.getReferralManager().unlock();
970                            
971                            LdapPartialResultException exception = buildLdapPartialResultException( childDn );
972                            throw exception;
973                        }
974                        else
975                        {
976                            // Unlock the referral manager
977                            directoryService.getReferralManager().unlock();
978                            
979                            LdapReferralException exception = buildReferralException( parentEntry, childDn );
980                            throw exception;
981                        }
982                    }
983                }
984    
985                // Unlock the ReferralManager
986                directoryService.getReferralManager().unlock();
987    
988                // Call the Add method
989                InterceptorChain interceptorChain = directoryService.getInterceptorChain();
990                interceptorChain.rename( opContext );
991            }
992            finally
993            {
994                pop();
995    
996                LOG.debug( "<< RenameOperation successful" );
997                LOG_CHANGES.debug( "<< RenameOperation successful" );
998            }
999        }
1000    
1001    
1002        /**
1003         * {@inheritDoc}
1004         */
1005        public EntryFilteringCursor search( SearchOperationContext opContext ) throws Exception
1006        {
1007            LOG.debug( ">> SearchOperation : {}", opContext );
1008            
1009            ensureStarted();
1010            push( opContext );
1011            
1012            try
1013            {
1014                // Normalize the opContext DN
1015                DN dn = opContext.getDn();
1016                dn.normalize( directoryService.getSchemaManager().getNormalizerMapping() );
1017    
1018                // We have to deal with the referral first
1019                directoryService.getReferralManager().lockRead();
1020    
1021                // Check if we have an ancestor for this DN
1022                ServerEntry parentEntry = directoryService.getReferralManager().getParentReferral( dn );
1023                
1024                if ( parentEntry != null )
1025                {
1026                    // We have found a parent referral for the current DN 
1027                    DN childDn = (DN)dn.getSuffix( parentEntry.getDn().size() );
1028        
1029                    if ( directoryService.getReferralManager().isReferral( dn ) )
1030                    {
1031                        // This is a referral. We can return it if the ManageDsaIt flag is true
1032                        // Otherwise, we just throw a LdapReferralException
1033                        if ( !opContext.isReferralIgnored() )
1034                        {
1035                            // Throw a Referral Exception
1036                            // Unlock the referral manager
1037                            directoryService.getReferralManager().unlock();
1038                            
1039                            LdapReferralException exception = buildReferralExceptionForSearch( parentEntry, childDn, opContext.getScope() );
1040                            throw exception;
1041                        }
1042                    }
1043                    else if ( directoryService.getReferralManager().hasParentReferral( dn ) )
1044                    {
1045                        // We can't search an entry which has an ancestor referral
1046        
1047                        // Depending on the Context.REFERRAL property value, we will throw
1048                        // a different exception.
1049                        if ( opContext.isReferralIgnored() )
1050                        {
1051                            directoryService.getReferralManager().unlock();
1052                            
1053                            LdapPartialResultException exception = buildLdapPartialResultException( childDn );
1054                            throw exception;
1055                        }
1056                        else
1057                        {
1058                            // Unlock the referral manager
1059                            directoryService.getReferralManager().unlock();
1060                            
1061                            LdapReferralException exception = buildReferralExceptionForSearch( parentEntry, childDn, opContext.getScope() );
1062                            throw exception;
1063                        }
1064                    }
1065                }
1066    
1067                // Unlock the ReferralManager
1068                directoryService.getReferralManager().unlock();
1069    
1070                // Call the Add method
1071                InterceptorChain interceptorChain = directoryService.getInterceptorChain();
1072                return interceptorChain.search( opContext );
1073            }
1074            finally
1075            {
1076                pop();
1077    
1078                LOG.debug( "<< SearchOperation successful" );
1079            }
1080        }
1081    
1082    
1083        /**
1084         * {@inheritDoc}
1085         */
1086        public void unbind( UnbindOperationContext opContext ) throws Exception
1087        {
1088            LOG.debug( ">> UnbindOperation : {}", opContext );
1089            
1090            ensureStarted();
1091            push( opContext );
1092            
1093            try
1094            {
1095                directoryService.getInterceptorChain().unbind( opContext );
1096            }
1097            finally
1098            {
1099                pop();
1100            }
1101    
1102            LOG.debug( "<< UnbindOperation successful" );
1103        }
1104    
1105    
1106        private void ensureStarted() throws LdapServiceUnavailableException
1107        {
1108            if ( ! directoryService.isStarted() )
1109            {
1110                throw new LdapServiceUnavailableException( ResultCodeEnum.UNAVAILABLE, I18n.err( I18n.ERR_316 ) );
1111            }
1112        }
1113        
1114        
1115        private void pop() 
1116        {
1117            // TODO - need to remove Context caller and PartitionNexusProxy from Invocations
1118            InvocationStack stack = InvocationStack.getInstance();
1119            stack.pop();
1120        }
1121    
1122    
1123        private void push( OperationContext opContext )
1124        {
1125            // TODO - need to remove Context caller and PartitionNexusProxy from Invocations
1126            InvocationStack stack = InvocationStack.getInstance();
1127            stack.push( opContext );
1128        }
1129    }