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;
021
022
023import static org.apache.directory.api.ldap.model.message.ResultCodeEnum.processResponse;
024
025import java.io.IOException;
026import java.util.Collection;
027import java.util.Iterator;
028import java.util.List;
029
030import org.apache.directory.api.asn1.util.Oid;
031import org.apache.directory.api.ldap.codec.api.BinaryAttributeDetector;
032import org.apache.directory.api.ldap.codec.api.LdapApiService;
033import org.apache.directory.api.ldap.model.constants.SchemaConstants;
034import org.apache.directory.api.ldap.model.cursor.Cursor;
035import org.apache.directory.api.ldap.model.cursor.EmptyCursor;
036import org.apache.directory.api.ldap.model.cursor.EntryCursor;
037import org.apache.directory.api.ldap.model.cursor.SearchCursor;
038import org.apache.directory.api.ldap.model.entry.Attribute;
039import org.apache.directory.api.ldap.model.entry.DefaultModification;
040import org.apache.directory.api.ldap.model.entry.Entry;
041import org.apache.directory.api.ldap.model.entry.Modification;
042import org.apache.directory.api.ldap.model.entry.ModificationOperation;
043import org.apache.directory.api.ldap.model.entry.Value;
044import org.apache.directory.api.ldap.model.exception.LdapException;
045import org.apache.directory.api.ldap.model.exception.LdapNoPermissionException;
046import org.apache.directory.api.ldap.model.exception.LdapOperationException;
047import org.apache.directory.api.ldap.model.message.AbandonRequest;
048import org.apache.directory.api.ldap.model.message.AddRequest;
049import org.apache.directory.api.ldap.model.message.AddRequestImpl;
050import org.apache.directory.api.ldap.model.message.AddResponse;
051import org.apache.directory.api.ldap.model.message.AddResponseImpl;
052import org.apache.directory.api.ldap.model.message.AliasDerefMode;
053import org.apache.directory.api.ldap.model.message.BindRequest;
054import org.apache.directory.api.ldap.model.message.BindRequestImpl;
055import org.apache.directory.api.ldap.model.message.BindResponse;
056import org.apache.directory.api.ldap.model.message.BindResponseImpl;
057import org.apache.directory.api.ldap.model.message.CompareRequest;
058import org.apache.directory.api.ldap.model.message.CompareRequestImpl;
059import org.apache.directory.api.ldap.model.message.CompareResponse;
060import org.apache.directory.api.ldap.model.message.CompareResponseImpl;
061import org.apache.directory.api.ldap.model.message.Control;
062import org.apache.directory.api.ldap.model.message.DeleteRequest;
063import org.apache.directory.api.ldap.model.message.DeleteRequestImpl;
064import org.apache.directory.api.ldap.model.message.DeleteResponse;
065import org.apache.directory.api.ldap.model.message.DeleteResponseImpl;
066import org.apache.directory.api.ldap.model.message.ExtendedRequest;
067import org.apache.directory.api.ldap.model.message.ExtendedResponse;
068import org.apache.directory.api.ldap.model.message.LdapResult;
069import org.apache.directory.api.ldap.model.message.Message;
070import org.apache.directory.api.ldap.model.message.ModifyDnRequest;
071import org.apache.directory.api.ldap.model.message.ModifyDnRequestImpl;
072import org.apache.directory.api.ldap.model.message.ModifyDnResponse;
073import org.apache.directory.api.ldap.model.message.ModifyDnResponseImpl;
074import org.apache.directory.api.ldap.model.message.ModifyRequest;
075import org.apache.directory.api.ldap.model.message.ModifyRequestImpl;
076import org.apache.directory.api.ldap.model.message.ModifyResponse;
077import org.apache.directory.api.ldap.model.message.ModifyResponseImpl;
078import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
079import org.apache.directory.api.ldap.model.message.ResultResponseRequest;
080import org.apache.directory.api.ldap.model.message.SearchRequest;
081import org.apache.directory.api.ldap.model.message.SearchRequestImpl;
082import org.apache.directory.api.ldap.model.message.SearchScope;
083import org.apache.directory.api.ldap.model.name.Dn;
084import org.apache.directory.api.ldap.model.name.Rdn;
085import org.apache.directory.api.ldap.model.schema.SchemaManager;
086import org.apache.directory.api.util.exception.NotImplementedException;
087import org.apache.directory.ldap.client.api.AbstractLdapConnection;
088import org.apache.directory.ldap.client.api.EntryCursorImpl;
089import org.apache.directory.ldap.client.api.SaslRequest;
090import org.apache.directory.server.core.api.interceptor.context.BindOperationContext;
091import org.slf4j.Logger;
092import org.slf4j.LoggerFactory;
093
094
095/**
096 *  An implementation of LdapConnection based on the CoreSession.
097 *
098 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
099 */
100public class LdapCoreSessionConnection extends AbstractLdapConnection
101{
102    /** The logger for this class */
103    private static final Logger LOG = LoggerFactory.getLogger( LdapCoreSessionConnection.class );
104
105    /** the CoreSession object */
106    private CoreSession session;
107
108    /** the session's DirectoryService */
109    private DirectoryService directoryService;
110
111
112    public LdapCoreSessionConnection()
113    {
114        super();
115    }
116
117
118    public LdapCoreSessionConnection( DirectoryService directoryService )
119    {
120        super();
121        setDirectoryService( directoryService );
122    }
123
124
125    public LdapCoreSessionConnection( CoreSession session )
126    {
127        super();
128        this.session = session;
129        setDirectoryService( session.getDirectoryService() );
130
131        // treat the session was already bound, hence increment the message ID
132        messageId.incrementAndGet();
133    }
134
135
136    /**
137     * {@inheritDoc}
138     */
139    @Override
140    public void close() throws IOException
141    {
142        try
143        {
144            unBind();
145        }
146        catch ( Exception e )
147        {
148            IOException ioe = new IOException( e.getMessage() );
149            ioe.initCause( e );
150            throw ioe;
151        }
152    }
153
154
155    /**
156     * {@inheritDoc}
157     */
158    @Override
159    public boolean connect() throws LdapException
160    {
161        return true;
162    }
163
164
165    /**
166     * {@inheritDoc}
167     */
168    @Override
169    public AddResponse add( AddRequest addRequest ) throws LdapException
170    {
171        if ( addRequest == null )
172        {
173            String msg = "Cannot process a null addRequest";
174            LOG.debug( msg );
175            throw new IllegalArgumentException( msg );
176        }
177
178        if ( addRequest.getEntry() == null )
179        {
180            String msg = "Cannot add a null entry";
181            LOG.debug( msg );
182            throw new IllegalArgumentException( msg );
183        }
184
185        int newId = messageId.incrementAndGet();
186
187        addRequest.setMessageId( newId );
188
189        AddResponse resp = new AddResponseImpl( newId );
190        resp.getLdapResult().setResultCode( ResultCodeEnum.SUCCESS );
191
192        try
193        {
194            session.add( addRequest );
195        }
196        catch ( LdapException e )
197        {
198            LOG.warn( e.getMessage(), e );
199
200            resp.getLdapResult().setResultCode( ResultCodeEnum.getResultCode( e ) );
201            resp.getLdapResult().setDiagnosticMessage( e.getMessage() );
202        }
203
204        addResponseControls( addRequest, resp );
205        return resp;
206    }
207
208
209    /**
210     * {@inheritDoc}
211     */
212    @Override
213    public void add( Entry entry ) throws LdapException
214    {
215        if ( entry == null )
216        {
217            String msg = "Cannot add an empty entry";
218            LOG.debug( msg );
219            throw new IllegalArgumentException( msg );
220        }
221
222        AddRequest addRequest = new AddRequestImpl();
223        addRequest.setEntry( entry );
224        addRequest.setEntryDn( entry.getDn() );
225
226        AddResponse addResponse = add( addRequest );
227
228        processResponse( addResponse );
229    }
230
231
232    /**
233     * Process the SASL Bind. It's a dialog with the server, we will send a first BindRequest, receive
234     * a response and the, if this response is a challenge, continue by sending a new BindRequest with
235     * the requested informations.
236     *
237     * @param saslRequest The SASL request object containing all the needed parameters
238     * @return A {@link BindResponse} containing the result
239     * @throws LdapException if some error occurred
240     */
241    @Override
242    public BindResponse bind( SaslRequest saslRequest ) throws LdapException
243    {
244        throw new NotImplementedException();
245    }
246
247
248    /**
249     * {@inheritDoc}
250     */
251    @Override
252    public CompareResponse compare( CompareRequest compareRequest ) throws LdapException
253    {
254        if ( compareRequest == null )
255        {
256            String msg = "Cannot process a null compareRequest";
257            LOG.debug( msg );
258            throw new IllegalArgumentException( msg );
259        }
260
261        int newId = messageId.incrementAndGet();
262
263        CompareResponse resp = new CompareResponseImpl( newId );
264        resp.getLdapResult().setResultCode( ResultCodeEnum.COMPARE_TRUE );
265
266        try
267        {
268            session.compare( compareRequest );
269        }
270        catch ( Exception e )
271        {
272            resp.getLdapResult().setResultCode( ResultCodeEnum.getResultCode( e ) );
273        }
274
275        addResponseControls( compareRequest, resp );
276        return resp;
277    }
278
279
280    /**
281     * {@inheritDoc}
282     */
283    @Override
284    public boolean compare( Dn dn, String attributeName, byte[] value ) throws LdapException
285    {
286        CompareRequest compareRequest = new CompareRequestImpl();
287        compareRequest.setName( dn );
288        compareRequest.setAttributeId( attributeName );
289        compareRequest.setAssertionValue( value );
290
291        CompareResponse compareResponse = compare( compareRequest );
292
293        return processResponse( compareResponse );
294    }
295
296
297    /**
298     * {@inheritDoc}
299     */
300    @Override
301    public boolean compare( Dn dn, String attributeName, String value ) throws LdapException
302    {
303        CompareRequest compareRequest = new CompareRequestImpl();
304        compareRequest.setName( dn );
305        compareRequest.setAttributeId( attributeName );
306        compareRequest.setAssertionValue( value );
307
308        CompareResponse compareResponse = compare( compareRequest );
309
310        return processResponse( compareResponse );
311    }
312
313
314    /**
315     * {@inheritDoc}
316     */
317    @Override
318    public boolean compare( String dn, String attributeName, byte[] value ) throws LdapException
319    {
320        return compare( new Dn( schemaManager, dn ), attributeName, value );
321    }
322
323
324    /**
325     * {@inheritDoc}
326     */
327    @Override
328    public boolean compare( String dn, String attributeName, String value ) throws LdapException
329    {
330        return compare( new Dn( schemaManager, dn ), attributeName, value );
331    }
332
333
334    /**
335     * {@inheritDoc}
336     */
337    @Override
338    public boolean compare( Dn dn, String attributeName, Value value ) throws LdapException
339    {
340        CompareRequest compareRequest = new CompareRequestImpl();
341        compareRequest.setName( dn );
342        compareRequest.setAttributeId( attributeName );
343
344        if ( value.isHumanReadable() )
345        {
346            compareRequest.setAssertionValue( value.getString() );
347        }
348        else
349        {
350            compareRequest.setAssertionValue( value.getBytes() );
351        }
352
353        CompareResponse compareResponse = compare( compareRequest );
354
355        return processResponse( compareResponse );
356    }
357
358
359    /**
360     * {@inheritDoc}
361     */
362    @Override
363    public boolean compare( String dn, String attributeName, Value value ) throws LdapException
364    {
365        return compare( new Dn( schemaManager, dn ), attributeName, value );
366    }
367
368
369    /**
370     * {@inheritDoc}
371     */
372    @Override
373    public DeleteResponse delete( DeleteRequest deleteRequest ) throws LdapException
374    {
375        if ( deleteRequest == null )
376        {
377            String msg = "Cannot process a null deleteRequest";
378            LOG.debug( msg );
379            throw new IllegalArgumentException( msg );
380        }
381
382        int newId = messageId.incrementAndGet();
383
384        DeleteResponse resp = new DeleteResponseImpl( newId );
385        resp.getLdapResult().setResultCode( ResultCodeEnum.SUCCESS );
386
387        try
388        {
389            session.delete( deleteRequest );
390        }
391        catch ( LdapException e )
392        {
393            LOG.warn( e.getMessage(), e );
394
395            resp.getLdapResult().setResultCode( ResultCodeEnum.getResultCode( e ) );
396            resp.getLdapResult().setDiagnosticMessage( e.getMessage() );
397        }
398
399        addResponseControls( deleteRequest, resp );
400
401        return resp;
402    }
403
404
405    /**
406     * {@inheritDoc}
407     */
408    @Override
409    public void delete( Dn dn ) throws LdapException
410    {
411        DeleteRequest deleteRequest = new DeleteRequestImpl();
412        deleteRequest.setName( dn );
413
414        DeleteResponse deleteResponse = delete( deleteRequest );
415
416        processResponse( deleteResponse );
417    }
418
419
420    /**
421     * {@inheritDoc}
422     */
423    @Override
424    public void delete( String dn ) throws LdapException
425    {
426        delete( new Dn( schemaManager, dn ) );
427    }
428
429
430    /**
431     * {@inheritDoc}
432     */
433    @Override
434    public boolean isRequestCompleted( int messageId )
435    {
436        return false;
437    }
438
439
440    /**
441     * {@inheritDoc}
442     */
443    @Override
444    public boolean doesFutureExistFor( int messageId )
445    {
446        return false;
447    }
448
449
450    /**
451     * {@inheritDoc}
452     */
453    @Override
454    public SchemaManager getSchemaManager()
455    {
456        return schemaManager;
457    }
458
459
460    /**
461     * {@inheritDoc}
462     */
463    @Override
464    public LdapApiService getCodecService()
465    {
466        return codec;
467    }
468
469
470    /**
471     * {@inheritDoc}
472     */
473    @Override
474    public List<String> getSupportedControls() throws LdapException
475    {
476        return null;
477    }
478
479
480    /**
481     * {@inheritDoc}
482     */
483    @Override
484    public boolean isAuthenticated()
485    {
486        return session != null;
487    }
488
489
490    /**
491     * {@inheritDoc}
492     */
493    @Override
494    public boolean isConnected()
495    {
496        return true;
497    }
498
499
500    /**
501     * {@inheritDoc}
502     */
503    @Override
504    public boolean isControlSupported( String controlOID ) throws LdapException
505    {
506        return false;
507    }
508
509
510    /**
511     * {@inheritDoc}
512     */
513    @Override
514    public void loadSchema() throws LdapException
515    {
516        // do nothing, cause we already have SchemaManager in the session's DirectoryService
517    }
518
519
520    /**
521     * {@inheritDoc}
522     */
523    @Override
524    public void loadSchemaRelaxed() throws LdapException
525    {
526        // do nothing, cause we already have SchemaManager in the session's DirectoryService
527    }
528
529
530    /**
531     * {@inheritDoc}
532     */
533    @Override
534    public Entry lookup( Dn dn, String... attributes ) throws LdapException
535    {
536        return lookup( dn, null, attributes );
537    }
538
539
540    /**
541     * {@inheritDoc}
542     */
543    @Override
544    public Entry lookup( Dn dn, Control[] controls, String... attributes ) throws LdapException
545    {
546        messageId.incrementAndGet();
547
548        Entry entry = null;
549
550        try
551        {
552            entry = session.lookup( dn, controls, attributes );
553        }
554        catch ( LdapException e )
555        {
556            LOG.warn( e.getMessage(), e );
557        }
558
559        return entry;
560    }
561
562
563    /**
564     * {@inheritDoc}
565     */
566    @Override
567    public Entry lookup( String dn, String... attributes ) throws LdapException
568    {
569        Dn baseDn = new Dn( schemaManager, dn );
570
571        return lookup( baseDn, null, attributes );
572    }
573
574
575    /**
576     * {@inheritDoc}
577     */
578    @Override
579    public Entry lookup( String dn, Control[] controls, String... attributes ) throws LdapException
580    {
581        Dn baseDn = new Dn( schemaManager, dn );
582
583        return lookup( baseDn, controls, attributes );
584    }
585
586
587    /**
588     * {@inheritDoc}
589     */
590    @Override
591    public boolean exists( String dn ) throws LdapException
592    {
593        return exists( new Dn( schemaManager, dn ) );
594    }
595
596
597    /**
598     * {@inheritDoc}
599     */
600    @Override
601    public boolean exists( Dn dn ) throws LdapException
602    {
603        try
604        {
605            Entry entry = lookup( dn, SchemaConstants.NO_ATTRIBUTE );
606
607            return entry != null;
608        }
609        catch ( LdapNoPermissionException lnpe )
610        {
611            // Special case to deal with insufficient permissions
612            LOG.info( lnpe.getMessage(), lnpe );
613
614            return false;
615        }
616        catch ( LdapException le )
617        {
618            throw le;
619        }
620    }
621
622
623    /**
624     * {@inheritDoc}
625     */
626    @Override
627    public Entry getRootDse() throws LdapException
628    {
629        return lookup( Dn.ROOT_DSE, SchemaConstants.ALL_USER_ATTRIBUTES_ARRAY );
630    }
631
632
633    /**
634     * {@inheritDoc}
635     */
636    @Override
637    public Entry getRootDse( String... attributes ) throws LdapException
638    {
639        return lookup( Dn.ROOT_DSE, attributes );
640    }
641
642
643    /**
644     * {@inheritDoc}
645     */
646    @Override
647    public Entry lookup( Dn dn ) throws LdapException
648    {
649        return lookup( dn, ( String[] ) null );
650    }
651
652
653    /**
654     * {@inheritDoc}
655     */
656    @Override
657    public Entry lookup( String dn ) throws LdapException
658    {
659        return lookup( new Dn( schemaManager, dn ), ( String[] ) null );
660    }
661
662
663    /**
664     * {@inheritDoc}
665     */
666    @Override
667    public void modify( Dn dn, Modification... modifications ) throws LdapException
668    {
669        if ( dn == null )
670        {
671            LOG.debug( "received a null dn for modification" );
672            throw new IllegalArgumentException( "The Dn to be modified cannot be null" );
673        }
674
675        if ( ( modifications == null ) || ( modifications.length == 0 ) )
676        {
677            String msg = "Cannot process a ModifyRequest without any modification";
678            LOG.debug( msg );
679            throw new IllegalArgumentException( msg );
680        }
681
682        int newId = messageId.incrementAndGet();
683
684        ModifyRequest modifyRequest = new ModifyRequestImpl();
685        modifyRequest.setMessageId( newId );
686
687        modifyRequest.setName( dn );
688
689        for ( Modification modification : modifications )
690        {
691            modifyRequest.addModification( modification );
692        }
693
694        ModifyResponse modifyResponse = modify( modifyRequest );
695
696        processResponse( modifyResponse );
697    }
698
699
700    /**
701     * {@inheritDoc}
702     */
703    @Override
704    public void modify( String dn, Modification... modifications ) throws LdapException
705    {
706        modify( new Dn( schemaManager, dn ), modifications );
707    }
708
709
710    /**
711     * {@inheritDoc}
712     */
713    @Override
714    public void modify( Entry entry, ModificationOperation modOp ) throws LdapException
715    {
716        if ( entry == null )
717        {
718            LOG.debug( "received a null entry for modification" );
719            throw new IllegalArgumentException( "Entry to be modified cannot be null" );
720        }
721
722        int newId = messageId.incrementAndGet();
723        ModifyRequest modifyRequest = new ModifyRequestImpl();
724        modifyRequest.setMessageId( newId );
725
726        modifyRequest.setName( entry.getDn() );
727
728        Iterator<Attribute> itr = entry.iterator();
729
730        while ( itr.hasNext() )
731        {
732            modifyRequest.addModification( new DefaultModification( modOp, itr.next() ) );
733        }
734
735        ModifyResponse modifyResponse = modify( modifyRequest );
736
737        processResponse( modifyResponse );
738    }
739
740
741    /**
742     * {@inheritDoc}
743     */
744    @Override
745    public ModifyResponse modify( ModifyRequest modRequest ) throws LdapException
746    {
747        if ( modRequest == null )
748        {
749            String msg = "Cannot process a null modifyRequest";
750            LOG.debug( msg );
751            throw new IllegalArgumentException( msg );
752        }
753
754        int newId = messageId.incrementAndGet();
755
756        modRequest.setMessageId( newId );
757        ModifyResponse resp = new ModifyResponseImpl( newId );
758        resp.getLdapResult().setResultCode( ResultCodeEnum.SUCCESS );
759
760        try
761        {
762            session.modify( modRequest );
763        }
764        catch ( LdapException e )
765        {
766            LOG.warn( e.getMessage(), e );
767
768            resp.getLdapResult().setResultCode( ResultCodeEnum.getResultCode( e ) );
769            resp.getLdapResult().setDiagnosticMessage( e.getMessage() );
770        }
771
772        addResponseControls( modRequest, resp );
773
774        return resp;
775    }
776
777
778    /**
779     * {@inheritDoc}
780     */
781    @Override
782    public ModifyDnResponse modifyDn( ModifyDnRequest modDnRequest ) throws LdapException
783    {
784        if ( modDnRequest == null )
785        {
786            String msg = "Cannot process a null modDnRequest";
787            LOG.debug( msg );
788            throw new IllegalArgumentException( msg );
789        }
790
791        int newId = messageId.incrementAndGet();
792
793        ModifyDnResponse resp = new ModifyDnResponseImpl( newId );
794        LdapResult result = resp.getLdapResult();
795        result.setResultCode( ResultCodeEnum.SUCCESS );
796
797        if ( modDnRequest.getName().isEmpty() )
798        {
799            // it is not allowed to modify the name of the Root DSE
800            String msg = "Modify Dn is not allowed on Root DSE.";
801            result.setResultCode( ResultCodeEnum.PROTOCOL_ERROR );
802            result.setDiagnosticMessage( msg );
803
804            return resp;
805        }
806
807        try
808        {
809            Rdn newRdn = modDnRequest.getNewRdn();
810
811            if ( ( newRdn != null ) && !newRdn.isSchemaAware() )
812            {
813                modDnRequest.setNewRdn( new Rdn( schemaManager, newRdn ) );
814            }
815
816            Rdn oldRdn = modDnRequest.getName().getRdn();
817
818            if ( !modDnRequest.getName().isSchemaAware() )
819            {
820                modDnRequest.setName( new Dn( schemaManager, modDnRequest.getName() ) );
821                oldRdn = modDnRequest.getName().getRdn();
822            }
823
824            boolean rdnChanged = modDnRequest.getNewRdn() != null
825                && !newRdn.getNormName().equals( oldRdn.getNormName() );
826
827            if ( rdnChanged )
828            {
829                if ( modDnRequest.getNewSuperior() != null )
830                {
831                    session.moveAndRename( modDnRequest );
832                }
833                else
834                {
835                    session.rename( modDnRequest );
836                }
837            }
838            else if ( modDnRequest.getNewSuperior() != null )
839            {
840                modDnRequest.setNewRdn( null );
841                session.move( modDnRequest );
842            }
843            else
844            {
845                // This might be a simple change, we will update the DN and the entry
846                // with the new provided value by using a modify operation later on
847                session.rename( modDnRequest );
848            }
849
850        }
851        catch ( LdapException e )
852        {
853            LOG.warn( e.getMessage(), e );
854
855            resp.getLdapResult().setResultCode( ResultCodeEnum.getResultCode( e ) );
856            resp.getLdapResult().setDiagnosticMessage( e.getMessage() );
857        }
858
859        addResponseControls( modDnRequest, resp );
860        return resp;
861    }
862
863
864    /**
865     * {@inheritDoc}
866     */
867    @Override
868    public void move( Dn entryDn, Dn newSuperiorDn ) throws LdapException
869    {
870        if ( entryDn == null )
871        {
872            String msg = "Cannot process a move of a null Dn";
873            LOG.debug( msg );
874            throw new IllegalArgumentException( msg );
875        }
876
877        if ( newSuperiorDn == null )
878        {
879            String msg = "Cannot process a move to a null Dn";
880            LOG.debug( msg );
881            throw new IllegalArgumentException( msg );
882        }
883
884        ModifyDnRequest modDnReq = new ModifyDnRequestImpl();
885        modDnReq.setName( entryDn );
886        modDnReq.setNewSuperior( newSuperiorDn );
887
888        ModifyDnResponse modifyDnResponse = modifyDn( modDnReq );
889        processResponse( modifyDnResponse );
890    }
891
892
893    /**
894     * {@inheritDoc}
895     */
896    @Override
897    public void move( String entryDn, String newSuperiorDn ) throws LdapException
898    {
899        if ( entryDn == null )
900        {
901            String msg = "Cannot process a move of a null Dn";
902            LOG.debug( msg );
903            throw new IllegalArgumentException( msg );
904        }
905
906        if ( newSuperiorDn == null )
907        {
908            String msg = "Cannot process a move to a null Dn";
909            LOG.debug( msg );
910            throw new IllegalArgumentException( msg );
911        }
912
913        move( new Dn( schemaManager, entryDn ), new Dn( schemaManager, newSuperiorDn ) );
914    }
915
916
917    /**
918     * {@inheritDoc}
919     */
920    @Override
921    public void rename( Dn entryDn, Rdn newRdn, boolean deleteOldRdn ) throws LdapException
922    {
923        if ( entryDn == null )
924        {
925            String msg = "Cannot process a rename of a null Dn";
926            LOG.debug( msg );
927            throw new IllegalArgumentException( msg );
928        }
929
930        if ( newRdn == null )
931        {
932            String msg = "Cannot process a rename with a null Rdn";
933            LOG.debug( msg );
934            throw new IllegalArgumentException( msg );
935        }
936
937        ModifyDnRequest modifyDnRequest = new ModifyDnRequestImpl();
938        modifyDnRequest.setName( entryDn );
939        modifyDnRequest.setNewRdn( newRdn );
940        modifyDnRequest.setDeleteOldRdn( deleteOldRdn );
941
942        ModifyDnResponse modifyDnResponse = modifyDn( modifyDnRequest );
943        processResponse( modifyDnResponse );
944
945    }
946
947
948    /**
949     * {@inheritDoc}
950     */
951    @Override
952    public void rename( Dn entryDn, Rdn newRdn ) throws LdapException
953    {
954        rename( entryDn, newRdn, false );
955    }
956
957
958    /**
959     * {@inheritDoc}
960     */
961    @Override
962    public void rename( String entryDn, String newRdn, boolean deleteOldRdn ) throws LdapException
963    {
964        rename( new Dn( schemaManager, entryDn ), new Rdn( newRdn ), deleteOldRdn );
965    }
966
967
968    /**
969     * {@inheritDoc}
970     */
971    @Override
972    public void rename( String entryDn, String newRdn ) throws LdapException
973    {
974        if ( entryDn == null )
975        {
976            String msg = "Cannot process a rename of a null Dn";
977            LOG.debug( msg );
978            throw new IllegalArgumentException( msg );
979        }
980
981        if ( newRdn == null )
982        {
983            String msg = "Cannot process a rename with a null Rdn";
984            LOG.debug( msg );
985            throw new IllegalArgumentException( msg );
986        }
987
988        rename( new Dn( schemaManager, entryDn ), new Rdn( schemaManager, newRdn ) );
989    }
990
991
992    /**
993     * Moves and renames the given entryDn.The old Rdn will be deleted
994     *
995     * @see #moveAndRename(org.apache.directory.api.ldap.model.name.Dn, org.apache.directory.api.ldap.model.name.Dn, boolean)
996     */
997    @Override
998    public void moveAndRename( Dn entryDn, Dn newDn ) throws LdapException
999    {
1000        moveAndRename( entryDn, newDn, true );
1001    }
1002
1003
1004    /**
1005     * Moves and renames the given entryDn.The old Rdn will be deleted
1006     *
1007     * @see #moveAndRename(org.apache.directory.api.ldap.model.name.Dn, org.apache.directory.api.ldap.model.name.Dn, boolean)
1008     */
1009    @Override
1010    public void moveAndRename( String entryDn, String newDn ) throws LdapException
1011    {
1012        moveAndRename( new Dn( schemaManager, entryDn ), new Dn( schemaManager, newDn ), true );
1013    }
1014
1015
1016    /**
1017     * Moves and renames the given entryDn.The old Rdn will be deleted if requested
1018     *
1019     * @param entryDn The original entry Dn
1020     * @param newDn The new Entry Dn
1021     * @param deleteOldRdn Tells if the old Rdn must be removed
1022     */
1023    @Override
1024    public void moveAndRename( Dn entryDn, Dn newDn, boolean deleteOldRdn ) throws LdapException
1025    {
1026        // Check the parameters first
1027        if ( entryDn == null )
1028        {
1029            throw new IllegalArgumentException( "The entry Dn must not be null" );
1030        }
1031
1032        if ( entryDn.isRootDse() )
1033        {
1034            throw new IllegalArgumentException( "The RootDSE cannot be moved" );
1035        }
1036
1037        if ( newDn == null )
1038        {
1039            throw new IllegalArgumentException( "The new Dn must not be null" );
1040        }
1041
1042        if ( newDn.isRootDse() )
1043        {
1044            throw new IllegalArgumentException( "The RootDSE cannot be the target" );
1045        }
1046
1047        ModifyDnResponse resp = new ModifyDnResponseImpl();
1048        resp.getLdapResult().setResultCode( ResultCodeEnum.SUCCESS );
1049
1050        ModifyDnRequest modifyDnRequest = new ModifyDnRequestImpl();
1051
1052        modifyDnRequest.setName( entryDn );
1053        modifyDnRequest.setNewRdn( newDn.getRdn() );
1054        modifyDnRequest.setNewSuperior( newDn.getParent() );
1055        modifyDnRequest.setDeleteOldRdn( deleteOldRdn );
1056
1057        ModifyDnResponse modifyDnResponse = modifyDn( modifyDnRequest );
1058        processResponse( modifyDnResponse );
1059    }
1060
1061
1062    /**
1063     * Moves and renames the given entryDn.The old Rdn will be deleted if requested
1064     *
1065     * @param entryDn The original entry Dn
1066     * @param newDn The new Entry Dn
1067     * @param deleteOldRdn Tells if the old Rdn must be removed
1068     */
1069    @Override
1070    public void moveAndRename( String entryDn, String newDn, boolean deleteOldRdn ) throws LdapException
1071    {
1072        moveAndRename( new Dn( schemaManager, entryDn ), new Dn( schemaManager, newDn ), deleteOldRdn );
1073    }
1074
1075
1076    /**
1077     * {@inheritDoc}
1078     */
1079    @Override
1080    public SearchCursor search( SearchRequest searchRequest ) throws LdapException
1081    {
1082        if ( searchRequest == null )
1083        {
1084            String msg = "Cannot process a null searchRequest";
1085            LOG.debug( msg );
1086            throw new IllegalArgumentException( msg );
1087        }
1088
1089        try
1090        {
1091            int newId = messageId.incrementAndGet();
1092
1093            searchRequest.setMessageId( newId );
1094
1095            Cursor<Entry> entryCursor = session.search( searchRequest );
1096            entryCursor.beforeFirst();
1097
1098            //TODO enforce the size and time limits, similar in the way SearchHandler does
1099            return new EntryToResponseCursor( searchRequest, newId, entryCursor );
1100        }
1101        catch ( Exception e )
1102        {
1103            LOG.warn( e.getMessage(), e );
1104        }
1105
1106        return new EntryToResponseCursor( searchRequest, -1, new EmptyCursor<Entry>() );
1107    }
1108
1109
1110    /**
1111     * {@inheritDoc}
1112     */
1113    @Override
1114    public EntryCursor search( Dn baseDn, String filter, SearchScope scope, String... attributes )
1115        throws LdapException
1116    {
1117        if ( baseDn == null )
1118        {
1119            LOG.debug( "received a null dn for a search" );
1120            throw new IllegalArgumentException( "The base Dn cannot be null" );
1121        }
1122
1123        // generate some random operation number
1124        SearchRequest searchRequest = new SearchRequestImpl();
1125
1126        searchRequest.setBase( baseDn );
1127
1128        searchRequest.setFilter( filter );
1129        searchRequest.setScope( scope );
1130        searchRequest.addAttributes( attributes );
1131        searchRequest.setDerefAliases( AliasDerefMode.DEREF_ALWAYS );
1132
1133        return new EntryCursorImpl( search( searchRequest ) );
1134    }
1135
1136
1137    /**
1138     * {@inheritDoc}
1139     */
1140    @Override
1141    public EntryCursor search( String baseDn, String filter, SearchScope scope, String... attributes )
1142        throws LdapException
1143    {
1144        return search( new Dn( schemaManager, baseDn ), filter, scope, attributes );
1145    }
1146
1147
1148    /**
1149     * {@inheritDoc}
1150     */
1151    @Override
1152    public void unBind() throws LdapException
1153    {
1154        messageId.set( 0 );
1155
1156        if ( session != null )
1157        {
1158            // No need to unbind if the session is anonymous
1159            if ( !session.isAnonymous() )
1160            {
1161                session.unbind();
1162            }
1163
1164            session = null;
1165        }
1166    }
1167
1168
1169    /**
1170     * {@inheritDoc}
1171     */
1172    @Override
1173    public ExtendedResponse extended( String oid ) throws LdapException
1174    {
1175        throw new UnsupportedOperationException(
1176            "extended operations are not supported on CoreSession based connection" );
1177    }
1178
1179
1180    /**
1181     * {@inheritDoc}
1182     */
1183    @Override
1184    public ExtendedResponse extended( ExtendedRequest extendedRequest ) throws LdapException
1185    {
1186        if ( extendedRequest == null )
1187        {
1188            String msg = "Cannot process a null extendedRequest";
1189            LOG.debug( msg );
1190            throw new IllegalArgumentException( msg );
1191        }
1192
1193        return extended( ( String ) null );
1194
1195    }
1196
1197
1198    /**
1199     * {@inheritDoc}
1200     */
1201    @Override
1202    public ExtendedResponse extended( Oid oid, byte[] value ) throws LdapException
1203    {
1204        return extended( ( String ) null );
1205    }
1206
1207
1208    /**
1209     * {@inheritDoc}
1210     */
1211    @Override
1212    public ExtendedResponse extended( Oid oid ) throws LdapException
1213    {
1214        return extended( ( String ) null );
1215    }
1216
1217
1218    /**
1219     * {@inheritDoc}
1220     */
1221    @Override
1222    public ExtendedResponse extended( String oid, byte[] value ) throws LdapException
1223    {
1224        return extended( ( String ) null );
1225    }
1226
1227
1228    /**
1229     * {@inheritDoc}
1230     */
1231    @Override
1232    public void setTimeOut( long timeOut )
1233    {
1234        throw new UnsupportedOperationException( "setting timeout is not supported on CoreSession" );
1235    }
1236
1237
1238    /**
1239     * {@inheritDoc}
1240     */
1241    @Override
1242    public void abandon( AbandonRequest abandonRequest )
1243    {
1244        throw new UnsupportedOperationException( "abandon operation is not supported" );
1245    }
1246
1247
1248    /**
1249     * {@inheritDoc}
1250     */
1251    @Override
1252    public void abandon( int messageId )
1253    {
1254        abandon( null );
1255    }
1256
1257
1258    /**
1259     * {@inheritDoc}
1260     */
1261    @Override
1262    public void bind() throws LdapException
1263    {
1264        throw new UnsupportedOperationException(
1265            "Bind operation using LdapConnectionConfig are not supported on CoreSession based connection" );
1266    }
1267
1268
1269    /**
1270     * {@inheritDoc}
1271     */
1272    @Override
1273    public void anonymousBind() throws LdapException
1274    {
1275        BindRequest bindRequest = new BindRequestImpl();
1276        bindRequest.setName( "" );
1277        bindRequest.setCredentials( ( byte[] ) null );
1278
1279        BindResponse bindResponse = bind( bindRequest );
1280
1281        processResponse( bindResponse );
1282    }
1283
1284
1285    /**
1286     * {@inheritDoc}
1287     */
1288    @Override
1289    public BindResponse bind( BindRequest bindRequest ) throws LdapException
1290    {
1291        if ( bindRequest == null )
1292        {
1293            String msg = "Cannot process a null bindRequest";
1294            LOG.debug( msg );
1295            throw new IllegalArgumentException( msg );
1296        }
1297
1298        int newId = messageId.incrementAndGet();
1299
1300        BindOperationContext bindContext = new BindOperationContext( null );
1301        bindContext.setCredentials( bindRequest.getCredentials() );
1302
1303        Dn bindDn =  bindRequest.getDn();
1304
1305        if ( !bindDn.isSchemaAware() )
1306        {
1307            bindDn = new Dn( directoryService.getSchemaManager(), bindDn );
1308        }
1309
1310        bindContext.setDn( bindDn );
1311        bindContext.setInterceptors( directoryService.getInterceptors( OperationEnum.BIND ) );
1312
1313        for ( Control control : bindRequest.getControls().values() )
1314        {
1315            bindContext.addRequestControl( control );
1316        }
1317
1318        OperationManager operationManager = directoryService.getOperationManager();
1319
1320        BindResponse bindResp = new BindResponseImpl( newId );
1321        bindResp.getLdapResult().setResultCode( ResultCodeEnum.SUCCESS );
1322
1323        try
1324        {
1325            if ( !bindRequest.isSimple() )
1326            {
1327                bindContext.setSaslMechanism( bindRequest.getSaslMechanism() );
1328            }
1329
1330            operationManager.bind( bindContext );
1331            session = bindContext.getSession();
1332
1333            bindResp.addAllControls( bindContext.getResponseControls() );
1334        }
1335        catch ( LdapOperationException e )
1336        {
1337            LOG.warn( e.getMessage(), e );
1338            LdapResult res = bindResp.getLdapResult();
1339            res.setDiagnosticMessage( e.getMessage() );
1340            res.setResultCode( e.getResultCode() );
1341        }
1342
1343        return bindResp;
1344    }
1345
1346
1347    private void addResponseControls( ResultResponseRequest iReq, Message clientResp )
1348    {
1349        Collection<Control> ctrlSet = iReq.getResultResponse().getControls().values();
1350
1351        for ( Control c : ctrlSet )
1352        {
1353            clientResp.addControl( c );
1354        }
1355    }
1356
1357
1358    public DirectoryService getDirectoryService()
1359    {
1360        return directoryService;
1361    }
1362
1363
1364    public void setDirectoryService( DirectoryService directoryService )
1365    {
1366        this.directoryService = directoryService;
1367        this.schemaManager = directoryService.getSchemaManager();
1368        this.session = directoryService.getAdminSession();
1369    }
1370
1371
1372    /**
1373     * {@inheritDoc}
1374     */
1375    @Override
1376    public BinaryAttributeDetector getBinaryAttributeDetector()
1377    {
1378        return null;
1379    }
1380
1381
1382    /**
1383     * {@inheritDoc}
1384     */
1385    @Override
1386    public void setBinaryAttributeDetector( BinaryAttributeDetector binaryAttributeDetector )
1387    {
1388        // Does nothing
1389    }
1390
1391
1392    /**
1393     * {@inheritDoc}
1394     */
1395    @Override
1396    public void setSchemaManager( SchemaManager schemaManager )
1397    {
1398        this.schemaManager = schemaManager;
1399    }
1400
1401
1402    /**
1403     * @return The session, if we have some
1404     */
1405    public CoreSession getSession()
1406    {
1407        return session;
1408    }
1409}