Merge "Deprecate model-flow-management as it was never used and is confusing people."
[controller.git] / opendaylight / md-sal / samples / toaster-consumer / src / main / java / org / opendaylight / controller / sample / kitchen / impl / KitchenServiceImpl.java
1 package org.opendaylight.controller.sample.kitchen.impl;
2
3 import java.util.Arrays;
4 import java.util.Collections;
5 import java.util.List;
6 import java.util.concurrent.Callable;
7 import java.util.concurrent.ExecutionException;
8 import java.util.concurrent.Executors;
9 import java.util.concurrent.Future;
10 import org.opendaylight.controller.config.yang.config.kitchen_service.impl.KitchenServiceRuntimeMXBean;
11 import org.opendaylight.controller.sal.common.util.RpcErrors;
12 import org.opendaylight.controller.sal.common.util.Rpcs;
13 import org.opendaylight.controller.sample.kitchen.api.EggsType;
14 import org.opendaylight.controller.sample.kitchen.api.KitchenService;
15 import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.MakeToastInput;
16 import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.MakeToastInputBuilder;
17 import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToastType;
18 import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterListener;
19 import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterOutOfBread;
20 import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterRestocked;
21 import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterService;
22 import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.WheatBread;
23 import org.opendaylight.yangtools.yang.common.RpcError.ErrorSeverity;
24 import org.opendaylight.yangtools.yang.common.RpcError;
25 import org.opendaylight.yangtools.yang.common.RpcResult;
26 import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 import com.google.common.collect.ImmutableList;
31 import com.google.common.collect.ImmutableList.Builder;
32 import com.google.common.util.concurrent.AsyncFunction;
33 import com.google.common.util.concurrent.Futures;
34 import com.google.common.util.concurrent.JdkFutureAdapters;
35 import com.google.common.util.concurrent.ListenableFuture;
36 import com.google.common.util.concurrent.ListeningExecutorService;
37 import com.google.common.util.concurrent.MoreExecutors;
38
39 public class KitchenServiceImpl implements KitchenService, KitchenServiceRuntimeMXBean, ToasterListener {
40
41     private static final Logger log = LoggerFactory.getLogger( KitchenServiceImpl.class );
42
43     private final ToasterService toaster;
44
45     private final ListeningExecutorService executor =
46                                    MoreExecutors.listeningDecorator( Executors.newCachedThreadPool() );
47
48     private volatile boolean toasterOutOfBread;
49
50     public KitchenServiceImpl(ToasterService toaster) {
51         this.toaster = toaster;
52     }
53
54     @Override
55     public Future<RpcResult<Void>> makeBreakfast( EggsType eggsType, Class<? extends ToastType> toastType,
56                                                   int toastDoneness ) {
57
58         // Call makeToast and use JdkFutureAdapters to convert the Future to a ListenableFuture,
59         // The OpendaylightToaster impl already returns a ListenableFuture so the conversion is
60         // actually a no-op.
61
62         ListenableFuture<RpcResult<Void>> makeToastFuture = JdkFutureAdapters.listenInPoolThread(
63                 makeToast( toastType, toastDoneness ), executor );
64
65         ListenableFuture<RpcResult<Void>> makeEggsFuture = makeEggs( eggsType );
66
67         // Combine the 2 ListenableFutures into 1 containing a list of RpcResults.
68
69         ListenableFuture<List<RpcResult<Void>>> combinedFutures =
70                 Futures.allAsList( ImmutableList.of( makeToastFuture, makeEggsFuture ) );
71
72         // Then transform the RpcResults into 1.
73
74         return Futures.transform( combinedFutures,
75             new AsyncFunction<List<RpcResult<Void>>,RpcResult<Void>>() {
76                 @Override
77                 public ListenableFuture<RpcResult<Void>> apply( List<RpcResult<Void>> results )
78                                                                                  throws Exception {
79                     boolean atLeastOneSucceeded = false;
80                     Builder<RpcError> errorList = ImmutableList.builder();
81                     for( RpcResult<Void> result: results ) {
82                         if( result.isSuccessful() ) {
83                             atLeastOneSucceeded = true;
84                         }
85
86                         if( result.getErrors() != null ) {
87                             errorList.addAll( result.getErrors() );
88                         }
89                     }
90
91                     return Futures.immediateFuture(
92                               Rpcs.<Void> getRpcResult( atLeastOneSucceeded, errorList.build() ) );
93                 }
94         } );
95     }
96
97     private ListenableFuture<RpcResult<Void>> makeEggs( EggsType eggsType ) {
98
99         return executor.submit( new Callable<RpcResult<Void>>() {
100
101             @Override
102             public RpcResult<Void> call() throws Exception {
103
104                 // We don't actually do anything here - just return a successful result.
105                 return Rpcs.<Void> getRpcResult( true, Collections.<RpcError>emptyList() );
106             }
107         } );
108     }
109
110     private Future<RpcResult<Void>> makeToast( Class<? extends ToastType> toastType,
111                                                int toastDoneness ) {
112
113         if( toasterOutOfBread )
114         {
115             log.info( "We're out of toast but we can make eggs" );
116             return Futures.immediateFuture( Rpcs.<Void> getRpcResult( true,
117                        Arrays.asList( RpcErrors.getRpcError( "", "partial-operation", null,
118                                           ErrorSeverity.WARNING,
119                                           "Toaster is out of bread but we can make you eggs",
120                                           ErrorType.APPLICATION, null ) ) ) );
121         }
122
123         // Access the ToasterService to make the toast.
124
125         MakeToastInput toastInput = new MakeToastInputBuilder()
126             .setToasterDoneness( (long) toastDoneness )
127             .setToasterToastType( toastType )
128             .build();
129
130         return toaster.makeToast( toastInput );
131     }
132
133     @Override
134     public Boolean makeScrambledWithWheat() {
135         try {
136             // This call has to block since we must return a result to the JMX client.
137             RpcResult<Void> result = makeBreakfast( EggsType.SCRAMBLED, WheatBread.class, 2 ).get();
138             if( result.isSuccessful() ) {
139                 log.info( "makeBreakfast succeeded" );
140             } else {
141                 log.warn( "makeBreakfast failed: " + result.getErrors() );
142             }
143
144             return result.isSuccessful();
145
146         } catch( InterruptedException | ExecutionException e ) {
147             log.warn( "An error occurred while maing breakfast: " + e );
148         }
149
150         return Boolean.FALSE;
151     }
152
153     /**
154      * Implemented from the ToasterListener interface.
155      */
156     @Override
157     public void onToasterOutOfBread( ToasterOutOfBread notification ) {
158         log.info( "ToasterOutOfBread notification" );
159         toasterOutOfBread = true;
160     }
161
162     /**
163      * Implemented from the ToasterListener interface.
164      */
165     @Override
166     public void onToasterRestocked( ToasterRestocked notification ) {
167         log.info( "ToasterRestocked notification - amountOfBread: " + notification.getAmountOfBread() );
168         toasterOutOfBread = false;
169     }
170 }