[TransWarp] peak.naming .. first contact
Phillip J. Eby
pje at telecommunity.com
Fri Feb 14 12:42:49 EST 2003
At 04:27 PM 2/14/03 +0100, Ulrich Eck wrote:
>Imap is somewhat special, cause is has basically 3 different types of
>objects:
>
>1. Connection: The Connection is the root object that does basically all
> all the work.
> it should be accessible through an URL like:
> "imap://user:[email protected]:port"
Sounds good. Note that you can derive the connection from
storage.ManagedConnection if you want to make use of its "lazy opening"
capabilities.
>2. Folder: Folders can contain other Folders and Messages. Folders should
> probably be Contexts that allow retrieval of child-Folders and Messages
> as well as creating child-Folders and Messages.
> a FolderURL would look like this:
> "imap://user:[email protected]:port/folder.path"
>
>3. Message: The Message is the "Leaf" of that tree that represent the
>actual message
> given an MessageUrl the message should be retrieved from the server.
> a MessageURL would look like this:
> "imap://user:[email protected]:port/folder.path/123"
>
>What i have now:
>
>1. an imapURL(naming.ParsedURL) class that does the parsing of that url
>correctly.
> the retrieve method currently returns:
> - a connection-object if no folder/message was given
> - a connection-object with the selected Folder if folder given but not
> message
> - an email.Message-object if folder/messageid is given.
>
>2. an imapFolderPath(naming.CompoundName) that defines that a folder-path
>is seperated
> with a "." and left-to-right.
>
>what i think i need (but don't know how to implement):
>
>- ImapFolderContext: a naming.NameContext that represents that actual folder
> hierarchy and has methods to lookup/bind other contexts and leafs.
>
>i've had a look at the Property-Context impl, where the URL doesn't
>implement the
>"retrieve" method but the context has _get/_contextNNS methods implemented.
>
>Am I on the right path ??
Here's a sketch of what I suggest:
class imapFolderContext(naming.NameContext):
def imapConn(self,d,a):
return imapConnection(address=self.namingAuthority)
imapConn = binding.Once(imapConn, provides=IConnectionToIMAP)
def _get(self, name, retrieve=True):
# this is rough; you'll need to flesh it out a bit
return self.__class__(self, namingAuthority=self.namingAuthority,
nameInContext=self.nameInContext+name,
imapConn=self.imapConn
)
def _contextNNS(self, attrs=None):
# this needs work too...
return imapMessageContext(self, folderPath=self.nameInContext,
...), attrs
class imapMessageContext(naming.NameContext):
imapConn = binding.bindTo(IConnectionToIMAP)
# _get method retrieves message from folder using self.imapConn
These two contexts will use different 'compoundParser' definitions; the
first one wants a '.'-based name parser for the folder path, and the other
wants a flat syntax for the message number. Your imapURL will use a
*composite* name parser for its body, and the folder path syntax for its
*compound* parser.
The URL class doesn't need a retrieve method. That's for URLs which are
pure addresses that don't really have a "name in context" part, just a
"naming authority" part.
Anyway, you want to use a composite name and two kinds of contexts here,
because the folder naming system is not the same as the message naming
system. The '/' between the folder path and the message identifier
effectively means "go to the Next Naming System" (NNS). So by implementing
a _contextNNS() method that returns another naming context class that
implements the "next naming system", PEAK will bridge the gap for you.
The PropertyContext, PropertyPath, and PropertyURL classes in
peak.naming.factories.config_ctx are good examples for all of this, except
that you need a second context class, and also a way to "pass down" a
connection object among the contexts so that they can share the same
connection. Once you've done this, you can do things like:
aContext=naming.lookup("imap://u:pw@host/folder.path")
fooFolderCtx = aContext['foo'] # get subfolder 'folder.path.foo'
aMessage = aContext['/1234'] # message 1234 from 'folder.path'
barMsgCtx = fooFolderCtx['bar/'] # message context for 'folder.path.foo.bar'
anotherMsg = barMsgCtx['456'] # message 456 from 'folder.path.foo.bar'
See how this works?
As far as the folder (not message) contexts go, you probably want to
implement 'createSubcontext' and 'destroySubcontext', not bind/unbind. The
message context can implement bind/unbind, which means you can do:
fooFolderCtx.bind('/1234',aMessage)
or
fooFolderCtx['/1234'] = aMessage
Note that even though the folder context doesn't implement bind/unbind, the
composite name will be looked up using the 'resolveToInterface()' method,
and the message context will be told to "bind('1234',aMessage)".
>I also thought about building datamanagers for imap-access, but i have no
>idea how to setup tree-like dm-structures. Setting up datamangers would
>have the advantage of being able to cache results and more ..
It's certainly possible to do that, but the implementation structure would
probably be very different than what I've outlined. Instead of passing
down a connection between contexts, you'd probably need to pass down the
data manager.
>or (if more appropriate) how to build dm's for tree-like content?
>(i could imagine using a tuple(<folder>,[None|messageid]) as key for the dm.)
You could do it that way, if by '<folder>' you mean a folder path string.
I'd say that the optimal way to do this depends a lot on your application
and how it wants to use IMAP. If you need to acess IMAP in a
"navigational" way, naming contexts might be better. If you need to
address specific objects or transform representation, data managers are
more suited. If you need a mixture of both, you can combine the two,
either as a data manager that returns naming contexts, or as a set of
naming contexts that use a data manager "behind the scenes".
More information about the PEAK
mailing list