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
021package org.apache.directory.api.dsmlv2.engine;
022
023
024import java.io.BufferedWriter;
025import java.io.ByteArrayOutputStream;
026import java.io.File;
027import java.io.IOException;
028import java.io.InputStream;
029import java.io.OutputStream;
030import java.io.OutputStreamWriter;
031import java.nio.charset.StandardCharsets;
032
033import org.apache.commons.codec.Charsets;
034import org.apache.directory.api.dsmlv2.DsmlDecorator;
035import org.apache.directory.api.dsmlv2.Dsmlv2Parser;
036import org.apache.directory.api.dsmlv2.ParserUtils;
037import org.apache.directory.api.dsmlv2.request.BatchRequestDsml;
038import org.apache.directory.api.dsmlv2.request.BatchRequestDsml.OnError;
039import org.apache.directory.api.dsmlv2.request.BatchRequestDsml.Processing;
040import org.apache.directory.api.dsmlv2.request.BatchRequestDsml.ResponseOrder;
041import org.apache.directory.api.dsmlv2.request.Dsmlv2Grammar;
042import org.apache.directory.api.dsmlv2.response.AddResponseDsml;
043import org.apache.directory.api.dsmlv2.response.BatchResponseDsml;
044import org.apache.directory.api.dsmlv2.response.BindResponseDsml;
045import org.apache.directory.api.dsmlv2.response.CompareResponseDsml;
046import org.apache.directory.api.dsmlv2.response.DelResponseDsml;
047import org.apache.directory.api.dsmlv2.response.ErrorResponse;
048import org.apache.directory.api.dsmlv2.response.ErrorResponse.ErrorResponseType;
049import org.apache.directory.api.dsmlv2.response.ExtendedResponseDsml;
050import org.apache.directory.api.dsmlv2.response.ModDNResponseDsml;
051import org.apache.directory.api.dsmlv2.response.ModifyResponseDsml;
052import org.apache.directory.api.dsmlv2.response.SearchResponseDsml;
053import org.apache.directory.api.dsmlv2.response.SearchResultDoneDsml;
054import org.apache.directory.api.dsmlv2.response.SearchResultEntryDsml;
055import org.apache.directory.api.dsmlv2.response.SearchResultReferenceDsml;
056import org.apache.directory.api.i18n.I18n;
057import org.apache.directory.api.ldap.model.cursor.SearchCursor;
058import org.apache.directory.api.ldap.model.exception.LdapException;
059import org.apache.directory.api.ldap.model.message.AbandonRequest;
060import org.apache.directory.api.ldap.model.message.AddRequest;
061import org.apache.directory.api.ldap.model.message.AddResponse;
062import org.apache.directory.api.ldap.model.message.BindRequest;
063import org.apache.directory.api.ldap.model.message.BindRequestImpl;
064import org.apache.directory.api.ldap.model.message.BindResponse;
065import org.apache.directory.api.ldap.model.message.CompareRequest;
066import org.apache.directory.api.ldap.model.message.CompareResponse;
067import org.apache.directory.api.ldap.model.message.DeleteRequest;
068import org.apache.directory.api.ldap.model.message.DeleteResponse;
069import org.apache.directory.api.ldap.model.message.ExtendedRequest;
070import org.apache.directory.api.ldap.model.message.ExtendedResponse;
071import org.apache.directory.api.ldap.model.message.MessageTypeEnum;
072import org.apache.directory.api.ldap.model.message.ModifyDnRequest;
073import org.apache.directory.api.ldap.model.message.ModifyDnResponse;
074import org.apache.directory.api.ldap.model.message.ModifyRequest;
075import org.apache.directory.api.ldap.model.message.ModifyResponse;
076import org.apache.directory.api.ldap.model.message.Request;
077import org.apache.directory.api.ldap.model.message.Response;
078import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
079import org.apache.directory.api.ldap.model.message.SearchRequest;
080import org.apache.directory.api.ldap.model.message.SearchResultDone;
081import org.apache.directory.api.ldap.model.message.SearchResultEntry;
082import org.apache.directory.api.ldap.model.message.SearchResultReference;
083import org.apache.directory.api.util.Strings;
084import org.apache.directory.ldap.client.api.LdapConnection;
085import org.apache.directory.ldap.client.api.LdapNetworkConnection;
086import org.dom4j.Element;
087import org.dom4j.Namespace;
088import org.slf4j.Logger;
089import org.slf4j.LoggerFactory;
090import org.xmlpull.v1.XmlPullParserException;
091
092
093/**
094 * This is the DSMLv2Engine. It can be use to execute operations on a LDAP Server and get the results of these operations.
095 * The format used for request and responses is the DSMLv2 format.
096 *
097 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
098 */
099public class Dsmlv2Engine
100{
101    /** The user. */
102    protected String user;
103
104    /** The password. */
105    protected String password;
106
107    /** The LDAP connection */
108    protected LdapConnection connection;
109
110    /** The DSVMv2 parser. */
111    protected Dsmlv2Parser parser;
112
113    /** The continue on error flag. */
114    protected boolean continueOnError;
115
116    /** The exit flag. */
117    protected boolean exit = false;
118
119    /** The batch request. */
120    protected BatchRequestDsml batchRequest;
121
122    /** The batch response. */
123    protected BatchResponseDsml batchResponse = new BatchResponseDsml();
124
125    protected Dsmlv2Grammar grammar = new Dsmlv2Grammar();
126
127    /** flag to indicate to generate the response in a SOAP envelope */
128    protected boolean generateSoapResp = false;
129
130    /** A logger for this class */
131    private static final Logger LOG = LoggerFactory.getLogger( Dsmlv2Engine.class );
132    
133    private static final String BODY_ENVELOPE = "</Body></Envelope>";
134
135
136    /**
137     * Creates a new instance of Dsmlv2Engine.
138     * 
139     * @param host the server host
140     * @param port the server port
141     * @param user the server admin Dn
142     * @param password the server admin's password
143     */
144    public Dsmlv2Engine( String host, int port, String user, String password )
145    {
146        this.user = user;
147        this.password = password;
148
149        connection = new LdapNetworkConnection( host, port );
150    }
151
152
153    /**
154     * Creates a new instance of Dsmlv2Engine.
155     *
156     * @param connection an unbound active connection
157     * @param user the user name to be used to bind this connection to the server
158     * @param password user's credentials
159     */
160    public Dsmlv2Engine( LdapConnection connection, String user, String password )
161    {
162        this.user = user;
163        this.password = password;
164
165        this.connection = connection;
166    }
167
168
169    /**
170     * Processes the file given and return the result of the operations
171     * 
172     * @param dsmlInput the DSMLv2 formatted request input
173     * @return the XML response in DSMLv2 Format
174     * @throws XmlPullParserException if an error occurs in the parser
175     */
176    public String processDSML( String dsmlInput ) throws XmlPullParserException
177    {
178        parser = new Dsmlv2Parser( grammar );
179        parser.setInput( dsmlInput );
180
181        return processDSML();
182    }
183
184
185    /**
186     * Processes the file given and return the result of the operations
187     * 
188     * @param fileName the path to the file
189     * @return the XML response in DSMLv2 Format
190     * @throws XmlPullParserException if an error occurs in the parser
191     * @throws IOException if the file does not exist
192     */
193    public String processDSMLFile( String fileName ) throws XmlPullParserException, IOException
194    {
195        parser = new Dsmlv2Parser( grammar );
196        parser.setInputFile( fileName );
197
198        return processDSML();
199    }
200
201
202    /**
203     * Process the given file and optionally writing the output to the
204     * output stream(if not null)
205     *
206     * @param file the DSML file
207     * @param respStream the output stream to which response will be written, skipped if null
208     * @throws Exception If the processing fails
209     */
210    public void processDSMLFile( File file, OutputStream respStream ) throws Exception
211    {
212        parser = new Dsmlv2Parser( grammar );
213        parser.setInputFile( file.getAbsolutePath() );
214
215        processDSML( respStream );
216    }
217
218
219    /**
220     * Uses the default UTF-8 encoding for processing the DSML
221     * 
222     * @see #processDSML(InputStream, String, OutputStream)
223     * @param inputStream The Stream containing the DSML to process
224     * @param out The Stream where to put the result
225     * @throws Exception If we had an error while processing the DSML
226     */
227    public void processDSML( InputStream inputStream, OutputStream out ) throws Exception
228    {
229        processDSML( inputStream, "UTF-8", out );
230    }
231
232
233    /**
234     * Processes the DSML request(s) from the given input stream with the specified encoding
235     * and writes the response to the output stream
236     * 
237     * @param inputStream the input stream for DSML batch request
238     * @param inputEncoding encoding to be used while reading the DSML request data
239     * @param out the output stream to which DSML response will be written
240     * @throws Exception If the processing fails
241     */
242    public void processDSML( InputStream inputStream, String inputEncoding, OutputStream out ) throws Exception
243    {
244        parser = new Dsmlv2Parser( grammar );
245        parser.setInput( inputStream, inputEncoding );
246        processDSML( out );
247    }
248
249
250    /**
251     * Processes the Request document
252     * 
253     * @return the XML response in DSMLv2 Format
254     */
255    private String processDSML()
256    {
257        try
258        {
259            ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
260            processDSML( byteOut );
261            return new String( byteOut.toByteArray(), Charsets.UTF_8 );
262        }
263        catch ( IOException e )
264        {
265            LOG.error( I18n.err( I18n.ERR_02000_FAILED_PROCESSING_DSML ), e );
266        }
267
268        return null;
269    }
270
271
272    /**
273     * Processes the DSML batch request and writes the response of each operation will be
274     * written to the given response stream if it is not null
275     *
276     * @param outStream the stream to which the responses will be written, can be null
277     * @throws IOException If we had an issue while reading or writing the data
278     */
279    protected void processDSML( OutputStream outStream ) throws IOException
280    {
281        BufferedWriter respWriter = null;
282
283        if ( outStream != null )
284        {
285            respWriter = new BufferedWriter( new OutputStreamWriter( outStream, StandardCharsets.UTF_8 ) );
286
287            if ( generateSoapResp )
288            {
289                respWriter.write( "<Envelope " );
290
291                Namespace soapNs = new Namespace( null, "http://www.w3.org/2001/12/soap-envelope" );
292                soapNs.write( respWriter );
293
294                respWriter.write( "><Body>" );
295            }
296        }
297
298        // Binding to LDAP Server
299        try
300        {
301            bind( 1 );
302        }
303        catch ( Exception e )
304        {
305            if ( LOG.isWarnEnabled() )
306            {
307                LOG.warn( I18n.msg( I18n.MSG_02002_FAILED_TO_BIND ), e );
308            }
309
310            // Unable to connect to server
311            // We create a new ErrorResponse and return the XML response.
312            ErrorResponse errorResponse = new ErrorResponse( 0, ErrorResponseType.COULD_NOT_CONNECT, e
313                .getLocalizedMessage() );
314
315            batchResponse.addResponse( errorResponse );
316
317            if ( respWriter != null )
318            {
319                respWriter.write( batchResponse.toDsml() );
320                if ( generateSoapResp )
321                {
322                    respWriter.write( BODY_ENVELOPE );
323                }
324
325                respWriter.flush();
326            }
327
328            return;
329        }
330
331        // Processing BatchRequest:
332        //    - Parsing and Getting BatchRequest
333        //    - Getting and registering options from BatchRequest
334        try
335        {
336            processBatchRequest();
337        }
338        catch ( XmlPullParserException e )
339        {
340            // We create a new ErrorResponse and return the XML response.
341            ErrorResponse errorResponse = new ErrorResponse( 0, ErrorResponseType.MALFORMED_REQUEST, I18n.err(
342                I18n.ERR_02003_LINE_COLUMN, e.getLocalizedMessage(), e.getLineNumber(), e.getColumnNumber() ) );
343
344            batchResponse.addResponse( errorResponse );
345
346            if ( respWriter != null )
347            {
348                respWriter.write( batchResponse.toDsml() );
349                if ( generateSoapResp )
350                {
351                    respWriter.write( BODY_ENVELOPE );
352                }
353
354                respWriter.flush();
355            }
356
357            return;
358        }
359
360        String batchResponseTag = null;
361        
362        if ( respWriter != null )
363        {
364            StringBuilder sb = new StringBuilder();
365
366            sb.append( "<batchResponse " );
367
368            sb.append( ParserUtils.DSML_NAMESPACE.asXML() );
369
370            // a space to separate the namespace declarations
371            sb.append( " " );
372
373            sb.append( ParserUtils.XSD_NAMESPACE.asXML() );
374
375            // a space to separate the namespace declarations
376            sb.append( " " );
377
378            sb.append( ParserUtils.XSI_NAMESPACE.asXML() );
379
380            sb.append( " requestID=\"" );
381            sb.append( batchRequest.getRequestID() );
382            sb.append( "\">" );
383
384            batchResponseTag = sb.toString();
385        }
386
387        // Processing each request:
388        //    - Getting a new request
389        //    - Checking if the request is well formed
390        //    - Sending the request to the server
391        //    - Getting and converting reponse(s) as XML
392        //    - Looping until last request
393        DsmlDecorator<? extends Request> request = null;
394
395        try
396        {
397            request = parser.getNextRequest();
398        }
399        catch ( XmlPullParserException e )
400        {
401            if ( LOG.isWarnEnabled() )
402            {
403                LOG.warn( I18n.msg( I18n.MSG_02000_FAILED_GETTING_NEXT_REQUEST ), e );
404            }
405
406            int reqId = 0;
407
408            // We create a new ErrorResponse and return the XML response.
409            ErrorResponse errorResponse = new ErrorResponse( reqId, ErrorResponseType.MALFORMED_REQUEST, I18n.err(
410                I18n.ERR_02003_LINE_COLUMN, e.getLocalizedMessage(), e.getLineNumber(), e.getColumnNumber() ) );
411
412            batchResponse.addResponse( errorResponse );
413
414            if ( respWriter != null )
415            {
416                respWriter.write( batchResponse.toDsml() );
417
418                if ( generateSoapResp )
419                {
420                    respWriter.write( BODY_ENVELOPE );
421                }
422
423                respWriter.flush();
424            }
425
426            return;
427        }
428
429        // We can now write the tag, as we don't have an error
430        if ( respWriter != null )
431        {
432            respWriter.write( batchResponseTag );
433        }
434
435        // (Request == null when there's no more request to process)
436        while ( request != null )
437        {
438            // Checking the request has a requestID attribute if Processing = Parallel and ResponseOrder = Unordered
439            if ( ( batchRequest.getProcessing().equals( Processing.PARALLEL ) )
440                && ( batchRequest.getResponseOrder().equals( ResponseOrder.UNORDERED ) )
441                && ( request.getDecorated().getMessageId() <= 0 ) )
442            {
443                // Then we have to send an errorResponse
444                ErrorResponse errorResponse = new ErrorResponse( 0, ErrorResponseType.MALFORMED_REQUEST, I18n
445                    .err( I18n.ERR_02004_MISSING_REQUEST_ID ) );
446
447                if ( respWriter != null )
448                {
449                    writeResponse( respWriter, errorResponse );
450                }
451                else
452                {
453                    batchResponse.addResponse( errorResponse );
454                }
455
456                break;
457            }
458
459            try
460            {
461                processRequest( request, respWriter );
462            }
463            catch ( Exception e )
464            {
465                if ( LOG.isWarnEnabled() )
466                {
467                    LOG.warn( I18n.msg( I18n.MSG_02001_FAILED_PROCESSING_REQUEST ), e );
468                }
469
470                // We create a new ErrorResponse and return the XML response.
471                ErrorResponse errorResponse = new ErrorResponse( request.getDecorated().getMessageId(),
472                    ErrorResponseType.GATEWAY_INTERNAL_ERROR, I18n.err(
473                        I18n.ERR_02005_INTERNAL_ERROR, e.getMessage() ) );
474
475                if ( respWriter != null )
476                {
477                    writeResponse( respWriter, errorResponse );
478                }
479                else
480                {
481                    batchResponse.addResponse( errorResponse );
482                }
483
484                break;
485            }
486
487            // Checking if we need to exit processing (if an error has occurred if onError == Exit)
488            if ( exit )
489            {
490                break;
491            }
492
493            // Getting next request
494            try
495            {
496                request = parser.getNextRequest();
497            }
498            catch ( XmlPullParserException e )
499            {
500                // We create a new ErrorResponse and return the XML response.
501                ErrorResponse errorResponse = new ErrorResponse( 0, ErrorResponseType.MALFORMED_REQUEST, I18n.err(
502                    I18n.ERR_02003_LINE_COLUMN, e.getLocalizedMessage(), e.getLineNumber(), e.getColumnNumber() ) );
503
504                if ( respWriter != null )
505                {
506                    writeResponse( respWriter, errorResponse );
507                }
508                else
509                {
510                    batchResponse.addResponse( errorResponse );
511                }
512
513                break;
514            }
515        }
516
517        if ( respWriter != null )
518        {
519            respWriter.write( "</batchResponse>" );
520
521            if ( generateSoapResp )
522            {
523                respWriter.write( BODY_ENVELOPE );
524            }
525
526            respWriter.flush();
527        }
528    }
529
530
531    /**
532     * Writes the response to the writer of the underlying output stream
533     * 
534     * @param respWriter The writer used to write the response
535     * @param respDsml The decorator containing the response
536     * @throws IOException If we had an error while writing the DSML response
537     */
538    protected void writeResponse( BufferedWriter respWriter, DsmlDecorator<?> respDsml ) throws IOException
539    {
540        if ( respWriter != null )
541        {
542            Element xml = respDsml.toDsml( null );
543            xml.write( respWriter );
544        }
545    }
546
547
548    /**
549     * @return the generateSoapResp
550     */
551    public boolean isGenerateSoapResp()
552    {
553        return generateSoapResp;
554    }
555
556
557    /**
558     * @param generateSoapResp the generateSoapResp to set
559     */
560    public void setGenerateSoapResp( boolean generateSoapResp )
561    {
562        this.generateSoapResp = generateSoapResp;
563    }
564
565
566    /**
567     * @return the batchResponse
568     */
569    public BatchResponseDsml getBatchResponse()
570    {
571        return batchResponse;
572    }
573
574
575    /**
576     * @return the connection
577     */
578    public LdapConnection getConnection()
579    {
580        return connection;
581    }
582
583
584    /**
585     * Processes a single request
586     * 
587     * @param request the request to process
588     * @param respWriter The writer used to store the DSML response
589     * @exception Exception If we had an error while processing the request
590     */
591    protected void processRequest( DsmlDecorator<? extends Request> request, BufferedWriter respWriter )
592        throws Exception
593    {
594        ResultCodeEnum resultCode = null;
595
596        switch ( request.getDecorated().getType() )
597        {
598            case ABANDON_REQUEST:
599                connection.abandon( ( AbandonRequest ) request );
600                return;
601
602            case ADD_REQUEST:
603                AddResponse response = connection.add( ( AddRequest ) request );
604                resultCode = response.getLdapResult().getResultCode();
605                AddResponseDsml addResponseDsml = new AddResponseDsml( connection.getCodecService(), response );
606                writeResponse( respWriter, addResponseDsml );
607
608                break;
609
610            case BIND_REQUEST:
611                BindResponse bindResponse = connection.bind( ( BindRequest ) request );
612                resultCode = bindResponse.getLdapResult().getResultCode();
613                BindResponseDsml authResponseDsml = new BindResponseDsml( connection.getCodecService(), bindResponse );
614                writeResponse( respWriter, authResponseDsml );
615
616                break;
617
618            case COMPARE_REQUEST:
619                CompareResponse compareResponse = connection.compare( ( CompareRequest ) request );
620                resultCode = compareResponse.getLdapResult().getResultCode();
621                CompareResponseDsml compareResponseDsml = new CompareResponseDsml( connection.getCodecService(),
622                    compareResponse );
623                writeResponse( respWriter, compareResponseDsml );
624
625                break;
626
627            case DEL_REQUEST:
628                DeleteResponse delResponse = connection.delete( ( DeleteRequest ) request );
629                resultCode = delResponse.getLdapResult().getResultCode();
630                DelResponseDsml delResponseDsml = new DelResponseDsml( connection.getCodecService(), delResponse );
631                writeResponse( respWriter, delResponseDsml );
632
633                break;
634
635            case EXTENDED_REQUEST:
636                ExtendedResponse extendedResponse = connection.extended( ( ExtendedRequest ) request );
637                resultCode = extendedResponse.getLdapResult().getResultCode();
638                ExtendedResponseDsml extendedResponseDsml = new ExtendedResponseDsml( connection.getCodecService(),
639                    extendedResponse );
640                writeResponse( respWriter, extendedResponseDsml );
641
642                break;
643
644            case MODIFY_REQUEST:
645                ModifyResponse modifyResponse = connection.modify( ( ModifyRequest ) request );
646                resultCode = modifyResponse.getLdapResult().getResultCode();
647                ModifyResponseDsml modifyResponseDsml = new ModifyResponseDsml( connection.getCodecService(),
648                    modifyResponse );
649                writeResponse( respWriter, modifyResponseDsml );
650
651                break;
652
653            case MODIFYDN_REQUEST:
654                ModifyDnResponse modifyDnResponse = connection.modifyDn( ( ModifyDnRequest ) request );
655                resultCode = modifyDnResponse.getLdapResult().getResultCode();
656                ModDNResponseDsml modDNResponseDsml = new ModDNResponseDsml( connection.getCodecService(),
657                    modifyDnResponse );
658                writeResponse( respWriter, modDNResponseDsml );
659
660                break;
661
662            case SEARCH_REQUEST:
663                SearchCursor searchResponses = connection.search( ( SearchRequest ) request );
664
665                SearchResponseDsml searchResponseDsml = new SearchResponseDsml( connection.getCodecService() );
666
667                if ( respWriter != null )
668                {
669                    StringBuilder sb = new StringBuilder();
670                    sb.append( "<searchResponse" );
671
672                    if ( request.getDecorated().getMessageId() > 0 )
673                    {
674                        sb.append( " requestID=\"" );
675                        sb.append( request.getDecorated().getMessageId() );
676                        sb.append( '"' );
677                    }
678
679                    sb.append( '>' );
680
681                    respWriter.write( sb.toString() );
682                }
683
684                while ( searchResponses.next() )
685                {
686                    Response searchResponse = searchResponses.get();
687
688                    if ( searchResponse.getType() == MessageTypeEnum.SEARCH_RESULT_ENTRY )
689                    {
690                        SearchResultEntry searchResultEntry = ( SearchResultEntry ) searchResponse;
691
692                        SearchResultEntryDsml searchResultEntryDsml = new SearchResultEntryDsml(
693                            connection.getCodecService(), searchResultEntry );
694                        searchResponseDsml = new SearchResponseDsml( connection.getCodecService(),
695                            searchResultEntryDsml );
696
697                        if ( respWriter != null )
698                        {
699                            writeResponse( respWriter, searchResultEntryDsml );
700                        }
701                        else
702                        {
703                            searchResponseDsml.addResponse( searchResultEntryDsml );
704                        }
705                    }
706                    else if ( searchResponse.getType() == MessageTypeEnum.SEARCH_RESULT_REFERENCE )
707                    {
708                        SearchResultReference searchResultReference = ( SearchResultReference ) searchResponse;
709
710                        SearchResultReferenceDsml searchResultReferenceDsml = new SearchResultReferenceDsml(
711                            connection.getCodecService(), searchResultReference );
712                        searchResponseDsml = new SearchResponseDsml( connection.getCodecService(),
713                            searchResultReferenceDsml );
714
715                        if ( respWriter != null )
716                        {
717                            writeResponse( respWriter, searchResultReferenceDsml );
718                        }
719                        else
720                        {
721                            searchResponseDsml.addResponse( searchResultReferenceDsml );
722                        }
723                    }
724                }
725
726                SearchResultDone srDone = searchResponses.getSearchResultDone();
727
728                if ( srDone != null )
729                {
730                    resultCode = srDone.getLdapResult().getResultCode();
731
732                    SearchResultDoneDsml srdDsml = new SearchResultDoneDsml( connection.getCodecService(), srDone );
733
734                    if ( respWriter != null )
735                    {
736                        writeResponse( respWriter, srdDsml );
737                        respWriter.write( "</searchResponse>" );
738                    }
739                    else
740                    {
741                        searchResponseDsml.addResponse( srdDsml );
742                        batchResponse.addResponse( searchResponseDsml );
743                    }
744                }
745
746                break;
747
748            case UNBIND_REQUEST:
749                connection.unBind();
750                break;
751
752            default:
753                throw new IllegalStateException( I18n.err( I18n.ERR_02001_UNEXPECTED_REQUEST_TYPE, request.getDecorated().getType() ) );
754        }
755
756        if ( ( !continueOnError ) && ( resultCode != null ) && ( resultCode != ResultCodeEnum.SUCCESS )
757            && ( resultCode != ResultCodeEnum.COMPARE_TRUE ) && ( resultCode != ResultCodeEnum.COMPARE_FALSE )
758            && ( resultCode != ResultCodeEnum.REFERRAL ) )
759        {
760            // Turning on Exit flag
761            exit = true;
762        }
763    }
764
765
766    /**
767     * Processes the BatchRequest
768     * <ul>
769     *     <li>Parsing and Getting BatchRequest</li>
770     *     <li>Getting and registering options from BatchRequest</li>
771     * </ul>
772     * 
773     * @throws XmlPullParserException if an error occurs in the parser
774     */
775    protected void processBatchRequest() throws XmlPullParserException
776    {
777        // Parsing BatchRequest
778        parser.parseBatchRequest();
779
780        // Getting BatchRequest
781        batchRequest = parser.getBatchRequest();
782
783        if ( OnError.RESUME.equals( batchRequest.getOnError() ) )
784        {
785            continueOnError = true;
786        }
787        else if ( OnError.EXIT.equals( batchRequest.getOnError() ) )
788        {
789            continueOnError = false;
790        }
791
792        if ( ( batchRequest.getRequestID() != 0 ) && ( batchResponse != null ) )
793        {
794            batchResponse.setRequestID( batchRequest.getRequestID() );
795        }
796    }
797
798
799    /**
800     * Binds to the ldap server
801     * 
802     * @param messageId the message Id
803     * @throws LdapException If we had an issue while binding
804     * @throws IOException If we had an issue while transmitting the request or re ceiving the response
805     */
806    protected void bind( int messageId ) throws LdapException, IOException
807    {
808        if ( ( connection != null ) && connection.isAuthenticated() )
809        {
810            return;
811        }
812
813        if ( connection == null )
814        {
815            throw new IOException( I18n.err( I18n.ERR_02002_MISSING_CONNECTION_TO_BIND ) );
816        }
817
818        BindRequest bindRequest = new BindRequestImpl();
819        bindRequest.setSimple( true );
820        bindRequest.setCredentials( Strings.getBytesUtf8( password ) );
821        bindRequest.setName( user );
822        bindRequest.setVersion3( true );
823        bindRequest.setMessageId( messageId );
824
825        BindResponse bindResponse = connection.bind( bindRequest );
826
827        if ( bindResponse.getLdapResult().getResultCode() != ResultCodeEnum.SUCCESS )
828        {
829            if ( LOG.isWarnEnabled() )
830            {
831                LOG.warn( I18n.msg( I18n.MSG_02003_ERROR, bindResponse.getLdapResult().getDiagnosticMessage() ) );
832            }
833        }
834    }
835}