1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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.commons.codec.Charsets;
34 import org.apache.directory.api.dsmlv2.DsmlDecorator;
35 import org.apache.directory.api.dsmlv2.Dsmlv2Parser;
36 import org.apache.directory.api.dsmlv2.ParserUtils;
37 import org.apache.directory.api.dsmlv2.request.BatchRequestDsml;
38 import org.apache.directory.api.dsmlv2.request.BatchRequestDsml.OnError;
39 import org.apache.directory.api.dsmlv2.request.BatchRequestDsml.Processing;
40 import org.apache.directory.api.dsmlv2.request.BatchRequestDsml.ResponseOrder;
41 import org.apache.directory.api.dsmlv2.request.Dsmlv2Grammar;
42 import org.apache.directory.api.dsmlv2.response.AddResponseDsml;
43 import org.apache.directory.api.dsmlv2.response.BatchResponseDsml;
44 import org.apache.directory.api.dsmlv2.response.BindResponseDsml;
45 import org.apache.directory.api.dsmlv2.response.CompareResponseDsml;
46 import org.apache.directory.api.dsmlv2.response.DelResponseDsml;
47 import org.apache.directory.api.dsmlv2.response.ErrorResponse;
48 import org.apache.directory.api.dsmlv2.response.ErrorResponse.ErrorResponseType;
49 import org.apache.directory.api.dsmlv2.response.ExtendedResponseDsml;
50 import org.apache.directory.api.dsmlv2.response.ModDNResponseDsml;
51 import org.apache.directory.api.dsmlv2.response.ModifyResponseDsml;
52 import org.apache.directory.api.dsmlv2.response.SearchResponseDsml;
53 import org.apache.directory.api.dsmlv2.response.SearchResultDoneDsml;
54 import org.apache.directory.api.dsmlv2.response.SearchResultEntryDsml;
55 import org.apache.directory.api.dsmlv2.response.SearchResultReferenceDsml;
56 import org.apache.directory.api.i18n.I18n;
57 import org.apache.directory.api.ldap.model.cursor.SearchCursor;
58 import org.apache.directory.api.ldap.model.exception.LdapException;
59 import org.apache.directory.api.ldap.model.message.AbandonRequest;
60 import org.apache.directory.api.ldap.model.message.AddRequest;
61 import org.apache.directory.api.ldap.model.message.AddResponse;
62 import org.apache.directory.api.ldap.model.message.BindRequest;
63 import org.apache.directory.api.ldap.model.message.BindRequestImpl;
64 import org.apache.directory.api.ldap.model.message.BindResponse;
65 import org.apache.directory.api.ldap.model.message.CompareRequest;
66 import org.apache.directory.api.ldap.model.message.CompareResponse;
67 import org.apache.directory.api.ldap.model.message.DeleteRequest;
68 import org.apache.directory.api.ldap.model.message.DeleteResponse;
69 import org.apache.directory.api.ldap.model.message.ExtendedRequest;
70 import org.apache.directory.api.ldap.model.message.ExtendedResponse;
71 import org.apache.directory.api.ldap.model.message.MessageTypeEnum;
72 import org.apache.directory.api.ldap.model.message.ModifyDnRequest;
73 import org.apache.directory.api.ldap.model.message.ModifyDnResponse;
74 import org.apache.directory.api.ldap.model.message.ModifyRequest;
75 import org.apache.directory.api.ldap.model.message.ModifyResponse;
76 import org.apache.directory.api.ldap.model.message.Request;
77 import org.apache.directory.api.ldap.model.message.Response;
78 import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
79 import org.apache.directory.api.ldap.model.message.SearchRequest;
80 import org.apache.directory.api.ldap.model.message.SearchResultDone;
81 import org.apache.directory.api.ldap.model.message.SearchResultEntry;
82 import org.apache.directory.api.ldap.model.message.SearchResultReference;
83 import org.apache.directory.api.util.Strings;
84 import org.apache.directory.ldap.client.api.LdapConnection;
85 import org.apache.directory.ldap.client.api.LdapNetworkConnection;
86 import org.dom4j.Element;
87 import org.dom4j.Namespace;
88 import org.slf4j.Logger;
89 import org.slf4j.LoggerFactory;
90 import org.xmlpull.v1.XmlPullParserException;
91
92
93
94
95
96
97
98
99 public class Dsmlv2Engine
100 {
101
102 protected String user;
103
104
105 protected String password;
106
107
108 protected LdapConnection connection;
109
110
111 protected Dsmlv2Parser parser;
112
113
114 protected boolean continueOnError;
115
116
117 protected boolean exit = false;
118
119
120 protected BatchRequestDsml batchRequest;
121
122
123 protected BatchResponseDsml batchResponse = new BatchResponseDsml();
124
125 protected Dsmlv2Grammar grammar = new Dsmlv2Grammar();
126
127
128 protected boolean generateSoapResp = false;
129
130
131 private static final Logger LOG = LoggerFactory.getLogger( Dsmlv2Engine.class );
132
133 private static final String BODY_ENVELOPE = "</Body></Envelope>";
134
135
136
137
138
139
140
141
142
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
155
156
157
158
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
171
172
173
174
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
187
188
189
190
191
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
204
205
206
207
208
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
221
222
223
224
225
226
227 public void processDSML( InputStream inputStream, OutputStream out ) throws Exception
228 {
229 processDSML( inputStream, "UTF-8", out );
230 }
231
232
233
234
235
236
237
238
239
240
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
252
253
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
274
275
276
277
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
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
311
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
332
333
334 try
335 {
336 processBatchRequest();
337 }
338 catch ( XmlPullParserException e )
339 {
340
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
371 sb.append( " " );
372
373 sb.append( ParserUtils.XSD_NAMESPACE.asXML() );
374
375
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
388
389
390
391
392
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
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
430 if ( respWriter != null )
431 {
432 respWriter.write( batchResponseTag );
433 }
434
435
436 while ( request != null )
437 {
438
439 if ( ( batchRequest.getProcessing().equals( Processing.PARALLEL ) )
440 && ( batchRequest.getResponseOrder().equals( ResponseOrder.UNORDERED ) )
441 && ( request.getDecorated().getMessageId() <= 0 ) )
442 {
443
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
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
488 if ( exit )
489 {
490 break;
491 }
492
493
494 try
495 {
496 request = parser.getNextRequest();
497 }
498 catch ( XmlPullParserException e )
499 {
500
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
533
534
535
536
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
550
551 public boolean isGenerateSoapResp()
552 {
553 return generateSoapResp;
554 }
555
556
557
558
559
560 public void setGenerateSoapResp( boolean generateSoapResp )
561 {
562 this.generateSoapResp = generateSoapResp;
563 }
564
565
566
567
568
569 public BatchResponseDsml getBatchResponse()
570 {
571 return batchResponse;
572 }
573
574
575
576
577
578 public LdapConnection getConnection()
579 {
580 return connection;
581 }
582
583
584
585
586
587
588
589
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
761 exit = true;
762 }
763 }
764
765
766
767
768
769
770
771
772
773
774
775 protected void processBatchRequest() throws XmlPullParserException
776 {
777
778 parser.parseBatchRequest();
779
780
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
801
802
803
804
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 }