News and Notes from the Makers of Nexus | Sonatype Blog

A Tour of the Nexus Repository Internals

Written by Tamas Cservenak | March 15, 2009

As part of the Nexus 1.3 release we revamped internals which makes for some interesting feature possibilities. Let's take a look at what's now available in the Nexus system.

## How the repository system works in Nexus

Nexus 1.3 can now consistently handle all repository types (hosted, proxy, group, virtual) in the same way. We made changes to the repository model to handle all future Core and 3rd party Repository implementations by creating an API that will allow us to support alternative repository formats (p2, GEM, RPM) in a common way. Here, I will show you how to detect what sort of Live Repository instance you are dealing with.

Live Repository instances can describe their capabilities. They do it in future proof way, but let me explain few concepts first.

All repository objects are handled in the Nexus Proxy Core in same way. But, you are able to extend Nexus even by adding your new Repository interface implementation, and it will be still usable: you will be able to create instances of your repository using the same UI, and Core will handle those repositories in transparent way.

A Repository in Nexus has two orthogonal properties: ContentClass and RepositoryKind (naming was always my weakness, ask Brian!).

ContentClass describes the content of the repository. For you Maven users, it could be understood a layout in Maven World. Content classes supported in the core are: maven1, maven2. But, nothing stops you from adding new content classes, like P2, eclipse-update-site, etc. One key method exists on ContentClass:

public interface ContentClass
{
    String getId();

    boolean isCompatible( ContentClass contentClass );
}

As you can see, a content class can say it's "compatible" with another content class. The reasoning for this is simple: you could have two **different** Java implementations for Maven2 Repositories for example. Both of them would hold Maven2 repositories with the standard maven2 layout, but they would be completely different implementations! Even then, you want to be able to group them together, right? So, they must have "compatible" content classes. The grouping is the most obvious operation that relies on ContentClass, but they are important in other places too, like virtual repositories. A virtual repository expects a ContentClass C1 as master repository, and "emits" a ContentClass C2. It does not have any expectations the class should only implement the Repository interface! It is simply a "conversion" between the C1 and C2 content classes.

The RepositoryKind is more a programmatic reflection. The RepositoryKind is for runtime inspection of live Repository instances.

public interface RepositoryKind
{
    Class getMainFacet();

    boolean isFacetAvailable( Class f );
}

Since Nexus 1.3 handles **all** repositories in same way there are no longer any difference in API to get at groups, virtuals, or hosted repositories. They are all unified. But how do you make the distinction then between a group and a hosted repo? Or how to discover is a Repository instance reference is a ProxyRepository? Simple: just ask the repository, and it will tell you.

repository.isFacetAvailable( GroupRepository.class );

And what about programmatic reflection? Well, there is one big exception: the DefaultRepository class. Despite it's name, it is an abstract class, and serves as common ground for all simple repository implementations (those are the hosted and proxy repositories with potentially different content classes. Core contains only Maven2 repositories, but that will change soon). For that reason, this implementation is like a chameleon: when set up to be a proxy repository, it will be proxy repository even if the Java implementation does implement the ProxyRepository interface (hence, the plain Java reflection would lie to you)!

repository.getRepositoryKind().isFacetAvailable( ProxyRepository.class) will be TRUE if proxy
repository.getRepositoryKind().isFacetAvailable( HostedRepository.class) will be TRUE if hosted
repository.getRepositoryKind().isFacetAvailable( GroupRepository.class ) will be always FALSE
...

What's the reason for doing these acrobatics? Well, if you look at the sources, the hosted repository implementation is 100% contained in the "proxy" repository (the proxy does a little bit more when doing retrieve, that's all).

And finally, when you find out what kind of repository instance you have, what should you do then? Simple:

if ( repository.getRepositoryKind().isFacetAvailable( ProxyRepository.class) )
{
    ProxyRepository p = repository.adapt( ProxyRepository.class );
}

Actually, you can adapt and the result will be null if not adaptable.

So, as you see, currently the only implementation that uses the runtime adaptable RepositoryKind is the DefaultRepository class, which is actually the base class for simple repositories. **Simple repositories are hosted and proxy types. Those two kinds of repositories are only ones that have actual content. The composite repositories, like group, and virtual have no content. Groups are just an aggregated view of member repositories, while virtual is a handful of links pointing to the master repository.**

And finally, after having this slightly complex taxonomy, it is not the end. Nexus is extensible regarding Repository implementation. Just watch us in the future!

## The repository type registry

Yes, having all capabilities stated above available at runtime is nice, but how do you detect the available _types_ of Repositories in Nexus? And also make that too future proof? Here comes the RepositoryTypeRegistry to make picture complete. Just like RepositoryRegistry says in its name it is a registry for live repository instances, offering various handy methods to get a hold of them. The RepositoryTypeRegistry here does the same, but for type discovery (think about new Repository types contributed by a Nexus Plugin).

The RepositoryTypeRegistry offers some basic methods to discover **all** available Repository implementations that are available to Nexus.

Actually, it is already used in Nexus. Nexus Pro already has P2 repository support. And you know what? Just throw in the P2 Nexus Plugin to existing Pro instance, and your drop down menus of the **same** UI elements you had before will get populated with new values. The **same** dialogs, like Repository Edit, Add New Repository, etc... will be used in the **same** UI to manage that new, plugin contributed Repository implementation. Neato! An entirely pluggable repository management system!

## What other repository features are there?

We're just scratching the surface here but we'll explain a couple more prominent features. Nexus supports links (a la Linux symlinks) which let you do exactly the same things you are able to do on Linux file systems. Actually, the Maven1-to-Maven2 and Maven2-to-Maven1 virtual repositories are exactly built using solely links. Links do not have any content hence, no content duplication, as we promised. Naturally, when accessing Nexus over it's Proxy API, you can use links even in your everyday repositories.

Another feature introduced is what we call a dynamic file. Let's say, you want to make a file accessible somewhere in your repository. But, instead of using Nexus simply for storage and have the file updated every time it's content changes, you want to make it's content dynamic: to have its content pulled from somewhere else, from any underlying source you want.

Using dynamic files, you can decorate your repositories (and groups and shadows) any way you like. All you need to do is provide the component that will create the needed content, point it at the dynamic file, and simply store it just like you would with any other file in Nexus.

## Oi! And what about Maven Archetypes?

A new OSS Nexus plugin is available called the nexus-archetype-plugin. The plugin is documented on the [wiki][1].

In short, the Nexus Archetype Plugin will examine the content of your repositories, find all your Archetypes and an publish Archetype catalog on-the-fly. Yes, on-the-fly, so just deploy an archetype to your hosted repository, and it will be available in catalog right away.

Moreover, the plugin will automatically **aggregate the catalog** all the catalogs so you can have a repository group with a number of hosted repositories which contain Archetypes and they will all be available from what appears to be a single catalog available at the group URL. This uses the dynamic file capability in Nexus, very cool!

[![][2]][3]

[![][4]][5]

Have fun!

[1]: https://docs.sonatype.com/display/NX/Nexus+Archetype+Plugin
[2]: http://blogs.sonatype.com/people/wp-content/uploads/2009/01/picture-31-300x68.png
[3]: http://blogs.sonatype.com/people/wp-content/uploads/2009/01/picture-31.png
[4]: http://blogs.sonatype.com/people/wp-content/uploads/2009/01/picture-4-300x78.png
[5]: http://blogs.sonatype.com/people/wp-content/uploads/2009/01/picture-4.png