r5 - 26 Oct 2004 - 11:46:54 - MorgenSagenYou are here: OSAF >  Journal Web  >  ContributorNotes > MorgenSagenNotes > MorgenSagen20041021

Clouds (Under Construction)

Motivation

It is often the case that when you perform an operation on an item in the repository you really want the operation to also include a set of related items. For example, when copying a UI widget item you most likely will want to copy all of that item's children, children's children, etc. Or if you are sharing a calendar event item you will also probably want to share the items representing the event's participants and location. The repository cloud mechanism allows you to define these relationships between kinds in the schema, and to ask the repository for a given item's related items. We found having a single generic notion of how one kind relates to another is insufficient, and therefore the repository supports multiple cloud definitions per kind; this allows you to ask the repository, "If I am going to copy a given item, which others should also get copied," and "If I am going to share a given item, which others should also get shared?" By defining "copy" and "share" clouds for the item's kind, the repository can answer those questions.

Cloud Definitions and Item Clouds

'Cloud definitions' are roadmaps to lead you from a starting point to a set of reachable items. They are like functions, associated with a Kind, that take an item - the cloud entrypoint - as an input and return a list of items (or give you a copy of a set of items); the resulting set of related items is referred to as an 'item cloud'. A cloud definition is essentially a list of attributes to traverse, and policies for how to traverse them (such as whether or not to recursively traverse). More precisely, a cloud definition is a list of 'Endpoints' which encapsulate an attribute/traversal-policy pair. A Kind item may have multiple cloud definitions items assigned to it, each with a different "alias" such as "share" or "copy". To define a cloud, you create a Cloud item in the repository, and add it to a Kind's clouds attribute. Next you define one or more Endpoint items which are each associated with an attribute of that kind.

For example, say you have the following simple Email schema, which in plain English reads, "Email Folders contain Email Messages which are to/from Email Accounts":

xmlns="http://osafoundation.org/parcels/core"
xmlns:cm="http://osafoundation.org/parcels/contentmodel"
xmlns:mail="http://osafoundation.org/parcels/contentmodel/mail"

<!-- The Email Message kind -->
<Kind itsName="EmailMessage">

    <!-- Subject -->
    <Attribute itsName="subject">
        <type itemref="String"/>
    </Attribute>

    <!-- From -->
    <Attribute itsName="from">
        <type itemref="mail:EmailAccount"/>
    </Attribute>

    <!-- To -->
    <Attribute itsName="to">
        <cardinality value="list"/>
        <type itemref="mail:EmailAccount"/>
    </Attribute>

    <!-- the list of messages (directly) contained by this message -->
    <Attribute itsName="containedMessages">
        <cardinality value="list" />
        <initialValue />
        <type itemref="mail:EmailMessage"/>
        <inverseAttribute itemref="mail:EmailMessage/containedBy"/>
    </Attribute>

    <!-- the list of messages that (directly) contain this message -->
    <Attribute itsName="containedBy">
        <cardinality value="list" />
        <initialValue />
        <type itemref="mail:EmailMessage"/>
        <inverseAttribute itemref="mail:EmailMessage/containedMessages"/>
    </Attribute>

    <!-- the list of email folders that this message appears in -->
    <Attribute itsName="folders">
        <cardinality value="list" />
        <initialValue />
        <type itemref="mail:EmailFolder"/>
        <inverseAttribute itemref="mail:EmailFolder/messages"/>
    </Attribute>

</Kind>

<!-- An Email Account kind -->
<Kind itsName="EmailAccount">

    <!-- the actual email address string -->
    <Attribute itsName="address">
        <type itemref="String"/>
    </Attribute>

    <!-- a reference to some contact item which represents the owner of
         this email account (I've not included this contact kind in this
         schema file) -->
    <Attribute itsName="contact">
        <type itemref="cm:Contact"/>
        <inverseAttribute itemref="cm:Contact/emailAccounts"/>
    </Attribute>

</Kind>

<!-- A folder item representing a place to stick email messages -->
<Kind itsName="EmailFolder">

    <!-- A ref collection of email messages -->
    <Attribute itsName="messages">
        <cardinality value="list" />
        <initialValue />
        <type itemref="mail:EmailMessage"/>
        <inverseAttribute itemref="mail:EmailMessage/folders"/>
    </Attribute>

</Kind>

Now when it's time to share Email Message items, say you also want to include the Email Account it was sent to, and (recursively) all Email Message items it contains. Let's define a "share" cloud definition:

<Cloud itsName="emailMessageShareCloud">

    <!-- specify which attributes to traverse and how -->
    <Endpoint itsName="toEndpoint">
        <attribute value="to" />
        <includePolicy value="byValue"/>
    </Endpoint>
    <Endpoint itsName="fromEndpoint">
        <attribute value="from" />
        <includePolicy value="byReference"/>
    </Endpoint>
    <Endpoint itsName="containedMessagesEndpoint">
        <attribute value="containedMessages"/>
        <includePolicy value="byCloud"/>
        <cloudAlias value="share"/>
    </Endpoint>

    <!-- hook up these endpoints to the cloud -->
    <endpoints itemref="mail:emailMessageShareCloud/toEndpoint"/>
    <endpoints itemref="mail:emailMessageShareCloud/fromEndpoint"/>
    <endpoints itemref="mail:emailMessageShareCloud/containedMessagesEndpoint"/>
</Cloud>

<-- The following lines would be added within the Email Message kind -->
    <!-- associate emailMessageShareCloud with the Email Message kind -->
    <clouds itemref="mail:emailMessageShareCloud" alias="share"/>

This will create a Cloud item named emailMessageShareCloud with three Endpoints:

  • toEndpoint will traverse the 'to' attribute using the 'byValue' traversal policy; this policy means that the item(s) pointed to by the 'to' attribute will be considered part of the item cloud

  • fromEndpoint will traverse the 'from' attribute using the 'byReference' traversal policy; this policy means the item(s) pointed to by the 'from' attribute will not be considered part of the item cloud, but during a copy( ) a reference to the item(s) will be copied

  • containedMessagesEndpoint will traverse the 'containedMessages' attribute using the 'byCloud' traversal policy; this policy means that not only are the item(s) pointed to by the 'containedMessages' attribute considered part of the item cloud, those item(s) will in turn be fed into the "share" cloud definition and the resulting items will also be added to the item cloud

Cloud traversal policies are discussed in the Cloud epydoc.

Cloud Definition and Endpoint Inheritance

As mentioned earlier clouds are aliased - have a name - in their kind's clouds collection. The set of endpoints used to gather all the items in a cloud by a given alias on this item's kind is the aggregation of the endpoints defined on this cloud and the endpoints inherited through the clouds by the same alias defined on the kind's superKinds, recursively. Endpoints are inherited vertically up the superKinds chain and horizontally along the cloud's kind superKinds list.
Just as with clouds, endpoints maybe be aliased in their clouds' endpoints collections. Unaliased endpoints - in other words, anonymous endpoints - are always inherited. Aliased endpoints are only inherited if there is no locally defined endpoint by the same alias.

Current/Future

In 0.4, there is the notion of a 'default' cloud which is special-cased -- if you didn't specify a cloud alias to use, the 'default' cloud would be selected. This has proven to complicate matters -- what does it mean for a cloud definition to be the default? There are different cloud definitions for different purposes, and when making use of a cloud definition, the application writer should always be explicit about which one to use.

Edit | WYSIWYG | Attach | Printable | Raw View | Backlinks: Web, All Webs | History: r5 < r4 < r3 < r2 < r1 | More topic actions
 
Open Source Applications Foundation
Except where otherwise noted, this site and its content are licensed by OSAF under an Creative Commons License, Attribution Only 3.0.
See list of page contributors for attributions.