Entry.java revision d25372dc8e65a9ed019a88fdf659ca61313f1b31
/*
* 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
* 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-2008 Sun Microsystems, Inc.
*/
/**
* This class defines a data structure for a Directory Server entry.
* It includes a DN and a set of attributes.
* <BR><BR>
* The entry also contains a volatile attachment object, which should
* be used to associate the entry with a special type of object that
* is based on its contents. For example, if the entry holds access
* control information, then the attachment might be an object that
* contains a representation of that access control definition in a
* more useful form. This is only useful if the entry is to be
* cached, since the attachment may be accessed if the entry is
* retrieved from the cache, but if the entry is retrieved from the
* backend repository it cannot be guaranteed to contain any
* attachment (and in most cases will not). This attachment is
* volatile in that it is not always guaranteed to be present, it may
* be removed or overwritten at any time, and it will be invalidated
* and removed if the entry is altered in any way.
*/
mayInstantiate=true,
mayExtend=false,
mayInvoke=true)
public class Entry
implements ProtocolElement
{
/**
* The tracer object for the debug logger.
*/
// Indicates whether virtual attribute processing has been performed
// for this entry.
private boolean virtualAttributeProcessingPerformed;
// The set of operational attributes for this entry.
// The set of user attributes for this entry.
// The set of suppressed real attributes for this entry.
// The set of objectclasses for this entry.
// The DN for this entry.
// A generic attachment that may be used to associate this entry
// with some other object.
private transient Object attachment;
// The schema used to govern this entry.
/**
* Creates a new entry with the provided information.
*
* @param dn The distinguished name for this
* entry.
* @param objectClasses The set of objectclasses for this
* entry as a mapping between the
* objectclass and the name to use to
* reference it.
* @param userAttributes The set of user attributes for
* this entry as a mapping between
* the attribute type and the list of
* attributes with that type.
* @param operationalAttributes The set of operational attributes
* for this entry as a mapping
* between the attribute type and the
* list of attributes with that type.
*/
{
attachment = null;
virtualAttributeProcessingPerformed = false;
{
}
else
{
}
if (objectClasses == null)
{
}
else
{
this.objectClasses = objectClasses;
}
if (userAttributes == null)
{
this.userAttributes =
}
else
{
this.userAttributes = userAttributes;
}
if (operationalAttributes == null)
{
this.operationalAttributes =
}
else
{
}
}
/**
* Retrieves the distinguished name for this entry.
*
* @return The distinguished name for this entry.
*/
{
return dn;
}
/**
* Specifies the distinguished name for this entry.
*
* @param dn The distinguished name for this entry.
*/
{
{
}
else
{
}
attachment = null;
}
/**
* Retrieves the set of objectclasses defined for this entry. The
* caller should be allowed to modify the contents of this list, but
* if it does then it should also invalidate the attachment.
*
* @return The set of objectclasses defined for this entry.
*/
{
return objectClasses;
}
/**
* Indicates whether this entry has the specified objectclass.
*
* @param objectClass The objectclass for which to make the
* determination.
*
* @return <CODE>true</CODE> if this entry has the specified
* objectclass, or <CODE>false</CODE> if not.
*/
{
}
/**
* Retrieves the structural objectclass for this entry.
*
* @return The structural objectclass for this entry, or
* <CODE>null</CODE> if there is none for some reason. If
* there are multiple structural classes in the entry, then
* the first will be returned.
*/
public ObjectClass getStructuralObjectClass()
{
{
{
if (structuralClass == null)
{
}
else
{
{
}
}
}
}
return structuralClass;
}
/**
* Specifies the set of objectclasses for this entry.
*
* @param objectClassNames The values containing the names or OIDs
* of the objectClasses for this entry.
*
* @throws DirectoryException If a problem occurs while attempting
* to set the objectclasses for this
* entry.
*/
public void setObjectClasses(
throws DirectoryException
{
attachment = null;
// Iterate through all the provided objectclass names and make
// sure that they are names of valid objectclasses.
for (AttributeValue v : objectClassNames)
{
try
{
}
catch (Exception e)
{
if (debugEnabled())
{
}
}
{
message);
}
}
// If we've gotten here, then everything is fine so put the new
// set of objectclasses.
}
/**
* Adds the provided objectClass to this entry.
*
* @param oc The objectClass to add to this entry.
*
* @throws DirectoryException If a problem occurs while attempting
* to add the objectclass to this
* entry.
*/
throws DirectoryException
{
attachment = null;
{
message);
}
}
/**
* Retrieves the entire set of attributes for this entry. This will
* include both user and operational attributes. The caller must
* not modify the contents of this list. Also note that this method
* is less efficient than calling either (or both)
* <CODE>getUserAttributes</CODE> or
* <CODE>getOperationalAttributes</CODE>, so it should only be used
* when calls to those methods are not appropriate.
*
* @return The entire set of attributes for this entry.
*/
{
{
{
attributes.add(a);
}
}
{
{
attributes.add(a);
}
}
return attributes;
}
/**
* Retrieves the entire set of user (i.e., non-operational)
* attributes for this entry. The caller should be allowed to
* modify the contents of this list, but if it does then it should
* also invalidate the attachment.
*
* @return The entire set of user attributes for this entry.
*/
{
return userAttributes;
}
/**
* Retrieves the entire set of operational attributes for this
* entry. The caller should be allowed to modify the contents of
* this list, but if it does then it should also invalidate the
* attachment.
*
* @return The entire set of operational attributes for this entry.
*/
{
return operationalAttributes;
}
/**
* Retrieves an attribute holding the objectclass information for
* this entry. The returned attribute must not be altered.
*
* @return An attribute holding the objectclass information for
* this entry, or <CODE>null</CODE> if it does not have any
* objectclass information.
*/
public Attribute getObjectClassAttribute()
{
{
return null;
}
{
}
return builder.toAttribute();
}
/**
* Indicates whether this entry contains the specified attribute.
* Any subordinate attribute of the specified attribute will also be
* used in the determination.
*
* @param attributeType
* The attribute type for which to make the determination.
* @return <CODE>true</CODE> if this entry contains the specified
* attribute, or <CODE>false</CODE> if not.
*/
{
}
/**
* Indicates whether this entry contains the specified attribute.
*
* @param attributeType The attribute type for which to
* make the determination.
* @param includeSubordinates Whether to include any subordinate
* attributes of the attribute type
* being retrieved.
*
* @return <CODE>true</CODE> if this entry contains the specified
* attribute, or <CODE>false</CODE> if not.
*/
boolean includeSubordinates)
{
}
/**
* Indicates whether this entry contains the specified attribute
* with all of the options in the provided set. Any subordinate
* attribute of the specified attribute will also be used in the
* determination.
*
* @param attributeType
* The attribute type for which to make the determination.
* @param options
* The set of options to use in the determination.
* @return <CODE>true</CODE> if this entry contains the specified
* attribute, or <CODE>false</CODE> if not.
*/
public boolean hasAttribute(
{
}
/**
* Indicates whether this entry contains the specified attribute
* with all of the options in the provided set.
*
* @param attributeType
* The attribute type for which to make the determination.
* @param options
* The set of options to use in the determination.
* @param includeSubordinates
* Whether to include any subordinate attributes of the
* attribute type being retrieved.
* @return <CODE>true</CODE> if this entry contains the specified
* attribute, or <CODE>false</CODE> if not.
*/
public boolean hasAttribute(
boolean includeSubordinates)
{
// Handle object class.
if (attributeType.isObjectClassType())
{
if (!objectClasses.isEmpty())
{
}
return false;
}
if (!includeSubordinates)
{
// It's possible that there could be an attribute without any
// values, which we should treat as not having the requested
// attribute.
}
// Check all matching attributes.
if (attributeType.isOperational())
{
}
else
{
}
if (attributes != null)
{
{
// It's possible that there could be an attribute without any
// values, which we should treat as not having the requested
// attribute.
{
return true;
}
}
}
// Check sub-types.
{
{
if (subType.isOperational())
{
}
else
{
}
if (attributes != null)
{
{
// It's possible that there could be an attribute without
// any values, which we should treat as not having the
// requested attribute.
{
return true;
}
}
}
}
}
return false;
}
/**
* Retrieves the requested attribute element(s) for the specified
* attribute type. The list returned may include multiple elements
* if the same attribute exists in the entry multiple times with
* different sets of options. It may also include any subordinate
* attributes of the attribute being retrieved.
*
* @param attributeType
* The attribute type to retrieve.
* @return The requested attribute element(s) for the specified
* attribute type, or <CODE>null</CODE> if the specified
* attribute type is not present in this entry.
*/
{
return getAttribute(attributeType, true);
}
/**
* Retrieves the requested attribute element(s) for the specified
* attribute type. The list returned may include multiple elements
* if the same attribute exists in the entry multiple times with
* different sets of options.
*
* @param attributeType The attribute type to retrieve.
* @param includeSubordinates Whether to include any subordinate
* attributes of the attribute type
* being retrieved.
*
* @return The requested attribute element(s) for the specified
* attribute type, or <CODE>null</CODE> if the specified
* attribute type is not present in this entry.
*/
boolean includeSubordinates)
{
if (includeSubordinates &&
{
{
}
{
}
{
{
}
{
}
}
if (attributes.isEmpty())
{
return null;
}
else
{
return attributes;
}
}
else
{
if (attributes == null)
{
if (attributes == null)
{
if (attributeType.isObjectClassType() &&
(! objectClasses.isEmpty()))
{
return attributes;
}
else
{
return null;
}
}
else
{
return attributes;
}
}
else
{
return attributes;
}
}
}
/**
* Retrieves the requested attribute element(s) for the attribute
* with the specified name or OID. The list returned may include
* multiple elements if the same attribute exists in the entry
* multiple times with different sets of options. It may also
* include any subordinate attributes of the attribute being
* retrieved.
* <BR><BR>
* Note that this method should only be used in cases in which the
* Directory Server schema has no reference of an attribute type
* with the specified name. It is not as accurate or efficient as
* the version of this method that takes an
* <CODE>AttributeType</CODE> argument.
*
* @param lowerName The name or OID of the attribute to return,
* formatted in all lowercase characters.
*
* @return The requested attribute element(s) for the specified
* attribute type, or <CODE>null</CODE> if the specified
* attribute type is not present in this entry.
*/
{
{
{
return getAttribute(attr, true);
}
}
{
{
return getAttribute(attr, true);
}
}
(! objectClasses.isEmpty()))
{
return attrList;
}
return null;
}
/**
* Retrieves the requested attribute element(s) for the specified
* attribute type. The list returned may include multiple elements
* if the same attribute exists in the entry multiple times with
* different sets of options. It may also include any subordinate
* attributes of the attribute being retrieved.
*
* @param attributeType The attribute type to retrieve.
* @param options The set of attribute options to
* include in matching elements.
*
* @return The requested attribute element(s) for the specified
* attribute type, or <CODE>null</CODE> if the specified
* attribute type is not present in this entry with the
* provided set of options.
*/
{
}
/**
* Retrieves the requested attribute element(s) for the specified
* attribute type. The list returned may include multiple elements
* if the same attribute exists in the entry multiple times with
* different sets of options.
*
* @param attributeType The attribute type to retrieve.
* @param includeSubordinates Whether to include any subordinate
* attributes of the attribute type
* being retrieved.
* @param options The set of attribute options to
* include in matching elements.
*
* @return The requested attribute element(s) for the specified
* attribute type, or <CODE>null</CODE> if the specified
* attribute type is not present in this entry with the
* provided set of options.
*/
boolean includeSubordinates,
{
if (includeSubordinates &&
{
{
}
{
}
{
{
}
{
}
}
}
else
{
{
{
if (attributeType.isObjectClassType() &&
(! objectClasses.isEmpty()) &&
{
return attributes;
}
else
{
return null;
}
}
else
{
}
}
else
{
}
}
{
if (! a.hasAllOptions(options))
{
}
}
if (attributes.isEmpty())
{
return null;
}
else
{
return attributes;
}
}
/**
* Retrieves the requested attribute element(s) for the attribute
* with the specified name or OID and set of options. The list
* returned may include multiple elements if the same attribute
* exists in the entry multiple times with different sets of
* matching options.
* <BR><BR>
* Note that this method should only be used in cases in which the
* Directory Server schema has no reference of an attribute type
* with the specified name. It is not as accurate or efficient as
* the version of this method that takes an
* <CODE>AttributeType</CODE> argument.
*
* @param lowerName The name or OID of the attribute to return,
* formatted in all lowercase characters.
* @param options The set of attribute options to include in
* matching elements.
*
* @return The requested attribute element(s) for the specified
* attribute type, or <CODE>null</CODE> if the specified
* attribute type is not present in this entry.
*/
{
{
{
}
}
{
{
}
}
{
return attributes;
}
else
{
return null;
}
}
/**
* Retrieves the requested attribute type from the entry and decodes
* a single value as an object of type T.
* <p>
* If the requested attribute type is not present then
* <code>null</code> is returned. If more than one attribute value
* is present, then the first value found will be decoded and
* returned.
* <p>
* The attribute value is decoded using the specified
* {@link org.opends.server.api.AttributeValueDecoder}.
*
* @param <T>
* Decode the attribute value to an object of this type.
* @param attributeType
* The attribute type to retrieve.
* @param decoder
* The attribute value decoder.
* @return The decoded attribute value or <code>null</code> if no
* attribute value having the specified attribute type was
* found.
* @throws DirectoryException
* If the requested attribute value could not be decoded
* successfully.
*/
{
{
}
else
{
return null;
}
}
/**
* Retrieves the requested attribute type from the entry and decodes
* any values as objects of type T and then places them in the
* specified collection.
* <p>
* If the requested attribute type is not present then no decoded
* values will be added to the container.
* <p>
* The attribute value is decoded using the specified
* {@link org.opends.server.api.AttributeValueDecoder}.
*
* @param <T>
* Decode the attribute values to objects of this type.
* @param attributeType
* The attribute type to retrieve.
* @param decoder
* The attribute value decoder.
* @param collection
* The collection to which decoded values should be added.
* @return The collection containing the decoded attribute value.
* @throws DirectoryException
* If one or more of the requested attribute values could
* not be decoded successfully.
*/
public final <T> Collection<T> getAttributeValues(
AttributeValueDecoder<? extends T> decoder,
Collection<T> collection)
throws DirectoryException
{
{
}
return collection;
}
/**
* Indicates whether this entry contains the specified user
* attribute.
*
* @param attributeType
* The attribute type for which to make the determination.
* @return <CODE>true</CODE> if this entry contains the specified
* user attribute, or <CODE>false</CODE> if not.
*/
{
{
return true;
}
{
{
{
return true;
}
}
}
return false;
}
/**
* Retrieves the requested user attribute element(s) for the
* specified attribute type. The list returned may include multiple
* elements if the same attribute exists in the entry multiple times
* with different sets of options.
*
* @param attributeType The attribute type to retrieve.
*
* @return The requested attribute element(s) for the specified
* attribute type, or <CODE>null</CODE> if there is no such
* user attribute.
*/
{
{
{
}
{
{
}
}
if (attributes.isEmpty())
{
return null;
}
else
{
return attributes;
}
}
else
{
}
}
/**
* Retrieves the requested user attribute element(s) for the
* specified attribute type. The list returned may include multiple
* elements if the same attribute exists in the entry multiple times
* with different sets of options.
*
* @param attributeType The attribute type to retrieve.
* @param options The set of attribute options to include in
* matching elements.
*
* @return The requested attribute element(s) for the specified
* attribute type, or <CODE>null</CODE> if there is no such
* user attribute with the specified set of options.
*/
{
{
}
{
{
{
}
}
}
{
if (! a.hasAllOptions(options))
{
}
}
if (attributes.isEmpty())
{
return null;
}
else
{
return attributes;
}
}
/**
* Makes a copy of attributes matching the specified options.
*
* @param attrList The attributes to be copied.
* @param options The set of attribute options to include in
* matching elements.
* @param omitValues <CODE>true</CODE> if the values are to be
* omitted.
*
* @return A copy of the attributes matching the specified options,
* or <CODE>null</CODE> if there is no such attribute with
* the specified set of options.
*/
boolean omitValues)
{
{
return null;
}
{
if (a.hasAllOptions(options))
{
if (omitValues)
{
}
else
{
duplicateList.add(a);
}
}
}
if (duplicateList.isEmpty())
{
return null;
}
else
{
return duplicateList;
}
}
/**
* Retrieves a copy of the requested user attribute element(s) for
* the specified attribute type. The list returned may include
* multiple elements if the same attribute exists in the entry
* multiple times with different sets of options.
*
* @param attributeType The attribute type to retrieve.
* @param options The set of attribute options to include in
* matching elements.
* @param omitValues <CODE>true</CODE> if the values are to be
* omitted.
*
* @return A copy of the requested attribute element(s) for the
* specified attribute type, or <CODE>null</CODE> if there
* is no such user attribute with the specified set of
* options.
*/
boolean omitValues)
{
}
/**
* Retrieves a copy of the requested operational attribute
* element(s) for the specified attribute type. The list returned
* may include multiple elements if the same attribute exists in
* the entry multiple times with different sets of options.
*
* @param attributeType The attribute type to retrieve.
* @param options The set of attribute options to include in
* matching elements.
* @param omitValues <CODE>true</CODE> if the values are to be
* omitted.
*
* @return A copy of the requested attribute element(s) for the
* specified attribute type, or <CODE>null</CODE> if there
* is no such user attribute with the specified set of
* options.
*/
boolean omitValues)
{
}
/**
* Indicates whether this entry contains the specified operational
* attribute.
*
* @param attributeType The attribute type for which to make the
* determination.
*
* @return <CODE>true</CODE> if this entry contains the specified
* operational attribute, or <CODE>false</CODE> if not.
*/
{
{
return true;
}
{
{
{
return true;
}
}
}
return false;
}
/**
* Retrieves the requested operational attribute element(s) for the
* specified attribute type. The list returned may include multiple
* elements if the same attribute exists in the entry multiple times
* with different sets of options.
*
* @param attributeType The attribute type to retrieve.
*
* @return The requested attribute element(s) for the specified
* attribute type, or <CODE>null</CODE> if there is no such
* operational attribute.
*/
{
{
{
}
{
{
}
}
if (attributes.isEmpty())
{
return null;
}
else
{
return attributes;
}
}
else
{
}
}
/**
* Retrieves the requested operational attribute element(s) for the
* specified attribute type. The list returned may include multiple
* elements if the same attribute exists in the entry multiple times
* with different sets of options.
*
* @param attributeType The attribute type to retrieve.
* @param options The set of attribute options to include in
* matching elements.
*
* @return The requested attribute element(s) for the specified
* attribute type, or <CODE>null</CODE> if there is no such
* operational attribute with the specified set of options.
*/
{
{
}
{
{
{
}
}
}
{
if (! a.hasAllOptions(options))
{
}
}
if (attributes.isEmpty())
{
return null;
}
else
{
return attributes;
}
}
/**
* Puts the provided attribute in this entry. If an attribute
* already exists with the provided type, it will be overwritten.
* Otherwise, a new attribute will be added. Note that no
* validation will be performed.
*
* @param attributeType The attribute type for the set of
* attributes to add.
* @param attributeList The set of attributes to add for the given
* type.
*/
{
attachment = null;
// See if there is already a set of attributes with the specified
// type. If so, then overwrite it.
{
return;
}
{
return;
}
// This is a new attribute, so add it to the set of user or
// operational attributes as appropriate.
if (attributeType.isOperational())
{
}
else
{
}
}
/**
* Ensures that this entry contains the provided attribute and its
* values. If an attribute with the provided type already exists,
* then its attribute values will be merged.
* <p>
* This method handles object class additions but will not perform
* any object class validation. In particular, it will create
* default object classes when an object class is unknown.
* <p>
* This method implements LDAP modification add semantics, with the
* exception that it allows empty attributes to be added.
*
* @param attribute
* The attribute to add or merge with this entry.
* @param duplicateValues
* A list to which any duplicate values will be added.
*/
{
}
/**
* Puts the provided attribute into this entry. If an attribute with
* the provided type and options already exists, then it will be
* replaced. If the provided attribute is empty then any existing
* attribute will be completely removed.
* <p>
* This method handles object class replacements but will not
* perform any object class validation. In particular, it will
* create default object classes when an object class is unknown.
* <p>
* This method implements LDAP modification replace semantics.
*
* @param attribute
* The attribute to replace in this entry.
*/
{
// There can never be duplicate values for a replace.
}
/**
* Increments an attribute in this entry by the amount specified in
* the provided attribute.
*
* @param attribute
* The attribute identifying the attribute to be increment
* and the amount it is to be incremented by. The attribute
* must contain a single value.
* @throws DirectoryException
* If a problem occurs while attempting to increment the
* provided attribute. This may occur if the provided
* attribute was not single valued or if it could not be
* parsed as an integer of if the existing attribute
* values could not be parsed as integers.
*/
public void incrementAttribute(
{
// Get the attribute that is to be incremented.
Attribute a =
if (a == null)
{
throw new DirectoryException(
}
// Decode the increment.
if (!i.hasNext())
{
throw new DirectoryException(
}
long increment;
try
{
}
catch (NumberFormatException e)
{
throw new DirectoryException(
}
if (i.hasNext())
{
throw new DirectoryException(
}
// Increment each attribute value by the specified amount.
for (AttributeValue v : a)
{
String s = v.getStringValue();
long currentValue;
try
{
}
catch (NumberFormatException e)
{
throw new DirectoryException(
}
}
}
/**
* Removes all instances of the specified attribute type from this
* entry, including any instances with options. If the provided
* attribute type is the objectclass type, then all objectclass
* values will be removed (but must be replaced for the entry to be
* valid). If the specified attribute type is not present in this
* entry, then this method will have no effect.
*
* @param attributeType
* The attribute type for the attribute to remove from this
* entry.
* @return <CODE>true</CODE> if the attribute was found and
* removed, or <CODE>false</CODE> if it was not present in
* the entry.
*/
{
attachment = null;
if (attributeType.isObjectClassType())
{
return true;
}
else
{
}
}
/**
* Ensures that this entry does not contain the provided attribute
* values. If the provided attribute is empty, then all values of
* the associated attribute type will be removed. Otherwise, only
* the specified values will be removed.
* <p>
* This method handles object class deletions.
* <p>
* This method implements LDAP modification delete semantics.
*
* @param attribute
* The attribute containing the information to use to
* perform the removal.
* @param missingValues
* A list to which any values contained in the provided
* attribute but not present in the entry will be added.
* @return <CODE>true</CODE> if the attribute type was present and
* the specified values that were present were removed, or
* <CODE>false</CODE> if the attribute type was not
* present in the entry. If the attribute type was present
* but only contained some of the values in the provided
* attribute, then this method will return <CODE>true</CODE>
* but will add those values to the provided list.
*/
{
attachment = null;
{
{
return true;
}
boolean allSuccessful = true;
for (AttributeValue v : attribute)
{
try
{
ocName = v.getNormalizedStringValue();
}
catch (Exception e)
{
if (debugEnabled())
{
}
}
boolean matchFound = false;
{
{
matchFound = true;
break;
}
}
if (!matchFound)
{
allSuccessful = false;
missingValues.add(v);
}
}
return allSuccessful;
}
if (attributeType.isOperational())
{
}
else
{
}
if (attributes == null)
{
// There are no attributes with the same attribute type.
for (AttributeValue v : attribute)
{
missingValues.add(v);
}
return false;
}
// There are already attributes with the same attribute type.
{
if (a.optionsEqual(options))
{
{
// Remove the entire attribute.
attributes.remove(i);
}
else
{
// Remove Specified values.
for (AttributeValue v : attribute)
{
{
missingValues.add(v);
}
}
// Remove / replace the attribute as necessary.
{
}
else
{
attributes.remove(i);
}
}
// If the attribute list is now empty remove it.
if (attributes.isEmpty())
{
if (attributeType.isOperational())
{
}
else
{
}
}
return true;
}
}
// No matching attribute found.
return false;
}
/**
* Indicates whether this entry contains the specified attribute
* value.
*
* @param attributeType The attribute type for the attribute.
* @param options The set of options for the attribute.
* @param value The value for the attribute.
*
* @return <CODE>true</CODE> if this entry contains the specified
* attribute value, or <CODE>false</CODE> if it does not.
*/
{
{
return false;
}
{
if (a.optionsEqual(options))
{
}
}
return false;
}
/**
* Applies the provided modification to this entry. No schema
* checking will be performed.
*
* @param mod The modification to apply to this entry.
*
* @throws DirectoryException If a problem occurs while attempting
* to apply the modification. Note
* that even if a problem occurs, then
* the entry may have been altered in
* some way.
*/
throws DirectoryException
{
AttributeType t = a.getAttributeType();
// We'll need to handle changes to the objectclass attribute in a
// special way.
if (t.isObjectClassType())
{
for (AttributeValue v : a)
{
}
switch (mod.getModificationType())
{
case ADD:
{
{
throw new DirectoryException(
message);
}
else
{
}
}
break;
case DELETE:
{
{
throw new DirectoryException(
}
}
break;
case REPLACE:
objectClasses = ocs;
break;
case INCREMENT:
throw new DirectoryException(
default:
throw new DirectoryException(
}
return;
}
switch (mod.getModificationType())
{
case ADD:
new LinkedList<AttributeValue>();
if (! duplicateValues.isEmpty())
{
throw new DirectoryException(
message);
}
break;
case DELETE:
new LinkedList<AttributeValue>();
if (! missingValues.isEmpty())
{
message);
}
break;
case REPLACE:
replaceAttribute(a);
break;
case INCREMENT:
break;
default:
message);
}
}
/**
* Applies all of the provided modifications to this entry.
*
* @param mods The modifications to apply to this entry.
*
* @throws DirectoryException If a problem occurs while attempting
* to apply the modifications. Note
* that even if a problem occurs, then
* the entry may have been altered in
* some way.
*/
throws DirectoryException
{
for (Modification m : mods)
{
}
}
/**
* Indicates whether this entry conforms to the server's schema
* requirements. The checks performed by this method include:
*
* <UL>
* <LI>Make sure that all required attributes are present, either
* in the list of user or operational attributes.</LI>
* <LI>Make sure that all user attributes are allowed by at least
* one of the objectclasses. The operational attributes will
* not be checked in this manner.</LI>
* <LI>Make sure that all single-valued attributes contained in
* the entry have only a single value.</LI>
* <LI>Make sure that the entry contains a single structural
* objectclass.</LI>
* <LI>Make sure that the entry complies with any defined name
* forms, DIT content rules, and DIT structure rules.</LI>
* </UL>
*
* @param parentEntry The entry that is the immediate
* parent of this entry, which may
* be checked for DIT structure rule
* conformance. This may be
* {@code null} if there is no
* parent or if it is unavailable
* to the caller.
* @param parentProvided Indicates whether the caller
* attempted to provide the parent.
* If not, then the parent entry
* will be loaded on demand if it is
* required.
* @param validateNameForms Indicates whether to validate the
* entry against name form
* definitions. This should only be
* {@code true} for add and modify
* DN operations, as well as for
* for imports.
* @param validateStructureRules Indicates whether to validate the
* entry against DIT structure rule
* definitions. This should only
* be {@code true} for add and
* modify DN operations.
* @param invalidReason The buffer to which an
* explanation will be appended if
* this entry does not conform to
* the server's schema
* configuration.
*
* @return {@code true} if this entry conforms to the server's
* schema requirements, or {@code false} if it does not.
*/
boolean parentProvided,
boolean validateNameForms,
boolean validateStructureRules,
{
// Get the structural objectclass for the entry. If there isn't
// one, or if there's more than one, then see if that's OK.
boolean multipleOCErrorLogged = false;
{
{
if ((structuralClass == null) ||
{
}
{
oc.getNameOrOID());
{
return false;
}
{
if (! multipleOCErrorLogged)
{
multipleOCErrorLogged = true;
}
}
}
}
}
if (structuralClass == null)
{
{
return false;
}
{
}
}
else
{
{
}
if (validateNameForms)
{
{
}
{
if ((ditStructureRule != null) &&
{
}
}
}
}
{
return false;
}
// If there is a name form for this entry, then make sure that the
// RDN for the entry is in compliance with it.
{
{
return false;
}
}
// If there is a DIT content rule for this entry, then make sure
// that the entry is in compliance with it.
if (ditContentRule != null)
{
{
return false;
}
}
{
return false;
}
// If we've gotten here, then the entry is acceptable.
return true;
}
/**
* Checks the attributes and object classes contained in this entry
* to determine whether they conform to the server schema
* requirements.
*
* @param ditContentRule The DIT content rule for this entry, if
* any.
* @param structuralPolicy The policy that should be used for
* structural object class compliance.
* @param invalidReason A buffer into which an invalid reason
* may be added.
*
* @return {@code true} if this entry passes all of the checks, or
* {@code false} if there are any failures.
*/
private boolean checkAttributesAndObjectClasses(
{
// Make sure that we recognize all of the objectclasses, that all
// auxiliary classes are allowed by the DIT content rule, and that
// all attributes required by the object classes are present.
{
{
.getNameOrOID());
return false;
}
(ditContentRule != null) &&
{
o.getNameOrOID(),
{
return false;
}
{
}
}
for (AttributeType t : o.getRequiredAttributes())
{
if (! (userAttributes.containsKey(t) ||
t.isObjectClassType()))
{
t.getNameOrOID(),
o.getNameOrOID());
return false;
}
}
}
// Make sure all the user attributes are allowed, have at least
// one value, and if they are single-valued that they have exactly
// one value.
{
boolean found = false;
{
if (o.isRequiredOrOptional(t))
{
found = true;
break;
}
}
{
if (ditContentRule.isRequiredOrOptional(t))
{
found = true;
}
}
if (! found)
{
t.getNameOrOID());
return false;
}
{
{
if (a.isEmpty())
{
t.getNameOrOID());
return false;
}
{
t.getNameOrOID());
return false;
}
}
}
}
// Iterate through all of the operational attributes and make sure
// that all of the single-valued attributes only have one value.
{
if (t.isSingleValue())
{
{
{
if (a.size() > 1)
{
t.getNameOrOID());
return false;
}
}
}
}
}
// If we've gotten here, then things are OK.
return true;
}
/**
* Performs any processing needed for name form validation.
*
* @param nameForm The name form to validate against this
* entry.
* @param structuralPolicy The policy that should be used for
* structural object class compliance.
* @param invalidReason A buffer into which an invalid reason
* may be added.
*
* @return {@code true} if this entry passes all of the checks, or
* {@code false} if there are any failures.
*/
{
{
// Make sure that all the required attributes are present.
{
if (! rdn.hasAttributeType(t))
{
t.getNameOrOID(),
nameForm.getNameOrOID());
{
return false;
}
{
}
}
}
// Make sure that all attributes in the RDN are allowed.
for (int i = 0; i < numAVAs; i++)
{
if (! nameForm.isRequiredOrOptional(t))
{
t.getNameOrOID(),
nameForm.getNameOrOID());
{
return false;
}
{
}
}
}
}
// If we've gotten here, then things are OK.
return true;
}
/**
* Performs any processing needed for DIT content rule validation.
*
* @param ditContentRule The DIT content rule to validate
* against this entry.
* @param structuralPolicy The policy that should be used for
* structural object class compliance.
* @param invalidReason A buffer into which an invalid reason
* may be added.
*
* @return {@code true} if this entry passes all of the checks, or
* {@code false} if there are any failures.
*/
{
// Make sure that all of the required attributes are present.
{
if (! (userAttributes.containsKey(t) ||
t.isObjectClassType()))
{
t.getNameOrOID(),
{
return false;
}
{
}
}
}
// Make sure that none of the prohibited attributes are present.
{
if (userAttributes.containsKey(t) ||
{
t.getNameOrOID(),
{
return false;
}
{
}
}
}
// If we've gotten here, then things are OK.
return true;
}
/**
* Performs any processing needed for DIT structure rule validation.
*
* @param ditStructureRule The DIT structure rule for this
* entry.
* @param structuralClass The structural object class for
* this entry.
* @param parentEntry The parent entry, if available
* and applicable.
* @param parentProvided Indicates whether the parent
* entry was provided.
* @param validateStructureRules Indicates whether to check to see
* if this entry violates a DIT
* structure rule for its parent.
* @param structuralPolicy The policy that should be used
* for structural object class
* compliance.
* @param invalidReason A buffer into which an invalid
* reason may be added.
*
* @return {@code true} if this entry passes all of the checks, or
* {@code false} if there are any failures.
*/
private boolean checkDITStructureRule(
boolean validateStructureRules,
{
// If there is a DIT structure rule for this entry, then make sure
// that the entry is in compliance with it.
if ((ditStructureRule != null) &&
{
if (parentProvided)
{
if (parentEntry != null)
{
boolean dsrValid =
if (! dsrValid)
{
return false;
}
}
}
else
{
// Get the DN of the parent entry if possible.
{
// Get the parent entry and check its structural class.
for (int i=0; i < 3; i++)
{
{
break;
}
}
{
{
return false;
}
{
}
}
else
{
try
{
if (parentEntry == null)
{
{
return false;
}
{
}
}
else
{
boolean dsrValid =
if (! dsrValid)
{
return false;
}
}
}
catch (Exception e)
{
if (debugEnabled())
{
}
getExceptionMessage(e));
{
return false;
}
{
}
}
finally
{
}
}
}
}
}
else if (validateStructureRules)
{
// There is no DIT structure rule for this entry, but there may
// be one for the parent entry. If there is such a rule for the
// parent entry, then this entry will not be valid.
boolean parentExists = false;
if (parentEntry != null)
{
parentExists = true;
}
else if (! parentProvided)
{
{
// Get the parent entry and check its structural class.
for (int i=0; i < 3; i++)
{
{
break;
}
}
{
{
return false;
}
{
}
}
else
{
try
{
if (parentEntry == null)
{
{
return false;
}
{
}
}
else
{
parentExists = true;
}
}
catch (Exception e)
{
if (debugEnabled())
{
}
getExceptionMessage(e));
{
return false;
}
{
}
}
finally
{
}
}
}
}
if (parentExists)
{
if (parentStructuralClass == null)
{
{
return false;
}
{
}
}
else
{
{
{
{
return false;
}
{
}
}
}
}
}
}
// If we've gotten here, then things are OK.
return true;
}
/**
* Determines whether this entry is in conformance to the provided
* DIT structure rule.
*
* @param dsr The DIT structure rule to use in the
* determination.
* @param structuralClass The structural objectclass for this
* entry to use in the determination.
* @param parentEntry The reference to the parent entry to
* check.
* @param structuralPolicy The policy that should be used around
* enforcement of DIT structure rules.
* @param invalidReason The buffer to which the invalid reason
* should be appended if a problem is
* found.
*
* @return <CODE>true</CODE> if this entry conforms to the provided
* DIT structure rule, or <CODE>false</CODE> if not.
*/
{
{
{
return false;
}
{
}
}
boolean matchFound = false;
{
{
matchFound = true;
}
}
if (! matchFound)
{
oc.getNameOrOID());
{
return false;
}
{
}
}
return true;
}
/**
* Retrieves the attachment for this entry.
*
* @return The attachment for this entry, or <CODE>null</CODE> if
* there is none.
*/
public Object getAttachment()
{
return attachment;
}
/**
* Specifies the attachment for this entry. This will replace any
* existing attachment that might be defined.
*
* @param attachment The attachment for this entry, or
* <CODE>null</CODE> if there should not be an
* attachment.
*/
{
this.attachment = attachment;
}
/**
* Creates a duplicate of this entry that may be altered without
* impacting the information in this entry.
*
* @param processVirtual Indicates whether virtual attribute
* processing should be performed for the
* entry.
*
* @return A duplicate of this entry that may be altered without
* impacting the information in this entry.
*/
{
userAttributes.size());
{
if (t.isOperational())
{
}
else
{
}
}
if (processVirtual)
{
}
return e;
}
/**
* Creates a duplicate of this entry without any operational
* attributes that may be altered without impacting the information
* in this entry.
*
* @param typesOnly Indicates whether to include attribute
* types only without values.
* @param processVirtual Indicates whether virtual attribute
* processing should be performed for the
* entry.
*
* @return A duplicate of this entry that may be altered without
* impacting the information in this entry and that does
* not contain any operational attributes.
*/
boolean typesOnly, boolean processVirtual)
{
if (typesOnly)
{
}
else
{
}
userAttributes.size());
if (typesOnly)
{
// Make sure to include the objectClass attribute here because
// it won't make it in otherwise.
}
{
if (! t.isOperational())
{
}
}
if (processVirtual)
{
e.processVirtualAttributes(false);
}
return e;
}
/**
* Performs a deep copy from the source map to the target map. In
* this case, the attributes in the list will be duplicates rather
* than re-using the same reference. Virtual attributes will not be
* included when making the copy.
*
* @param source The source map from which to obtain the
* information.
* @param target The target map into which to place the
* copied information.
* @param omitValues Indicates whether to omit attribute values
* when processing.
*/
boolean omitValues)
{
{
for (Attribute a : sourceList)
{
if (a.isVirtual())
{
continue;
}
if (omitValues)
{
}
else
{
targetList.add(a);
}
}
if (! targetList.isEmpty())
{
}
}
}
/**
* Creates a duplicate of this entry without any attribute or
* objectclass information (i.e., it will just contain the DN and
* placeholders for adding attributes) and objectclasses.
*
* @return A duplicate of this entry that may be altered without
* impacting the information in this entry and that does
* not contain attribute or objectclass information.
*/
public Entry duplicateWithoutAttributes()
{
userAttributes.size());
}
/**
* Indicates whether this entry meets the criteria to consider it a
* referral (e.g., it contains the "referral" objectclass and a
* "ref" attribute).
*
* @return <CODE>true</CODE> if this entry meets the criteria to
* consider it a referral, or <CODE>false</CODE> if not.
*/
public boolean isReferral()
{
if (referralOC == null)
{
// This should not happen -- The server doesn't have a referral
// objectclass defined.
if (debugEnabled())
{
"No %s objectclass is defined in the server schema.",
}
{
{
return true;
}
}
return false;
}
{
return false;
}
if (referralType == null)
{
// This should not happen -- The server doesn't have a ref
// attribute type defined.
if (debugEnabled())
{
"No %s attribute type is defined in the server schema.",
}
return false;
}
}
/**
* Retrieves the set of referral URLs that are included in this
* referral entry. This should only be called if
* <CODE>isReferral()</CODE> returns <CODE>true</CODE>.
*
* @return The set of referral URLs that are included in this entry
* if it is a referral, or <CODE>null</CODE> if it is not a
* referral.
*/
{
if (referralType == null)
{
// This should not happen -- The server doesn't have a ref
// attribute type defined.
if (debugEnabled())
{
"No %s attribute type is defined in the server schema.",
}
return null;
}
{
{
return null;
}
}
{
for (AttributeValue v : a)
{
}
}
return referralURLs;
}
/**
* Indicates whether this entry meets the criteria to consider it an
* alias (e.g., it contains the "aliasObject" objectclass and a
* "alias" attribute).
*
* @return <CODE>true</CODE> if this entry meets the criteria to
* consider it an alias, or <CODE>false</CODE> if not.
*/
public boolean isAlias()
{
{
// This should not happen -- The server doesn't have an alias
// objectclass defined.
if (debugEnabled())
{
"No %s objectclass is defined in the server schema.",
OC_ALIAS);
}
{
{
return true;
}
}
return false;
}
{
return false;
}
{
// This should not happen -- The server doesn't have an
// aliasedObjectName attribute type defined.
if (debugEnabled())
{
"No %s attribute type is defined in the server schema.",
}
return false;
}
}
/**
* Retrieves the DN of the entry referenced by this alias entry.
* This should only be called if <CODE>isAlias()</CODE> returns
* <CODE>true</CODE>.
*
* @return The DN of the entry referenced by this alias entry, or
* <CODE>null</CODE> if it is not an alias.
*
* @throws DirectoryException If there is an aliasedObjectName
* attribute but its value cannot be
* parsed as a DN.
*/
public DN getAliasedDN()
throws DirectoryException
{
{
// This should not happen -- The server doesn't have an
// aliasedObjectName attribute type defined.
if (debugEnabled())
{
"No %s attribute type is defined in the server schema.",
}
return null;
}
if (aliasAttrs == null)
{
if (aliasAttrs == null)
{
return null;
}
}
if (aliasAttrs.isEmpty())
{
return null;
}
else
{
// There should only be a single alias attribute in an entry,
// and we'll skip the check for others for performance reasons.
// We would just end up taking the first one anyway. The same
// is true with the set of values, since it should be a
// single-valued attribute.
{
return null;
}
else
{
}
}
}
/**
* Indicates whether this entry meets the criteria to consider it an
* LDAP subentry (i.e., it contains the "ldapSubentry" objectclass).
*
* @return <CODE>true</CODE> if this entry meets the criteria to
* consider it an LDAP subentry, or <CODE>false</CODE> if
* not.
*/
public boolean isLDAPSubentry()
{
if (ldapSubentryOC == null)
{
// This should not happen -- The server doesn't have an
// ldapsubentry objectclass defined.
if (debugEnabled())
{
"No %s objectclass is defined in the server schema.",
}
{
{
return true;
}
}
return false;
}
// Make the determination based on whether this entry has the
// ldapSubentry objectclass.
}
/**
* Indicates whether this entry falls within the range of the
* provided search base DN and scope.
*
* @param baseDN The base DN for which to make the determination.
* @param scope The search scope for which to make the
* determination.
*
* @return <CODE>true</CODE> if this entry is within the given
* base and scope, or <CODE>false</CODE> if it is not.
*/
{
}
/**
* Performs any necessary virtual attribute processing for this
* entry. This should only be called at the time the entry is
* decoded or created within the backend.
*/
public void processVirtualAttributes()
{
processVirtualAttributes(true);
}
/**
* Performs any necessary virtual attribute processing for this
* entry. This should only be called at the time the entry is
* decoded or created within the backend.
*
* @param includeOperational Indicates whether to include
* operational attributes.
*/
public void processVirtualAttributes(boolean includeOperational)
{
for (VirtualAttributeRule rule :
{
{
continue;
}
{
{
// There aren't any conflicts, so we can just add the
// attribute to the entry.
rule));
if (attributeType.isOperational())
{
}
else
{
}
}
else
{
// There is a conflict with an existing operational
// attribute.
{
// The existing attribute is already virtual, so we've got
// a different conflict, but we'll let the first win.
// FIXME -- Should we handle this differently?
continue;
}
// The conflict is with a real attribute. See what the
// conflict behavior is and figure out how to handle it.
switch (rule.getConflictBehavior())
{
case REAL_OVERRIDES_VIRTUAL:
// We don't need to update the entry because the real
// attribute will take precedence.
break;
case VIRTUAL_OVERRIDES_REAL:
// We need to move the real attribute to the suppressed
// list and replace it with the virtual attribute.
rule));
break;
case MERGE_REAL_AND_VIRTUAL:
// We need to add the virtual attribute to the list and
// keep the existing real attribute(s).
rule));
break;
}
}
}
else
{
// There is a conflict with an existing user attribute.
{
// The existing attribute is already virtual, so we've got
// a different conflict, but we'll let the first win.
// FIXME -- Should we handle this differently?
continue;
}
// The conflict is with a real attribute. See what the
// conflict behavior is and figure out how to handle it.
switch (rule.getConflictBehavior())
{
case REAL_OVERRIDES_VIRTUAL:
// We don't need to update the entry because the real
// attribute will take precedence.
break;
case VIRTUAL_OVERRIDES_REAL:
// We need to move the real attribute to the suppressed
// list and replace it with the virtual attribute.
rule));
break;
case MERGE_REAL_AND_VIRTUAL:
// We need to add the virtual attribute to the list and
// keep the existing real attribute(s).
rule));
break;
}
}
}
}
/**
* Indicates whether virtual attribute processing has been performed
* for this entry.
*
* @return {@code true} if virtual attribute processing has been
* performed for this entry, or {@code false} if not.
*/
public boolean virtualAttributeProcessingPerformed()
{
}
/**
* Strips out all real attributes from this entry so that it only
* contains virtual attributes.
*/
public void stripRealAttributes()
{
// The objectClass attribute will always be a real attribute.
while (attrListIterator.hasNext())
{
while (attrIterator.hasNext())
{
if (! a.isVirtual())
{
}
}
{
}
}
while (attrListIterator.hasNext())
{
while (attrIterator.hasNext())
{
if (! a.isVirtual())
{
}
}
{
}
}
}
/**
* Strips out all virtual attributes from this entry so that it only
* contains real attributes.
*/
public void stripVirtualAttributes()
{
while (attrListIterator.hasNext())
{
while (attrIterator.hasNext())
{
if (a.isVirtual())
{
}
}
{
}
}
while (attrListIterator.hasNext())
{
while (attrIterator.hasNext())
{
if (a.isVirtual())
{
}
}
{
}
}
}
/**
* Encodes this entry into a form that is suitable for long-term
* persistent storage. The encoding will have a version number so
* that if the way we store entries changes in the future we will
* still be able to read entries encoded in an older format.
*
* @param config The configuration that may be used to control how
* the entry is encoded.
*
* @return The entry encoded in a form that is suitable for
* long-term persistent storage.
*
* @throws DirectoryException If a problem occurs while attempting
* to encode the entry.
*/
throws DirectoryException
{
}
/**
* Encodes this entry using the V1 encoding.
*
* @return The entry encoded in the V1 encoding.
*/
public byte[] encodeV1()
{
// The version number will be one byte. We'll add that later.
// The DN will be encoded as a one-to-five byte length followed
// byte the UTF-8 byte representation.
// The object classes will be encoded as one-to-five byte length
// followed by a zero-delimited UTF-8 byte representation of the
// names (e.g., top\0person\0organizationalPerson\0inetOrgPerson).
int i=0;
{
}
// The user attributes will be encoded as a one-to-five byte
// number of attributes followed by a sequence of:
// - A UTF-8 byte representation of the attribute name.
// - A zero delimiter
// - A one-to-five byte number of values for the attribute
// - A sequence of:
// - A one-to-five byte length for the value
// - A UTF-8 byte representation for the value
i=0;
int numUserAttributes = 0;
int totalUserAttrBytes = 0;
{
{
{
continue;
}
int numValues = 0;
int totalValueBytes = 0;
for (AttributeValue v : a)
{
numValues++;
byte[] vBytes = v.getValueBytes();
}
totalValueBytes + 1];
for (byte[] b : valueBytes)
{
}
}
}
byte[] userAttrCount =
// The operational attributes will be encoded in the same way as
// the user attributes.
i=0;
int numOperationalAttributes = 0;
int totalOperationalAttrBytes = 0;
LinkedList<byte[]> operationalAttrBytes =
new LinkedList<byte[]>();
{
{
{
continue;
}
int numValues = 0;
int totalValueBytes = 0;
for (AttributeValue v : a)
{
numValues++;
byte[] vBytes = v.getValueBytes();
}
totalValueBytes + 1];
for (byte[] b : valueBytes)
{
}
}
}
byte[] operationalAttrCount =
// Now we've got all the data that we need. Create a big byte
// array to hold it all and pack it in.
byte[] entryBytes = new byte[totalBytes];
// Add the entry version number as the first byte.
// Next, add the DN length and value.
// Next, add the object classes length and values.
for (byte[] b : ocBytes)
{
}
// We need to back up one because there's no zero-teriminator
// after the last object class name.
pos--;
// Next, add the user attribute count and the user attribute
// data.
for (byte[] b : userAttrBytes)
{
}
// Finally, add the operational attribute count and the
// operational attribute data.
for (byte[] b : operationalAttrBytes)
{
}
return entryBytes;
}
/**
* Encodes this entry using the V2 encoding.
*
* @param config The configuration that should be used to encode
* the entry.
*
* @return The entry encoded in the V2 encoding.
*
* @throws DirectoryException If a problem occurs while attempting
* to encode the entry.
*/
throws DirectoryException
{
// The version number will be one byte. We'll add that later.
// Get the encoded respresentation of the config.
byte[] configLength =
// If we should include the DN, then it will be encoded as a
// one-to-five byte length followed by the UTF-8 byte
// representation.
{
}
// Encode the object classes in the appropriate manner.
byte[] ocLength;
if (config.compressObjectClassSets())
{
byte[] b = config.getCompressedSchema().
}
else
{
{
totalOCBytes += b.length;
}
}
// Encode the user attributes in the appropriate manner.
int numUserAttributes = 0;
int totalUserAttrBytes = 0;
{
{
{
{
continue;
}
byte[] attrBytes =
byte[] lengthBytes =
}
}
}
else
{
// The user attributes will be encoded as a one-to-five byte
// number of attributes followed by a sequence of:
// - A UTF-8 byte representation of the attribute name.
// - A zero delimiter
// - A one-to-five byte number of values for the attribute
// - A sequence of:
// - A one-to-five byte length for the value
// - A UTF-8 byte representation for the value
{
{
{
continue;
}
int numValues = 0;
int totalValueBytes = 0;
for (AttributeValue v : a)
{
numValues++;
byte[] vBytes = v.getValueBytes();
}
totalValueBytes + 1];
for (byte[] b : valueBytes)
{
}
}
}
}
byte[] userAttrCount =
// Encode the operational attributes in the appropriate manner.
int numOperationalAttributes = 0;
int totalOperationalAttrBytes = 0;
LinkedList<byte[]> operationalAttrBytes =
new LinkedList<byte[]>();
{
{
{
{
continue;
}
byte[] attrBytes =
byte[] lengthBytes =
}
}
}
else
{
// Encode the operational attributes in the same way as the user
// attributes.
{
{
{
continue;
}
int numValues = 0;
int totalValueBytes = 0;
for (AttributeValue v : a)
{
numValues++;
byte[] vBytes = v.getValueBytes();
}
totalValueBytes + 1];
for (byte[] b : valueBytes)
{
}
}
}
}
byte[] operationalAttrCount =
// Now we've got all the data that we need. Create a big byte
// array to hold it all and pack it in.
byte[] entryBytes = new byte[totalBytes];
// Add the entry version number as the first byte.
// Next, add the encoded config.
// Next, add the DN length and value.
{
}
// Next, add the object classes length and values.
if (config.compressObjectClassSets())
{
for (byte[] b : ocBytes)
{
}
}
else
{
for (byte[] b : ocBytes)
{
}
// We need to back up one because there's no zero-teriminator
// after the last object class name.
pos--;
}
// Next, add the user attribute count and the user attribute
// data.
for (byte[] b : userAttrBytes)
{
}
// Finally, add the operational attribute count and the
// operational attribute data.
for (byte[] b : operationalAttrBytes)
{
}
return entryBytes;
}
/**
* Decodes the provided byte array as an entry.
*
* @param entryBytes The byte array containing the data to be
* decoded.
*
* @return The decoded entry.
*
* @throws DirectoryException If the provided byte array cannot be
* decoded as an entry.
*/
throws DirectoryException
{
return decode(entryBytes,
}
/**
* Decodes the provided byte array as an entry.
*
* @param entryBytes The byte array containing the data to
* be decoded.
* @param compressedSchema The compressed schema manager to use
* when decoding tokenized schema
* elements.
*
* @return The decoded entry.
*
* @throws DirectoryException If the provided byte array cannot be
* decoded as an entry.
*/
throws DirectoryException
{
switch(entryBytes[0])
{
case 0x01:
return decodeV1(entryBytes);
case 0x02:
default:
throw new DirectoryException(
message);
}
}
/**
* Decodes the provided byte array as an entry using the V1
* encoding.
*
* @param entryBytes The byte array containing the data to be
* decoded.
*
* @return The decoded entry.
*
* @throws DirectoryException If the provided byte array cannot be
* decoded as an entry.
*/
throws DirectoryException
{
try
{
// The first byte must be the entry version. If it's not one
// we recognize, then that's an error.
{
throw new DirectoryException(
message);
}
// Next is the length of the DN. It may be a single byte or
// multiple bytes.
int pos = 1;
{
int numLengthBytes = dnLength;
dnLength = 0;
{
}
}
// Next is the DN itself.
// Next is the length of the object classes. It may be a single
// byte or multiple bytes.
{
int numLengthBytes = ocLength;
ocLength = 0;
{
}
}
// Next is the encoded set of object classes. It will be a
// single string with the object class names separated by zeros.
{
{
"UTF-8");
}
}
"UTF-8");
// Next is the total number of user attributes. It may be a
// single byte or multiple bytes.
{
int numLengthBytes = numUserAttrs;
numUserAttrs = 0;
{
}
}
// Now, we should iterate through the user attributes and decode
// each one.
for (int i=0; i < numUserAttrs; i++)
{
// First, we have the zero-terminated attribute name.
{
pos++;
}
"UTF-8");
if (semicolonPos > 0)
{
while (nextPos > 0)
{
{
}
}
{
}
}
else
{
}
// Next, we have the number of values.
{
int numLengthBytes = numValues;
numValues = 0;
{
}
}
// Next, we have the sequence of length-value pairs.
for (int j=0; j < numValues; j++)
{
{
int numLengthBytes = valueLength;
valueLength = 0;
{
}
}
byte[] valueBytes = new byte[valueLength];
new ASN1OctetString(valueBytes)));
pos += valueLength;
}
// Create the attribute and add it to the set of user
// attributes.
{
}
else
{
}
}
// Next is the total number of operational attributes. It may
// be a single byte or multiple bytes.
{
numOperationalAttrs = 0;
{
}
}
// Now, we should iterate through the operational attributes and
// decode each one.
for (int i=0; i < numOperationalAttrs; i++)
{
// First, we have the zero-terminated attribute name.
{
pos++;
}
"UTF-8");
if (semicolonPos > 0)
{
while (nextPos > 0)
{
{
}
}
{
}
}
else
{
}
// Next, we have the number of values.
{
int numLengthBytes = numValues;
numValues = 0;
{
}
}
// Next, we have the sequence of length-value pairs.
for (int j=0; j < numValues; j++)
{
{
int numLengthBytes = valueLength;
valueLength = 0;
{
}
}
byte[] valueBytes = new byte[valueLength];
new ASN1OctetString(valueBytes)));
pos += valueLength;
}
// Create the attribute and add it to the set of operational
// attributes.
{
}
else
{
}
}
// We've got everything that we need, so create and return the
// entry.
}
catch (DirectoryException de)
{
throw de;
}
catch (Exception e)
{
if (debugEnabled())
{
}
throw new DirectoryException(
message, e);
}
}
/**
* Decodes the provided byte array as an entry using the V2
* encoding.
*
* @param entryBytes The byte array containing the data to
* be decoded.
* @param compressedSchema The compressed schema manager to use
* when decoding tokenized schema
* elements.
*
* @return The decoded entry.
*
* @throws DirectoryException If the provided byte array cannot be
* decoded as an entry.
*/
throws DirectoryException
{
try
{
// The first byte must be the entry version. If it's not one
// we recognize, then that's an error.
{
throw new DirectoryException(
message);
}
// Next is the length of the encoded configuration. It may be a
// single byte or multiple bytes.
int pos = 1;
{
int numLengthBytes = configLength;
configLength = 0;
{
}
}
// Next is the encoded configuration itself.
pos += configLength;
// If we should have included the DN in the entry, then it's
// next.
{
}
else
{
// Next is the length of the DN. It may be a single byte or
// multiple bytes.
{
int numLengthBytes = dnLength;
dnLength = 0;
{
}
}
// Next is the DN itself.
}
// Next is the length of the object classes. It may be a single
// byte or multiple bytes.
{
int numLengthBytes = ocLength;
ocLength = 0;
{
}
}
// Next is the set of encoded object classes. The encoding will
// depend on the configuration.
if (config.compressObjectClassSets())
{
}
else
{
// The set of object classes will be encoded as a single
// string with the oibject class names separated by zeros.
{
{
}
}
"UTF-8");
}
// Next is the total number of user attributes. It may be a
// single byte or multiple bytes.
{
int numLengthBytes = numUserAttrs;
numUserAttrs = 0;
{
}
}
// Now, we should iterate through the user attributes and decode
// each one.
{
for (int i=0; i < numUserAttrs; i++)
{
// Get the length of the attribute.
{
int attrLengthBytes = attrLength;
attrLength = 0;
{
}
}
// Decode the attribute.
{
}
pos += attrLength;
}
}
else
{
for (int i=0; i < numUserAttrs; i++)
{
// First, we have the zero-terminated attribute name.
{
pos++;
}
"UTF-8");
if (semicolonPos > 0)
{
while (nextPos > 0)
{
{
}
}
{
}
}
else
{
}
// Next, we have the number of values.
{
int numLengthBytes = numValues;
numValues = 0;
{
}
}
// Next, we have the sequence of length-value pairs.
for (int j=0; j < numValues; j++)
{
{
int numLengthBytes = valueLength;
valueLength = 0;
{
}
}
byte[] valueBytes = new byte[valueLength];
new ASN1OctetString(valueBytes)));
pos += valueLength;
}
// Create the attribute and add it to the set of user
// attributes.
{
}
else
{
}
}
}
// Next is the total number of operational attributes. It may
// be a single byte or multiple bytes.
{
numOperationalAttrs = 0;
{
}
}
// Now, we should iterate through the operational attributes and
// decode each one.
{
for (int i=0; i < numOperationalAttrs; i++)
{
// Get the length of the attribute.
{
int attrLengthBytes = attrLength;
attrLength = 0;
{
}
}
// Decode the attribute.
{
}
pos += attrLength;
}
}
else
{
for (int i=0; i < numOperationalAttrs; i++)
{
// First, we have the zero-terminated attribute name.
{
pos++;
}
"UTF-8");
if (semicolonPos > 0)
{
while (nextPos > 0)
{
{
}
}
{
}
}
else
{
}
// Next, we have the number of values.
{
int numLengthBytes = numValues;
numValues = 0;
{
}
}
// Next, we have the sequence of length-value pairs.
for (int j=0; j < numValues; j++)
{
{
int numLengthBytes = valueLength;
valueLength = 0;
{
}
}
byte[] valueBytes = new byte[valueLength];
new ASN1OctetString(valueBytes)));
pos += valueLength;
}
// Create the attribute and add it to the set of operational
// attributes.
{
}
else
{
}
}
}
// We've got everything that we need, so create and return the
// entry.
}
catch (DirectoryException de)
{
throw de;
}
catch (Exception e)
{
if (debugEnabled())
{
}
throw new DirectoryException(
message, e);
}
}
/**
* Retrieves a list of the lines for this entry in LDIF form. Long
* lines will not be wrapped automatically.
*
* @return A list of the lines for this entry in LDIF form.
*/
{
new LinkedList<StringBuilder>();
// First, append the DN.
// Next, add the set of objectclasses.
{
}
// Next, add the set of user attributes.
{
{
for (String o : a.getOptions())
{
}
for (AttributeValue v : a)
{
}
}
}
// Finally, add the set of operational attributes.
{
{
for (String o : a.getOptions())
{
}
for (AttributeValue v : a)
{
}
}
}
return ldifLines;
}
/**
* Writes this entry in LDIF form according to the provided
* configuration.
*
* @param exportConfig The configuration that specifies how the
* entry should be written.
*
* @return <CODE>true</CODE> if the entry is actually written, or
* <CODE>false</CODE> if it is not for some reason.
*
* @throws IOException If a problem occurs while writing the
* information.
*
* @throws LDIFException If a problem occurs while trying to
* determine whether to write the entry.
*/
throws IOException, LDIFException
{
// See if this entry should be included in the export at all.
try
{
if (! exportConfig.includeEntry(this))
{
if (debugEnabled())
{
"Skipping entry %s because of the export " +
}
return false;
}
}
catch (Exception e)
{
if (debugEnabled())
{
}
throw new LDIFException(message, e);
}
// Invoke LDIF export plugins on the entry if appropriate.
if (exportConfig.invokeExportPlugins())
{
this);
if (! pluginResult.continueProcessing())
{
return false;
}
}
// Get the information necessary to write the LDIF.
// First, write the DN. It will always be included.
// Next, the set of objectclasses.
if (exportConfig.includeObjectClasses())
{
if (typesOnly)
{
}
else
{
{
}
}
}
else
{
if (debugEnabled())
{
"Skipping objectclasses for entry %s because of " +
}
}
// Now the set of user attributes.
{
{
{
if (a.isVirtual() &&
{
continue;
}
if (typesOnly)
{
for (String o : a.getOptions())
{
}
}
else
{
for (String o : a.getOptions())
{
}
for (AttributeValue v : a)
{
v.getValueBytes());
}
}
}
}
else
{
if (debugEnabled())
{
"Skipping user attribute %s for entry %s because of " +
"the export configuration.",
}
}
}
// Next, the set of operational attributes.
{
{
{
{
if (a.isVirtual() &&
{
continue;
}
if (typesOnly)
{
for (String o : a.getOptions())
{
}
}
else
{
for (String o : a.getOptions())
{
}
for (AttributeValue v : a)
{
v.getValueBytes());
}
}
}
}
else
{
if (debugEnabled())
{
"Skipping operational attribute %s for entry %s " +
"because of the export configuration.",
}
}
}
}
else
{
if (debugEnabled())
{
"Skipping all operational attributes for entry %s " +
"because of the export configuration.",
}
}
// If we are not supposed to include virtual attributes, then
// write any attributes that may normally be suppressed by a
// virtual attribute.
if (! exportConfig.includeVirtualAttributes())
{
{
if (exportConfig.includeAttribute(t))
{
{
if (typesOnly)
{
for (String o : a.getOptions())
{
}
}
else
{
for (String o : a.getOptions())
{
}
for (AttributeValue v : a)
{
v.getValueBytes());
}
}
}
}
}
}
// Make sure there is a blank line after the entry.
return true;
}
/**
* Retrieves the name of the protocol associated with this protocol
* element.
*
* @return The name of the protocol associated with this protocol
* element.
*/
public String getProtocolElementName()
{
return "Entry";
}
/**
* Retrieves a hash code for this entry.
*
* @return The hash code for this entry.
*/
@Override()
public int hashCode()
{
{
}
{
{
}
}
{
{
}
}
return hashCode;
}
/**
* Indicates whether the provided object is equal to this entry. In
* order for the object to be considered equal, it must be an entry
* with the same DN, set of object classes, and set of user and
* operational attributes.
*
* @param o The object for which to make the determination.
*
* @return {@code true} if the provided object may be considered
* equal to this entry, or {@code false} if not.
*/
@Override()
{
if (this == o)
{
return true;
}
if (o == null)
{
return false;
}
if (! (o instanceof Entry))
{
return false;
}
{
return false;
}
{
return false;
}
{
{
return false;
}
{
{
return false;
}
}
}
{
{
return false;
}
{
{
return false;
}
}
}
return true;
}
/**
* Retrieves a string representation of this protocol element.
*
* @return A string representation of this protocol element.
*/
{
}
/**
* Appends a string representation of this protocol element to the
* provided buffer.
*
* @param buffer The buffer into which the string representation
* should be written.
*/
{
if (! objectClasses.isEmpty())
{
{
}
}
if (! userAttributes.isEmpty())
{
{
}
}
if (! operationalAttributes.isEmpty())
{
{
}
}
}
/**
* Appends a string representation of this protocol element to the
* provided buffer.
*
* @param buffer The buffer into which the string representation
* should be written.
* @param indent The number of spaces that should be used to
* indent the resulting string representation.
*/
{
for (int i=0 ; i < indent; i++)
{
}
for (StringBuilder b : toLDIF())
{
}
}
/**
* Retrieves a string representation of this entry in LDIF form.
*
* @return A string representation of this entry in LDIF form.
*/
public String toLDIFString()
{
{
}
}
/**
* Retrieves a one-line representation of this entry.
*
* @return A one-line representation of this entry.
*/
public String toSingleLineString()
{
}
/**
* Appends a single-line representation of this entry to the
* provided buffer.
*
* @param buffer The buffer to which the information should be
* written.
*/
{
{
{
}
}
boolean firstAttr = true;
{
{
if (firstAttr)
{
firstAttr = false;
}
else
{
}
if (a.hasOptions())
{
{
}
}
if (valueIterator.hasNext())
{
while (valueIterator.hasNext())
{
}
}
}
}
{
{
if (firstAttr)
{
firstAttr = false;
}
else
{
}
if (a.hasOptions())
{
{
}
}
if (valueIterator.hasNext())
{
while (valueIterator.hasNext())
{
}
}
}
}
}
/**
* Retrieves the requested attribute element for the specified
* attribute type and options or <code>null</code> if this entry
* does not contain an attribute with the specified attribute type
* and options.
*
* @param attributeType
* The attribute type to retrieve.
* @param options
* The set of attribute options.
* @return The requested attribute element for the specified
* attribute type and options, or <code>null</code> if the
* specified attribute type is not present in this entry
* with the provided set of options.
*/
{
if (attributeType.isOperational())
{
}
else
{
}
if (attributes != null)
{
{
{
return attribute;
}
}
}
return null;
}
/**
* Adds the provided attribute to this entry. If an attribute with
* the provided type and options already exists, then it will be
* either merged or replaced depending on the value of
* <code>replace</code>.
*
* @param attribute
* @param duplicateValues
* A list to which any duplicate values will be added.
* @param replace
* <code>true</code> if the attribute should replace any
* existing attribute.
*/
{
attachment = null;
{
// We will not do any validation of the object classes - this is
// left to the caller.
if (replace)
{
}
for (AttributeValue v : attribute)
{
try
{
}
catch (Exception e)
{
if (debugEnabled())
{
}
}
// Create a default object class if necessary.
if (replace)
{
}
else
{
{
duplicateValues.add(v);
}
else
{
}
}
}
return;
}
if (attributeType.isOperational())
{
}
else
{
}
if (attributes == null)
{
// Do nothing if we are deleting a non-existing attribute.
{
return;
}
// We are adding the first attribute with this attribute type.
if (attributeType.isOperational())
{
}
else
{
}
return;
}
// There are already attributes with the same attribute type.
{
if (a.optionsEqual(options))
{
if (replace)
{
{
}
else
{
attributes.remove(i);
if (attributes.isEmpty())
{
if (attributeType.isOperational())
{
}
else
{
}
}
}
}
else
{
for (AttributeValue v : attribute)
{
{
duplicateValues.add(v);
}
}
}
return;
}
}
// There were no attributes with the same options.
{
// Do nothing.
return;
}
}
}