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