001/*
002 * Copyright 2014-2020 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2014-2020 Ping Identity Corporation
007 *
008 * Licensed under the Apache License, Version 2.0 (the "License");
009 * you may not use this file except in compliance with the License.
010 * You may obtain a copy of the License at
011 *
012 *    http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing, software
015 * distributed under the License is distributed on an "AS IS" BASIS,
016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017 * See the License for the specific language governing permissions and
018 * limitations under the License.
019 */
020/*
021 * Copyright (C) 2014-2020 Ping Identity Corporation
022 *
023 * This program is free software; you can redistribute it and/or modify
024 * it under the terms of the GNU General Public License (GPLv2 only)
025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
026 * as published by the Free Software Foundation.
027 *
028 * This program is distributed in the hope that it will be useful,
029 * but WITHOUT ANY WARRANTY; without even the implied warranty of
030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
031 * GNU General Public License for more details.
032 *
033 * You should have received a copy of the GNU General Public License
034 * along with this program; if not, see <http://www.gnu.org/licenses>.
035 */
036package com.unboundid.ldap.listener.interceptor;
037
038
039
040import java.util.List;
041import java.util.HashMap;
042import java.util.Map;
043
044import com.unboundid.ldap.listener.IntermediateResponseTransformer;
045import com.unboundid.ldap.listener.LDAPListenerClientConnection;
046import com.unboundid.ldap.listener.LDAPListenerRequestHandler;
047import com.unboundid.ldap.listener.SearchEntryTransformer;
048import com.unboundid.ldap.listener.SearchReferenceTransformer;
049import com.unboundid.ldap.protocol.AddRequestProtocolOp;
050import com.unboundid.ldap.protocol.AddResponseProtocolOp;
051import com.unboundid.ldap.protocol.BindRequestProtocolOp;
052import com.unboundid.ldap.protocol.BindResponseProtocolOp;
053import com.unboundid.ldap.protocol.CompareRequestProtocolOp;
054import com.unboundid.ldap.protocol.CompareResponseProtocolOp;
055import com.unboundid.ldap.protocol.DeleteRequestProtocolOp;
056import com.unboundid.ldap.protocol.DeleteResponseProtocolOp;
057import com.unboundid.ldap.protocol.ExtendedRequestProtocolOp;
058import com.unboundid.ldap.protocol.ExtendedResponseProtocolOp;
059import com.unboundid.ldap.protocol.IntermediateResponseProtocolOp;
060import com.unboundid.ldap.protocol.LDAPMessage;
061import com.unboundid.ldap.protocol.ModifyRequestProtocolOp;
062import com.unboundid.ldap.protocol.ModifyResponseProtocolOp;
063import com.unboundid.ldap.protocol.ModifyDNRequestProtocolOp;
064import com.unboundid.ldap.protocol.ModifyDNResponseProtocolOp;
065import com.unboundid.ldap.protocol.SearchRequestProtocolOp;
066import com.unboundid.ldap.protocol.SearchResultDoneProtocolOp;
067import com.unboundid.ldap.protocol.SearchResultEntryProtocolOp;
068import com.unboundid.ldap.protocol.SearchResultReferenceProtocolOp;
069import com.unboundid.ldap.sdk.AddRequest;
070import com.unboundid.ldap.sdk.CompareRequest;
071import com.unboundid.ldap.sdk.Control;
072import com.unboundid.ldap.sdk.DeleteRequest;
073import com.unboundid.ldap.sdk.LDAPException;
074import com.unboundid.ldap.sdk.ModifyRequest;
075import com.unboundid.ldap.sdk.ModifyDNRequest;
076import com.unboundid.ldap.sdk.ResultCode;
077import com.unboundid.ldap.sdk.SearchRequest;
078import com.unboundid.util.Debug;
079import com.unboundid.util.ObjectPair;
080import com.unboundid.util.ThreadSafety;
081import com.unboundid.util.ThreadSafetyLevel;
082import com.unboundid.util.StaticUtils;
083
084import static com.unboundid.ldap.listener.interceptor.InterceptorMessages.*;
085
086
087
088/**
089 * This class provides an LDAP listener request handler that may be used to
090 * invoke any in-memory operation interceptors in the course of processing
091 * operations for the in-memory directory server.
092 */
093@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
094public final class InMemoryOperationInterceptorRequestHandler
095       extends LDAPListenerRequestHandler
096       implements IntermediateResponseTransformer, SearchEntryTransformer,
097                  SearchReferenceTransformer
098{
099  // The set of interceptors to be used to transform requests and responses.
100  private final InMemoryOperationInterceptor[] interceptors;
101
102  // The client connection associated with this request handler instance.
103  private final LDAPListenerClientConnection connection;
104
105  // The request handler that will be used to ensure that operations actually
106  // get processed.
107  private final LDAPListenerRequestHandler wrappedHandler;
108
109  // A map containing active operations mapped by message ID.
110  private final Map<Integer,InterceptedOperation> activeOperations;
111
112
113
114  /**
115   * Creates a new instance of this LDAP listener request handler that will be
116   * used to process the provided set of operation interceptors.
117   *
118   * @param  interceptors    The set of operation interceptors that will be used
119   *                         to transform requests and responses.  If there are
120   *                         multiple interceptors, then they will be invoked in
121   *                         the same order as elements in the provided list
122   *                         when processing both requests and results.
123   * @param  wrappedHandler  The request handler that will be used to ensure
124   *                         that operations actually get processed.
125   */
126  public InMemoryOperationInterceptorRequestHandler(
127              final List<InMemoryOperationInterceptor> interceptors,
128              final LDAPListenerRequestHandler wrappedHandler)
129  {
130    this.wrappedHandler = wrappedHandler;
131
132    this.interceptors = new InMemoryOperationInterceptor[interceptors.size()];
133    interceptors.toArray(this.interceptors);
134
135    connection       = null;
136    activeOperations = new HashMap<>(StaticUtils.computeMapCapacity(5));
137  }
138
139
140
141  /**
142   * Creates a new instance of this LDAP listener request handler that will be
143   * used to process the provided set of operation interceptors.
144   *
145   * @param  interceptors    The set of operation interceptors that will be used
146   *                         to transform requests and responses.  If there are
147   *                         multiple interceptors, then they will be invoked in
148   *                         the same order as elements in the provided list
149   *                         when processing both requests and results.
150   * @param  wrappedHandler  The request handler that will be used to ensure
151   *                         that operations actually get processed.
152   * @param  connection      The client connection associated with this request
153   *                         handler instance.
154   */
155  private InMemoryOperationInterceptorRequestHandler(
156               final InMemoryOperationInterceptor[] interceptors,
157               final LDAPListenerRequestHandler wrappedHandler,
158               final LDAPListenerClientConnection connection)
159  {
160    this.interceptors   = interceptors;
161    this.wrappedHandler = wrappedHandler;
162    this.connection     = connection;
163
164    activeOperations = new HashMap<>(StaticUtils.computeMapCapacity(5));
165  }
166
167
168
169  /**
170   * {@inheritDoc}
171   */
172  @Override()
173  public InMemoryOperationInterceptorRequestHandler newInstance(
174              final LDAPListenerClientConnection connection)
175         throws LDAPException
176  {
177    final InMemoryOperationInterceptorRequestHandler handler =
178         new InMemoryOperationInterceptorRequestHandler(interceptors,
179              wrappedHandler.newInstance(connection), connection);
180
181    connection.addSearchEntryTransformer(handler);
182    connection.addSearchReferenceTransformer(handler);
183    connection.addIntermediateResponseTransformer(handler);
184
185    return handler;
186  }
187
188
189
190  /**
191   * {@inheritDoc}
192   */
193  @Override()
194  public LDAPMessage processAddRequest(final int messageID,
195                                       final AddRequestProtocolOp request,
196                                       final List<Control> controls)
197  {
198    final InterceptedAddOperation op = new InterceptedAddOperation(connection,
199         messageID, request, toArray(controls));
200    activeOperations.put(messageID, op);
201
202    try
203    {
204      for (final InMemoryOperationInterceptor i : interceptors)
205      {
206        try
207        {
208          i.processAddRequest(op);
209        }
210        catch (final LDAPException le)
211        {
212          Debug.debugException(le);
213          return new LDAPMessage(messageID,
214               new AddResponseProtocolOp(le.toLDAPResult()),
215               le.getResponseControls());
216        }
217        catch (final Exception e)
218        {
219          Debug.debugException(e);
220          return new LDAPMessage(messageID,
221               new AddResponseProtocolOp(ResultCode.OTHER_INT_VALUE, null,
222                    ERR_DS_INTERCEPTOR_REQUEST_ERROR.get(
223                         String.valueOf(op), i.getClass().getName(),
224                         StaticUtils.getExceptionMessage(e)),
225                    null
226               )
227          );
228        }
229      }
230
231      final LDAPMessage resultMessage = wrappedHandler.processAddRequest(
232           messageID,
233           new AddRequestProtocolOp((AddRequest) op.getRequest()),
234           op.getRequest().getControlList());
235      op.setResult(resultMessage.getAddResponseProtocolOp().toLDAPResult(
236           toArray(resultMessage.getControls())));
237      for (final InMemoryOperationInterceptor i : interceptors)
238      {
239        try
240        {
241          i.processAddResult(op);
242        }
243        catch (final Exception e)
244        {
245          Debug.debugException(e);
246          return new LDAPMessage(messageID,
247               new AddResponseProtocolOp(ResultCode.OTHER_INT_VALUE, null,
248                    ERR_DS_INTERCEPTOR_RESULT_ERROR.get(
249                         String.valueOf(op), i.getClass().getName(),
250                         StaticUtils.getExceptionMessage(e)),
251                    null
252               )
253          );
254        }
255      }
256
257      return new LDAPMessage(messageID,
258           new AddResponseProtocolOp(op.getResult()),
259           op.getResult().getResponseControls());
260    }
261    finally
262    {
263      activeOperations.remove(messageID);
264    }
265  }
266
267
268
269  /**
270   * {@inheritDoc}
271   */
272  @Override()
273  public LDAPMessage processBindRequest(final int messageID,
274                                        final BindRequestProtocolOp request,
275                                        final List<Control> controls)
276  {
277    if (request.getCredentialsType() == BindRequestProtocolOp.CRED_TYPE_SIMPLE)
278    {
279      final InterceptedSimpleBindOperation op =
280           new InterceptedSimpleBindOperation(connection, messageID, request,
281                toArray(controls));
282      activeOperations.put(messageID, op);
283
284      try
285      {
286        for (final InMemoryOperationInterceptor i : interceptors)
287        {
288          try
289          {
290            i.processSimpleBindRequest(op);
291          }
292          catch (final LDAPException le)
293          {
294            Debug.debugException(le);
295            return new LDAPMessage(messageID,
296                 new BindResponseProtocolOp(le.toLDAPResult()),
297                 le.getResponseControls());
298          }
299          catch (final Exception e)
300          {
301            Debug.debugException(e);
302            return new LDAPMessage(messageID,
303                 new BindResponseProtocolOp(ResultCode.OTHER_INT_VALUE, null,
304                      ERR_DS_INTERCEPTOR_REQUEST_ERROR.get(
305                           String.valueOf(op), i.getClass().getName(),
306                           StaticUtils.getExceptionMessage(e)),
307                      null, null));
308          }
309        }
310
311        final LDAPMessage resultMessage = wrappedHandler.processBindRequest(
312             messageID,
313             new BindRequestProtocolOp(op.getRequest()),
314             op.getRequest().getControlList());
315        op.setResult(resultMessage.getBindResponseProtocolOp().toBindResult(
316             toArray(resultMessage.getControls())));
317        for (final InMemoryOperationInterceptor i : interceptors)
318        {
319          try
320          {
321            i.processSimpleBindResult(op);
322          }
323          catch (final Exception e)
324          {
325            Debug.debugException(e);
326            return new LDAPMessage(messageID,
327                 new BindResponseProtocolOp(ResultCode.OTHER_INT_VALUE, null,
328                      ERR_DS_INTERCEPTOR_RESULT_ERROR.get(
329                           String.valueOf(op), i.getClass().getName(),
330                           StaticUtils.getExceptionMessage(e)),
331                      null, null));
332          }
333        }
334
335        return new LDAPMessage(messageID,
336             new BindResponseProtocolOp(op.getResult()),
337             op.getResult().getResponseControls());
338      }
339      finally
340      {
341        activeOperations.remove(messageID);
342      }
343    }
344    else
345    {
346      final InterceptedSASLBindOperation op =
347           new InterceptedSASLBindOperation(connection, messageID, request,
348                toArray(controls));
349      activeOperations.put(messageID, op);
350
351      try
352      {
353        for (final InMemoryOperationInterceptor i : interceptors)
354        {
355          try
356          {
357            i.processSASLBindRequest(op);
358          }
359          catch (final LDAPException le)
360          {
361            Debug.debugException(le);
362            return new LDAPMessage(messageID,
363                 new BindResponseProtocolOp(le.toLDAPResult()),
364                 le.getResponseControls());
365          }
366          catch (final Exception e)
367          {
368            Debug.debugException(e);
369            return new LDAPMessage(messageID,
370                 new BindResponseProtocolOp(ResultCode.OTHER_INT_VALUE, null,
371                      ERR_DS_INTERCEPTOR_REQUEST_ERROR.get(
372                           String.valueOf(op), i.getClass().getName(),
373                           StaticUtils.getExceptionMessage(e)),
374                      null, null));
375          }
376        }
377
378        final LDAPMessage resultMessage = wrappedHandler.processBindRequest(
379             messageID,
380             new BindRequestProtocolOp(op.getRequest()),
381             op.getRequest().getControlList());
382        op.setResult(resultMessage.getBindResponseProtocolOp().toBindResult(
383             toArray(resultMessage.getControls())));
384        for (final InMemoryOperationInterceptor i : interceptors)
385        {
386          try
387          {
388            i.processSASLBindResult(op);
389          }
390          catch (final Exception e)
391          {
392            Debug.debugException(e);
393            return new LDAPMessage(messageID,
394                 new BindResponseProtocolOp(ResultCode.OTHER_INT_VALUE, null,
395                      ERR_DS_INTERCEPTOR_RESULT_ERROR.get(
396                           String.valueOf(op), i.getClass().getName(),
397                           StaticUtils.getExceptionMessage(e)),
398                      null, null));
399          }
400        }
401
402        return new LDAPMessage(messageID,
403             new BindResponseProtocolOp(op.getResult()),
404             op.getResult().getResponseControls());
405      }
406      finally
407      {
408        activeOperations.remove(messageID);
409      }
410    }
411  }
412
413
414
415  /**
416   * {@inheritDoc}
417   */
418  @Override()
419  public LDAPMessage processCompareRequest(final int messageID,
420                          final CompareRequestProtocolOp request,
421                          final List<Control> controls)
422  {
423    final InterceptedCompareOperation op =
424         new InterceptedCompareOperation(connection, messageID, request,
425              toArray(controls));
426    activeOperations.put(messageID, op);
427
428    try
429    {
430      for (final InMemoryOperationInterceptor i : interceptors)
431      {
432        try
433        {
434          i.processCompareRequest(op);
435        }
436        catch (final LDAPException le)
437        {
438          Debug.debugException(le);
439          return new LDAPMessage(messageID,
440               new CompareResponseProtocolOp(le.toLDAPResult()),
441               le.getResponseControls());
442        }
443        catch (final Exception e)
444        {
445          Debug.debugException(e);
446          return new LDAPMessage(messageID,
447               new CompareResponseProtocolOp(ResultCode.OTHER_INT_VALUE, null,
448                    ERR_DS_INTERCEPTOR_REQUEST_ERROR.get(
449                         String.valueOf(op), i.getClass().getName(),
450                         StaticUtils.getExceptionMessage(e)),
451                    null));
452        }
453      }
454
455      final LDAPMessage resultMessage = wrappedHandler.processCompareRequest(
456           messageID,
457           new CompareRequestProtocolOp((CompareRequest) op.getRequest()),
458           op.getRequest().getControlList());
459      op.setResult(resultMessage.getCompareResponseProtocolOp().toLDAPResult(
460           toArray(resultMessage.getControls())));
461      for (final InMemoryOperationInterceptor i : interceptors)
462      {
463        try
464        {
465          i.processCompareResult(op);
466        }
467        catch (final Exception e)
468        {
469          Debug.debugException(e);
470          return new LDAPMessage(messageID,
471               new CompareResponseProtocolOp(ResultCode.OTHER_INT_VALUE, null,
472                    ERR_DS_INTERCEPTOR_RESULT_ERROR.get(
473                         String.valueOf(op), i.getClass().getName(),
474                         StaticUtils.getExceptionMessage(e)),
475                    null));
476        }
477      }
478
479      return new LDAPMessage(messageID,
480           new CompareResponseProtocolOp(op.getResult()),
481           op.getResult().getResponseControls());
482    }
483    finally
484    {
485      activeOperations.remove(messageID);
486    }
487  }
488
489
490
491  /**
492   * {@inheritDoc}
493   */
494  @Override()
495  public LDAPMessage processDeleteRequest(final int messageID,
496                                          final DeleteRequestProtocolOp request,
497                                          final List<Control> controls)
498  {
499    final InterceptedDeleteOperation op =
500         new InterceptedDeleteOperation(connection, messageID, request,
501              toArray(controls));
502    activeOperations.put(messageID, op);
503
504    try
505    {
506      for (final InMemoryOperationInterceptor i : interceptors)
507      {
508        try
509        {
510          i.processDeleteRequest(op);
511        }
512        catch (final LDAPException le)
513        {
514          Debug.debugException(le);
515          return new LDAPMessage(messageID,
516               new DeleteResponseProtocolOp(le.toLDAPResult()),
517               le.getResponseControls());
518        }
519        catch (final Exception e)
520        {
521          Debug.debugException(e);
522          return new LDAPMessage(messageID,
523               new DeleteResponseProtocolOp(ResultCode.OTHER_INT_VALUE, null,
524                    ERR_DS_INTERCEPTOR_REQUEST_ERROR.get(
525                         String.valueOf(op), i.getClass().getName(),
526                         StaticUtils.getExceptionMessage(e)),
527                    null));
528        }
529      }
530
531      final LDAPMessage resultMessage = wrappedHandler.processDeleteRequest(
532           messageID,
533           new DeleteRequestProtocolOp((DeleteRequest) op.getRequest()),
534           op.getRequest().getControlList());
535      op.setResult(resultMessage.getDeleteResponseProtocolOp().toLDAPResult(
536           toArray(resultMessage.getControls())));
537      for (final InMemoryOperationInterceptor i : interceptors)
538      {
539        try
540        {
541          i.processDeleteResult(op);
542        }
543        catch (final Exception e)
544        {
545          Debug.debugException(e);
546          return new LDAPMessage(messageID,
547               new DeleteResponseProtocolOp(ResultCode.OTHER_INT_VALUE, null,
548                    ERR_DS_INTERCEPTOR_RESULT_ERROR.get(
549                         String.valueOf(op), i.getClass().getName(),
550                         StaticUtils.getExceptionMessage(e)),
551                    null));
552        }
553      }
554
555      return new LDAPMessage(messageID,
556           new DeleteResponseProtocolOp(op.getResult()),
557           op.getResult().getResponseControls());
558    }
559    finally
560    {
561      activeOperations.remove(messageID);
562    }
563  }
564
565
566
567  /**
568   * {@inheritDoc}
569   */
570  @Override()
571  public LDAPMessage processExtendedRequest(final int messageID,
572                          final ExtendedRequestProtocolOp request,
573                          final List<Control> controls)
574  {
575    final InterceptedExtendedOperation op =
576         new InterceptedExtendedOperation(connection, messageID, request,
577              toArray(controls));
578    activeOperations.put(messageID, op);
579
580    try
581    {
582      for (final InMemoryOperationInterceptor i : interceptors)
583      {
584        try
585        {
586          i.processExtendedRequest(op);
587        }
588        catch (final LDAPException le)
589        {
590          Debug.debugException(le);
591          return new LDAPMessage(messageID,
592               new ExtendedResponseProtocolOp(le.toLDAPResult()),
593               le.getResponseControls());
594        }
595        catch (final Exception e)
596        {
597          Debug.debugException(e);
598          return new LDAPMessage(messageID,
599               new ExtendedResponseProtocolOp(ResultCode.OTHER_INT_VALUE, null,
600                    ERR_DS_INTERCEPTOR_REQUEST_ERROR.get(
601                         String.valueOf(op), i.getClass().getName(),
602                         StaticUtils.getExceptionMessage(e)),
603                    null, null, null));
604        }
605      }
606
607      final LDAPMessage resultMessage = wrappedHandler.processExtendedRequest(
608           messageID,
609           new ExtendedRequestProtocolOp(op.getRequest()),
610           op.getRequest().getControlList());
611      op.setResult(
612           resultMessage.getExtendedResponseProtocolOp().toExtendedResult(
613                toArray(resultMessage.getControls())));
614      for (final InMemoryOperationInterceptor i : interceptors)
615      {
616        try
617        {
618          i.processExtendedResult(op);
619        }
620        catch (final Exception e)
621        {
622          Debug.debugException(e);
623          return new LDAPMessage(messageID,
624               new ExtendedResponseProtocolOp(ResultCode.OTHER_INT_VALUE, null,
625                    ERR_DS_INTERCEPTOR_RESULT_ERROR.get(
626                         String.valueOf(op), i.getClass().getName(),
627                         StaticUtils.getExceptionMessage(e)),
628                    null, null, null));
629        }
630      }
631
632      return new LDAPMessage(messageID,
633           new ExtendedResponseProtocolOp(op.getResult()),
634           op.getResult().getResponseControls());
635    }
636    finally
637    {
638      activeOperations.remove(messageID);
639    }
640  }
641
642
643
644  /**
645   * {@inheritDoc}
646   */
647  @Override()
648  public LDAPMessage processModifyRequest(final int messageID,
649                                          final ModifyRequestProtocolOp request,
650                                          final List<Control> controls)
651  {
652    final InterceptedModifyOperation op =
653         new InterceptedModifyOperation(connection, messageID, request,
654              toArray(controls));
655    activeOperations.put(messageID, op);
656
657    try
658    {
659      for (final InMemoryOperationInterceptor i : interceptors)
660      {
661        try
662        {
663          i.processModifyRequest(op);
664        }
665        catch (final LDAPException le)
666        {
667          Debug.debugException(le);
668          return new LDAPMessage(messageID,
669               new ModifyResponseProtocolOp(le.toLDAPResult()),
670               le.getResponseControls());
671        }
672        catch (final Exception e)
673        {
674          Debug.debugException(e);
675          return new LDAPMessage(messageID,
676               new ModifyResponseProtocolOp(ResultCode.OTHER_INT_VALUE, null,
677                    ERR_DS_INTERCEPTOR_REQUEST_ERROR.get(
678                         String.valueOf(op), i.getClass().getName(),
679                         StaticUtils.getExceptionMessage(e)),
680                    null));
681        }
682      }
683
684      final LDAPMessage resultMessage = wrappedHandler.processModifyRequest(
685           messageID,
686           new ModifyRequestProtocolOp((ModifyRequest) op.getRequest()),
687           op.getRequest().getControlList());
688      op.setResult(resultMessage.getModifyResponseProtocolOp().toLDAPResult(
689           toArray(resultMessage.getControls())));
690      for (final InMemoryOperationInterceptor i : interceptors)
691      {
692        try
693        {
694          i.processModifyResult(op);
695        }
696        catch (final Exception e)
697        {
698          Debug.debugException(e);
699          return new LDAPMessage(messageID,
700               new ModifyResponseProtocolOp(ResultCode.OTHER_INT_VALUE, null,
701                    ERR_DS_INTERCEPTOR_RESULT_ERROR.get(
702                         String.valueOf(op), i.getClass().getName(),
703                         StaticUtils.getExceptionMessage(e)),
704                    null));
705        }
706      }
707
708      return new LDAPMessage(messageID,
709           new ModifyResponseProtocolOp(op.getResult()),
710           op.getResult().getResponseControls());
711    }
712    finally
713    {
714      activeOperations.remove(messageID);
715    }
716  }
717
718
719
720  /**
721   * {@inheritDoc}
722   */
723  @Override()
724  public LDAPMessage processModifyDNRequest(final int messageID,
725                          final ModifyDNRequestProtocolOp request,
726                          final List<Control> controls)
727  {
728    final InterceptedModifyDNOperation op =
729         new InterceptedModifyDNOperation(connection, messageID, request,
730              toArray(controls));
731    activeOperations.put(messageID, op);
732
733    try
734    {
735      for (final InMemoryOperationInterceptor i : interceptors)
736      {
737        try
738        {
739          i.processModifyDNRequest(op);
740        }
741        catch (final LDAPException le)
742        {
743          Debug.debugException(le);
744          return new LDAPMessage(messageID,
745               new ModifyDNResponseProtocolOp(le.toLDAPResult()),
746               le.getResponseControls());
747        }
748        catch (final Exception e)
749        {
750          Debug.debugException(e);
751          return new LDAPMessage(messageID,
752               new ModifyDNResponseProtocolOp(ResultCode.OTHER_INT_VALUE, null,
753                    ERR_DS_INTERCEPTOR_REQUEST_ERROR.get(
754                         String.valueOf(op), i.getClass().getName(),
755                         StaticUtils.getExceptionMessage(e)),
756                    null));
757        }
758      }
759
760      final LDAPMessage resultMessage = wrappedHandler.processModifyDNRequest(
761           messageID,
762           new ModifyDNRequestProtocolOp((ModifyDNRequest) op.getRequest()),
763           op.getRequest().getControlList());
764      op.setResult(resultMessage.getModifyDNResponseProtocolOp().toLDAPResult(
765           toArray(resultMessage.getControls())));
766      for (final InMemoryOperationInterceptor i : interceptors)
767      {
768        try
769        {
770          i.processModifyDNResult(op);
771        }
772        catch (final Exception e)
773        {
774          Debug.debugException(e);
775          return new LDAPMessage(messageID,
776               new ModifyDNResponseProtocolOp(ResultCode.OTHER_INT_VALUE, null,
777                    ERR_DS_INTERCEPTOR_RESULT_ERROR.get(
778                         String.valueOf(op), i.getClass().getName(),
779                         StaticUtils.getExceptionMessage(e)),
780                    null));
781        }
782      }
783
784      return new LDAPMessage(messageID,
785           new ModifyDNResponseProtocolOp(op.getResult()),
786           op.getResult().getResponseControls());
787    }
788    finally
789    {
790      activeOperations.remove(messageID);
791    }
792  }
793
794
795
796  /**
797   * {@inheritDoc}
798   */
799  @Override()
800  public LDAPMessage processSearchRequest(final int messageID,
801                                          final SearchRequestProtocolOp request,
802                                          final List<Control> controls)
803  {
804    final InterceptedSearchOperation op =
805         new InterceptedSearchOperation(connection, messageID, request,
806              toArray(controls));
807    activeOperations.put(messageID, op);
808
809    try
810    {
811      for (final InMemoryOperationInterceptor i : interceptors)
812      {
813        try
814        {
815          i.processSearchRequest(op);
816        }
817        catch (final LDAPException le)
818        {
819          Debug.debugException(le);
820          return new LDAPMessage(messageID,
821               new SearchResultDoneProtocolOp(le.toLDAPResult()),
822               le.getResponseControls());
823        }
824        catch (final Exception e)
825        {
826          Debug.debugException(e);
827          return new LDAPMessage(messageID,
828               new SearchResultDoneProtocolOp(ResultCode.OTHER_INT_VALUE, null,
829                    ERR_DS_INTERCEPTOR_REQUEST_ERROR.get(
830                         String.valueOf(op), i.getClass().getName(),
831                         StaticUtils.getExceptionMessage(e)),
832                    null));
833        }
834      }
835
836      final LDAPMessage resultMessage = wrappedHandler.processSearchRequest(
837           messageID,
838           new SearchRequestProtocolOp((SearchRequest) op.getRequest()),
839           op.getRequest().getControlList());
840      op.setResult(resultMessage.getSearchResultDoneProtocolOp().toLDAPResult(
841           toArray(resultMessage.getControls())));
842      for (final InMemoryOperationInterceptor i : interceptors)
843      {
844        try
845        {
846          i.processSearchResult(op);
847        }
848        catch (final Exception e)
849        {
850          Debug.debugException(e);
851          return new LDAPMessage(messageID,
852               new SearchResultDoneProtocolOp(ResultCode.OTHER_INT_VALUE, null,
853                    ERR_DS_INTERCEPTOR_RESULT_ERROR.get(
854                         String.valueOf(op), i.getClass().getName(),
855                         StaticUtils.getExceptionMessage(e)),
856                    null));
857        }
858      }
859
860      return new LDAPMessage(messageID,
861           new SearchResultDoneProtocolOp(op.getResult()),
862           op.getResult().getResponseControls());
863    }
864    finally
865    {
866      activeOperations.remove(messageID);
867    }
868  }
869
870
871
872  /**
873   * {@inheritDoc}
874   */
875  @Override()
876  public ObjectPair<SearchResultEntryProtocolOp,Control[]> transformEntry(
877              final int messageID, final SearchResultEntryProtocolOp entry,
878              final Control[] controls)
879  {
880    final InterceptedSearchOperation op =
881         (InterceptedSearchOperation) activeOperations.get(messageID);
882    if (op == null)
883    {
884      return new ObjectPair<>(entry, controls);
885    }
886
887    final InterceptedSearchEntry e =
888         new InterceptedSearchEntry(op, entry, controls);
889    for (final InMemoryOperationInterceptor i : interceptors)
890    {
891      try
892      {
893        i.processSearchEntry(e);
894        if (e.getSearchEntry() == null)
895        {
896          return null;
897        }
898      }
899      catch (final Exception ex)
900      {
901        Debug.debugException(ex);
902        return null;
903      }
904    }
905
906    return new ObjectPair<>(new SearchResultEntryProtocolOp(e.getSearchEntry()),
907         e.getSearchEntry().getControls());
908  }
909
910
911
912  /**
913   * {@inheritDoc}
914   */
915  @Override()
916  public ObjectPair<SearchResultReferenceProtocolOp,Control[]>
917              transformReference(final int messageID,
918                   final SearchResultReferenceProtocolOp reference,
919                   final Control[] controls)
920  {
921    final InterceptedSearchOperation op =
922         (InterceptedSearchOperation) activeOperations.get(messageID);
923    if (op == null)
924    {
925      return new ObjectPair<>(reference, controls);
926    }
927
928    final InterceptedSearchReference r =
929         new InterceptedSearchReference(op, reference, controls);
930    for (final InMemoryOperationInterceptor i : interceptors)
931    {
932      try
933      {
934        i.processSearchReference(r);
935        if (r.getSearchReference() == null)
936        {
937          return null;
938        }
939      }
940      catch (final Exception ex)
941      {
942        Debug.debugException(ex);
943        return null;
944      }
945    }
946
947    return new ObjectPair<>(
948         new SearchResultReferenceProtocolOp(r.getSearchReference()),
949         r.getSearchReference().getControls());
950  }
951
952
953
954  /**
955   * Transforms the provided intermediate response and/or set of controls to
956   * alter what will be returned to the client.
957   *
958   * @param  messageID  The message ID for the associated search operation.
959   * @param  response   The intermediate response to be processed.  It will not
960   *                    be {@code null}.
961   * @param  controls   The set of controls to be processed.  It will not be
962   *                    {@code null} but may be empty if there are no controls.
963   *
964   * @return  An {@link ObjectPair} containing a possibly updated intermediate
965   *          response and set of controls, or {@code null} to indicate that the
966   *          response should not be returned to the client.
967   */
968  @Override()
969  public ObjectPair<IntermediateResponseProtocolOp,Control[]>
970              transformIntermediateResponse(final int messageID,
971                   final IntermediateResponseProtocolOp response,
972                   final Control[] controls)
973  {
974    final InterceptedOperation op = activeOperations.get(messageID);
975    if (op == null)
976    {
977      return new ObjectPair<>(response, controls);
978    }
979
980    final InterceptedIntermediateResponse r =
981         new InterceptedIntermediateResponse(op, response, controls);
982    for (final InMemoryOperationInterceptor i : interceptors)
983    {
984      try
985      {
986        i.processIntermediateResponse(r);
987        if (r.getIntermediateResponse() == null)
988        {
989          return null;
990        }
991      }
992      catch (final Exception ex)
993      {
994        Debug.debugException(ex);
995        return null;
996      }
997    }
998
999    return new ObjectPair<>(
1000         new IntermediateResponseProtocolOp(r.getIntermediateResponse()),
1001         r.getIntermediateResponse().getControls());
1002  }
1003
1004
1005
1006  /**
1007   * Converts the provided control list to a control array.
1008   *
1009   * @param  controls  The list of controls to be converted to an array.
1010   *
1011   * @return  The resulting array of controls.
1012   */
1013  private static Control[] toArray(final List<Control> controls)
1014  {
1015    if ((controls == null) || controls.isEmpty())
1016    {
1017      return StaticUtils.NO_CONTROLS;
1018    }
1019
1020    final Control[] controlArray = new Control[controls.size()];
1021    return controls.toArray(controlArray);
1022  }
1023}