Remove CSS-related files from the toaster
[controller.git] / opendaylight / md-sal / samples / toaster-provider / src / main / java / org / opendaylight / controller / sample / toaster / provider / OpendaylightToaster.java
index d2b0f90194a9a066558f6d4dca5d1d8751ec01aa..b0daca7ce07ef377d605fc9da1bc658f8d2d10a8 100644 (file)
@@ -7,9 +7,14 @@
  */
 package org.opendaylight.controller.sample.toaster.provider;
 
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
+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;
@@ -17,19 +22,18 @@ 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.sal.common.util.RpcErrors;
-import org.opendaylight.controller.sal.common.util.Rpcs;
+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;
@@ -40,25 +44,19 @@ 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.RpcError.ErrorSeverity;
 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<Toaster>, AutoCloseable {
 
     private static final Logger LOG = LoggerFactory.getLogger(OpendaylightToaster.class);
 
@@ -67,8 +65,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<OpendaylightToaster> dataTreeChangeListenerRegistration;
 
     private final ExecutorService executor;
 
@@ -83,16 +82,29 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti
     // 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;
+
+        dataProvider.registerDataTreeChangeListener(new DataTreeIdentifier<Toaster>(
+                LogicalDatastoreType.CONFIGURATION, OpendaylightToaster.TOASTER_IID), this);
+
         setToasterStatusUp( null );
     }
 
@@ -105,47 +117,55 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti
         executor.shutdown();
 
         if (dataProvider != null) {
-            WriteTransaction t = dataProvider.newWriteOnlyTransaction();
-            t.delete(LogicalDatastoreType.OPERATIONAL,TOASTER_IID);
-            ListenableFuture<RpcResult<TransactionStatus>> future = t.commit();
-            Futures.addCallback( future, new FutureCallback<RpcResult<TransactionStatus>>() {
+            dataTreeChangeListenerRegistration.close();
+
+            WriteTransaction tx = dataProvider.newWriteOnlyTransaction();
+            tx.delete(LogicalDatastoreType.OPERATIONAL,TOASTER_IID);
+            Futures.addCallback( tx.submit(), new FutureCallback<Void>() {
                 @Override
-                public void onSuccess( RpcResult<TransactionStatus> 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.
         // 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<InstanceIdentifier<?>, 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<DataTreeModification<Toaster>> changes) {
+        for(DataTreeModification<Toaster> change: changes) {
+            DataObjectModification<Toaster> 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());
             }
         }
     }
@@ -163,8 +183,7 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti
         }
 
         // Always return success from the cancel toast call.
-        return Futures.immediateFuture( Rpcs.<Void> getRpcResult( true,
-                                        Collections.<RpcError>emptyList() ) );
+        return Futures.immediateFuture( RpcResultBuilder.<Void> success().build() );
     }
 
     /**
@@ -176,46 +195,43 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti
 
         final SettableFuture<RpcResult<Void>> futureResult = SettableFuture.create();
 
-        checkStatusAndMakeToast( input, futureResult );
+        checkStatusAndMakeToast( input, futureResult, toasterAppConfig.getMaxMakeToastTries() );
 
         return futureResult;
     }
 
-    private List<RpcError> makeToasterOutOfBreadError() {
-        return Arrays.asList(
-                RpcErrors.getRpcError( "out-of-stock", "resource-denied", null, null,
-                                       "Toaster is out of bread",
-                                       ErrorType.APPLICATION, null ) );
+    private RpcError makeToasterOutOfBreadError() {
+        return RpcResultBuilder.newError( ErrorType.APPLICATION, "resource-denied",
+                "Toaster is out of bread", "out-of-stock", null, null );
     }
 
-    private List<RpcError> makeToasterInUseError() {
-        return Arrays.asList(
-            RpcErrors.getRpcError( "", "in-use", null, ErrorSeverity.WARNING,
-                                   "Toaster is busy", ErrorType.APPLICATION, null ) );
+    private RpcError makeToasterInUseError() {
+        return RpcResultBuilder.newWarning( ErrorType.APPLICATION, "in-use",
+                "Toaster is busy", null, null, null );
     }
 
     private void checkStatusAndMakeToast( final MakeToastInput input,
-                                          final SettableFuture<RpcResult<Void>> futureResult ) {
+                                          final SettableFuture<RpcResult<Void>> 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<Optional<DataObject>> readFuture =
+        ListenableFuture<Optional<Toaster>> readFuture =
                                           tx.read( LogicalDatastoreType.OPERATIONAL, TOASTER_IID );
 
-        final ListenableFuture<RpcResult<TransactionStatus>> commitFuture =
-            Futures.transform( readFuture, new AsyncFunction<Optional<DataObject>,
-                                                                   RpcResult<TransactionStatus>>() {
+        final ListenableFuture<Void> commitFuture =
+            Futures.transform( readFuture, new AsyncFunction<Optional<Toaster>,Void>() {
 
                 @Override
-                public ListenableFuture<RpcResult<TransactionStatus>> apply(
-                        Optional<DataObject> toasterData ) throws Exception {
+                public ListenableFuture<Void> apply(
+                        final Optional<Toaster> 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 );
@@ -225,8 +241,8 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti
                         if( outOfBread() ) {
                             LOG.debug( "Toaster is out of bread" );
 
-                            return Futures.immediateFuture( Rpcs.<TransactionStatus>getRpcResult(
-                                       false, null, makeToasterOutOfBreadError() ) );
+                            return Futures.immediateFailedCheckedFuture(
+                                    new TransactionCommitFailedException( "", makeToasterOutOfBreadError() ) );
                         }
 
                         LOG.debug( "Setting Toaster status to Down" );
@@ -236,7 +252,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!" );
@@ -244,52 +260,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( Rpcs.<TransactionStatus>getRpcResult(
-                            false, null, makeToasterInUseError() ) );
+                    return Futures.immediateFailedCheckedFuture(
+                            new TransactionCommitFailedException( "", makeToasterInUseError() ) );
                 }
         } );
 
-        Futures.addCallback( commitFuture, new FutureCallback<RpcResult<TransactionStatus>>() {
+        Futures.addCallback( commitFuture, new FutureCallback<Void>() {
             @Override
-            public void onSuccess( RpcResult<TransactionStatus> 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( Rpcs.<Void>getRpcResult( false, null, result.getErrors() ) );
-                }
+            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.<Void> 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.
-                    futureResult.set( Rpcs.<Void> getRpcResult( false, null, Arrays.asList(
-                        RpcErrors.getRpcError( null, null, null, ErrorSeverity.ERROR,
-                                               ex.getMessage(),
-                                               ErrorType.APPLICATION, ex ) ) ) );
+                    // Probably already making toast.
+                    futureResult.set( RpcResultBuilder.<Void> failed()
+                            .withRpcErrors( ((TransactionCommitFailedException)ex).getErrorList() )
+                            .build() );
                 }
             }
         } );
@@ -309,10 +317,10 @@ 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(Rpcs.<Void> getRpcResult(true, Collections.<RpcError>emptyList()));
+        return Futures.immediateFuture( RpcResultBuilder.<Void> success().build() );
     }
 
     /**
@@ -337,20 +345,14 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti
         WriteTransaction tx = dataProvider.newWriteOnlyTransaction();
         tx.put( LogicalDatastoreType.OPERATIONAL,TOASTER_IID, buildToaster( ToasterStatus.Up ) );
 
-        ListenableFuture<RpcResult<TransactionStatus>> commitFuture = tx.commit();
-
-        Futures.addCallback( commitFuture, new FutureCallback<RpcResult<TransactionStatus>>() {
+        Futures.addCallback( tx.submit(), new FutureCallback<Void>() {
             @Override
-            public void onSuccess( RpcResult<TransactionStatus> 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 );
@@ -358,7 +360,7 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti
                 notifyCallback( false );
             }
 
-            void notifyCallback( boolean result ) {
+            void notifyCallback( final boolean result ) {
                 if( resultCallback != null ) {
                     resultCallback.apply( result );
                 }
@@ -401,7 +403,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.
@@ -410,14 +412,13 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti
 
             setToasterStatusUp( new Function<Boolean,Void>() {
                 @Override
-                public Void apply( Boolean result ) {
+                public Void apply( final Boolean result ) {
 
                     currentMakeToastTask.set( null );
 
                     LOG.debug("Toast done");
 
-                    futureResult.set( Rpcs.<Void>getRpcResult( true, null,
-                                                          Collections.<RpcError>emptyList() ) );
+                    futureResult.set( RpcResultBuilder.<Void>success().build() );
 
                     return null;
                 }