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