With UnitOfWork being eventbased rather than statebased this changes how we should think about the REST integration for client/server read/writes.

I suggest the following: the server has three REST endpoints:
/changes
/entity
/query

See attached image for details. Blue arrows are information flow, red arrows are request direction.

The client starts by calling /entity a number of times in order to read information from the server. This is done using GET.

The UnitOfWork then performs changes on the Entities in the client. These changes are recorded as a series of events, along with all information about what Usecase was performed to trigger it. Example (mock XML format):
<unitofwork usecase="Add new task to project">
  <read id="1234"/>
  <newentity id="5678"/>
  <addentitytype id="5678" type="Task"/>
  <setproperty id="5678" name="description">Do stuff</setproperty>
<addmanyassociation id="1234" name="tasks" index="10">5678</addmanyassociation>
</unitofwork>
---
This would be the base information about this UnitOfWork. Lots of metainfo could be added as well, as custom events.

When the UnitOfWork completes the changes are PUT to /changes. Changes is an Atom feed which supports adding things to it. The reason PUT is used is to be able to re-do the PUT if the request fails. The URL used for the put includes the *id of the UnitOfWork*. This is new! A UoW has its own id, which is either a UUID or the hash of all the changes, or similar. The changes would then be PUT to:
/changes/unitofwork/aG324JWH

If the PUT completes then the changes have been sent successfully. If it fails, then the client can redo it until it completes. Since the client and server has agreed on the identity of the changes the server can reject multiple successful PUT's to the same id.

Once the UnitOfWork has been transactionally stored it can be used for all sorts of things (see later posts for details).

/entity is where you go to get state for a single entity. It does support PUT as well, but with the entire snapshot state rather than changes. One reason it supports PUT is because if all we have is /changes where UoW logs are sent to, then cache proxies in front of /entity will not know when to invalidate their caches. Therefore, when the change messages are processed they should do PUT on /entity to update the snapshots and also to invalidate the proxy caches.

/query is similar to /entity in that it allows clients to read information about the state, but instead of storing information about single entities it store the state in an indexed form, specialized for attribute or relationship querying. This can be done either using RDF, Lucene or Neo4j, depending on what kind of queries you need to do.

Note that in true REST-sense there is NO need whatever for /changes, /entity and /query to be on the same host! It is quite possible, and in clustered deployments very likely, that /changes is on one host and then /entity and /query is on a whole bunch of servers. If we implement consistent hashing that will define where you go for what, and we can also follow the HATEOAS principle (Hypermedia as the Engine of Application State) to allow clients to just follow links to know which host has what service.

If you look at the attached image you can see that the red arrows all go from client to server, but then also from readers to writer. The funny part of this is that if there are no readers then there are also no state snapshots for reading or indexing! Think about this for a moment. I'll get back to it later :-)

Continued in part 4.

_______________________________________________
qi4j-dev mailing list
[email protected]
http://lists.ops4j.org/mailman/listinfo/qi4j-dev

Reply via email to