Jump to: navigation, search

Sodium platform upgrade

This page describes the changes projects need to make in order to upgrade to the planned platform for Sodium.

You can have a look at how others projects did it on https://git.opendaylight.org/gerrit/#/q/topic:sodium-mri.

Preparation

Version bumps

Replace all of your project's odlparent versions from 4.0.9 to 5.0.0 (using e.g. bump-odl-version: "bump-odl-version odlparent 4.0.9 5.0.0"). You should not have any references to org.opendaylight.odlparent.* other than 5.0.0. Note this includes custom feature.xml templates (src/main/feature/feature.xml), the version range there should be "[5,6)" instead of "[4,5)", "[4.0.5,5)" or any variation thereof.

Replace all of your project's direct yangtools version references, if you have any (you may not, as this typically often inherited transitively) from 2.1.8 to 3.0.0. You should not have any references to org.opendaylight.yangtools.* other than 3.0.0. Note this includes custom feature.xml templates (src/main/feature/feature.xml), the version range there should be "[3,4)" instead of "[2.1,3)"

Replace all of your project's mdsal versions from 3.0.6 to 4.0.0 (using e.g. "rpl -R 3.0.6 4.0.0 ."). You should not have any references to org.opendaylight.mdsal* other than 4.0.0.

Locally install dependant projects

You'll have to locally pull and install the respective sodium-mri changes for all of the projects that your project depends on. At the very very least, you'll most likely want controller, aaa and netconf.

Save time when locally installing those dependencies:

  • by using quick install ("mvn -Pq clean install")
  • by going offline and/or just no-snapshot-updates, if you previously installed ("mvn -Pq -o -nsu clean install")

ODL Parent 5 Impacts

Upgrading to ODL Parent 5 will involve the changes detailed in this section.

Fully detailed odlparent Release Notes are here.

Feature changes

You’ll need to change any version range referencing version 4 of ODL Parent to “[5,6)” for ODL Parent 5, e.g.

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

JSR305 (javax.annotation.Nullable and friends)

JSR305 annotations are no longer pulled into your project by default. You have the optional of migrating annotations to JDT (@Nullable et al), Checker Framework (@GuardedBy), SpotBugs (@CheckReturnValue) or simply pulling in the JSR305 dependency into your project by adding:

   <dependency>
     <groupId>com.google.code.findbugs</groupId>
     <artifactId>jsr305</artifactId>
     <optional>true</optional>
   </dependency>

to each pom.xml which uses these annotations.

FindBugs

findbugs-maven-plugin is no longer supported by odlparent. you will need to upgrade to spotbugs by changing:

               <groupId>org.codehaus.mojo</groupId>
               <artifactId>findbugs-maven-plugin</artifactId>

to:

               <groupId>com.github.spotbugs</groupId>
               <artifactId>spotbugs-maven-plugin</artifactId>

JUnit 4.11 and Hamcrest 2.1

If you are declaring dependencies on hamcrest, you need to update the order of junit and hamcrest references to match the required order. Alternatively you can remove the declarations completely, as odlparent provides them (at scope=test).

Powermockito

An unfortunate interaction exists between powermock-2.0.0 and mockito-2.25.0, where the latter requires a newer byte-buddy library. This leads to scary-looking exceptions when powermock tests are run, like this:


   13:15:50 Underlying exception : java.lang.IllegalArgumentException: Could not create type
   13:15:50 	at org.opendaylight.genius.itm.tests.ItmTestModule.configureBindings(ItmTestModule.java:97)
   13:15:50 	at org.opendaylight.infrautils.inject.guice.testutils.AbstractGuiceJsr250Module.checkedConfigure(AbstractGuiceJsr250Module.java:23)
   13:15:50 	at org.opendaylight.infrautils.inject.guice.testutils.AbstractCheckedModule.configure(AbstractCheckedModule.java:35)
   13:15:50 	... 27 more
   13:15:50 Caused by: java.lang.IllegalArgumentException: Could not create type
   13:15:50 	at net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:154)
   13:15:50 	at net.bytebuddy.TypeCache$WithInlineExpunction.findOrInsert(TypeCache.java:365)
   13:15:50 	at net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:174)
   13:15:50 	at net.bytebuddy.TypeCache$WithInlineExpunction.findOrInsert(TypeCache.java:376)
   13:15:50 	at org.mockito.internal.creation.bytebuddy.TypeCachingBytecodeGenerator.mockClass(TypeCachingBytecodeGenerator.java:32)
   13:15:50 	at org.mockito.internal.creation.bytebuddy.SubclassByteBuddyMockMaker.createMockType(SubclassByteBuddyMockMaker.java:71)
   13:15:50 	at org.mockito.internal.creation.bytebuddy.SubclassByteBuddyMockMaker.createMock(SubclassByteBuddyMockMaker.java:42)
   13:15:50 	at org.mockito.internal.creation.bytebuddy.ByteBuddyMockMaker.createMock(ByteBuddyMockMaker.java:25)
   13:15:50 	at org.powermock.api.mockito.mockmaker.PowerMockMaker.createMock(PowerMockMaker.java:41)
   13:15:50 	at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:35)
   13:15:50 	at org.mockito.internal.MockitoCore.mock(MockitoCore.java:62)
   13:15:50 	at org.mockito.Mockito.mock(Mockito.java:1907)
   13:15:50 	at org.mockito.Mockito.mock(Mockito.java:1816)
   13:15:50 	... 30 more
   13:15:50 Caused by: java.lang.NoSuchMethodError: net.bytebuddy.dynamic.loading.MultipleParentClassLoader$Builder.appendMostSpecific(Ljava/util/Collection;)Lnet/bytebuddy/dynamic/loading/MultipleParentClassLoader$Builder;
   13:15:50 	at org.mockito.internal.creation.bytebuddy.SubclassBytecodeGenerator.mockClass(SubclassBytecodeGenerator.java:83)
   13:15:50 	at org.mockito.internal.creation.bytebuddy.TypeCachingBytecodeGenerator$1.call(TypeCachingBytecodeGenerator.java:37)
   13:15:50 	at org.mockito.internal.creation.bytebuddy.TypeCachingBytecodeGenerator$1.call(TypeCachingBytecodeGenerator.java:34)
   13:15:50 	at net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:152)
   13:15:50 	... 42 more


The solution is to declare a dependency on mockito-core *before* the powermock dependency:

   <dependency>
     <groupId>org.mockito</groupId>
     <artifactId>mockito-core</artifactId>
     <scope>test</scope>
   </dependency>
   <dependency>
     <groupId>org.powermock</groupId>
     <artifactId>powermock-api-mockito2</artifactId>
     <scope>test</scope>
   </dependency>
   <dependency>
     <groupId>org.powermock</groupId>
     <artifactId>powermock-module-junit4</artifactId>
     <scope>test</scope>
   </dependency>
   <dependency>
     <groupId>org.powermock</groupId>
     <artifactId>powermock-reflect</artifactId>
     <scope>test</scope>
   </dependency>
   <dependency>
     <groupId>org.powermock</groupId>
     <artifactId>powermock-core</artifactId>
     <scope>test</scope>
   </dependency>

blueprint-maven-plugin

Default configuration of blueprint-maven-plugin has been tightened to only consider classes within ${project.groupId}. If you have classes outside of your assigned namespace, like netconf has in org.opendaylight.restconf (instead of org.opendaylight.netconf), you will need to override the configuration:

     <plugin>
       <groupId>org.apache.aries.blueprint</groupId>
       <artifactId>blueprint-maven-plugin</artifactId>
       <configuration>
         <scanPaths>
           <scanPath>org.opendaylight.restconf</scanPath>
         </scanPaths>
       </configuration>
     </plugin>

javadoc-maven-plugin

Default configuration of javadoc-maven-plugin has been updated, so that javadoc generation defaults to HTML5 when built with JDK9+. This can result in javadoc failures like:

   /w/workspace/autorelease-release-sodium-mvn35-openjdk11/openflowplugin/extension/openflowplugin-extension-api/src/main/java/org/opendaylight/openflowplugin/extension/api/GroupingLooseResolver.java:71: error: tag not supported in the generated HTML version: tt
    * @param data expected to match <T extends Augmentable<T>>

There are two options: either fix the Javadoc (preferred, as it is really simple) or add an override for a particular artifact by creating (and commiting to git) an empty file named "odl-javadoc-html5-optout" in a particular artifact's root directory (i.e. where its pom.xml is).

YANG Tools Impacts

YANG Parser

Default parser configuration will now validate the following construct:

    leaf foo {
        type leafref {
            path "/foo:bar";
        }
    }

to strictly comply with RFC7950, i.e. it is not a random XPath and the prefixes used must be validly imported.

Other changes

Aside from that, the following | bugs, enhancements and features have been delivered to Sodium Simultaneous Release.

MD-SAL Impacts

Empty type mapping

Java mapping for "type empty" construct has changed, leading to

   leaf foo {
       type empty;
   }

changing from:

   java.lang.Boolean isFoo();

to:

   org.opendaylight.yangtools.yang.common.Empty getFoo();

Code interacting with such models needs to be updated like this.

DataContainer.getImplementedInterface() renamed

This method has been renamed to implementedInterface() and it is now correctly type-narrowed in generated interfaces, which also provide a default implementation.

If you are implementing a type registry, you will need to update references to point to the new implementedInterface() method like this.

If you are hand-crafting interfaces or providing mock implementations, you will need to provide a proper implementedInterface() implementation like this.

DataContainer.implementedInterface() is type-narrowed in DataObjects

The replacement for getImplementedInterface(), implementedInterface() is futher narrowed in generated intermediate interfaces, such as groupings and provided with a default implementation in container-like interfaces.

Groupings look like this:

   public interface Grp
       extends
       DataObject
   {
       @Override
       Class<? extends Grp> implementedInterface();
   }

and their users like this:

   public interface Cont
       extends
       ChildOf<Mdsal437Data>,
       Augmentable<Cont>,
       Grp
   {
       @Override
       default Class<Cont> implementedInterface() {
           return Cont.class;
       }
   }

This works perfectly, but unfortunately seems to trigger a javac bug (or something forbidden by JLS, the information is not quite readily available/digestable), where the following construct involving two unrelated groupings will fail to compile:

   <T extends Grp1 & Grp2> void doSomething(Builder<T>);

The intent here is to say "require a Builder of a type T which extends both Grp1 and Grp2" . It seems javac (tested with JDK8, JDK11) internally performs the equivalent of

    interface T extends Grp1, Grp2 {
    }

which fails to compile (with the same error as javac reports in the <T ..> case), as T must do the equivalent of Cont does -- narrow implementedInterface() and solve the ambiguity. That is not a reason to not allow it -- for example Eclipse (i.e. JDT compiler) will accept this construct without any issues.

MD-SAL PingPongDataBroker no longer separate

Both Binding and DOM definitions of DataBroker have been updated to include a 'createMergingTransactionChain()' method, which integrates the functionality formerly provided by odl:type="pingpong" data broker instance. Downstreams will need to update to use the default instance and create the appriate transaction chain manually. Note this impacts only org.opendaylight.mdsal interfaces, not the org.opendaylight.controller one!

An example of changes is here and here -- note the same broker can be used in both ways, hence the proper place to change the createTransactionChain() call needs to be updated.