The Attribute class is used to store values associated to AttributeType (...). An Entry can contain many Attributes, but only one of them is mandatory : the ObjectClass Attribute.
An Attribute can store zero, one or N values, accordingly to the associated AttributeType (...), which may allow null values, and which also can forbid muli-values.
The Attribute has a interned AttributeType (...) which is usually defined using its name. This name is case insensitive, and we can also use the AttributeType (...) OID.
Content
Creating an Attribute
Creating an Attribute is not really a complex operation. Again, we split the API into two categories:
- the schema agnostic Attributes
- the schema aware Attributes
Schema agnostic Attribute
If we don't inject a SchemaManager (...) in the constructor, then the Attribute will have no way to control that the AttributeType (...) exists, nor that the Values are valid.
Let's see how we can create Attributes. Basically, all what you need is to provide the AttributeType (...) as a String, and some Values (it's optional). Here is an example:
Here, we created an empty Attribute. Note that cn does not allow empty values, but it's not controlled. Also note that the AttributeType (...) is lower cased and trimmed internally.
Let's see another example, with some values:
Here, we create an Attribute with 3 values. We can see that the values are not duplicated (the "test" value is only inserted once) and that values are case sensitive (the "test" and "Test" values are both stored in the Attribute). The values aren't trimmed either, so we can have a "test" and a " test " values stored.
This is why having a schema aware Attribute is really handy.
It's possible to store binary values into an Attribute too:
Same here : values are not duplicated.
Note that it's not allowed to store a mix of binary and String values in an Attribute:
Schema aware Attribute
We can inject a SchemaManager (...) into the Attribute which will allow more control on the values stored into the Attribute. Let's see with some example how it works:
Here, we created an Attribute with a specific AttributeType (...) and no value. Let's create a new Attribute with some values:
The important point here is that the values are all considered equals. The contains method also use the schema to compare the given value with the interned values. Here, with the cn AttributeType (...), the value is not case sensitive, so "TEST" is considered as an existing value, even if we injected "test".
Modifying an Attribute
Now that we created an Attribute we would like to add or remove values from it. This is quite easy. We have a set of methods to add or remove values, and depending on the fact the Attribute is schema aware or not, the added values will be checked.
Adding some value
Here is an example of some value addition into a schema agnostic Attribute, then the same operation into a schema aware Attribute:
We can see that the schema aware Attribute just contains only one value after the operation, as the cn attribute type does not allow empty strings.
There is one important point to understand : when a schema agnostic Attribute is created, it knows nothing about the type of values it will store. Once the first value is added, the Attribute will be typed accordingly to the first value added. Then, we can't anymore add values if it has not the same type.
If the Attribute is schema aware, it's quite obvious. You won't be able to add a binary value into a Human Readable Attribute.
The following test shows that:
Removing some values
Removing a value from an Attribute is a trivial operation. Of course, if the Attribute is schema aware, we will use the AttributeType (...) comparator to check if the value is present in the Attribute or not (the comparator is associated with the attribute equality MatchingRule (e)).
Here is an example:
And the same example, on a schema aware Attribute. It demonstrates how convenient it is to manipulate such schema aware objects:
Attribute data access methods
We have a set of methods used to get some information about the Attribute. They are described in this chapter.
contains()
Checks if the given values are present in the Attribute. We can check for more than one value, but in this case, the method returns true only if all the values are present.
If the Attribute is schema aware, then the check uses the AttributeType (...) to compare the given values with the interned values, otherwise, we do a strict comparison.
Here is an example:
get()
Returns the first value from the Attribute. The first value is the one which has been added first. Note that it returns a Value instance.
getAttributeType()
Returns the internal AttributeType (...), if the Attribute is schema aware.
getBytes()
Returns the first value as a byte[], if the Attribute is not human readable. The user must know that the Attribute contains binary values, otherwise he will get an LdapInvalidAttributeValueException.
getString()
Returns the first value as a String, if the Attribute is human readable. The user must know that the Attribute contains String values, otherwise he will get an LdapInvalidAttributeValueException.
getId()
Returns the AttributeType (...) normalized ID. If the Attribute is schema agnostic, it will be the trimmed and lower cased user provided ID, otherwise it will be the AttributeType (...) OID (not the name).
getUpId()
Returns the attribute type user provided ID, if the user provided one. Typically, if the Attribute is schema aware, the user might not provide an ID, and in this case, this method will return the AttributeType (...) name, or default to the OID.
isHumanReadable()
Tells if the Attribute contains String values or binary values.
Miscellaneous methods
We also have a set of miscellaneous methods, which are not frequently used. Here they are:
apply( AttributeType )
Inject an AttributeType (...) into the Attribute, making it schema aware. It will check that the associated values are valid at the same time, and normalize the values.
Here is an example of the impact of such a method on an existing attribute :
It shows that we can now check that a value is not literately compared, the modified attribute uses the Equality MatchingRule (e) to compare the values.
Here is another example, where we try to apply an attribute type to some attribute containing an invalid value : it generates an exception, as expected.
clear()
This method removes all the values from the attribute. The attribute type is not removed. Here is an example demonstrating how it works:
clone()
This method create a new instance of an existing attribute. All the values and the attribute type are cloned too and distinct from the original attribute.
equals( Object )
Compares two Attributes. All the values are compared and should be present in both attributes. If you compare a schema aware Attribute with a schema agnostic Attribute, they won't be equal.
Here is a snippet of code demonstrating the equals method:
isInstanceOf( AttributeType )
Tells if an Attribute derives from a given AttributeType (...). It can be useful if you have some schema aware Attribute and if you want to know if its attribute type inherit from an other one. Here is an example of usage:
isValid( AttributeType )
Checks if the Attribute contains valid data. It's useful if one wants to apply an AttributeType (...) to the Attribute, as the isValid method will tell if it's possible to do so without throwing an exception.
Here is some code that test the different use cases:
iterator()
A convenient way to iterate on all the Attribute values. It makes it possible to use a for ( Value<?> value : attribute ) construct. Here is an example using the iterator:
This code produces the following output:
setUpId()
Sets the user provided identifier for the attribute type. If the Attribute is schema agnostic, then the normalized ID will be the given user provided ID lower cased and trimmed. If it's schema aware, it will be used instead of the AttributeType (...) ID.
size()
Returns the number of values stored in this Attribute