/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at
* trunk/opends/resource/legal-notices/OpenDS.LICENSE
* or https://OpenDS.dev.java.net/OpenDS.LICENSE.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at
* trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
* add the following below this CDDL HEADER, with the fields enclosed
* by brackets "[]" replaced with your own identifying information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*
* Copyright 2006-2009 Sun Microsystems, Inc.
* Portions Copyright 2013 ForgeRock AS.
*/
package org.opends.server.types;
import static org.opends.messages.UtilityMessages.*;
import static org.opends.server.loggers.debug.DebugLogger.*;
import static org.opends.server.util.StaticUtils.*;
import java.io.*;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.zip.GZIPOutputStream;
import org.opends.messages.Message;
import org.opends.server.loggers.debug.DebugTracer;
/**
* This class defines a data structure for holding configuration
* information to use when performing an LDIF export.
*/
@org.opends.server.types.PublicAPI(
stability=org.opends.server.types.StabilityLevel.VOLATILE,
mayInstantiate=true,
mayExtend=false,
mayInvoke=true)
public final class LDIFExportConfig extends OperationConfig
implements Closeable
{
/**
* The tracer object for the debug logger.
*/
private static final DebugTracer TRACER = getTracer();
// Indicates whether the data should be compressed as it is written.
private boolean compressData;
// Indicates whether the data should be encrypted as it is written.
private boolean encryptData;
// Indicates whether we should exclude operational attributes.
private boolean excludeOperationalAttributes;
// Indicates whether to generate a cryptographic hash of the data as
// it is // written.
private boolean hashData;
// Indicates whether to include the objectclasses in the entries
// written in the export.
private boolean includeObjectClasses;
// Indicates whether to include operational attributes in the
// export.
private boolean includeOperationalAttributes;
// Indicates whether to include virutal attributes in the export.
private boolean includeVirtualAttributes;
// Indicates whether to invoke LDIF export plugins on entries being
// exported.
private boolean invokeExportPlugins;
// Indicates whether to digitally sign the hash when the export is
// complete.
private boolean signHash;
// Indicates whether to include attribute types (i.e., names) only
// or both types and values.
private boolean typesOnly;
// The buffered writer to which the LDIF data should be written.
private BufferedWriter writer;
// The behavior that should be used when writing an LDIF file and a
// file with the same name already exists.
private ExistingFileBehavior existingFileBehavior;
// The column number at which long lines should be wrapped.
private int wrapColumn;
// The set of base DNs to exclude from the export.
private List<DN> excludeBranches;
// The set of base DNs to include from the export.
private List<DN> includeBranches;
// The set of search filters for entries to exclude from the export.
private List<SearchFilter> excludeFilters;
// The set of search filters for entries to include in the export.
private List<SearchFilter> includeFilters;
// The output stream to which the LDIF data should be written.
private OutputStream ldifOutputStream;
// The set of attribute types that should be excluded from the
// export.
private Set<AttributeType> excludeAttributes;
// The set of attribute types that should be included in the export.
private Set<AttributeType> includeAttributes;
// The path to the LDIF file that should be written.
private String ldifFile;
/**
* Creates a new LDIF export configuration that will write to the
* specified LDIF file.
*
* @param ldifFile The path to the LDIF file to
* export.
* @param existingFileBehavior Indicates how to proceed if the
* specified file already exists.
*/
public LDIFExportConfig(String ldifFile,
ExistingFileBehavior existingFileBehavior)
{
this.ldifFile = ldifFile;
this.existingFileBehavior = existingFileBehavior;
ldifOutputStream = null;
excludeBranches = new ArrayList<DN>();
includeBranches = new ArrayList<DN>();
excludeFilters = new ArrayList<SearchFilter>();
includeFilters = new ArrayList<SearchFilter>();
compressData = false;
encryptData = false;
excludeOperationalAttributes = false;
hashData = false;
includeObjectClasses = true;
includeOperationalAttributes = true;
includeVirtualAttributes = false;
invokeExportPlugins = false;
signHash = false;
typesOnly = false;
writer = null;
excludeAttributes = new HashSet<AttributeType>();
includeAttributes = new HashSet<AttributeType>();
wrapColumn = -1;
}
/**
* Creates a new LDIF export configuration that will write to the
* provided output stream.
*
* @param ldifOutputStream The output stream to which the LDIF
* data should be written.
*/
public LDIFExportConfig(OutputStream ldifOutputStream)
{
this.ldifOutputStream = ldifOutputStream;
ldifFile = null;
existingFileBehavior = ExistingFileBehavior.FAIL;
excludeBranches = new ArrayList<DN>();
includeBranches = new ArrayList<DN>();
excludeFilters = new ArrayList<SearchFilter>();
includeFilters = new ArrayList<SearchFilter>();
compressData = false;
encryptData = false;
hashData = false;
includeObjectClasses = true;
includeOperationalAttributes = true;
includeVirtualAttributes = false;
invokeExportPlugins = false;
signHash = false;
typesOnly = false;
writer = null;
excludeAttributes = new HashSet<AttributeType>();
includeAttributes = new HashSet<AttributeType>();
wrapColumn = -1;
}
/**
* Retrieves the writer that should be used to write the LDIF data.
* If compression or encryption are to be used, then they must be
* enabled before the first call to this method.
*
* @return The writer that should be used to write the LDIF data.
*
* @throws IOException If a problem occurs while preparing the
* writer.
*/
public BufferedWriter getWriter()
throws IOException
{
if (writer == null)
{
if (ldifOutputStream == null)
{
File f = new File(ldifFile);
boolean mustSetPermissions = false;
switch (existingFileBehavior)
{
case APPEND:
// Create new file if it doesn't exist ensuring that we can
// set its permissions.
if (!f.exists())
{
f.createNewFile();
mustSetPermissions = true;
}
ldifOutputStream = new FileOutputStream(ldifFile, true);
break;
case OVERWRITE:
// Create new file if it doesn't exist ensuring that we can
// set its permissions.
if (!f.exists())
{
f.createNewFile();
mustSetPermissions = true;
}
ldifOutputStream = new FileOutputStream(ldifFile, false);
break;
case FAIL:
if (f.exists())
{
Message message = ERR_LDIF_FILE_EXISTS.get(ldifFile);
throw new IOException(message.toString());
}
else
{
// Create new file ensuring that we can set its
// permissions.
f.createNewFile();
mustSetPermissions = true;
ldifOutputStream = new FileOutputStream(ldifFile);
}
break;
}
if (mustSetPermissions)
{
try
{
// Ignore
FilePermission.setPermissions(f,
new FilePermission(0600));
}
catch (Exception e)
{
// The file could not be created with the correct
// permissions.
Message message =
WARN_EXPORT_LDIF_SET_PERMISSION_FAILED.get(f.toString(),
stackTraceToSingleLineString(e));
throw new IOException(message.toString());
}
}
}
// See if we should compress the output.
OutputStream outputStream;
if (compressData)
{
outputStream = new GZIPOutputStream(ldifOutputStream);
}
else
{
outputStream = ldifOutputStream;
}
// See if we should encrypt the output.
if (encryptData)
{
// FIXME -- Implement this.
}
// Create the writer.
writer =
new BufferedWriter(new OutputStreamWriter(outputStream));
}
return writer;
}
/**
* Indicates whether the LDIF export plugins should be invoked for
* entries as they are exported.
*
* @return <CODE>true</CODE> if LDIF export plugins should be
* invoked for entries as they are exported, or
* <CODE>false</CODE> if not.
*/
public boolean invokeExportPlugins()
{
return invokeExportPlugins;
}
/**
* Specifies whether the LDIF export plugins should be invoked for
* entries as they are exported.
*
* @param invokeExportPlugins Specifies whether the LDIF export
* plugins should be invoked for
* entries as they are exported.
*/
public void setInvokeExportPlugins(boolean invokeExportPlugins)
{
this.invokeExportPlugins = invokeExportPlugins;
}
/**
* Indicates whether the LDIF data should be compressed as it is
* written.
*
* @return <CODE>true</CODE> if the LDIF data should be compressed
* as it is written, or <CODE>false</CODE> if not.
*/
public boolean compressData()
{
return compressData;
}
/**
* Specifies whether the LDIF data should be compressed as it is
* written. If compression should be used, then this must be set
* before calling <CODE>getWriter</CODE> for the first time.
*
* @param compressData Indicates whether the LDIF data should be
* compressed as it is written.
*/
public void setCompressData(boolean compressData)
{
this.compressData = compressData;
}
/**
* Indicates whether the LDIF data should be encrypted as it is
* written.
*
* @return <CODE>true</CODE> if the LDIF data should be encrypted
* as it is written, or <CODE>false</CODE> if not.
*/
public boolean encryptData()
{
return encryptData;
}
/**
* Specifies whether the LDIF data should be encrypted as it is
* written. If encryption should be used, then this must be set
* before calling <CODE>getWriter</CODE> for the first time.
*
* @param encryptData Indicates whether the LDIF data should be
* encrypted as it is written.
*/
public void setEncryptData(boolean encryptData)
{
this.encryptData = encryptData;
}
/**
* Indicates whether to generate a cryptographic hash of the data
* that is written.
*
* @return <CODE>true</CODE> if a hash should be generated as the
* data is written, or <CODE>false</CODE> if not.
*/
public boolean hashData()
{
return hashData;
}
/**
* Specifies whether to generate a cryptographic hash of the data
* that is written. If hashing is to be used, then this must be set
* before calling <CODE>getWriter</CODE> for the first time.
*
* @param hashData Indicates whether to generate a hash of the
* data as it is written.
*/
public void setHashData(boolean hashData)
{
this.hashData = hashData;
}
/**
* Indicates whether to sign the cryptographic hash of the data that
* is written when the export is complete.
*
* @return <CODE>true</CODE> if the hash should be signed when the
* export is complete, or <CODE>false</CODE> if not.
*/
public boolean signHash()
{
return signHash;
}
/**
* Specifies whether to sign the cryptographic hash of the data that
* is written when the export is complete. If the export is not
* configured to generate a hash, then this will be ignored. If
* hashing is to be used and the hash should be signed, then this
* must be set before calling <CODE>getWriter</CODE> for the first
* time.
*
* @param signHash Indicates whether to generate a hash of the
* data as it is written.
*/
public void setSignHash(boolean signHash)
{
this.signHash = signHash;
}
/**
* Indicates whether the LDIF generated should include attribute
* types (i.e., attribute names) only or both attribute types and
* values.
*
* @return <CODE>true</CODE> if only attribute types should be
* included in the resulting LDIF, or <CODE>false</CODE> if
* both types and values should be included.
*/
public boolean typesOnly()
{
return typesOnly;
}
/**
* Specifies whether the LDIF generated should include attribute
* types (i.e., attribute names) only or both attribute types and
* values.
*
* @param typesOnly Specifies whether the LDIF generated should
* include attribute types only or both attribute
* types and values.
*/
public void setTypesOnly(boolean typesOnly)
{
this.typesOnly = typesOnly;
}
/**
* Retrieves the column at which long lines should be wrapped.
*
* @return The column at which long lines should be wrapped, or a
* value less than or equal to zero to indicate that no
* wrapping should be performed.
*/
public int getWrapColumn()
{
return wrapColumn;
}
/**
* Specifies the column at which long lines should be wrapped. A
* value less than or equal to zero indicates that no wrapping
* should be performed.
*
* @param wrapColumn The column at which long lines should be
* wrapped.
*/
public void setWrapColumn(int wrapColumn)
{
this.wrapColumn = wrapColumn;
}
/**
* Retrieves the set of base DNs that specify the set of entries to
* exclude from the export. The list that is returned may be
* altered by the caller.
*
* @return The set of base DNs that specify the set of entries to
* exclude from the export.
*/
public List<DN> getExcludeBranches()
{
return excludeBranches;
}
/**
* Specifies the set of base DNs that specify the set of entries to
* exclude from the export.
*
* @param excludeBranches The set of base DNs that specify the set
* of entries to exclude from the export.
*/
public void setExcludeBranches(List<DN> excludeBranches)
{
if (excludeBranches == null)
{
this.excludeBranches = new ArrayList<DN>(0);
}
else
{
this.excludeBranches = excludeBranches;
}
}
/**
* Retrieves the set of base DNs that specify the set of entries to
* include in the export. The list that is returned may be altered
* by the caller.
*
* @return The set of base DNs that specify the set of entries to
* include in the export.
*/
public List<DN> getIncludeBranches()
{
return includeBranches;
}
/**
* Specifies the set of base DNs that specify the set of entries to
* include in the export.
*
* @param includeBranches The set of base DNs that specify the set
* of entries to include in the export.
*/
public void setIncludeBranches(List<DN> includeBranches)
{
if (includeBranches == null)
{
this.includeBranches = new ArrayList<DN>(0);
}
else
{
this.includeBranches = includeBranches;
}
}
/**
* Indicates whether the set of objectclasses should be included in
* the entries written to LDIF.
*
* @return <CODE>true</CODE> if the set of objectclasses should be
* included in the entries written to LDIF, or
* <CODE>false</CODE> if not.
*/
public boolean includeObjectClasses()
{
return includeObjectClasses;
}
/**
* Indicates whether the set of operational attributes should be
* included in the export.
*
* @return <CODE>true</CODE> if the set of operational attributes
* should be included in the export.
*/
public boolean includeOperationalAttributes()
{
return includeOperationalAttributes;
}
/**
* Specifies whether the objectclasss attribute should be
* included in the export.
*
* @param includeObjectClasses Specifies whether the
* objectclass attribute
* should be included in the
* export.
*/
public void setIncludeObjectClasses(
boolean includeObjectClasses)
{
this.includeObjectClasses = includeObjectClasses;
}
/**
* Specifies whether the set of operational attributes should be
* included in the export.
*
* @param includeOperationalAttributes Specifies whether the set
* of operational attributes
* should be included in the
* export.
*/
public void setIncludeOperationalAttributes(
boolean includeOperationalAttributes)
{
this.includeOperationalAttributes = includeOperationalAttributes;
}
/**
* Indicates whether virtual attributes should be included in the
* export.
*
* @return {@code true} if virtual attributes should be included in
* the export, or {@code false} if not.
*/
public boolean includeVirtualAttributes()
{
return includeVirtualAttributes;
}
/**
* Specifies whether virtual attributes should be included in the
* export.
*
* @param includeVirtualAttributes Specifies whether virtual
* attributes should be included
* in the export.
*/
public void setIncludeVirtualAttributes(
boolean includeVirtualAttributes)
{
this.includeVirtualAttributes = includeVirtualAttributes;
}
/**
* Retrieves the set of attributes that should be excluded from the
* entries written to LDIF. The set that is returned may be altered
* by the caller.
*
* @return The set of attributes that should be excluded from the
* entries written to LDIF.
*/
public Set<AttributeType> getExcludeAttributes()
{
return excludeAttributes;
}
/**
* Specifies the set of attributes that should be excluded from the
* entries written to LDIF.
*
* @param excludeAttributes The set of attributes that should be
* excluded from the entries written to
* LDIF.
*/
public void setExcludeAttributes(
Set<AttributeType> excludeAttributes)
{
if (excludeAttributes == null)
{
this.excludeAttributes = new HashSet<AttributeType>(0);
}
else
{
this.excludeAttributes = excludeAttributes;
}
}
/**
* Retrieves the set of attributes that should be included in the
* entries written to LDIF. The set that is returned may be altered
* by the caller.
*
* @return The set of attributes that should be included in the
* entries written to LDIF.
*/
public Set<AttributeType> getIncludeAttributes()
{
return includeAttributes;
}
/**
* Specifies the set of attributes that should be included in the
* entries written to LDIF.
*
* @param includeAttributes The set of attributes that should be
* included in the entries written to
* LDIF.
*/
public void setIncludeAttributes(
Set<AttributeType> includeAttributes)
{
if (includeAttributes == null)
{
this.includeAttributes = new HashSet<AttributeType>(0);
}
else
{
this.includeAttributes = includeAttributes;
}
}
/**
* Indicates whether the specified attribute should be included in
* the entries written to LDIF.
*
* @param attributeType The attribute type for which to make the
* determination.
*
* @return <CODE>true</CODE> if the specified attribute should be
* included in the entries written to LDIF, or
* <CODE>false</CODE> if not.
*/
public boolean includeAttribute(AttributeType attributeType)
{
if ((! excludeAttributes.isEmpty()) &&
excludeAttributes.contains(attributeType))
{
return false;
}
return includeAttributes.isEmpty() ||
includeAttributes.contains(attributeType);
}
/**
* Retrieves the set of search filters that should be used to
* determine which entries to exclude from the LDIF. The list that
* is returned may be altered by the caller.
*
* @return The set of search filters that should be used to
* determine which entries to exclude from the LDIF.
*/
public List<SearchFilter> getExcludeFilters()
{
return excludeFilters;
}
/**
* Specifies the set of search filters that should be used to
* determine which entries to exclude from the LDIF.
*
* @param excludeFilters The set of search filters that should be
* used to determine which entries to
* exclude from the LDIF.
*/
public void setExcludeFilters(List<SearchFilter> excludeFilters)
{
if (excludeFilters == null)
{
this.excludeFilters = new ArrayList<SearchFilter>(0);
}
else
{
this.excludeFilters = excludeFilters;
}
}
/**
* Retrieves the set of search filters that should be used to
* determine which entries to include in the LDIF. The list that is
* returned may be altered by the caller.
*
* @return The set of search filters that should be used to
* determine which entries to include in the LDIF.
*/
public List<SearchFilter> getIncludeFilters()
{
return includeFilters;
}
/**
* Specifies the set of search filters that should be used to
* determine which entries to include in the LDIF.
*
* @param includeFilters The set of search filters that should be
* used to determine which entries to
* include in the LDIF.
*/
public void setIncludeFilters(List<SearchFilter> includeFilters)
{
if (includeFilters == null)
{
this.includeFilters = new ArrayList<SearchFilter>(0);
}
else
{
this.includeFilters = includeFilters;
}
}
/**
* Indicates whether the specified entry should be included in the
* export based on the configured set of include and exclude
* filters.
*
* @param entry The entry for which to make the determination.
*
* @return <CODE>true</CODE> if the specified entry should be
* included in the export, or <CODE>false</CODE> if not.
*
* @throws DirectoryException If there is a problem with any of
* the search filters used to make the
* determination.
*/
public boolean includeEntry(Entry entry)
throws DirectoryException
{
DN dn = entry.getDN();
if (! excludeBranches.isEmpty())
{
for (DN excludeBranch : excludeBranches)
{
if (excludeBranch.isAncestorOf(dn))
{
return false;
}
}
}
checkIncludeBranches: if (! includeBranches.isEmpty())
{
for (DN includeBranch : includeBranches)
{
if (includeBranch.isAncestorOf(dn))
{
break checkIncludeBranches;
}
}
return false;
}
if (! excludeFilters.isEmpty())
{
for (SearchFilter filter : excludeFilters)
{
if (filter.matchesEntry(entry))
{
return false;
}
}
}
if (! includeFilters.isEmpty())
{
for (SearchFilter filter : includeFilters)
{
if (filter.matchesEntry(entry))
{
return true;
}
}
return false;
}
return true;
}
/**
* Closes any resources that this export config might have open.
*/
public void close()
{
// FIXME -- Need to add code to generate a signed hash of the LDIF
// content.
if (writer != null) {
try
{
writer.close();
}
catch (Exception e)
{
if (debugEnabled())
{
TRACER.debugCaught(DebugLogLevel.ERROR, e);
}
}
}
}
}