第5部分:为ToasterService添加一个消费者

5部分:ToasterService添加一个消费者——让我们做早餐!

我们已经看到了如何使用RestConf访问ToasterService RPC方法。在本节中,我们将展示如何从内部控制器以编程方式访问ToasterService

我们将创建一个名为KitchenService的新服务,它提供了一个方法来做早餐(这是位于sample-toaster-consumer项目中)。此服务将访问ToasterService提供早餐的烤面包。

KitchenService定义了一个更高级别的服务为做一个完整的早餐。这个很好地展示了“service chaining”,消费者的一个或多个服务也是另一个服务提供者。这个例子只会调用到‘toast’服务,但可以看到,它可以扩展到eggs”服务也可以是添加一个“coffee”服务等。

1.1 定义KitchenService接口

为了简便起见,我们将手工编写KitchenService数据模型和接口,而不是在yang文件中定义。在真正kitchenService模型中您可能想在yang文件中定义kitchenService,去获得由MDSAL提供的自动生成类和开箱即用的功能的好处。对于这个示例,我们定义一个枚举类型和接口的java文件在src /main/ java下,在包org.opendaylight.controller.sample.kitchen.api中。

1. //EggsType.java  

1. public enum EggsType {

2.     SCRAMBLED,

3.     OVER_EASY,

4.     POACHED

5. }

 

1. //KitchenService.java 

6. public interface KitchenService {

7.   

8.     Future> makeBreakfast( EggsType eggs, Class toast, int toastDoneness );

9.    

10. }

我们的早餐只包括简单的鸡蛋和烤面包——一个完整的早餐也包括熏肉或香肠和咖啡。早餐鸡蛋、肉、咖啡等也可以单独的分配不同的数据模型与相应的服务,ToasterService——我们把它留给读者作为练习。

1.2 定义KitchenService实现

接下来,我们创建一个类KitchenServiceImp,来实现接口和访问的ToasterService去烤面包:

1. public class KitchenServiceImpl implements KitchenService {

11.  

12.     private static final Logger log = LoggerFactory.getLogger( KitchenServiceImpl.class );

13.  

14.     private final ToasterService toaster;

15.  

16.     public KitchenServiceImpl(ToasterService toaster) {

17.         this.toaster = toaster;

18.     }

19.  

20.     @Override

21.     public Future> makeBreakfast( EggsType eggs, Class toast, int toastDoneness ) {

22.   

23.         // Call makeToast and use JdkFutureAdapters to convert the Future to a ListenableFuture,

24.         // The OpendaylightToaster impl already returns a ListenableFuture so the conversion is

25.         // actually a no-op.

26.   

27.         ListenableFuture> makeToastFuture = JdkFutureAdapters.listenInPoolThread(

28.                 makeToast( toastType, toastDoneness ), executor );

29.   

30.         ListenableFuture> makeEggsFuture = makeEggs( eggsType );

31.   

32.         // Combine the 2 ListenableFutures into 1 containing a list of RpcResults.

33.   

34.         ListenableFuture>> combinedFutures =

35.                 Futures.allAsList( ImmutableList.of( makeToastFuture, makeEggsFuture ) );

36.   

37.         // Then transform the RpcResults into 1.

38.   

39.         return Futures.transform( combinedFutures,

40.             new AsyncFunction>,RpcResult>() {

41.                 @Override

42.                 public ListenableFuture> apply( List> results )

43.                                                                                  throws Exception {

44.                     boolean atLeastOneSucceeded = false;

45.                     Builder errorList = ImmutableList.builder();

46.                     for( RpcResult result: results ) {

47.                         if( result.isSuccessful() ) {

48.                             atLeastOneSucceeded = true;

49.                         }

50.   

51.                         if( result.getErrors() != null ) {

52.                             errorList.addAll( result.getErrors() );

53.                         }

54.                     }

55.   

56.                     return Futures.immediateFuture(

57.                               Rpcs. getRpcResult( atLeastOneSucceeded, errorList.build() ) );

58.                 }

59.         } );

60.     }

61.   

62.     private ListenableFuture> makeEggs( EggsType eggsType ) {

63.   

64.         return executor.submit( new Callable>() {

65.   

66.             @Override

67.             public RpcResult call() throws Exception {

68.   

69.                 // We don't actually do anything here - just return a successful result.

70.                 return Rpcs. getRpcResult( true, Collections.emptyList() );

71.             }

72.         } );

73.     }

74.   

75.     private Future> makeToast( Class toastType,

76.                                                int toastDoneness ) {

77.         // Access the ToasterService to make the toast.

78.   

79.         MakeToastInput toastInput = new MakeToastInputBuilder()

80.             .setToasterDoneness( (long) toastDoneness )

81.             .setToasterToastType( toastType )

82.             .build();

83.   

84.         return toaster.makeToast( toastInput );

85.     }

86. }

1.3 连接KitchenService实现

类似于烤面包机供应者服务,在yang和提供初始配置xml中我们将描述一个厨房服务实现。因此MDSAL可以把这些连接起来。

定义厨房服务

kitchen-service-impl.yang中我们将定义厨房服务实现及其依赖项:

1. module kitchen-service-impl {

87.  

88.     yang-version 1;

89.     namespace "urn:opendaylight:params:xml:ns:yang:controller:config:kitchen-service:impl";

90.     prefix "kitchen-service-impl";

91.  

92.     import config { prefix config; revision-date 2013-04-05; }

93.     import rpc-context { prefix rpcx; revision-date 2013-06-17; }

94.  

95.     import opendaylight-md-sal-binding { prefix mdsal; revision-date 2013-10-28; }

96.  

97.     description

98.         "This module contains the base YANG definitions for

99.         kitchen-service impl implementation.";

100.  

101.     revision "2014-01-31" {

102.         description

103.             "Initial revision.";

104.     }

105.  

106.     // This is the definition of kitchen service interface identity.

107.     identity kitchen-service {

108.         base "config:service-type";

109.         config:java-class "org.opendaylight.controller.sample.kitchen.api.KitchenService";

110.     }

111.  

112.     // This is the definition of kitchen service implementation module identity. 

113.     identity kitchen-service-impl {

114.             base config:module-type;

115.             config:provided-service kitchen-service;

116.             config:java-name-prefix KitchenService;

117.     }

118.  

119.     augment "/config:modules/config:module/config:configuration" {

120.         case kitchen-service-impl {

121.             when "/config:modules/config:module/config:type = 'kitchen-service-impl'";

122.  

123.             container rpc-registry {

124.                 uses config:service-ref {

125.                     refine type {

126.                         mandatory true;

127.                         config:required-identity mdsal:binding-rpc-registry;

128.                     }

129.                 }

130.             }

131.         }

132.     }

133. }

这类似于toaster-provider-impl yang,除了我们也定义一个kitchen-service 服务类型的身份,这为厨房服务接口定义了一个全局标识符,并且可以被引用。config:java-class性能指定KitchenService  java接口。

kitchen-service的身份将被用于配置子系统去通知提供的服务实例kitchen-service-impl模块作为OSGi服务KitchenService java接口。

 

实现kitchenservicemodule

在运行'mvn clean install'之后,几个源文件将生成类似于the toaster provider,我们只需要修改KitchenServiceModule.createInstance()方法来实例化KitchenServiceImpl实例并且连接他:

1.  @Override

134.     public java.lang.AutoCloseable createInstance() {

135.         ToasterService toasterService = getRpcRegistryDependency().getRpcService(ToasterService.class);

136.  

137.         final KitchenServiceImpl kitchenService = new KitchenServiceImpl(toasterService);

138.  

139.         final class AutoCloseableKitchenService implements KitchenService, AutoCloseable {

140.  

141.             @Override

142.             public void close() throws Exception {

143.             }

144.  

145.             @Override

146.             public Future> makeBreakfast( EggsType eggs, Class toast, int toastDoneness ) {

147.                 return kitchenService.makeBreakfast( eggs, toast, toastDoneness );

148.             }

149.         }

150.  

151.         AutoCloseable ret = new AutoCloseableKitchenService();

152.         return ret;

153.     }

因为我们指定的为在kitchen-service-impl.yang中的厨房服务实现模块提供服务,我们必须返回一个AutoCloseable实例并且也实现了KitchenService接口。否则这将导致一个失败的配置子系统。

定义初始配置

最后,在初始配置xml创建之前把厨房服务和模块定义添加到其中:

1. 

154.    

155.        

156.            

157.               ...

158.               

159.                  

160.                     kitchen:kitchen-service-impl

161.                  

162.                  kitchen-service-impl

163.                  

164.  

165.                  

166.                     binding:binding-rpc-registry

167.                     binding-rpc-broker

168.                  

169.                

170.            

171.            

172.                

173.                    

174.                        kitchen:kitchen-service

175.                    

176.                    

177.                        kitchen-service

178.                        /modules/module[type='kitchen-service-impl'][name='kitchen-service-impl']

179.                    

180.                

181.            

182.        

183.    

184.    

185.    

186.        urn:opendaylight:params:xml:ns:yang:controller:config:kitchen-service:impl?module=kitchen-service-impl&revision=2014-01-31

187.        urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider:impl?module=toaster-provider-impl&revision=2014-01-31

188.    

189. 

kitchen-service-impl模块定义类似于toaster-provider-impl模块概述。

我们还为kitchen-service接口定义了一个服务入口,用来告知config subsystem去通知OSGI服务。这个type元素指的是完整的kitchen-service标识并且是指定服务的接口类型。Instance元素指定服务实例信息。Name元素指定一个独一无二的服务名称,provider元素指定的路径形式/modules/module/name来定位kitchen-service-impl模块,通过模块名称提供了服务实例。在运行时,实际的服务实例被实例化,并被插入在config/services/service/ hierarchy结点下并通知OSGI

1.4 添加JMX RPC做早餐

在这一点上,如果我们部署kitchen服务我们不能通过restconf去访问它,因为我们没有为它定义一个yang数据模型。据推测,真正的服务,会有java客户去消耗它。取而代之的是我们可以利用JMX训练kitchen服务来做早餐。

通过JMX  MD-SAL也支持RPC调用。我们只是在yang中简单定义了RPC并且通过augmentation把它与config:state绑定起来,就像我们之前为toaster provider中的clearToastsMade RPC做的一样。

我们将会为kitchen-service-impl.yang添加一个make-scrambled-with-wheat RPC定义。这个调用不接受输入和hard-codes

1.  augment "/config:modules/config:module/config:state" {

190.         case kitchen-service-impl {

191.             when "/config:modules/config:module/config:type = 'kitchen-service-impl'";

192.  

193.             rpcx:rpc-context-instance "make-scrambled-with-wheat-rpc";

194.         }

195.     }

196.  

197.     identity make-scrambled-with-wheat-rpc;

198.  

199.     rpc make-scrambled-with-wheat  {

200.         description

201.           "Shortcut JMX call to make breakfast with scrambled eggs and wheat toast for testing.";

202.  

203.         input {

204.             uses rpcx:rpc-context-ref {

205.                 refine context-instance {

206.                     rpcx:rpc-context-instance make-scrambled-with-wheat-rpc;

207.                 }

208.             }

209.         }

210.         output {

211.             leaf result {

212.                 type boolean;

213.             }

214.         }

215.     }

重新生成源后,修改KitchenServiceImpl 实现生成的接口KitchenServiceRuntimeMXBean,它定义了makeScrambledWithWheat()方法。

1. @Override

216.     public Boolean makeScrambledWithWheat() {

217.         try {

218.             // This call has to block since we must return a result to the JMX client.

219.             RpcResult result = makeBreakfast( EggsType.SCRAMBLED, WheatBread.class, 2 ).get();

220.             if( result.isSuccessful() ) {

221.                 log.info( "makeBreakfast succeeded" );

222.             } else {

223.                 log.warn( "makeBreakfast failed: " + result.getErrors() );

224.             }

225.   

226.             return result.isSuccessful();

227.   

228.         } catch( InterruptedException | ExecutionException e ) {

229.             log.warn( "An error occurred while maing breakfast: " + e );

230.         }

231.   

232.         return Boolean.FALSE;

233.     }

接下来,修改KitchenServiceModule.createInstance()来使用JMX注册KitchenService,然后在AutoCloseable wrapper内关闭它。

1.  final KitchenServiceRuntimeRegistration runtimeReg =

234.                                  getRootRuntimeBeanRegistratorWrapper().register( kitchenService );

235.    ...

236.    final class AutoCloseableKitchenService implements AutoCloseable {

237.        @Override

238.        public void close() throws Exception {

239.            ...

240.            runtimeReg.close();            

241.        }

242.    }

243.    ...

1.5 通过JMX做早餐

我们可以通过JConsole来访问kitchen-service-impl MBean正如我们前面对toaster-service-impl MBean所做的一样。

l 导航到MBeans选项卡。

l 扩展org.opendaylight.controller->RuntimeBean->kitchen-service-impl->kitchen-service-imp->Operations结点。

l 点击makeScrambledWithWheat按钮。

l 来验证实际面包,扩展org.opendaylight.controller->RuntimeBean->toaster-provider-impl->toaster-provider-imp ->Attributes并检查ToastsMade的值。

你可能感兴趣的:(SDN,toaster,opendaylight,mdsal,SDN,controller,mdsal,opendaylight,ToasterService)