001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2006-2009 Sun Microsystems, Inc. 015 * Portions Copyright 2012-2016 ForgeRock AS. 016 */ 017package org.opends.server.tools; 018 019import static org.opends.messages.ToolMessages.*; 020import static org.opends.server.config.ConfigConstants.*; 021import static org.opends.server.util.StaticUtils.*; 022import static com.forgerock.opendj.cli.ArgumentConstants.*; 023import static com.forgerock.opendj.cli.CommonArguments.*; 024import static com.forgerock.opendj.cli.Utils.*; 025 026import java.io.OutputStream; 027import java.io.PrintStream; 028import java.util.ArrayList; 029import java.util.HashSet; 030import java.util.List; 031import java.util.Set; 032 033import org.forgerock.i18n.slf4j.LocalizedLogger; 034import org.forgerock.opendj.ldap.DN; 035import org.forgerock.opendj.ldap.schema.AttributeType; 036import org.forgerock.opendj.server.config.server.BackendCfg; 037import org.opends.server.api.Backend; 038import org.opends.server.api.Backend.BackendOperation; 039import org.opends.server.api.plugin.PluginType; 040import org.opends.server.core.DirectoryServer; 041import org.opends.server.core.LockFileManager; 042import org.opends.server.loggers.JDKLogging; 043import org.opends.server.protocols.ldap.LDAPAttribute; 044import org.opends.server.tasks.ExportTask; 045import org.opends.server.tools.tasks.TaskTool; 046import org.opends.server.types.DirectoryException; 047import org.opends.server.types.ExistingFileBehavior; 048import org.opends.server.types.InitializationException; 049import org.opends.server.types.LDIFExportConfig; 050import org.opends.server.types.NullOutputStream; 051import org.opends.server.types.RawAttribute; 052import org.opends.server.types.SearchFilter; 053import org.opends.server.util.cli.LDAPConnectionArgumentParser; 054 055import com.forgerock.opendj.cli.Argument; 056import com.forgerock.opendj.cli.ArgumentException; 057import com.forgerock.opendj.cli.BooleanArgument; 058import com.forgerock.opendj.cli.ClientException; 059import com.forgerock.opendj.cli.IntegerArgument; 060import com.forgerock.opendj.cli.StringArgument; 061 062/** 063 * This program provides a utility that may be used to export the contents of a 064 * Directory Server backend to an LDIF file. Depending on the arguments given, 065 * this program will either perform the export directly as a process that 066 * runs separate from Directory Server; or by scheduling a task to perform the 067 * action within the Directory Server via the tasks interface. 068 */ 069public class ExportLDIF extends TaskTool { 070 071 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 072 073 /** 074 * The main method for ExportLDIF tool. 075 * 076 * @param args The command-line arguments provided to this program. 077 */ 078 public static void main(String[] args) 079 { 080 int retCode = mainExportLDIF(args, true, System.out, System.err); 081 if(retCode != 0) 082 { 083 System.exit(filterExitCode(retCode)); 084 } 085 } 086 087 /** 088 * Processes the command-line arguments and invokes the export process. 089 * 090 * @param args The command-line arguments provided to this 091 * program. 092 * @param initializeServer Indicates whether to initialize the server. 093 * @param outStream The output stream to use for standard output, or 094 * {@code null} if standard output is not needed. 095 * @param errStream The output stream to use for standard error, or 096 * {@code null} if standard error is not needed. 097 * 098 * @return The error code. 099 */ 100 public static int mainExportLDIF(String[] args, boolean initializeServer, 101 OutputStream outStream, 102 OutputStream errStream) 103 { 104 ExportLDIF tool = new ExportLDIF(); 105 return tool.process(args, initializeServer, outStream, errStream); 106 } 107 108 /** Define the command-line arguments that may be used with this program. */ 109 private BooleanArgument appendToLDIF; 110 private BooleanArgument compressLDIF; 111 private BooleanArgument displayUsage; 112 private BooleanArgument encryptLDIF; 113 private BooleanArgument excludeOperationalAttrs; 114 private BooleanArgument signHash; 115 private IntegerArgument wrapColumn; 116 private StringArgument backendID; 117 private StringArgument configFile; 118 private StringArgument excludeAttributeStrings; 119 private StringArgument excludeBranchStrings; 120 private StringArgument excludeFilterStrings; 121 private StringArgument includeAttributeStrings; 122 private StringArgument includeBranchStrings; 123 private StringArgument includeFilterStrings; 124 private StringArgument ldifFile; 125 126 private int process(String[] args, boolean initializeServer, 127 OutputStream outStream, OutputStream errStream) { 128 129 PrintStream out = NullOutputStream.wrapOrNullStream(outStream); 130 PrintStream err = NullOutputStream.wrapOrNullStream(errStream); 131 JDKLogging.disableLogging(); 132 133 // Create the command-line argument parser for use with this program. 134 LDAPConnectionArgumentParser argParser = 135 createArgParser("org.opends.server.tools.ExportLDIF", 136 INFO_LDIFEXPORT_TOOL_DESCRIPTION.get()); 137 argParser.setShortToolDescription(REF_SHORT_DESC_EXPORT_LDIF.get()); 138 139 140 // Initialize all the command-line argument types and register them with the parser. 141 try 142 { 143 configFile = 144 StringArgument.builder("configFile") 145 .shortIdentifier('f') 146 .description(INFO_DESCRIPTION_CONFIG_FILE.get()) 147 .hidden() 148 .required() 149 .valuePlaceholder(INFO_CONFIGFILE_PLACEHOLDER.get()) 150 .buildAndAddToParser(argParser); 151 ldifFile = 152 StringArgument.builder(OPTION_LONG_LDIF_FILE) 153 .shortIdentifier(OPTION_SHORT_LDIF_FILE) 154 .description(INFO_LDIFEXPORT_DESCRIPTION_LDIF_FILE.get()) 155 .required() 156 .valuePlaceholder(INFO_LDIFFILE_PLACEHOLDER.get()) 157 .buildAndAddToParser(argParser); 158 appendToLDIF = 159 BooleanArgument.builder("appendToLDIF") 160 .shortIdentifier('a') 161 .description(INFO_LDIFEXPORT_DESCRIPTION_APPEND_TO_LDIF.get()) 162 .buildAndAddToParser(argParser); 163 backendID = 164 StringArgument.builder("backendID") 165 .shortIdentifier('n') 166 .description(INFO_LDIFEXPORT_DESCRIPTION_BACKEND_ID.get()) 167 .required() 168 .valuePlaceholder(INFO_BACKENDNAME_PLACEHOLDER.get()) 169 .buildAndAddToParser(argParser); 170 includeBranchStrings = 171 StringArgument.builder("includeBranch") 172 .shortIdentifier('b') 173 .description(INFO_LDIFEXPORT_DESCRIPTION_INCLUDE_BRANCH.get()) 174 .multiValued() 175 .valuePlaceholder(INFO_BRANCH_DN_PLACEHOLDER.get()) 176 .buildAndAddToParser(argParser); 177 excludeBranchStrings = 178 StringArgument.builder("excludeBranch") 179 .shortIdentifier('B') 180 .description(INFO_LDIFEXPORT_DESCRIPTION_EXCLUDE_BRANCH.get()) 181 .multiValued() 182 .valuePlaceholder(INFO_BRANCH_DN_PLACEHOLDER.get()) 183 .buildAndAddToParser(argParser); 184 includeAttributeStrings = 185 StringArgument.builder("includeAttribute") 186 .shortIdentifier('i') 187 .description(INFO_LDIFEXPORT_DESCRIPTION_INCLUDE_ATTRIBUTE.get()) 188 .multiValued() 189 .valuePlaceholder(INFO_ATTRIBUTE_PLACEHOLDER.get()) 190 .buildAndAddToParser(argParser); 191 excludeAttributeStrings = 192 StringArgument.builder("excludeAttribute") 193 .shortIdentifier('e') 194 .description(INFO_LDIFEXPORT_DESCRIPTION_EXCLUDE_ATTRIBUTE.get()) 195 .multiValued() 196 .valuePlaceholder(INFO_ATTRIBUTE_PLACEHOLDER.get()) 197 .buildAndAddToParser(argParser); 198 includeFilterStrings = 199 StringArgument.builder("includeFilter") 200 .shortIdentifier('I') 201 .description(INFO_LDIFEXPORT_DESCRIPTION_INCLUDE_FILTER.get()) 202 .multiValued() 203 .valuePlaceholder(INFO_FILTER_PLACEHOLDER.get()) 204 .buildAndAddToParser(argParser); 205 excludeFilterStrings = 206 StringArgument.builder("excludeFilter") 207 .shortIdentifier('E') 208 .description(INFO_LDIFEXPORT_DESCRIPTION_EXCLUDE_FILTER.get()) 209 .multiValued() 210 .valuePlaceholder(INFO_FILTER_PLACEHOLDER.get()) 211 .buildAndAddToParser(argParser); 212 excludeOperationalAttrs = 213 BooleanArgument.builder("excludeOperational") 214 .shortIdentifier('O') 215 .description(INFO_LDIFEXPORT_DESCRIPTION_EXCLUDE_OPERATIONAL.get()) 216 .buildAndAddToParser(argParser); 217 wrapColumn = 218 IntegerArgument.builder("wrapColumn") 219 .description(INFO_LDIFEXPORT_DESCRIPTION_WRAP_COLUMN.get()) 220 .lowerBound(0) 221 .defaultValue(0) 222 .valuePlaceholder(INFO_WRAP_COLUMN_PLACEHOLDER.get()) 223 .buildAndAddToParser(argParser); 224 compressLDIF = 225 BooleanArgument.builder(OPTION_LONG_COMPRESS) 226 .shortIdentifier(OPTION_SHORT_COMPRESS) 227 .description(INFO_LDIFEXPORT_DESCRIPTION_COMPRESS_LDIF.get()) 228 .buildAndAddToParser(argParser); 229 encryptLDIF = 230 BooleanArgument.builder("encryptLDIF") 231 .shortIdentifier('y') 232 .description(INFO_LDIFEXPORT_DESCRIPTION_ENCRYPT_LDIF.get()) 233 .hidden() // See issue OPENDJ-448 234 .buildAndAddToParser(argParser); 235 signHash = 236 BooleanArgument.builder("signHash") 237 .shortIdentifier('s') 238 .description(INFO_LDIFEXPORT_DESCRIPTION_SIGN_HASH.get()) 239 .hidden() // See issue OPENDJ-448 240 .buildAndAddToParser(argParser); 241 242 displayUsage = showUsageArgument(); 243 argParser.addArgument(displayUsage); 244 argParser.setUsageArgument(displayUsage); 245 } 246 catch (ArgumentException ae) 247 { 248 printWrappedText(err, ERR_CANNOT_INITIALIZE_ARGS.get(ae.getMessage())); 249 return 1; 250 } 251 252 253 // Init the default values so that they can appear also on the usage. 254 argParser.getArguments().initArgumentsWithConfiguration(argParser); 255 256 // Parse the command-line arguments provided to this program. 257 try 258 { 259 argParser.parseArguments(args); 260 validateTaskArgs(); 261 } 262 catch (ArgumentException ae) 263 { 264 argParser.displayMessageAndUsageReference(err, ERR_ERROR_PARSING_ARGS.get(ae.getMessage())); 265 return 1; 266 } 267 catch (ClientException ce) 268 { 269 // No need to display the usage since the problem comes with a provided value. 270 printWrappedText(err, ce.getMessageObject()); 271 return 1; 272 } 273 274 275 // If we should just display usage or version information, 276 // then print it and exit. 277 if (argParser.usageOrVersionDisplayed()) 278 { 279 return 0; 280 } 281 282 // Checks the version - if upgrade required, the tool is unusable 283 try 284 { 285 checkVersion(); 286 } 287 catch (InitializationException e) 288 { 289 printWrappedText(err, e.getMessage()); 290 return 1; 291 } 292 293 return process(argParser, initializeServer, out, err); 294 } 295 296 @Override 297 public void addTaskAttributes(List<RawAttribute> attributes) 298 { 299 // Required attributes 300 attributes.add(new LDAPAttribute(ATTR_TASK_EXPORT_LDIF_FILE, ldifFile.getValue())); 301 attributes.add(new LDAPAttribute(ATTR_TASK_EXPORT_BACKEND_ID, backendID.getValue())); 302 303 // Optional attributes 304 addAttribute(attributes, ATTR_TASK_EXPORT_APPEND_TO_LDIF, appendToLDIF); 305 addAttribute(attributes, ATTR_TASK_EXPORT_COMPRESS_LDIF, compressLDIF); 306 addAttribute(attributes, ATTR_TASK_EXPORT_ENCRYPT_LDIF, encryptLDIF); 307 addAttribute(attributes, ATTR_TASK_EXPORT_SIGN_HASH, signHash); 308 addAttribute(attributes, ATTR_TASK_EXPORT_INCLUDE_ATTRIBUTE, includeAttributeStrings.getValues()); 309 addAttribute(attributes, ATTR_TASK_EXPORT_EXCLUDE_ATTRIBUTE, excludeAttributeStrings.getValues()); 310 addAttribute(attributes, ATTR_TASK_EXPORT_INCLUDE_FILTER, includeFilterStrings.getValues()); 311 addAttribute(attributes, ATTR_TASK_EXPORT_EXCLUDE_FILTER, excludeFilterStrings.getValues()); 312 addAttribute(attributes, ATTR_TASK_EXPORT_INCLUDE_BRANCH, includeBranchStrings.getValues()); 313 addAttribute(attributes, ATTR_TASK_EXPORT_EXCLUDE_BRANCH, excludeBranchStrings.getValues()); 314 addAttribute(attributes, ATTR_TASK_EXPORT_WRAP_COLUMN, wrapColumn); 315 316 if (excludeOperationalAttrs.isPresent()) 317 { 318 attributes.add( 319 new LDAPAttribute(ATTR_TASK_EXPORT_INCLUDE_OPERATIONAL_ATTRIBUTES, "false")); 320 } 321 } 322 323 private void addAttribute(List<RawAttribute> attributes, String attrName, Argument arg) 324 { 325 if (arg.getValue() != null && !arg.getValue().equals(arg.getDefaultValue())) 326 { 327 attributes.add(new LDAPAttribute(attrName, arg.getValue())); 328 } 329 } 330 331 private void addAttribute(List<RawAttribute> attributes, String attrName, List<String> attrValues) 332 { 333 if (attrValues != null && !attrValues.isEmpty()) 334 { 335 attributes.add(new LDAPAttribute(attrName, attrValues)); 336 } 337 } 338 339 @Override 340 public String getTaskObjectclass() { 341 return "ds-task-export"; 342 } 343 344 @Override 345 public Class<?> getTaskClass() { 346 return ExportTask.class; 347 } 348 349 @Override 350 protected int processLocal(boolean initializeServer, PrintStream out, PrintStream err) 351 { 352 if (initializeServer) 353 { 354 try 355 { 356 new DirectoryServer.InitializationBuilder(configFile.getValue()) 357 .requireCryptoServices() 358 .requireUserPlugins(PluginType.LDIF_EXPORT) 359 .requireErrorAndDebugLogPublisher(out, err) 360 .initialize(); 361 } 362 catch (InitializationException ie) 363 { 364 printWrappedText(err, ERR_CANNOT_INITIALIZE_SERVER_COMPONENTS.get(getExceptionMessage(ie))); 365 return 1; 366 } 367 } 368 369 // See if there were any user-defined sets of include/exclude attributes or 370 // filters. If so, then process them. 371 Set<AttributeType> excludeAttributes = toAttributeTypes(excludeAttributeStrings); 372 Set<AttributeType> includeAttributes = toAttributeTypes(includeAttributeStrings); 373 374 ArrayList<SearchFilter> excludeFilters; 375 if (excludeFilterStrings == null) 376 { 377 excludeFilters = null; 378 } 379 else 380 { 381 excludeFilters = new ArrayList<>(); 382 for (String filterString : excludeFilterStrings.getValues()) 383 { 384 try 385 { 386 excludeFilters.add(SearchFilter.createFilterFromString(filterString)); 387 } 388 catch (DirectoryException de) 389 { 390 logger.error(ERR_LDIFEXPORT_CANNOT_PARSE_EXCLUDE_FILTER, filterString, de.getMessageObject()); 391 return 1; 392 } 393 catch (Exception e) 394 { 395 logger.error(ERR_LDIFEXPORT_CANNOT_PARSE_EXCLUDE_FILTER, filterString, getExceptionMessage(e)); 396 return 1; 397 } 398 } 399 } 400 401 ArrayList<SearchFilter> includeFilters; 402 if (includeFilterStrings == null) 403 { 404 includeFilters = null; 405 } 406 else 407 { 408 includeFilters = new ArrayList<>(); 409 for (String filterString : includeFilterStrings.getValues()) 410 { 411 try 412 { 413 includeFilters.add(SearchFilter.createFilterFromString(filterString)); 414 } 415 catch (DirectoryException de) 416 { 417 logger.error(ERR_LDIFEXPORT_CANNOT_PARSE_INCLUDE_FILTER, filterString, de.getMessageObject()); 418 return 1; 419 } 420 catch (Exception e) 421 { 422 logger.error(ERR_LDIFEXPORT_CANNOT_PARSE_INCLUDE_FILTER, filterString, getExceptionMessage(e)); 423 return 1; 424 } 425 } 426 } 427 428 429 // Get information about the backends defined in the server. Iterate 430 // through them, finding the one backend that should be used for the export, 431 // and also finding backends with subordinate base DNs that should be 432 // excluded from the export. 433 Backend<?> backend = null; 434 List<DN> baseDNList = null; 435 List<DN> defaultIncludeBranches = null; 436 ArrayList<DN> excludeBranches = null; 437 438 List<Backend<?>> backendList = new ArrayList<>(); 439 List<BackendCfg> entryList = new ArrayList<>(); 440 List<List<DN>> dnList = new ArrayList<>(); 441 BackendToolUtils.getBackends(backendList, entryList, dnList); 442 443 int numBackends = backendList.size(); 444 for (int i=0; i < numBackends; i++) 445 { 446 Backend<?> b = backendList.get(i); 447 if (! backendID.getValue().equals(b.getBackendID())) 448 { 449 continue; 450 } 451 452 if (backend == null) 453 { 454 backend = b; 455 baseDNList = dnList.get(i); 456 defaultIncludeBranches = dnList.get(i); 457 } 458 else 459 { 460 logger.error(ERR_LDIFEXPORT_MULTIPLE_BACKENDS_FOR_ID, backendID.getValue()); 461 return 1; 462 } 463 } 464 465 if (backend == null) 466 { 467 logger.error(ERR_LDIFEXPORT_NO_BACKENDS_FOR_ID, backendID.getValue()); 468 return 1; 469 } 470 else if (!backend.supports(BackendOperation.RESTORE)) 471 { 472 logger.error(ERR_LDIFEXPORT_CANNOT_EXPORT_BACKEND, backendID.getValue()); 473 return 1; 474 } 475 476 if (excludeBranchStrings.isPresent()) 477 { 478 excludeBranches = new ArrayList<>(); 479 for (String s : excludeBranchStrings.getValues()) 480 { 481 DN excludeBranch; 482 try 483 { 484 excludeBranch = DN.valueOf(s); 485 } 486 catch (Exception e) 487 { 488 logger.error(ERR_LDIFEXPORT_CANNOT_DECODE_EXCLUDE_BASE, s, getExceptionMessage(e)); 489 return 1; 490 } 491 492 if (! excludeBranches.contains(excludeBranch)) 493 { 494 excludeBranches.add(excludeBranch); 495 } 496 } 497 } 498 499 500 List<DN> includeBranches; 501 if (includeBranchStrings.isPresent()) 502 { 503 includeBranches = new ArrayList<>(); 504 for (String s : includeBranchStrings.getValues()) 505 { 506 DN includeBranch; 507 try 508 { 509 includeBranch = DN.valueOf(s); 510 } 511 catch (Exception e) 512 { 513 logger.error(ERR_LDIFIMPORT_CANNOT_DECODE_INCLUDE_BASE, s, getExceptionMessage(e)); 514 return 1; 515 } 516 517 if (! Backend.handlesEntry(includeBranch, defaultIncludeBranches, 518 excludeBranches)) 519 { 520 logger.error(ERR_LDIFEXPORT_INVALID_INCLUDE_BASE, s, backendID.getValue()); 521 return 1; 522 } 523 524 includeBranches.add(includeBranch); 525 } 526 } 527 else 528 { 529 includeBranches = defaultIncludeBranches; 530 } 531 532 533 // Create the LDIF export configuration to use when reading the LDIF. 534 ExistingFileBehavior existingBehavior; 535 if (appendToLDIF.isPresent()) 536 { 537 existingBehavior = ExistingFileBehavior.APPEND; 538 } 539 else 540 { 541 existingBehavior = ExistingFileBehavior.OVERWRITE; 542 } 543 544 LDIFExportConfig exportConfig = new LDIFExportConfig(ldifFile.getValue(), 545 existingBehavior); 546 exportConfig.setCompressData(compressLDIF.isPresent()); 547 exportConfig.setEncryptData(encryptLDIF.isPresent()); 548 exportConfig.setExcludeAttributes(excludeAttributes); 549 exportConfig.setExcludeBranches(excludeBranches); 550 exportConfig.setExcludeFilters(excludeFilters); 551 exportConfig.setIncludeAttributes(includeAttributes); 552 exportConfig.setIncludeBranches(includeBranches); 553 exportConfig.setIncludeFilters(includeFilters); 554 exportConfig.setSignHash(signHash.isPresent()); 555 exportConfig.setIncludeOperationalAttributes( 556 !excludeOperationalAttrs.isPresent()); 557 558 // FIXME -- Should this be conditional? 559 exportConfig.setInvokeExportPlugins(true); 560 561 try 562 { 563 exportConfig.setWrapColumn(wrapColumn.getIntValue()); 564 } 565 catch (ArgumentException ae) 566 { 567 logger.error(ERR_LDIFEXPORT_CANNOT_DECODE_WRAP_COLUMN_AS_INTEGER, wrapColumn.getValue()); 568 return 1; 569 } 570 571 572 // Get the set of base DNs for the backend as an array. 573 DN[] baseDNs = new DN[baseDNList.size()]; 574 baseDNList.toArray(baseDNs); 575 576 577 // Acquire a shared lock for the backend. 578 try 579 { 580 String lockFile = LockFileManager.getBackendLockFileName(backend); 581 StringBuilder failureReason = new StringBuilder(); 582 if (! LockFileManager.acquireSharedLock(lockFile, failureReason)) 583 { 584 logger.error(ERR_LDIFEXPORT_CANNOT_LOCK_BACKEND, backend.getBackendID(), failureReason); 585 return 1; 586 } 587 } 588 catch (Exception e) 589 { 590 logger.error(ERR_LDIFEXPORT_CANNOT_LOCK_BACKEND, backend.getBackendID(), getExceptionMessage(e)); 591 return 1; 592 } 593 594 boolean errorOccurred = false; 595 596 // Launch the export. 597 try 598 { 599 backend.exportLDIF(exportConfig); 600 } 601 catch (DirectoryException de) 602 { 603 logger.error(ERR_LDIFEXPORT_ERROR_DURING_EXPORT, de.getMessageObject()); 604 errorOccurred = true; 605 } 606 catch (Exception e) 607 { 608 logger.error(ERR_LDIFEXPORT_ERROR_DURING_EXPORT, getExceptionMessage(e)); 609 errorOccurred = true; 610 } 611 612 613 // Release the shared lock on the backend. 614 try 615 { 616 String lockFile = LockFileManager.getBackendLockFileName(backend); 617 StringBuilder failureReason = new StringBuilder(); 618 if (! LockFileManager.releaseLock(lockFile, failureReason)) 619 { 620 logger.warn(WARN_LDIFEXPORT_CANNOT_UNLOCK_BACKEND, backend.getBackendID(), failureReason); 621 } 622 } 623 catch (Exception e) 624 { 625 logger.warn(WARN_LDIFEXPORT_CANNOT_UNLOCK_BACKEND, backend.getBackendID(), getExceptionMessage(e)); 626 } 627 628 629 // Clean up after the export by closing the export config. 630 exportConfig.close(); 631 return !errorOccurred ? 0 : 1; 632 } 633 634 @Override 635 protected void cleanup() 636 { 637 DirectoryServer.shutdownBackends(); 638 } 639 640 private Set<AttributeType> toAttributeTypes(StringArgument attributeArg) 641 { 642 if (attributeArg == null) 643 { 644 return null; 645 } 646 647 Set<AttributeType> results = new HashSet<>(); 648 for (String attrName : attributeArg.getValues()) 649 { 650 results.add(DirectoryServer.getSchema().getAttributeType(attrName)); 651 } 652 return results; 653 } 654 655 @Override 656 public String getTaskId() { 657 // NYI. 658 return null; 659 } 660}