Hi everyone, As I'm sure you've noticed, I've been doing a lot of work on 2.0, and so its time I took a break and explained some of the key changes, why I've made them, and what the current status is.
Project structure ============ I've broken the project down into a number of components, all built as Maven modules. So the server is now a component in its own right, as well as the parser and connector. I've replaced all of our Ant and Ivy scripting with Maven for all the Java components, but widgets are still built and deployed using Ant from within their own subproject. The server can run for development using Cargo, which deploys it using Tomcat. Back when Wookie joined ASF I was initially not so keen on using Maven, but the experience of using it in Apache Rave has been useful in seeing how it can, if used appropriately, make a project easier to understand and extend, and other community members have commented before about the Wookie project structure being non-standard and therefore harder to get started with. So hopefully this change will make it easier for everyone to work with Wookie and to contribute new modules. So how does the project now look? Well, inside wookie-project, the various sub-modules look like this: wookie-services is where the service integration lives. The core API is in the wookie-spi submodule (more on this below) and there are also the wookie-redis and wookie-jpa implementations. wookie-features is where the runtime features live, so all the injected JS packages are here. wookie-parser is the W3C parser Jar wookie-widgets is where the widgets and templating system lives (thought maybe templates needs its own module) wookie-server is the actual server itself. wookie-connector is the connector framework There is also the wookie-master module at the top level of our svn which is where common metadata is stored for all modules, such as committer names etc. The pom.xml in wookie-project lists which modules are built, so if you create a new one, you can add it to the list. You can build and run Wookie by following the instructions in BUILDING. SPI === I've broken out the repository management from the server into an SPI (service provider interface) package. This means that how Wookie stores user preferences, shared data and participants - and even the widget metadata - can be determined at runtime using dependency injection. The injection mechanism I've put in place is the JDK built-in service loader, which doesn't have a lot of features but does have the benefit of being both simple and not requiring any other dependencies. For example, if you create a module that implements the Preferences SPI, you put the class name of your implementation in a single-line text file at: wookie-server/src/main/resources/META-INF/services/org.apache.wookie.services.PreferencesService … and as long as its on the classpath when the server starts, Wookie will use it. The default implementations of the SPI are very simple in-memory hash tables and tree models, so Wookie can run without any database at all for simple testing. I've also created a Redis NoSQL SPI provider, and started porting the JPA code to work as an SPI provider (it doesn't work yet, as there is a lot to untangle). Other options could be an Apache Rave SPI, for example, or modules for MongoDB or cloud storage using AWS. If you want to have a go at creating another SPI provider, take a look at the Redis one as an example as its fairly simple. AuthToken ======== The concept of "WidgetInstance" has been replaced with that of an "AuthToken". This is an encrypted token based on the same concept (and some of the same code) used in Shindig for its security token implementation, and can convey the same information needed to contextualize a widget for a user and link it with stored preferences etc. The tokens have an expiry time built in, so connectors will need to periodically refresh tokens; this will need thinking through as to what are good practices here that won't impact usability. The main effect of AuthToken implementation is there is now no need to store "WidgetInstance" information, greatly simplifying the server back end. HMAC-Signed REST API methods =========================== In Wookie 1.0 we used an API key for REST calls, assuming that the connection itself should always be secured (e.g. using HTTPS, or not exposed outside an intranet). However in Wookie 2.0 I've implemented HMAC signatures on methods, based on the approach used for Amazon Web Services. This means that API messages are given a nonce, timestamped, and signed with a shared secret that is never transmitted across the network. The upshot of all this is that it is much more difficult to gain access to API calls even when made over the open web on an unencrypted connection. It also means that in Wookie 2.0, if a secret is compromised for any reason, then it can be revoked and changed without needing to change any of the stored data - something that is quite tricky in Wookie 1.0. This does require more work on the connector side to correctly sign messages, but I've implemented it in both Java and JavaScript successfully, and the code for other languages such as Python, PHP and Ruby looks like it could follow the examples given for connecting to AWS. If you have a look inside the implementing classes in the Java connector and in wookie-server you should be able to figure out what's needed, but I'll also write up a proper spec at some point. What's next? ========== The things I've listed above are primarily changes to the underlying structure of Wookie, and don't really impact the user much. However it should provide a basis for other improvements. For example, for some time we've also wanted to move away from DWR to a framework with better support for WebSockets and other new web technologies such as WebRTC, or perhaps use JSR-356. I've finished my "refactoring sprint" for now so there should be no more major changes going in, so feel free to check out the 2.0 code in trunk and start working with it. If anything doesn't make sense, just ask. Have fun! -S
PGP.sig
Description: This is a digitally signed message part
