Entry.java revision cf364c082dfe5ea566abc3c20bc5546a4629c5eb
/*
* 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 legal-notices/CDDLv1_0.txt
* 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 legal-notices/CDDLv1_0.txt.
* 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-2010 Sun Microsystems, Inc.
* Portions Copyright 2011-2015 ForgeRock AS
*/
/**
* 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 set of operational attributes for this entry. */
/** The set of user attributes for this entry. */
/**
* The set of suppressed real attributes for this entry. It contains real
* attributes that have been overridden by virtual attributes.
*/
/** The set of objectclasses for this entry. */
private Attribute objectClassAttribute;
/** 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.
*/
{
}
/**
* Returns a new Map if the passed in Map is null.
*
* @param <K>
* the type of the key
* @param <V>
* the type of the value
* @param map
* the map to test
* @return a new Map if the passed in Map is null.
*/
{
{
return map;
}
return new HashMap<K, V>();
}
/**
* 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)
{
}
{
}
}
}
return structuralClass;
}
/**
* 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;
{
}
}
/**
* 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.
*/
{
// Estimate the size.
{
}
{
}
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;
}
if(objectClassAttribute == null)
{
{
}
}
return objectClassAttribute;
}
/**
* 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.isObjectClass())
{
}
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 (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 (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;
}
/**
* Returns the attributes Map corresponding to the operational status of the
* supplied attribute type.
*
* @param attrType
* the attribute type
* @return the user of operational attributes Map
*/
{
if (attrType.isOperational())
{
return operationalAttributes;
}
return userAttributes;
}
/**
* Return the List of attributes for the passed in attribute type.
*
* @param attrType
* the attribute type
* @return the List of user or operational attributes
*/
{
}
/**
* Puts the supplied List of attributes for the passed in attribute type into
* the map of attributes.
*
* @param attrType
* the attribute type
* @param attributes
* the List of user or operational attributes to put
*/
{
}
/**
* Removes the List of attributes for the passed in attribute type from the
* map of attributes.
*
* @param attrType
* the attribute type
*/
{
}
/**
* 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 (!attributes.isEmpty())
{
return attributes;
}
return null;
}
if (attributes != null)
{
return attributes;
}
if (attributes != null)
{
return attributes;
}
{
return newList(getObjectClassAttribute());
}
return null;
}
/**
* Add to the destination all the elements from a non null source .
*
* @param dest
* the destination where to add
* @param source
* the source with the elements to be added
*/
{
{
}
}
/**
* 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,
{
{
{
}
}
else
{
{
{
if (attributeType.isObjectClass()
&& !objectClasses.isEmpty()
{
return attributes;
}
return null;
}
}
}
if (!attributes.isEmpty())
{
return attributes;
}
return null;
}
/**
* 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;
}
return null;
}
/**
* Returns a parser for the named attribute contained in this entry.
* <p>
* The attribute description will be decoded using the schema associated
* with this entry (usually the default schema).
*
* @param attributeDescription
* The name of the attribute to be parsed.
* @return A parser for the named attribute.
* @throws LocalizedIllegalArgumentException
* If {@code attributeDescription} could not be decoded using
* the schema associated with this entry.
* @throws NullPointerException
* If {@code attributeDescription} was {@code null}.
*/
{
}
/**
* 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.
*/
{
}
/**
* Returns the List of attributes for a given attribute type.
*
* @param attributeType
* the attribute type to be looked for
* @param attrs
* the attributes Map where to find the attributes
* @return the List of attributes
*/
{
{
{
}
if (!attributes.isEmpty())
{
return attributes;
}
return null;
}
}
/**
* 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.
*/
{
}
/**
* Returns the List of attributes for a given attribute type having all the
* required options.
*
* @param attributeType
* the attribute type to be looked for
* @param options
* the options that must all be present
* @param attrs
* the attributes Map where to find the attributes
* @return the filtered List of attributes
*/
{
{
{
}
}
if (!attributes.isEmpty())
{
return attributes;
}
return null;
}
/**
* Removes all the attributes that do not have all the supplied options.
*
* @param attributes
* the attributes to filter.
* @param options
* the options to look for
*/
{
{
if (!a.hasAllOptions(options))
{
}
}
}
/**
* 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.
*/
{
}
/**
* 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.
*/
{
}
/**
* 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;
}
}
/**
* 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.
if (a == null)
{
}
// Decode the increment.
if (!i.hasNext())
{
}
long increment;
try
{
}
catch (NumberFormatException e)
{
}
if (i.hasNext())
{
}
// Increment each attribute value by the specified amount.
for (ByteString v : a)
{
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.isObjectClass())
{
return true;
}
}
/**
* 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 (ByteString v : attribute)
{
boolean matchFound = false;
{
{
matchFound = true;
break;
}
}
if (!matchFound)
{
allSuccessful = false;
missingValues.add(v);
}
}
return allSuccessful;
}
if (attributes == null)
{
// There are no attributes with the same attribute type.
for (ByteString 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 (ByteString 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())
{
}
return true;
}
}
// No matching attribute found.
return false;
}
{
try
{
}
catch (Exception e)
{
logger.traceException(e);
}
}
/**
* 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;
}
{
{
return true;
}
}
return false;
}
/**
* Applies the provided modification to this entry. No schema
* checking will be performed.
*
* @param mod The modification to apply to this entry.
* @param relaxConstraints indicates if the modification
* constraints are relaxed to match
* the ones of a set (add existing
* value and delete absent value do not fail)
*
* @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.isObjectClass())
{
for (ByteString v : a)
{
}
{
case ADD:
{
{
if (!relaxConstraints)
{
}
}
else
{
}
}
break;
case DELETE:
{
{
}
}
break;
case REPLACE:
objectClasses = ocs;
break;
case INCREMENT:
default:
}
return;
}
{
case ADD:
{
}
break;
case DELETE:
{
}
break;
case REPLACE:
replaceAttribute(a);
break;
case INCREMENT:
break;
default:
}
}
/**
* 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.
*/
{
applyModification(mod, false);
}
/**
* 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;
{
{
{
}
{
dn,
oc.getNameOrOID());
{
return false;
}
{
multipleOCErrorLogged = true;
}
}
}
}
if (structuralClass == null)
{
{
return false;
}
{
}
}
else
{
{
}
{
return false;
}
if (validateNameForms)
{
/**
* There may be multiple nameforms registered with this
* structural objectclass.However, we need to select only one
* of the nameforms and its corresponding DITstructure rule.
* We will iterate over all the nameforms and see if atleast
* one is acceptable before rejecting the entry.
* DITStructureRules corresponding to other non-acceptable
* nameforms are not applied.
*/
{
boolean matchFound = false;
boolean obsolete = true;
{
if(!nf.isObsolete())
{
obsolete = false;
if(matchFound)
{
break;
}
{
}
}
}
if(! obsolete && !matchFound)
{
// We couldn't match this entry against any of the nameforms.
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;
}
}
/**
* 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.
{
{
return false;
}
(ditContentRule != null) &&
{
dn,
o.getNameOrOID(),
{
return false;
}
{
}
}
for (AttributeType t : o.getRequiredAttributes())
{
if (!userAttributes.containsKey(t)
&& !operationalAttributes.containsKey(t)
&& !t.isObjectClass())
{
dn,
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;
}
}
{
found = true;
}
if (! found)
{
return false;
}
{
{
if (a.isEmpty())
{
return false;
}
{
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)
{
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))
{
dn,
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))
{
dn,
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)
&& !operationalAttributes.containsKey(t)
&& !t.isObjectClass())
{
dn,
t.getNameOrOID(),
{
return false;
}
{
}
}
}
// Make sure that none of the prohibited attributes are present.
{
if (userAttributes.containsKey(t) ||
{
dn,
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 (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.
{
{
return false;
}
{
}
}
else
{
try
{
if (parentEntry == null)
{
{
return false;
}
{
}
}
else
{
boolean dsrValid =
if (! dsrValid)
{
return false;
}
}
}
catch (Exception e)
{
logger.traceException(e);
dn,
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.
{
{
return false;
}
{
}
}
else
{
try
{
if (parentEntry == null)
{
{
return false;
}
{
}
}
else
{
parentExists = true;
}
}
catch (Exception e)
{
logger.traceException(e);
dn, 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)
{
dn,
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());
true, false);
false, false, true, false);
// Put back all the suppressed attributes where they belonged to.
// Then hopefully processVirtualAttributes() will rebuild the suppressed
// attribute list correctly.
{
if (t.isOperational())
{
}
else
{
}
}
if (processVirtual)
{
}
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.
*
* @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.
* @param omitEmpty
* Indicates whether to omit empty attributes when
* processing.
* @param omitReal
* Indicates whether to exclude real attributes.
* @param omitVirtual
* Indicates whether to exclude virtual attributes.
* @param mergeDuplicates
* Indicates whether duplicate attributes should be merged.
*/
boolean omitValues,
boolean omitEmpty,
boolean omitReal,
boolean omitVirtual,
boolean mergeDuplicates)
{
{
for (Attribute a : sourceList)
{
{
continue;
}
else if (omitVirtual && a.isVirtual())
{
continue;
}
{
continue;
}
if (omitValues)
{
a = Attributes.empty(a);
}
{
// Ensure that there is only one attribute with the same
// type and options. This is not very efficient but will
// occur very rarely.
boolean found = false;
{
{
found = true;
}
}
if (!found)
{
targetList.add(a);
}
}
else
{
targetList.add(a);
}
}
if (!targetList.isEmpty())
{
}
}
}
/**
* 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()
{
}
/**
* Returns whether the current entry has a specific object class or attribute.
*
* @param objectClassName
* the name of the object class to look for
* @param attrTypeName
* the attribute type name of the object class to look for
* @return true if the current entry has the object class or the attribute,
* false otherwise
*/
{
{
// This should not happen
// The server doesn't have this objectclass defined.
if (logger.isTraceEnabled())
{
"No %s objectclass is defined in the server schema.",
}
return containsObjectClassByName(objectClassName);
}
{
return false;
}
{
// This should not happen
// The server doesn't have this attribute type defined.
if (logger.isTraceEnabled())
{
"No %s attribute type is defined in the server schema.",
}
return false;
}
}
/**
* Whether the object class name exists in the objectClass of this entry.
*
* @param objectClassName
* the name of the object class to look for
* @return true if the object class name exists in the objectClass of this
* entry, false otherwise
*/
{
{
{
return true;
}
}
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 (logger.isTraceEnabled())
{
"No %s attribute type is defined in the server schema.",
}
return null;
}
{
{
return null;
}
}
{
for (ByteString 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()
{
}
/**
* 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.
*/
{
{
// This should not happen -- The server doesn't have an
// aliasedObjectName attribute type defined.
if (logger.isTraceEnabled())
{
"No %s attribute type is defined in the server schema.",
}
return null;
}
if (aliasAttrs == null)
{
if (aliasAttrs == null)
{
return null;
}
}
if (!aliasAttrs.isEmpty())
{
// 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;
}
/**
* 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()
{
return hasObjectClass(OC_LDAP_SUBENTRY_LC);
}
/**
* Returns whether the current entry has a specific object class.
*
* @param objectClassLowerCase
* the lowercase name of the object class to look for
* @return true if the current entry has the object class, false otherwise
*/
{
{
// This should not happen
// The server doesn't have this object class defined.
if (logger.isTraceEnabled())
{
"No %s objectclass is defined in the server schema.",
}
}
// Make the determination based on whether this entry has this objectclass.
}
/**
* Indicates whether this entry meets the criteria to consider it
* an RFC 3672 LDAP subentry (i.e., it contains the "subentry"
* objectclass).
*
* @return <CODE>true</CODE> if this entry meets the criteria to
* consider it an RFC 3672 LDAP subentry, or <CODE>false
* </CODE> if not.
*/
public boolean isSubentry()
{
return hasObjectClass(OC_SUBENTRY);
}
/**
* Indicates whether the entry meets the criteria to consider it an
* RFC 3671 LDAP collective attributes subentry (i.e., it contains
* the "collectiveAttributeSubentry" objectclass).
*
* @return <CODE>true</CODE> if this entry meets the criteria to
* consider it an RFC 3671 LDAP collective attributes
* subentry, or <CODE>false</CODE> if not.
*/
public boolean isCollectiveAttributeSubentry()
{
}
/**
* Indicates whether the entry meets the criteria to consider it an
* inherited collective attributes subentry (i.e., it contains
* the "inheritedCollectiveAttributeSubentry" objectclass).
*
* @return <CODE>true</CODE> if this entry meets the criteria to
* consider it an inherited collective attributes
* subentry, or <CODE>false</CODE> if not.
*/
public boolean isInheritedCollectiveAttributeSubentry()
{
}
/**
* Indicates whether the entry meets the criteria to consider it an inherited
* from DN collective attributes subentry (i.e., it contains the
* "inheritedFromDNCollectiveAttributeSubentry" objectclass).
*
* @return <CODE>true</CODE> if this entry meets the criteria to consider it
* an inherited from DN collective attributes subentry, or
* <CODE>false</CODE> if not.
*/
public boolean isInheritedFromDNCollectiveAttributeSubentry()
{
}
/**
* Indicates whether the entry meets the criteria to consider it
* an inherited from RDN collective attributes subentry (i.e.,
* it contains the "inheritedFromRDNCollectiveAttributeSubentry"
* objectclass).
*
* @return <CODE>true</CODE> if this entry meets the criteria to
* consider it an inherited from RDN collective attributes
* subentry, or <CODE>false</CODE> if not.
*/
public boolean isInheritedFromRDNCollectiveAttributeSubentry()
{
}
/**
* Indicates whether the entry meets the criteria to consider it a
* LDAP password policy subentry (i.e., it contains the "pwdPolicy"
* objectclass of LDAP Password Policy Internet-Draft).
*
* @return <CODE>true</CODE> if this entry meets the criteria to
* consider it a LDAP Password Policy Internet-Draft
* subentry, or <CODE>false</CODE> if not.
*/
public boolean isPasswordPolicySubentry()
{
return hasObjectClass(OC_PWD_POLICY_SUBENTRY_LC);
}
/**
* 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 collective attribute processing for this
* entry. This should only be called at the time the entry is
* decoded or created within the backend.
*/
private void processCollectiveAttributes()
{
if (isSubentry() || isLDAPSubentry())
{
return;
}
{
//Subentry manager may not have been initialized by
//a component that doesn't require it.
return;
}
// Get applicable collective subentries.
manager.getCollectiveSubentries(this);
{
// Nothing to see here, move along.
return;
}
// Get collective attribute exclusions.
{
{
{
{
return;
}
}
}
}
// Process collective attributes.
{
{
if (subEntry.isInheritedCollective())
{
if (subEntry.isInheritedFromDNCollective() &&
{
try
{
{
{
// Respect subentry root scope.
if (!inheritFromDN.isDescendantOf(
{
}
break;
}
}
if (inheritFromDN == null)
{
continue;
}
// TODO : ACI check; needs re-factoring to happen.
}
catch (DirectoryException de)
{
}
}
else if (subEntry.isInheritedFromRDNCollective() &&
{
if (inheritFromDN != null)
{
try
{
{
{
value));
break;
}
}
// TODO : ACI check; needs re-factoring to happen.
}
catch (DirectoryException de)
{
}
}
else
{
continue;
}
}
}
{
{
continue;
}
if (subEntry.isInheritedCollective())
{
if (inheritFromEntry != null)
{
{
continue;
}
}
else
{
continue;
}
}
{
{
// There aren't any conflicts, so we can just add the
// attribute to the entry.
}
else
{
// There is a conflict with an existing operational
// attribute.
}
}
else
{
// There is a conflict with an existing user attribute.
}
}
}
}
}
throws DirectoryException
{
try
{
}
catch (DecodeException e)
{
e.getMessageObject(), e);
}
}
/**
* Resolves a conflict arising with a collective attribute.
*
* @param conflictBehavior
* the behavior of the conflict
* @param collectiveAttr
* the attribute in conflict
* @param attrList
* the List of attribute where to resolve the conflict
* @param attributes
* the Map of attributes where to solve the conflict
* @param attributeType
* the attribute type used with the Map
*/
private void resolveCollectiveConflict(
{
{
// 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?
return;
}
// The conflict is with a real attribute. See what the
// conflict behavior is and figure out how to handle it.
switch (conflictBehavior)
{
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.
break;
case MERGE_REAL_AND_VIRTUAL:
// We need to add the virtual attribute to the
// list and keep the existing real attribute(s).
break;
}
}
/**
* 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()
{
// Virtual attributes.
for (VirtualAttributeRule rule :
{
{
{
// There aren't any conflicts, so we can just add the
// attribute to the entry.
}
else
{
// There is a conflict with an existing operational attribute.
}
}
else
{
// There is a conflict with an existing user attribute.
}
}
// Collective attributes.
}
/**
* Resolves a conflict arising with a virtual attribute.
*
* @param rule
* the VirtualAttributeRule in conflict
* @param attrList
* the List of attribute where to resolve the conflict
* @param attributes
* the Map of attribute where to resolve the conflict
* @param attributeType
* the attribute type used with the Map
*/
{
{
// 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?
return;
}
// 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.
break;
case MERGE_REAL_AND_VIRTUAL:
// We need to add the virtual attribute to the list and
// keep the existing real attribute(s).
break;
}
}
/**
* 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 buffer The buffer to encode into.
* @param config The configuration that may be used to control how
* the entry is encoded.
*
* @throws DirectoryException If a problem occurs while attempting
* to encode the entry.
*/
throws DirectoryException
{
}
/**
* Encodes this entry using the V3 encoding.
*
* @param buffer The buffer to encode into.
* @param config The configuration that should be used to encode
* the entry.
*
* @throws DirectoryException If a problem occurs while attempting
* to encode the entry.
*/
throws DirectoryException
{
// The version number will be one byte.
// Get the encoded representation of the config.
// 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.
{
// TODO: Can we encode the DN directly into buffer?
}
// Encode the object classes in the appropriate manner.
if (config.compressObjectClassSets())
{
}
else
{
// Encode number of OCs and 0 terminated names.
{
}
}
// Encode the user attributes in the appropriate manner.
// The operational attributes will be encoded in the same way as
// the user attributes.
}
/**
* Encode the given attributes of an entry.
*
* @param buffer The buffer to encode into.
* @param attributes The attributes to encode.
* @param config The configuration that may be used to control how
* the entry is encoded.
*
* @throws DirectoryException If a problem occurs while attempting
* to encode the entry.
*/
throws DirectoryException
{
int numAttributes = 0;
// First count how many attributes are there to encode.
{
Attribute a;
{
{
continue;
}
}
}
// Encoded one-to-five byte number of attributes
{
{
{
{
continue;
}
}
}
}
else
{
// The attributes will be encoded as 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
{
{
for(ByteString v : a)
{
}
}
}
}
}
/**
* Decodes the provided byte array as an entry.
*
* @param entryBuffer 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(entryBuffer,
}
/**
* Decodes the provided byte array as an entry using the V3
* encoding.
*
* @param entryBuffer The byte buffer 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);
}
if(version != 0x01)
{
// Next is the length of the encoded configuration.
// Next is the encoded configuration itself.
config =
}
else
{
}
// 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.
// Next is the DN itself.
}
// Next is the set of encoded object classes. The encoding will
// depend on the configuration.
// Now, we should iterate through the user and operational attributes and
// decode each one.
// We've got everything that we need, so create and return the entry.
}
catch (DirectoryException de)
{
throw de;
}
catch (Exception e)
{
logger.traceException(e);
throw new DirectoryException(
message, e);
}
}
/**
* Decode the object classes of an encoded entry.
*
* @param ver The version of the entry encoding.
* @param entryBuffer The byte sequence containing the encoded
* entry.
* @param config The configuration that may be used to control how
* the entry is encoded.
*
* @return A map of the decoded object classes.
* @throws DirectoryException If a problem occurs while attempting
* to encode the entry.
*/
{
// Next is the set of encoded object classes. The encoding will
// depend on the configuration.
if (config.compressObjectClassSets())
{
}
{
if(ver < 0x03)
{
// Next is the length of the object classes. It may be a
// single byte or multiple bytes.
// The set of object classes will be encoded as a single
// string with the object class names separated by zeros.
for (int i=0; i < ocLength; i++)
{
{
}
}
}
else
{
// Next is the number of zero terminated object classes.
for(int i = 0; i < numOC; i++)
{
{}
}
}
}
return objectClasses;
}
/**
* Adds the objectClass contained in the buffer to the map of object class.
*
* @param objectClasses
* the Map where to add the objectClass
* @param entryBuffer
* the buffer containing the objectClass name
* @param startPos
* the starting position in the buffer
* @param endPos
* the ending position in the buffer
*/
{
}
/**
* Decode the attributes of an encoded entry.
*
* @param ver The version of the entry encoding.
* @param entryBuffer The byte sequence containing the encoded
* entry.
* @param config The configuration that may be used to control how
* the entry is encoded.
*
* @return A map of the decoded object classes.
* @throws DirectoryException If a problem occurs while attempting
* to encode the entry.
*/
{
// Next is the total number of attributes. It may be a
// single byte or multiple bytes.
// Now, we should iterate through the attributes and decode each one.
{
for (int i=0; i < attrs; i++)
{
if(ver < 0x03)
{
// Version 2 includes a total attribute length
}
// Decode the attribute.
{
}
}
}
else
{
int startPos;
int endPos;
for (int i=0; i < attrs; i++)
{
// First, we have the zero-terminated attribute name.
{}
if (semicolonPos > 0)
{
while (nextPos > 0)
{
{
}
}
{
}
}
else
{
}
// Next, we have the number of values.
// Next, we have the sequence of length-value pairs.
for (int j=0; j < numValues; j++)
{
}
// Create the attribute and add it to the set of attributes.
{
}
}
}
return attributes;
}
/**
* 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.
*/
{
// First, append the DN.
// Next, add the set of objectclasses.
{
}
// Finally, add the set of user and operational attributes.
return ldifLines;
}
/**
* Add LDIF lines for each passed in attributes.
*
* @param ldifLines
* the List where to add the LDIF lines
* @param attributes
* the List of attributes to convert into LDIf lines
*/
{
{
{
for (String o : a.getOptions())
{
}
for (ByteString v : a)
{
}
}
}
}
/**
* 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 (logger.isTraceEnabled())
{
}
return false;
}
}
catch (Exception e)
{
logger.traceException(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 (logger.isTraceEnabled())
{
}
}
// Now the set of user attributes.
// Next, the set of operational attributes.
{
}
else
{
if (logger.isTraceEnabled())
{
"Skipping all operational attributes for entry %s " +
"because of the export configuration.", dn);
}
}
// 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))
{
{
}
}
}
}
// Make sure there is a blank line after the entry.
return true;
}
/**
* Writes the provided List of attributes to LDIF using the provided
* information.
*
* @param attributes
* the List of attributes to write as LDIF
* @param typesOnly
* if true, only writes the type information, else writes the type
* information and values for the attribute.
* @param attributeType
* the type of attribute being written to LDIF
* @param exportConfig
* configures the export to LDIF
* @param writer
* The writer to which the data should be written. It must not be
* <CODE>null</CODE>.
* @param wrapLines
* Indicates whether to wrap long lines.
* @param wrapColumn
* The column at which long lines should be wrapped.
* @throws IOException
* If a problem occurs while writing the information.
*/
boolean wrapLines) throws IOException
{
{
{
{
{
continue;
}
}
}
else
{
if (logger.isTraceEnabled())
{
}
}
}
}
/**
* Writes the provided attribute to LDIF using the provided information.
*
* @param attribute
* the attribute to write to LDIF
* @param typesOnly
* if true, only writes the type information, else writes the type
* information and values for the attribute.
* @param writer
* The writer to which the data should be written. It must not be
* <CODE>null</CODE>.
* @param wrapLines
* Indicates whether to wrap long lines.
* @param wrapColumn
* The column at which long lines should be wrapped.
* @throws IOException
* If a problem occurs while writing the information.
*/
throws IOException
{
{
}
if (typesOnly)
{
}
else
{
for (ByteString v : attribute)
{
}
}
}
/**
* 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.
*/
public int hashCode()
{
{
}
return hashCode;
}
/**
* Computes the hashCode for the list of attributes list.
*
* @param attributesLists
* the attributes for which to commpute the hashCode
* @return the hashCode for the list of attributes list.
*/
{
int result = 0;
{
for (Attribute a : attributes)
{
}
}
return result;
}
/**
* 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.
*/
{
if (this == o)
{
return true;
}
if (o == null)
{
return false;
}
if (! (o instanceof Entry))
{
return false;
}
}
/**
* Returns whether the 2 Maps are equal.
*
* @param attributes1
* the first Map of attributes
* @param attributes2
* the second Map of attributes
* @return true if the 2 Maps are equal, false otherwise
*/
{
{
{
return false;
}
{
{
return false;
}
}
}
return true;
}
/**
* Retrieves a string representation of this protocol element.
*
* @return A string representation of this protocol element.
*/
{
return toLDIFString();
}
/**
* Appends a string representation of this protocol element to the
* provided buffer.
*
* @param buffer The buffer into which the string representation
* should be written.
*/
{
}
/**
* 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()
{
{
}
}
/**
* Appends a single-line representation of this entry to the
* provided buffer.
*
* @param buffer The buffer to which the information should be
* written.
*/
{
{
{
}
}
}
/**
* Appends the attributes to the StringBuilder.
*
* @param buffer
* the StringBuilder where to append
* @param attributesLists
* the attributesLists to append
*/
{
boolean firstAttr = true;
{
for (Attribute a : attributes)
{
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 (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 (ByteString v : attribute)
{
// Create a default object class if necessary.
if (replace)
{
}
else
{
{
duplicateValues.add(v);
}
else
{
}
}
}
return;
}
if (attributes == null)
{
// Do nothing if we are deleting a non-existing attribute.
{
return;
}
// We are adding the first attribute with this attribute type.
return;
}
// There are already attributes with the same attribute type.
{
if (a.optionsEqual(options))
{
if (replace)
{
{
}
else
{
attributes.remove(i);
if (attributes.isEmpty())
{
}
}
}
else
{
for (ByteString v : attribute)
{
{
duplicateValues.add(v);
}
}
}
return;
}
}
// There were no attributes with the same options.
{
// Do nothing.
return;
}
}
/**
* Returns an entry containing only those attributes of this entry
* which match the provided criteria.
*
* @param attrNameList
* The list of attributes to include, may include wild
* cards.
* @param omitValues
* Indicates whether to omit attribute values when
* processing.
* @param omitReal
* Indicates whether to exclude real attributes.
* @param omitVirtual
* Indicates whether to exclude virtual attributes.
* @return An entry containing only those attributes of this entry
* which match the provided criteria.
*/
{
{
// Common case: return filtered user attributes.
userAttributes.size());
if (omitReal)
{
}
else if (omitValues)
{
// Add empty object class attribute.
}
else
{
// First, add the objectclass attribute.
{
}
}
// Copy all user attributes.
omitReal, omitVirtual, true);
}
else
{
// Incrementally build table of attributes.
if (omitReal || omitValues)
{
}
else
{
}
userAttributes.size());
{
{
// This is a special placeholder indicating that all user
// attributes should be returned.
if (!omitReal)
{
if (omitValues)
{
// Add empty object class attribute.
}
else
{
// Add the objectclass attribute.
{
}
}
}
// Copy all user attributes.
omitReal, omitVirtual, true);
continue;
}
{
// This is a special placeholder indicating that all
// operational attributes should be returned.
continue;
}
if (semicolonPos > 0)
{
while (nextPos > 0)
{
}
}
else
{
}
{
// Unrecognized attribute type - do best effort search.
{
AttributeType t = e.getKey();
if (t.hasNameOrOID(lowerName))
{
continue;
}
}
{
AttributeType t = e.getKey();
if (t.hasNameOrOID(lowerName))
{
continue;
}
}
}
else
{
// Recognized attribute type.
if (attrType.isObjectClass()) {
if (!omitReal)
{
if (omitValues)
{
attrName)));
}
else
{
{
{
// User requested non-default object class type name.
}
}
}
}
}
else
{
{
}
else
{
{
}
}
}
}
}
}
}
/**
* Returns a new List containing only the supplied element.
*
* @param elem
* the element to add to the list
* @return a new List containing only the supplied element.
*/
{
return l;
}
/**
* Copies the provided list of attributes into the destination
* attribute map according to the provided criteria.
*
* @param sourceList
* The list containing the attributes to be copied.
* @param destMap
* The map where the attributes should be copied to.
* @param attrType
* The attribute type.
* @param attrName
* The user-provided attribute name.
* @param options
* The user-provided attribute options.
* @param omitValues
* Indicates whether to exclude attribute values.
* @param omitReal
* Indicates whether to exclude real attributes.
* @param omitVirtual
* Indicates whether to exclude virtual attributes.
*/
{
if (sourceList == null)
{
return;
}
{
{
continue;
}
{
continue;
}
{
continue;
}
{
continue;
}
else
{
// If a non-default attribute name was provided or if the
// attribute has options then we will need to rebuild the
// attribute so that it contains the user-requested names and options.
{
// We want to use the user-provided name only if this attribute has
// the same type as the requested type. This might not be the case for
// sub-types e.g. requesting "name" and getting back "cn" - we don't
// want to rename "name" to "cn".
{
}
else
{
}
{
}
// Now add in remaining options from original attribute
// (this will not overwrite options already present).
if (!omitValues)
{
}
}
else if (omitValues)
{
}
// Now put the attribute into the destination map.
// Be careful of duplicates.
{
// Assume that they'll all go in the one list. This isn't
// always the case, for example if the list contains
// sub-types.
}
else
{
// The attribute may have already been put in the list.
//
// This may occur in two cases:
//
// 1) The attribute is identified by more than one attribute
// type description in the attribute list (e.g. in a
// wildcard).
//
// 2) The attribute has both a real and virtual component.
//
boolean found = false;
{
{
// Assume that wildcards appear first in an attribute
// list with more specific attribute names afterwards:
// let the attribute name and options from the later
// attribute take preference.
found = true;
}
}
if (!found)
{
}
}
}
}
}
}