directory-api mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Matthew Swift <Matthew.Sw...@Sun.COM>
Subject Re: Let's start for real ?
Date Mon, 30 Nov 2009 14:27:48 GMT
Hi Emmanuel,

I've put my responses inline..

On 27/11/09 12:42, Emmanuel Lecharny wrote:
> Ok, so we can start with :
> DN
> Entry
> Attribute
> Modification
> Control
> AttributeType
> DitContentRule
> DitStructureRule
> MatchingRule
> MatchingRuleUse
> NameForm
> ObjectClass
> Syntax
> ResultCode
> Still to be decided :
> LdapURL or LdapUrl ? I'm fine with both, but I don't like LDAPURL

I think LdapURL.

BTW, in our current SDK effort we have AVA as an inner class of RDN in 
order to make it clearer to users of the tight coupling between the two. 
In particular, an AVA is not the same sort of AVA that you'd find in a 
compare operation or in a filter since it does not permit attribute 
options and, perhaps more subtly, the "value" should not conform to the 
matching rule assertion syntax, but to the attribute syntax (which is 
usually the same anyway for equality matching rules, but it's worth 
pointing out).

> OID: It's much more a ASN.1 notion, right. But in many case, we may
> manipulate an OID instead of a String. Frankly, the only thing I do
> with such a class right now is to use a static method named OID.isOid(
> String ). It can be left outside of the API too.
> CSN: Or EntryCSN. Not sure that it should be exposed too.
>> A data type that we have found particularly useful is AttributeDescription
> <snip/>
> If this is a wrapper on top of an AttributeType (or an ID), with
> options, then it sounds like a good idea. It could help having a
> lightweight API instead of having tens of methods for each specific
> case : AT with options, etc.

Agreed - in our server we don't have an AttributeDescription API and 
instead we have many methods of the form that you describe, e.g:

    Entry.getAttribute(AttributeType type)
    Entry.getAttribute(AttributeType type, String... options)
    Entry.getAttribute(AttributeType type, Set<String> options)

It gets pretty bloated once you add in methods for removing attributes 
and checking for containment, etc. Another nice thing about having an 
AttributeDescription type is that you can cache them in ThreadLocals for 
very faster decoding and reduction in memory throughput.

>> We don't require that the client API has a schema available. The default
>> schema can be either the built in standard "core" schema (e.g. cn, sn, etc)
>> or it could even be the built in "empty" schema, both of which fake up
>> missing attribute type definitions on demand (in which case they use octet
>> string syntax and equality matching). This is nice because it means that the
>> API does not need get bloated by having two API abstractions (non schema
>> aware and  schema aware).
> We discussed a lot with Ludo about it. The Client API must not be
> schema aware, but it must allow someone to use a schema if needed. The
> default would be to use the core schema.


> In order to use the Schema within an entry, it would just be a matter
> of injecting the Schema into the Entry, either in the constructor, or
> later. It will of course propagate to all the included AT, Dn, etc...
> The details have to be explicited, of course

In our SDK I have made the following two assumptions with the aim of 
keeping the API as lean as possible:

    * most client application developers will only use a single LDAP schema

    * if an application requires multiple schema then it's probably
      acceptable to force them to use more "heavy weight" methods

This means that high-level API components such as Entry and Attribute 
(but not DN or AttributeDescription which IMO are low level) do not 
provide a means for specifying a schema during construction. Instead 
they use the application default schema. Developers still get the 
flexibility to use non-default schema by using the more heavy weight API 
methods. Here's some examples:

    // Use application default schema to decode attribute descriptions
    and DNs.
    Attribute a1 = new LinkedAttribute("description", "value1",
    "value2", "value3");
    a1.add("another value");

    Entry e1 = new SortedEntry("dc=example,dc=com");
    e1.addAttribute("description", "value1", "value2", "value3");
    e1.addAttribute("dc", "example");

    // Now more heavyweight approach using alternative schema.
    Schema schema = ...;
    AttributeDescription ad =
    AttributeDescription.valueOf("description", schema);
    Attribute a2 = new LinkedAttribute(ad, "value1", "value2", "value3");

    // It is possible, though not advisable, to use both approaches for
    DN dn = DN.valueOf("dc=example,dc=com", schema);
    Entry e2 = new SortedEntry(dn);
    e2.addAttribute("description", "value1", "value2", "value3");

Like you say we could inject the schema when constructing the Entry - 
it's only an additional constructor.

>> Here's some other types that you'll probably need:
>>    * Filter - this is the raw Filter structure defined in RFC 4511
>>      protocol def. We also have a Matcher object (in the style of the
>>      Regex APIs) which represents a Filter compiled against a
>>      particular schema.
> Filter, +1
> I'm not sure about the Matcher object, as it's supposed to be used by
> the server only. But who knows?

Yeah - I don't know. It could be useful when parsing and filtering LDIF 
or doing client side entry filtering.

>>    * Assertion - represents an attribute value assertion compiled by a
>>      MatchingRule - typically these are stored in a compiled Filter
>>      (Matcher)
> Same as above...


>>    * Schema - a container of attribute types, object classes, etc
> We call it SchemaManager in ADS, Schema is definitively better. +1
>>    * ByteString and/or AttributeValue - you'll need at the bear minimum
>>      a ByteString for storing attribute values. You may decide that you
>>      need an AttributeValue as well in order to cache the normalized
>>      form, but I don't think that it's necessary and it just bloats the
>>      API and memory - the Attribute can cache normalized forms.
>>      Matching rules will need to normalize bytes. For such a low level
>>      primitive it's best to use an immutable object for this. We also
>>      have a ByteSequence and ByteStringBuilder in the same manner as
>>      CharSequence, StringBuilder, and String.
> Again, a lot of discussion about it. I'm not convinced that we really
> need a ByteString object, as data are either String or byte[], and
> String will be internally converted to byte[] (after a PrepareString
> normalization). The AttributeValue is what I called AVA (sticking to
> the RFC terminology). It makes sense to me to have such an object, as
> we have to keep the user provided value, and to have a normalized form
> of this value. Of course, you can cach such a value in the Attribute,
> but you will have to do the same thing for the RDNs.
> I would arther discuss those specific points on another thread to not
> confuse people.


>>    * Search scope (needs to be extensible - i.e. not an enum)
> So Scope or SearchScope ? Also, does it really have to be extensible ?

I think SearchScope - Scope seems a bit generic to me. I don't feel 
strongly about this though.

The LDAP RFC specify several extension points. Two of them are the 
search scope and modification type. I don't that we need to go overboard 
supporting extensibility, but I think that it may be too limiting to use 
a enums for these since they are inextensible (e.g. adding new values 
could break switch statements in client apps). Also it might be the case 
that certain applications are using their own custom scope/mod-type 
which are out of our control. Therefore I think that it would be nice if 
we supported the standard scopes and mod-types as constants but perhaps 
allowed client apps to define their own on the fly. E.g:

    SearchScope scope = SearchScope.SUBTREE;

    // User defined value (we could allow the caller to pass in a
    user-friendly name as well):
    SearchScope scope = SearchScope.valueOf(4);

    // But... what does this do? Should it evaluate to true?
    if (SearchScope.valueOf(5) == SearchScope.valueOf(5)) {
       // Same instance - enum like behavior.

For modification types I thought it might be cool to allow registration 
of new types including a Strategy pattern call-back which can be used to 
apply changes to an attribute.

    public interface ModificationStrategy {

       // Ignore exceptions for now for simplicity.
       Attribute modifyAttribute(Attribute currentAttribute, Attribute

    public final class ModificationType {

       public static final ModificationType ADD = register(...);

       public static final ModificationType DELETE = register(...);

       public static final ModificationType REPLACE = register(...);

       public static final ModificationType INCREMENT = register(...);

       // Support registration of additional types.
       public static void register(int type, String shortName,
    ModificationStrategy strategy);


I think that this is probably more useful on the server side rather than 
in a client API so I'm not going to push for this. However, I think that 
we should allow clients to pass in arbitrary modification types in 
modify requests. If we want elements of this API to be used on the 
server side then I think that it's really important to support 
user-defined scopes and mod-types since, if we do not, the LDAP server 
will fail incoming operations during the request decode phase.

Result codes should definitely allow arbitrary values (i.e. not an enum) 
since LDAP extended operations and controls can define their own.

>>    * Modification type (needs to be extensible - i.e. not an enum)
> Operation ? ModOp?

The protocol calls this field Operation, but I think that this is one of 
those cases where we should ignore the RFC naming. In this case 
Operation is way too generic - for a start basic LDAP  request types are 
referred to as Operations (add, delete, modify, modifyDN, search, etc).

In our server we've used Modification (RFC element 
ModifyRequest.changes)  and ModificationType (RFC element 
ModifyRequest.changes.operation). In our prototype SDK we've used Change 
instead of Modification and ModificationType as per the server. I was 
probably smoking something that day since I haven't been consistent! ;-) 
For consistency I should have stuck with Modification/ModificationType 
or Change/ChangeType. However, the latter form could easily be confused 
with an LDIF record change type.

So after all that verboseness, my preference is for 
Modification/ModificationType. I prefer ModificationType because it is 
clearly associated with the class Modification.

>>    * Dereference aliases policy
> Sure. Don't have a name in mind

We just use DereferenceAliasesPolicy. It's a bit long but it's rarely 
used so developers rarely need to type it in.

>>    * Condition result for filters (true, false, undefined)
> Yup. A name ?

Err... we've been imaginative and used ConditionResult :-)


View raw message