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 legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2009-2010 Sun Microsystems, Inc. 025 * Portions copyright 2012-2013 ForgeRock AS. 026 */ 027 028package org.forgerock.opendj.ldif; 029 030import java.io.IOException; 031import java.io.OutputStream; 032import java.io.StringWriter; 033import java.io.Writer; 034import java.util.List; 035 036import org.forgerock.opendj.ldap.Attribute; 037import org.forgerock.opendj.ldap.AttributeDescription; 038import org.forgerock.opendj.ldap.ByteString; 039import org.forgerock.opendj.ldap.DN; 040import org.forgerock.opendj.ldap.Entry; 041import org.forgerock.opendj.ldap.Matcher; 042 043import org.forgerock.util.Reject; 044 045/** 046 * An LDIF entry writer writes attribute value records (entries) using the LDAP 047 * Data Interchange Format (LDIF) to a user defined destination. 048 * 049 * @see <a href="http://tools.ietf.org/html/rfc2849">RFC 2849 - The LDAP Data 050 * Interchange Format (LDIF) - Technical Specification </a> 051 */ 052public final class LDIFEntryWriter extends AbstractLDIFWriter implements EntryWriter { 053 054 /** 055 * Returns the LDIF string representation of the provided entry. 056 * 057 * @param entry 058 * The entry. 059 * @return The LDIF string representation of the provided entry. 060 */ 061 public static String toString(final Entry entry) { 062 final StringWriter writer = new StringWriter(128); 063 try { 064 new LDIFEntryWriter(writer).setAddUserFriendlyComments(true).writeEntry(entry).close(); 065 } catch (final IOException e) { 066 // Should never happen. 067 throw new IllegalStateException(e); 068 } 069 return writer.toString(); 070 } 071 072 /** 073 * Creates a new LDIF entry writer which will append lines of LDIF to the 074 * provided list. 075 * 076 * @param ldifLines 077 * The list to which lines of LDIF should be appended. 078 */ 079 public LDIFEntryWriter(final List<String> ldifLines) { 080 super(ldifLines); 081 } 082 083 /** 084 * Creates a new LDIF entry writer whose destination is the provided output 085 * stream. 086 * 087 * @param out 088 * The output stream to use. 089 */ 090 public LDIFEntryWriter(final OutputStream out) { 091 super(out); 092 } 093 094 /** 095 * Creates a new LDIF entry writer whose destination is the provided 096 * character stream writer. 097 * 098 * @param writer 099 * The character stream writer to use. 100 */ 101 public LDIFEntryWriter(final Writer writer) { 102 super(writer); 103 } 104 105 /** {@inheritDoc} */ 106 @Override 107 public void close() throws IOException { 108 close0(); 109 } 110 111 /** {@inheritDoc} */ 112 @Override 113 public void flush() throws IOException { 114 flush0(); 115 } 116 117 /** 118 * Specifies whether or not user-friendly comments should be added whenever 119 * distinguished names or UTF-8 attribute values are encountered which 120 * contained non-ASCII characters. The default is {@code false}. 121 * 122 * @param addUserFriendlyComments 123 * {@code true} if user-friendly comments should be added, or 124 * {@code false} otherwise. 125 * @return A reference to this {@code LDIFEntryWriter}. 126 */ 127 public LDIFEntryWriter setAddUserFriendlyComments(final boolean addUserFriendlyComments) { 128 this.addUserFriendlyComments = addUserFriendlyComments; 129 return this; 130 } 131 132 /** 133 * Specifies whether or not all operational attributes should be excluded 134 * from any entries that are written to LDIF. The default is {@code false}. 135 * 136 * @param excludeOperationalAttributes 137 * {@code true} if all operational attributes should be excluded, 138 * or {@code false} otherwise. 139 * @return A reference to this {@code LDIFEntryWriter}. 140 */ 141 public LDIFEntryWriter setExcludeAllOperationalAttributes( 142 final boolean excludeOperationalAttributes) { 143 this.excludeOperationalAttributes = excludeOperationalAttributes; 144 return this; 145 } 146 147 /** 148 * Specifies whether or not all user attributes should be excluded from any 149 * entries that are written to LDIF. The default is {@code false}. 150 * 151 * @param excludeUserAttributes 152 * {@code true} if all user attributes should be excluded, or 153 * {@code false} otherwise. 154 * @return A reference to this {@code LDIFEntryWriter}. 155 */ 156 public LDIFEntryWriter setExcludeAllUserAttributes(final boolean excludeUserAttributes) { 157 this.excludeUserAttributes = excludeUserAttributes; 158 return this; 159 } 160 161 /** 162 * Excludes the named attribute from any entries that are written to LDIF. 163 * By default all attributes are included unless explicitly excluded. 164 * 165 * @param attributeDescription 166 * The name of the attribute to be excluded. 167 * @return A reference to this {@code LDIFEntryWriter}. 168 */ 169 public LDIFEntryWriter setExcludeAttribute(final AttributeDescription attributeDescription) { 170 Reject.ifNull(attributeDescription); 171 excludeAttributes.add(attributeDescription); 172 return this; 173 } 174 175 /** 176 * Excludes all entries beneath the named entry (inclusive) from being 177 * written to LDIF. By default all entries are written unless explicitly 178 * excluded or included by branches or filters. 179 * 180 * @param excludeBranch 181 * The distinguished name of the branch to be excluded. 182 * @return A reference to this {@code LDIFEntryWriter}. 183 */ 184 public LDIFEntryWriter setExcludeBranch(final DN excludeBranch) { 185 Reject.ifNull(excludeBranch); 186 excludeBranches.add(excludeBranch); 187 return this; 188 } 189 190 /** 191 * Excludes all entries which match the provided filter matcher from being 192 * written to LDIF. By default all entries are written unless explicitly 193 * excluded or included by branches or filters. 194 * 195 * @param excludeFilter 196 * The filter matcher. 197 * @return A reference to this {@code LDIFEntryWriter}. 198 */ 199 public LDIFEntryWriter setExcludeFilter(final Matcher excludeFilter) { 200 Reject.ifNull(excludeFilter); 201 excludeFilters.add(excludeFilter); 202 return this; 203 } 204 205 /** 206 * Ensures that the named attribute is not excluded from any entries that 207 * are written to LDIF. By default all attributes are included unless 208 * explicitly excluded. 209 * 210 * @param attributeDescription 211 * The name of the attribute to be included. 212 * @return A reference to this {@code LDIFEntryWriter}. 213 */ 214 public LDIFEntryWriter setIncludeAttribute(final AttributeDescription attributeDescription) { 215 Reject.ifNull(attributeDescription); 216 includeAttributes.add(attributeDescription); 217 return this; 218 } 219 220 /** 221 * Ensures that all entries beneath the named entry (inclusive) are written 222 * to LDIF. By default all entries are written unless explicitly excluded or 223 * included by branches or filters. 224 * 225 * @param includeBranch 226 * The distinguished name of the branch to be included. 227 * @return A reference to this {@code LDIFEntryWriter}. 228 */ 229 public LDIFEntryWriter setIncludeBranch(final DN includeBranch) { 230 Reject.ifNull(includeBranch); 231 includeBranches.add(includeBranch); 232 return this; 233 } 234 235 /** 236 * Ensures that all entries which match the provided filter matcher are 237 * written to LDIF. By default all entries are written unless explicitly 238 * excluded or included by branches or filters. 239 * 240 * @param includeFilter 241 * The filter matcher. 242 * @return A reference to this {@code LDIFEntryWriter}. 243 */ 244 public LDIFEntryWriter setIncludeFilter(final Matcher includeFilter) { 245 Reject.ifNull(includeFilter); 246 includeFilters.add(includeFilter); 247 return this; 248 } 249 250 /** 251 * Specifies the column at which long lines should be wrapped. A value less 252 * than or equal to zero (the default) indicates that no wrapping should be 253 * performed. 254 * 255 * @param wrapColumn 256 * The column at which long lines should be wrapped. 257 * @return A reference to this {@code LDIFEntryWriter}. 258 */ 259 public LDIFEntryWriter setWrapColumn(final int wrapColumn) { 260 this.wrapColumn = wrapColumn; 261 return this; 262 } 263 264 /** {@inheritDoc} */ 265 @Override 266 public LDIFEntryWriter writeComment(final CharSequence comment) throws IOException { 267 writeComment0(comment); 268 return this; 269 } 270 271 /** {@inheritDoc} */ 272 @Override 273 public LDIFEntryWriter writeEntry(final Entry entry) throws IOException { 274 Reject.ifNull(entry); 275 276 // Skip if branch containing the entry is excluded. 277 if (isBranchExcluded(entry.getName())) { 278 return this; 279 } 280 281 // Skip if the entry is excluded by any filters. 282 if (isEntryExcluded(entry)) { 283 return this; 284 } 285 286 writeKeyAndValue("dn", entry.getName().toString()); 287 for (final Attribute attribute : entry.getAllAttributes()) { 288 // Filter the attribute if required. 289 if (isAttributeExcluded(attribute.getAttributeDescription())) { 290 continue; 291 } 292 293 final String attributeDescription = attribute.getAttributeDescriptionAsString(); 294 if (attribute.isEmpty()) { 295 writeKeyAndValue(attributeDescription, ByteString.empty()); 296 } else { 297 for (final ByteString value : attribute) { 298 writeKeyAndValue(attributeDescription, value); 299 } 300 } 301 } 302 303 // Make sure there is a blank line after the entry. 304 impl.println(); 305 306 return this; 307 } 308}