| Title: 6.3 - Attribute |
| NavPrev: 6.2-administrative-role.html |
| NavPrevText: 6.2 - AdministrativeRole |
| NavUp: 6-ldap-data-structures.html |
| NavUpText: 6 - LDAP data structures |
| NavNext: 6.4-attribute-type.html |
| NavNextText: 6.4 - AttributeType |
| Notice: Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| . |
| http://www.apache.org/licenses/LICENSE-2.0 |
| . |
| Unless required by applicable law or agreed to in writing, |
| software distributed under the License is distributed on an |
| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| KIND, either express or implied. See the License for the |
| specific language governing permissions and limitations |
| under the License. |
| |
| # 6.3 - Attribute |
| |
| The _Attribute_ class is used to store values associated with an _AttributeType_. An _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 its associated _AttributeType_, which may allow null values, and which also can forbid muli-values. |
| |
| The _Attribute_ has a internal _AttributeType_ which is usually defined using its name. This name is case insensitive, and we can also use the _AttributeType_ _OID_. |
| |
| ## Creating an Attribute |
| |
| Creating an _Attribute_ is not complex. 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_ into the constructor, then the _Attribute_ will have no way to control whether its _AttributeType_ exists, nor that its _Values_ are valid. |
| |
| Let's see how we can create _Attributes_. Basically, all what that needed is to provide the _AttributeType_ as a String, and some _Values_ (that are optional). Here is an example: |
| |
| :::Java |
| Attribute attribute = new DefaultAttribute( " CN " ); |
| |
| Here, we created an empty _Attribute_. Note that _cn_ does not allow empty values, but it's not enforced. Also note that the _AttributeType_ is lowercase and trimmed internally. |
| |
| Let's see another example, with some values: |
| |
| :::Java |
| Attribute attribute = new DefaultAttribute( " CN ", "test", "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 |
| 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 ); |
| |
| Same here: values are not duplicated. |
| |
| Note that it's not allowed to store a mix of binary and String values into an _Attribute_: |
| |
| :::Java |
| byte[] bytes1 = new byte[]{0x01, 0x02}; |
| |
| Attribute attribute = new DefaultAttribute( " JpegPhoto ", "test", bytes1 ); // Does not compile |
| |
| ### Schema aware Attribute |
| |
| We can inject a _SchemaManager_ into the _Attribute_ which will allow more control over the values stored within the _Attribute_. Let's see an example of how this works: |
| |
| :::Java |
| Attribute attribute = new DefaultAttribute( atCn ); |
| |
| Here, we created an _Attribute_ with a specific _AttributeType_ ('atCn') and no value. Let's create a new _Attribute_ with some values: |
| |
| :::Java |
| Attribute attribute = new DefaultAttribute( atCn, "test", "Test", " test " ); |
| |
| The important point here is that the values are all considered equal. The _contains_ method also uses the schema to compare its 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 whether the _Attribute_ is schema aware or not, the added values will be checked. |
| |
| ### Adding some value |
| |
| Here is an example of a value addition into a schema agnostic _Attribute_, then the same operation into a schema aware _Attribute_: |
| |
| :::Java |
| Attribute attribute = new DefaultAttribute( " CN " ); |
| Attribute attributeSA = new DefaultAttribute( atCn ); |
| |
| // Add two values |
| attribute.add( "test1", "" ); |
| |
| // add two values |
| attributeSA.add( "test1", "" ); |
| |
| |
| 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 -- whenever 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 no longer add values that are not of 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 |
| 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 ); |
| |
| // add two values |
| attributeSA.add( "test1" ); |
| attributeSA.add( 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_. |
| |
| Here is an example: |
| |
| :::Java |
| Attribute attribute = new DefaultAttribute( " CN " ); |
| |
| // Add three values |
| attribute.add( "test1", "test2", "test3" ); |
| |
| // Remove 2 of them |
| attribute.remove( "test2", "test3" ); |
| |
| // Try to remove the last one, using wrong casing |
| attribute.remove( "Test1" ); |
| |
| And the same example, on a schema aware _Attribute_. It demonstrates how convenient it is to manipulate such schema aware objects: |
| |
| :::Java |
| Attribute attribute = new DefaultAttribute( atCn ); |
| |
| // Add three values |
| attribute.add( "test 1", "test 2", "test 3" ); |
| |
| // Remove 2 of them |
| attribute.remove( "TEST 2", "test 3" ); |
| |
| // Try to remove the last one, using wrong casing |
| attribute.remove( "Test 1" ); |
| |
| ## 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 |
| Attribute attribute1 = new DefaultAttribute( atCn ); |
| |
| // Add three values |
| attribute1.add( "test 1", "test 2", "test 3" ); |
| |
| Attribute attribute2 = new DefaultAttribute( "cn" ); |
| |
| // Add three values |
| attribute2.add( "test 1", "test 2", "test 3" ); |
| |
| ### 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 they 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 they 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 |
| Attribute attribute = new DefaultAttribute( "CN", " A test" ); |
| |
| attribute.apply( atCn ); |
| |
| It shows that we can now check that a value is not literately compared, the modified attribute uses the Equality _MatchingRule_ 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 |
| 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 |
| Attribute attribute = new DefaultAttribute( atCn, "test1", "test2" ); |
| |
| attribute.clear(); |
| |
| ### clone() |
| |
| This method creates a new instance of an existing attribute. All of the attribute values along with its attribute type are cloned and distinct from the original attribute. |
| |
| ### equals( Object ) |
| |
| Compares two _Attributes_. All of its 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 |
| 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" ); |
| |
| // Should be true |
| boolean equals = attribute1.equals( attribute2 ); |
| equals = attribute3.equals( attribute4 ); |
| |
| // Should be false |
| equals = attribute1.equals( attribute3 ); |
| equals = attribute1.equals( attribute4 ); |
| equals = attribute2.equals( attribute4 ); |
| |
| // Now, inject an AttrbuteType in one attribute |
| attribute4.apply( atCn ); |
| |
| // The previously not equals attributes are now equal : |
| equals = attribute1.equals( attribute4 ); |
| equals = attribute2.equals( attribute4 ); |
| |
| |
| ### isInstanceOf( AttributeType ) |
| |
| Tells if an _Attribute_ derives from a given _AttributeType_. It can be useful if you have a schema aware _Attribute_ and want to know if its attribute type inherits from another one. Here is an example of usage: |
| |
| :::Java |
| Attribute attribute = new DefaultAttribute( atCn, "test 1", "test 2", "test 3" ); |
| |
| // Should be true |
| boolean value = attribute.isInstanceOf( atCn ); |
| |
| ### 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 |
| Attribute attribute1 = new DefaultAttribute( "cn", "\uFFFDtest" ); |
| |
| // Should be false |
| boolean isValid = attribute1.isValid( atCn ) ); |
| |
| Attribute attribute2 = new DefaultAttribute( "cn" ); |
| |
| // Should be false, 'cn' requires a value |
| isValid = attribute2.isValid( atCn ); |
| |
| Attribute attribute3 = new DefaultAttribute( "cn", "test" ); |
| |
| // Should be true |
| value = attribute3.isValid( atCn ); |
| |
| Attribute attribute4 = new DefaultAttribute( "dc", "test", "test2" ); |
| |
| // Should be false, we can't put more than one value in 'dc' |
| value = attribute4.isValid( atDc ); |
| |
| ### iterator() |
| |
| A convenient way to iterate over all of the _Attribute_ values. It enables the _for ( Value<?> value : attribute )_ construct. Here is an example using the iterator: |
| |
| :::Java |
| 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_ |