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