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.FileNotFoundException;
28 import java.io.IOException;
29 import java.io.InputStream;
30 import java.io.OutputStream;
31 import java.io.OutputStreamWriter;
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.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.dsmlv2.response.ErrorResponse.ErrorResponseType;
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
96
97
98
99
100 public class Dsmlv2Engine
101 {
102
103 protected String user;
104
105
106 protected String password;
107
108
109 protected LdapConnection connection;
110
111
112 protected Dsmlv2Parser parser;
113
114
115 protected boolean continueOnError;
116
117
118 protected boolean exit = false;
119
120
121 protected BatchRequestDsml batchRequest;
122
123
124 protected BatchResponseDsml batchResponse = new BatchResponseDsml();
125
126 protected Dsmlv2Grammar grammar = new Dsmlv2Grammar();
127
128
129 protected boolean generateSoapResp = false;
130
131
132 private static final Logger LOG = LoggerFactory.getLogger( Dsmlv2Engine.class );
133
134
135
136
137
138
139
140
141
142
143 public Dsmlv2Engine( String host, int port, String user, String password )
144 {
145 this.user = user;
146 this.password = password;
147
148 connection = new LdapNetworkConnection( host, port );
149 }
150
151
152
153
154
155
156
157
158
159 public Dsmlv2Engine( LdapConnection connection, String user, String password )
160 {
161 this.user = user;
162 this.password = password;
163
164 this.connection = connection;
165 }
166
167
168
169
170
171
172
173
174
175 public String processDSML( String dsmlInput ) throws XmlPullParserException
176 {
177 parser = new Dsmlv2Parser( grammar );
178 parser.setInput( dsmlInput );
179
180 return processDSML();
181 }
182
183
184
185
186
187
188
189
190
191
192 public String processDSMLFile( String fileName ) throws XmlPullParserException, FileNotFoundException
193 {
194 parser = new Dsmlv2Parser( grammar );
195 parser.setInputFile( fileName );
196
197 return processDSML();
198 }
199
200
201
202
203
204
205
206
207
208
209 public void processDSMLFile( File file, OutputStream respStream ) throws Exception
210 {
211 parser = new Dsmlv2Parser( grammar );
212 parser.setInputFile( file.getAbsolutePath() );
213
214 processDSML( respStream );
215 }
216
217
218
219
220
221
222
223 public void processDSML( InputStream inputStream, OutputStream out ) throws Exception
224 {
225 processDSML( inputStream, "UTF-8", out );
226 }
227
228
229
230
231
232
233
234
235
236
237
238 public void processDSML( InputStream inputStream, String inputEncoding, OutputStream out ) throws Exception
239 {
240 parser = new Dsmlv2Parser( grammar );
241 parser.setInput( inputStream, inputEncoding );
242 processDSML( out );
243 }
244
245
246
247
248
249
250
251 private String processDSML()
252 {
253 try
254 {
255 ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
256 processDSML( byteOut );
257 return new String( byteOut.toByteArray(), "UTF-8" );
258 }
259 catch ( IOException e )
260 {
261 LOG.error( "Failed to process the DSML", e );
262 }
263
264 return null;
265 }
266
267
268
269
270
271
272
273
274
275 protected void processDSML( OutputStream outStream ) throws IOException
276 {
277 BufferedWriter respWriter = null;
278
279 if ( outStream != null )
280 {
281 respWriter = new BufferedWriter( new OutputStreamWriter( outStream ) );
282
283 if ( generateSoapResp )
284 {
285 respWriter.write( "<Envelope " );
286
287 Namespace soapNs = new Namespace( null, "http://www.w3.org/2001/12/soap-envelope" );
288 soapNs.write( respWriter );
289
290 respWriter.write( "><Body>" );
291 }
292 }
293
294
295 try
296 {
297 bind( 1 );
298 }
299 catch ( Exception e )
300 {
301 LOG.warn( "Failed to bind", e );
302
303
304
305 ErrorResponse errorResponse = new ErrorResponse( 0, ErrorResponseType.COULD_NOT_CONNECT, e
306 .getLocalizedMessage() );
307
308 batchResponse.addResponse( errorResponse );
309
310 if ( respWriter != null )
311 {
312 respWriter.write( batchResponse.toDsml() );
313 if ( generateSoapResp )
314 {
315 respWriter.write( "</Body></Envelope>" );
316 }
317
318 respWriter.flush();
319 }
320
321 return;
322 }
323
324
325
326
327 try
328 {
329 processBatchRequest();
330 }
331 catch ( XmlPullParserException e )
332 {
333
334 ErrorResponse errorResponse = new ErrorResponse( 0, ErrorResponseType.MALFORMED_REQUEST, I18n.err(
335 I18n.ERR_03001, e.getLocalizedMessage(), e.getLineNumber(), e.getColumnNumber() ) );
336
337 batchResponse.addResponse( errorResponse );
338
339 if ( respWriter != null )
340 {
341 respWriter.write( batchResponse.toDsml() );
342 if ( generateSoapResp )
343 {
344 respWriter.write( "</Body></Envelope>" );
345 }
346
347 respWriter.flush();
348 }
349
350 return;
351 }
352
353 if ( respWriter != null )
354 {
355 StringBuilder sb = new StringBuilder();
356
357 sb.append( "<batchResponse " );
358
359 sb.append( ParserUtils.DSML_NAMESPACE.asXML() );
360
361 sb.append( " " );
362
363 sb.append( ParserUtils.XSD_NAMESPACE.asXML() );
364
365 sb.append( " " );
366
367 sb.append( ParserUtils.XSI_NAMESPACE.asXML() );
368
369 sb.append( " requestID=\"" );
370 sb.append( batchRequest.getRequestID() );
371 sb.append( "\">" );
372
373 respWriter.write( sb.toString() );
374 }
375
376
377
378
379
380
381
382 DsmlDecorator<? extends Request> request = null;
383
384 try
385 {
386 request = parser.getNextRequest();
387 }
388 catch ( XmlPullParserException e )
389 {
390 LOG.warn( "Failed while getting next request", e );
391
392 int reqId = 0;
393
394
395 ErrorResponse errorResponse = new ErrorResponse( reqId, ErrorResponseType.MALFORMED_REQUEST, I18n.err(
396 I18n.ERR_03001, e.getLocalizedMessage(), e.getLineNumber(), e.getColumnNumber() ) );
397
398 batchResponse.addResponse( errorResponse );
399
400 if ( respWriter != null )
401 {
402 respWriter.write( batchResponse.toDsml() );
403
404 if ( generateSoapResp )
405 {
406 respWriter.write( "</Body></Envelope>" );
407 }
408
409 respWriter.flush();
410 }
411
412 return;
413 }
414
415 while ( request != null )
416 {
417
418 if ( ( batchRequest.getProcessing().equals( Processing.PARALLEL ) )
419 && ( batchRequest.getResponseOrder().equals( ResponseOrder.UNORDERED ) )
420 && ( request.getDecorated().getMessageId() <= 0 ) )
421 {
422
423 ErrorResponse errorResponse = new ErrorResponse( 0, ErrorResponseType.MALFORMED_REQUEST, I18n
424 .err( I18n.ERR_03002 ) );
425
426 if ( respWriter != null )
427 {
428 writeResponse( respWriter, errorResponse );
429 }
430 else
431 {
432 batchResponse.addResponse( errorResponse );
433 }
434
435 break;
436 }
437
438 try
439 {
440 processRequest( request, respWriter );
441 }
442 catch ( Exception e )
443 {
444 LOG.warn( "Failed to process request", e );
445
446
447 ErrorResponse errorResponse = new ErrorResponse( request.getDecorated().getMessageId(),
448 ErrorResponseType.GATEWAY_INTERNAL_ERROR, I18n.err(
449 I18n.ERR_03003, e.getMessage() ) );
450
451 if ( respWriter != null )
452 {
453 writeResponse( respWriter, errorResponse );
454 }
455 else
456 {
457 batchResponse.addResponse( errorResponse );
458 }
459
460 break;
461 }
462
463
464 if ( exit )
465 {
466 break;
467 }
468
469
470 try
471 {
472 request = parser.getNextRequest();
473 }
474 catch ( XmlPullParserException e )
475 {
476
477 ErrorResponse errorResponse = new ErrorResponse( 0, ErrorResponseType.MALFORMED_REQUEST, I18n.err(
478 I18n.ERR_03001, e.getLocalizedMessage(), e.getLineNumber(), e.getColumnNumber() ) );
479
480 if ( respWriter != null )
481 {
482 writeResponse( respWriter, errorResponse );
483 }
484 else
485 {
486 batchResponse.addResponse( errorResponse );
487 }
488
489 break;
490 }
491 }
492
493 if ( respWriter != null )
494 {
495 respWriter.write( "</batchResponse>" );
496
497 if ( generateSoapResp )
498 {
499 respWriter.write( "</Body></Envelope>" );
500 }
501
502 respWriter.flush();
503 }
504 }
505
506
507
508
509
510
511
512
513
514 protected void writeResponse( BufferedWriter respWriter, DsmlDecorator<?> respDsml ) throws IOException
515 {
516 if ( respWriter != null )
517 {
518 Element xml = respDsml.toDsml( null );
519 xml.write( respWriter );
520 }
521 }
522
523
524
525
526
527 public boolean isGenerateSoapResp()
528 {
529 return generateSoapResp;
530 }
531
532
533
534
535
536 public void setGenerateSoapResp( boolean generateSoapResp )
537 {
538 this.generateSoapResp = generateSoapResp;
539 }
540
541
542
543
544
545 public BatchResponseDsml getBatchResponse()
546 {
547 return batchResponse;
548 }
549
550
551
552
553
554 public LdapConnection getConnection()
555 {
556 return connection;
557 }
558
559
560
561
562
563
564
565
566
567 protected void processRequest( DsmlDecorator<? extends Request> request, BufferedWriter respWriter )
568 throws Exception
569 {
570 ResultCodeEnum resultCode = null;
571
572 switch ( request.getDecorated().getType() )
573 {
574 case ABANDON_REQUEST:
575 connection.abandon( ( AbandonRequest ) request );
576 return;
577
578 case ADD_REQUEST:
579 AddResponse response = connection.add( ( AddRequest ) request );
580 resultCode = response.getLdapResult().getResultCode();
581 AddResponseDsml addResponseDsml = new AddResponseDsml( connection.getCodecService(), response );
582 writeResponse( respWriter, addResponseDsml );
583
584 break;
585
586 case BIND_REQUEST:
587 BindResponse bindResponse = connection.bind( ( BindRequest ) request );
588 resultCode = bindResponse.getLdapResult().getResultCode();
589 BindResponseDsml authResponseDsml = new BindResponseDsml( connection.getCodecService(), bindResponse );
590 writeResponse( respWriter, authResponseDsml );
591
592 break;
593
594 case COMPARE_REQUEST:
595 CompareResponse compareResponse = connection.compare( ( CompareRequest ) request );
596 resultCode = compareResponse.getLdapResult().getResultCode();
597 CompareResponseDsml compareResponseDsml = new CompareResponseDsml( connection.getCodecService(),
598 compareResponse );
599 writeResponse( respWriter, compareResponseDsml );
600
601 break;
602
603 case DEL_REQUEST:
604 DeleteResponse delResponse = connection.delete( ( DeleteRequest ) request );
605 resultCode = delResponse.getLdapResult().getResultCode();
606 DelResponseDsml delResponseDsml = new DelResponseDsml( connection.getCodecService(), delResponse );
607 writeResponse( respWriter, delResponseDsml );
608
609 break;
610
611 case EXTENDED_REQUEST:
612 ExtendedResponse extendedResponse = connection.extended( ( ExtendedRequest ) request );
613 resultCode = extendedResponse.getLdapResult().getResultCode();
614 ExtendedResponseDsml extendedResponseDsml = new ExtendedResponseDsml( connection.getCodecService(),
615 extendedResponse );
616 writeResponse( respWriter, extendedResponseDsml );
617
618 break;
619
620 case MODIFY_REQUEST:
621 ModifyResponse modifyResponse = connection.modify( ( ModifyRequest ) request );
622 resultCode = modifyResponse.getLdapResult().getResultCode();
623 ModifyResponseDsml modifyResponseDsml = new ModifyResponseDsml( connection.getCodecService(),
624 modifyResponse );
625 writeResponse( respWriter, modifyResponseDsml );
626
627 break;
628
629 case MODIFYDN_REQUEST:
630 ModifyDnResponse modifyDnResponse = connection.modifyDn( ( ModifyDnRequest ) request );
631 resultCode = modifyDnResponse.getLdapResult().getResultCode();
632 ModDNResponseDsml modDNResponseDsml = new ModDNResponseDsml( connection.getCodecService(),
633 modifyDnResponse );
634 writeResponse( respWriter, modDNResponseDsml );
635
636 break;
637
638 case SEARCH_REQUEST:
639 SearchCursor searchResponses = connection.search( ( SearchRequest ) request );
640
641 SearchResponseDsml searchResponseDsml = new SearchResponseDsml( connection.getCodecService() );
642
643 if ( respWriter != null )
644 {
645 StringBuilder sb = new StringBuilder();
646 sb.append( "<searchResponse" );
647
648 if ( request.getDecorated().getMessageId() > 0 )
649 {
650 sb.append( " requestID=\"" );
651 sb.append( request.getDecorated().getMessageId() );
652 sb.append( '"' );
653 }
654
655 sb.append( '>' );
656
657 respWriter.write( sb.toString() );
658 }
659
660 while ( searchResponses.next() )
661 {
662 Response searchResponse = searchResponses.get();
663
664 if ( searchResponse.getType() == MessageTypeEnum.SEARCH_RESULT_ENTRY )
665 {
666 SearchResultEntry searchResultEntry = ( SearchResultEntry ) searchResponse;
667
668 SearchResultEntryDsml searchResultEntryDsml = new SearchResultEntryDsml(
669 connection.getCodecService(), searchResultEntry );
670 searchResponseDsml = new SearchResponseDsml( connection.getCodecService(),
671 searchResultEntryDsml );
672
673 if ( respWriter != null )
674 {
675 writeResponse( respWriter, searchResultEntryDsml );
676 }
677 else
678 {
679 searchResponseDsml.addResponse( searchResultEntryDsml );
680 }
681 }
682 else if ( searchResponse.getType() == MessageTypeEnum.SEARCH_RESULT_REFERENCE )
683 {
684 SearchResultReference searchResultReference = ( SearchResultReference ) searchResponse;
685
686 SearchResultReferenceDsml searchResultReferenceDsml = new SearchResultReferenceDsml(
687 connection.getCodecService(), searchResultReference );
688 searchResponseDsml = new SearchResponseDsml( connection.getCodecService(),
689 searchResultReferenceDsml );
690
691 if ( respWriter != null )
692 {
693 writeResponse( respWriter, searchResultReferenceDsml );
694 }
695 else
696 {
697 searchResponseDsml.addResponse( searchResultReferenceDsml );
698 }
699 }
700 }
701
702 SearchResultDone srDone = searchResponses.getSearchResultDone();
703
704 if ( srDone != null )
705 {
706 resultCode = srDone.getLdapResult().getResultCode();
707
708 SearchResultDoneDsml srdDsml = new SearchResultDoneDsml( connection.getCodecService(), srDone );
709
710 if ( respWriter != null )
711 {
712 writeResponse( respWriter, srdDsml );
713 respWriter.write( "</searchResponse>" );
714 }
715 else
716 {
717 searchResponseDsml.addResponse( srdDsml );
718 batchResponse.addResponse( searchResponseDsml );
719 }
720 }
721
722 break;
723
724 case UNBIND_REQUEST:
725 connection.unBind();
726 break;
727
728 default:
729 throw new IllegalStateException( "Unexpected request tpye " + request.getDecorated().getType() );
730 }
731
732 if ( ( !continueOnError ) && ( resultCode != null ) && ( resultCode != ResultCodeEnum.SUCCESS )
733 && ( resultCode != ResultCodeEnum.COMPARE_TRUE ) && ( resultCode != ResultCodeEnum.COMPARE_FALSE )
734 && ( resultCode != ResultCodeEnum.REFERRAL ) )
735 {
736
737 exit = true;
738 }
739 }
740
741
742
743
744
745
746
747
748
749
750
751 protected void processBatchRequest() throws XmlPullParserException
752 {
753
754 parser.parseBatchRequest();
755
756
757 batchRequest = parser.getBatchRequest();
758
759 if ( OnError.RESUME.equals( batchRequest.getOnError() ) )
760 {
761 continueOnError = true;
762 }
763 else if ( OnError.EXIT.equals( batchRequest.getOnError() ) )
764 {
765 continueOnError = false;
766 }
767
768 if ( ( batchRequest.getRequestID() != 0 ) && ( batchResponse != null ) )
769 {
770 batchResponse.setRequestID( batchRequest.getRequestID() );
771 }
772 }
773
774
775
776
777
778
779
780
781
782
783 protected void bind( int messageId ) throws LdapException, EncoderException, DecoderException, IOException
784 {
785 if ( ( connection != null ) && connection.isAuthenticated() )
786 {
787 return;
788 }
789
790 if ( connection == null )
791 {
792 throw new IOException( I18n.err( I18n.ERR_03101_MISSING_CONNECTION_TO ) );
793 }
794
795 BindRequest bindRequest = new BindRequestImpl();
796 bindRequest.setSimple( true );
797 bindRequest.setCredentials( Strings.getBytesUtf8( password ) );
798 bindRequest.setName( user );
799 bindRequest.setVersion3( true );
800 bindRequest.setMessageId( messageId );
801
802 BindResponse bindResponse = connection.bind( bindRequest );
803
804 if ( bindResponse.getLdapResult().getResultCode() != ResultCodeEnum.SUCCESS )
805 {
806 LOG.warn( "Error : {}", bindResponse.getLdapResult().getDiagnosticMessage() );
807 }
808 }
809 }