Good news, bad news: good news is I've implemented a LDAP based
membership adapter that implements the complete MemberAdapter interface
(the previous LDAP adapter was incomplete and limited in application).
In stand alone testing my adapter seems to work quite nicely.
Skip to the last paragraph if you don't need or want the details.
Now the bad news, I'm having trouble integrating it because of either
structural problems with adapters or a lack of understanding of how
adapters are supposed to work. I'm looking for guidance or insight. Here
are the issues I've run into:
* Adapters are discovered by the presence of extend.py in the list's
directory. How does extend.py get into the list directory? The only way
I could figure was manual copying after list creation, this isn't a
viable mechanism for a running site.
Also, while I can see the value of per list adapters that seems like a
niche case, a more common scenario would be every list resident at a
site would use the same adapter module. To solve this problem I added
code in the MailList constructor to look for a mm_cfg variable defining
a global adapter module. But list creation/instantiation is a two step
process, MailList object construction in __init__, followed by
MailList.Create(). The adapter is not loaded in __init__ unless a name
is provided, which is only done after Create() has been called.
Most importantly an adapter cannot correctly initialize itself until the
work of Create() is complete. This is very important, but more on this
This sequence in TestBase.py leaves the adapter unloaded and
uninitialized, it does not work.
mlist = MailList.MailList()
mlist.Create('_xtest', 'test(a)dom.ain', 'xxxxx')
This idiom below which is found in most of the code does work because
the list has already been created, but now we're back to the chicken and
egg problem of when does extend.py get into the list directory.
mlist = MailList.MailList(listname, lock=0)
This is a good moment to go back to the issue of per list adapter
initialization (or rather the lack of it). After the mlist is
instantiated as above it might very well call an adapter method, for
example mlist.addNewMember(). But the adapter has never been called as
part of list creation. If the adapter must create entities in a backend
database to service the list data it has never been given that
opportunity. Thus the adapter is dependent on asking the question "does
this list exist in my database, if not create it" every time the adapter
object is instantiated, this is not only a big performance problem but
it completely fails with the calling sequence in TestBase.py.
If you've followed along so far pat yourself on the back :-) here's the
Unless I'm out to lunch with a horrible misunderstanding I propose 3
1) Provide a site wide variable that specifies an adapter for every list
which is overridden by the presence of extend.py in the list directory.
If the site wide adapter is used then MailList.__init__() loads it and
calls an initialization function in the module (extend()??,
2) At the end of MailList.Create() it should test for the existence of
an adapter and if so it should attempt to call the adapters Create()
3) Just as the adapter is not informed of list creation is is not
informed of list destruction either, calls need to be added to invoke
Remove() as well.
I'm happy to provide patches for all this, I'm not interested in
suggesting anyone else do more work, I'm mostly interested in knowing if
I'm on the right track or if I have a misunderstanding.
PostScript (or a few more questions):
Now after having fully implemented the adapter interface I have to admit
I don't really understand what its buying you over the existing
OldMemberAdapter. My initial thought was to capitalize on existing user
information at a site, but given the way mailman data is structured (a
set of lists, each list may contain both local and unknown foreign
users, and user properties are per list) then there seems to be little
value in intermingling site user data and mailman list data.
Also, it was not clear how an adapter might implement just a subset of
the methods via inheritance, I suppose it would copy the function
pointers from the mlist._memberadapter into its own methods before
resetting mlist._memberadapter to itself. yes/no?
John Dennis <jdennis(a)redhat.com>