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-2012 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 }