use of com.unboundid.ldap.sdk.ModificationType in project ldapsdk by pingidentity.
the class LDIFReader method parseModifications.
/**
* Parses the data available through the provided iterator into an array of
* modifications suitable for use in a modify change record.
*
* @param dn The DN of the entry being parsed.
* @param trailingSpaceBehavior The behavior that should be exhibited when
* encountering attribute values which are not
* base64-encoded but contain trailing spaces.
* @param ldifLines The lines that comprise the LDIF
* representation of the full record being
* parsed.
* @param iterator The iterator to use to access the
* modification data.
* @param relativeBasePath The base path that will be prepended to
* relative paths in order to obtain an
* absolute path.
* @param firstLineNumber The line number for the start of the record.
* @param schema The schema to use in processing.
*
* @return An array containing the modifications that were read.
*
* @throws LDIFException If the provided LDIF data cannot be decoded as a
* set of modifications.
*/
@NotNull()
private static Modification[] parseModifications(@NotNull final String dn, @NotNull final TrailingSpaceBehavior trailingSpaceBehavior, @NotNull final ArrayList<StringBuilder> ldifLines, @NotNull final Iterator<StringBuilder> iterator, @NotNull final String relativeBasePath, final long firstLineNumber, @Nullable final Schema schema) throws LDIFException {
final ArrayList<Modification> modList = new ArrayList<>(ldifLines.size());
while (iterator.hasNext()) {
// The first line must start with "add:", "delete:", "replace:", or
// "increment:" followed by an attribute name.
StringBuilder line = iterator.next();
handleTrailingSpaces(line, dn, firstLineNumber, trailingSpaceBehavior);
int colonPos = line.indexOf(":");
if (colonPos < 0) {
throw new LDIFException(ERR_READ_MOD_CR_NO_MODTYPE.get(firstLineNumber), firstLineNumber, true, ldifLines, null);
}
final ModificationType modType;
final String modTypeStr = StaticUtils.toLowerCase(line.substring(0, colonPos));
if (modTypeStr.equals("add")) {
modType = ModificationType.ADD;
} else if (modTypeStr.equals("delete")) {
modType = ModificationType.DELETE;
} else if (modTypeStr.equals("replace")) {
modType = ModificationType.REPLACE;
} else if (modTypeStr.equals("increment")) {
modType = ModificationType.INCREMENT;
} else {
throw new LDIFException(ERR_READ_MOD_CR_INVALID_MODTYPE.get(modTypeStr, firstLineNumber), firstLineNumber, true, ldifLines, null);
}
String attributeName;
int length = line.length();
if (length == (colonPos + 1)) {
// acceptable.
throw new LDIFException(ERR_READ_MOD_CR_MODTYPE_NO_ATTR.get(firstLineNumber), firstLineNumber, true, ldifLines, null);
} else if (line.charAt(colonPos + 1) == ':') {
// Skip over any spaces leading up to the value, and then the rest of
// the string is the base64-encoded attribute name.
int pos = colonPos + 2;
while ((pos < length) && (line.charAt(pos) == ' ')) {
pos++;
}
try {
final byte[] dnBytes = Base64.decode(line.substring(pos));
attributeName = StaticUtils.toUTF8String(dnBytes);
} catch (final ParseException pe) {
Debug.debugException(pe);
throw new LDIFException(ERR_READ_MOD_CR_MODTYPE_CANNOT_BASE64_DECODE_ATTR.get(firstLineNumber, pe.getMessage()), firstLineNumber, true, ldifLines, pe);
} catch (final Exception e) {
Debug.debugException(e);
throw new LDIFException(ERR_READ_MOD_CR_MODTYPE_CANNOT_BASE64_DECODE_ATTR.get(firstLineNumber, e), firstLineNumber, true, ldifLines, e);
}
} else {
// Skip over any spaces leading up to the value, and then the rest of
// the string is the attribute name.
int pos = colonPos + 1;
while ((pos < length) && (line.charAt(pos) == ' ')) {
pos++;
}
attributeName = line.substring(pos);
}
if (attributeName.isEmpty()) {
throw new LDIFException(ERR_READ_MOD_CR_MODTYPE_NO_ATTR.get(firstLineNumber), firstLineNumber, true, ldifLines, null);
}
// The next zero or more lines may be the set of attribute values. Keep
// reading until we reach the end of the iterator or until we find a line
// with just a "-".
final ArrayList<ASN1OctetString> valueList = new ArrayList<>(ldifLines.size());
while (iterator.hasNext()) {
line = iterator.next();
handleTrailingSpaces(line, dn, firstLineNumber, trailingSpaceBehavior);
if (line.toString().equals("-")) {
break;
}
colonPos = line.indexOf(":");
if (colonPos < 0) {
throw new LDIFException(ERR_READ_NO_ATTR_COLON.get(firstLineNumber), firstLineNumber, true, ldifLines, null);
} else if (!line.substring(0, colonPos).equalsIgnoreCase(attributeName)) {
// There are a couple of cases in which this might be acceptable:
// - If the two names are logically equivalent, but have an alternate
// name (or OID) for the target attribute type, or if there are
// attribute options and the options are just in a different order.
// - If this is the first value for the target attribute and the
// alternate name includes a "binary" option that the original
// attribute name did not have. In this case, all subsequent values
// will also be required to have the binary option.
final String alternateName = line.substring(0, colonPos);
// Check to see if the base names are equivalent.
boolean baseNameEquivalent = false;
final String expectedBaseName = Attribute.getBaseName(attributeName);
final String alternateBaseName = Attribute.getBaseName(alternateName);
if (alternateBaseName.equalsIgnoreCase(expectedBaseName)) {
baseNameEquivalent = true;
} else {
if (schema != null) {
final AttributeTypeDefinition expectedAT = schema.getAttributeType(expectedBaseName);
final AttributeTypeDefinition alternateAT = schema.getAttributeType(alternateBaseName);
if ((expectedAT != null) && (alternateAT != null) && expectedAT.equals(alternateAT)) {
baseNameEquivalent = true;
}
}
}
// Check to see if the attribute options are equivalent.
final Set<String> expectedOptions = Attribute.getOptions(attributeName);
final Set<String> lowerExpectedOptions = new HashSet<>(StaticUtils.computeMapCapacity(expectedOptions.size()));
for (final String s : expectedOptions) {
lowerExpectedOptions.add(StaticUtils.toLowerCase(s));
}
final Set<String> alternateOptions = Attribute.getOptions(alternateName);
final Set<String> lowerAlternateOptions = new HashSet<>(StaticUtils.computeMapCapacity(alternateOptions.size()));
for (final String s : alternateOptions) {
lowerAlternateOptions.add(StaticUtils.toLowerCase(s));
}
final boolean optionsEquivalent = lowerAlternateOptions.equals(lowerExpectedOptions);
if (baseNameEquivalent && optionsEquivalent) {
// This is fine. The two attribute descriptions are logically
// equivalent. We'll continue using the attribute description that
// was provided first.
} else if (valueList.isEmpty() && baseNameEquivalent && lowerAlternateOptions.remove("binary") && lowerAlternateOptions.equals(lowerExpectedOptions)) {
// This means that the provided value is the first value for the
// attribute, and that the only significant difference is that the
// provided attribute description included an unexpected "binary"
// option. We'll accept this, but will require any additional
// values for this modification to also include the binary option,
// and we'll use the binary option in the attribute that is
// eventually created.
attributeName = alternateName;
} else {
// of options are incompatible. This is not acceptable.
throw new LDIFException(ERR_READ_MOD_CR_ATTR_MISMATCH.get(firstLineNumber, line.substring(0, colonPos), attributeName), firstLineNumber, true, ldifLines, null);
}
}
length = line.length();
final ASN1OctetString value;
if (length == (colonPos + 1)) {
// The colon was the last character on the line. This is fine.
value = new ASN1OctetString();
} else if (line.charAt(colonPos + 1) == ':') {
// Skip over any spaces leading up to the value, and then the rest of
// the string is the base64-encoded value. This is unusual and
// unnecessary, but is nevertheless acceptable.
int pos = colonPos + 2;
while ((pos < length) && (line.charAt(pos) == ' ')) {
pos++;
}
try {
value = new ASN1OctetString(Base64.decode(line.substring(pos)));
} catch (final ParseException pe) {
Debug.debugException(pe);
throw new LDIFException(ERR_READ_CANNOT_BASE64_DECODE_ATTR.get(attributeName, firstLineNumber, pe.getMessage()), firstLineNumber, true, ldifLines, pe);
} catch (final Exception e) {
Debug.debugException(e);
throw new LDIFException(ERR_READ_CANNOT_BASE64_DECODE_ATTR.get(firstLineNumber, e), firstLineNumber, true, ldifLines, e);
}
} else if (line.charAt(colonPos + 1) == '<') {
// Skip over any spaces leading up to the value, and then the rest of
// the string is a URL that indicates where to get the real content.
// At the present time, we'll only support the file URLs.
int pos = colonPos + 2;
while ((pos < length) && (line.charAt(pos) == ' ')) {
pos++;
}
final String urlString = line.substring(pos);
try {
final byte[] urlBytes = retrieveURLBytes(urlString, relativeBasePath, firstLineNumber);
value = new ASN1OctetString(urlBytes);
} catch (final Exception e) {
Debug.debugException(e);
throw new LDIFException(ERR_READ_URL_EXCEPTION.get(attributeName, urlString, firstLineNumber, e), firstLineNumber, true, ldifLines, e);
}
} else {
// Skip over any spaces leading up to the value, and then the rest of
// the string is the value.
int pos = colonPos + 1;
while ((pos < length) && (line.charAt(pos) == ' ')) {
pos++;
}
value = new ASN1OctetString(line.substring(pos));
}
valueList.add(value);
}
final ASN1OctetString[] values = new ASN1OctetString[valueList.size()];
valueList.toArray(values);
// value.
if ((modType.intValue() == ModificationType.ADD.intValue()) && (values.length == 0)) {
throw new LDIFException(ERR_READ_MOD_CR_NO_ADD_VALUES.get(attributeName, firstLineNumber), firstLineNumber, true, ldifLines, null);
}
// value.
if ((modType.intValue() == ModificationType.INCREMENT.intValue()) && (values.length != 1)) {
throw new LDIFException(ERR_READ_MOD_CR_INVALID_INCR_VALUE_COUNT.get(firstLineNumber, attributeName), firstLineNumber, true, ldifLines, null);
}
modList.add(new Modification(modType, attributeName, values));
}
final Modification[] mods = new Modification[modList.size()];
modList.toArray(mods);
return mods;
}
use of com.unboundid.ldap.sdk.ModificationType in project ldapsdk by pingidentity.
the class JNDIConverter method convertModification.
/**
* Converts the provided JNDI modification item to an LDAP SDK modification.
*
* @param m The JNDI modification item to be converted.
*
* @return The LDAP SDK modification that corresponds to the provided JNDI
* modification item.
*
* @throws NamingException If a problem is encountered during the conversion
* process.
*/
@Nullable()
public static Modification convertModification(@Nullable final ModificationItem m) throws NamingException {
if (m == null) {
return null;
}
final ModificationType modType;
switch(m.getModificationOp()) {
case DirContext.ADD_ATTRIBUTE:
modType = ModificationType.ADD;
break;
case DirContext.REMOVE_ATTRIBUTE:
modType = ModificationType.DELETE;
break;
case DirContext.REPLACE_ATTRIBUTE:
modType = ModificationType.REPLACE;
break;
default:
throw new NamingException("Unsupported modification type " + m);
}
final Attribute a = convertAttribute(m.getAttribute());
return new Modification(modType, a.getName(), a.getRawValues());
}
use of com.unboundid.ldap.sdk.ModificationType in project zm-mailbox by Zimbra.
the class UBIDModificationList method modifyAttr.
@Override
public void modifyAttr(String name, String value, Entry entry, boolean containsBinaryData, boolean isBinaryTransfer) {
ModificationType modOp = (StringUtil.isNullOrEmpty(value)) ? ModificationType.DELETE : ModificationType.REPLACE;
if (modOp == ModificationType.DELETE) {
// make sure it exists
if (entry.getAttr(name, false) == null) {
return;
}
}
if (modOp == ModificationType.DELETE) {
removeAttr(name, isBinaryTransfer);
} else {
String[] val = new String[] { value };
modifyAttr(name, val, containsBinaryData, isBinaryTransfer);
}
}
Aggregations