CoreObject
==========

:Maintainer: Quentin Mathe <qmathe@club-internet.fr>
:Authors: Yen-Ju Chen, Quentin Mathe, Eric Wasylischen
:License: MIT Licence.
:Version: 0.4

*CoreObject* is a framework for describing and organizing model objects, with 
automatic persistence and versioning by recording messages sent to objects. It 
offers a flexible versioning scheme where both individual objects and their 
entire object graph can be versioned separately. The built-in object model is a 
generalization of the property model used by the AddressBook framework. Foreign 
model objects can be also integrated by wrapping them with a special proxy.
CoreObject uses the EtoileSerialize framework which, in many cases, allows 
objects and messages to be automatically serialized with no extra code being 
written.

Before writing code that uses CoreObject, be sure to read Known Limitations 
section.

Note: CoreObject is written from scratch. 
It only try to mimic the API of AddressBook.
CoreObject was initially called OrganizeKit. This framework was supposedly to 
be the next version of CollectionKit. OrganizeKit became CoreObject when we 
realized it precisely offers the Name Service layer which had been envisionned
for CoreObject.

Build and Install
-----------------

Read INSTALL document.


Mac OS X support
----------------

CoreObject is not supported on Mac OS X, mostly because it depends on 
EtoileSerialize that heavily depends on the GNU ObjC runtime API. 
No future support is currently planned at this time, but patches are welcome if 
you are interested in porting CoreObject to Cocoa. To achieve that, 
EtoileSerialize will have to be rewritten or eventually ported to the 
NeXT/Apple runtime.


Developer notes
===============

CoreObject provides small number of basic units:
  - COMetadataServer, COObjectContext, COObjectServer
  - COObject, COGroup, COProxy
  Usually you only need to interact with the last three classes that conforms 
  to the COManagedObject protocol and eventually COObjectContext if you want to
  interact with the persistency history.

* COObject is the base data model class that you can extend with arbitrary 
  properties. It provides -setValue:forProperty: and -valueForProperty: as the 
  basic property access protocol. Besides basic data type provided by GNUstep, 
  COMultiValue is allowed.

* COGroup is a subclass of COObject and can contain members, either objects or 
  groups. It has a hierarchical structure where any object must belong to one or 
  more groups. This class can be also subclassed,  if you want to define 
  additional properties or your own constraints on the members that can be added 
  or removed.

* COProxy is a proxy class to integrate any object models that stand apart from 
  the COObject/COGroup hierarchy. By passing a model object to the proxy 
  initializer, you get a proxy which is a core object

* Each core object is uniquely identified by a UUID. It is generated 
  automatically and must not be changed.

* COObject and COGroup are also two protocols that makes up the Core Object 
  Protocol. Every core objects implements either one or both.
  If a class implements COManagedObject in addition to the previous two, its 
  instances are persistent core objects whose persistency is managed by 
  CoreObject, otherwise they are transient core objects such as 
  COFile/CODirectory instances. Transient core object have no history associated 
  with them, they are recreated each time they are used, and they are typically 
  used to map arbitrary external representations into the core object graph.

* Search is handled with NSPredicate instead of something similar to 
  ABSearchElement to reduce redundancy.


Built-in Object Model
---------------------

CoreObject provides a semi-structured object model, that can be used as a common 
storage facility for objects with properties, such as contact information, 
playlist, bookmark, etc.
These objects have defined structure (property-value relationship) 
which can be handled better than general property list. But values of these 
properties are too flexible to be stored in database, for example, a contact 
information may have multipe home phone numbers. Records can be grouped and 
groups can have groups inside.
AddressBook framework from Apple provides a good mechanism of handling these 
kind of objects. CoreObject aims to provide a general storage facility based on 
similar interface.


Known Limitations
-----------------

- The Filesystem backend (COFile and CODirectory) is work-in-progress, don't 
  play with it if you prefer to be sure you won't lost any data on your 
  filesystem. Well, in theory it isn't designed to erase your data, but who 
  knows, that's a developer preview release... ;-)
- Transient core object support is a moving target for now, the current support 
  is very limited and not well integrated with the rest of CoreObject
- COPersistentPool, COCollection API should be ignored
- COObjectServer API is very unstable and some methods such as -objectForURL:,
  -objectForUUID:, managedObjectForURL:, distantObjectForURL: may not work at 
  all.
- Multiple object contexts per process are supported but mostly untested.
- Context restoration with one or more COProxy intances in the graph of the 
  registered objects is untested, altough restoring a single COProxy to a past
  version is well supported.
- Switching to another metadata DB isn't yet supported, only the default one 
  bound to the current user can be used.
- Messages sent to multivalues aren't recorded, so you must reset a multivalue 
  on the object that uses it each time you alter a COMultiValue instance.
- No support for the recording of messages sent within an object cluster, only 
  the persistent roots COObject, COGroup or COProxy can trigger persistency, 
  the objects that belongs to the object graph/cluster behind those class 
  instances cannot. This multivalue limitation previously described is in fact a 
  subcase of this one.
  For now, if you want to record changes within an object cluster, the 
  problem can be worked around for COProxy. You can do it by adding a special 
  method to which you pass an object ref of your own, and implements this method 
  so that it records then forwards the message to the desired object in the 
  cluster.
- No deletion model, so you cannot remove an object from an object context once 
  it has been inserted and there is also no way to handle in-store deletion 
  (deleting an object bundle on disk and removing the entry from the metadata 
  DB).
- Backwards pointers between persistent roots aren't well supported. They are 
  returned by -parentGroups for COObject class or subclass instances, so for 
  now it is advised to avoid using this method.
- No history cleaning.
- No indexing of object properties or metadatas
- No fine-grained concurrency control, hence the loading of an object in memory 
  and the access to an object context must be limited to a single procress. 
  Different processes can read/write different objects at the same time if they 
  belong to different object contexts.
- Object bundles on disk that are moved or renamed must have their entries in 
  the metadata DB updated by hand. There is no way that the metadata server can 
  detect such moves for now. See COMetadataServer.h if you are interested in 
  doing that.
- Property list export should mostly work but currently depends on having all
  the core objects to export in-memory. Property list import works more or less, 
  but isn't truly usable because the metadata DB isn't updated at import time. 
  So it's a bit of no use, unless you decide to update the metadata DB by 
  yourself once the property list has been read and the object graph recreated 
  in-memory. Property list export/import hasn't been recently tested and was 
  written before COObjectContext and COObjectServer existed, so an imported 
  object graph is recreated without any care for the new persistency 
  architecture. This means imported core objects won't be correctly registered 
  into the current context and cached in the object server.


Tests suite
-----------

UnitKit (bundled with Etoile) is required.

   Steps to produce a test bundle and run tests suite:

    * make test=yes 

    * ukrun


Contribute 
----------

Read TODO document.
