X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsamples%2Ftoaster-provider%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fsample%2Ftoaster%2Fprovider%2FOpendaylightToaster.java;h=cc275a9b006005bf84ff09c0ca9028b986b0d3c0;hb=1c79e662c75f327e4d1953710cc78b70780ef4e1;hp=e475c320d1e11c45258ebb6415083589fcf0302d;hpb=390c714cdeae2efe67d55d5a401929653b534f5c;p=controller.git 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 e475c320d1..cc275a9b00 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 @@ -7,71 +7,109 @@ */ package org.opendaylight.controller.sample.toaster.provider; -import static org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType.DELETE; -import static org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType.WRITE; -import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.CONFIGURATION; -import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.OPERATIONAL; -import static org.opendaylight.yangtools.yang.common.RpcError.ErrorType.APPLICATION; - -import com.google.common.base.Function; -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; -import com.google.common.util.concurrent.AsyncFunction; +import static java.util.Objects.requireNonNull; +import static org.opendaylight.mdsal.common.api.LogicalDatastoreType.CONFIGURATION; +import static org.opendaylight.mdsal.common.api.LogicalDatastoreType.OPERATIONAL; +import static org.opendaylight.yangtools.yang.common.ErrorType.APPLICATION; + +import com.google.common.util.concurrent.FluentFuture; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.SettableFuture; -import java.util.Collection; +import java.util.List; +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 org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.controller.md.sal.binding.api.DataObjectModification; -import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener; -import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier; -import org.opendaylight.controller.md.sal.binding.api.DataTreeModification; -import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService; -import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; -import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; -import org.opendaylight.controller.md.sal.common.api.data.OptimisticLockFailedException; -import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +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.DataTreeChangeListener; +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; +import org.opendaylight.mdsal.common.api.TransactionCommitFailedException; +import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.CancelToast; +import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.CancelToastInput; +import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.CancelToastOutput; +import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.CancelToastOutputBuilder; import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.DisplayString; +import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.MakeToast; import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.MakeToastInput; +import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.MakeToastOutput; +import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.MakeToastOutputBuilder; +import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.RestockToaster; import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.RestockToasterInput; +import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.RestockToasterOutput; +import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.RestockToasterOutputBuilder; import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.Toaster; import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.Toaster.ToasterStatus; import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterBuilder; import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterOutOfBreadBuilder; 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.RpcError.ErrorType; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.common.RpcResultBuilder; +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 - implements ToasterService, ToasterProviderRuntimeMXBean, DataTreeChangeListener, AutoCloseable { +@Singleton +@Component(service = MakeToast.class, immediate = true) +@Designate(ocd = OpendaylightToaster.Configuration.class) +public final class OpendaylightToaster extends AbstractMXBean + implements MakeToast, 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(); + private static final RestockToasterOutput EMPTY_RESTOCK_OUTPUT = new RestockToasterOutputBuilder().build(); 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 Registration dataTreeChangeListenerRegistration; + private final Registration reg; private final ExecutorService executor; @@ -83,48 +121,68 @@ public class OpendaylightToaster extends AbstractMXBean private final AtomicLong toastsMade = new AtomicLong(0); private final AtomicLong darknessFactor = new AtomicLong(1000); - private final ToasterAppConfig toasterAppConfig; + private final @NonNull DisplayString manufacturer; + private final @NonNull DisplayString modelNumber; + private final int maxMakeToastTries; - public OpendaylightToaster() { - this(new ToasterAppConfigBuilder().setManufacturer(TOASTER_MANUFACTURER).setModelNumber(TOASTER_MODEL_NUMBER) - .setMaxMakeToastTries(2).build()); - } - - public OpendaylightToaster(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) { - this.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.registerRpcImplementations( + (CancelToast) this::cancelToast, + this, + (RestockToaster) this::restockToaster); - public void init() { LOG.info("Initializing..."); - Preconditions.checkNotNull(dataBroker, "dataBroker must be set"); - dataTreeChangeListenerRegistration = dataBroker.registerDataTreeChangeListener( - new DataTreeIdentifier<>(CONFIGURATION, TOASTER_IID), this); - setToasterStatusUp(null); + dataTreeChangeListenerRegistration = requireNonNull(dataBroker, "dataBroker must be set") + .registerTreeChangeListener(DataTreeIdentifier.of(CONFIGURATION, TOASTER_IID), this); + 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(); @@ -136,9 +194,9 @@ public class OpendaylightToaster extends AbstractMXBean if (dataBroker != null) { WriteTransaction tx = dataBroker.newWriteOnlyTransaction(); tx.delete(OPERATIONAL,TOASTER_IID); - Futures.addCallback(tx.submit(), new FutureCallback() { + Futures.addCallback(tx.commit(), new FutureCallback() { @Override - public void onSuccess(final Void result) { + public void onSuccess(final CommitInfo result) { LOG.debug("Successfully deleted the operational Toaster"); } @@ -146,7 +204,7 @@ public class OpendaylightToaster extends AbstractMXBean public void onFailure(final Throwable failure) { LOG.error("Delete of the operational Toaster failed", failure); } - }); + }, MoreExecutors.directExecutor()); } } @@ -154,31 +212,37 @@ 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(); } /** * Implemented from the DataTreeChangeListener interface. */ @Override - public void onDataTreeChanged(Collection> changes) { - for (DataTreeModification change: changes) { - DataObjectModification rootNode = change.getRootNode(); - if (rootNode.getModificationType() == WRITE) { - Toaster oldToaster = rootNode.getDataBefore(); - Toaster newToaster = rootNode.getDataAfter(); - LOG.info("onDataTreeChanged - Toaster config with path {} was added or replaced: " - + "old Toaster: {}, new Toaster: {}", change.getRootPath().getRootIdentifier(), - oldToaster, newToaster); - - Long darkness = newToaster.getDarknessFactor(); - if (darkness != null) { - darknessFactor.set(darkness); + public void onDataTreeChanged(final List> changes) { + for (var change: changes) { + final var rootNode = change.getRootNode(); + switch (rootNode.modificationType()) { + case WRITE -> { + final var oldToaster = rootNode.dataBefore(); + final var newToaster = rootNode.dataAfter(); + LOG.info("onDataTreeChanged - Toaster config with path {} was added or replaced: old Toaster: {}, " + + "new Toaster: {}", change.getRootPath().path(), oldToaster, newToaster); + + final var darkness = newToaster.getDarknessFactor(); + if (darkness != null) { + darknessFactor.set(darkness.toJava()); + } + } + case DELETE -> LOG.info("onDataTreeChanged - Toaster config with path {} was deleted: old Toaster: {}", + change.getRootPath().path(), rootNode.dataBefore()); + default -> { + // No-op } - } else if (rootNode.getModificationType() == DELETE) { - LOG.info("onDataTreeChanged - Toaster config with path {} was deleted: old Toaster: {}", - change.getRootPath().getRootIdentifier(), rootNode.getDataBefore()); } } } @@ -186,53 +250,49 @@ public class OpendaylightToaster extends AbstractMXBean /** * RPC call implemented from the ToasterService interface that cancels the current toast, if any. */ - @Override - public Future> cancelToast() { - Future current = currentMakeToastTask.getAndSet(null); + private ListenableFuture> cancelToast(final CancelToastInput input) { + final var current = currentMakeToastTask.getAndSet(null); if (current != null) { current.cancel(true); } // Always return success from the cancel toast call - return Futures.immediateFuture(RpcResultBuilder.success().build()); + return Futures.immediateFuture(RpcResultBuilder.success(EMPTY_CANCEL_OUTPUT).build()); } /** * RPC call implemented from the ToasterService interface that attempts to make toast. */ @Override - public Future> makeToast(final MakeToastInput input) { - LOG.info("makeToast: " + input); - - final SettableFuture> futureResult = SettableFuture.create(); - - checkStatusAndMakeToast(input, futureResult, toasterAppConfig.getMaxMakeToastTries()); - + public ListenableFuture> invoke(final MakeToastInput input) { + LOG.info("makeToast: {}", input); + final var futureResult = SettableFuture.>create(); + checkStatusAndMakeToast(input, futureResult, maxMakeToastTries); return futureResult; } - private RpcError makeToasterOutOfBreadError() { - return RpcResultBuilder.newError(APPLICATION, "resource-denied", "Toaster is out of bread", "out-of-stock", - null, null); + private static RpcError makeToasterOutOfBreadError() { + return RpcResultBuilder.newError(APPLICATION, ErrorTag.RESOURCE_DENIED, "Toaster is out of bread", + "out-of-stock", null, null); } - private RpcError makeToasterInUseError() { - return RpcResultBuilder.newWarning(APPLICATION, "in-use", "Toaster is busy", null, null, null); + private static RpcError makeToasterInUseError() { + return RpcResultBuilder.newWarning(APPLICATION, ErrorTag.IN_USE, "Toaster is busy", null, null, null); } - private void checkStatusAndMakeToast(final MakeToastInput input, final SettableFuture> futureResult, - final int tries) { + private void checkStatusAndMakeToast(final MakeToastInput input, + final SettableFuture> futureResult, final int tries) { // Read the ToasterStatus and, if currently Up, try to write the status to Down. // If that succeeds, then we essentially have an exclusive lock and can proceed // to make toast. final ReadWriteTransaction tx = dataBroker.newReadWriteTransaction(); - ListenableFuture> readFuture = tx.read(OPERATIONAL, TOASTER_IID); + FluentFuture> readFuture = tx.read(OPERATIONAL, TOASTER_IID); - final ListenableFuture commitFuture = - Futures.transform(readFuture, (AsyncFunction, Void>) toasterData -> { + final ListenableFuture commitFuture = + Futures.transformAsync(readFuture, toasterData -> { ToasterStatus toasterStatus = ToasterStatus.Up; if (toasterData.isPresent()) { - toasterStatus = toasterData.get().getToasterStatus(); + toasterStatus = toasterData.orElseThrow().getToasterStatus(); } LOG.debug("Read toaster status: {}", toasterStatus); @@ -241,7 +301,8 @@ public class OpendaylightToaster extends AbstractMXBean if (outOfBread()) { LOG.debug("Toaster is out of bread"); - return Futures.immediateFailedCheckedFuture( + tx.cancel(); + return Futures.immediateFailedFuture( new TransactionCommitFailedException("", makeToasterOutOfBreadError())); } @@ -251,7 +312,7 @@ public class OpendaylightToaster extends AbstractMXBean // to indicate we're going to make toast. This acts as a lock to prevent // concurrent toasting. tx.put(OPERATIONAL, TOASTER_IID, buildToaster(ToasterStatus.Down)); - return tx.submit(); + return tx.commit(); } LOG.debug("Oops - already making toast!"); @@ -259,13 +320,14 @@ public class OpendaylightToaster extends AbstractMXBean // Return an error since we are already making toast. This will get // propagated to the commitFuture below which will interpret the null // TransactionStatus in the RpcResult as an error condition. - return Futures.immediateFailedCheckedFuture( + tx.cancel(); + return Futures.immediateFailedFuture( new TransactionCommitFailedException("", makeToasterInUseError())); - }); + }, MoreExecutors.directExecutor()); - Futures.addCallback(commitFuture, new FutureCallback() { + Futures.addCallback(commitFuture, new FutureCallback() { @Override - public void onSuccess(final Void result) { + public void onSuccess(final CommitInfo result) { // OK to make toast currentMakeToastTask.set(executor.submit(new MakeToastTask(input, futureResult))); } @@ -282,22 +344,22 @@ public class OpendaylightToaster extends AbstractMXBean LOG.debug("Got OptimisticLockFailedException - trying again"); checkStatusAndMakeToast(input, futureResult, tries - 1); } else { - futureResult.set(RpcResultBuilder.failed() + futureResult.set(RpcResultBuilder.failed() .withError(ErrorType.APPLICATION, ex.getMessage()).build()); } } else if (ex instanceof TransactionCommitFailedException) { LOG.debug("Failed to commit Toaster status", ex); // Probably already making toast. - futureResult.set(RpcResultBuilder.failed() + futureResult.set(RpcResultBuilder.failed() .withRpcErrors(((TransactionCommitFailedException)ex).getErrorList()).build()); } else { LOG.debug("Unexpected error committing Toaster status", ex); - futureResult.set(RpcResultBuilder.failed().withError(ErrorType.APPLICATION, + futureResult.set(RpcResultBuilder.failed().withError(ErrorType.APPLICATION, "Unexpected error committing Toaster status", ex).build()); } } - }); + }, MoreExecutors.directExecutor()); } /** @@ -305,11 +367,10 @@ public class OpendaylightToaster extends AbstractMXBean * Restocks the bread for the toaster, resets the toastsMade counter to 0, and sends a * ToasterRestocked notification. */ - @Override - public Future> restockToaster(final RestockToasterInput input) { - LOG.info("restockToaster: " + input); + private ListenableFuture> restockToaster(final RestockToasterInput input) { + LOG.info("restockToaster: {}", input); - amountOfBreadInStock.set(input.getAmountOfBreadToStock()); + amountOfBreadInStock.set(input.getAmountOfBreadToStock().toJava()); if (amountOfBreadInStock.get() > 0) { ToasterRestocked reStockedNotification = new ToasterRestockedBuilder() @@ -317,7 +378,7 @@ public class OpendaylightToaster extends AbstractMXBean notificationProvider.offerNotification(reStockedNotification); } - return Futures.immediateFuture(RpcResultBuilder.success().build()); + return Futures.immediateFuture(RpcResultBuilder.success(EMPTY_RESTOCK_OUTPUT).build()); } /** @@ -337,13 +398,14 @@ 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.submit(), new FutureCallback() { + final var future = tx.commit(); + Futures.addCallback(future, new FutureCallback() { @Override - public void onSuccess(final Void result) { + public void onSuccess(final CommitInfo result) { LOG.info("Successfully set ToasterStatus to Up"); notifyCallback(true); } @@ -362,7 +424,9 @@ public class OpendaylightToaster extends AbstractMXBean resultCallback.apply(result); } } - }); + }, MoreExecutors.directExecutor()); + + return future; } private boolean outOfBread() { @@ -372,9 +436,10 @@ public class OpendaylightToaster extends AbstractMXBean private class MakeToastTask implements Callable { final MakeToastInput toastRequest; - final SettableFuture> futureResult; + final SettableFuture> futureResult; - MakeToastTask(final MakeToastInput toastRequest, final SettableFuture> futureResult) { + MakeToastTask(final MakeToastInput toastRequest, + final SettableFuture> futureResult) { this.toastRequest = toastRequest; this.futureResult = futureResult; } @@ -383,7 +448,8 @@ public class OpendaylightToaster extends AbstractMXBean public Void call() { try { // make toast just sleeps for n seconds per doneness level. - Thread.sleep(OpendaylightToaster.this.darknessFactor.get() * toastRequest.getToasterDoneness()); + Thread.sleep(darknessFactor.get() + * toastRequest.getToasterDoneness().toJava()); } catch (InterruptedException e) { LOG.info("Interrupted while making the toast"); @@ -405,7 +471,7 @@ public class OpendaylightToaster extends AbstractMXBean setToasterStatusUp(result -> { currentMakeToastTask.set(null); LOG.debug("Toast done"); - futureResult.set(RpcResultBuilder.success().build()); + futureResult.set(RpcResultBuilder.success(EMPTY_MAKE_OUTPUT).build()); return null; });