{scrollbar}

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

2Content

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:

java @Test public void testCreateEmptyAttribute() { Attribute attribute = new DefaultAttribute( " CN " ); assertNotNull( attribute ); assertEquals( "cn", attribute.getId() ); assertEquals( " CN ", attribute.getUpId() ); assertNotSame( "CommonName", attribute.getId() ); }

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:

java @Test public void testCreateAttribute() { Attribute attribute = new DefaultAttribute( " CN ", "test", "Test", " test ", "test" ); assertNotNull( attribute ); assertEquals( "cn", attribute.getId() ); assertEquals( " CN ", attribute.getUpId() ); assertEquals( 3, attribute.size() ); assertTrue( attribute.contains( "test", "Test", " test " ) ); }

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:

java @Test public void testCreateBinaryAttribute() { byte[] bytes1 = new byte[]{0x01, 0x02}; byte[] bytes2 = new byte[]{0x03, 0x04}; byte[] bytes3 = new byte[]{0x01, 0x02}; Attribute attribute = new DefaultAttribute( " JpegPhoto ", bytes1, bytes2, bytes3 ); assertNotNull( attribute ); assertEquals( "jpegphoto", attribute.getId() ); assertEquals( " JpegPhoto ", attribute.getUpId() ); assertEquals( 2, attribute.size() ); assertTrue( attribute.contains( bytes1, bytes2, bytes3 ) ); }

Same here : values are not duplicated.

Note that it's not allowed to store a mix of binary and String values in an Attribute:

java @Test public void testCreateMixedAttribute() { byte[] bytes1 = new byte[]{0x01, 0x02}; Attribute attribute = new DefaultAttribute( " JpegPhoto ", "test", bytes1 ); // Does not compile assertNotNull( attribute ); assertEquals( "jpegphoto", attribute.getId() ); assertEquals( " JpegPhoto ", attribute.getUpId() ); assertEquals( 3, attribute.size() ); assertTrue( attribute.contains( bytes1, "test" ) ); // Does not compile }

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:

java @Test public void testCreateEmptySchemaAwareAttribute() throws Exception { Attribute attribute = new DefaultAttribute( atCn ); assertNotNull( attribute ); assertEquals( "2.5.4.3", attribute.getId() ); assertEquals( "cn", attribute.getUpId() ); assertTrue( attribute.isInstanceOf( atCn ) ); assertEquals( 0, attribute.size() ); }

Here, we created an Attribute with a specific AttributeType (...) and no value. Let's create a new Attribute with some values:

java @Test public void testCreateSchemaAwareAttribute() throws Exception { Attribute attribute = new DefaultAttribute( atCn, "test", "Test", " test " ); assertNotNull( attribute ); assertEquals( "2.5.4.3", attribute.getId() ); assertEquals( "cn", attribute.getUpId() ); assertTrue( attribute.isInstanceOf( atCn ) ); assertEquals( 1, attribute.size() ); assertTrue( attribute.contains( "TEST" ) ); }

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:

java @Test public void testAddValue() throws LdapInvalidAttributeValueException { Attribute attribute = new DefaultAttribute( " CN " ); Attribute attributeSA = new DefaultAttribute( atCn ); // Add two values attribute.add( "test1", "" ); assertEquals( 2, attribute.size() ); // add two values attributeSA.add( "test1", "" ); assertEquals( 1, attributeSA.size() ); }

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:

java @Test public void testAddMixedValue() throws LdapInvalidAttributeValueException { Attribute attribute = new DefaultAttribute( " CN " ); Attribute attributeSA = new DefaultAttribute( atCn ); byte[] bytes = new byte[]{0x01, 0x02}; // Add two values attribute.add( "test1" ); attribute.add( bytes ); assertEquals( 1, attribute.size() ); assertTrue( attribute.contains( "test1" ) ); assertFalse( attribute.contains( bytes ) ); // add two values attributeSA.add( "test1" ); attributeSA.add( bytes ); assertEquals( 1, attributeSA.size() ); assertTrue( attributeSA.contains( "test1" ) ); assertFalse( attributeSA.contains( bytes ) ); }
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:

java @Test public void testRemoveValue() throws LdapInvalidAttributeValueException { Attribute attribute = new DefaultAttribute( " CN " ); // Add three values attribute.add( "test1", "test2", "test3" ); assertEquals( 3, attribute.size() ); // Remove 2 of them attribute.remove( "test2", "test3" ); assertEquals( 1, attribute.size() ); assertTrue( attribute.contains( "test1" ) ); assertFalse( attribute.contains( "test2" ) ); assertFalse( attribute.contains( "test3" ) ); // Try to remove the last one, using wrong casing attribute.remove( "Test1" ); assertEquals( 1, attribute.size() ); assertTrue( attribute.contains( "test1" ) ); }

And the same example, on a schema aware Attribute. It demonstrates how convenient it is to manipulate such schema aware objects:

java @Test public void testRemoveSchemaAwareValue() throws LdapInvalidAttributeValueException { Attribute attribute = new DefaultAttribute( atCn ); // Add three values attribute.add( "test 1", "test 2", "test 3" ); assertEquals( 3, attribute.size() ); // Remove 2 of them attribute.remove( "TEST 2", "test 3" ); assertEquals( 1, attribute.size() ); assertTrue( attribute.contains( "tESt 1" ) ); assertFalse( attribute.contains( "test 2" ) ); assertFalse( attribute.contains( "TEST 3" ) ); // Try to remove the last one, using wrong casing attribute.remove( "Test 1" ); assertEquals( 0, attribute.size() ); }

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:

java @Test public void testContains() throws LdapInvalidAttributeValueException { Attribute attribute1 = new DefaultAttribute( atCn ); // Add three values attribute1.add( "test 1", "test 2", "test 3" ); assertTrue( attribute1.contains( "tESt 1", "test 2 " ) ); assertTrue( attribute1.contains( " test 2" ) ); assertTrue( attribute1.contains( "TEST 3" ) ); assertFalse( attribute1.contains( "test 1", "Test 4" ) ); Attribute attribute2 = new DefaultAttribute( "cn" ); // Add three values attribute2.add( "test 1", "test 2", "test 3" ); assertTrue( attribute2.contains( "test 1" ) ); assertTrue( attribute2.contains( "test 2" ) ); assertTrue( attribute2.contains( "test 3" ) ); assertFalse( attribute2.contains( "Test 1" ) ); assertFalse( attribute2.contains( " test 2" ) ); assertFalse( attribute2.contains( "test 4" ) ); }
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 :

java @Test public void testApplyAttributeType() throws LdapInvalidAttributeValueException { Attribute attribute = new DefaultAttribute( "CN", " A test" ); attribute.apply( atCn ); assertTrue( attribute.contains( "a test" ) ); assertEquals( "2.5.4.3", attribute.getId() ); }

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.

java @Test( expected=LdapInvalidAttributeValueException.class ) public void testApplyAttributeTypeWrongValue() throws LdapInvalidAttributeValueException { byte[] bytes = new byte[]{0x01, 0x02}; Attribute attribute = new DefaultAttribute( "CN", bytes ); attribute.apply( atCn ); }
clear()

This method removes all the values from the attribute. The attribute type is not removed. Here is an example demonstrating how it works:

java @Test public void testClear() throws LdapInvalidAttributeValueException { Attribute attribute = new DefaultAttribute( atCn, "test1", "test2" ); assertEquals( 2, attribute.size() ); attribute.clear(); assertEquals( 0, attribute.size() ); }
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:

java @Test public void testEquals() throws LdapInvalidAttributeValueException { Attribute attribute1 = new DefaultAttribute( atCn, "test 1", "test 2", "test 3" ); Attribute attribute2 = new DefaultAttribute( atCn, "Test 3", "Test 2 ", "Test 1" ); Attribute attribute3 = new DefaultAttribute( "cn", "test 1", "test 3", "test 2" ); Attribute attribute4 = new DefaultAttribute( "cn", "test 1", "test 3", "test 2" ); assertEquals( attribute1, attribute2 ); assertEquals( attribute3, attribute4 ); assertNotSame( attribute1, attribute3 ); assertNotSame( attribute1, attribute4 ); assertNotSame( attribute2, attribute4 ); attribute4.apply( atCn ); assertEquals( attribute1, attribute4 ); assertEquals( attribute2, attribute4 ); assertNotSame( attribute3, attribute4 ); }
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:

java @Test public void testIsInstanceOf() throws LdapInvalidAttributeValueException { Attribute attribute = new DefaultAttribute( atCn, "test 1", "test 2", "test 3" ); assertTrue( attribute.isInstanceOf( atCn ) ); assertTrue( attribute.isInstanceOf( atName ) ); assertFalse( attribute.isInstanceOf( atSn ) ); }
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:

java @Test public void testIsValid() throws LdapInvalidAttributeValueException { Attribute attribute1 = new DefaultAttribute( "cn", "\uFFFDtest" ); assertFalse( attribute1.isValid( atCn ) ); Attribute attribute2 = new DefaultAttribute( "cn" ); assertFalse( attribute2.isValid( atCn ) ); Attribute attribute3 = new DefaultAttribute( "cn", "test" ); assertTrue( attribute3.isValid( atCn ) ); Attribute attribute4 = new DefaultAttribute( "dc", "test", "test2" ); assertFalse( attribute4.isValid( atDc ) ); }
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:

java @Test public void testIIterator() throws LdapInvalidAttributeValueException { Attribute attribute = new DefaultAttribute( atCn, "test 1", "test 2", "test 3" ); for ( Value<?> value : attribute ) { System.out.println( "Value : " + value ); } }

This code produces the following output:

java Value : test 1 Value : test 2 Value : test 3
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

  • No labels