From c18f35dc4659c301354e25aca4d41178201975f1 Mon Sep 17 00:00:00 2001 From: Samuel Schneider Date: Wed, 4 Jan 2023 17:20:46 +0100 Subject: [PATCH] Migrate toaster-producer to OSGi DS Use declarative services instead of blueprint, removing unnecessary models in the process. ToasterTest is updated to wait for ToasterService, as we are touching its MXBean. Change-Id: I6b947ccb0024da934457e4c52d0665f3fc9a5bb6 Signed-off-by: Oleksandr Panasiuk Signed-off-by: Samuel Schneider Signed-off-by: Robert Varga --- .../sample/toaster/it/ToasterTest.java | 4 + .../md-sal/samples/toaster-provider/pom.xml | 20 ++++ .../toaster/provider/OpendaylightToaster.java | 113 +++++++++++++----- .../OSGI-INF/blueprint/toaster-provider.xml | 64 ---------- .../src/main/yang/toaster-app-config.yang | 33 ----- .../provider/OpenDaylightToasterTest.java | 10 +- 6 files changed, 108 insertions(+), 136 deletions(-) delete mode 100644 opendaylight/md-sal/samples/toaster-provider/src/main/resources/OSGI-INF/blueprint/toaster-provider.xml delete mode 100644 opendaylight/md-sal/samples/toaster-provider/src/main/yang/toaster-app-config.yang diff --git a/opendaylight/md-sal/samples/toaster-it/src/test/java/org/opendaylight/controller/sample/toaster/it/ToasterTest.java b/opendaylight/md-sal/samples/toaster-it/src/test/java/org/opendaylight/controller/sample/toaster/it/ToasterTest.java index dd5535697d..9bc905c3f4 100644 --- a/opendaylight/md-sal/samples/toaster-it/src/test/java/org/opendaylight/controller/sample/toaster/it/ToasterTest.java +++ b/opendaylight/md-sal/samples/toaster-it/src/test/java/org/opendaylight/controller/sample/toaster/it/ToasterTest.java @@ -21,6 +21,7 @@ import org.opendaylight.controller.mdsal.it.base.AbstractMdsalTestBase; import org.opendaylight.controller.sample.kitchen.api.EggsType; import org.opendaylight.controller.sample.kitchen.api.KitchenService; import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.HashBrown; +import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterService; import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.WhiteBread; import org.ops4j.pax.exam.junit.PaxExam; import org.ops4j.pax.exam.options.MavenUrlReference; @@ -31,6 +32,9 @@ public class ToasterTest extends AbstractMdsalTestBase { @Inject @Filter(timeout = 60 * 1000) KitchenService kitchenService; + @Inject + @Filter(timeout = 60 * 1000) + ToasterService toasterService; @Override public MavenUrlReference getFeatureRepo() { diff --git a/opendaylight/md-sal/samples/toaster-provider/pom.xml b/opendaylight/md-sal/samples/toaster-provider/pom.xml index a6bb2ff359..5fd77da1ef 100644 --- a/opendaylight/md-sal/samples/toaster-provider/pom.xml +++ b/opendaylight/md-sal/samples/toaster-provider/pom.xml @@ -31,6 +31,26 @@ org.opendaylight.mdsal mdsal-binding-test-utils + + + jakarta.annotation + jakarta.annotation-api + true + + + org.osgi + org.osgi.service.component.annotations + + + com.guicedee.services + javax.inject + true + + + org.osgi + org.osgi.service.metatype.annotations + compile + diff --git a/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/OpendaylightToaster.java b/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/OpendaylightToaster.java index 54e7b9a65c..b0eda4c42f 100644 --- a/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/OpendaylightToaster.java +++ b/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/OpendaylightToaster.java @@ -23,12 +23,17 @@ import com.google.common.util.concurrent.SettableFuture; import java.util.Collection; import java.util.Optional; import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; +import javax.annotation.PreDestroy; +import javax.inject.Inject; +import javax.inject.Singleton; +import org.eclipse.jdt.annotation.NonNull; import org.opendaylight.controller.md.sal.common.util.jmx.AbstractMXBean; import org.opendaylight.mdsal.binding.api.DataBroker; import org.opendaylight.mdsal.binding.api.DataObjectModification; @@ -37,6 +42,7 @@ import org.opendaylight.mdsal.binding.api.DataTreeIdentifier; import org.opendaylight.mdsal.binding.api.DataTreeModification; import org.opendaylight.mdsal.binding.api.NotificationPublishService; import org.opendaylight.mdsal.binding.api.ReadWriteTransaction; +import org.opendaylight.mdsal.binding.api.RpcProviderService; import org.opendaylight.mdsal.binding.api.WriteTransaction; import org.opendaylight.mdsal.common.api.CommitInfo; import org.opendaylight.mdsal.common.api.OptimisticLockFailedException; @@ -58,22 +64,40 @@ import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120 import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterRestocked; import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterRestockedBuilder; import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.toaster.app.config.rev160503.ToasterAppConfig; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.toaster.app.config.rev160503.ToasterAppConfigBuilder; import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.concepts.Registration; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.common.ErrorTag; import org.opendaylight.yangtools.yang.common.ErrorType; import org.opendaylight.yangtools.yang.common.RpcError; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.common.RpcResultBuilder; -import org.opendaylight.yangtools.yang.common.Uint16; import org.opendaylight.yangtools.yang.common.Uint32; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.Designate; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class OpendaylightToaster extends AbstractMXBean +@Singleton +@Component(service = ToasterService.class, immediate = true) +@Designate(ocd = OpendaylightToaster.Configuration.class) +public final class OpendaylightToaster extends AbstractMXBean implements ToasterService, ToasterProviderRuntimeMXBean, DataTreeChangeListener, AutoCloseable { + @ObjectClassDefinition + public @interface Configuration { + @AttributeDefinition(description = "The name of the toaster's manufacturer", max = "255") + String manufacturer() default TOASTER_MANUFACTURER; + @AttributeDefinition(description = "The name of the toaster's model", max = "255") + String modelNumber() default TOASTER_MODEL_NUMBER; + @AttributeDefinition(description = "How many times we attempt to make toast before failing ", + min = "0", max = "65535") + int maxMakeToastTries() default 2; + } private static final CancelToastOutput EMPTY_CANCEL_OUTPUT = new CancelToastOutputBuilder().build(); private static final MakeToastOutput EMPTY_MAKE_OUTPUT = new MakeToastOutputBuilder().build(); @@ -82,12 +106,13 @@ public class OpendaylightToaster extends AbstractMXBean private static final Logger LOG = LoggerFactory.getLogger(OpendaylightToaster.class); private static final InstanceIdentifier TOASTER_IID = InstanceIdentifier.builder(Toaster.class).build(); - private static final DisplayString TOASTER_MANUFACTURER = new DisplayString("Opendaylight"); - private static final DisplayString TOASTER_MODEL_NUMBER = new DisplayString("Model 1 - Binding Aware"); + private static final String TOASTER_MANUFACTURER = "Opendaylight"; + private static final String TOASTER_MODEL_NUMBER = "Model 1 - Binding Aware"; - private DataBroker dataBroker; - private NotificationPublishService notificationProvider; - private ListenerRegistration dataTreeChangeListenerRegistration; + private final DataBroker dataBroker; + private final NotificationPublishService notificationProvider; + private final ListenerRegistration dataTreeChangeListenerRegistration; + private final Registration reg; private final ExecutorService executor; @@ -99,47 +124,65 @@ public class OpendaylightToaster extends AbstractMXBean private final AtomicLong toastsMade = new AtomicLong(0); private final AtomicLong darknessFactor = new AtomicLong(1000); - private final ToasterAppConfig toasterAppConfig; - - public OpendaylightToaster() { - this(new ToasterAppConfigBuilder().setManufacturer(TOASTER_MANUFACTURER).setModelNumber(TOASTER_MODEL_NUMBER) - .setMaxMakeToastTries(Uint16.valueOf(2)).build()); - } + private final @NonNull DisplayString manufacturer; + private final @NonNull DisplayString modelNumber; + private final int maxMakeToastTries; - public OpendaylightToaster(final ToasterAppConfig toasterAppConfig) { + public OpendaylightToaster(final DataBroker dataProvider, + final NotificationPublishService notificationPublishService, final RpcProviderService rpcProviderService, + final String manufacturer, final String modelNumber, final int maxMakeToastTries) { super("OpendaylightToaster", "toaster-provider", null); - executor = Executors.newFixedThreadPool(1); - this.toasterAppConfig = toasterAppConfig; - } + notificationProvider = requireNonNull(notificationPublishService); + dataBroker = requireNonNull(dataProvider); - public void setNotificationProvider(final NotificationPublishService notificationPublishService) { - notificationProvider = notificationPublishService; - } + this.manufacturer = new DisplayString(manufacturer); + this.modelNumber = new DisplayString(modelNumber); + this.maxMakeToastTries = maxMakeToastTries; - public void setDataBroker(final DataBroker dataBroker) { - this.dataBroker = dataBroker; - } + executor = Executors.newFixedThreadPool(1); + reg = rpcProviderService.registerRpcImplementation(ToasterService.class, this); - public void init() { LOG.info("Initializing..."); dataTreeChangeListenerRegistration = requireNonNull(dataBroker, "dataBroker must be set") .registerDataTreeChangeListener(DataTreeIdentifier.create(CONFIGURATION, TOASTER_IID), this); - setToasterStatusUp(null); + try { + setToasterStatusUp(null).get(); + } catch (InterruptedException | ExecutionException e) { + throw new IllegalStateException("Failed to commit initial data", e); + } // Register our MXBean. register(); } + @Inject + public OpendaylightToaster(final DataBroker dataProvider, + final NotificationPublishService notificationPublishService, final RpcProviderService rpcProviderService) { + this(dataProvider, notificationPublishService, rpcProviderService, TOASTER_MANUFACTURER, TOASTER_MODEL_NUMBER, + 2); + } + + @Activate + public OpendaylightToaster(@Reference final DataBroker dataProvider, + @Reference final NotificationPublishService notificationPublishService, + @Reference final RpcProviderService rpcProviderService, final @NonNull Configuration configuration) { + this(dataProvider, notificationPublishService, rpcProviderService, configuration.manufacturer(), + configuration.modelNumber(), configuration.maxMakeToastTries()); + } + /** * Implemented from the AutoCloseable interface. */ @Override + @PreDestroy + @Deactivate public void close() { LOG.info("Closing..."); // Unregister our MXBean. unregister(); + reg.close(); // When we close this service we need to shutdown our executor! executor.shutdown(); @@ -169,8 +212,11 @@ public class OpendaylightToaster extends AbstractMXBean // note - we are simulating a device whose manufacture and model are // fixed (embedded) into the hardware. // This is why the manufacture and model number are hardcoded. - return new ToasterBuilder().setToasterManufacturer(toasterAppConfig.getManufacturer()) - .setToasterModelNumber(toasterAppConfig.getModelNumber()).setToasterStatus(status).build(); + return new ToasterBuilder() + .setToasterManufacturer(manufacturer) + .setToasterModelNumber(modelNumber) + .setToasterStatus(status) + .build(); } /** @@ -221,7 +267,7 @@ public class OpendaylightToaster extends AbstractMXBean final SettableFuture> futureResult = SettableFuture.create(); - checkStatusAndMakeToast(input, futureResult, toasterAppConfig.getMaxMakeToastTries().toJava()); + checkStatusAndMakeToast(input, futureResult, maxMakeToastTries); return futureResult; } @@ -354,11 +400,12 @@ public class OpendaylightToaster extends AbstractMXBean return toastsMade.get(); } - private void setToasterStatusUp(final Function resultCallback) { + private ListenableFuture setToasterStatusUp(final Function resultCallback) { WriteTransaction tx = dataBroker.newWriteOnlyTransaction(); tx.put(OPERATIONAL,TOASTER_IID, buildToaster(ToasterStatus.Up)); - Futures.addCallback(tx.commit(), new FutureCallback() { + final var future = tx.commit(); + Futures.addCallback(future, new FutureCallback() { @Override public void onSuccess(final CommitInfo result) { LOG.info("Successfully set ToasterStatus to Up"); @@ -380,6 +427,8 @@ public class OpendaylightToaster extends AbstractMXBean } } }, MoreExecutors.directExecutor()); + + return future; } private boolean outOfBread() { diff --git a/opendaylight/md-sal/samples/toaster-provider/src/main/resources/OSGI-INF/blueprint/toaster-provider.xml b/opendaylight/md-sal/samples/toaster-provider/src/main/resources/OSGI-INF/blueprint/toaster-provider.xml deleted file mode 100644 index 4c7af5b635..0000000000 --- a/opendaylight/md-sal/samples/toaster-provider/src/main/resources/OSGI-INF/blueprint/toaster-provider.xml +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - - - - - - - - - - 3 - - ]]> - - - - - - - - - - - - - - - - diff --git a/opendaylight/md-sal/samples/toaster-provider/src/main/yang/toaster-app-config.yang b/opendaylight/md-sal/samples/toaster-provider/src/main/yang/toaster-app-config.yang deleted file mode 100644 index 369ba463e0..0000000000 --- a/opendaylight/md-sal/samples/toaster-provider/src/main/yang/toaster-app-config.yang +++ /dev/null @@ -1,33 +0,0 @@ -module toaster-app-config { - yang-version 1; - - namespace "urn:opendaylight:params:xml:ns:yang:controller:toaster-app-config"; - prefix toaster-app-config; - - import toaster { prefix toaster; revision-date 2009-11-20; } - - description - "Configuration for the Opendaylight toaster application."; - - revision "2016-05-03" { - description - "Initial revision."; - } - - container toaster-app-config { - leaf manufacturer { - type toaster:DisplayString; - default "Opendaylight"; - } - - leaf model-number { - type toaster:DisplayString; - default "Model 1 - Binding Aware"; - } - - leaf max-make-toast-tries { - type uint16; - default 2; - } - } -} \ No newline at end of file diff --git a/opendaylight/md-sal/samples/toaster-provider/src/test/java/org/opendaylight/controller/sample/toaster/provider/OpenDaylightToasterTest.java b/opendaylight/md-sal/samples/toaster-provider/src/test/java/org/opendaylight/controller/sample/toaster/provider/OpenDaylightToasterTest.java index b703a2b20b..7ad1e38e2c 100644 --- a/opendaylight/md-sal/samples/toaster-provider/src/test/java/org/opendaylight/controller/sample/toaster/provider/OpenDaylightToasterTest.java +++ b/opendaylight/md-sal/samples/toaster-provider/src/test/java/org/opendaylight/controller/sample/toaster/provider/OpenDaylightToasterTest.java @@ -22,6 +22,7 @@ import org.junit.Test; import org.opendaylight.mdsal.binding.api.DataBroker; import org.opendaylight.mdsal.binding.api.NotificationPublishService; import org.opendaylight.mdsal.binding.api.ReadTransaction; +import org.opendaylight.mdsal.binding.api.RpcProviderService; import org.opendaylight.mdsal.binding.dom.adapter.test.AbstractConcurrentDataBrokerTest; import org.opendaylight.mdsal.common.api.LogicalDatastoreType; import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.DisplayString; @@ -41,13 +42,8 @@ public class OpenDaylightToasterTest extends AbstractConcurrentDataBrokerTest { @Before public void setupToaster() { - toaster = new OpendaylightToaster(); - toaster.setDataBroker(getDataBroker()); - toaster.init(); - - // We'll mock the NotificationProviderService. - NotificationPublishService mockNotification = mock(NotificationPublishService.class); - toaster.setNotificationProvider(mockNotification); + toaster = new OpendaylightToaster(getDataBroker(), mock(NotificationPublishService.class), + mock(RpcProviderService.class)); } @Test -- 2.36.6