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