-
Notifications
You must be signed in to change notification settings - Fork 30
Hacking
The basic architecture of AProx is a core API, a core implementation, and a series of decorator and/or integration-specific libraries. The whole thing is stitched together using CDI, and skinned using Javascript.
##Overview
AProx is fundamentally a RESTful design; it exposes all of its services using REST interfaces and JSON as the wire protocol. Currently, it does NOT support XML as a wire protocol, mainly because getting the XML binding libraries to play nice is not fun, and XML is verbose compared to JSON. We don't really need both.
##Architecture
- CDI used for dependency injection of component instances
- Support for bindings to multiple server technologies. Current implementations:
- JAX-RS (designed/implemented to be deployed on JBoss AS 7 / EAP 6)
- Vert.x (delivered as standalone launcher archives for use via CLI invocation)
- REST with JSON wire protocol (not XML currently)
- Add-ons supported via CDI @Decorator and JEE Event/@Observes APIs
- Default UI is JavaScript (jQuery + Spine.js + AJAX) from the
monorail
project module
##Basic Component Libraries and What They Do
-
/api
- provides interfaces and exceptions that are the core model and services AProx provides. Designed to minimize the interdependency between implementation libraries -
/core
- provides the implementations for data-handling logic and core services of AProx. Does NOT provide a means of storing model information, or authentication of AProx REST services. -
/db/flat
- provides the flat-file database storage driver for use with the core AProx StoreDataManager, whose interface is in/api
and whose default implementation is defined in/core
. -
/filer/default
- provides configuration for Galley, which handles file download and caching. -
/uis/monorail
- provides default UI that talks via AJAX with REST services defined in/core
.
Of course, there are many other modules in the AProx build, but these are responsible for the bulk of the core feature set.
##Add-Ons
Add-ons in AProx are implemented using two basic strategies:
###Decorators
As with the autoprox decorator (/addons/autoprox
), the simplest strategy for decorating the behavior of existing REST services and other components is to use the CDI @Decorator/@Delegate approach. Basically, your class is declared as abstract and implements the interface for the component you wish to decorate. It is annotated with @Decorator at the class level. Then, you @Inject the same interface into your abstract class as a field, adding the @Delegate annotation. At this point, you're free to implement the methods you wish to decorate, and simply call delegate.methodName(..)
wherever you wish to proceed with normal service execution.
See also Weld's documentation on Decorators.
###Events and @Observes
AProx also publishes several different types of JEE Event, for consumption by methods using the @Observes annotation. Simply implement a method using something like this:
public void storeDeleted( @Observes final ProxyManagerDeleteEvent event )
{
// do something interesting in response.
}
AProx currently fires the following events from its core implementation:
- FileStorageEvent - Triggered whenever a file is uploaded to a deploy point or cached in a repository proxy.
- ArtifactStoreUpdateEvent - Triggered whenever an ArtifactStore (Group, Repository, or DeployPoint) is added or updated
- ProxyManagerDeleteEvent - Triggered whenever an ArtifactStore is deleted.
Other add-ons for AProx may trigger their own custom events.
See also Weld's documentation on Events
AProx's REST interface is "skinned" by a Javascript UI by default, the current incarnation of which (called monorail) is actually written using CoffeeScript, jQuery, and Spine.js. The UI is transcoded into Javascript and CSS using an application called Hem, which runs on Node.js. The generated Javascript and CSS is stored in Git (tsk, tsk, don't store computed results, I know), and built into a WAR overlay using Maven during the main AProx build process. The UI WAR overlay is then applied to the basic (and other) WARs.
##Anatomy of the distribution archives (WARs and Launcher tarballs)
AProx's WARs and launcher tarballs are built using a somewhat unusual process. Instead of the normal Maven WAR plugin or Maven Assembly Plugin approach of putting the dependency jars into a specific directory structure as-is, the AProx distributions actually use the Maven Assembly plugin to aggregate all of the org.commonjava*
dependencies together into one jar. Third-party jars still go in the normal library directory structure. This actually necessitates the use of the Assembly plugin in both WAR and launcher-archive builds, in order to get the desired aggregation to work.
Are you insane??
Unfortunately, the way CDI seems to work, selecting an implementation for a component from a range of possible alternatives is only possible within a single jar. Alternatives cannot be supplied by separate jars; it seems the CDI environment doesn't wires up the dependencies in each jar separately from all the rest of the classpath. You can look at the JIRA if you don't believe me. Similarly, it seems there is no "application-level" bean descriptor where you can specify which Alternative should be used when the implementations and consumer components are all within the same dependency jar.
The only way I was able to maintain the flexibility of mixing and matching backends, add-ons, and the core of AProx in a single archive using CDI was to combine the add-ons, backend, and core into a single classpath location in the archive, and configure it with a single beans.xml
specific to that launcher or WAR build. For WARs, I chose to grab all of the org.commonjava.*:*
dependencies and unzip them into WEB-INF/classes to enable this. For launcher archives, these same dependencies are aggregated into a single commonjava-components.jar
. It works reasonably well, as long as you're okay with losing some information about what's in the WAR (it's still available, you just have to go to the POM for the WAR to find it...alternatively, the META-INF/maven/* information should also be available to shed light on the specific contents of the aggregated classes).