Fork me on GitHub

Rio provides the ability to deploy and provision service artifacts and their dependencies. The resolution of artifacts is done from configured repositories, and becomes a natural extension of the build, test and deploy lifecycle.

As Rio deploys services, service artifacts and dependencies are automatically provisioned and installed on compute resources that meet declared requirements of services being deployed.

Rio addresses the issue of duplicating dependency management configuration between the development and deployment phases by ensuring that the versioned components that have been used in development, test and qualification are seamlessly carried over.


The Rio Resolver currently resolves artifacts using configured Maven 2 repositories. Using the declaration(s) found in Resolver configuration, and Maven POMs and settings. The Rio Resolver is implemented using Aether, and the Rio Resolver simply uses Maven repositories to obtain declared artifacts and dependencies.

The Resolver configuration by default is in ${rio.home}/config/resolverConfig.groovy directory. This file is used to configure the SettableResolver, defining the resolver jar file as well as the remote Maven repositories and any flatDir repositories that the resolver will use.

resolver {
    jar = "${rioHome()}/lib/resolver/resolver-aether-${RioVersion.VERSION}.jar"

    repositories {
        remote = ["rio"    : "",
                  "central": ""]

        flatDirs = [new File(rioHome(), "lib-dl"),
                    new File(rioHome(), "config/poms"),
                    new File(rioHome(), "lib")]

def rioHome() {
    return System.getProperty("rio.home")

The resolver configuration above shows the jar file to use, as well as the repositories to use. The order in which these repositories are listed is the order in which they will be searched. If you have configured repositories into your ~/.m2/settings.xml, those repositories will be appended to the repositories listed in the resolverConfig.groovy file.

You can override the location of the resolverConfig.groovy file by using the org.rioproject.resolver.config system property. You can also override the location of the resolver jar file by using the org.rioproject.resolver.jar system property.

The Rio Resolver abstracts the underlying dependency resolution implementation in order to give the flexibility to potentially support other repository based dependency management approaches. In the future we may seek to provide support for Ivy or the OSGi Bundle Repository. Providing an abstraction on top of the concrete dependency management solutions gives us flexibility going forward.

Artifact URL

Rio provides a custom artifact: protocol to use as a codebase annotation for services. The artifact: provides a way to resolve an artifact's dependencies when used as a codebase annotation. It provides an easy and efficient way to configure services in a versioned and easy-to-deploy way.

This allows classpath dependencies of the artifact resolved (direct and transitive dependencies) as the codebase for a service, or a service user interface. So your 'depends on graph' is complete, in as much as your dependency graph is correctly constructed for your artifact. This comes naturally for maven/gradle projects, you can't produce your artifact unless the dependencies have been declared correctly.

Note that this becomes important especially for a client that uses a service. With the artifact: URL scheme, instead of annotating a service's codebase with http:// based jars, the service's codebase contains the artifact URL, which (when resolved) resolves the dependencies for the service's codebase at the client. This not only presents a performance boost (why load classes over http if they can be loaded locally), but also addresses lost codebase issues. Add to that secure repository connections that require uid/password, and you can confirm that the artifact a service requires you download in order for you to use that service, comes from a site you trust.

Of course this is all versioned, and once loaded over the wire never needs to be loaded again. If the service's version changes, it's artifact changes, and any jars that have not been resolved get resolved.

The URL scheme for this handler is:


Here are some examples:

  • An artifact URL for groupId, artifactId and version
  • An artifact URL for groupId, artifactId, version and repository with an id

Once an artifact has been resolved to a URL, the artifact:URL pair is cached, avoiding future interactions with the underlying Resolver

Artifact Declaration

Artifacts are referenced in abstract terms (groupId:artifactId[:type[:classifier]]:version), rather than a (logical) file path. This is the big difference with the use of artifacts in opstrings with Rio. Previously, you declared jars as resources for both the interface and service implementation classes. With the introduction of artifact declaration in opstrings, you now just declare the groupId:artifactId[:type[:classifier]]:version instead.

The benefits here are that the declared artifact, it's dependencies and any transitive dependencies are resolved. If the machine the Monitor or Cybernode is executing on does not have the required jars available, they will be provisioned. Its that simple.

Declaring artifacts in opstrings follows the same conventions that Maven uses. Take a look at the example below:

The keyword artifact in the DSL (or Artifact in an XML document) triggers artifact resolution. You cannot have both artifact resolution and resource declarations in the same opstring.

You can also include other opstrings using an artifact. This allows external services to be included in the activation of your application.

The included artifact is resolved from configured repositories. The artifact must have a .oar extension. Once located, the resolved OAR is included in the deployment and subsequent management of the declared service(s).

Artifact URL

Artifact Resolution

Artifacts and dependencies are resolved from repositories. The Rio resolver obtains repository configuration from the resolverConfig.groovy file, from POMs and from your settings.xml. When service artifacts are being resolved, repository configurations are lazily obtained, appending configured repository definitions from POMs (if declared), and filtering them against any declared mirror declarations insettings.xml. Maven central is always included last.

It is generally a good idea that the <repositories> section be removed from POMs, and repositories be specified only in either resolverConfig.groovy or in settings.xml. This makes for cleaner and predictable deployments.

By translating groupId:artifactId:[classifier:]version to groupId/artifactId/version we can derive the location of the artifact and download it to the (configured) local repository. If there are issues with the message digests not matching, the retrieval of the artifact is retried. If there are still issues with the message digests not matching, the Rio Resolver will not provision the artifact. In Maven terms, this follows a checksumPolicy set tofail.

We highly recommend the use of a repository manager.

Automatic Dependency Exclusions

Dependency scope is used to limit the transitivity of a dependency, and also to affect the resolved classpath for a service. The following scopes are automatically excluded:
  • test
    This scope indicates that the dependency is not required for normal use of the application, and is only available for the test compilation and execution phases.
  • provided
    Indicates you expect the dependency to be provided at runtime.
  • system
    Indicates you have to provide the dependency. The artifact is always available and is not looked up in a repository.
  • optional
    Although not a dependencyscope, dependencies declared as optional are automatically excluded.

Back to top

Version: 5.6.6. Last Published: 2018-10-25.