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