001/*
002 * Copyright 2010-2020 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2010-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) 2010-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;
037
038
039
040import java.io.Serializable;
041import java.util.ArrayList;
042import java.util.Collection;
043import java.util.Collections;
044import java.util.List;
045
046import com.unboundid.ldap.protocol.AddRequestProtocolOp;
047import com.unboundid.ldap.protocol.AddResponseProtocolOp;
048import com.unboundid.ldap.protocol.BindRequestProtocolOp;
049import com.unboundid.ldap.protocol.BindResponseProtocolOp;
050import com.unboundid.ldap.protocol.CompareRequestProtocolOp;
051import com.unboundid.ldap.protocol.CompareResponseProtocolOp;
052import com.unboundid.ldap.protocol.DeleteRequestProtocolOp;
053import com.unboundid.ldap.protocol.DeleteResponseProtocolOp;
054import com.unboundid.ldap.protocol.ExtendedRequestProtocolOp;
055import com.unboundid.ldap.protocol.ExtendedResponseProtocolOp;
056import com.unboundid.ldap.protocol.LDAPMessage;
057import com.unboundid.ldap.protocol.ModifyRequestProtocolOp;
058import com.unboundid.ldap.protocol.ModifyResponseProtocolOp;
059import com.unboundid.ldap.protocol.ModifyDNRequestProtocolOp;
060import com.unboundid.ldap.protocol.ModifyDNResponseProtocolOp;
061import com.unboundid.ldap.protocol.SearchRequestProtocolOp;
062import com.unboundid.ldap.protocol.SearchResultDoneProtocolOp;
063import com.unboundid.ldap.protocol.SearchResultEntryProtocolOp;
064import com.unboundid.ldap.protocol.SearchResultReferenceProtocolOp;
065import com.unboundid.ldap.sdk.Control;
066import com.unboundid.ldap.sdk.Entry;
067import com.unboundid.ldap.sdk.LDAPException;
068import com.unboundid.ldap.sdk.ResultCode;
069import com.unboundid.ldap.sdk.SearchResultReference;
070import com.unboundid.util.Debug;
071import com.unboundid.util.NotMutable;
072import com.unboundid.util.ThreadSafety;
073import com.unboundid.util.ThreadSafetyLevel;
074import com.unboundid.util.Validator;
075
076
077
078/**
079 * This class provides a very simple LDAP listener request handler
080 * implementation that simply returns a canned response to the client for each
081 * type of operation.
082 */
083@NotMutable()
084@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
085public final class CannedResponseRequestHandler
086       extends LDAPListenerRequestHandler
087       implements Serializable
088{
089  /**
090   * The serial version UID for this serializable class.
091   */
092  private static final long serialVersionUID = 6199105854736880833L;
093
094
095
096  // The protocol ops that will be used in responses.
097  private final AddResponseProtocolOp addResponseProtocolOp;
098  private final BindResponseProtocolOp bindResponseProtocolOp;
099  private final CompareResponseProtocolOp compareResponseProtocolOp;
100  private final DeleteResponseProtocolOp deleteResponseProtocolOp;
101  private final ExtendedResponseProtocolOp extendedResponseProtocolOp;
102  private final ModifyResponseProtocolOp modifyResponseProtocolOp;
103  private final ModifyDNResponseProtocolOp modifyDNResponseProtocolOp;
104  private final List<SearchResultEntryProtocolOp> searchEntryProtocolOps;
105  private final List<SearchResultReferenceProtocolOp>
106       searchReferenceProtocolOps;
107  private final SearchResultDoneProtocolOp searchResultDoneProtocolOp;
108
109  // The connection that will be used to communicate with the client.
110  private final LDAPListenerClientConnection clientConnection;
111
112
113
114  /**
115   * Creates a new instance of this canned response request handler that will
116   * immediately return a "SUCCESS" response to any request that is received.
117   */
118  public CannedResponseRequestHandler()
119  {
120    this(ResultCode.SUCCESS, null, null, null);
121  }
122
123
124
125  /**
126   * Creates a new instance of this canned response request handler that will
127   * immediately return a response with the provided information to any request
128   * that is received.
129   *
130   * @param  resultCode         The result code to use for the responses.  It
131   *                            must not be {@code null}.
132   * @param  matchedDN          The matched DN to use for the responses.  It may
133   *                            be {@code null} if no matched DN should be
134   *                            included.
135   * @param  diagnosticMessage  The diagnostic message to use for the responses.
136   *                            It may be {@code null} if no diagnostic message
137   *                            should be included.
138   * @param  referralURLs       The referral URLs to use for the responses.  It
139   *                            may be empty or {@code null} if no referral URLs
140   *                            should be included.
141   */
142  public CannedResponseRequestHandler(final ResultCode resultCode,
143                                      final String matchedDN,
144                                      final String diagnosticMessage,
145                                      final List<String> referralURLs)
146  {
147    this(resultCode, matchedDN, diagnosticMessage, referralURLs, null, null);
148  }
149
150
151
152  /**
153   * Creates a new instance of this canned response request handler that will
154   * immediately return a response with the provided information to any request
155   * that is received.
156   *
157   * @param  resultCode         The result code to use for the responses.  It
158   *                            must not be {@code null}.
159   * @param  matchedDN          The matched DN to use for the responses.  It may
160   *                            be {@code null} if no matched DN should be
161   *                            included.
162   * @param  diagnosticMessage  The diagnostic message to use for the responses.
163   *                            It may be {@code null} if no diagnostic message
164   *                            should be included.
165   * @param  referralURLs       The referral URLs to use for the responses.  It
166   *                            may be empty or {@code null} if no referral URLs
167   *                            should be included.
168   * @param  searchEntries      The set of search result entries that should be
169   *                            returned for every search.  It may be
170   *                            {@code null} or empty if no entries are
171   *                            required.
172   * @param  searchReferences   The set of search result references that should
173   *                            be returned for every search.  It may be
174   *                            {@code null} or empty if no references are
175   *                            required.
176   */
177  public CannedResponseRequestHandler(final ResultCode resultCode,
178              final String matchedDN, final String diagnosticMessage,
179              final List<String> referralURLs,
180              final Collection<? extends Entry> searchEntries,
181              final Collection<SearchResultReference> searchReferences)
182  {
183    Validator.ensureNotNull(resultCode);
184
185    clientConnection = null;
186
187    final int rc = resultCode.intValue();
188    addResponseProtocolOp = new AddResponseProtocolOp(rc, matchedDN,
189         diagnosticMessage, referralURLs);
190    bindResponseProtocolOp = new BindResponseProtocolOp(rc, matchedDN,
191         diagnosticMessage, referralURLs, null);
192    compareResponseProtocolOp = new CompareResponseProtocolOp(rc, matchedDN,
193         diagnosticMessage, referralURLs);
194    deleteResponseProtocolOp = new DeleteResponseProtocolOp(rc, matchedDN,
195         diagnosticMessage, referralURLs);
196    extendedResponseProtocolOp = new ExtendedResponseProtocolOp(rc, matchedDN,
197         diagnosticMessage, referralURLs, null, null);
198    modifyResponseProtocolOp = new ModifyResponseProtocolOp(rc, matchedDN,
199         diagnosticMessage, referralURLs);
200    modifyDNResponseProtocolOp = new ModifyDNResponseProtocolOp(rc, matchedDN,
201         diagnosticMessage, referralURLs);
202    searchResultDoneProtocolOp = new SearchResultDoneProtocolOp(rc, matchedDN,
203         diagnosticMessage, referralURLs);
204
205    if ((searchEntries == null) || searchEntries.isEmpty())
206    {
207      searchEntryProtocolOps = Collections.emptyList();
208    }
209    else
210    {
211      final ArrayList<SearchResultEntryProtocolOp> l =
212           new ArrayList<>(searchEntries.size());
213      for (final Entry e : searchEntries)
214      {
215        l.add(new SearchResultEntryProtocolOp(e));
216      }
217
218      searchEntryProtocolOps = Collections.unmodifiableList(l);
219    }
220
221    if ((searchReferences == null) || searchReferences.isEmpty())
222    {
223      searchReferenceProtocolOps = Collections.emptyList();
224    }
225    else
226    {
227      final ArrayList<SearchResultReferenceProtocolOp> l =
228           new ArrayList<>(searchReferences.size());
229      for (final SearchResultReference r : searchReferences)
230      {
231        l.add(new SearchResultReferenceProtocolOp(r));
232      }
233
234      searchReferenceProtocolOps = Collections.unmodifiableList(l);
235    }
236  }
237
238
239
240  /**
241   * Creates a new instance of this canned response request handler using the
242   * information of the provided handler and the given client connection.
243   *
244   * @param  h  The request handler from which to take the canned responses.
245   * @param  c  The connection to use to communicate with the client.
246   */
247  private CannedResponseRequestHandler(final CannedResponseRequestHandler h,
248               final LDAPListenerClientConnection c)
249  {
250    addResponseProtocolOp      = h.addResponseProtocolOp;
251    bindResponseProtocolOp     = h.bindResponseProtocolOp;
252    compareResponseProtocolOp  = h.compareResponseProtocolOp;
253    deleteResponseProtocolOp   = h.deleteResponseProtocolOp;
254    extendedResponseProtocolOp = h.extendedResponseProtocolOp;
255    modifyResponseProtocolOp   = h.modifyResponseProtocolOp;
256    modifyDNResponseProtocolOp = h.modifyDNResponseProtocolOp;
257    searchEntryProtocolOps     = h.searchEntryProtocolOps;
258    searchReferenceProtocolOps = h.searchReferenceProtocolOps;
259    searchResultDoneProtocolOp = h.searchResultDoneProtocolOp;
260
261    clientConnection = c;
262  }
263
264
265
266  /**
267   * {@inheritDoc}
268   */
269  @Override()
270  public CannedResponseRequestHandler newInstance(
271              final LDAPListenerClientConnection connection)
272         throws LDAPException
273  {
274    return new CannedResponseRequestHandler(this, connection);
275  }
276
277
278
279  /**
280   * {@inheritDoc}
281   */
282  @Override()
283  public LDAPMessage processAddRequest(final int messageID,
284                                       final AddRequestProtocolOp request,
285                                       final List<Control> controls)
286  {
287    return new LDAPMessage(messageID, addResponseProtocolOp,
288         Collections.<Control>emptyList());
289  }
290
291
292
293  /**
294   * {@inheritDoc}
295   */
296  @Override()
297  public LDAPMessage processBindRequest(final int messageID,
298                                        final BindRequestProtocolOp request,
299                                        final List<Control> controls)
300  {
301    return new LDAPMessage(messageID, bindResponseProtocolOp,
302         Collections.<Control>emptyList());
303  }
304
305
306
307  /**
308   * {@inheritDoc}
309   */
310  @Override()
311  public LDAPMessage processCompareRequest(final int messageID,
312                          final CompareRequestProtocolOp request,
313                          final List<Control> controls)
314  {
315    return new LDAPMessage(messageID, compareResponseProtocolOp,
316         Collections.<Control>emptyList());
317  }
318
319
320
321  /**
322   * {@inheritDoc}
323   */
324  @Override()
325  public LDAPMessage processDeleteRequest(final int messageID,
326                                          final DeleteRequestProtocolOp request,
327                                          final List<Control> controls)
328  {
329    return new LDAPMessage(messageID, deleteResponseProtocolOp,
330         Collections.<Control>emptyList());
331  }
332
333
334
335  /**
336   * {@inheritDoc}
337   */
338  @Override()
339  public LDAPMessage processExtendedRequest(final int messageID,
340                          final ExtendedRequestProtocolOp request,
341                          final List<Control> controls)
342  {
343    return new LDAPMessage(messageID, extendedResponseProtocolOp,
344         Collections.<Control>emptyList());
345  }
346
347
348
349  /**
350   * {@inheritDoc}
351   */
352  @Override()
353  public LDAPMessage processModifyRequest(final int messageID,
354                                          final ModifyRequestProtocolOp request,
355                                          final List<Control> controls)
356  {
357    return new LDAPMessage(messageID, modifyResponseProtocolOp,
358         Collections.<Control>emptyList());
359  }
360
361
362
363  /**
364   * {@inheritDoc}
365   */
366  @Override()
367  public LDAPMessage processModifyDNRequest(final int messageID,
368                          final ModifyDNRequestProtocolOp request,
369                          final List<Control> controls)
370  {
371    return new LDAPMessage(messageID, modifyDNResponseProtocolOp,
372         Collections.<Control>emptyList());
373  }
374
375
376
377  /**
378   * {@inheritDoc}
379   */
380  @Override()
381  public LDAPMessage processSearchRequest(final int messageID,
382                                          final SearchRequestProtocolOp request,
383                                          final List<Control> controls)
384  {
385    for (final SearchResultEntryProtocolOp e : searchEntryProtocolOps)
386    {
387      try
388      {
389        clientConnection.sendSearchResultEntry(messageID, e);
390      }
391      catch (final Exception ex)
392      {
393        Debug.debugException(ex);
394      }
395    }
396
397    for (final SearchResultReferenceProtocolOp r : searchReferenceProtocolOps)
398    {
399      try
400      {
401        clientConnection.sendSearchResultReference(messageID, r);
402      }
403      catch (final Exception ex)
404      {
405        Debug.debugException(ex);
406      }
407    }
408
409    return new LDAPMessage(messageID, searchResultDoneProtocolOp,
410         Collections.<Control>emptyList());
411  }
412}