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