4 posts tagged “cosmo”
When I originally implemented support for subscriptions and preferences in Cosmo's Atom subsystem, I represented their info in sort of strange ways. Subscription entries had a couple of extension elements that specified the sub's collection UUID and ticket key, the entry's title was the sub's display name, and the entry had no content (which isn't technically legal). Preference entries used the title element to specify the preference key and included the preference value as text content. The representation styles weren't symmetrical with each other nor with that for items (which are completely represented by an external format like JSON or EIMML and included wholly in the entry's content element). The client programmer had to learn all these different styles, which is confusing and sucky, and write different framework code for each. Even worse, by not treating subs and prefs as media, we couldn't do things like POSTing and PUTting subs and prefs directly into their collections or GETting them directly out of their collections without wrapping them in Atom entries.
Let's take a step back and think about why we're actually using APP in Cosmo. APP is basically a set of rules layered on top of basic REST principles for allowing the server to create, update and delete resources. When the client wants to create or update a resource with APP, it encloses a representation of the resource inside an Atom entry document. The idea with most APP implementations is that the entry meta-data will actually be useful in some way. But for Cosmo items, subscriptions and preferences, it tends not to be. These resources don't have client-modifiable attributes that correspond to Atom entry data like id, owner, updated. So, modeling them as media resources makes a lot of sense. This is almost like not using APP at all, except for the fact that Cosmo follows the general rules for control and publishing (sections 4.3 and most of 5) and provides service documents (section 5.1), which I think are the two most important parts of the document. This means that Cosmo clients can be written with standard Atom and APP libraries rather than built on top of lower level HTTP libraries.
We do care about Atom entry (and feed) documents when the server is sending data to the client (because the documents include the links to related resources that provide the property of the Resource-Oriented Architecture that RESTful Web Services calls "interconnectedness") but not so much when the client sends data to the server. This means we should probably come up with self-contained representations for subscriptions and preferences that don't piggyback on top of Atom entries (but can be reasonably included as entry content for clients that, say, don't support sending media resources).
XHTML + microformats is an increasingly popular way to represent resources these days. It's easy to parse and generate XHTML in basically any client and server software, and the grammar is already known, so we don't have to come up with a new one and write validators for it. Microformats.org lists a number of best practices for defining microformats, including describing them with XMDP (which itself is just an XHTML microformat).
This week I checked in code that uses XHTML and custom microformats to represents subscriptions and preferences. Profiles and examples can be found at http://chandlerproject.org/Projects/CosmoMicroformats (the profile documents aren't available yet at their permanent non-wiki locations, but they will be shortly). I'd like to come up with examples that display more pleasantly in browsers, but the ones that are there now are perfectly useful. This is my first attempt at defining microformats, and I can't claim any mastery of semantic HTML, so it may well be that there are better element choices than span and div. Feedback is welcome.
Over the last several months I've designed and implemented two HTTP-based protocols for accessing Cosmo: an end user-oriented "feed service" for managing your collections of content items, subscriptions to other people's collections, and your user preferences; and Morse Code, a batch protocol used by Chandler desktop to synchronize entire collections across multiple clients.
When I started working on these protocols eight months ago, I wasn't very familiar with the concept of REST. I'd heard the term kicked around, and I'd read enough about it to know that it was a different architectural style than RPC, but I couldn't articulate the differences intelligibly and wouldn't have been able to tell you why I'd prefer a REST architecture for Cosmo. Still, enough had creeped into my subconscious that I was able to sense some of the deficiencies of RPC that we'd found and drive myself towards REST in the design of the new protocols.
For example, the calendar part of our web UI used JSON-RPC to talk the server, and that presented some clear architectural challenges. The name of the RPC operation and its parameters (including the object to call the remote method on), and sometimes the authentication credentials, were hidden inside the JSON payload in the HTTP request, so the servlet filter responsible for authenticating protocol requests and authorizing them to operate on their targets could not find the information it needed to do its job without processing the request body, a responsibility of the JSON-RPC servlet which isn't executed until after the filter has been invoked. In some circumstances, we had to pass credentials as parameters of the RPC operation and process them manually, bypassing our standard filter-based security choke point and adding explicit awareness of security concerns to additional layers.
By contrast, the resource-oriented Cosmo Management Protocol (an older, HTTP+POX version of the feed service designed for user management and other system administration tasks) uses Basic authentication, maps the HTTP method to the operation to perform on the server, and addresses the resource on which the operation is performed by URI only. This allows the security filter to step in and make decisions about authentication (extracting the credentials from the Authorization header and validating them) and authorization (determining the operation and the resource being operated on and evaluating access control rules) without ever having to process or even peek into the request body. A different software layer (the CMP servlet) is responsible for translating the POX request body into a representation of the resource and updating the resource's state. Acegi Security is usable right out of the box with just some declarative configuration; there are no compilation dependencies between the security and processing layers, whereas our JSON-RPC-based stuff had to use Acegi Security APIs explicitly in order to manually authenticate and authorize the RPC operations.
Another benefit is the individual addressing of CMP resources. This lets the server apply security rules based on a resource's URI - for example, requests to /admin/user/** are only accessible by administrative users, but any old authenticated user can access /account/view to see a web page with is account details, and any unauthenticated user can pull up /account/signup to get a web page that lets them sign up for an account. With the JSON-RPC setup, all requests were POSTed to a single URI, so there was no opportunity to use it to discriminate between security rules. Had we used JSON-RPC for any part of our web Ui other than the personal calendar interface, the RPC implementation layer would have had to manually select and evaluate security rules based on the RPC method call.
I didn't realize any of this at the time that I designed CMP a couple of years ago; like a naive teenager, I just did what felt natural. We wanted a network protocol that administrators could easily script, and I figured using HTTP's built-in verb set would make it easy to script tasks with Perl+LWP or curl. When Bobby proposed JSON-RPC for the Ajax calendar UI, I didn't see anything wrong with it. Neither of us knew any better. We figured hey, there's a Javascript library for it, so let's get something working and move on from there. The problems only became obvious over time, but of course by then we were fairly well invested in the existing JSON-RPC implementation and had to wait for a suitable point in our development schedule before we could consider a wholesale replacement. And that's where the feed service I mentioned above comes in.
I'll talk more about the feed service in subsequent posts and discuss topics that will have you on the edge of your seat like: the difference between the feed as a general purpose data representation and the feed meant to be consumed by a feed reader, the joys of synchronization over HTTP, the folly of inventing your own XML dialect when an existing one will do, how to build an Atom-based web service with Abdera, how I beergoggled GData but saved myself from having to gnaw my arm off the next morning, and how reading Leonard Richardson and Sam Ruby's RESTful Web Services could have saved me a big chunk of the 8 months I put into Morse Code and the feed service.
for those of you who care about such things, i'll be talking about Cosmo at ApacheCon in Austin on Oct 13. i'm hoping for the release of Cosmo 0.5 to coincide with the conference, but as we're still planning features, i can't say for sure yet. anyway, should be a good time. i'm looking forward to actually getting to see some of Austin for once, rather than just driving through it on the way between Fredericksburg and the airport.