Dynamic Dependencies

When expanding or harvesting, nsx-prime requires the following resources to function properly:

  1. The elements jars: elements-shared, elements-proxy, elements-io(xml).
  2. The correct expanders
  3. Optionally, additional added expander jars
  4. The webStyles and baseComponents directories

The goal of this article is to find a simple solution for providing these resources during development and during a new release.

Elements resources

The elements jars are generated by building a version of the Prime Radiant. They also have a very distinct dependency with other libraries:

  • the elements version should always be the same or a more recent version than the one the expanders being used are based on
  • the elements version should be up to date with the version of the Prime Radiant

As such, the easiest way of providing the correct version is to package these libraries along with nsx-prime in a single jar. The nsx-prime jar can then be kept up to date with each release.

Expanders jar

The upgrades for the Prime Radiant foresee the ability to use different versions of the expanders.

With this in mind each application instance defines its own expander version. In the current implementation, the Prime Radiant provides the correct expander version through the classpath and the expansion from xml completely ignores the setting.

To rectify this, nsx-prime must find the correct expander jar during execution and dynamically add it to the classpath. The expansion can then be jump-started through an interface defined in a common library, such as elements-shared.

public interface ExpansionRunner {
  void expand(ExpansionParameters parameters);
}

The expanders then implement this interface with an actual expansion runner, which provides a default constructor:

public class FullApplicationExpander implements ExpansionRunner {

  public FullApplicationExpander() {}

  public void expand(ExpansionParameters parameters) {
    //...
  }
}

The expander jar is loaded with a specialized ClassLoader and started through the interface:

Class<?> expansionRunnerClass = expanderClassLoader.loadClass("net.democritus.expander.FullApplicationExpander");
ExpansionRunner expansionRunner = (ExpansionRunner) expansionRunnerClass.newInstance();
expansionRunner.expand(parameters);

The current location of expander jars in the NSF-3.0 structure is under NSF-3.0/repositories/nsfInstaller/expanders/lib. This can be simplified to e.g. NSF-3.0/repositories/nsx/expanders/.

External expanders

External expanders can either be provided through the classpath or dynamically loaded. In case of the latter, nsx-prime should be provided with the knowledge to find the jars.

E.g. lets say we have a jar of expanders expanders-green-1.2.jar. We can define a folder ext in repositories to stash all external jars:

NSF-3.0
    |- repositories
          |- ext
                |- green
                      |- expanders-green-1.2.jar

Allowing for subfolders within the ext folder will make it easier to group external artefacts into different repositories:

NSF-3.0
    |- repositories
          |- ext
                |- green
                |      |- .git
                |      |- expanders-green-1.1.jar
                |      |- expanders-green-1.2.jar
                |- red  
                       |- .git
                       |- expanders-red-1.0.jar

The jar can then be referenced as:

<expanderJars>
  <expanderJar>
    <name>expanders-green</name>
    <version>1.2</version>
    <subFolder>green</subFolder>
  </expanderJar>
</expanderJars>

WebStyles and BaseComponents

The webStyles and baseComponents directories are regularly updated with new features. Currently, new features are patched by copying the files that have changed since the last release. However, this process is error-prone:

  • If not configured correctly, files can be missing.
  • It is never certain that the folder to which the files are copied is in the correct state (that previous upgrades have succeeded)
  • Removing files is likewise never a sure thing.

Alternatively, both resources can be supplied as jar artefacts and extracted before expansion. This ensures that the content is always what we expect it to be.

To manage the different versions of the baseComponents without requiring an update of nsx-prime, the versions should be configured separately:

<resources>
  <resource>
    <name>baseComponents</name>
    <version>2018.12.4</version>
  </resource>
  <resource>
    <name>webStyles</name>
    <version>2018.12.4</version>
  </resource>
</resources>

The jars can be kept in a folder under repositories:

NSF-3.0
    |- repositories
          |- nsx
                |- resources
                      |- baseComponents-2018.12.4.jar
                      |- webStyles-2018.12.4.jar

To avoid extracting the same jar each time the expansion is run, nsx-prime can create a .version file that contains the version of the extracted resource, which can be checked against the configuration to see if an update is necessary.