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