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=ef2bfb690454c4c411c6a19f4006e8957fe67e62;hb=refs%2Fchanges%2F67%2F35867%2F26;hp=de5ddd9a75298f61d5c4ce15c00b9df0e170cc92;hpb=605e93859db80e6d0858a26046ee446f9fb967d6;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 de5ddd9a75..ef2bfb6904 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,14 @@ */ package org.opendaylight.controller.sample.toaster.provider; +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 +22,19 @@ 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.TransactionStatus; -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.sal.binding.api.NotificationProviderService; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +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,25 +45,17 @@ 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.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); @@ -62,8 +64,9 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti 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 NotificationPublishService notificationProvider; private DataBroker dataProvider; + private ListenerRegistration dataTreeChangeListenerRegistration; private final ExecutorService executor; @@ -79,15 +82,20 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti private final AtomicLong darknessFactor = new AtomicLong( 1000 ); public OpendaylightToaster() { + super("OpendaylightToaster", "toaster-provider", null); executor = Executors.newFixedThreadPool(1); } - 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; + + dataProvider.registerDataTreeChangeListener(new DataTreeIdentifier( + LogicalDatastoreType.CONFIGURATION, OpendaylightToaster.TOASTER_IID), this); + setToasterStatusUp( null ); } @@ -100,24 +108,25 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti executor.shutdown(); if (dataProvider != null) { - WriteTransaction t = dataProvider.newWriteOnlyTransaction(); - t.delete(LogicalDatastoreType.OPERATIONAL,TOASTER_IID); - ListenableFuture> future = t.commit(); - Futures.addCallback( future, new FutureCallback>() { + dataTreeChangeListenerRegistration.close(); + + WriteTransaction tx = dataProvider.newWriteOnlyTransaction(); + tx.delete(LogicalDatastoreType.OPERATIONAL,TOASTER_IID); + Futures.addCallback( tx.submit(), new FutureCallback() { @Override - public void onSuccess( RpcResult result ) { + public void onSuccess( final Void result ) { LOG.debug( "Delete Toaster commit result: " + result ); } @Override - public void onFailure( Throwable t ) { + public void onFailure( final Throwable t ) { LOG.error( "Delete of Toaster failed", t ); } } ); } } - private Toaster buildToaster( ToasterStatus status ) { + private Toaster buildToaster( final ToasterStatus status ) { // note - we are simulating a device whose manufacture and model are // fixed (embedded) into the hardware. @@ -129,18 +138,25 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti } /** - * 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() == DataObjectModification.ModificationType.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() == DataObjectModification.ModificationType.DELETE) { + LOG.info("onDataTreeChanged - Toaster config with path {} was deleted: old Toaster: {}", + change.getRootPath().getRootIdentifier(), rootNode.getDataBefore()); } } } @@ -170,7 +186,7 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti final SettableFuture> futureResult = SettableFuture.create(); - checkStatusAndMakeToast( input, futureResult ); + checkStatusAndMakeToast( input, futureResult, 2 ); return futureResult; } @@ -186,27 +202,27 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti } private void checkStatusAndMakeToast( final MakeToastInput input, - final SettableFuture> futureResult ) { + 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 = dataProvider.newReadWriteTransaction(); - ListenableFuture> readFuture = + ListenableFuture> readFuture = tx.read( LogicalDatastoreType.OPERATIONAL, TOASTER_IID ); - final ListenableFuture> commitFuture = - Futures.transform( readFuture, new AsyncFunction, - RpcResult>() { + final ListenableFuture commitFuture = + Futures.transform( readFuture, new AsyncFunction,Void>() { @Override - public ListenableFuture> apply( - Optional toasterData ) throws Exception { + public ListenableFuture apply( + final Optional toasterData ) throws Exception { ToasterStatus toasterStatus = ToasterStatus.Up; if( toasterData.isPresent() ) { - toasterStatus = ((Toaster)toasterData.get()).getToasterStatus(); + toasterStatus = toasterData.get().getToasterStatus(); } LOG.debug( "Read toaster status: {}", toasterStatus ); @@ -216,8 +232,8 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti if( outOfBread() ) { LOG.debug( "Toaster is out of bread" ); - return Futures.immediateFuture( RpcResultBuilder.failed() - .withRpcError( makeToasterOutOfBreadError() ).build() ); + return Futures.immediateFailedCheckedFuture( + new TransactionCommitFailedException( "", makeToasterOutOfBreadError() ) ); } LOG.debug( "Setting Toaster status to Down" ); @@ -227,7 +243,7 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti // concurrent toasting. tx.put( LogicalDatastoreType.OPERATIONAL, TOASTER_IID, buildToaster( ToasterStatus.Down ) ); - return tx.commit(); + return tx.submit(); } LOG.debug( "Oops - already making toast!" ); @@ -235,51 +251,44 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti // 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.immediateFuture( RpcResultBuilder.failed() - .withRpcError( makeToasterInUseError() ).build() ); + return Futures.immediateFailedCheckedFuture( + new TransactionCommitFailedException( "", makeToasterInUseError() ) ); } } ); - Futures.addCallback( commitFuture, new FutureCallback>() { + Futures.addCallback( commitFuture, new FutureCallback() { @Override - public void onSuccess( RpcResult result ) { - if( result.getResult() == TransactionStatus.COMMITED ) { - - // OK to make toast - currentMakeToastTask.set( executor.submit( - new MakeToastTask( input, futureResult ) ) ); - } else { - - LOG.debug( "Setting error result" ); - - // Either the transaction failed to commit for some reason or, more likely, - // the read above returned ToasterStatus.Down. Either way, fail the - // futureResult and copy the errors. - - futureResult.set( RpcResultBuilder.failed().withRpcErrors( - result.getErrors() ).build() ); - } + public void onSuccess( final Void result ) { + // OK to make toast + currentMakeToastTask.set( executor.submit( new MakeToastTask( input, futureResult ) ) ); } @Override - public void onFailure( Throwable ex ) { + public void onFailure( final Throwable ex ) { if( ex instanceof OptimisticLockFailedException ) { // Another thread is likely trying to make toast simultaneously and updated the // status before us. Try reading the status again - if another make toast is // now in progress, we should get ToasterStatus.Down and fail. - LOG.debug( "Got OptimisticLockFailedException - trying again" ); + if( ( tries - 1 ) > 0 ) { + LOG.debug( "Got OptimisticLockFailedException - trying again" ); - checkStatusAndMakeToast( input, futureResult ); + checkStatusAndMakeToast( input, futureResult, tries - 1 ); + } + else { + futureResult.set( RpcResultBuilder. failed() + .withError( ErrorType.APPLICATION, ex.getMessage() ).build() ); + } } else { - LOG.error( "Failed to commit Toaster status", ex ); + LOG.debug( "Failed to commit Toaster status", ex ); - // Got some unexpected error so fail. + // Probably already making toast. futureResult.set( RpcResultBuilder. failed() - .withError( ErrorType.APPLICATION, ex.getMessage() ).build() ); + .withRpcErrors( ((TransactionCommitFailedException)ex).getErrorList() ) + .build() ); } } } ); @@ -299,7 +308,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() ); @@ -327,20 +336,14 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti WriteTransaction tx = dataProvider.newWriteOnlyTransaction(); tx.put( LogicalDatastoreType.OPERATIONAL,TOASTER_IID, buildToaster( ToasterStatus.Up ) ); - ListenableFuture> commitFuture = tx.commit(); - - Futures.addCallback( commitFuture, new FutureCallback>() { + Futures.addCallback( tx.submit(), new FutureCallback() { @Override - public void onSuccess( RpcResult result ) { - if( result.getResult() != TransactionStatus.COMMITED ) { - LOG.error( "Failed to update toaster status: " + result.getErrors() ); - } - - notifyCallback( result.getResult() == TransactionStatus.COMMITED ); + public void onSuccess( final Void result ) { + notifyCallback( true ); } @Override - public void onFailure( Throwable t ) { + public void onFailure( final Throwable t ) { // We shouldn't get an OptimisticLockFailedException (or any ex) as no // other component should be updating the operational state. LOG.error( "Failed to update toaster status", t ); @@ -348,7 +351,7 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti notifyCallback( false ); } - void notifyCallback( boolean result ) { + void notifyCallback( final boolean result ) { if( resultCallback != null ) { resultCallback.apply( result ); } @@ -391,7 +394,7 @@ 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. @@ -400,7 +403,7 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti setToasterStatusUp( new Function() { @Override - public Void apply( Boolean result ) { + public Void apply( final Boolean result ) { currentMakeToastTask.set( null );