Hi Emmanuel,

I've put my responses inline..


On 27/11/09 12:42, Emmanuel Lecharny wrote:
Ok, so we can start with :

DN
RDN
AVA
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.


Agreed.


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
   Entries.
   DN dn = DN.valueOf("dc=example,dc=com", schema);
   Entry e2 = new SortedEntry(dn);
   e2.addAttribute("description", "value1", "value2", "value3");
   e2.addAttribute(a2);


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...


Agreed.



   * 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.


OK.


   * 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
   changes);
   }

   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 :-)


Matt

Reply via email to