Cosmo 0.7 Architecture Notes
Changes from 0.6.1
- ContentItem is now abstract
- Files represented as FileItem instead of ContentItem
- time-range indexes refactored and now stored on EventStamp
- icalendar property indexes removed (this plus time-range index refactoring results in smaller db size)
- new query api that uses new ItemFilter model
Source Structure
The cosmo source code is organized into java packages. The major packages are:
| package name | description |
| org.osaf.cosmo.model | model objects |
| org.osaf.cosmo.service | service api |
| org.osaf.cosmo.service.impl | service api implementation |
| org.osaf.cosmo.dao | dao api |
| org.osaf.cosmo.dao.hibernate | hibernate dao implementation |
| org.osaf.cosmo.hibernate | cosmo hibernate extensions |
| org.osaf.cosmo.acegisecurity.* | cosmo acegi security extensions |
| org.osaf.cosmo.security | security api used in cosmo |
| org.osaf.cosmo.security.impl | security api implementation |
| org.osaf.cosmo.dav.* | WebDAV/CalDAV protocol |
| org.osaf.cosmo.atom.* | Atom protocol |
| org.osaf.cosmo.mc | Morse Code protocol |
| org.osaf.cosmo.cmp | CMP protocol |
| org.osaf.cosmo.ui.* | Application code for Account Browser ui |
The rest of this document is going to focus mainly on the model,service, and dao layers.
User
A
User represents a Cosmo user. In addition to standard attributes such as
username ,
email ,
firstName , and
lastName ,
User contains a
Set of
Preference s which allow arbitrary attributes to be associated to a
User . These preferences are mainly used by the ui. A
Set of
CollectionSubscription s provides a way to associate "subscription" collections to a user.
Item
All content in Cosmo inherits from the abstract
Item class.
Item defines common attributes such as
uid (unique identifier),
name (used in DAV URI),
displayName (item description), and common associations such as
owner (user that created item),
parents (collections that item belong to),
attributes ,
tickets , and
stamps .
A group of items is called a collection. Collections are modeled as items (
CollectionItem ) with an additional association
children . Cosmo 0.7 supports items belonging to a multiple collections.
HomeCollectionItem is a special
CollectionItem that represents the root collection for a user. When a user is created a
HomeCollectionItem is automatically created. It is possible to have collections within collections.
The abstract class
ContentItem represents a piece of content. There are two implementations.
FileItem represents a file with binary content. All files created through DAV are stored as
FilteItem. NoteItem is the base for all pim (personal information manager) items. A personal information item includes notes, tasks, events, messages and any combination of these.
Implementation Notes
Items are mapped to the
item table using a
table per class hierarchy in Hibernate.
This means all
Item subclasses are mapped to the same table, and use a discriminator column (
itemtype ) to denote the item type for the row.
Attribute
Item has a
Map of
Attribute objects, indexed by a
QName . An
Attribute can be associated to a single
Item .
QName is a composite key that represents a qualified name (namespace and local name). There are several
Attribute implementations (String, Binary, Integer, etc) that are used to store different types of values. The polymorphic mapping allows any number of any mix of
Attribute implementations to be associated to an item.
Implementation Notes
Attributes are mapped to the
attribute table using a
table per class hierarchy in Hibernate. All
Attribute implementations are stored in the same table, and use a discriminator column (
attributetype ) to denote the attribute type for the row.
There is a bi-directional association between
Item and
Attribute , with
Item containing the inverse mapping. This means that
Attribute is responsible for managing the association.
Save, update and delete operations are cascaded to
Attriubte from
Item .
Stamp
Item has a
Set of
Stamp objects. A stamp can be associated to a single
Item .
A stamp associates a related set of properties/attributes/methods to an
Item .
This is different from
Attribute , which generally represents a single value.
For example
EventStamp , contains properties and apis relating to an event and
MessageStamp contains properties related to an email message. The stamp model allows items to be stamped and unstamped with these related sets of properties throughout its life-cycle.
CalendarCollectionStamp is another stamp implementation that is usedto indicate that a
CollectionItem is a calendar collection.
Like
Attribute , the polymorphic mapping allows any number and mix of stamps
to be associated to an
Item .
Implementation Notes
Stamps are mapped to the
stamp table using a
table per class hierarchy in Hibernate.
This means all item implementations are stored in the same table, and use a discriminator column (
stamptype ) to denote the stamp type for the row.
EventStamp and
CalendarCollectionStamp are mapped to secondary
tables (
event_stamp and
calendar_stamp ) that is joined to the primary stamp table.
Note that not all
Stamp implementations require a new table.
MessageStamp is implemented by storing its data as item attributes. One benefit (or drawback depending on how you look at it) of this is that
when a stamp is removed, the underlying attributes remain associated to the item, allowing the item to be "stamped" and "unstamped" without losing the stamp data. There is a bi-directional association between
Item and
Stamp with
Item containing the inverse mapping. Like
Attribute , stamp creation, modification and deletion is cascaded by
Item .
Ticket
Item has a set of associated
Ticket objects. A ticket can be associated to a single
Item .
A ticket is an authorization object that grants some level of access to an item and its descendents based on a unique ticket key. If a client has this key, then the client can gain access to the item and its descendants with the ticket key.
Implementation Notes
Tickets are mapped to the
tickets table. Ticket privileges are mapped to the
ticket_privilege table. There is a bi-directional association between
Item and
Ticket , with
Item containing the inverse mapping.
Colleciton Subscription
A
User contains a set of
CollectionSubscription s. A
CollectionSubscription contains a ticket key and a collection uid. It is a way to associate a collection that is not owned by the user to the user. The ticket key provides the necessary authentication to access the collection.
Tombstones
Item has a set of associated
Tombstone objects. A tombstone can be associated to a single
Item . A tombstone is a way to represent that something existed and was removed from the item. The implementations are
ItemTombstone ,
StampTombstone , and
AttributeTombstone .
ItemTombstone are added to
CollectionItem and represent that an item was removed from the collection.
StampTombstone and
AttributeTombstone are used to represent that a stamp and attribute have been removed from the collection. Tombstones are used for synchronization purposes (think the morse code protocol) where a client only wants the changes from the last time it synchronized.
PIM Items
As stated before,
NoteItem provides the basis for a pim item in Cosmo. Cosmo 0.7 supports the full range of pim items that Chandler supports. All pim items start out as a
NoteItem . The
NoteItem can be stamped as a task, event and message. A calendar event is represented by
NoteItem stamped with
EventStamp .
The
EventStamp contains an ical4j
Calendar object,
which is an iCalendar component as defined in RFC 2445. The iCalendar component must contain a single VEVENT component (master event).
Note that this allows Cosmo to support events submitted using an external protocol such as CalDAV because the internal representation of an event is iCalendar. Cosmo preserves all valid iCalendar data.
Indexing Calendar Items
In order for Cosmo to provide useful queries such as a time-range query, it must be smart about indexing events. Cosmo 0.7 indexes events by calculating and storing extra data on the
EventStamp during creation/modification of the event. This data includes a start and end date for the event and whether that event is recurring or floating (no timezone associated with the event).
Previous versions of Cosmo indexed every occurrence of a recurring event, which didn’t prove well for recurring events with no end (Cosmo only indexed a year or so). Cosmo 0.7 handles these events by expanding them during the query, allowing time-range queries well into the future.
Persistence
Cosmo 0.7 uses Hibernate annotations (
http://www.hibernate.org/397.html) on all the model classes (
org.osaf.cosmo.model ) to map Cosmo objects to database tables. This frees us from the use of separate XML config files (as used in Cosmo 0.5).
All package level Hibernate configuration annotations are defined in
org.osaf.cosmo.model.package-info.java . This includes named queries and custom types.
Cosmo utlizes Hiberate's second level and query caches. The cache implementation used is Ehcache, which can be configured using
echache.xml .
Cosmo 0.7 has been developed and tested on Derby 10.2.2.0,
MySQL? 5 (
InnoDB?), and
PostgreSQL? 8.2 databases. Cosmo relies on Hibernate's auto schema generation to create the
database schema at startup (see
DbInitializer.java ). Hibernate
uses the annotations defined on all the model objects to automatically generate and execute the ddl statements that define the Cosmo schema. Because one of the goals for Cosmo is to support multiple databases, the database schema is not as optimized as is could be. We have to support the least common denominator, which means no custom triggers, stored procedures, or anything that is database specific that isn't handled by
Hibernate's dialect abstraction.
Cosmo makes extensive use of Hibernate's lazy-loading feature. This means associations such as
children ,
parents,
attributes,
stamps, etc aren't loaded until they are needed. This allows additional data to be loaded from the db without requiring additional service calls. Cosmo uses the "Open Session in View" pattern to allow lazing loading outside of the service layer. This means a new Hibernate session is created for each request and kept open for the duration (implemented as a servlet filter).
DAO Layer
The DAO layer in Cosmo provides the basic CRUD operations for the model objects. The main DAOs in Cosmo are
UserDao and
ContentDao .
UserDao handles all
User CRUD operations and
ContentDao handles the
ContentItem CRUD operations. There is also a
CalendarDao that provides special calendar object query apis. The only consumer of the DAO layer is the Service layer. That is, the only code that uses DAO
objects is the Service layer.
Implementation Notes
Cosmo provides a Hibernate based implementations for the DAOs. These implementations extend from Spring's
HibernateDaoSupport class.
more notes:
CosmoZeroPointSevenDaoLayer
Service Layer
The service layer consists of
UserService and
ContentService and is what is exposed to the application. The transaction boundary in Cosmo is at the service layer, meaning each service call is a transaction. A service can utilize several DAOs. One example is
UserService .createUser(), which needs to create a new
User and create a new
HomeCollection for that
User .
more notes:
CosmoZeroPointSevenServiceLayer
Implementation Notes
Cosmo uses Spring's declarative transaction management
TransactionProxyFactoryBean for the service layer. There is no transaction code in any of the Cosmo service/dao implementation classes. Instead, transactional behavior is defined in Spring's
applicationContext.xml . For Cosmo, this means each method called on a service requires a transaction to be present, and will create a new transaction if
one doesn't exist. Cosmo relies on transactions for atomicity. If a service method is called that updates multiple database tables and fails halfway through, the transaction is rolled back instead of leaving Cosmo in an invalid state. This requires the use of a database that supports transactions. For
MySQL? this means using
InnoDB? tables.
Security
CosmoZeroPointSevenSecurityNotes
Application Framework
Cosmo utilizes the Spring framework extensively to instantiate and configure the majority of the service/dao layer objects. An example is the Hibernate
SessionFactory (no hibernate.cfg.xml file as everything is configured in Spring's applicationContext.xml).
--
RandyLetness - 20 Aug 2007