On 4/22/07, Emmanuel Lecharny <elecharny@gmail.com> wrote:

we have had a little convo yesturday with Alex about the way
attributeTypes are handled.

AT = AttributeType
AV = AttributeValue

First let's sum up some of the problems we have :
- when looking for an AT in an attributes, we are using the get( String
) method. The problem is that the String could be a name, an alias or an
OID. Lookup like attrs.get( "entryACI" ) just returns a value *if* the
"entryACI" exists as an attribute. If the user has created an attribute
with AT = "" (entryACI OID), the the get() method will return


- we may also have aliases (commonName instead of cn), so we must search
for all the possible values of an AT (, cn or commonName)
- the user may provide a name or an alias with his own casing : CN or
Cn, CommonName or commonName...)

We presently handle case by default since AttributesImpl by default ignores the case of the attribute ID when performing lookups.  Funny how JNDI allows this to be something that can be toggled on and off.

- we must return the AT as it has been injected by the user : if a user
create an entry with CN=something, we should return CN=something later
when this user request the server for this AT. In other words, we should
not return commonName=something unless specifically requested by the
user (one can do a search request asking for cn, CN, commonName or even, and we should return the response using the user syntax)

Stefan Z uncovered an interesting dynamic here as well.  It seems if you include an attribute in the attributes to return with a specific case or an OID then other servers return that attribute *ONLY* in the DN of the entry as it was requested in the lookup (search) operation.

I wonder if this also applies to the way the attribute's ID appears within the entry as opposed to in the DN. 

However say there are no attribute ids specified in the attributes to request parameter of search then you must return all the attributes in the entry (non-operational) as it was added to that entry by users via ADD and MODIFY operations.  Meaning you must return it as it was supplied with the same case/alias/oid it was added to the entry.  So if user added an entry with an ou attribute with a add operation but used the case Ou then you must return the entry's attribute with the case Ou.

- last, not least, this should be as fast as possible (just because some
retarded hackers seems to be looking over our shoulder ;)


Ok, some proposals now:
1) Attributes should be normalized as soon as spossible, to let the
server manipulate OIDs instead of multiple names


2) We should *never* use any AT names into the server (such as
attrs.get( "entryACI" ) or attrs.get( "" )), but constants like
: attrs.get( SchemaConstants.PRESCRIPTIVE_ACI_AT_OID )


3) Of course this imply that we declare all those constants (work in


4) the internal structure of AttributesImpl is questionnable : for each
attribute, we should keep the UP AT and the values, plus the associated
OID (this is a triplet). As we only receive the two last elements, we
must add the first part (OID). To speedup lookups, the idea is to store
those triplets into a hashMap. The big problem is that we have no way to
get this OID inside AttributesImpl, because this class has been designed
to be used bu the client side, so we must find a way to feed the map
without changing the API

Considering the last point, the best approch seems to define a
ServerAttributesImpl, for internal use only. The little tricky problem
with this approach is that it's not really optimal : attributes are
constructed during the decoding phase, where we don't have access to the
registries (the place where AT <-> OID mapping is stored). And this
codec is stored in shared-ldap...

We might go a step further, with a shared-ldap-server and a
shared-ldap-client, but this is a major refactoring...


Another possibility is to copy the entire Attributes during the
Normalization phase, substituting names for OIDs. But this means
creating a new Attributes. Costly ...


ideas ?

I am still thinking about this.

What about this crazy idea?

Create a ServerEntry object that stops using the Attributes interface yet can be easily wrapped or extracted from an Attributes object via an implementation specific method or by copying in the worst case.

The ServerEntry will be a server side specific object.  It will contain a  map of ServerEntryAttribute[s].  Each ServerEntryAttribute has a reference to the AttributeType associated with it's attribute instead of a String for alias/OID.  We can further refine this class with subtypes for Single and Multi valued ServerEntryAttributes to save on space and access time.  The AttributeType reference is transient and the object is serializable yet we do not use default serialization for persisting these objects.

The ServerEntry can also reference all the ObjectClass objects associated with it.  This way schema violations can be detected while adding attributes to an entry.  Furthermore syntax violations can be detected while adding values to ServerEntryAttributes.   However this may make certain intermediate steps in building an entry inconsistent so there might be a method that can be used to relax checks from occurring?

As with any approach we will consider I think we need to look into all the use cases we will have for these objects.  That means we must consider the codec, translations from JNDI objects to these objects and vice versa.  Are we going to waste cycles in doing these things and/or will we cause more problems for the various subsystems.

Right now the safest bet for us to make sure the server behaves correctly is to find all the code where we are using attributes.get( "" ) and replace it with AttributeUtils.getAttribute( <AttributeType>, <Attributes> ).  This could be an intermediate solution until we find the best answer to this question.