h2. Attribute The *Attribute* class is used to store values associated to *[AttributeType (...)]*. An *[DIRAPI:Entry]* can contain many *Attribute{*}s, 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 (...)]* *[DIRAPI:OID]*. h3. 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* h4. 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 *[DIRAPI:Value]s* 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 *[DIRAPI:Value]s* (it's optional). Here is an example: {code:java} @Test public void testCreateEmptyAttribute() { Attribute attribute = new DefaultAttribute( " CN " ); assertNotNull( attribute ); assertEquals( "cn", attribute.getId() ); assertEquals( " CN ", attribute.getUpId() ); assertNotSame( "CommonName", attribute.getId() ); } {code} 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: {code: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 " ) ); } {code} 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: {code: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 ) ); } {code} Same here : values are not duplicated. Note that it's not allowed to store a mix of binary and String values in an *Attribute*: {code: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 } {code} h4. 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: {code: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() ); } {code} Here, we created an *Attribute* with a specific *[AttributeType (...)]* and no value. Let's create a new *Attribute* with some values: {code: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" ) ); } {code} 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"_. h3. 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. h5. 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*: {code: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() ); } {code} 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: {code: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 ) ); } {code} h5. 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: {code: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" ) ); } {code} And the same example, on a schema aware *Attribute*. It demonstrates how convenient it is to manipulate such schema aware objects: {code: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() ); } {code} h3. Attribute data access methods We have a set of methods used to get some information about the *Attribute*. They are described in this chapter. h5. 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: {code: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" ) ); } {code} h5. get() Returns the first value from the *Attribute*. The first value is the one which has been added first. Note that it returns a *[DIRAPI:Value]* instance. h5. getAttributeType() Returns the internal *[AttributeType (...)]*, if the *Attribute* is schema aware. h5. 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_. h5. 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_. h5. 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). h5. 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. h5. isHumanReadable() Tells if the *Attribute* contains String values or binary values. h3. Miscellaneous methods We also have a set of miscellaneous methods, which are not frequently used. Here they are: h5. 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 : {code: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() ); } {code} 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. {code: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 ); } {code} h5. clear() This method removes all the values from the attribute. The attribute type is not removed. Here is an example demonstrating how it works: {code:java} @Test public void testClear() throws LdapInvalidAttributeValueException { Attribute attribute = new DefaultAttribute( atCn, "test1", "test2" ); assertEquals( 2, attribute.size() ); attribute.clear(); assertEquals( 0, attribute.size() ); } {code} h5. 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. h5. 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: {code: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 ); } {code} h5. 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: {code: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 ) ); } {code} h5. 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: {code: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 ) ); } {code} h5. 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: {code: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 ); } } {code} This code produces the following output: {code:java} Value : test 1 Value : test 2 Value : test 3 {code} h5. 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. h5. size() Returns the number of values stored in this *Attribute*