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     *      Copyright 2010-2013 UnboundID Corp.
026     */
027    package com.unboundid.directory.sdk.proxy.api;
028    
029    
030    
031    import java.util.Collections;
032    import java.util.List;
033    import java.util.Map;
034    
035    import com.unboundid.directory.sdk.common.internal.ExampleUsageProvider;
036    import com.unboundid.directory.sdk.common.internal.Reconfigurable;
037    import com.unboundid.directory.sdk.common.internal.UnboundIDExtension;
038    import com.unboundid.directory.sdk.proxy.config.ProxyTransformationConfig;
039    import com.unboundid.directory.sdk.proxy.internal.DirectoryProxyServerExtension;
040    import com.unboundid.directory.sdk.proxy.internal.SearchResultProvider;
041    import com.unboundid.directory.sdk.proxy.types.ProxyOperationContext;
042    import com.unboundid.directory.sdk.proxy.types.ProxyServerContext;
043    import com.unboundid.ldap.sdk.AddRequest;
044    import com.unboundid.ldap.sdk.BindRequest;
045    import com.unboundid.ldap.sdk.BindResult;
046    import com.unboundid.ldap.sdk.CompareRequest;
047    import com.unboundid.ldap.sdk.DeleteRequest;
048    import com.unboundid.ldap.sdk.LDAPException;
049    import com.unboundid.ldap.sdk.LDAPResult;
050    import com.unboundid.ldap.sdk.ModifyRequest;
051    import com.unboundid.ldap.sdk.ModifyDNRequest;
052    import com.unboundid.ldap.sdk.ReadOnlyAddRequest;
053    import com.unboundid.ldap.sdk.ReadOnlyCompareRequest;
054    import com.unboundid.ldap.sdk.ReadOnlyDeleteRequest;
055    import com.unboundid.ldap.sdk.ReadOnlyModifyRequest;
056    import com.unboundid.ldap.sdk.ReadOnlyModifyDNRequest;
057    import com.unboundid.ldap.sdk.ReadOnlySearchRequest;
058    import com.unboundid.ldap.sdk.ResultCode;
059    import com.unboundid.ldap.sdk.SearchRequest;
060    import com.unboundid.ldap.sdk.SearchResult;
061    import com.unboundid.ldap.sdk.SearchResultEntry;
062    import com.unboundid.ldap.sdk.SearchResultReference;
063    import com.unboundid.util.Extensible;
064    import com.unboundid.util.ThreadSafety;
065    import com.unboundid.util.ThreadSafetyLevel;
066    import com.unboundid.util.args.ArgumentException;
067    import 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)
109    public 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    }