| | |
| | | |
| | | |
| | | import static com.sun.opends.sdk.messages.Messages.*; |
| | | import static com.sun.opends.sdk.util.StaticUtils.*; |
| | | import static com.sun.opends.sdk.util.StaticUtils.toLowerCase; |
| | | |
| | | import java.io.IOException; |
| | | import java.io.InputStream; |
| | |
| | | * An LDIF change record reader reads change records using the LDAP Data |
| | | * Interchange Format (LDIF) from a user defined source. |
| | | * |
| | | * @see <a href="http://tools.ietf.org/html/rfc2849">RFC 2849 - The LDAP |
| | | * Data Interchange Format (LDIF) - Technical Specification </a> |
| | | * @see <a href="http://tools.ietf.org/html/rfc2849">RFC 2849 - The LDAP Data |
| | | * Interchange Format (LDIF) - Technical Specification </a> |
| | | */ |
| | | public final class LDIFChangeRecordReader extends AbstractLDIFReader |
| | | implements ChangeRecordReader |
| | | public final class LDIFChangeRecordReader extends AbstractLDIFReader implements |
| | | ChangeRecordReader |
| | | { |
| | | /** |
| | | * Parses the provided array of LDIF lines as a single LDIF change |
| | | * record. |
| | | * Parses the provided array of LDIF lines as a single LDIF change record. |
| | | * |
| | | * @param ldifLines |
| | | * The lines of LDIF to be parsed. |
| | | * @return The parsed LDIF change record. |
| | | * @throws LocalizedIllegalArgumentException |
| | | * If {@code ldifLines} did not contain an LDIF change |
| | | * record, if it contained multiple change records, if |
| | | * contained malformed LDIF, or if the change record could |
| | | * not be decoded using the default schema. |
| | | * If {@code ldifLines} did not contain an LDIF change record, if it |
| | | * contained multiple change records, if contained malformed LDIF, |
| | | * or if the change record could not be decoded using the default |
| | | * schema. |
| | | * @throws NullPointerException |
| | | * If {@code ldifLines} was {@code null}. |
| | | */ |
| | | public static ChangeRecord valueOfLDIFChangeRecord( |
| | | String... ldifLines) throws LocalizedIllegalArgumentException, |
| | | NullPointerException |
| | | public static ChangeRecord valueOfLDIFChangeRecord(final String... ldifLines) |
| | | throws LocalizedIllegalArgumentException, NullPointerException |
| | | { |
| | | // LDIF change record reader is tolerant to missing change types. |
| | | LDIFChangeRecordReader reader = new LDIFChangeRecordReader( |
| | | ldifLines); |
| | | final LDIFChangeRecordReader reader = new LDIFChangeRecordReader(ldifLines); |
| | | try |
| | | { |
| | | ChangeRecord record = reader.readChangeRecord(); |
| | | final ChangeRecord record = reader.readChangeRecord(); |
| | | |
| | | if (record == null) |
| | | { |
| | | // No change record found. |
| | | LocalizableMessage message = WARN_READ_LDIF_RECORD_NO_CHANGE_RECORD_FOUND |
| | | final LocalizableMessage message = WARN_READ_LDIF_RECORD_NO_CHANGE_RECORD_FOUND |
| | | .get(); |
| | | throw new LocalizedIllegalArgumentException(message); |
| | | } |
| | |
| | | if (reader.readChangeRecord() != null) |
| | | { |
| | | // Multiple change records found. |
| | | LocalizableMessage message = WARN_READ_LDIF_RECORD_MULTIPLE_CHANGE_RECORDS_FOUND |
| | | final LocalizableMessage message = WARN_READ_LDIF_RECORD_MULTIPLE_CHANGE_RECORDS_FOUND |
| | | .get(); |
| | | throw new LocalizedIllegalArgumentException(message); |
| | | } |
| | | |
| | | return record; |
| | | } |
| | | catch (DecodeException e) |
| | | catch (final DecodeException e) |
| | | { |
| | | // Badly formed LDIF. |
| | | throw new LocalizedIllegalArgumentException(e.getMessageObject()); |
| | | } |
| | | catch (IOException e) |
| | | catch (final IOException e) |
| | | { |
| | | // This should never happen for a String based reader. |
| | | LocalizableMessage message = WARN_READ_LDIF_RECORD_UNEXPECTED_IO_ERROR.get(e |
| | | .getMessage()); |
| | | final LocalizableMessage message = WARN_READ_LDIF_RECORD_UNEXPECTED_IO_ERROR |
| | | .get(e.getMessage()); |
| | | throw new LocalizedIllegalArgumentException(message); |
| | | } |
| | | } |
| | |
| | | |
| | | |
| | | /** |
| | | * Creates a new LDIF change record reader whose source is the |
| | | * provided input stream. |
| | | * Creates a new LDIF change record reader whose source is the provided input |
| | | * stream. |
| | | * |
| | | * @param in |
| | | * The input stream to use. |
| | | * @throws NullPointerException |
| | | * If {@code in} was {@code null}. |
| | | */ |
| | | public LDIFChangeRecordReader(InputStream in) |
| | | public LDIFChangeRecordReader(final InputStream in) |
| | | throws NullPointerException |
| | | { |
| | | super(in); |
| | |
| | | |
| | | |
| | | /** |
| | | * Creates a new LDIF change record reader which will read lines of |
| | | * LDIF from the provided list of LDIF lines. |
| | | * Creates a new LDIF change record reader which will read lines of LDIF from |
| | | * the provided list of LDIF lines. |
| | | * |
| | | * @param ldifLines |
| | | * The lines of LDIF to be read. |
| | | * @throws NullPointerException |
| | | * If {@code ldifLines} was {@code null}. |
| | | */ |
| | | public LDIFChangeRecordReader(List<String> ldifLines) |
| | | public LDIFChangeRecordReader(final List<String> ldifLines) |
| | | throws NullPointerException |
| | | { |
| | | super(ldifLines); |
| | |
| | | |
| | | |
| | | /** |
| | | * Creates a new LDIF change record reader which will read lines of |
| | | * LDIF from the provided array of LDIF lines. |
| | | * Creates a new LDIF change record reader which will read lines of LDIF from |
| | | * the provided array of LDIF lines. |
| | | * |
| | | * @param ldifLines |
| | | * The lines of LDIF to be read. |
| | | * @throws NullPointerException |
| | | * If {@code ldifLines} was {@code null}. |
| | | */ |
| | | public LDIFChangeRecordReader(String... ldifLines) |
| | | public LDIFChangeRecordReader(final String... ldifLines) |
| | | throws NullPointerException |
| | | { |
| | | super(Arrays.asList(ldifLines)); |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ChangeRecord readChangeRecord() throws DecodeException, |
| | | IOException |
| | | public ChangeRecord readChangeRecord() throws DecodeException, IOException |
| | | { |
| | | // Continue until an unfiltered entry is obtained. |
| | | while (true) |
| | |
| | | if (!record.iterator.hasNext()) |
| | | { |
| | | // FIXME: improve error. |
| | | final LocalizableMessage message = LocalizableMessage.raw("Missing changetype"); |
| | | final LocalizableMessage message = LocalizableMessage |
| | | .raw("Missing changetype"); |
| | | throw DecodeException.error(message); |
| | | } |
| | | |
| | | final KeyValuePair pair = new KeyValuePair(); |
| | | final String ldifLine = readLDIFRecordKeyValuePair(record, |
| | | pair, false); |
| | | final String ldifLine = readLDIFRecordKeyValuePair(record, pair, false); |
| | | |
| | | if (!toLowerCase(pair.key).equals("changetype")) |
| | | { |
| | | // Default to add change record. |
| | | changeRecord = parseAddChangeRecordEntry(entryDN, ldifLine, |
| | | record); |
| | | changeRecord = parseAddChangeRecordEntry(entryDN, ldifLine, record); |
| | | } |
| | | else |
| | | { |
| | | final String changeType = toLowerCase(pair.value); |
| | | if (changeType.equals("add")) |
| | | { |
| | | changeRecord = parseAddChangeRecordEntry(entryDN, null, |
| | | record); |
| | | changeRecord = parseAddChangeRecordEntry(entryDN, null, record); |
| | | } |
| | | else if (changeType.equals("delete")) |
| | | { |
| | |
| | | } |
| | | else if (changeType.equals("modrdn")) |
| | | { |
| | | changeRecord = parseModifyDNChangeRecordEntry(entryDN, |
| | | record); |
| | | changeRecord = parseModifyDNChangeRecordEntry(entryDN, record); |
| | | } |
| | | else if (changeType.equals("moddn")) |
| | | { |
| | | changeRecord = parseModifyDNChangeRecordEntry(entryDN, |
| | | record); |
| | | changeRecord = parseModifyDNChangeRecordEntry(entryDN, record); |
| | | } |
| | | else |
| | | { |
| | |
| | | |
| | | |
| | | /** |
| | | * Specifies whether or not all operational attributes should be |
| | | * excluded from any change records that are read from LDIF. The |
| | | * default is {@code false}. |
| | | * Specifies whether or not all operational attributes should be excluded from |
| | | * any change records that are read from LDIF. The default is {@code false}. |
| | | * |
| | | * @param excludeOperationalAttributes |
| | | * {@code true} if all operational attributes should be |
| | | * excluded, or {@code false} otherwise. |
| | | * {@code true} if all operational attributes should be excluded, or |
| | | * {@code false} otherwise. |
| | | * @return A reference to this {@code LDIFChangeRecordReader}. |
| | | */ |
| | | public LDIFChangeRecordReader setExcludeAllOperationalAttributes( |
| | | boolean excludeOperationalAttributes) |
| | | final boolean excludeOperationalAttributes) |
| | | { |
| | | this.excludeOperationalAttributes = excludeOperationalAttributes; |
| | | return this; |
| | |
| | | |
| | | |
| | | /** |
| | | * Specifies whether or not all user attributes should be excluded |
| | | * from any change records that are read from LDIF. The default is |
| | | * {@code false}. |
| | | * Specifies whether or not all user attributes should be excluded from any |
| | | * change records that are read from LDIF. The default is {@code false}. |
| | | * |
| | | * @param excludeUserAttributes |
| | | * {@code true} if all user attributes should be excluded, or |
| | | * {@code false} otherwise. |
| | | * {@code true} if all user attributes should be excluded, or {@code |
| | | * false} otherwise. |
| | | * @return A reference to this {@code LDIFChangeRecordReader}. |
| | | */ |
| | | public LDIFChangeRecordReader setExcludeAllUserAttributes( |
| | | boolean excludeUserAttributes) |
| | | final boolean excludeUserAttributes) |
| | | { |
| | | this.excludeUserAttributes = excludeUserAttributes; |
| | | return this; |
| | |
| | | |
| | | |
| | | /** |
| | | * Excludes the named attribute from any change records that are read |
| | | * from LDIF. By default all attributes are included unless explicitly |
| | | * excluded. |
| | | * Excludes the named attribute from any change records that are read from |
| | | * LDIF. By default all attributes are included unless explicitly excluded. |
| | | * |
| | | * @param attributeDescription |
| | | * The name of the attribute to be excluded. |
| | | * @return A reference to this {@code LDIFChangeRecordReader}. |
| | | */ |
| | | public LDIFChangeRecordReader setExcludeAttribute( |
| | | AttributeDescription attributeDescription) |
| | | final AttributeDescription attributeDescription) |
| | | { |
| | | Validator.ensureNotNull(attributeDescription); |
| | | excludeAttributes.add(attributeDescription); |
| | |
| | | |
| | | |
| | | /** |
| | | * Excludes all change records which target entries beneath the named |
| | | * entry (inclusive) from being read from LDIF. By default all change |
| | | * records are read unless explicitly excluded or included. |
| | | * Excludes all change records which target entries beneath the named entry |
| | | * (inclusive) from being read from LDIF. By default all change records are |
| | | * read unless explicitly excluded or included. |
| | | * |
| | | * @param excludeBranch |
| | | * The distinguished name of the branch to be excluded. |
| | | * @return A reference to this {@code LDIFChangeRecordReader}. |
| | | */ |
| | | public LDIFChangeRecordReader setExcludeBranch(DN excludeBranch) |
| | | public LDIFChangeRecordReader setExcludeBranch(final DN excludeBranch) |
| | | { |
| | | Validator.ensureNotNull(excludeBranch); |
| | | excludeBranches.add(excludeBranch); |
| | |
| | | |
| | | |
| | | /** |
| | | * Ensures that the named attribute is not excluded from any change |
| | | * records that are read from LDIF. By default all attributes are |
| | | * included unless explicitly excluded. |
| | | * Ensures that the named attribute is not excluded from any change records |
| | | * that are read from LDIF. By default all attributes are included unless |
| | | * explicitly excluded. |
| | | * |
| | | * @param attributeDescription |
| | | * The name of the attribute to be included. |
| | | * @return A reference to this {@code LDIFChangeRecordReader}. |
| | | */ |
| | | public LDIFChangeRecordReader setIncludeAttribute( |
| | | AttributeDescription attributeDescription) |
| | | final AttributeDescription attributeDescription) |
| | | { |
| | | Validator.ensureNotNull(attributeDescription); |
| | | includeAttributes.add(attributeDescription); |
| | |
| | | |
| | | |
| | | /** |
| | | * Ensures that all change records which target entries beneath the |
| | | * named entry (inclusive) are read from LDIF. By default all change |
| | | * records are read unless explicitly excluded or included. |
| | | * Ensures that all change records which target entries beneath the named |
| | | * entry (inclusive) are read from LDIF. By default all change records are |
| | | * read unless explicitly excluded or included. |
| | | * |
| | | * @param includeBranch |
| | | * The distinguished name of the branch to be included. |
| | | * @return A reference to this {@code LDIFChangeRecordReader}. |
| | | */ |
| | | public LDIFChangeRecordReader setIncludeBranch(DN includeBranch) |
| | | public LDIFChangeRecordReader setIncludeBranch(final DN includeBranch) |
| | | { |
| | | Validator.ensureNotNull(includeBranch); |
| | | includeBranches.add(includeBranch); |
| | |
| | | |
| | | |
| | | /** |
| | | * Sets the schema which should be used for decoding change records |
| | | * that are read from LDIF. The default schema is used if no other is |
| | | * specified. |
| | | * Sets the schema which should be used for decoding change records that are |
| | | * read from LDIF. The default schema is used if no other is specified. |
| | | * |
| | | * @param schema |
| | | * The schema which should be used for decoding change |
| | | * records that are read from LDIF. |
| | | * The schema which should be used for decoding change records that |
| | | * are read from LDIF. |
| | | * @return A reference to this {@code LDIFChangeRecordReader}. |
| | | */ |
| | | public LDIFChangeRecordReader setSchema(Schema schema) |
| | | public LDIFChangeRecordReader setSchema(final Schema schema) |
| | | { |
| | | Validator.ensureNotNull(schema); |
| | | this.schema = schema; |
| | |
| | | |
| | | |
| | | /** |
| | | * Specifies whether or not schema validation should be performed for |
| | | * change records that are read from LDIF. The default is {@code true} |
| | | * . |
| | | * Specifies whether or not schema validation should be performed for change |
| | | * records that are read from LDIF. The default is {@code true} . |
| | | * |
| | | * @param validateSchema |
| | | * {@code true} if schema validation should be performed, or |
| | | * {@code false} otherwise. |
| | | * {@code true} if schema validation should be performed, or {@code |
| | | * false} otherwise. |
| | | * @return A reference to this {@code LDIFChangeRecordReader}. |
| | | */ |
| | | public LDIFChangeRecordReader setValidateSchema(boolean validateSchema) |
| | | public LDIFChangeRecordReader setValidateSchema(final boolean validateSchema) |
| | | { |
| | | this.validateSchema = validateSchema; |
| | | return this; |
| | |
| | | |
| | | |
| | | |
| | | private ChangeRecord parseAddChangeRecordEntry(DN entryDN, |
| | | String lastLDIFLine, LDIFRecord record) throws DecodeException |
| | | private ChangeRecord parseAddChangeRecordEntry(final DN entryDN, |
| | | final String lastLDIFLine, final LDIFRecord record) |
| | | throws DecodeException |
| | | { |
| | | // Use an Entry for the AttributeSequence. |
| | | final Entry entry = new SortedEntry(entryDN); |
| | | final Entry entry = new LinkedHashMapEntry(entryDN); |
| | | |
| | | if (lastLDIFLine != null) |
| | | { |
| | |
| | | |
| | | |
| | | |
| | | private ChangeRecord parseDeleteChangeRecordEntry(DN entryDN, |
| | | LDIFRecord record) throws DecodeException |
| | | private ChangeRecord parseDeleteChangeRecordEntry(final DN entryDN, |
| | | final LDIFRecord record) throws DecodeException |
| | | { |
| | | if (record.iterator.hasNext()) |
| | | { |
| | | // FIXME: include line number in error. |
| | | final LocalizableMessage message = ERR_LDIF_INVALID_DELETE_ATTRIBUTES.get(); |
| | | final LocalizableMessage message = ERR_LDIF_INVALID_DELETE_ATTRIBUTES |
| | | .get(); |
| | | throw DecodeException.error(message); |
| | | } |
| | | |
| | |
| | | |
| | | |
| | | |
| | | private ChangeRecord parseModifyChangeRecordEntry(DN entryDN, |
| | | LDIFRecord record) throws DecodeException |
| | | private ChangeRecord parseModifyChangeRecordEntry(final DN entryDN, |
| | | final LDIFRecord record) throws DecodeException |
| | | { |
| | | final ModifyRequest modifyRequest = Requests |
| | | .newModifyRequest(entryDN); |
| | | final ModifyRequest modifyRequest = Requests.newModifyRequest(entryDN); |
| | | |
| | | final KeyValuePair pair = new KeyValuePair(); |
| | | final List<ByteString> attributeValues = new ArrayList<ByteString>(); |
| | |
| | | else |
| | | { |
| | | // FIXME: improve error. |
| | | final LocalizableMessage message = ERR_LDIF_INVALID_MODIFY_ATTRIBUTE.get( |
| | | pair.key, "add, delete, replace, increment"); |
| | | final LocalizableMessage message = ERR_LDIF_INVALID_MODIFY_ATTRIBUTE |
| | | .get(pair.key, "add, delete, replace, increment"); |
| | | throw DecodeException.error(message); |
| | | } |
| | | |
| | | AttributeDescription attributeDescription; |
| | | try |
| | | { |
| | | attributeDescription = AttributeDescription.valueOf(pair.value, |
| | | schema); |
| | | attributeDescription = AttributeDescription.valueOf(pair.value, schema); |
| | | } |
| | | catch (final LocalizedIllegalArgumentException e) |
| | | { |
| | |
| | | if (!attributeDescription.getAttributeType().getSyntax() |
| | | .isBEREncodingRequired()) |
| | | { |
| | | if (validateSchema |
| | | && attributeDescription.containsOption("binary")) |
| | | if (validateSchema && attributeDescription.containsOption("binary")) |
| | | { |
| | | final LocalizableMessage message = ERR_LDIF_INVALID_ATTR_OPTION.get( |
| | | entryDN.toString(), record.lineNumber, pair.value); |
| | |
| | | AttributeDescription attributeDescription2; |
| | | try |
| | | { |
| | | attributeDescription2 = AttributeDescription.valueOf( |
| | | attrDescr, schema); |
| | | attributeDescription2 = AttributeDescription.valueOf(attrDescr, |
| | | schema); |
| | | } |
| | | catch (final LocalizedIllegalArgumentException e) |
| | | { |
| | |
| | | { |
| | | // TODO: include line number. |
| | | final LocalizableMessage message = ERR_LDIF_INVALID_CHANGERECORD_ATTRIBUTE |
| | | .get(attributeDescription2.toString(), |
| | | attributeDescription.toString()); |
| | | .get(attributeDescription2.toString(), attributeDescription |
| | | .toString()); |
| | | throw DecodeException.error(message); |
| | | } |
| | | |
| | |
| | | colonPos, attrDescr)); |
| | | } |
| | | |
| | | Change change = new Change(modType, new LinkedAttribute( |
| | | attributeDescription, attributeValues)); |
| | | modifyRequest.addChange(change); |
| | | final Modification change = new Modification(modType, |
| | | new LinkedAttribute(attributeDescription, attributeValues)); |
| | | modifyRequest.addModification(change); |
| | | } |
| | | |
| | | return modifyRequest; |
| | |
| | | |
| | | |
| | | |
| | | private ChangeRecord parseModifyDNChangeRecordEntry(DN entryDN, |
| | | LDIFRecord record) throws DecodeException |
| | | private ChangeRecord parseModifyDNChangeRecordEntry(final DN entryDN, |
| | | final LDIFRecord record) throws DecodeException |
| | | { |
| | | ModifyDNRequest modifyDNRequest; |
| | | |
| | |
| | | if (!toLowerCase(pair.key).equals("newrdn")) |
| | | { |
| | | // FIXME: improve error. |
| | | final LocalizableMessage message = LocalizableMessage.raw("Missing newrdn"); |
| | | final LocalizableMessage message = LocalizableMessage |
| | | .raw("Missing newrdn"); |
| | | throw DecodeException.error(message); |
| | | } |
| | | |
| | |
| | | if (!record.iterator.hasNext()) |
| | | { |
| | | // TODO: include line number. |
| | | final LocalizableMessage message = ERR_LDIF_NO_DELETE_OLDRDN_ATTRIBUTE.get(); |
| | | final LocalizableMessage message = ERR_LDIF_NO_DELETE_OLDRDN_ATTRIBUTE |
| | | .get(); |
| | | throw DecodeException.error(message); |
| | | } |
| | | |
| | |
| | | if (!toLowerCase(pair.key).equals("deleteoldrdn")) |
| | | { |
| | | // FIXME: improve error. |
| | | final LocalizableMessage message = LocalizableMessage.raw("Missing deleteoldrdn"); |
| | | final LocalizableMessage message = LocalizableMessage |
| | | .raw("Missing deleteoldrdn"); |
| | | throw DecodeException.error(message); |
| | | } |
| | | |
| | | final String delStr = toLowerCase(pair.value); |
| | | if (delStr.equals("false") || delStr.equals("no") |
| | | || delStr.equals("0")) |
| | | if (delStr.equals("false") || delStr.equals("no") || delStr.equals("0")) |
| | | { |
| | | modifyDNRequest.setDeleteOldRDN(false); |
| | | } |
| | |
| | | if (!toLowerCase(pair.key).equals("newsuperior")) |
| | | { |
| | | // FIXME: improve error. |
| | | final LocalizableMessage message = LocalizableMessage.raw("Missing newsuperior"); |
| | | final LocalizableMessage message = LocalizableMessage |
| | | .raw("Missing newsuperior"); |
| | | throw DecodeException.error(message); |
| | | } |
| | | |