opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/AbstractLDIFReader.java
@@ -22,18 +22,31 @@ * * * Copyright 2009-2010 Sun Microsystems, Inc. * Portions copyright 2011 ForgeRock AS * Portions copyright 2011-2013 ForgeRock AS */ package org.forgerock.opendj.ldif; import static com.forgerock.opendj.util.StaticUtils.toLowerCase; import static org.forgerock.opendj.ldap.CoreMessages.*; import static org.forgerock.opendj.ldap.CoreMessages.ERR_LDIF_COULD_NOT_BASE64_DECODE_ATTR; import static org.forgerock.opendj.ldap.CoreMessages.ERR_LDIF_COULD_NOT_BASE64_DECODE_DN; import static org.forgerock.opendj.ldap.CoreMessages.ERR_LDIF_INVALID_DN; import static org.forgerock.opendj.ldap.CoreMessages.ERR_LDIF_INVALID_LEADING_SPACE; import static org.forgerock.opendj.ldap.CoreMessages.ERR_LDIF_INVALID_URL; import static org.forgerock.opendj.ldap.CoreMessages.ERR_LDIF_MALFORMED_ATTRIBUTE_NAME; import static org.forgerock.opendj.ldap.CoreMessages.ERR_LDIF_MULTI_VALUED_SINGLE_VALUED_ATTRIBUTE; import static org.forgerock.opendj.ldap.CoreMessages.ERR_LDIF_NO_ATTR_NAME; import static org.forgerock.opendj.ldap.CoreMessages.ERR_LDIF_NO_DN; import static org.forgerock.opendj.ldap.CoreMessages.ERR_LDIF_UNEXPECTED_BINARY_OPTION; import static org.forgerock.opendj.ldap.CoreMessages.ERR_LDIF_UNKNOWN_ATTRIBUTE_TYPE; import static org.forgerock.opendj.ldap.CoreMessages.ERR_LDIF_URL_IO_ERROR; import static org.forgerock.opendj.ldap.CoreMessages.WARN_LDIF_DUPLICATE_ATTRIBUTE_VALUE; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.net.URL; import java.util.Iterator; import java.util.LinkedList; @@ -63,7 +76,6 @@ abstract class AbstractLDIFReader extends AbstractLDIFStream { static final class KeyValuePair { String key; String value; } @@ -94,9 +106,7 @@ static final class LDIFRecord { final Iterator<String> iterator; final LinkedList<String> ldifLines; final long lineNumber; private LDIFRecord(final long lineNumber, final LinkedList<String> ldifLines) { @@ -110,22 +120,15 @@ * LDIF output stream writer implementation. */ private static final class LDIFReaderInputStreamImpl implements LDIFReaderImpl { private BufferedReader reader; /** * Creates a new LDIF input stream reader implementation. * * @param in * The input stream to use. */ LDIFReaderInputStreamImpl(final InputStream in) { this.reader = new BufferedReader(new InputStreamReader(in)); LDIFReaderInputStreamImpl(final Reader reader) { this.reader = reader instanceof BufferedReader ? (BufferedReader) reader : new BufferedReader(reader); } /** * {@inheritDoc} */ @Override public void close() throws IOException { if (reader != null) { reader.close(); @@ -133,9 +136,7 @@ } } /** * {@inheritDoc} */ @Override public String readLine() throws IOException { String line = null; if (reader != null) { @@ -153,29 +154,18 @@ * LDIF output stream writer implementation. */ private static final class LDIFReaderListImpl implements LDIFReaderImpl { private final Iterator<String> iterator; /** * Creates a new LDIF list reader. * * @param ldifLines * The string list. */ LDIFReaderListImpl(final List<String> ldifLines) { this.iterator = ldifLines.iterator(); } /** * {@inheritDoc} */ @Override public void close() throws IOException { // Nothing to do. } /** * {@inheritDoc} */ @Override public String readLine() throws IOException { if (iterator.hasNext()) { return iterator.next(); @@ -186,43 +176,50 @@ } RejectedLDIFListener rejectedRecordListener = RejectedLDIFListener.FAIL_FAST; Schema schema = Schema.getDefaultSchema().asNonStrictSchema(); SchemaValidationPolicy schemaValidationPolicy = SchemaValidationPolicy.ignoreAll(); private final LDIFReaderImpl impl; private long lineNumber = 0; /** * Creates a new LDIF entry reader whose source is the provided input * stream. * * @param in * The input stream to use. */ AbstractLDIFReader(final InputStream in) { Validator.ensureNotNull(in); this.impl = new LDIFReaderInputStreamImpl(in); this(new InputStreamReader(in)); } /** * Creates a new LDIF entry reader which will read lines of LDIF from the * provided list. * * @param ldifLines * The list from which lines of LDIF should be read. */ AbstractLDIFReader(final List<String> ldifLines) { Validator.ensureNotNull(ldifLines); this.impl = new LDIFReaderListImpl(ldifLines); } AbstractLDIFReader(final Reader reader) { this.impl = new LDIFReaderInputStreamImpl(reader); } final void close0() throws IOException { impl.close(); } final void handleMalformedRecord(final LDIFRecord record, final LocalizableMessage message) throws DecodeException { rejectedRecordListener.handleMalformedRecord(record.lineNumber, record.ldifLines, message); } final void handleSchemaValidationFailure(final LDIFRecord record, final List<LocalizableMessage> messages) throws DecodeException { rejectedRecordListener.handleSchemaValidationFailure(record.lineNumber, record.ldifLines, messages); } final void handleSchemaValidationWarning(final LDIFRecord record, final List<LocalizableMessage> messages) throws DecodeException { rejectedRecordListener.handleSchemaValidationWarning(record.lineNumber, record.ldifLines, messages); } final void handleSkippedRecord(final LDIFRecord record, final LocalizableMessage message) throws DecodeException { rejectedRecordListener.handleSkippedRecord(record.lineNumber, record.ldifLines, message); } final int parseColonPosition(final LDIFRecord record, final String ldifLine) throws DecodeException { final int colonPos = ldifLine.indexOf(":"); @@ -237,11 +234,12 @@ final ByteString parseSingleValue(final LDIFRecord record, final String ldifLine, final DN entryDN, final int colonPos, final String attrName) throws DecodeException { // Look at the character immediately after the colon. If there is // none, then assume an attribute with an empty value. If it is // another colon, then the value must be base64-encoded. If it is a // less-than sign, then assume that it is a URL. Otherwise, it is a // regular value. /* * Look at the character immediately after the colon. If there is none, * then assume an attribute with an empty value. If it is another colon, * then the value must be base64-encoded. If it is a less-than sign, * then assume that it is a URL. Otherwise, it is a regular value. */ final int length = ldifLine.length(); ByteString value; if (colonPos == length - 1) { @@ -249,8 +247,10 @@ } else { final char c = ldifLine.charAt(colonPos + 1); if (c == ':') { // The value is base64-encoded. Find the first non-blank // character, take the rest of the line, and base64-decode it. /* * The value is base64-encoded. Find the first non-blank * character, take the rest of the line, and base64-decode it. */ int pos = colonPos + 2; while (pos < length && ldifLine.charAt(pos) == ' ') { pos++; @@ -259,15 +259,19 @@ try { value = ByteString.valueOfBase64(ldifLine.substring(pos)); } catch (final LocalizedIllegalArgumentException e) { // The value did not have a valid base64-encoding. /* * The value did not have a valid base64-encoding. */ final LocalizableMessage message = ERR_LDIF_COULD_NOT_BASE64_DECODE_ATTR.get(entryDN.toString(), record.lineNumber, ldifLine, e.getMessageObject()); throw DecodeException.error(message); } } else if (c == '<') { // Find the first non-blank character, decode the rest of the // line as a URL, and read its contents. /* * Find the first non-blank character, decode the rest of the * line as a URL, and read its contents. */ int pos = colonPos + 2; while (pos < length && ldifLine.charAt(pos) == ' ') { pos++; @@ -298,8 +302,10 @@ value = builder.toByteString(); } catch (final Exception e) { // We were unable to read the contents of that URL for some // reason. /* * We were unable to read the contents of that URL for some * reason. */ final LocalizableMessage message = ERR_LDIF_URL_IO_ERROR.get(entryDN.toString(), record.lineNumber, attrName, String.valueOf(contentURL), String.valueOf(e)); @@ -314,8 +320,10 @@ } } } else { // The rest of the line should be the value. Skip over any // spaces and take the rest of the line as the value. /* * The rest of the line should be the value. Skip over any * spaces and take the rest of the line as the value. */ int pos = colonPos + 1; while (pos < length && ldifLine.charAt(pos) == ' ') { pos++; @@ -332,13 +340,11 @@ final StringBuilder lastLineBuilder = new StringBuilder(); final LinkedList<String> ldifLines = new LinkedList<String>(); long recordLineNumber = 0; final int stateStart = 0; final int stateStartCommentLine = 1; final int stateGotLDIFLine = 2; final int stateGotCommentLine = 3; final int appendingLDIFLine = 4; int state = stateStart; while (true) { @@ -355,8 +361,10 @@ // This is a comment at the start of the LDIF record. state = stateStartCommentLine; } else if (isContinuationLine(line)) { // Fatal: got a continuation line at the start of the // record. /* * Fatal: got a continuation line at the start of the * record. */ final LocalizableMessage message = ERR_LDIF_INVALID_LEADING_SPACE.get(lineNumber, line); throw DecodeException.fatalError(message); @@ -473,9 +481,10 @@ schemaErrors.add(message); return true; default: // Ignore // This should not happen: we should be using a non-strict // schema for // this policy. /* * This should not happen: we should be using a non-strict * schema for this policy. */ throw new IllegalStateException("Schema is not consistent with policy", e); } } catch (final LocalizedIllegalArgumentException e) { @@ -489,9 +498,11 @@ final ByteString value = parseSingleValue(record, ldifLine, entry.getName(), colonPos, attrDescr); // Skip the attribute if requested before performing any schema // checking: the attribute may have been excluded because it is // known to violate the schema. /* * Skip the attribute if requested before performing any schema * checking: the attribute may have been excluded because it is known to * violate the schema. */ if (isAttributeExcluded(attributeDescription)) { return true; } @@ -515,7 +526,7 @@ final boolean checkAttributeValues = schemaValidationPolicy.checkAttributeValues().needsChecking(); if (checkAttributeValues) { LocalizableMessageBuilder builder = new LocalizableMessageBuilder(); final LocalizableMessageBuilder builder = new LocalizableMessageBuilder(); if (!syntax.valueIsAcceptable(value, builder)) { schemaErrors.add(builder.toMessage()); if (schemaValidationPolicy.checkAttributeValues().isReject()) { @@ -586,10 +597,11 @@ throw DecodeException.error(message); } // Look at the character immediately after the colon. If there is // none, then assume the null DN. If it is another colon, then the // DN must be base64-encoded. Otherwise, it may be one or more // spaces. /* * Look at the character immediately after the colon. If there is none, * then assume the null DN. If it is another colon, then the DN must be * base64-encoded. Otherwise, it may be one or more spaces. */ final int length = ldifLine.length(); if (colonPos == length - 1) { return DN.rootDN(); @@ -598,8 +610,10 @@ String dnString = null; if (ldifLine.charAt(colonPos + 1) == ':') { // The DN is base64-encoded. Find the first non-blank character // and take the rest of the line and base64-decode it. /* * The DN is base64-encoded. Find the first non-blank character and * take the rest of the line and base64-decode it. */ int pos = colonPos + 2; while (pos < length && ldifLine.charAt(pos) == ' ') { pos++; @@ -616,8 +630,10 @@ throw DecodeException.error(message); } } else { // The rest of the value should be the DN. Skip over any spaces // and attempt to decode the rest of the line as the DN. /* * The rest of the value should be the DN. Skip over any spaces and * attempt to decode the rest of the line as the DN. */ int pos = colonPos + 1; while (pos < length && ldifLine.charAt(pos) == ' ') { pos++; @@ -645,8 +661,10 @@ } pair.key = ldifLine.substring(0, colonPos); // Look at the character immediately after the colon. If there is // none, then no value was specified. Throw an exception /* * Look at the character immediately after the colon. If there is none, * then no value was specified. Throw an exception */ final int length = ldifLine.length(); if (colonPos == length - 1) { pair.key = null; @@ -654,8 +672,10 @@ } if (allowBase64 && ldifLine.charAt(colonPos + 1) == ':') { // The value is base64-encoded. Find the first non-blank // character, take the rest of the line, and base64-decode it. /* * The value is base64-encoded. Find the first non-blank character, * take the rest of the line, and base64-decode it. */ int pos = colonPos + 2; while (pos < length && ldifLine.charAt(pos) == ' ') { pos++; @@ -668,9 +688,11 @@ return ldifLine; } } else { // The rest of the value should be the changetype. Skip over any // spaces and attempt to decode the rest of the line as the // changetype string. /* * The rest of the value should be the changetype. Skip over any * spaces and attempt to decode the rest of the line as the * changetype string. */ int pos = colonPos + 1; while (pos < length && ldifLine.charAt(pos) == ' ') { pos++; @@ -682,33 +704,12 @@ return ldifLine; } final void handleMalformedRecord(final LDIFRecord record, final LocalizableMessage message) throws DecodeException { rejectedRecordListener.handleMalformedRecord(record.lineNumber, record.ldifLines, message); } final void handleSchemaValidationFailure(final LDIFRecord record, final List<LocalizableMessage> messages) throws DecodeException { rejectedRecordListener.handleSchemaValidationFailure(record.lineNumber, record.ldifLines, messages); } final void handleSchemaValidationWarning(final LDIFRecord record, final List<LocalizableMessage> messages) throws DecodeException { rejectedRecordListener.handleSchemaValidationWarning(record.lineNumber, record.ldifLines, messages); } final void handleSkippedRecord(final LDIFRecord record, final LocalizableMessage message) throws DecodeException { rejectedRecordListener.handleSkippedRecord(record.lineNumber, record.ldifLines, message); } // Determine whether the provided line is a continuation line. Note // that while RFC 2849 technically only allows a space in this // position, both OpenLDAP and the Sun Java System Directory Server // allow a tab as well, so we will too for compatibility reasons. See // issue #852 for details. /* * Determine whether the provided line is a continuation line. Note that * while RFC 2849 technically only allows a space in this position, both * OpenLDAP and the Sun Java System Directory Server allow a tab as well, so * we will too for compatibility reasons. See issue #852 for details. */ private boolean isContinuationLine(final String line) { return line.charAt(0) == ' ' || line.charAt(0) == '\t'; } @@ -720,5 +721,4 @@ } return line; } } opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/AbstractLDIFStream.java
@@ -22,7 +22,7 @@ * * * Copyright 2009 Sun Microsystems, Inc. * Portions copyright 2011 ForgeRock AS * Portions copyright 2011-2013 ForgeRock AS */ package org.forgerock.opendj.ldif; @@ -42,51 +42,30 @@ * Common LDIF reader/writer functionality. */ abstract class AbstractLDIFStream { final Set<AttributeDescription> excludeAttributes = new HashSet<AttributeDescription>(); boolean excludeOperationalAttributes = false; boolean excludeUserAttributes = false; final Set<AttributeDescription> includeAttributes = new HashSet<AttributeDescription>(); final Set<DN> includeBranches = new HashSet<DN>(); final Set<DN> excludeBranches = new HashSet<DN>(); final List<Matcher> excludeFilters = new LinkedList<Matcher>(); boolean excludeOperationalAttributes = false; boolean excludeUserAttributes = false; final Set<AttributeDescription> includeAttributes = new HashSet<AttributeDescription>(); final Set<DN> includeBranches = new HashSet<DN>(); final List<Matcher> includeFilters = new LinkedList<Matcher>(); final List<Matcher> excludeFilters = new LinkedList<Matcher>(); /** * Creates a new abstract LDIF stream. */ AbstractLDIFStream() { // Nothing to do. } final boolean isAttributeExcluded(final AttributeDescription attributeDescription) { // Let explicit include override more general exclude. if (!excludeAttributes.isEmpty() && excludeAttributes.contains(attributeDescription)) { return true; } // Let explicit include override more general exclude. if (!includeAttributes.isEmpty()) { } else if (!includeAttributes.isEmpty()) { return !includeAttributes.contains(attributeDescription); } else { final AttributeType type = attributeDescription.getAttributeType(); return (excludeOperationalAttributes && type.isOperational()) || (excludeUserAttributes && !type.isOperational()); } final AttributeType type = attributeDescription.getAttributeType(); if (excludeOperationalAttributes && type.isOperational()) { return true; } if (excludeUserAttributes && !type.isOperational()) { return true; } return false; } final boolean isBranchExcluded(final DN dn) { @@ -97,7 +76,6 @@ } } } if (!includeBranches.isEmpty()) { for (final DN includeBranch : includeBranches) { if (includeBranch.isSuperiorOrEqualTo(dn)) { @@ -105,9 +83,9 @@ } } return true; } else { return false; } return false; } final boolean isEntryExcluded(final Entry entry) { @@ -118,7 +96,6 @@ } } } if (!includeFilters.isEmpty()) { for (final Matcher includeFilter : includeFilters) { if (includeFilter.matches(entry).toBoolean()) { @@ -126,9 +103,9 @@ } } return true; } else { return false; } return false; } } opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/AbstractLDIFWriter.java
@@ -22,7 +22,7 @@ * * * Copyright 2009 Sun Microsystems, Inc. * Portions copyright 2011-2012 ForgeRock AS * Portions copyright 2011-2013 ForgeRock AS */ package org.forgerock.opendj.ldif; @@ -31,6 +31,7 @@ import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.util.List; import java.util.regex.Pattern; @@ -100,45 +101,29 @@ * LDIF string list writer implementation. */ private static final class LDIFWriterListImpl implements LDIFWriterImpl { private final StringBuilder builder = new StringBuilder(); private final List<String> ldifLines; /** * Creates a new LDIF list writer. * * @param ldifLines * The string list. */ LDIFWriterListImpl(final List<String> ldifLines) { this.ldifLines = ldifLines; } /** * {@inheritDoc} */ @Override public void close() throws IOException { // Nothing to do. } /** * {@inheritDoc} */ @Override public void flush() throws IOException { // Nothing to do. } /** * {@inheritDoc} */ @Override public void print(final CharSequence s) throws IOException { builder.append(s); } /** * {@inheritDoc} */ @Override public void println() throws IOException { ldifLines.add(builder.toString()); builder.setLength(0); @@ -149,81 +134,54 @@ * LDIF output stream writer implementation. */ private static final class LDIFWriterOutputStreamImpl implements LDIFWriterImpl { private final BufferedWriter writer; /** * Creates a new LDIF output stream writer. * * @param out * The output stream. */ LDIFWriterOutputStreamImpl(final OutputStream out) { this.writer = new BufferedWriter(new OutputStreamWriter(out)); LDIFWriterOutputStreamImpl(final Writer writer) { this.writer = writer instanceof BufferedWriter ? (BufferedWriter) writer : new BufferedWriter(writer); } /** * {@inheritDoc} */ @Override public void close() throws IOException { writer.close(); } /** * {@inheritDoc} */ @Override public void flush() throws IOException { writer.flush(); } /** * {@inheritDoc} */ @Override public void print(final CharSequence s) throws IOException { writer.append(s); } /** * {@inheritDoc} */ @Override public void println() throws IOException { writer.newLine(); } } // Regular expression used for splitting comments on line-breaks. /* * Regular expression used for splitting comments on line-breaks. */ private static final Pattern SPLIT_NEWLINE = Pattern.compile("\\r?\\n"); boolean addUserFriendlyComments = false; final LDIFWriterImpl impl; int wrapColumn = 0; private final StringBuilder builder = new StringBuilder(80); /** * Creates a new LDIF entry writer which will append lines of LDIF to the * provided list. * * @param ldifLines * The list to which lines of LDIF should be appended. */ public AbstractLDIFWriter(final List<String> ldifLines) { Validator.ensureNotNull(ldifLines); AbstractLDIFWriter(final List<String> ldifLines) { this.impl = new LDIFWriterListImpl(ldifLines); } /** * Creates a new LDIF entry writer whose destination is the provided output * stream. * * @param out * The output stream to use. */ public AbstractLDIFWriter(final OutputStream out) { Validator.ensureNotNull(out); this.impl = new LDIFWriterOutputStreamImpl(out); AbstractLDIFWriter(final OutputStream out) { this(new OutputStreamWriter(out)); } AbstractLDIFWriter(final Writer writer) { this.impl = new LDIFWriterOutputStreamImpl(writer); } final void close0() throws IOException { @@ -238,12 +196,16 @@ final void writeComment0(final CharSequence comment) throws IOException { Validator.ensureNotNull(comment); // First, break up the comment into multiple lines to preserve the // original spacing that it contained. /* * First, break up the comment into multiple lines to preserve the * original spacing that it contained. */ final String[] lines = SPLIT_NEWLINE.split(comment); // Now iterate through the lines and write them out, prefixing and // wrapping them as necessary. /* * Now iterate through the lines and write them out, prefixing and * wrapping them as necessary. */ for (final String line : lines) { if (!shouldWrap()) { impl.print("# "); @@ -251,7 +213,6 @@ impl.println(); } else { final int breakColumn = wrapColumn - 2; if (line.length() <= breakColumn) { impl.print("# "); impl.print(line); @@ -267,7 +228,6 @@ startPos = line.length(); } else { final int endPos = startPos + breakColumn; int i = endPos - 1; while (i > startPos) { if (line.charAt(i) == ' ') { @@ -278,19 +238,17 @@ startPos = i + 1; continue outerLoop; } i--; } // If we've gotten here, then there are no spaces on // the // entire line. If that happens, then we'll have to // break // in the middle of a word. /* * If we've gotten here, then there are no spaces on * the entire line. If that happens, then we'll have * to break in the middle of a word. */ impl.print("# "); impl.print(line.substring(startPos, endPos)); impl.println(); startPos = endPos; } } @@ -304,7 +262,6 @@ final StringBuilder key = new StringBuilder("control: "); key.append(control.getOID()); key.append(control.isCritical() ? " true" : " false"); if (control.hasValue()) { writeKeyAndValue(key, control.getValue()); } else { @@ -317,17 +274,20 @@ throws IOException { builder.setLength(0); // If the value is empty, then just append a single colon and a // single space. /* * If the value is empty, then just append a single colon and a single * space. */ if (value.length() == 0) { builder.append(key); builder.append(": "); } else if (needsBase64Encoding(value)) { if (addUserFriendlyComments) { // TODO: Only display comments for valid UTF-8 values, not // binary values. /* * TODO: Only display comments for valid UTF-8 values, not * binary values. */ } builder.setLength(0); builder.append(key); builder.append(":: "); @@ -337,7 +297,6 @@ builder.append(": "); builder.append(value.toString()); } writeLine(builder); } @@ -372,8 +331,10 @@ return false; } // If the value starts with a space, colon, or less than, then it // needs to be base64 encoded. /* * If the value starts with a space, colon, or less than, then it needs * to be base64 encoded. */ switch (bytes.byteAt(0)) { case 0x20: // Space case 0x3A: // Colon @@ -381,14 +342,17 @@ return true; } // If the value ends with a space, then it needs to be // base64 encoded. /* * If the value ends with a space, then it needs to be base64 encoded. */ if (length > 1 && bytes.byteAt(length - 1) == 0x20) { return true; } // If the value contains a null, newline, or return character, then // it needs to be base64 encoded. /* * If the value contains a null, newline, or return character, then it * needs to be base64 encoded. */ byte b; for (int i = 0; i < bytes.length(); i++) { b = bytes.byteAt(i); @@ -404,7 +368,7 @@ } } // If we've made it here, then there's no reason to base64 encode. /* If we've made it here, then there's no reason to base64 encode. */ return false; } @@ -415,11 +379,9 @@ @SuppressWarnings("unused") private void writeKeyAndURL(final CharSequence key, final CharSequence url) throws IOException { builder.setLength(0); builder.append(key); builder.append(":: "); builder.append(url); writeLine(builder); } } opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIFChangeRecordReader.java
@@ -28,10 +28,30 @@ package org.forgerock.opendj.ldif; import static com.forgerock.opendj.util.StaticUtils.toLowerCase; import static org.forgerock.opendj.ldap.CoreMessages.*; import static org.forgerock.opendj.ldap.CoreMessages.ERR_LDIF_ATTRIBUTE_NAME_MISMATCH; import static org.forgerock.opendj.ldap.CoreMessages.ERR_LDIF_BAD_CHANGE_TYPE; import static org.forgerock.opendj.ldap.CoreMessages.ERR_LDIF_BAD_MODIFICATION_TYPE; import static org.forgerock.opendj.ldap.CoreMessages.ERR_LDIF_CHANGE_EXCLUDED_BY_DN; import static org.forgerock.opendj.ldap.CoreMessages.ERR_LDIF_MALFORMED_ATTRIBUTE_NAME; import static org.forgerock.opendj.ldap.CoreMessages.ERR_LDIF_MALFORMED_CHANGE_TYPE; import static org.forgerock.opendj.ldap.CoreMessages.ERR_LDIF_MALFORMED_CONTROL; import static org.forgerock.opendj.ldap.CoreMessages.ERR_LDIF_MALFORMED_DELETE; import static org.forgerock.opendj.ldap.CoreMessages.ERR_LDIF_MALFORMED_DELETE_OLD_RDN; import static org.forgerock.opendj.ldap.CoreMessages.ERR_LDIF_MALFORMED_MODIFICATION_TYPE; import static org.forgerock.opendj.ldap.CoreMessages.ERR_LDIF_MALFORMED_NEW_RDN; import static org.forgerock.opendj.ldap.CoreMessages.ERR_LDIF_MALFORMED_NEW_SUPERIOR; import static org.forgerock.opendj.ldap.CoreMessages.ERR_LDIF_NO_CHANGE_TYPE; import static org.forgerock.opendj.ldap.CoreMessages.ERR_LDIF_NO_DELETE_OLD_RDN; import static org.forgerock.opendj.ldap.CoreMessages.ERR_LDIF_NO_NEW_RDN; import static org.forgerock.opendj.ldap.CoreMessages.ERR_LDIF_UNEXPECTED_BINARY_OPTION; import static org.forgerock.opendj.ldap.CoreMessages.ERR_LDIF_UNKNOWN_ATTRIBUTE_TYPE; import static org.forgerock.opendj.ldap.CoreMessages.WARN_READ_LDIF_RECORD_MULTIPLE_CHANGE_RECORDS_FOUND; import static org.forgerock.opendj.ldap.CoreMessages.WARN_READ_LDIF_RECORD_NO_CHANGE_RECORD_FOUND; import static org.forgerock.opendj.ldap.CoreMessages.WARN_READ_LDIF_RECORD_UNEXPECTED_IO_ERROR; import java.io.IOException; import java.io.InputStream; import java.io.Reader; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; @@ -91,6 +111,12 @@ * Interchange Format (LDIF) - Technical Specification </a> */ public final class LDIFChangeRecordReader extends AbstractLDIFReader implements ChangeRecordReader { private static final Pattern CONTROL_REGEX = Pattern .compile("^\\s*(\\d+(.\\d+)*)(\\s+((true)|(false)))?\\s*(:(:)?\\s*?\\S+)?\\s*$"); // Poison used to indicate end of LDIF. private static final ChangeRecord EOF = Requests.newAddRequest(DN.rootDN()); /** * Parses the provided array of LDIF lines as a single LDIF change record. * @@ -140,12 +166,6 @@ private ChangeRecord nextChangeRecord = null; // Poison used to indicate end of LDIF. private static final ChangeRecord EOF = Requests.newAddRequest(DN.rootDN()); private static final Pattern CONTROL_REGEX = Pattern.compile("^\\s*(\\d+(.\\d+)*)(\\s+((true)|(false)))?\\s*(:(:)?\\s*?\\S+)?\\s*$"); /** * Creates a new LDIF change record reader whose source is the provided * input stream. @@ -173,6 +193,19 @@ } /** * Creates a new LDIF change record reader whose source is the provided * character stream reader. * * @param reader * The character stream reader to use. * @throws NullPointerException * If {@code reader} was {@code null}. */ public LDIFChangeRecordReader(final Reader reader) { super(reader); } /** * Creates a new LDIF change record reader which will read lines of LDIF * from the provided array of LDIF lines. * @@ -379,8 +412,10 @@ } try { // Read the DN of the entry and see if it is one that should be // included in the import. /* * Read the DN of the entry and see if it is one that should be * included in the import. */ final DN entryDN = readLDIFRecordDN(record); if (entryDN == null) { // Skip version record. @@ -450,7 +485,7 @@ // Add the controls to the record. if (controls != null) { for (Control control : controls) { for (final Control control : controls) { nextChangeRecord.addControl(control); } } @@ -463,27 +498,6 @@ return nextChangeRecord; } private Control parseControl(DN entryDN, LDIFRecord record, String ldifLine, String value) throws DecodeException { Matcher matcher = CONTROL_REGEX.matcher(value); if (!matcher.matches()) { final LocalizableMessage message = ERR_LDIF_MALFORMED_CONTROL.get(record.lineNumber, entryDN.toString(), ldifLine); throw DecodeException.error(message); } String oid = matcher.group(1); boolean isCritical = matcher.group(5) != null; String controlValueString = matcher.group(7); ByteString controlValue = null; if (controlValueString != null) { controlValue = parseSingleValue(record, ldifLine, entryDN, ldifLine.indexOf(':', 8), oid); } return GenericControl.newControl(oid, isCritical, controlValue); } private ChangeRecord parseAddChangeRecordEntry(final DN entryDN, final String lastLDIFLine, final LDIFRecord record) throws DecodeException { // Use an Entry for the AttributeSequence. @@ -520,6 +534,25 @@ return Requests.newAddRequest(entry); } private Control parseControl(final DN entryDN, final LDIFRecord record, final String ldifLine, final String value) throws DecodeException { final Matcher matcher = CONTROL_REGEX.matcher(value); if (!matcher.matches()) { final LocalizableMessage message = ERR_LDIF_MALFORMED_CONTROL.get(record.lineNumber, entryDN.toString(), ldifLine); throw DecodeException.error(message); } final String oid = matcher.group(1); final boolean isCritical = matcher.group(5) != null; final String controlValueString = matcher.group(7); ByteString controlValue = null; if (controlValueString != null) { controlValue = parseSingleValue(record, ldifLine, entryDN, ldifLine.indexOf(':', 8), oid); } return GenericControl.newControl(oid, isCritical, controlValue); } private ChangeRecord parseDeleteChangeRecordEntry(final DN entryDN, final LDIFRecord record) throws DecodeException { if (record.iterator.hasNext()) { @@ -582,9 +615,10 @@ schemaErrors.add(message); continue; default: // Ignore // This should not happen: we should be using a non-strict // schema for // this policy. /* * This should not happen: we should be using a non-strict * schema for this policy. */ throw new IllegalStateException("Schema is not consistent with policy", e); } } catch (final LocalizedIllegalArgumentException e) { @@ -594,9 +628,11 @@ throw DecodeException.error(message); } // Skip the attribute if requested before performing any schema // checking: the attribute may have been excluded because it is // known to violate the schema. /* * Skip the attribute if requested before performing any schema * checking: the attribute may have been excluded because it is * known to violate the schema. */ if (isAttributeExcluded(attributeDescription)) { continue; } @@ -620,8 +656,10 @@ attributeDescription = attributeDescription.withOption("binary"); } // Now go through the rest of the attributes until the "-" line is // reached. /* * Now go through the rest of the attributes until the "-" line is * reached. */ attributeValues.clear(); while (record.iterator.hasNext()) { ldifLine = record.iterator.next(); @@ -637,9 +675,11 @@ try { attributeDescription2 = AttributeDescription.valueOf(attrDescr, schema); } catch (final LocalizedIllegalArgumentException e) { // No need to catch schema exception here because it implies // that the // attribute name is wrong and the record is malformed. /* * No need to catch schema exception here because it implies * that the attribute name is wrong and the record is * malformed. */ final LocalizableMessage message = ERR_LDIF_MALFORMED_ATTRIBUTE_NAME.get(record.lineNumber, entryDN .toString(), attrDescr); @@ -664,15 +704,14 @@ final ByteString value = parseSingleValue(record, ldifLine, entryDN, colonPos, attrDescr); if (schemaValidationPolicy.checkAttributeValues().needsChecking()) { LocalizableMessageBuilder builder = new LocalizableMessageBuilder(); final LocalizableMessageBuilder builder = new LocalizableMessageBuilder(); if (!syntax.valueIsAcceptable(value, builder)) { // Just log a message, but don't skip the value since // this could // change the semantics of the modification (e.g. if all // values in a // delete are skipped then this implies that the whole // attribute // should be removed). /* * Just log a message, but don't skip the value since * this could change the semantics of the modification * (e.g. if all values in a delete are skipped then this * implies that the whole attribute should be removed). */ if (schemaValidationPolicy.checkAttributeValues().isReject()) { schemaValidationFailure = true; } opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIFChangeRecordWriter.java
@@ -22,13 +22,15 @@ * * * Copyright 2009 Sun Microsystems, Inc. * Portions copyright 2012 ForgeRock AS. * Portions copyright 2012-2013 ForgeRock AS. */ package org.forgerock.opendj.ldif; import java.io.IOException; import java.io.OutputStream; import java.io.StringWriter; import java.io.Writer; import java.util.List; import org.forgerock.opendj.ldap.Attribute; @@ -72,6 +74,25 @@ public final class LDIFChangeRecordWriter extends AbstractLDIFWriter implements ChangeRecordWriter { /** * Returns the LDIF string representation of the provided change record. * * @param change * The change record. * @return The LDIF string representation of the provided change record. */ public static String toString(final ChangeRecord change) { final StringWriter writer = new StringWriter(128); try { new LDIFChangeRecordWriter(writer).setAddUserFriendlyComments(true).writeChangeRecord( change).close(); } catch (final IOException e) { // Should never happen. throw new IllegalStateException(e); } return writer.toString(); } /** * Creates a new LDIF change record writer which will append lines of LDIF * to the provided list. * @@ -94,8 +115,20 @@ } /** * Creates a new LDIF change record writer whose destination is the provided * character stream writer. * * @param writer * The character stream writer to use. */ public LDIFChangeRecordWriter(final Writer writer) { super(writer); } /** * {@inheritDoc} */ @Override public void close() throws IOException { close0(); } @@ -103,6 +136,7 @@ /** * {@inheritDoc} */ @Override public void flush() throws IOException { flush0(); } @@ -230,6 +264,7 @@ /** * {@inheritDoc} */ @Override public LDIFChangeRecordWriter writeChangeRecord(final AddRequest change) throws IOException { Validator.ensureNotNull(change); @@ -262,6 +297,7 @@ /** * {@inheritDoc} */ @Override public LDIFChangeRecordWriter writeChangeRecord(final ChangeRecord change) throws IOException { Validator.ensureNotNull(change); @@ -281,6 +317,7 @@ /** * {@inheritDoc} */ @Override public LDIFChangeRecordWriter writeChangeRecord(final DeleteRequest change) throws IOException { Validator.ensureNotNull(change); @@ -302,6 +339,7 @@ /** * {@inheritDoc} */ @Override public LDIFChangeRecordWriter writeChangeRecord(final ModifyDNRequest change) throws IOException { Validator.ensureNotNull(change); @@ -314,9 +352,11 @@ writeKeyAndValue("dn", change.getName().toString()); writeControls(change.getControls()); // Write the changetype. Some older tools may not support the // "moddn" changetype, so only use it if a newSuperior element has // been provided, but use modrdn elsewhere. /* * Write the changetype. Some older tools may not support the "moddn" * changetype, so only use it if a newSuperior element has been * provided, but use modrdn elsewhere. */ if (change.getNewSuperior() == null) { writeLine("changetype: modrdn"); } else { @@ -338,6 +378,7 @@ /** * {@inheritDoc} */ @Override public LDIFChangeRecordWriter writeChangeRecord(final ModifyRequest change) throws IOException { Validator.ensureNotNull(change); @@ -381,6 +422,7 @@ /** * {@inheritDoc} */ @Override public LDIFChangeRecordWriter writeComment(final CharSequence comment) throws IOException { writeComment0(comment); return this; opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIFEntryReader.java
@@ -22,15 +22,20 @@ * * * Copyright 2009-2010 Sun Microsystems, Inc. * Portions copyright 2011-2012 ForgeRock AS * Portions copyright 2011-2013 ForgeRock AS */ package org.forgerock.opendj.ldif; import static org.forgerock.opendj.ldap.CoreMessages.*; import static org.forgerock.opendj.ldap.CoreMessages.ERR_LDIF_ENTRY_EXCLUDED_BY_DN; import static org.forgerock.opendj.ldap.CoreMessages.ERR_LDIF_ENTRY_EXCLUDED_BY_FILTER; import static org.forgerock.opendj.ldap.CoreMessages.WARN_READ_LDIF_RECORD_MULTIPLE_CHANGE_RECORDS_FOUND; import static org.forgerock.opendj.ldap.CoreMessages.WARN_READ_LDIF_RECORD_NO_CHANGE_RECORD_FOUND; import static org.forgerock.opendj.ldap.CoreMessages.WARN_READ_LDIF_RECORD_UNEXPECTED_IO_ERROR; import java.io.IOException; import java.io.InputStream; import java.io.Reader; import java.util.Arrays; import java.util.LinkedList; import java.util.List; @@ -134,6 +139,19 @@ } /** * Creates a new LDIF entry reader whose source is the provided character * stream reader. * * @param reader * The character stream reader to use. * @throws NullPointerException * If {@code reader} was {@code null}. */ public LDIFEntryReader(final Reader reader) { super(reader); } /** * Creates a new LDIF entry reader which will read lines of LDIF from the * provided array of LDIF lines. * @@ -366,8 +384,10 @@ } try { // Read the DN of the entry and see if it is one that should be // included in the import. /* * Read the DN of the entry and see if it is one that should be * included in the import. */ final DN entryDN = readLDIFRecordDN(record); if (entryDN == null) { // Skip version record. opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIFEntryWriter.java
@@ -22,13 +22,15 @@ * * * Copyright 2009-2010 Sun Microsystems, Inc. * Portions copyright 2012 ForgeRock AS. * Portions copyright 2012-2013 ForgeRock AS. */ package org.forgerock.opendj.ldif; import java.io.IOException; import java.io.OutputStream; import java.io.StringWriter; import java.io.Writer; import java.util.List; import org.forgerock.opendj.ldap.Attribute; @@ -50,6 +52,24 @@ public final class LDIFEntryWriter extends AbstractLDIFWriter implements EntryWriter { /** * Returns the LDIF string representation of the provided entry. * * @param entry * The entry. * @return The LDIF string representation of the provided entry. */ public static String toString(final Entry entry) { final StringWriter writer = new StringWriter(128); try { new LDIFEntryWriter(writer).setAddUserFriendlyComments(true).writeEntry(entry).close(); } catch (final IOException e) { // Should never happen. throw new IllegalStateException(e); } return writer.toString(); } /** * Creates a new LDIF entry writer which will append lines of LDIF to the * provided list. * @@ -72,8 +92,20 @@ } /** * Creates a new LDIF entry writer whose destination is the provided * character stream writer. * * @param writer * The character stream writer to use. */ public LDIFEntryWriter(final Writer writer) { super(writer); } /** * {@inheritDoc} */ @Override public void close() throws IOException { close0(); } @@ -81,6 +113,7 @@ /** * {@inheritDoc} */ @Override public void flush() throws IOException { flush0(); } @@ -235,6 +268,7 @@ /** * {@inheritDoc} */ @Override public LDIFEntryWriter writeComment(final CharSequence comment) throws IOException { writeComment0(comment); return this; @@ -243,6 +277,7 @@ /** * {@inheritDoc} */ @Override public LDIFEntryWriter writeEntry(final Entry entry) throws IOException { Validator.ensureNotNull(entry);