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 }