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-2008 Sun Microsystems, Inc. 015 * Portions Copyright 2013-2016 ForgeRock AS. 016 */ 017package org.opends.server.tools; 018 019import static com.forgerock.opendj.cli.ArgumentConstants.*; 020import static com.forgerock.opendj.cli.Utils.*; 021import static com.forgerock.opendj.cli.CommonArguments.*; 022 023import static org.opends.messages.ToolMessages.*; 024import static org.opends.server.util.CollectionUtils.*; 025import static org.opends.server.protocols.ldap.LDAPResultCode.*; 026import static org.opends.server.util.StaticUtils.*; 027 028import java.io.BufferedReader; 029import java.io.FileReader; 030import java.io.OutputStream; 031import java.io.PrintStream; 032import java.util.ArrayList; 033import java.util.Iterator; 034import java.util.LinkedHashSet; 035import java.util.LinkedList; 036 037import org.forgerock.i18n.LocalizableMessage; 038import org.forgerock.opendj.ldap.DN; 039import org.forgerock.opendj.ldap.SearchScope; 040import org.opends.server.core.DirectoryServer; 041import org.opends.server.core.DirectoryServer.DirectoryServerVersionHandler; 042import org.opends.server.extensions.ConfigFileHandler; 043import org.opends.server.loggers.JDKLogging; 044import org.opends.server.protocols.ldap.LDAPResultCode; 045import org.forgerock.opendj.ldap.schema.AttributeType; 046import org.opends.server.types.*; 047import org.opends.server.util.BuildVersion; 048import org.opends.server.util.LDIFException; 049import org.opends.server.util.LDIFReader; 050import org.opends.server.util.LDIFWriter; 051 052import com.forgerock.opendj.cli.*; 053 054/** 055 * This class provides a program that may be used to search LDIF files. It is 056 * modeled after the LDAPSearch tool, with the primary differencing being that 057 * all of its data comes from LDIF rather than communicating over LDAP. 058 * However, it does have a number of differences that allow it to perform 059 * multiple operations in a single pass rather than requiring multiple passes 060 * through the LDIF. 061 */ 062public class LDIFSearch 063{ 064 /** The fully-qualified name of this class. */ 065 private static final String CLASS_NAME = "org.opends.server.tools.LDIFSearch"; 066 067 /** The search scope string that will be used for baseObject searches. */ 068 private static final String SCOPE_STRING_BASE = "base"; 069 /** The search scope string that will be used for singleLevel searches. */ 070 private static final String SCOPE_STRING_ONE = "one"; 071 /** The search scope string that will be used for wholeSubtree searches. */ 072 private static final String SCOPE_STRING_SUB = "sub"; 073 /** The search scope string that will be used for subordinateSubtree searches. */ 074 private static final String SCOPE_STRING_SUBORDINATE = "subordinate"; 075 076 /** 077 * Provides the command line arguments to the <CODE>mainSearch</CODE> method 078 * so that they can be processed. 079 * 080 * @param args The command line arguments provided to this program. 081 */ 082 public static void main(String[] args) 083 { 084 int exitCode = mainSearch(args, true, System.out, System.err); 085 if (exitCode != 0) 086 { 087 System.exit(filterExitCode(exitCode)); 088 } 089 } 090 091 092 093 /** 094 * Parses the provided command line arguments and performs the appropriate 095 * search operation. 096 * 097 * @param args The command line arguments provided to this 098 * program. 099 * @param initializeServer True if server initialization should be done. 100 * @param outStream The output stream to use for standard output, or 101 * {@code null} if standard output is not needed. 102 * @param errStream The output stream to use for standard error, or 103 * {@code null} if standard error is not needed. 104 * 105 * @return The return code for this operation. A value of zero indicates 106 * that all processing completed successfully. A nonzero value 107 * indicates that some problem occurred during processing. 108 */ 109 public static int mainSearch(String[] args, boolean initializeServer, 110 OutputStream outStream, OutputStream errStream) 111 { 112 PrintStream out = NullOutputStream.wrapOrNullStream(outStream); 113 PrintStream err = NullOutputStream.wrapOrNullStream(errStream); 114 JDKLogging.disableLogging(); 115 116 LinkedHashSet<String> scopeStrings = new LinkedHashSet<>(4); 117 scopeStrings.add(SCOPE_STRING_BASE); 118 scopeStrings.add(SCOPE_STRING_ONE); 119 scopeStrings.add(SCOPE_STRING_SUB); 120 scopeStrings.add(SCOPE_STRING_SUBORDINATE); 121 122 123 BooleanArgument dontWrap; 124 BooleanArgument overwriteExisting; 125 BooleanArgument showUsage; 126 StringArgument filterFile; 127 IntegerArgument sizeLimit; 128 IntegerArgument timeLimit; 129 MultiChoiceArgument<String> scopeString; 130 StringArgument baseDNString; 131 StringArgument configClass; 132 StringArgument configFile; 133 StringArgument ldifFile; 134 StringArgument outputFile; 135 136 137 LocalizableMessage toolDescription = INFO_LDIFSEARCH_TOOL_DESCRIPTION.get(); 138 ArgumentParser argParser = new ArgumentParser(CLASS_NAME, toolDescription, 139 false, true, 0, 0, 140 "[filter] [attributes ...]"); 141 argParser.setShortToolDescription(REF_SHORT_DESC_LDIFSEARCH.get()); 142 argParser.setVersionHandler(new DirectoryServerVersionHandler()); 143 144 try 145 { 146 ldifFile = 147 StringArgument.builder("ldifFile") 148 .shortIdentifier('l') 149 .description(INFO_LDIFSEARCH_DESCRIPTION_LDIF_FILE.get()) 150 .multiValued() 151 .valuePlaceholder(INFO_LDIFFILE_PLACEHOLDER.get()) 152 .buildAndAddToParser(argParser); 153 baseDNString = 154 StringArgument.builder(OPTION_LONG_BASEDN) 155 .shortIdentifier(OPTION_SHORT_BASEDN) 156 .description(INFO_LDIFSEARCH_DESCRIPTION_BASEDN.get()) 157 .multiValued() 158 .defaultValue("") 159 .valuePlaceholder(INFO_BASEDN_PLACEHOLDER.get()) 160 .buildAndAddToParser(argParser); 161 scopeString = 162 MultiChoiceArgument.<String>builder("searchScope") 163 .shortIdentifier('s') 164 .description(INFO_LDIFSEARCH_DESCRIPTION_SCOPE.get()) 165 .allowedValues(scopeStrings) 166 .defaultValue(SCOPE_STRING_SUB) 167 .valuePlaceholder(INFO_SCOPE_PLACEHOLDER.get()) 168 .buildAndAddToParser(argParser); 169 configFile = 170 StringArgument.builder("configFile") 171 .shortIdentifier('c') 172 .description(INFO_DESCRIPTION_CONFIG_FILE.get()) 173 .hidden() 174 .valuePlaceholder(INFO_CONFIGFILE_PLACEHOLDER.get()) 175 .buildAndAddToParser(argParser); 176 configClass = 177 StringArgument.builder(OPTION_LONG_CONFIG_CLASS) 178 .shortIdentifier(OPTION_SHORT_CONFIG_CLASS) 179 .description(INFO_DESCRIPTION_CONFIG_CLASS.get()) 180 .hidden() 181 .defaultValue(ConfigFileHandler.class.getName()) 182 .valuePlaceholder(INFO_CONFIGCLASS_PLACEHOLDER.get()) 183 .buildAndAddToParser(argParser); 184 filterFile = 185 StringArgument.builder("filterFile") 186 .shortIdentifier('f') 187 .description(INFO_LDIFSEARCH_DESCRIPTION_FILTER_FILE.get()) 188 .valuePlaceholder(INFO_FILTER_FILE_PLACEHOLDER.get()) 189 .buildAndAddToParser(argParser); 190 outputFile = 191 StringArgument.builder("outputFile") 192 .shortIdentifier('o') 193 .description(INFO_LDIFSEARCH_DESCRIPTION_OUTPUT_FILE.get()) 194 .valuePlaceholder(INFO_OUTPUT_FILE_PLACEHOLDER.get()) 195 .buildAndAddToParser(argParser); 196 overwriteExisting = 197 BooleanArgument.builder("overwriteExisting") 198 .shortIdentifier('O') 199 .description(INFO_LDIFSEARCH_DESCRIPTION_OVERWRITE_EXISTING.get()) 200 .buildAndAddToParser(argParser); 201 dontWrap = 202 BooleanArgument.builder("dontWrap") 203 .shortIdentifier('T') 204 .description(INFO_LDIFSEARCH_DESCRIPTION_DONT_WRAP.get()) 205 .buildAndAddToParser(argParser); 206 sizeLimit = 207 IntegerArgument.builder("sizeLimit") 208 .shortIdentifier('z') 209 .description(INFO_LDIFSEARCH_DESCRIPTION_SIZE_LIMIT.get()) 210 .lowerBound(0) 211 .defaultValue(0) 212 .valuePlaceholder(INFO_SIZE_LIMIT_PLACEHOLDER.get()) 213 .buildAndAddToParser(argParser); 214 timeLimit = 215 IntegerArgument.builder("timeLimit") 216 .shortIdentifier('t') 217 .description(INFO_LDIFSEARCH_DESCRIPTION_TIME_LIMIT.get()) 218 .lowerBound(0) 219 .defaultValue(0) 220 .valuePlaceholder(INFO_TIME_LIMIT_PLACEHOLDER.get()) 221 .buildAndAddToParser(argParser); 222 223 showUsage = showUsageArgument(); 224 argParser.addArgument(showUsage); 225 argParser.setUsageArgument(showUsage); 226 } 227 catch (ArgumentException ae) 228 { 229 printWrappedText(err, ERR_CANNOT_INITIALIZE_ARGS.get(ae.getMessage())); 230 return 1; 231 } 232 233 234 // Parse the command-line arguments provided to the program. 235 try 236 { 237 argParser.parseArguments(args); 238 } 239 catch (ArgumentException ae) 240 { 241 argParser.displayMessageAndUsageReference(err, ERR_ERROR_PARSING_ARGS.get(ae.getMessage())); 242 return CLIENT_SIDE_PARAM_ERROR; 243 } 244 245 246 // If we should just display usage or version information, 247 // then print it and exit. 248 if (argParser.usageOrVersionDisplayed()) 249 { 250 return 0; 251 } 252 253 // Checks the version - if upgrade required, the tool is unusable 254 try 255 { 256 BuildVersion.checkVersionMismatch(); 257 } 258 catch (InitializationException e) 259 { 260 printWrappedText(err, e.getMessage()); 261 return 1; 262 } 263 264 // Make sure that at least one filter was provided. Also get the attribute 265 // list at the same time because it may need to be specified in the same 266 // way. 267 boolean allUserAttrs = false; 268 boolean allOperationalAttrs = false; 269 //Return objectclass attribute unless analysis of the arguments determines 270 //otherwise. 271 boolean includeObjectclassAttrs = true; 272 final LinkedList<String> attributeNames = new LinkedList<>(); 273 LinkedList<String> objectClassNames = new LinkedList<>(); 274 LinkedList<String> filterStrings = new LinkedList<>(); 275 if (filterFile.isPresent()) 276 { 277 BufferedReader in = null; 278 try 279 { 280 String fileNameValue = filterFile.getValue(); 281 in = new BufferedReader(new FileReader(fileNameValue)); 282 String line = null; 283 284 while ((line = in.readLine()) != null) 285 { 286 if(line.trim().equals("")) 287 { 288 // ignore empty lines. 289 continue; 290 } 291 filterStrings.add(line); 292 } 293 } catch(Exception e) 294 { 295 printWrappedText(err, e.getMessage()); 296 return 1; 297 } 298 finally 299 { 300 close(in); 301 } 302 303 ArrayList<String> trailingArguments = argParser.getTrailingArguments(); 304 if (trailingArguments != null && !trailingArguments.isEmpty()) 305 { 306 for (String attributeName : trailingArguments) 307 { 308 String lowerName = toLowerCase(attributeName); 309 if (lowerName.equals("*")) 310 { 311 allUserAttrs = true; 312 } 313 else if (lowerName.equals("+")) 314 { 315 allOperationalAttrs = true; 316 } 317 else if (lowerName.startsWith("@")) 318 { 319 objectClassNames.add(lowerName.substring(1)); 320 } 321 else 322 { 323 attributeNames.add(lowerName); 324 } 325 } 326 } 327 } 328 else 329 { 330 ArrayList<String> trailingArguments = argParser.getTrailingArguments(); 331 if (trailingArguments == null || trailingArguments.isEmpty()) 332 { 333 argParser.displayMessageAndUsageReference(err, ERR_LDIFSEARCH_NO_FILTER.get()); 334 return 1; 335 } 336 337 Iterator<String> iterator = trailingArguments.iterator(); 338 filterStrings = newLinkedList(iterator.next()); 339 340 while (iterator.hasNext()) 341 { 342 String lowerName = toLowerCase(iterator.next()); 343 if (lowerName.equals("*")) 344 { 345 allUserAttrs = true; 346 } 347 else if (lowerName.equals("+")) 348 { 349 allOperationalAttrs = true; 350 } 351 else if (lowerName.startsWith("@")) 352 { 353 objectClassNames.add(lowerName.substring(1)); 354 } 355 else 356 { 357 attributeNames.add(lowerName); 358 } 359 } 360 } 361 362 if (attributeNames.isEmpty() 363 && objectClassNames.isEmpty() 364 && !allOperationalAttrs) 365 { 366 // This will be true if no attributes were requested, which is effectively 367 // all user attributes. It will also be true if just "*" was included, 368 // but the net result will be the same. 369 allUserAttrs = true; 370 } 371 372 //Determine if objectclass attribute should be returned. 373 if(!allUserAttrs) { 374 //Single '+', never return objectclass. 375 if(allOperationalAttrs && objectClassNames.isEmpty() && 376 attributeNames.isEmpty()) 377 { 378 includeObjectclassAttrs=false; 379 } 380 //If "objectclass" isn't specified in the attributes to return, then 381 //don't include objectclass attribute. 382 if(!attributeNames.isEmpty() && objectClassNames.isEmpty() && 383 !attributeNames.contains("objectclass")) 384 { 385 includeObjectclassAttrs=false; 386 } 387 } 388 389 390 // Bootstrap the Directory Server configuration for use as a client. 391 DirectoryServer directoryServer = DirectoryServer.getInstance(); 392 393 // If we're to use the configuration then initialize it, along with the 394 // schema. 395 boolean checkSchema = configFile.isPresent(); 396 397 if (initializeServer) 398 { 399 DirectoryServer.bootstrapClient(); 400 401 if (checkSchema) 402 { 403 try 404 { 405 DirectoryServer.initializeJMX(); 406 } 407 catch (Exception e) 408 { 409 printWrappedText(err, ERR_LDIFSEARCH_CANNOT_INITIALIZE_JMX.get(configFile.getValue(), e.getMessage())); 410 return 1; 411 } 412 413 try 414 { 415 directoryServer.initializeConfiguration(configClass.getValue(), configFile.getValue()); 416 } 417 catch (Exception e) 418 { 419 printWrappedText(err, ERR_LDIFSEARCH_CANNOT_INITIALIZE_CONFIG.get(configFile.getValue(), e.getMessage())); 420 return 1; 421 } 422 423 try 424 { 425 directoryServer.initializeSchema(); 426 } 427 catch (Exception e) 428 { 429 printWrappedText(err, ERR_LDIFSEARCH_CANNOT_INITIALIZE_SCHEMA.get(configFile.getValue(), e.getMessage())); 430 return 1; 431 } 432 } 433 } 434 435 // Choose the desired search scope. 436 SearchScope searchScope; 437 if (scopeString.isPresent()) 438 { 439 String scopeStr = toLowerCase(scopeString.getValue()); 440 if (scopeStr.equals(SCOPE_STRING_BASE)) 441 { 442 searchScope = SearchScope.BASE_OBJECT; 443 } 444 else if (scopeStr.equals(SCOPE_STRING_ONE)) 445 { 446 searchScope = SearchScope.SINGLE_LEVEL; 447 } 448 else if (scopeStr.equals(SCOPE_STRING_SUBORDINATE)) 449 { 450 searchScope = SearchScope.SUBORDINATES; 451 } 452 else 453 { 454 searchScope = SearchScope.WHOLE_SUBTREE; 455 } 456 } 457 else 458 { 459 searchScope = SearchScope.WHOLE_SUBTREE; 460 } 461 462 463 // Create the list of filters that will be used to process the searches. 464 LinkedList<SearchFilter> searchFilters = new LinkedList<>(); 465 for (String filterString : filterStrings) 466 { 467 try 468 { 469 searchFilters.add(SearchFilter.createFilterFromString(filterString)); 470 } 471 catch (Exception e) 472 { 473 printWrappedText(err, ERR_LDIFSEARCH_CANNOT_PARSE_FILTER.get(filterString, e.getMessage())); 474 return 1; 475 } 476 } 477 478 479 // Transform the attributes to return from strings to attribute types. 480 LinkedHashSet<AttributeType> userAttributeTypes = new LinkedHashSet<>(); 481 LinkedHashSet<AttributeType> operationalAttributeTypes = new LinkedHashSet<>(); 482 for (String attributeName : attributeNames) 483 { 484 AttributeType t = DirectoryServer.getAttributeType(attributeName); 485 if (t.isOperational()) 486 { 487 operationalAttributeTypes.add(t); 488 } 489 else 490 { 491 userAttributeTypes.add(t); 492 } 493 } 494 495 for (String objectClassName : objectClassNames) 496 { 497 ObjectClass c = DirectoryServer.getObjectClass(objectClassName, true); 498 for (AttributeType t : c.getRequiredAttributeChain()) 499 { 500 if (t.isOperational()) 501 { 502 operationalAttributeTypes.add(t); 503 } 504 else 505 { 506 userAttributeTypes.add(t); 507 } 508 } 509 510 for (AttributeType t : c.getOptionalAttributeChain()) 511 { 512 if (t.isOperational()) 513 { 514 operationalAttributeTypes.add(t); 515 } 516 else 517 { 518 userAttributeTypes.add(t); 519 } 520 } 521 } 522 523 524 // Set the base DNs for the import config. 525 LinkedList<DN> baseDNs = new LinkedList<>(); 526 if (baseDNString.isPresent()) 527 { 528 for (String dnString : baseDNString.getValues()) 529 { 530 try 531 { 532 baseDNs.add(DN.valueOf(dnString)); 533 } 534 catch (Exception e) 535 { 536 printWrappedText(err, ERR_LDIFSEARCH_CANNOT_PARSE_BASE_DN.get(dnString, e.getMessage())); 537 return 1; 538 } 539 } 540 } 541 else 542 { 543 baseDNs.add(DN.rootDN()); 544 } 545 546 547 // Get the time limit in milliseconds. 548 long timeLimitMillis; 549 try 550 { 551 if (timeLimit.isPresent()) 552 { 553 timeLimitMillis = 1000L * timeLimit.getIntValue(); 554 } 555 else 556 { 557 timeLimitMillis = 0; 558 } 559 } 560 catch (Exception e) 561 { 562 printWrappedText(err, ERR_LDIFSEARCH_CANNOT_PARSE_TIME_LIMIT.get(e)); 563 return 1; 564 } 565 566 567 // Convert the size limit to an integer. 568 int sizeLimitValue; 569 try 570 { 571 if (sizeLimit.isPresent()) 572 { 573 sizeLimitValue = sizeLimit.getIntValue(); 574 } 575 else 576 { 577 sizeLimitValue =0; 578 } 579 } 580 catch (Exception e) 581 { 582 printWrappedText(err, ERR_LDIFSEARCH_CANNOT_PARSE_SIZE_LIMIT.get(e)); 583 return 1; 584 } 585 586 587 // Create the LDIF import configuration that will be used to read the source 588 // data. 589 LDIFImportConfig importConfig; 590 if (ldifFile.isPresent()) 591 { 592 importConfig = new LDIFImportConfig(ldifFile.getValues()); 593 } 594 else 595 { 596 importConfig = new LDIFImportConfig(System.in); 597 } 598 599 600 // Create the LDIF export configuration that will be used to write the 601 // matching entries. 602 LDIFExportConfig exportConfig; 603 if (outputFile.isPresent()) 604 { 605 if (overwriteExisting.isPresent()) 606 { 607 exportConfig = new LDIFExportConfig(outputFile.getValue(), 608 ExistingFileBehavior.OVERWRITE); 609 } 610 else 611 { 612 exportConfig = new LDIFExportConfig(outputFile.getValue(), 613 ExistingFileBehavior.APPEND); 614 } 615 } 616 else 617 { 618 exportConfig = new LDIFExportConfig(out); 619 } 620 621 exportConfig.setIncludeObjectClasses(includeObjectclassAttrs); 622 if (dontWrap.isPresent()) 623 { 624 exportConfig.setWrapColumn(0); 625 } 626 else 627 { 628 exportConfig.setWrapColumn(75); 629 } 630 631 632 // Create the LDIF reader/writer from the import/export config. 633 LDIFReader reader; 634 LDIFWriter writer; 635 try 636 { 637 reader = new LDIFReader(importConfig); 638 } 639 catch (Exception e) 640 { 641 printWrappedText(err, ERR_LDIFSEARCH_CANNOT_CREATE_READER.get(e)); 642 return 1; 643 } 644 645 try 646 { 647 writer = new LDIFWriter(exportConfig); 648 } 649 catch (Exception e) 650 { 651 close(reader); 652 printWrappedText(err, ERR_LDIFSEARCH_CANNOT_CREATE_WRITER.get(e)); 653 return 1; 654 } 655 656 657 // Start reading data from the LDIF reader. 658 long startTime = System.currentTimeMillis(); 659 long stopTime = startTime + timeLimitMillis; 660 long matchCount = 0; 661 int resultCode = LDAPResultCode.SUCCESS; 662 while (true) 663 { 664 // If the time limit has been reached, then stop now. 665 if (timeLimitMillis > 0 && System.currentTimeMillis() > stopTime) 666 { 667 resultCode = LDAPResultCode.TIME_LIMIT_EXCEEDED; 668 669 LocalizableMessage message = WARN_LDIFSEARCH_TIME_LIMIT_EXCEEDED.get(); 670 err.println(message); 671 break; 672 } 673 674 675 try 676 { 677 Entry entry = reader.readEntry(checkSchema); 678 if (entry == null) 679 { 680 break; 681 } 682 683 684 // Check to see if the entry has an acceptable base and scope. 685 boolean matchesBaseAndScope = false; 686 for (DN baseDN : baseDNs) 687 { 688 if (entry.matchesBaseAndScope(baseDN, searchScope)) 689 { 690 matchesBaseAndScope = true; 691 break; 692 } 693 } 694 695 if (! matchesBaseAndScope) 696 { 697 continue; 698 } 699 700 701 // Check to see if the entry matches any of the filters. 702 boolean matchesFilter = false; 703 for (SearchFilter filter : searchFilters) 704 { 705 if (filter.matchesEntry(entry)) 706 { 707 matchesFilter = true; 708 break; 709 } 710 } 711 712 if (! matchesFilter) 713 { 714 continue; 715 } 716 717 718 // Prepare the entry to return to the client. 719 if (! allUserAttrs) 720 { 721 Iterator<AttributeType> iterator = 722 entry.getUserAttributes().keySet().iterator(); 723 while (iterator.hasNext()) 724 { 725 if (! userAttributeTypes.contains(iterator.next())) 726 { 727 iterator.remove(); 728 } 729 } 730 } 731 732 if (! allOperationalAttrs) 733 { 734 Iterator<AttributeType> iterator = 735 entry.getOperationalAttributes().keySet().iterator(); 736 while (iterator.hasNext()) 737 { 738 if (! operationalAttributeTypes.contains(iterator.next())) 739 { 740 iterator.remove(); 741 } 742 } 743 } 744 745 746 // Write the entry to the client and increase the count. 747 // FIXME -- Should we include a comment about which base+filter matched? 748 writer.writeEntry(entry); 749 writer.flush(); 750 751 matchCount++; 752 if (sizeLimitValue > 0 && matchCount >= sizeLimitValue) 753 { 754 resultCode = LDAPResultCode.SIZE_LIMIT_EXCEEDED; 755 756 LocalizableMessage message = WARN_LDIFSEARCH_SIZE_LIMIT_EXCEEDED.get(); 757 err.println(message); 758 break; 759 } 760 } 761 catch (LDIFException le) 762 { 763 if (le.canContinueReading()) 764 { 765 LocalizableMessage message = ERR_LDIFSEARCH_CANNOT_READ_ENTRY_RECOVERABLE.get( 766 le.getMessage()); 767 err.println(message); 768 } 769 else 770 { 771 LocalizableMessage message = ERR_LDIFSEARCH_CANNOT_READ_ENTRY_FATAL.get( 772 le.getMessage()); 773 err.println(message); 774 resultCode = LDAPResultCode.CLIENT_SIDE_LOCAL_ERROR; 775 break; 776 } 777 } 778 catch (Exception e) 779 { 780 err.println(ERR_LDIFSEARCH_ERROR_DURING_PROCESSING.get(e)); 781 resultCode = LDAPResultCode.CLIENT_SIDE_LOCAL_ERROR; 782 break; 783 } 784 } 785 786 close(reader, writer); 787 788 return resultCode; 789 } 790} 791