X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsamples%2Ftoaster-provider%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fsample%2Ftoaster%2Fprovider%2FOpendaylightToaster.java;h=b876fa2cd3ac15fe21f5dfb84650371d7eebb64d;hp=b7518e094d0e61594a391c2fc4a78b181294e00a;hb=8ef9a9c246b2389938b8211defb4911f0806565c;hpb=4386d86231d7c6b84a8a70795ef43b178c0b9996 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 b7518e094d..b876fa2cd3 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,6 +7,20 @@ */ package org.opendaylight.controller.sample.toaster.provider; +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 static org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType.DELETE; +import static org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType.WRITE; + +import com.google.common.base.Function; +import com.google.common.base.Optional; +import com.google.common.util.concurrent.AsyncFunction; +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.SettableFuture; +import java.util.Collection; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; @@ -14,17 +28,17 @@ 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.config.yang.config.toaster_provider.impl.ToasterProviderRuntimeMXBean; import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; +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.AsyncDataChangeEvent; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.common.api.data.OptimisticLockFailedException; import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; -import org.opendaylight.controller.sal.binding.api.NotificationProviderService; +import org.opendaylight.controller.md.sal.common.util.jmx.AbstractMXBean; 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.MakeToastInput; import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.RestockToasterInput; @@ -35,60 +49,61 @@ 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.yangtools.yang.binding.DataObject; +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.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.common.RpcError; -import org.opendaylight.yangtools.yang.common.RpcResultBuilder; import org.opendaylight.yangtools.yang.common.RpcError.ErrorType; import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.common.RpcResultBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.base.Function; -import com.google.common.base.Optional; -import com.google.common.util.concurrent.AsyncFunction; -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.SettableFuture; - -public class OpendaylightToaster implements ToasterService, ToasterProviderRuntimeMXBean, - DataChangeListener, AutoCloseable { +public class OpendaylightToaster extends AbstractMXBean + implements ToasterService, ToasterProviderRuntimeMXBean, DataTreeChangeListener, AutoCloseable { private static final Logger LOG = LoggerFactory.getLogger(OpendaylightToaster.class); - public static final InstanceIdentifier TOASTER_IID = InstanceIdentifier.builder(Toaster.class).build(); - + 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 NotificationProviderService notificationProvider; private DataBroker dataProvider; + private NotificationPublishService notificationProvider; + private ListenerRegistration dataTreeChangeListenerRegistration; private final ExecutorService executor; - // The following holds the Future for the current make toast task. - // This is used to cancel the current toast. + // This holds the Future for the current make toast task and is used to cancel the current toast. private final AtomicReference> currentMakeToastTask = new AtomicReference<>(); + // Thread safe holders private final AtomicLong amountOfBreadInStock = new AtomicLong( 100 ); - private final AtomicLong toastsMade = new AtomicLong(0); - - // Thread safe holder for our darkness multiplier. private final AtomicLong darknessFactor = new AtomicLong( 1000 ); + private final ToasterAppConfig toasterAppConfig; + public OpendaylightToaster() { + this(new ToasterAppConfigBuilder().setManufacturer(TOASTER_MANUFACTURER).setModelNumber(TOASTER_MODEL_NUMBER) + .setMaxMakeToastTries(2).build()); + } + + public OpendaylightToaster(ToasterAppConfig toasterAppConfig) { + super("OpendaylightToaster", "toaster-provider", null); executor = Executors.newFixedThreadPool(1); + this.toasterAppConfig = toasterAppConfig; } - public void setNotificationProvider(final NotificationProviderService salService) { - this.notificationProvider = salService; + public void setNotificationProvider(final NotificationPublishService notificationPublishService) { + this.notificationProvider = notificationPublishService; } public void setDataProvider(final DataBroker salDataProvider) { this.dataProvider = salDataProvider; - setToasterStatusUp( null ); + dataProvider.registerDataTreeChangeListener(new DataTreeIdentifier<>(CONFIGURATION, TOASTER_IID), this); + setToasterStatusUp(null); } /** @@ -100,8 +115,10 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti executor.shutdown(); if (dataProvider != null) { + dataTreeChangeListenerRegistration.close(); + WriteTransaction tx = dataProvider.newWriteOnlyTransaction(); - tx.delete(LogicalDatastoreType.OPERATIONAL,TOASTER_IID); + tx.delete(OPERATIONAL,TOASTER_IID); Futures.addCallback( tx.submit(), new FutureCallback() { @Override public void onSuccess( final Void result ) { @@ -117,46 +134,50 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti } private Toaster buildToaster( final ToasterStatus status ) { - // 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( TOASTER_MANUFACTURER ) - .setToasterModelNumber( TOASTER_MODEL_NUMBER ) + return new ToasterBuilder().setToasterManufacturer( toasterAppConfig.getManufacturer() ) + .setToasterModelNumber( toasterAppConfig.getModelNumber() ) .setToasterStatus( status ) .build(); } /** - * Implemented from the DataChangeListener interface. + * Implemented from the DataTreeChangeListener interface. */ @Override - public void onDataChanged( final AsyncDataChangeEvent, DataObject> change ) { - DataObject dataObject = change.getUpdatedSubtree(); - if( dataObject instanceof Toaster ) - { - Toaster toaster = (Toaster) dataObject; - Long darkness = toaster.getDarknessFactor(); - if( darkness != null ) - { - darknessFactor.set( darkness ); + 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); + } + } else if(rootNode.getModificationType() == DELETE) { + LOG.info("onDataTreeChanged - Toaster config with path {} was deleted: old Toaster: {}", + change.getRootPath().getRootIdentifier(), rootNode.getDataBefore()); } } } /** - * RPC call implemented from the ToasterService interface that cancels the current - * toast, if any. + * RPC call implemented from the ToasterService interface that cancels the current toast, if any. */ @Override public Future> cancelToast() { - Future current = currentMakeToastTask.getAndSet( null ); if( current != null ) { current.cancel( true ); } - // Always return success from the cancel toast call. + // Always return success from the cancel toast call return Futures.immediateFuture( RpcResultBuilder. success().build() ); } @@ -169,18 +190,18 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti final SettableFuture> futureResult = SettableFuture.create(); - checkStatusAndMakeToast( input, futureResult, 2 ); + checkStatusAndMakeToast( input, futureResult, toasterAppConfig.getMaxMakeToastTries() ); return futureResult; } private RpcError makeToasterOutOfBreadError() { - return RpcResultBuilder.newError( ErrorType.APPLICATION, "resource-denied", + return RpcResultBuilder.newError( APPLICATION, "resource-denied", "Toaster is out of bread", "out-of-stock", null, null ); } private RpcError makeToasterInUseError() { - return RpcResultBuilder.newWarning( ErrorType.APPLICATION, "in-use", + return RpcResultBuilder.newWarning( APPLICATION, "in-use", "Toaster is busy", null, null, null ); } @@ -193,15 +214,10 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti // to make toast. final ReadWriteTransaction tx = dataProvider.newReadWriteTransaction(); - ListenableFuture> readFuture = - tx.read( LogicalDatastoreType.OPERATIONAL, TOASTER_IID ); + ListenableFuture> readFuture = tx.read(OPERATIONAL, TOASTER_IID); final ListenableFuture commitFuture = - Futures.transform( readFuture, new AsyncFunction,Void>() { - - @Override - public ListenableFuture apply( - final Optional toasterData ) throws Exception { + Futures.transform( readFuture, (AsyncFunction, Void>) toasterData -> { ToasterStatus toasterStatus = ToasterStatus.Up; if( toasterData.isPresent() ) { @@ -224,7 +240,7 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti // We're not currently making toast - try to update the status to Down // to indicate we're going to make toast. This acts as a lock to prevent // concurrent toasting. - tx.put( LogicalDatastoreType.OPERATIONAL, TOASTER_IID, + tx.put( OPERATIONAL, TOASTER_IID, buildToaster( ToasterStatus.Down ) ); return tx.submit(); } @@ -236,7 +252,6 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti // TransactionStatus in the RpcResult as an error condition. return Futures.immediateFailedCheckedFuture( new TransactionCommitFailedException( "", makeToasterInUseError() ) ); - } } ); Futures.addCallback( commitFuture, new FutureCallback() { @@ -291,7 +306,7 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti if( amountOfBreadInStock.get() > 0 ) { ToasterRestocked reStockedNotification = new ToasterRestockedBuilder() .setAmountOfBread( input.getAmountOfBreadToStock() ).build(); - notificationProvider.publish( reStockedNotification ); + notificationProvider.offerNotification( reStockedNotification ); } return Futures.immediateFuture( RpcResultBuilder. success().build() ); @@ -315,9 +330,8 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti } private void setToasterStatusUp( final Function resultCallback ) { - WriteTransaction tx = dataProvider.newWriteOnlyTransaction(); - tx.put( LogicalDatastoreType.OPERATIONAL,TOASTER_IID, buildToaster( ToasterStatus.Up ) ); + tx.put( OPERATIONAL,TOASTER_IID, buildToaster( ToasterStatus.Up ) ); Futures.addCallback( tx.submit(), new FutureCallback() { @Override @@ -377,16 +391,14 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti if( outOfBread() ) { LOG.info( "Toaster is out of bread!" ); - notificationProvider.publish( new ToasterOutOfBreadBuilder().build() ); + notificationProvider.offerNotification( new ToasterOutOfBreadBuilder().build() ); } // Set the Toaster status back to up - this essentially releases the toasting lock. // We can't clear the current toast task nor set the Future result until the // update has been committed so we pass a callback to be notified on completion. - setToasterStatusUp( new Function() { - @Override - public Void apply( final Boolean result ) { + setToasterStatusUp( result -> { currentMakeToastTask.set( null ); @@ -395,7 +407,6 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti futureResult.set( RpcResultBuilder.success().build() ); return null; - } } ); return null;