Aluminium Platform Upgrade

This document describes the steps to help users upgrade from Magnesium to the Aluminium planned platform. Refer to Managed Release Integrated (MRI) project upgrade patches for more information.

Preparation

JDK 11 Version

Aluminium requires Java 11, both during compile-time and run-time. Make sure to install JDK 11 corresponding to at least openjdk-11.0.6, and that the JAVA_HOME environment variable points to the JDK directory. This variable is now particularly needed to perform the Javadoc generation. You may still build your project without it by using maven with the option “-Dmaven.javadoc.skip”.

Controller is a MRI project

Unlike in previous releases, the Controller project has joined the MRI family at the start of Aluminium Simultaneous Release cycle. Going forward it is an error to depend on any org.opendaylight.controller with a -SNAPSHOT version.

Version Bump

Before performing platform upgrade, do the following to bump the odlparent versions (for example, bump-odl-version):

  1. Update the odlparent version from 6.0.4 to 7.0.3. There should not be any reference to org.opendaylight.odlparent, except for 7.0.3. This includes custom feature.xml templates (src/main/feature/feature.xml), the version range there should be “[7,8)” instead of “[6,7)”, “[5.0.3,6)” or any other variation.

bump-odl-version odlparent 6.0.4 7.0.3
  1. Update the direct yangtools version references from 4.0.6 to 5.0.3, There should not be any reference to org.opendaylight.yangtools, except for 5.0.3. This includes custom feature.xml templates (src/main/feature/feature.xml), the version range there should be “[5,6)” instead of “[4,5)”.

  2. Update the MD-SAL version from 5.0.9 to 6.0.2. There should not be any reference to org.opendaylight.mdsal, except for 6.0.2.

rpl -R 5.0.9 6.0.2
  1. Update the Controller version from 1.11.0 to 2.0.2. There should not be any reference to org.opendaylight.controller, except for 2.0.2.

rpl -R 1.11.0 2.0.2

Current Aluminium stable and development versions usable for dependencies can be found at this page.

Install Dependent Projects

Before performing platform upgrade, users must also install any dependent project. To locally install a dependent project, pull and install the respective magnesium-mri changes for any dependent project.

Perform the following steps to save time when locally installing any dependent project:

  • For quick install:

mvn -Pq clean install
  • If previously installed, go offline and/or use the no-snapshot-update option.

mvn -Pq -o -nsu clean install

Upgrade the ODL Parent

The following sub-section describes how to upgrade to the ODL Parent version 4. Refer to the ODL Parent Release Notes for more information.

Features

Any version range referencing version 6 of ODL Parent must be changed to “[7,8)” for ODL Parent 7.

<feature name="odl-infrautils-caches">
    <feature version="[7,8)">odl-guava</feature>
</feature>

ODL Parent Impacts

OSGi Compendium dependency

ODL Parent no longer declares the old OSGi Release 5 org.osgi.compendium artifact. Please migrate to the correct Release 6 artifact.

<dependency>
    <groupId>org.osgi</groupId>
   <artifactId>osgi.cmpn</artifactId>
</dependency>

JAXB dependencies

ODL Parent no longer declares javax.xml.bind dependencies and provides replacement declarations from the Jakarta project.

<dependency>
    <groupId>jakarta.xml.bind</groupId>
   <artifactId>jakarta.xml.bind-api</artifactId>
</dependency>

Jackson feature name

The name of the Jackson feature changed to reflect the upgrade to version 2.10. The new name is odl-jackson-2.10.

YANG Tools Impacts

YANG parser validates XPath expressions

In an ongoing effort to improve our feature-completeness, YANG parser now requires a XPath parsing library and will perform a validation of syntactic well-formedness of every XPath expression encountered in YANG models – most notably when and must statement arguments are covered. Accepted syntax is strictly compliant with RFC7950.

This also extends to path statement arguments, as encountered in type leafref constructs. Unlike most parsers out there, YANG Tools does not allow any XPath expression to be used in this context, but rather follows strict definition in RFC7950, augmented to deal with the change proposed in Errata 5617. This should cover even the non-RFC7950-compliant models coming from various standards bodies, but it is certainly possible that a previously-accepted model will be rejected by the parser. If that happens, the chances are that the model itself is invalid. Please consult RFC7950 and the model author before filling an issue with YANG Tools JIRA.

SchemaContext is being retired

After many years of development and incremental updates, this release marks the start of the transition away from SchemaContext. The object model exposed by it is problematic in more ways than one. The replacement construct is EffectiveModelContext, which operates on EffectiveStatement and its related interfaces. EffectiveModelContext retains its SchemaContext trait for the duration of the transition and can be directly used in that capacity. Users are encouraged to update their interfaces to accept and give out EffectiveModelContext instances.

Restricted YANG parser internals

A number of internal classes now requires a proper service injection of their dependencies. This step is taken so that we can clearly separate API contract from implementation details.

The primary interface to YANG parser is YangParserFactory, which is available as an OSGi service, as well as being exposed to Guice and ServiceLoader injection mechanisms.

Single-classloader environments (such as JUnit-based unit tests) are not directly impacted by this change, as instantiation paths which are not provided with an instance of YangParserFactory end up falling back to ServiceLoader-based lookup.

This fallback mechanism does not extend to OSGi and other multi-classloader environments and therefore users need to acquire a YangParserFactory service from the OSGi service registry and pass it to other YANG tools functional blocks as appropriate.

These access restrictions will be extended to all environments in a future major version with the use of JPMS.

SchemaNode methods use collections with covariance

A number of methods which use to return invariant Sets, such as this:

interface SchemaContext {
  Set<Module> getModules();
}

now use Collection with covariance, such as:

interface SchemaContext {
  Collection<? extends Module> getModules();
}

For most cases this is not a problem, as the returned collection is only ever iterated through, but code that stores the result will need to either update the declaration, or use var type declaration available since Java 10 as part of JEP-286:

final var modules = context.getModules();
final int size = modules.size();

XML and JSON parsers accept only ‘true’ and ‘false’ for booleans

Due to historic implementation reasons, we have accepted various capitalizations of true and false in type boolean leaf values.

This leniency results in incorrect interpretation of constructs such as

leaf foo {
  type union {
    type boolean;
    type string;
  }
}

leading to value being changed when subjected to decode/encode cycle. Both codecs have been adjusted to accept only true and false literals.

Further details about this change can be found in the corresponding YANG Tools issue.

RPCs return codes slight evolution

There can be minor changes in the return codes sent by the RPCs. Most of the time, this concerns HTTP 404 codes “Not found” replaced by HTTP 409 codes “Conflict”. Example here.

MD-SAL Impacts

Binding DTOs and empty lists

Binding DTOs (data transfer objects), both created by a Builder and created dynamically by MD-SAL at runtime no longer discern between null and empty lists of any kind.

For a YANG model like this:

container foo {
  list bar {
    leaf baz {
      type string;
    }
  }
}

setting an empty list like this:

Foo foo = new FooBuilder().setBar(Collections.emptyList()).build();
assertNull(foo.getBar());
assertEquals(List.of(), foo.nonnullBar());

is completely equivalent to omitting the setter altogether:

Foo foo = new FooBuilder().build();
assertNull(foo.getBar());
assertEquals(List.of(), foo.nonnullBar());

The check for size is generally performed at the time build() is called, so if the collection is mutable and filled between the time the setBar() and build() is called, list items will be reflected in the built object. There is an exception to this lifecycle, explained in the next section. For further details see the MD-SAL issue.

YANG lists with key and system ordering result in Map

Type mapping of simple keyed lists has changed to better reflect their nature. Previously a YANG declaration

container foo {
  list bar {
    key baz;
    leaf baz {
      type string;
    }
  }
}

would result in

interface Foo {
  // regular getter
  @Nullable List<Bar> getBar();

  // null-to-empty transformation
  @NonNull List<Bar> nonnullBar();
}

In MD-SAL 6.0.x, that YANG snippet will result in

interface Foo {
  // regular getter
  @Nullable Map<BarKey, Bar> getBar();

  // null-to-empty transformation
  @NonNull Map<BarKey, Bar> nonnullBar();
}

This results in major usability improvements around iteration on such fields.

if (foo.getBar() != null) {
  for (Bar bar : foo.getBar()) {
    // ...
  }
}

becomes easier to read and slightly more efficient

for (Bar bar : foo.nonnullBar().values()) {
  // ...
}

If that iteration is searching for an object with specified key, as is quite common, the construct can be as simple as

// already known
BarKey key;
// efficient lookup in a Map, result is nullable as usual
Bar bar = foo.nonnullBar().get(key);

For compatibility purposes, the associated Builder class will look something like this:

class FooBuilder implements Builder<Foo> {
  // Regular setter
  FooBuilder setBar(Map<BarKey, Bar> value);

  // Legacy backwards compatibility setter
  @Deprecated(forRemoval = true)
  FooBuilder setBar(List<Bar> value) {
    return setBar(value == null ? null : Maps.uniqueIndex(value, Bar::key));
  }
}

This provides a smooth upgrade path for most users, while at the same time flagging all code relying on legacy setter in a very clear way. Also note that due to the eager nature of translation, the emptiness of the List passed to the legacy setter is evaluated during the setter’s invocation, rather than during the invocation of build().

Lists which do not have a key, or have an ordered-by user statement are not subject to this change and continue to behave just as they did.

Further details about this change can be found in the corresponding MD-SAL issue.

Removed packaging of draft models

Three sets of models from long-expired drafts have been removed. Each of these has at most one downstream user project in current Simultaneous Release and hence it is more appropriate to maintain these models in those projects. The models removed are:

Binding/DOM codec implementation is now isolated

The API contract of mdsal-binding-dom-codec has been split into a separate artifact and therefore codec internals are no longer available for direct use in OSGi. Users are advised to use proper injection of org.opendaylight.mdsal.binding.dom.codec.api interfaces available in the OSGi service registry.

This means that if you are using in your java code an import of a class in org.opendaylight.mdsal.binding.dom.codec.impl , Karaf will not properly work at run-time. So if you are still using this API contract for JSON or XML parsing, it is probably a good idea to now use the OSGi bindingDOMCodecServices as declared in the blueprint here.

This is a first step towards isolating API contract from implementation details. This isolation will be further extended to all environments through the use of JPMS in a future major release.

Since this only concerns OSGi, this API contract can still (and even maybe must) be used in Junit tests. In that case, some adaptations will be needed and is probably worth switching from SchemaContext to EffectiveModelContext at the same time, such as in the example here.

WriteOperations.put(…, boolean) and WriteOperations.merge(…, boolean) removed

These two methods have multiplexed two distinct operations. When the boolean is specified as true, they would end up issuing another merge operation. As such they have been deprecated in Magnesium and are now being removed.

WriteTransaction wtx;
wtx.merge(store, path, data, true);
wtx.put(store, path, data, true);

becomes

WriteTransaction wtx;
wtx.mergeParentStructureMerge(store, path, data);
wtx.mergeParentStructurePut(store, path, data);

The longer name reflects the fact that this operation is much more heavy-weight, as well as unnecessary in most situations.

Controller Impacts

Artifacts are advertised through controller-artifacts

All public artifacts produced by the controller project are declared in a single artifacts pom:

<dependency>
  <groupId>org.opendaylight.controller</groupId>
  <artifactId>controller-artifacts</artifactId>
  <version>2.0.1</version>
</dependency>

This pom combines the roles previously filled by mdsal-artifacts, config-artifacts and a few others.

Blueprint’s routed-rpc stanza has been removed

The BluePrint extension for creating a blanket routed RPC registrations has been removed. This extension did not work correctly for a couple of years now and the interface exposed by this stanza was deprecated for just as long.

This release removes support for this stanza. Users are advised to migrate to explicit point-registrations available in MD-SAL APIs.

Use of odl:type in Blueprint is discouraged

This property has been used for discerning between various implementations of MD-SAL services present in the OSGi service registry. As these services have been consolidated in the past couple of releases, the use of this qualifier is desupported and discouraged. While some services are advertized with this property set, it is no longer considered a binding contract and future releases will most likely stop adding this property in a future minor release.

Users are advised to stop specifying this attribute when making references to OSGi services, see example here.