r14 - 27 Nov 2006 - 15:17:24 - MorgenSagenYou are here: OSAF >  Projects Web  >  DevelopmentHome > ServicesWorkingGroup > SharingProject > ExternalInformationModel

External Information Model

The purpose of this proposal is to provide a new intermediate layer -- dubbed the 'External Information Model' (aka EIM) -- between objects and their external serialized representations. Decoupling the two in this manner means either can change format without affecting the other; a parcel developer doesn't need to know about external formats, as long as they write code that can convert items to and from EIM form. Whether we're dumping data to disk or sharing data across the wire, parcels will convert items to this new intermediate form which will then be converted to the appropriate external representation upon export. Having such a model also helps solve the schema evolution problem because it makes it easier for parcel developers to write upgrade code; they simply write code that translates a more-or-less fixed external format into their parcel's current schema. Because the external format is not used for normal application processing, it can be simpler and far more stable than the application-specific schema is likely to be.

When a parcel developer goes through the process of determining what attributes they want to share (or dump/reload), they figure out what "record types" would be required to store those attributes and then write methods which convert that parcel's items to and from those records. Think of a record type as a relational database table -- i.e. a ordered list of columns -- and records as rows. Next, for each record type the parcel writer defines a unique namespace name and registers the name with the sharing framework, providing two conversion callbacks -- 'inbound' and 'outbound' -- for that record type. When the time comes to import an item (whether by subscription, import, etc.) the external, serialized representation of the item is converted into to EIM form which consists of one or more record types, each with an associated namespace name. The sharing framework then steps through the record types' namespace names and calls the 'inbound' conversion callback that was registered on each. The callback is then responsible for creating/updating/deleting items.

Similarly, when it's time to export/publish an item, the set of namespaces appropriate to that item are determined, and the 'outbound' registered callbacks are called to convert the item to EIM form. Once there, the sharing framework hands the data to the appropriate conduit/format objects to serialize it.

Another new proposed concept is a "sharing schema" which consists of a name, a version, and a collection of namespaces that are mutually dependent. At the time a sharing conduit is being configured (for publish, subscribe, dump, reload, etc.) the appropriate sharing schema(s) are selected and noted in the conduit. We will ship with a sharing schema that covers all the out-of-the-box Kinds we define, and parcel writers can add their own.


Example 1:

A developer writes a Bookmark parcel, and defines Bookmark as a subkind of ContentItem, adding 'URL' and 'Last-Visited' attributes. Assuming that there is already a sharing schema defined which handles all the attributes of ContentItem, only a simple record type of three fields is required: UUID, URL, Last-Visited. The developer writes the two conversion methods:

def inbound(record):
   item = getItem(record[0])
   item.url, item.lastVisited = record[1:]
def outbound(item):
   return item.itsUUID, item.url, item.lastVisited

Next the developer chooses a namespace name, say 'http://example.org/schemas/bookmark/1.0', and registers the two conversion callbacks with it:

sharing.register('http://example.org/schemas/bookmark/1.0', inbound, outbound)


Example 2:

In the previous example we were able to add the new attributes "inline" in a single record type. However, a many-to-many relationship such as the "participants" relationship between CalendarEvents? and Contacts requires a separate record type (like an RDBMS join table) with two fields: Event-UID and Contact-UID. If the list needs to be ordered, a third field could be added to maintain sort order. If instead the attribute holds a dictionary, then a third dictionary-key field could be added.


Example 3: Sample Records

Here are a few record type definitions:

class ItemRecord(sharing.Record):
    uuid = sharing.key(schema.UUID)
    title = sharing.field(sharing.TextType(size=256))
    triage_status = sharing.field(sharing.TextType(size=256))
    triage_status_changed = sharing.field(sharing.DecimalType(digits=11,
        decimal_places=2))
    last_modified_by = sharing.field(sharing.TextType(size=256)) # storing an email address
    created_on = sharing.field(sharing.DateType)
class NoteRecord(sharing.Record):
    uuid = sharing.key(schema.UUID)
    body = sharing.field(sharing.LobType())
    icaluid = sharing.field(sharing.TextType(size=256))
class TaskRecord(sharing.Record):
    uuid = sharing.key(schema.UUID)
class EventRecord(sharing.Record):
    uuid = sharing.key(schema.UUID)
    dtstart = sharing.field(sharing.DateType)
    dtend = sharing.field(sharing.DateType)
    location = sharing.field(sharing.TextType(size=256))
    rrule = sharing.field(sharing.TextType(size=1024))
    exrule = sharing.field(sharing.TextType(size=1024))
    rdate = sharing.field(sharing.DateType)
    exdate = sharing.field(sharing.DateType)
    recurrenceid = sharing.field(sharing.DateType)
    status = sharing.field(sharing.TextType(size=256))

...and here are some sample items:

Note (UUID 1)

  • displayName = "Example note"
  • body = "Example body"
  • triageStatus = "done"
  • triageStatusChanged = (float) -1164697997.0
  • createdOn = 2006-07-13 12:26:00-07:00
  • lastModifiedBy = UUID 2

Contact (UUID 2)

  • createdOn = 2006-07-13 12:30:00-07:00
  • contactName = UUID 3
  • emailAddress = "morgen@example.com"

ContactName? (UUID 3)

  • createdOn = 2006-07-13 12:30:00-07:00
  • firstName = "Morgen"
  • lastName = "Sagen"

Example items in EIM form

2 tables:

Table 1: namespace http://schemas.osafoundation.org/pim/item

# (Item UUID, title, triage_status, triage_status_changed, lastModifiedBy UUID, createdOn)

  • (1, "Example note", "done", -1164697997.00, "morgen@example.com", "2006-07-13 12:26:00-07:00")

Table 2: namespace http://schemas.osafoundation.org/pim/note

# (Item UUID, body, icaluid)

  • (1, "Example body", "")
Edit | WYSIWYG | Attach | Printable | Raw View | Backlinks: Web, All Webs | History: r14 < r13 < r12 < r11 < r10 | 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.