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