001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at
010 * docs/licenses/cddl.txt
011 * or http://www.opensource.org/licenses/cddl1.php.
012 * See the License for the specific language governing permissions
013 * and limitations under the License.
014 *
015 * When distributing Covered Code, include this CDDL HEADER in each
016 * file and include the License file at
017 * docs/licenses/cddl.txt.  If applicable,
018 * add the following below this CDDL HEADER, with the fields enclosed
019 * by brackets "[]" replaced with your own identifying information:
020 *      Portions Copyright [yyyy] [name of copyright owner]
021 *
022 * CDDL HEADER END
023 *
024 *
025 *      Portions Copyright 2010-2024 Ping Identity Corporation
026 */
027package com.unboundid.directory.sdk.proxy.api;
028
029
030
031import java.util.Collections;
032import java.util.List;
033import java.util.Map;
034
035import com.unboundid.directory.sdk.common.internal.ExampleUsageProvider;
036import com.unboundid.directory.sdk.common.internal.Reconfigurable;
037import com.unboundid.directory.sdk.common.internal.UnboundIDExtension;
038import com.unboundid.directory.sdk.proxy.config.ProxyTransformationConfig;
039import com.unboundid.directory.sdk.proxy.internal.DirectoryProxyServerExtension;
040import com.unboundid.directory.sdk.proxy.internal.SearchResultProvider;
041import com.unboundid.directory.sdk.proxy.types.ProxyOperationContext;
042import com.unboundid.directory.sdk.proxy.types.ProxyServerContext;
043import com.unboundid.ldap.sdk.AddRequest;
044import com.unboundid.ldap.sdk.BindRequest;
045import com.unboundid.ldap.sdk.BindResult;
046import com.unboundid.ldap.sdk.CompareRequest;
047import com.unboundid.ldap.sdk.DeleteRequest;
048import com.unboundid.ldap.sdk.LDAPException;
049import com.unboundid.ldap.sdk.LDAPResult;
050import com.unboundid.ldap.sdk.ModifyRequest;
051import com.unboundid.ldap.sdk.ModifyDNRequest;
052import com.unboundid.ldap.sdk.ReadOnlyAddRequest;
053import com.unboundid.ldap.sdk.ReadOnlyCompareRequest;
054import com.unboundid.ldap.sdk.ReadOnlyDeleteRequest;
055import com.unboundid.ldap.sdk.ReadOnlyModifyRequest;
056import com.unboundid.ldap.sdk.ReadOnlyModifyDNRequest;
057import com.unboundid.ldap.sdk.ReadOnlySearchRequest;
058import com.unboundid.ldap.sdk.ResultCode;
059import com.unboundid.ldap.sdk.SearchRequest;
060import com.unboundid.ldap.sdk.SearchResult;
061import com.unboundid.ldap.sdk.SearchResultEntry;
062import com.unboundid.ldap.sdk.SearchResultReference;
063import com.unboundid.util.Extensible;
064import com.unboundid.util.ThreadSafety;
065import com.unboundid.util.ThreadSafetyLevel;
066import com.unboundid.util.args.ArgumentException;
067import com.unboundid.util.args.ArgumentParser;
068
069
070
071/**
072 * This class defines an API that must be implemented by extensions which are
073 * used to transform requests and/or responses as they pass through the
074 * Directory Proxy Server.  They may be used to alter the contents of any add,
075 * bind, compare, delete, modify, modify DN, or search request or result passing
076 * through the Directory Proxy Server, or they may cause a result to be returned
077 * to the client without it being forwarded to a backend server.  In addition,
078 * transformations may be applied to search result entries and references to be
079 * returned to the client, or those entries and references may be silently
080 * dropped so that they are not returned.
081 * <BR>
082 * <H2>Configuring Proxy Transformations</H2>
083 * In order to configure a proxy transformation created using this API, use a
084 * command like:
085 * <PRE>
086 *      dsconfig create-proxy-transformation \
087 *           --transformation-name "<I>{transformation-name}</I>" \
088 *           --type third-party \
089 *           --set enabled:true \
090 *           --set "extension-class:<I>{class-name}</I>" \
091 *           --set "extension-argument:<I>{name=value}</I>"
092 * </PRE>
093 * where "<I>{transformation-name}</I>" is the name to use for the proxy
094 * transformation instance, "<I>{class-name}</I>" is the fully-qualified name of
095 * the Java class that extends
096 * {@code com.unboundid.directory.sdk.proxy.api.ProxyTransformation}, and
097 * "<I>{name=value}</I>" represents name-value pairs for any arguments to
098 * provide to the proxy transformation.  If multiple arguments should be
099 * provided to the proxy transformation, then the
100 * "<CODE>--set extension-argument:<I>{name=value}</I></CODE>" option should be
101 * provided multiple times.
102 *
103 * @see  com.unboundid.directory.sdk.proxy.scripting.ScriptedProxyTransformation
104 */
105@Extensible()
106@DirectoryProxyServerExtension(appliesToLocalContent=false,
107     appliesToRemoteContent=true)
108@ThreadSafety(level=ThreadSafetyLevel.INTERFACE_THREADSAFE)
109public abstract class ProxyTransformation
110       implements UnboundIDExtension, Reconfigurable<ProxyTransformationConfig>,
111                  ExampleUsageProvider
112{
113  /**
114   * Creates a new instance of this proxy transformation.  All proxy
115   * transformation implementations must include a default constructor, but any
116   * initialization should generally be done in the
117   * {@code initializeProxyTransformation} method.
118   */
119  public ProxyTransformation()
120  {
121    // No implementation is required.
122  }
123
124
125
126  /**
127   * {@inheritDoc}
128   */
129  public abstract String getExtensionName();
130
131
132
133  /**
134   * {@inheritDoc}
135   */
136  public abstract String[] getExtensionDescription();
137
138
139
140  /**
141   * {@inheritDoc}
142   */
143  public void defineConfigArguments(final ArgumentParser parser)
144         throws ArgumentException
145  {
146    // No arguments will be allowed by default.
147  }
148
149
150
151  /**
152   * Initializes this proxy transformation.
153   *
154   * @param  serverContext  A handle to the server context for the Directory
155   *                        Proxy server in which this extension is running.
156   * @param  config         The general configuration for this proxy
157   *                        transformation.
158   * @param  parser         The argument parser which has been initialized from
159   *                        the configuration for this proxy transformation.
160   *
161   * @throws  LDAPException  If a problem occurs while initializing this proxy
162   *                         transformation.
163   */
164  public void initializeProxyTransformation(
165                   final ProxyServerContext serverContext,
166                   final ProxyTransformationConfig config,
167                   final ArgumentParser parser)
168         throws LDAPException
169  {
170    // No initialization will be performed by default.
171  }
172
173
174
175  /**
176   * {@inheritDoc}
177   */
178  public boolean isConfigurationAcceptable(
179                      final ProxyTransformationConfig config,
180                      final ArgumentParser parser,
181                      final List<String> unacceptableReasons)
182  {
183    // No extended validation will be performed by default.
184    return true;
185  }
186
187
188
189  /**
190   * {@inheritDoc}
191   */
192  public ResultCode applyConfiguration(final ProxyTransformationConfig config,
193                                       final ArgumentParser parser,
194                                       final List<String> adminActionsRequired,
195                                       final List<String> messages)
196  {
197    // By default, no configuration changes will be applied.  If there are any
198    // arguments, then add an admin action message indicating that the extension
199    // needs to be restarted for any changes to take effect.
200    if (! parser.getNamedArguments().isEmpty())
201    {
202      adminActionsRequired.add(
203           "No configuration change has actually been applied.  The new " +
204                "configuration will not take effect until this proxy " +
205                "transformation is disabled and re-enabled or until the " +
206                "server is restarted.");
207    }
208
209    return ResultCode.SUCCESS;
210  }
211
212
213
214  /**
215   * Performs any cleanup which may be necessary when this proxy transformation
216   * is to be taken out of service.
217   */
218  public void finalizeProxyTransformation()
219  {
220    // No implementation is required.
221  }
222
223
224
225  /**
226   * Applies any necessary transformation to the provided add request.
227   *
228   * @param  operationContext  Information about the operation being processed
229   *                           in the Directory Proxy Server.
230   * @param  addRequest        The add request to be transformed.
231   *
232   * @return  A new add request which has been transformed as necessary, or the
233   *          original request if no transformation is required or the provided
234   *          add request has been updated in place.
235   *
236   * @throws  LDAPException  If a problem is encountered while processing the
237   *                         transformation, or if the provided request should
238   *                         not be forwarded to a backend server.
239   */
240  public AddRequest transformAddRequest(
241                         final ProxyOperationContext operationContext,
242                         final AddRequest addRequest)
243         throws LDAPException
244  {
245    return addRequest;
246  }
247
248
249
250  /**
251   * Applies any necessary transformation to the provided add result.
252   *
253   * @param  operationContext  Information about the operation being processed
254   *                           in the Directory Proxy Server.
255   * @param  addRequest        The add request that was processed.
256   * @param  addResult         The add result to be transformed.
257   *
258   * @return  A new add result which has been transformed as necessary, or the
259   *          original result if no transformation is required or the provided
260   *          add result has been updated in place.
261   */
262  public LDAPResult transformAddResult(
263                         final ProxyOperationContext operationContext,
264                         final ReadOnlyAddRequest addRequest,
265                         final LDAPResult addResult)
266  {
267    return addResult;
268  }
269
270
271
272  /**
273   * Applies any necessary transformation to the provided bind request.
274   *
275   * @param  operationContext  Information about the operation being processed
276   *                           in the Directory Proxy Server.
277   * @param  bindRequest       The bind request to be transformed.
278   *
279   * @return  A new bind request which has been transformed as necessary, or the
280   *          original request if no transformation is required.
281   *
282   * @throws  LDAPException  If a problem is encountered while processing the
283   *                         transformation, or if the provided request should
284   *                         not be forwarded to a backend server.
285   */
286  public BindRequest transformBindRequest(
287                         final ProxyOperationContext operationContext,
288                         final BindRequest bindRequest)
289         throws LDAPException
290  {
291    return bindRequest;
292  }
293
294
295
296  /**
297   * Applies any necessary transformation to the provided bind request.
298   *
299   * @param  operationContext  Information about the operation being processed
300   *                           in the Directory Proxy Server.
301   * @param  bindRequest       The bind request that was processed.
302   * @param  bindResult        The bind result to be transformed.
303   *
304   * @return  A new bind result which has been transformed as necessary, or the
305   *          original result if no transformation is required.
306   */
307  public BindResult transformBindResult(
308                         final ProxyOperationContext operationContext,
309                         final BindRequest bindRequest,
310                         final BindResult bindResult)
311  {
312    return bindResult;
313  }
314
315
316
317  /**
318   * Applies any necessary transformation to the provided compare request.
319   *
320   * @param  operationContext  Information about the operation being processed
321   *                           in the Directory Proxy Server.
322   * @param  compareRequest    The compare request to be transformed.
323   *
324   * @return  A new compare request which has been transformed as necessary, or
325   *          the original request if no transformation is required or the
326   *          provided compare request has been updated in place.
327   *
328   * @throws  LDAPException  If a problem is encountered while processing the
329   *                         transformation, or if the provided request should
330   *                         not be forwarded to a backend server.
331   */
332  public CompareRequest transformCompareRequest(
333                             final ProxyOperationContext operationContext,
334                             final CompareRequest compareRequest)
335         throws LDAPException
336  {
337    return compareRequest;
338  }
339
340
341
342  /**
343   * Applies any necessary transformation to the provided compare result.
344   *
345   * @param  operationContext  Information about the operation being processed
346   *                           in the Directory Proxy Server.
347   * @param  compareRequest    The compare request that was processed.
348   * @param  compareResult     The compare result to be transformed.
349   *
350   * @return  A new compare result which has been transformed as necessary, or
351   *          the original result if no transformation is required or the
352   *          provided compare result has been updated in place.
353   */
354  public LDAPResult transformCompareResult(
355                         final ProxyOperationContext operationContext,
356                         final ReadOnlyCompareRequest compareRequest,
357                         final LDAPResult compareResult)
358  {
359    return compareResult;
360  }
361
362
363
364  /**
365   * Applies any necessary transformation to the provided delete request.
366   *
367   * @param  operationContext  Information about the operation being processed
368   *                           in the Directory Proxy Server.
369   * @param  deleteRequest     The delete request to be transformed.
370   *
371   * @return  A new delete request which has been transformed as necessary, or
372   *          the original request if no transformation is required or the
373   *          provided delete request has been updated in place.
374   *
375   * @throws  LDAPException  If a problem is encountered while processing the
376   *                         transformation, or if the provided request should
377   *                         not be forwarded to a backend server.
378   */
379  public DeleteRequest transformDeleteRequest(
380                            final ProxyOperationContext operationContext,
381                            final DeleteRequest deleteRequest)
382         throws LDAPException
383  {
384    return deleteRequest;
385  }
386
387
388
389  /**
390   * Applies any necessary transformation to the provided delete result.
391   *
392   * @param  operationContext  Information about the operation being processed
393   *                           in the Directory Proxy Server.
394   * @param  deleteRequest     The delete request that was processed.
395   * @param  deleteResult      The delete result to be transformed.
396   *
397   * @return  A new delete result which has been transformed as necessary, or
398   *          the original result if no transformation is required or the
399   *          provided delete result has been updated in place.
400   */
401  public LDAPResult transformDeleteResult(
402                         final ProxyOperationContext operationContext,
403                         final ReadOnlyDeleteRequest deleteRequest,
404                         final LDAPResult deleteResult)
405  {
406    return deleteResult;
407  }
408
409
410
411  /**
412   * Applies any necessary transformation to the provided modify request.
413   *
414   * @param  operationContext  Information about the operation being processed
415   *                           in the Directory Proxy Server.
416   * @param  modifyRequest     The modify request to be transformed.
417   *
418   * @return  A new modify request which has been transformed as necessary, or
419   *          the original request if no transformation is required or the
420   *          provided modify request has been updated in place.
421   *
422   * @throws  LDAPException  If a problem is encountered while processing the
423   *                         transformation, or if the provided request should
424   *                         not be forwarded to a backend server.
425   */
426  public ModifyRequest transformModifyRequest(
427                            final ProxyOperationContext operationContext,
428                            final ModifyRequest modifyRequest)
429         throws LDAPException
430  {
431    return modifyRequest;
432  }
433
434
435
436  /**
437   * Applies any necessary transformation to the provided modify result.
438   *
439   * @param  operationContext  Information about the operation being processed
440   *                           in the Directory Proxy Server.
441   * @param  modifyRequest     The modify request that was processed.
442   * @param  modifyResult      The modify result to be transformed.
443   *
444   * @return  A new modify result which has been transformed as necessary, or
445   *          the original result if no transformation is required or the
446   *          provided modify result has been updated in place.
447   */
448  public LDAPResult transformModifyResult(
449                         final ProxyOperationContext operationContext,
450                         final ReadOnlyModifyRequest modifyRequest,
451                         final LDAPResult modifyResult)
452  {
453    return modifyResult;
454  }
455
456
457
458  /**
459   * Applies any necessary transformation to the provided modify DN request.
460   *
461   * @param  operationContext  Information about the operation being processed
462   *                           in the Directory Proxy Server.
463   * @param  modifyDNRequest   The modify DN request to be transformed.
464   *
465   * @return  A new modify DN request which has been transformed as necessary,
466   *          or the original request if no transformation is required or the
467   *          provided modify DN request has been updated in place.
468   *
469   * @throws  LDAPException  If a problem is encountered while processing the
470   *                         transformation, or if the provided request should
471   *                         not be forwarded to a backend server.
472   */
473  public ModifyDNRequest transformModifyDNRequest(
474                              final ProxyOperationContext operationContext,
475                              final ModifyDNRequest modifyDNRequest)
476         throws LDAPException
477  {
478    return modifyDNRequest;
479  }
480
481
482
483  /**
484   * Applies any necessary transformation to the provided modify DN result.
485   *
486   * @param  operationContext  Information about the operation being processed
487   *                           in the Directory Proxy Server.
488   * @param  modifyDNRequest   The modify DN request that was processed.
489   * @param  modifyDNResult    The modify DN result to be transformed.
490   *
491   * @return  A new modify DN result which has been transformed as necessary, or
492   *          the original result if no transformation is required or the
493   *          provided modify DN result has been updated in place.
494   */
495  public LDAPResult transformModifyDNResult(
496                         final ProxyOperationContext operationContext,
497                         final ReadOnlyModifyDNRequest modifyDNRequest,
498                         final LDAPResult modifyDNResult)
499  {
500    return modifyDNResult;
501  }
502
503
504
505  /**
506   * Applies any necessary transformation to the provided search request.
507   *
508   * @param  operationContext  Information about the operation being processed
509   *                           in the Directory Proxy Server.
510   * @param  searchRequest     The search request to be transformed.
511   *
512   * @return  A new search request which has been transformed as necessary, or
513   *          the original request if no transformation is required or the
514   *          provided search request has been updated in place.
515   *
516   * @throws  LDAPException  If a problem is encountered while processing the
517   *                         transformation, or if the provided request should
518   *                         not be forwarded to a backend server.
519   */
520  public SearchRequest transformSearchRequest(
521                            final ProxyOperationContext operationContext,
522                            final SearchRequest searchRequest)
523         throws LDAPException
524  {
525    return searchRequest;
526  }
527
528
529
530  /**
531   * Applies any necessary transformation to the provided search result.
532   *
533   * @param  operationContext  Information about the operation being processed
534   *                           in the Directory Proxy Server.
535   * @param  searchRequest     The search request that was processed.
536   * @param  searchResult      The search result to be transformed.
537   * @param  resultProvider    The search result provider which may be used to
538   *                           send additional search result entries and/or
539   *                           references to the client.
540   *
541   * @return  A new search result which has been transformed as necessary, or
542   *          the original result if no transformation is required or the
543   *          provided search result has been updated in place.
544   */
545  public SearchResult transformSearchResult(
546                           final ProxyOperationContext operationContext,
547                           final ReadOnlySearchRequest searchRequest,
548                           final SearchResult searchResult,
549                           final SearchResultProvider resultProvider)
550  {
551    return searchResult;
552  }
553
554
555
556  /**
557   * Applies any necessary transformation to the provided search result entry.
558   *
559   * @param  operationContext  Information about the operation being processed
560   *                           in the Directory Proxy Server.
561   * @param  searchRequest     The search request that is being processed.
562   * @param  searchEntry       The search result entry to be transformed.
563   *
564   * @return  A new search result entry which has been transformed as necessary,
565   *          the original search result entry if no transformation is required,
566   *          or {@code null} if the entry should not be returned to the client.
567   */
568  public SearchResultEntry transformSearchResultEntry(
569                                final ProxyOperationContext operationContext,
570                                final ReadOnlySearchRequest searchRequest,
571                                final SearchResultEntry searchEntry)
572  {
573    return searchEntry;
574  }
575
576
577
578  /**
579   * Applies any necessary transformation to the provided search result
580   * reference.
581   *
582   * @param  operationContext  Information about the operation being processed
583   *                           in the Directory Proxy Server.
584   * @param  searchRequest     The search request that is being processed.
585   * @param  searchReference   The search result reference to be transformed.
586   *
587   * @return  A new search result reference which has been transformed as
588   *          necessary, the original search result reference if no
589   *          transformation is required, or {@code null} if the reference
590   *          should not be returned to the client.
591   */
592  public SearchResultReference transformSearchResultReference(
593              final ProxyOperationContext operationContext,
594              final ReadOnlySearchRequest searchRequest,
595              final SearchResultReference searchReference)
596  {
597    return searchReference;
598  }
599
600
601
602  /**
603   * Retrieves a string representation of this proxy transformation.
604   *
605   * @return  A string representation of this proxy transformation.
606   */
607  @Override()
608  public final String toString()
609  {
610    final StringBuilder buffer = new StringBuilder();
611    toString(buffer);
612    return buffer.toString();
613  }
614
615
616
617  /**
618   * Appends a string representation of this proxy transformation to the
619   * provided buffer.
620   *
621   * @param  buffer  The buffer to which the string representation should be
622   *                 appended.
623   */
624  public abstract void toString(final StringBuilder buffer);
625
626
627
628  /**
629   * {@inheritDoc}
630   */
631  public Map<List<String>,String> getExamplesArgumentSets()
632  {
633    return Collections.emptyMap();
634  }
635}