Skip to content
John Casey edited this page Aug 20, 2013 · 4 revisions

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.

AProx's REST interface is "skinned" by a Javascript UI by default, which is actually written using CoffeeScript, jQuery, and a library called 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.

##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

##Anatomy of a WAR

When an AProx WAR is built, something strange happens. Instead of using the normal Maven WAR plugin, AProx WAR builds actually use the Maven Assembly plugin to approximate what the WAR plugin does. Does this seem insane?

Unfortunately, the way CDI 1.0 works, 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.

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 WAR using CDI was to combine the add-ons, backend, and core into a single classpath location and configure it with a single beans.xml. I chose to grab all of the org.commonjava.*:* dependencies for my WAR and unzip them into WEB-INF/classes to enable this. 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).

I was okay with this until CDI 1.1 has a chance to fix it properly.

Clone this wiki locally