On Saturday, 5 May 2012, Mike Burton wrote: > Hi Dan, > > Thanks for the update, good work, worth eating a few bits of eggshell:-) > > Could you list/ clarify meanings of your canonical string for symbols #~! > etc please- I'm confused by difference between ~ and # eg > CUS:123~NME:2~CTY:LON >
Hi Mike, First off, I made two slight mistakes in my first email: # should have been $ throughout, and CUS:123#NME:2 should have been CUS:123~NME:2. Thus: CUS:123 - persistent root !CUS:123 - transient root CUS:123$items - collection of persistent root !CUS:123$items - collection of transient root CUS:123~NME:2 - aggregated object within persistent root !CUS:123~NME:2 - aggregated object within transient root CUS:123~NME:2~CTY:LON - aggregated object within aggregated object within root CUS:123~NME:2$items - collection of an aggregated object within root CUS:123~NME:2~CTY:LON$streets - collection of an aggregated object within aggregated object within root I wonder whether that is what caused your confusion? Otherwise, and to answer the question, though: There's no intrinsic "meaning" to the symbols, other than to distinguish the parts of the OID. The ~ is the prefix for each aggregated object, while $ is the prefix for a collection, if any. I chose "~" because it's easy to see, I chose "$" because it is used as a separator in Java (outer vs inner class bytecode). A more useful answer, though , might be for me to explain why OIDs are so important. Within Isis we use an OID as the identifier of an ObjectAdapter, which in turn is a wrapper around the pojo. The main responsibility of an ObjectAdapter is to manage the "resolve state", ie lazy loading of an object. It's also used in dirty tracking: whether an object needs to be saved to the object store. The ObjectAdapter also points to the corresponding ObjectSpecification which describes the structure of the object: ObjectAdapter is like java.lang.Object, while ObjectSpecification is like java.lang.Class. Also: an OID is a value object (equals, hashCode etc). OIDs are important because they are provide an immutable handle to an object. This is useful for webapps, eg to use in links and forms, and its useful for the JSON (restful) viewer, eg in URLs. It's also useful for object stores, because they can (or rather, will now be able to) use the OID's string form to represent a reference between an object or the contents of a collection. OIDs are also more generally useful in supporting workflows: an OID is bookmarkable, so could be added into a favourites list, o (as we do on the big Irish project), can be converted into a barcode, which is great for handling incoming communications/correspondence that's been scanned. ~~~ We've had the concept of "CollectionOid"s for a while in Isis: if a Customer has a collection of Order's, then the CollectionOid is the ID for the java.util.List that holds a Customer's Order pojos. The "AggregateOid" is newer, introduced to support NoSQL databases and the more general DDD concept of an aggregate root. Each AggregateOid has a localId, which is unique within the aggregate; or in other words it is globally unique in conjunction with the parent Oid. ~~ The string format I'm suggesting here tries to reflect the "nesting" of objects of both aggregated entities and of collections: CUS:123 is the RootOid for a simple root aggregate; it's a CUS(tomer), id=123. CUS:123~NME:1 is an AggregateOid for the N(a)ME of a customer, with localId=1. In other words, this is modelling the fact that a customer might have several names or aliases, this being the OID of one of those names. Note that we don't know how the name object is related to its "owning" customer; but that's the responsibility of the ObjectAdapter/ObjectSpecification to furnish that information. CUS:123$items is the CollectionOid of a the "items" collection of customer id=123. We don't know what type of thing are stored in the "items" collection; but that's not the responsibility of an Oid: such info can be found from the ObjectSpecification for the Customer type. Again, we also don't know what the content of the "items" collection is: but that is the responsibility of the ObjectAdapter. ~~~ Lastly, in case it's not obvious, the "CUS" is the abbreviated object type (as per @ObjectType annotation). If there is no such annotation, then the object type is taken to be the fully-qualified class name. HTH, Dan > > Mike Burton > ( iPhone) > > > On 5 May 2012, at 10:13, Dan Haywood <[email protected]> wrote: > > > Hello all, > > > > First, just to say that I *know* the build is broken, and it's a pretty > > poor show on my part to let it happen, but it's a little bit of breaking > > eggs to make an omelette. > > > > Second, wanted to update on my current thinking on OIDs ... because this > is > > what I'm currently working on and what I intend to commit as soon as I > can > > (hopefully this coming week). > > > > Already committed: > > * our OIDs are now immutable > > * we have three types of OID: > > - RootOid, which is the OID of a root entity (implementation: is > > RootOidDefault). > > - AggregateOid, which is an aggregated entity that is persisted within > a > > root entity (eg part of a JSON doc in MongoDB). > > - CollectionOid, which wraps a List or Set of a root entity > > - The RootOidDefault was refactored from SerialOid, but it now has an > > "objectType" (eg "CUS" for customer), so is self-describing. > > - The CollectionOid also existed previously, and wraps a List or Set for > an > > entity > > - The AggregatedOid we also had a version of; it has a localId to > > distinguish it from other aggregates of its type (within its parent root) > > - Both CollectionOid and AggregatedOid have a parentOid > > > > > > Not yet committed: > > > > The first thing I've added to AggregateOid is its own objectType, and so > > that has also led me to introduce a TypedOid interface: both > RootOidDefault > > and AggregatedOid implement TypedOid. And so from there we can say that > > parents (of either AggregateOids or of CollectionOids) are always > TypedOids. > > > > With this change to AggregateOid, we can now say that all OIDs contain > > enough information to fully recreate them as objects: we do know the type > > of the object to instantiate and its unique identity. That isn't to say > > there's enough information to determine how these objects are wired back > > together again, but that's a responsibility of the object store to > persist > > this additional structural information. > > > > ~~~ > > Following on from this, I've been working on a string format for each of > > these three types. Currently we have numerous incompatible ways of > > memo-izing OIDs: the XML object store does it one way, the NOSQL object > > store another, the SQL OS object store another, the "*Mapping" classes > for > > the scimpi and HTML viewers (for storing the states of transient objects > in > > the Http session) in another, the Memento utility class in yet another, > the > > JSON viewer (in its URLs) yet another. It's all very complex and messy. > > > > Having a standard canonical string form would therefore simplify things > > enormously. > > > > I've just been writing the unit tests for this, and I've come up with the > > following: > > > > CUS:123 - persistent root > > !CUS:123 - transient root > > CUS:123#items - collection of persistent root > > !CUS:123#items - collection of transient root > > CUS:123#NME:2 - aggregated object within persistent root > > !CUS:123~NME:2 - aggregated object within transient root > > CUS:123~NME:2~CTY:LON - aggregated object within aggregated > object > > within root > > CUS:123~NME:2#items - collection of an aggregated object within > > root > > CUS:123~NME:2~CTY:LON#streets - collection of an aggregated object within > > aggregated object within root > > > > I've pasted in the unit tests for this below, so you can see the tests in > > all its glory. > > > > Note how this allows for aggregates to be embedded within aggregates > (even > > though I'm not sure that any of the object stores could handle this yet). > > > > OK, that's it for now. Wanted to put this out there for reaction; as > usual > > with these things, I'll assume silence = consensus. > > > > Dan > > ~~~~~~ > > > > > > package org.apache.isis.core.metamodel.adapter.oid; > > > > import
