001/* 002 * Copyright 2009-2024 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2009-2024 Ping Identity Corporation 007 * 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 */ 020/* 021 * Copyright (C) 2009-2024 Ping Identity Corporation 022 * 023 * This program is free software; you can redistribute it and/or modify 024 * it under the terms of the GNU General Public License (GPLv2 only) 025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 026 * as published by the Free Software Foundation. 027 * 028 * This program is distributed in the hope that it will be useful, 029 * but WITHOUT ANY WARRANTY; without even the implied warranty of 030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 031 * GNU General Public License for more details. 032 * 033 * You should have received a copy of the GNU General Public License 034 * along with this program; if not, see <http://www.gnu.org/licenses>. 035 */ 036package com.unboundid.ldap.sdk.unboundidds.tasks; 037 038 039 040import java.util.Arrays; 041import java.util.Collections; 042import java.util.Date; 043import java.util.LinkedHashMap; 044import java.util.LinkedList; 045import java.util.List; 046import java.util.Map; 047 048import com.unboundid.ldap.sdk.Attribute; 049import com.unboundid.ldap.sdk.Entry; 050import com.unboundid.ldap.sdk.Filter; 051import com.unboundid.ldap.sdk.LDAPException; 052import com.unboundid.ldap.sdk.SearchScope; 053import com.unboundid.util.Debug; 054import com.unboundid.util.NotMutable; 055import com.unboundid.util.NotNull; 056import com.unboundid.util.Nullable; 057import com.unboundid.util.StaticUtils; 058import com.unboundid.util.ThreadSafety; 059import com.unboundid.util.ThreadSafetyLevel; 060import com.unboundid.util.Validator; 061 062import static com.unboundid.ldap.sdk.unboundidds.tasks.TaskMessages.*; 063 064 065 066/** 067 * This class defines a Directory Server task that can be used to perform an 068 * internal search within the server and write the contents to an LDIF file. 069 * <BR> 070 * <BLOCKQUOTE> 071 * <B>NOTE:</B> This class, and other classes within the 072 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 073 * supported for use against Ping Identity, UnboundID, and 074 * Nokia/Alcatel-Lucent 8661 server products. These classes provide support 075 * for proprietary functionality or for external specifications that are not 076 * considered stable or mature enough to be guaranteed to work in an 077 * interoperable way with other types of LDAP servers. 078 * </BLOCKQUOTE> 079 * <BR> 080 * The properties that are available for use with this type of task include: 081 * <UL> 082 * <LI>The base DN to use for the search. This is required.</LI> 083 * <LI>The scope to use for the search. This is required.</LI> 084 * <LI>The filter to use for the search. This is required.</LI> 085 * <LI>The attributes to return. This is optional and multivalued.</LI> 086 * <LI>The authorization DN to use for the search. This is optional.</LI> 087 * <LI>The path to the output file to use. This is required.</LI> 088 * </UL> 089 */ 090@NotMutable() 091@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 092public final class SearchTask 093 extends Task 094{ 095 /** 096 * The fully-qualified name of the Java class that is used for the search 097 * task. 098 */ 099 @NotNull static final String SEARCH_TASK_CLASS = 100 "com.unboundid.directory.server.tasks.SearchTask"; 101 102 103 104 /** 105 * The name of the attribute used to specify the search base DN. 106 */ 107 @NotNull private static final String ATTR_BASE_DN = "ds-task-search-base-dn"; 108 109 110 111 /** 112 * The name of the attribute used to specify the search scope. 113 */ 114 @NotNull private static final String ATTR_SCOPE = "ds-task-search-scope"; 115 116 117 118 /** 119 * The name of the attribute used to specify the search filter. 120 */ 121 @NotNull private static final String ATTR_FILTER = "ds-task-search-filter"; 122 123 124 125 /** 126 * The name of the attribute used to specify the attribute(s) to return. 127 */ 128 @NotNull private static final String ATTR_RETURN_ATTR = 129 "ds-task-search-return-attribute"; 130 131 132 133 /** 134 * The name of the attribute used to specify the authorization DN. 135 */ 136 @NotNull private static final String ATTR_AUTHZ_DN = 137 "ds-task-search-authz-dn"; 138 139 140 141 /** 142 * The name of the attribute used to specify the output file. 143 */ 144 @NotNull private static final String ATTR_OUTPUT_FILE = 145 "ds-task-search-output-file"; 146 147 148 149 /** 150 * The name of the object class used in search task entries. 151 */ 152 @NotNull private static final String OC_SEARCH_TASK = "ds-task-search"; 153 154 155 156 /** 157 * The task property that will be used for the base DN. 158 */ 159 @NotNull private static final TaskProperty PROPERTY_BASE_DN = 160 new TaskProperty(ATTR_BASE_DN, 161 INFO_SEARCH_TASK_DISPLAY_NAME_BASE_DN.get(), 162 INFO_SEARCH_TASK_DESCRIPTION_BASE_DN.get(), String.class, true, 163 false, false); 164 165 166 167 /** 168 * The allowed values for the scope property. 169 */ 170 @NotNull private static final Object[] ALLOWED_SCOPE_VALUES = 171 { 172 "base", "baseobject", "0", 173 "one", "onelevel", "singlelevel", "1", 174 "sub", "subtree", "wholesubtree", "2", 175 "subord", "subordinate", "subordinatesubtree", "3" 176 }; 177 178 179 180 /** 181 * The task property that will be used for the scope. 182 */ 183 @NotNull private static final TaskProperty PROPERTY_SCOPE = 184 new TaskProperty(ATTR_SCOPE, 185 INFO_SEARCH_TASK_DISPLAY_NAME_SCOPE.get(), 186 INFO_SEARCH_TASK_DESCRIPTION_SCOPE.get(), String.class, true, 187 false, false, ALLOWED_SCOPE_VALUES); 188 189 190 191 /** 192 * The task property that will be used for the filter. 193 */ 194 @NotNull private static final TaskProperty PROPERTY_FILTER = 195 new TaskProperty(ATTR_FILTER, 196 INFO_SEARCH_TASK_DISPLAY_NAME_FILTER.get(), 197 INFO_SEARCH_TASK_DESCRIPTION_FILTER.get(), String.class, true, 198 false, false); 199 200 201 202 /** 203 * The task property that will be used for the requested attributes. 204 */ 205 @NotNull private static final TaskProperty PROPERTY_REQUESTED_ATTR = 206 new TaskProperty(ATTR_RETURN_ATTR, 207 INFO_SEARCH_TASK_DISPLAY_NAME_RETURN_ATTR.get(), 208 INFO_SEARCH_TASK_DESCRIPTION_RETURN_ATTR.get(), String.class, false, 209 true, false); 210 211 212 213 /** 214 * The task property that will be used for the authorization DN. 215 */ 216 @NotNull private static final TaskProperty PROPERTY_AUTHZ_DN = 217 new TaskProperty(ATTR_AUTHZ_DN, 218 INFO_SEARCH_TASK_DISPLAY_NAME_AUTHZ_DN.get(), 219 INFO_SEARCH_TASK_DESCRIPTION_AUTHZ_DN.get(), String.class, false, 220 false, true); 221 222 223 224 /** 225 * The task property that will be used for the output file. 226 */ 227 @NotNull private static final TaskProperty PROPERTY_OUTPUT_FILE = 228 new TaskProperty(ATTR_OUTPUT_FILE, 229 INFO_SEARCH_TASK_DISPLAY_NAME_OUTPUT_FILE.get(), 230 INFO_SEARCH_TASK_DESCRIPTION_NAME_OUTPUT_FILE.get(), String.class, 231 true, false, false); 232 233 234 235 /** 236 * The serial version UID for this serializable class. 237 */ 238 private static final long serialVersionUID = -1742374271508548328L; 239 240 241 242 // The search filter. 243 @NotNull private final Filter filter; 244 245 // The list of attributes to return. 246 @NotNull private final List<String> attributes; 247 248 // The search scope. 249 @NotNull private final SearchScope scope; 250 251 // The authorization DN. 252 @Nullable private final String authzDN; 253 254 // The search base DN. 255 @NotNull private final String baseDN; 256 257 // The output file path. 258 @NotNull private final String outputFile; 259 260 261 262 /** 263 * Creates a new uninitialized search task instance which should only be used 264 * for obtaining general information about this task, including the task name, 265 * description, and supported properties. Attempts to use a task created with 266 * this constructor for any other reason will likely fail. 267 */ 268 public SearchTask() 269 { 270 filter = null; 271 attributes = null; 272 scope = null; 273 authzDN = null; 274 baseDN = null; 275 outputFile = null; 276 } 277 278 279 280 /** 281 * Creates a new search task with the provided information. 282 * 283 * @param taskID The task ID to use for this task. If it is 284 * {@code null} then a UUID will be generated for use as 285 * the task ID. 286 * @param baseDN The base DN to use for the search. It must not be 287 * {@code null}. 288 * @param scope The scope to use for the search. It must not be 289 * {@code null}. 290 * @param filter The filter to use for the search. It must not be 291 * {@code null}. 292 * @param attributes The list of attributes to include in matching entries. 293 * If it is {@code null} or empty, then all user 294 * attributes will be selected. 295 * @param outputFile The path to the file (on the server filesystem) to 296 * which the results should be written. It must not be 297 * {@code null}. 298 */ 299 public SearchTask(@Nullable final String taskID, 300 @NotNull final String baseDN, 301 @NotNull final SearchScope scope, 302 @NotNull final Filter filter, 303 @Nullable final List<String> attributes, 304 @NotNull final String outputFile) 305 { 306 this(taskID, baseDN, scope, filter, attributes, outputFile, null, null, 307 null, null, null, null); 308 } 309 310 311 312 /** 313 * Creates a new search task with the provided information. 314 * 315 * @param taskID The task ID to use for this task. If it is 316 * {@code null} then a UUID will be generated for use as 317 * the task ID. 318 * @param baseDN The base DN to use for the search. It must not be 319 * {@code null}. 320 * @param scope The scope to use for the search. It must not be 321 * {@code null}. 322 * @param filter The filter to use for the search. It must not be 323 * {@code null}. 324 * @param attributes The list of attributes to include in matching entries. 325 * If it is {@code null} or empty, then all user 326 * attributes will be selected. 327 * @param outputFile The path to the file (on the server filesystem) to 328 * which the results should be written. It must not be 329 * {@code null}. 330 * @param authzDN The DN of the user as whom the search should be 331 * processed. If this is {@code null}, then it will be 332 * processed as an internal root user. 333 */ 334 public SearchTask(@Nullable final String taskID, 335 @NotNull final String baseDN, 336 @NotNull final SearchScope scope, 337 @NotNull final Filter filter, 338 @Nullable final List<String> attributes, 339 @NotNull final String outputFile, 340 @Nullable final String authzDN) 341 { 342 this(taskID, baseDN, scope, filter, attributes, outputFile, authzDN, null, 343 null, null, null, null); 344 } 345 346 347 348 /** 349 * Creates a new search task with the provided information. 350 * 351 * @param taskID The task ID to use for this task. If it is 352 * {@code null} then a UUID will be generated 353 * for use as the task ID. 354 * @param baseDN The base DN to use for the search. It must 355 * not be {@code null}. 356 * @param scope The scope to use for the search. It must 357 * not be {@code null}. 358 * @param filter The filter to use for the search. It must 359 * not be {@code null}. 360 * @param attributes The list of attributes to include in 361 * matching entries. If it is {@code null} or 362 * empty, then all user attributes will be 363 * selected. 364 * @param outputFile The path to the file (on the server 365 * filesystem) to which the results should be 366 * written. It must not be {@code null}. 367 * @param authzDN The DN of the user as whom the search 368 * should be processed. If this is 369 * {@code null}, then it will be processed as 370 * an internal root user. 371 * @param scheduledStartTime The time that this task should start 372 * running. 373 * @param dependencyIDs The list of task IDs that will be required 374 * to complete before this task will be 375 * eligible to start. 376 * @param failedDependencyAction Indicates what action should be taken if 377 * any of the dependencies for this task do 378 * not complete successfully. 379 * @param notifyOnCompletion The list of e-mail addresses of individuals 380 * that should be notified when this task 381 * completes. 382 * @param notifyOnError The list of e-mail addresses of individuals 383 * that should be notified if this task does 384 * not complete successfully. 385 */ 386 public SearchTask(@Nullable final String taskID, 387 @NotNull final String baseDN, 388 @NotNull final SearchScope scope, 389 @NotNull final Filter filter, 390 @Nullable final List<String> attributes, 391 @NotNull final String outputFile, 392 @Nullable final String authzDN, 393 @Nullable final Date scheduledStartTime, 394 @Nullable final List<String> dependencyIDs, 395 @Nullable final FailedDependencyAction failedDependencyAction, 396 @Nullable final List<String> notifyOnCompletion, 397 @Nullable final List<String> notifyOnError) 398 { 399 this(taskID, baseDN, scope, filter, attributes, outputFile, authzDN, 400 scheduledStartTime, dependencyIDs, failedDependencyAction, null, 401 notifyOnCompletion, null, notifyOnError, null, null, null); 402 } 403 404 405 406 /** 407 * Creates a new search task with the provided information. 408 * 409 * @param taskID The task ID to use for this task. If it is 410 * {@code null} then a UUID will be generated 411 * for use as the task ID. 412 * @param baseDN The base DN to use for the search. It must 413 * not be {@code null}. 414 * @param scope The scope to use for the search. It must 415 * not be {@code null}. 416 * @param filter The filter to use for the search. It must 417 * not be {@code null}. 418 * @param attributes The list of attributes to include in 419 * matching entries. If it is {@code null} or 420 * empty, then all user attributes will be 421 * selected. 422 * @param outputFile The path to the file (on the server 423 * filesystem) to which the results should be 424 * written. It must not be {@code null}. 425 * @param authzDN The DN of the user as whom the search 426 * should be processed. If this is 427 * {@code null}, then it will be processed as 428 * an internal root user. 429 * @param scheduledStartTime The time that this task should start 430 * running. 431 * @param dependencyIDs The list of task IDs that will be required 432 * to complete before this task will be 433 * eligible to start. 434 * @param failedDependencyAction Indicates what action should be taken if 435 * any of the dependencies for this task do 436 * not complete successfully. 437 * @param notifyOnStart The list of e-mail addresses of individuals 438 * that should be notified when this task 439 * starts running. 440 * @param notifyOnCompletion The list of e-mail addresses of individuals 441 * that should be notified when this task 442 * completes. 443 * @param notifyOnSuccess The list of e-mail addresses of individuals 444 * that should be notified if this task 445 * completes successfully. 446 * @param notifyOnError The list of e-mail addresses of individuals 447 * that should be notified if this task does 448 * not complete successfully. 449 * @param alertOnStart Indicates whether the server should send an 450 * alert notification when this task starts. 451 * @param alertOnSuccess Indicates whether the server should send an 452 * alert notification if this task completes 453 * successfully. 454 * @param alertOnError Indicates whether the server should send an 455 * alert notification if this task fails to 456 * complete successfully. 457 */ 458 public SearchTask(@Nullable final String taskID, 459 @NotNull final String baseDN, 460 @NotNull final SearchScope scope, 461 @NotNull final Filter filter, 462 @Nullable final List<String> attributes, 463 @NotNull final String outputFile, 464 @Nullable final String authzDN, 465 @Nullable final Date scheduledStartTime, 466 @Nullable final List<String> dependencyIDs, 467 @Nullable final FailedDependencyAction failedDependencyAction, 468 @Nullable final List<String> notifyOnStart, 469 @Nullable final List<String> notifyOnCompletion, 470 @Nullable final List<String> notifyOnSuccess, 471 @Nullable final List<String> notifyOnError, 472 @Nullable final Boolean alertOnStart, 473 @Nullable final Boolean alertOnSuccess, 474 @Nullable final Boolean alertOnError) 475 { 476 super(taskID, SEARCH_TASK_CLASS, scheduledStartTime, dependencyIDs, 477 failedDependencyAction, notifyOnStart, notifyOnCompletion, 478 notifyOnSuccess, notifyOnError, alertOnStart, alertOnSuccess, 479 alertOnError); 480 481 Validator.ensureNotNull(baseDN, scope, filter, outputFile); 482 483 this.baseDN = baseDN; 484 this.scope = scope; 485 this.filter = filter; 486 this.outputFile = outputFile; 487 this.authzDN = authzDN; 488 489 if (attributes == null) 490 { 491 this.attributes = Collections.emptyList(); 492 } 493 else 494 { 495 this.attributes = Collections.unmodifiableList(attributes); 496 } 497 } 498 499 500 501 /** 502 * Creates a new search task from the provided entry. 503 * 504 * @param entry The entry to use to create this search task. 505 * 506 * @throws TaskException If the provided entry cannot be parsed as a search 507 * task entry. 508 */ 509 public SearchTask(@NotNull final Entry entry) 510 throws TaskException 511 { 512 super(entry); 513 514 515 // Get the base DN. It must be present. 516 baseDN = entry.getAttributeValue(ATTR_BASE_DN); 517 if (baseDN == null) 518 { 519 throw new TaskException(ERR_SEARCH_TASK_ENTRY_NO_BASE_DN.get( 520 entry.getDN())); 521 } 522 523 524 // Get the scope. It must be present. 525 final String scopeStr = 526 StaticUtils.toLowerCase(entry.getAttributeValue(ATTR_SCOPE)); 527 if (scopeStr == null) 528 { 529 throw new TaskException(ERR_SEARCH_TASK_ENTRY_NO_SCOPE.get( 530 entry.getDN())); 531 } 532 533 if (scopeStr.equals("base") || scopeStr.equals("baseobject") || 534 scopeStr.equals("0")) 535 { 536 scope = SearchScope.BASE; 537 } 538 else if (scopeStr.equals("one") || scopeStr.equals("onelevel") || 539 scopeStr.equals("singlelevel") || scopeStr.equals("1")) 540 { 541 scope = SearchScope.ONE; 542 } 543 else if (scopeStr.equals("sub") || scopeStr.equals("subtree") || 544 scopeStr.equals("wholesubtree") || scopeStr.equals("2")) 545 { 546 scope = SearchScope.SUB; 547 } 548 else if (scopeStr.equals("subord") || scopeStr.equals("subordinate") || 549 scopeStr.equals("subordinatesubtree") || scopeStr.equals("3")) 550 { 551 scope = SearchScope.SUBORDINATE_SUBTREE; 552 } 553 else 554 { 555 throw new TaskException(ERR_SEARCH_TASK_ENTRY_INVALID_SCOPE.get( 556 entry.getDN(), scopeStr)); 557 } 558 559 560 // Get the filter. It must be present. 561 final String filterStr = entry.getAttributeValue(ATTR_FILTER); 562 if (filterStr == null) 563 { 564 throw new TaskException(ERR_SEARCH_TASK_ENTRY_NO_FILTER.get( 565 entry.getDN())); 566 } 567 try 568 { 569 filter = Filter.create(filterStr); 570 } 571 catch (final LDAPException le) 572 { 573 Debug.debugException(le); 574 throw new TaskException(ERR_SEARCH_TASK_ENTRY_INVALID_FILTER.get( 575 entry.getDN(), filterStr), le); 576 } 577 578 579 // Get the list of requested attributes. It is optional. 580 final String[] attrs = entry.getAttributeValues(ATTR_RETURN_ATTR); 581 if (attrs == null) 582 { 583 attributes = Collections.emptyList(); 584 } 585 else 586 { 587 attributes = Collections.unmodifiableList(Arrays.asList(attrs)); 588 } 589 590 591 // Get the authorization DN. It is optional. 592 authzDN = entry.getAttributeValue(ATTR_AUTHZ_DN); 593 594 595 // Get the path to the output file. It must be present. 596 outputFile = entry.getAttributeValue(ATTR_OUTPUT_FILE); 597 if (outputFile == null) 598 { 599 throw new TaskException(ERR_SEARCH_TASK_ENTRY_NO_OUTPUT_FILE.get( 600 entry.getDN())); 601 } 602 } 603 604 605 606 /** 607 * Creates a new search task from the provided set of task properties. 608 * 609 * @param properties The set of task properties and their corresponding 610 * values to use for the task. It must not be 611 * {@code null}. 612 * 613 * @throws TaskException If the provided set of properties cannot be used to 614 * create a valid add schema file task. 615 */ 616 public SearchTask(@NotNull final Map<TaskProperty,List<Object>> properties) 617 throws TaskException 618 { 619 super(SEARCH_TASK_CLASS, properties); 620 621 Filter tmpFilter = null; 622 SearchScope tmpScope = null; 623 String tmpAuthzDN = null; 624 String tmpBaseDN = null; 625 String tmpFile = null; 626 String[] tmpAttrs = null; 627 628 for (final Map.Entry<TaskProperty,List<Object>> entry : 629 properties.entrySet()) 630 { 631 final TaskProperty p = entry.getKey(); 632 final String attrName = StaticUtils.toLowerCase(p.getAttributeName()); 633 final List<Object> values = entry.getValue(); 634 635 if (attrName.equals(ATTR_BASE_DN)) 636 { 637 tmpBaseDN = parseString(p, values, null); 638 } 639 else if (attrName.equals(ATTR_SCOPE)) 640 { 641 final String scopeStr = 642 StaticUtils.toLowerCase(parseString(p, values, null)); 643 if (scopeStr != null) 644 { 645 if (scopeStr.equals("base") || scopeStr.equals("baseobject") || 646 scopeStr.equals("0")) 647 { 648 tmpScope = SearchScope.BASE; 649 } 650 else if (scopeStr.equals("one") || scopeStr.equals("onelevel") || 651 scopeStr.equals("singlelevel") || scopeStr.equals("1")) 652 { 653 tmpScope = SearchScope.ONE; 654 } 655 else if (scopeStr.equals("sub") || scopeStr.equals("subtree") || 656 scopeStr.equals("wholesubtree") || scopeStr.equals("2")) 657 { 658 tmpScope = SearchScope.SUB; 659 } 660 else if (scopeStr.equals("subord") || 661 scopeStr.equals("subordinate") || 662 scopeStr.equals("subordinatesubtree") || 663 scopeStr.equals("3")) 664 { 665 tmpScope = SearchScope.SUBORDINATE_SUBTREE; 666 } 667 else 668 { 669 throw new TaskException(ERR_SEARCH_TASK_INVALID_SCOPE_PROPERTY.get( 670 scopeStr)); 671 } 672 } 673 } 674 else if (attrName.equals(ATTR_FILTER)) 675 { 676 final String filterStr = parseString(p, values, null); 677 if (filterStr != null) 678 { 679 try 680 { 681 tmpFilter = Filter.create(filterStr); 682 } 683 catch (final LDAPException le) 684 { 685 Debug.debugException(le); 686 throw new TaskException(ERR_SEARCH_TASK_INVALID_FILTER_PROPERTY.get( 687 filterStr), le); 688 } 689 } 690 } 691 else if (attrName.equals(ATTR_RETURN_ATTR)) 692 { 693 tmpAttrs = parseStrings(p, values, null); 694 } 695 else if (attrName.equals(ATTR_OUTPUT_FILE)) 696 { 697 tmpFile = parseString(p, values, null); 698 } 699 else if (attrName.equals(ATTR_AUTHZ_DN)) 700 { 701 tmpAuthzDN = parseString(p, values, null); 702 } 703 } 704 705 baseDN = tmpBaseDN; 706 if (baseDN == null) 707 { 708 throw new TaskException(ERR_SEARCH_TASK_NO_BASE_PROPERTY.get()); 709 } 710 711 scope = tmpScope; 712 if (scope == null) 713 { 714 throw new TaskException(ERR_SEARCH_TASK_NO_SCOPE_PROPERTY.get()); 715 } 716 717 filter = tmpFilter; 718 if (filter == null) 719 { 720 throw new TaskException(ERR_SEARCH_TASK_NO_FILTER_PROPERTY.get()); 721 } 722 723 outputFile = tmpFile; 724 if (outputFile == null) 725 { 726 throw new TaskException(ERR_SEARCH_TASK_NO_OUTPUT_FILE_PROPERTY.get()); 727 } 728 729 730 if (tmpAttrs == null) 731 { 732 attributes = Collections.emptyList(); 733 } 734 else 735 { 736 attributes = Collections.unmodifiableList(Arrays.asList(tmpAttrs)); 737 } 738 739 authzDN = tmpAuthzDN; 740 } 741 742 743 744 /** 745 * {@inheritDoc} 746 */ 747 @Override() 748 @NotNull() 749 public String getTaskName() 750 { 751 return INFO_TASK_NAME_SEARCH.get(); 752 } 753 754 755 756 /** 757 * {@inheritDoc} 758 */ 759 @Override() 760 @NotNull() 761 public String getTaskDescription() 762 { 763 return INFO_TASK_DESCRIPTION_SEARCH.get(); 764 } 765 766 767 768 /** 769 * Retrieves the base DN for the search. 770 * 771 * @return The base DN for the search. 772 */ 773 @NotNull() 774 public String getBaseDN() 775 { 776 return baseDN; 777 } 778 779 780 781 /** 782 * Retrieves the scope for the search. 783 * 784 * @return The scope for the search. 785 */ 786 @NotNull() 787 public SearchScope getScope() 788 { 789 return scope; 790 } 791 792 793 794 /** 795 * Retrieves the filter for the search. 796 * 797 * @return The filter for the search. 798 */ 799 @NotNull() 800 public Filter getFilter() 801 { 802 return filter; 803 } 804 805 806 807 /** 808 * Retrieves the list of attributes to include in matching entries. 809 * 810 * @return The list of attributes to include in matching entries, or an 811 * empty list of all user attributes should be requested. 812 */ 813 @NotNull() 814 public List<String> getAttributes() 815 { 816 return attributes; 817 } 818 819 820 821 /** 822 * Retrieves the DN of the user as whom the request should be processed. 823 * 824 * @return The DN of the user as whom the request should be processed, or 825 * {@code null} if it should be processed as an internal root user. 826 */ 827 @Nullable() 828 public String getAuthzDN() 829 { 830 return authzDN; 831 } 832 833 834 835 /** 836 * Retrieves the path to the file on the server filesystem to which the 837 * results should be written. 838 * 839 * @return The path to the file on the server filesystem to which the results 840 * should be written. 841 */ 842 @NotNull() 843 public String getOutputFile() 844 { 845 return outputFile; 846 } 847 848 849 850 /** 851 * {@inheritDoc} 852 */ 853 @Override() 854 @NotNull() 855 protected List<String> getAdditionalObjectClasses() 856 { 857 return Collections.singletonList(OC_SEARCH_TASK); 858 } 859 860 861 862 /** 863 * {@inheritDoc} 864 */ 865 @Override() 866 @NotNull() 867 protected List<Attribute> getAdditionalAttributes() 868 { 869 final LinkedList<Attribute> attrs = new LinkedList<>(); 870 871 attrs.add(new Attribute(ATTR_BASE_DN, baseDN)); 872 attrs.add(new Attribute(ATTR_SCOPE, String.valueOf(scope.intValue()))); 873 attrs.add(new Attribute(ATTR_FILTER, filter.toString())); 874 attrs.add(new Attribute(ATTR_OUTPUT_FILE, outputFile)); 875 876 if ((attributes != null) && (! attributes.isEmpty())) 877 { 878 attrs.add(new Attribute(ATTR_RETURN_ATTR, attributes)); 879 } 880 881 if (authzDN != null) 882 { 883 attrs.add(new Attribute(ATTR_AUTHZ_DN, authzDN)); 884 } 885 886 return Collections.unmodifiableList(attrs); 887 } 888 889 890 891 /** 892 * {@inheritDoc} 893 */ 894 @Override() 895 @NotNull() 896 public List<TaskProperty> getTaskSpecificProperties() 897 { 898 final LinkedList<TaskProperty> props = new LinkedList<>(); 899 900 props.add(PROPERTY_BASE_DN); 901 props.add(PROPERTY_SCOPE); 902 props.add(PROPERTY_FILTER); 903 props.add(PROPERTY_REQUESTED_ATTR); 904 props.add(PROPERTY_AUTHZ_DN); 905 props.add(PROPERTY_OUTPUT_FILE); 906 907 return Collections.unmodifiableList(props); 908 } 909 910 911 912 /** 913 * {@inheritDoc} 914 */ 915 @Override() 916 @NotNull() 917 public Map<TaskProperty,List<Object>> getTaskPropertyValues() 918 { 919 final LinkedHashMap<TaskProperty,List<Object>> props = 920 new LinkedHashMap<>(StaticUtils.computeMapCapacity(6)); 921 922 props.put(PROPERTY_BASE_DN, 923 Collections.<Object>singletonList(baseDN)); 924 925 props.put(PROPERTY_SCOPE, 926 Collections.<Object>singletonList(String.valueOf(scope.intValue()))); 927 928 props.put(PROPERTY_FILTER, 929 Collections.<Object>singletonList(filter.toString())); 930 931 if ((attributes != null) && (! attributes.isEmpty())) 932 { 933 final LinkedList<Object> attrObjects = new LinkedList<>(); 934 attrObjects.addAll(attributes); 935 936 props.put(PROPERTY_REQUESTED_ATTR, 937 Collections.unmodifiableList(attrObjects)); 938 } 939 940 if (authzDN != null) 941 { 942 props.put(PROPERTY_AUTHZ_DN, 943 Collections.<Object>singletonList(authzDN)); 944 } 945 946 props.put(PROPERTY_OUTPUT_FILE, 947 Collections.<Object>singletonList(outputFile)); 948 949 props.putAll(super.getTaskPropertyValues()); 950 return Collections.unmodifiableMap(props); 951 } 952}