001 /* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at 010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE 011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Copyright 2006-2008 Sun Microsystems, Inc. 026 */ 027 package org.opends.server.types; 028 import org.opends.messages.Message; 029 030 031 032 import java.io.BufferedWriter; 033 import java.io.File; 034 import java.io.FileOutputStream; 035 import java.io.IOException; 036 import java.io.OutputStream; 037 import java.io.OutputStreamWriter; 038 import java.util.ArrayList; 039 import java.util.HashSet; 040 import java.util.List; 041 import java.util.Set; 042 import java.util.zip.GZIPOutputStream; 043 044 import static org.opends.server.loggers.debug.DebugLogger.*; 045 import org.opends.server.loggers.debug.DebugTracer; 046 import static org.opends.messages.UtilityMessages.*; 047 048 049 050 /** 051 * This class defines a data structure for holding configuration 052 * information to use when performing an LDIF export. 053 */ 054 @org.opends.server.types.PublicAPI( 055 stability=org.opends.server.types.StabilityLevel.VOLATILE, 056 mayInstantiate=true, 057 mayExtend=false, 058 mayInvoke=true) 059 public final class LDIFExportConfig extends OperationConfig 060 { 061 /** 062 * The tracer object for the debug logger. 063 */ 064 private static final DebugTracer TRACER = getTracer(); 065 066 // Indicates whether the data should be compressed as it is written. 067 private boolean compressData; 068 069 // Indicates whether the data should be encrypted as it is written. 070 private boolean encryptData; 071 072 // Indicates whether we should exclude operational attributes. 073 private boolean excludeOperationalAttributes; 074 075 // Indicates whether to generate a cryptographic hash of the data as 076 // it is // written. 077 private boolean hashData; 078 079 // Indicates whether to include the objectclasses in the entries 080 // written in the export. 081 private boolean includeObjectClasses; 082 083 // Indicates whether to include operational attributes in the 084 // export. 085 private boolean includeOperationalAttributes; 086 087 // Indicates whether to include virutal attributes in the export. 088 private boolean includeVirtualAttributes; 089 090 // Indicates whether to invoke LDIF export plugins on entries being 091 // exported. 092 private boolean invokeExportPlugins; 093 094 // Indicates whether to digitally sign the hash when the export is 095 // complete. 096 private boolean signHash; 097 098 // Indicates whether to include attribute types (i.e., names) only 099 // or both types and values. 100 private boolean typesOnly; 101 102 // The buffered writer to which the LDIF data should be written. 103 private BufferedWriter writer; 104 105 // The behavior that should be used when writing an LDIF file and a 106 // file with the same name already exists. 107 private ExistingFileBehavior existingFileBehavior; 108 109 // The column number at which long lines should be wrapped. 110 private int wrapColumn; 111 112 // The set of base DNs to exclude from the export. 113 private List<DN> excludeBranches; 114 115 // The set of base DNs to include from the export. 116 private List<DN> includeBranches; 117 118 // The set of search filters for entries to exclude from the export. 119 private List<SearchFilter> excludeFilters; 120 121 // The set of search filters for entries to include in the export. 122 private List<SearchFilter> includeFilters; 123 124 // The output stream to which the LDIF data should be written. 125 private OutputStream ldifOutputStream; 126 127 // The set of attribute types that should be excluded from the 128 // export. 129 private Set<AttributeType> excludeAttributes; 130 131 // The set of attribute types that should be included in the export. 132 private Set<AttributeType> includeAttributes; 133 134 // The path to the LDIF file that should be written. 135 private String ldifFile; 136 137 138 139 /** 140 * Creates a new LDIF export configuration that will write to the 141 * specified LDIF file. 142 * 143 * @param ldifFile The path to the LDIF file to 144 * export. 145 * @param existingFileBehavior Indicates how to proceed if the 146 * specified file already exists. 147 */ 148 public LDIFExportConfig(String ldifFile, 149 ExistingFileBehavior existingFileBehavior) 150 { 151 this.ldifFile = ldifFile; 152 this.existingFileBehavior = existingFileBehavior; 153 ldifOutputStream = null; 154 155 excludeBranches = new ArrayList<DN>(); 156 includeBranches = new ArrayList<DN>(); 157 excludeFilters = new ArrayList<SearchFilter>(); 158 includeFilters = new ArrayList<SearchFilter>(); 159 compressData = false; 160 encryptData = false; 161 excludeOperationalAttributes = false; 162 hashData = false; 163 includeObjectClasses = true; 164 includeOperationalAttributes = true; 165 includeVirtualAttributes = false; 166 invokeExportPlugins = false; 167 signHash = false; 168 typesOnly = false; 169 writer = null; 170 excludeAttributes = new HashSet<AttributeType>(); 171 includeAttributes = new HashSet<AttributeType>(); 172 wrapColumn = -1; 173 } 174 175 176 177 /** 178 * Creates a new LDIF export configuration that will write to the 179 * provided output stream. 180 * 181 * @param ldifOutputStream The output stream to which the LDIF 182 * data should be written. 183 */ 184 public LDIFExportConfig(OutputStream ldifOutputStream) 185 { 186 this.ldifOutputStream = ldifOutputStream; 187 ldifFile = null; 188 existingFileBehavior = ExistingFileBehavior.FAIL; 189 190 excludeBranches = new ArrayList<DN>(); 191 includeBranches = new ArrayList<DN>(); 192 excludeFilters = new ArrayList<SearchFilter>(); 193 includeFilters = new ArrayList<SearchFilter>(); 194 compressData = false; 195 encryptData = false; 196 hashData = false; 197 includeObjectClasses = true; 198 includeOperationalAttributes = true; 199 includeVirtualAttributes = false; 200 invokeExportPlugins = false; 201 signHash = false; 202 typesOnly = false; 203 writer = null; 204 excludeAttributes = new HashSet<AttributeType>(); 205 includeAttributes = new HashSet<AttributeType>(); 206 wrapColumn = -1; 207 } 208 209 210 211 /** 212 * Retrieves the writer that should be used to write the LDIF data. 213 * If compression or encryption are to be used, then they must be 214 * enabled before the first call to this method. 215 * 216 * @return The writer that should be used to write the LDIF data. 217 * 218 * @throws IOException If a problem occurs while preparing the 219 * writer. 220 */ 221 public BufferedWriter getWriter() 222 throws IOException 223 { 224 if (writer == null) 225 { 226 if (ldifOutputStream == null) 227 { 228 switch (existingFileBehavior) 229 { 230 case APPEND: 231 ldifOutputStream = new FileOutputStream(ldifFile, true); 232 break; 233 case OVERWRITE: 234 ldifOutputStream = new FileOutputStream(ldifFile, false); 235 break; 236 case FAIL: 237 File f = new File(ldifFile); 238 if (f.exists()) 239 { 240 Message message = ERR_LDIF_FILE_EXISTS.get(ldifFile); 241 throw new IOException(message.toString()); 242 } 243 else 244 { 245 ldifOutputStream = new FileOutputStream(ldifFile); 246 } 247 break; 248 } 249 } 250 251 252 // See if we should compress the output. 253 OutputStream outputStream; 254 if (compressData) 255 { 256 outputStream = new GZIPOutputStream(ldifOutputStream); 257 } 258 else 259 { 260 outputStream = ldifOutputStream; 261 } 262 263 264 // See if we should encrypt the output. 265 if (encryptData) 266 { 267 // FIXME -- Implement this. 268 } 269 270 271 // Create the writer. 272 writer = 273 new BufferedWriter(new OutputStreamWriter(outputStream)); 274 } 275 276 return writer; 277 } 278 279 280 281 /** 282 * Indicates whether the LDIF export plugins should be invoked for 283 * entries as they are exported. 284 * 285 * @return <CODE>true</CODE> if LDIF export plugins should be 286 * invoked for entries as they are exported, or 287 * <CODE>false</CODE> if not. 288 */ 289 public boolean invokeExportPlugins() 290 { 291 return invokeExportPlugins; 292 } 293 294 295 296 /** 297 * Specifies whether the LDIF export plugins should be invoked for 298 * entries as they are exported. 299 * 300 * @param invokeExportPlugins Specifies whether the LDIF export 301 * plugins should be invoked for 302 * entries as they are exported. 303 */ 304 public void setInvokeExportPlugins(boolean invokeExportPlugins) 305 { 306 this.invokeExportPlugins = invokeExportPlugins; 307 } 308 309 310 311 /** 312 * Indicates whether the LDIF data should be compressed as it is 313 * written. 314 * 315 * @return <CODE>true</CODE> if the LDIF data should be compressed 316 * as it is written, or <CODE>false</CODE> if not. 317 */ 318 public boolean compressData() 319 { 320 return compressData; 321 } 322 323 324 325 /** 326 * Specifies whether the LDIF data should be compressed as it is 327 * written. If compression should be used, then this must be set 328 * before calling <CODE>getWriter</CODE> for the first time. 329 * 330 * @param compressData Indicates whether the LDIF data should be 331 * compressed as it is written. 332 */ 333 public void setCompressData(boolean compressData) 334 { 335 this.compressData = compressData; 336 } 337 338 339 340 /** 341 * Indicates whether the LDIF data should be encrypted as it is 342 * written. 343 * 344 * @return <CODE>true</CODE> if the LDIF data should be encrypted 345 * as it is written, or <CODE>false</CODE> if not. 346 */ 347 public boolean encryptData() 348 { 349 return encryptData; 350 } 351 352 353 354 /** 355 * Specifies whether the LDIF data should be encrypted as it is 356 * written. If encryption should be used, then this must be set 357 * before calling <CODE>getWriter</CODE> for the first time. 358 * 359 * @param encryptData Indicates whether the LDIF data should be 360 * encrypted as it is written. 361 */ 362 public void setEncryptData(boolean encryptData) 363 { 364 this.encryptData = encryptData; 365 } 366 367 368 369 /** 370 * Indicates whether to generate a cryptographic hash of the data 371 * that is written. 372 * 373 * @return <CODE>true</CODE> if a hash should be generated as the 374 * data is written, or <CODE>false</CODE> if not. 375 */ 376 public boolean hashData() 377 { 378 return hashData; 379 } 380 381 382 383 /** 384 * Specifies whether to generate a cryptographic hash of the data 385 * that is written. If hashing is to be used, then this must be set 386 * before calling <CODE>getWriter</CODE> for the first time. 387 * 388 * @param hashData Indicates whether to generate a hash of the 389 * data as it is written. 390 */ 391 public void setHashData(boolean hashData) 392 { 393 this.hashData = hashData; 394 } 395 396 397 398 /** 399 * Indicates whether to sign the cryptographic hash of the data that 400 * is written when the export is complete. 401 * 402 * @return <CODE>true</CODE> if the hash should be signed when the 403 * export is complete, or <CODE>false</CODE> if not. 404 */ 405 public boolean signHash() 406 { 407 return signHash; 408 } 409 410 411 412 /** 413 * Specifies whether to sign the cryptographic hash of the data that 414 * is written when the export is complete. If the export is not 415 * configured to generate a hash, then this will be ignored. If 416 * hashing is to be used and the hash should be signed, then this 417 * must be set before calling <CODE>getWriter</CODE> for the first 418 * time. 419 * 420 * @param signHash Indicates whether to generate a hash of the 421 * data as it is written. 422 */ 423 public void setSignHash(boolean signHash) 424 { 425 this.signHash = signHash; 426 } 427 428 429 430 /** 431 * Indicates whether the LDIF generated should include attribute 432 * types (i.e., attribute names) only or both attribute types and 433 * values. 434 * 435 * @return <CODE>true</CODE> if only attribute types should be 436 * included in the resulting LDIF, or <CODE>false</CODE> if 437 * both types and values should be included. 438 */ 439 public boolean typesOnly() 440 { 441 return typesOnly; 442 } 443 444 445 446 /** 447 * Specifies whether the LDIF generated should include attribute 448 * types (i.e., attribute names) only or both attribute types and 449 * values. 450 * 451 * @param typesOnly Specifies whether the LDIF generated should 452 * include attribute types only or both attribute 453 * types and values. 454 */ 455 public void setTypesOnly(boolean typesOnly) 456 { 457 this.typesOnly = typesOnly; 458 } 459 460 461 462 /** 463 * Retrieves the column at which long lines should be wrapped. 464 * 465 * @return The column at which long lines should be wrapped, or a 466 * value less than or equal to zero to indicate that no 467 * wrapping should be performed. 468 */ 469 public int getWrapColumn() 470 { 471 return wrapColumn; 472 } 473 474 475 476 /** 477 * Specifies the column at which long lines should be wrapped. A 478 * value less than or equal to zero indicates that no wrapping 479 * should be performed. 480 * 481 * @param wrapColumn The column at which long lines should be 482 * wrapped. 483 */ 484 public void setWrapColumn(int wrapColumn) 485 { 486 this.wrapColumn = wrapColumn; 487 } 488 489 490 491 /** 492 * Retrieves the set of base DNs that specify the set of entries to 493 * exclude from the export. The list that is returned may be 494 * altered by the caller. 495 * 496 * @return The set of base DNs that specify the set of entries to 497 * exclude from the export. 498 */ 499 public List<DN> getExcludeBranches() 500 { 501 return excludeBranches; 502 } 503 504 505 506 /** 507 * Specifies the set of base DNs that specify the set of entries to 508 * exclude from the export. 509 * 510 * @param excludeBranches The set of base DNs that specify the set 511 * of entries to exclude from the export. 512 */ 513 public void setExcludeBranches(List<DN> excludeBranches) 514 { 515 if (excludeBranches == null) 516 { 517 this.excludeBranches = new ArrayList<DN>(0); 518 } 519 else 520 { 521 this.excludeBranches = excludeBranches; 522 } 523 } 524 525 526 527 /** 528 * Retrieves the set of base DNs that specify the set of entries to 529 * include in the export. The list that is returned may be altered 530 * by the caller. 531 * 532 * @return The set of base DNs that specify the set of entries to 533 * include in the export. 534 */ 535 public List<DN> getIncludeBranches() 536 { 537 return includeBranches; 538 } 539 540 541 542 /** 543 * Specifies the set of base DNs that specify the set of entries to 544 * include in the export. 545 * 546 * @param includeBranches The set of base DNs that specify the set 547 * of entries to include in the export. 548 */ 549 public void setIncludeBranches(List<DN> includeBranches) 550 { 551 if (includeBranches == null) 552 { 553 this.includeBranches = new ArrayList<DN>(0); 554 } 555 else 556 { 557 this.includeBranches = includeBranches; 558 } 559 } 560 561 562 563 /** 564 * Indicates whether the set of objectclasses should be included in 565 * the entries written to LDIF. 566 * 567 * @return <CODE>true</CODE> if the set of objectclasses should be 568 * included in the entries written to LDIF, or 569 * <CODE>false</CODE> if not. 570 */ 571 public boolean includeObjectClasses() 572 { 573 return includeObjectClasses; 574 } 575 576 577 578 /** 579 * Indicates whether the set of operational attributes should be 580 * included in the export. 581 * 582 * @return <CODE>true</CODE> if the set of operational attributes 583 * should be included in the export. 584 */ 585 public boolean includeOperationalAttributes() 586 { 587 return includeOperationalAttributes; 588 } 589 590 591 592 /** 593 * Specifies whether the objectclasss attribute should be 594 * included in the export. 595 * 596 * @param includeObjectClasses Specifies whether the 597 * objectclass attribute 598 * should be included in the 599 * export. 600 */ 601 public void setIncludeObjectClasses( 602 boolean includeObjectClasses) 603 { 604 this.includeObjectClasses = includeObjectClasses; 605 } 606 607 /** 608 * Specifies whether the set of operational attributes should be 609 * included in the export. 610 * 611 * @param includeOperationalAttributes Specifies whether the set 612 * of operational attributes 613 * should be included in the 614 * export. 615 */ 616 public void setIncludeOperationalAttributes( 617 boolean includeOperationalAttributes) 618 { 619 this.includeOperationalAttributes = includeOperationalAttributes; 620 } 621 622 623 624 /** 625 * Indicates whether virtual attributes should be included in the 626 * export. 627 * 628 * @return {@code true} if virtual attributes should be included in 629 * the export, or {@code false} if not. 630 */ 631 public boolean includeVirtualAttributes() 632 { 633 return includeVirtualAttributes; 634 } 635 636 637 638 /** 639 * Specifies whether virtual attributes should be included in the 640 * export. 641 * 642 * @param includeVirtualAttributes Specifies whether virtual 643 * attributes should be included 644 * in the export. 645 */ 646 public void setIncludeVirtualAttributes( 647 boolean includeVirtualAttributes) 648 { 649 this.includeVirtualAttributes = includeVirtualAttributes; 650 } 651 652 653 654 /** 655 * Retrieves the set of attributes that should be excluded from the 656 * entries written to LDIF. The set that is returned may be altered 657 * by the caller. 658 * 659 * @return The set of attributes that should be excluded from the 660 * entries written to LDIF. 661 */ 662 public Set<AttributeType> getExcludeAttributes() 663 { 664 return excludeAttributes; 665 } 666 667 668 669 /** 670 * Specifies the set of attributes that should be excluded from the 671 * entries written to LDIF. 672 * 673 * @param excludeAttributes The set of attributes that should be 674 * excluded from the entries written to 675 * LDIF. 676 */ 677 public void setExcludeAttributes( 678 Set<AttributeType> excludeAttributes) 679 { 680 if (excludeAttributes == null) 681 { 682 this.excludeAttributes = new HashSet<AttributeType>(0); 683 } 684 else 685 { 686 this.excludeAttributes = excludeAttributes; 687 } 688 } 689 690 691 692 /** 693 * Retrieves the set of attributes that should be included in the 694 * entries written to LDIF. The set that is returned may be altered 695 * by the caller. 696 * 697 * @return The set of attributes that should be included in the 698 * entries written to LDIF. 699 */ 700 public Set<AttributeType> getIncludeAttributes() 701 { 702 return includeAttributes; 703 } 704 705 706 707 /** 708 * Specifies the set of attributes that should be included in the 709 * entries written to LDIF. 710 * 711 * @param includeAttributes The set of attributes that should be 712 * included in the entries written to 713 * LDIF. 714 */ 715 public void setIncludeAttributes( 716 Set<AttributeType> includeAttributes) 717 { 718 if (includeAttributes == null) 719 { 720 this.includeAttributes = new HashSet<AttributeType>(0); 721 } 722 else 723 { 724 this.includeAttributes = includeAttributes; 725 } 726 } 727 728 729 730 /** 731 * Indicates whether the specified attribute should be included in 732 * the entries written to LDIF. 733 * 734 * @param attributeType The attribute type for which to make the 735 * determination. 736 * 737 * @return <CODE>true</CODE> if the specified attribute should be 738 * included in the entries written to LDIF, or 739 * <CODE>false</CODE> if not. 740 */ 741 public boolean includeAttribute(AttributeType attributeType) 742 { 743 if ((! excludeAttributes.isEmpty()) && 744 excludeAttributes.contains(attributeType)) 745 { 746 return false; 747 } 748 749 if (! includeAttributes.isEmpty()) 750 { 751 return includeAttributes.contains(attributeType); 752 } 753 754 return true; 755 } 756 757 758 759 /** 760 * Retrieves the set of search filters that should be used to 761 * determine which entries to exclude from the LDIF. The list that 762 * is returned may be altered by the caller. 763 * 764 * @return The set of search filters that should be used to 765 * determine which entries to exclude from the LDIF. 766 */ 767 public List<SearchFilter> getExcludeFilters() 768 { 769 return excludeFilters; 770 } 771 772 773 774 /** 775 * Specifies the set of search filters that should be used to 776 * determine which entries to exclude from the LDIF. 777 * 778 * @param excludeFilters The set of search filters that should be 779 * used to determine which entries to 780 * exclude from the LDIF. 781 */ 782 public void setExcludeFilters(List<SearchFilter> excludeFilters) 783 { 784 if (excludeFilters == null) 785 { 786 this.excludeFilters = new ArrayList<SearchFilter>(0); 787 } 788 else 789 { 790 this.excludeFilters = excludeFilters; 791 } 792 } 793 794 795 796 /** 797 * Retrieves the set of search filters that should be used to 798 * determine which entries to include in the LDIF. The list that is 799 * returned may be altered by the caller. 800 * 801 * @return The set of search filters that should be used to 802 * determine which entries to include in the LDIF. 803 */ 804 public List<SearchFilter> getIncludeFilters() 805 { 806 return includeFilters; 807 } 808 809 810 811 /** 812 * Specifies the set of search filters that should be used to 813 * determine which entries to include in the LDIF. 814 * 815 * @param includeFilters The set of search filters that should be 816 * used to determine which entries to 817 * include in the LDIF. 818 */ 819 public void setIncludeFilters(List<SearchFilter> includeFilters) 820 { 821 if (includeFilters == null) 822 { 823 this.includeFilters = new ArrayList<SearchFilter>(0); 824 } 825 else 826 { 827 this.includeFilters = includeFilters; 828 } 829 } 830 831 832 833 /** 834 * Indicates whether the specified entry should be included in the 835 * export based on the configured set of include and exclude 836 * filters. 837 * 838 * @param entry The entry for which to make the determination. 839 * 840 * @return <CODE>true</CODE> if the specified entry should be 841 * included in the export, or <CODE>false</CODE> if not. 842 * 843 * @throws DirectoryException If there is a problem with any of 844 * the search filters used to make the 845 * determination. 846 */ 847 public boolean includeEntry(Entry entry) 848 throws DirectoryException 849 { 850 DN dn = entry.getDN(); 851 if (! excludeBranches.isEmpty()) 852 { 853 for (DN excludeBranch : excludeBranches) 854 { 855 if (excludeBranch.isAncestorOf(dn)) 856 { 857 return false; 858 } 859 } 860 } 861 862 checkIncludeBranches: if (! includeBranches.isEmpty()) 863 { 864 for (DN includeBranch : includeBranches) 865 { 866 if (includeBranch.isAncestorOf(dn)) 867 { 868 break checkIncludeBranches; 869 } 870 } 871 872 return false; 873 } 874 875 if (! excludeFilters.isEmpty()) 876 { 877 for (SearchFilter filter : excludeFilters) 878 { 879 if (filter.matchesEntry(entry)) 880 { 881 return false; 882 } 883 } 884 } 885 886 if (! includeFilters.isEmpty()) 887 { 888 for (SearchFilter filter : includeFilters) 889 { 890 if (filter.matchesEntry(entry)) 891 { 892 return true; 893 } 894 } 895 896 return false; 897 } 898 899 return true; 900 } 901 902 903 904 /** 905 * Closes any resources that this export config might have open. 906 */ 907 public void close() 908 { 909 // FIXME -- Need to add code to generate a signed hash of the LDIF 910 // content. 911 912 try 913 { 914 writer.close(); 915 } 916 catch (Exception e) 917 { 918 if (debugEnabled()) 919 { 920 TRACER.debugCaught(DebugLogLevel.ERROR, e); 921 } 922 } 923 } 924 } 925 926