See https://bugs.opendaylight.org/show_bug.cgi?id=809 for details.
Need someone to commit this!
Change-Id: Icb9697de77d844d816ec61a0e7a6ac2100d185ae
Signed-off-by: tpantelis <tpanteli@brocade.com>
<data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
<module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider:impl">
- prefix:toaster-provider-impl
+ <type xmlns:toaster="urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider:impl">
+ toaster:toaster-provider-impl
</type>
<name>toaster-provider-impl</name>
<name>binding-rpc-broker</name>
</rpc-registry>
+ <data-broker>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
+ <name>binding-data-broker</name>
+ </data-broker>
+
<notification-service>
<type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
binding:binding-notification-service
</module>
<module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer:impl">
- prefix:toaster-consumer-impl
+ <type xmlns:kitchen="urn:opendaylight:params:xml:ns:yang:controller:config:kitchen-service:impl">
+ kitchen:kitchen-service-impl
</type>
- <name>toaster-consumer-impl</name>
+ <name>kitchen-service-impl</name>
<rpc-registry>
<type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-rpc-registry</type>
</notification-service>
</module>
</modules>
-
+
<services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
<service>
- <type xmlns:toaster="urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider">toaster:toaster-provider</type>
- <instance>
- <name>toaster-provider</name>
- <provider>/modules/module[type='toaster-provider-impl'][name='toaster-provider-impl']</provider>
- </instance>
- </service>
- <service>
- <type xmlns:toaster="urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer">toaster:toaster-consumer</type>
+ <type xmlns:kitchen="urn:opendaylight:params:xml:ns:yang:controller:config:kitchen-service:impl">
+ kitchen:kitchen-service
+ </type>
<instance>
- <name>toaster-consumer</name>
- <provider>/modules/module[type='toaster-consumer-impl'][name='toaster-consumer-impl']</provider>
+ <name>kitchen-service</name>
+ <provider>/modules/module[type='kitchen-service-impl'][name='kitchen-service-impl']</provider>
</instance>
</service>
</services>
</configuration>
<required-capabilities>
- <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&revision=2013-10-28</capability>
- <capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer?module=toaster-consumer&revision=2014-01-31</capability>
- <capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer:impl?module=toaster-consumer-impl&revision=2014-01-31</capability>
- <capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider?module=toaster-provider&revision=2014-01-31</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:config:kitchen-service:impl?module=kitchen-service-impl&revision=2014-01-31</capability>
<capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider:impl?module=toaster-provider-impl&revision=2014-01-31</capability>
</required-capabilities>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
- <configuration>
- <instructions>
- <Export-Package>org.opendaylight.controller.sample.toaster.provider.api,
- org.opendaylight.controller.config.yang.toaster-consumer,</Export-Package>
- <Import-Package>*</Import-Package>
- </instructions>
- </configuration>
</plugin>
<plugin>
<groupId>org.opendaylight.yangtools</groupId>
--- /dev/null
+/**
+* Generated file
+
+* Generated from: yang module name: toaster-consumer-impl yang module local name: toaster-consumer-impl
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Wed Feb 05 11:31:30 CET 2014
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.controller.config.yang.config.kitchen_service.impl;
+
+import org.opendaylight.controller.config.yang.config.kitchen_service.impl.AbstractKitchenServiceModule;
+import org.opendaylight.controller.sample.kitchen.api.EggsType;
+import org.opendaylight.controller.sample.kitchen.api.KitchenService;
+import org.opendaylight.controller.sample.kitchen.impl.KitchenServiceImpl;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToastType;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterService;
+import org.opendaylight.yangtools.concepts.Registration;
+import org.opendaylight.yangtools.yang.binding.NotificationListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+*
+*/
+public final class KitchenServiceModule extends AbstractKitchenServiceModule {
+ private static final Logger log = LoggerFactory.getLogger(KitchenServiceModule.class);
+
+ public KitchenServiceModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+ super(identifier, dependencyResolver);
+ }
+
+ public KitchenServiceModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
+ KitchenServiceModule oldModule, java.lang.AutoCloseable oldInstance) {
+
+ super(identifier, dependencyResolver, oldModule, oldInstance);
+ }
+
+ @Override
+ protected void customValidation(){
+ // No need to validate dependencies, since all dependencies have mandatory true flag in yang
+ // config-subsystem will perform the validation
+ }
+
+ @Override
+ public java.lang.AutoCloseable createInstance() {
+ ToasterService toasterService = getRpcRegistryDependency().getRpcService(ToasterService.class);
+
+ final KitchenServiceImpl kitchenService = new KitchenServiceImpl(toasterService);
+
+ final Registration<NotificationListener> toasterListenerReg =
+ getNotificationServiceDependency().registerNotificationListener( kitchenService );
+
+ final KitchenServiceRuntimeRegistration runtimeReg =
+ getRootRuntimeBeanRegistratorWrapper().register( kitchenService );
+
+ final class AutoCloseableKitchenService implements KitchenService, AutoCloseable {
+
+ @Override
+ public void close() throws Exception {
+ toasterListenerReg.close();
+ runtimeReg.close();
+ log.info("Toaster consumer (instance {}) torn down.", this);
+ }
+
+ @Override
+ public boolean makeBreakfast( EggsType eggs, Class<? extends ToastType> toast, int toastDoneness ) {
+ return kitchenService.makeBreakfast( eggs, toast, toastDoneness );
+ }
+ }
+
+ AutoCloseable ret = new AutoCloseableKitchenService();
+ log.info("KitchenService (instance {}) initialized.", ret );
+ return ret;
+ }
+}
*
* Do not modify this file unless it is present under src/main directory
*/
-package org.opendaylight.controller.config.yang.config.toaster_consumer.impl;
+package org.opendaylight.controller.config.yang.config.kitchen_service.impl;
+
+import org.opendaylight.controller.config.yang.config.kitchen_service.impl.AbstractKitchenServiceModuleFactory;
/**
*
*/
-public class ToasterConsumerModuleFactory extends org.opendaylight.controller.config.yang.config.toaster_consumer.impl.AbstractToasterConsumerModuleFactory
+public class KitchenServiceModuleFactory extends AbstractKitchenServiceModuleFactory
{
+++ /dev/null
-/**
-* Generated file
-
-* Generated from: yang module name: toaster-consumer-impl yang module local name: toaster-consumer-impl
-* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
-* Generated at: Wed Feb 05 11:31:30 CET 2014
-*
-* Do not modify this file unless it is present under src/main directory
-*/
-package org.opendaylight.controller.config.yang.config.toaster_consumer.impl;
-
-import org.opendaylight.controller.sal.binding.api.NotificationListener;
-import org.opendaylight.controller.sample.toaster.provider.api.ToastConsumer;
-import org.opendaylight.controller.sample.toaster.provider.impl.ToastConsumerImpl;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToastDone;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToastType;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterService;
-import org.opendaylight.yangtools.concepts.Registration;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
-*
-*/
-public final class ToasterConsumerModule extends org.opendaylight.controller.config.yang.config.toaster_consumer.impl.AbstractToasterConsumerModule
- {
- private static final Logger log = LoggerFactory.getLogger(ToasterConsumerModule.class);
-
- public ToasterConsumerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
- super(identifier, dependencyResolver);
- }
-
- public ToasterConsumerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
- ToasterConsumerModule oldModule, java.lang.AutoCloseable oldInstance) {
-
- super(identifier, dependencyResolver, oldModule, oldInstance);
- }
-
- @Override
- protected void customValidation(){
- // No need to validate dependencies, since all dependencies have mandatory true flag in yang
- // config-subsystem will perform the validation
- }
-
- @Override
- public java.lang.AutoCloseable createInstance() {
- ToasterService toasterService = getRpcRegistryDependency().getRpcService(ToasterService.class);
-
- final ToastConsumerImpl consumer = new ToastConsumerImpl(toasterService);
- final Registration<NotificationListener<ToastDone>> notificationRegistration = getNotificationServiceDependency()
- .registerNotificationListener(ToastDone.class, consumer);
-
- final ToasterConsumerRuntimeRegistration runtimeRegistration = getRootRuntimeBeanRegistratorWrapper().register(consumer);
-
- final class AutoCloseableToastConsumer implements AutoCloseable, ToastConsumer {
-
- @Override
- public void close() throws Exception {
- runtimeRegistration.close();
- notificationRegistration.close();
- log.info("Toaster consumer (instance {}) torn down.", this);
- }
-
- @Override
- public boolean createToast(Class<? extends ToastType> type, int doneness) {
- return consumer.createToast(type, doneness);
- }
- }
-
- AutoCloseable ret = new AutoCloseableToastConsumer();
- log.info("Toaster consumer (instance {}) initialized.", ret);
- return ret;
- }
-}
--- /dev/null
+package org.opendaylight.controller.sample.kitchen.api;
+
+public enum EggsType {
+ SCRAMBLED,
+ OVER_EASY,
+ POACHED
+}
--- /dev/null
+package org.opendaylight.controller.sample.kitchen.api;
+
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToastType;
+
+public interface KitchenService {
+ boolean makeBreakfast( EggsType eggs, Class<? extends ToastType> toast, int toastDoneness );
+}
--- /dev/null
+package org.opendaylight.controller.sample.kitchen.impl;
+
+import java.util.concurrent.ExecutionException;
+
+import org.opendaylight.controller.config.yang.config.kitchen_service.impl.KitchenServiceRuntimeMXBean;
+import org.opendaylight.controller.sample.kitchen.api.EggsType;
+import org.opendaylight.controller.sample.kitchen.api.KitchenService;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.MakeToastInputBuilder;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToastType;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterListener;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterOutOfBread;
+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.ToasterService;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.WheatBread;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class KitchenServiceImpl implements KitchenService, KitchenServiceRuntimeMXBean, ToasterListener {
+
+ private static final Logger log = LoggerFactory.getLogger( KitchenServiceImpl.class );
+
+ private final ToasterService toaster;
+
+ private volatile boolean toasterOutOfBread;
+
+ public KitchenServiceImpl(ToasterService toaster) {
+ this.toaster = toaster;
+ }
+
+ @Override
+ public boolean makeBreakfast( EggsType eggs, Class<? extends ToastType> toast, int toastDoneness ) {
+
+ if( toasterOutOfBread )
+ {
+ log.info( "We're out of toast but we can make eggs" );
+ return true;
+ }
+
+ // Access the ToasterService to make the toast.
+ // We don't actually make the eggs for this example - sorry.
+ MakeToastInputBuilder toastInput = new MakeToastInputBuilder();
+ toastInput.setToasterDoneness( (long) toastDoneness);
+ toastInput.setToasterToastType( toast );
+
+ try {
+ RpcResult<Void> result = toaster.makeToast( toastInput.build() ).get();
+
+ if( result.isSuccessful() ) {
+ log.info( "makeToast succeeded" );
+ } else {
+ log.warn( "makeToast failed: " + result.getErrors() );
+ }
+
+ return result.isSuccessful();
+ } catch( InterruptedException | ExecutionException e ) {
+ log.warn( "Error occurred during toast creation" );
+ }
+ return false;
+ }
+
+ @Override
+ public Boolean makeScrambledWithWheat() {
+ return makeBreakfast( EggsType.SCRAMBLED, WheatBread.class, 2 );
+ }
+
+ /**
+ * Implemented from the ToasterListener interface.
+ */
+ @Override
+ public void onToasterOutOfBread( ToasterOutOfBread notification ) {
+ log.info( "ToasterOutOfBread notification" );
+ toasterOutOfBread = true;
+ }
+
+ /**
+ * Implemented from the ToasterListener interface.
+ */
+ @Override
+ public void onToasterRestocked( ToasterRestocked notification ) {
+ log.info( "ToasterRestocked notification - amountOfBread: " + notification.getAmountOfBread() );
+ toasterOutOfBread = false;
+ }
+}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.sample.toaster.provider.api;
-
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToastType;
-
-public interface ToastConsumer {
-
- boolean createToast(Class<? extends ToastType> type,int doneness);
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.sample.toaster.provider.impl;
-
-import java.util.concurrent.ExecutionException;
-
-import org.opendaylight.controller.config.yang.config.toaster_consumer.impl.ToasterConsumerRuntimeMXBean;
-import org.opendaylight.controller.sal.binding.api.NotificationListener;
-import org.opendaylight.controller.sample.toaster.provider.api.ToastConsumer;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.*;
-import org.opendaylight.yangtools.yang.common.RpcResult;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class ToastConsumerImpl implements
- ToastConsumer,
- NotificationListener<ToastDone>,ToasterConsumerRuntimeMXBean {
-
- private static final Logger log = LoggerFactory.getLogger(ToastConsumerImpl.class);
-
- private ToasterService toaster;
-
- public ToastConsumerImpl(ToasterService toaster) {
- this.toaster = toaster;
- }
-
- @Override
- public boolean createToast(Class<? extends ToastType> type, int doneness) {
- MakeToastInputBuilder toastInput = new MakeToastInputBuilder();
- toastInput.setToasterDoneness((long) doneness);
- toastInput.setToasterToastType(type);
-
- try {
- RpcResult<Void> result = toaster.makeToast(toastInput.build()).get();
-
- if (result.isSuccessful()) {
- log.trace("Toast was successfully finished");
- } else {
- log.warn("Toast was not successfully finished");
- }
- return result.isSuccessful();
- } catch (InterruptedException | ExecutionException e) {
- log.warn("Error occurred during toast creation");
- }
- return false;
-
- }
-
- @Override
- public void onNotification(ToastDone notification) {
- log.trace("ToastDone Notification Received: {} ",notification.getToastStatus());
- }
-
- @Override
- public Boolean makeHashBrownToast(Integer doneness) {
- return createToast(HashBrown.class, doneness);
- }
-}
// vi: set smarttab et sw=4 tabstop=4:
-module toaster-consumer-impl {
+module kitchen-service-impl {
yang-version 1;
- namespace "urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer:impl";
- prefix "toaster-consumer-impl";
+ namespace "urn:opendaylight:params:xml:ns:yang:controller:config:kitchen-service:impl";
+ prefix "kitchen-service-impl";
import config { prefix config; revision-date 2013-04-05; }
import rpc-context { prefix rpcx; revision-date 2013-06-17; }
- import toaster-consumer { prefix toaster-consumer; revision-date 2014-01-31; }
import opendaylight-md-sal-binding { prefix mdsal; revision-date 2013-10-28; }
description
"This module contains the base YANG definitions for
- toaster-consumer impl implementation.";
+ kitchen-service impl implementation.";
revision "2014-01-31" {
description
"Initial revision.";
}
- // This is the definition of a service implementation
- identity toaster-consumer-impl {
+ // This is the definition of kitchen service interface identity.
+ identity kitchen-service {
+ base "config:service-type";
+ config:java-class "org.opendaylight.controller.sample.kitchen.api.KitchenService";
+ }
+
+ // This is the definition of kitchen service implementation module identity.
+ identity kitchen-service-impl {
base config:module-type;
- config:provided-service toaster-consumer:toaster-consumer;
- config:java-name-prefix ToasterConsumer;
+ config:provided-service kitchen-service;
+ config:java-name-prefix KitchenService;
}
augment "/config:modules/config:module/config:configuration" {
- case toaster-consumer-impl {
- when "/config:modules/config:module/config:type = 'toaster-consumer-impl'";
+ case kitchen-service-impl {
+ when "/config:modules/config:module/config:type = 'kitchen-service-impl'";
container rpc-registry {
uses config:service-ref {
}
}
}
-
}
}
-
+
augment "/config:modules/config:module/config:state" {
- case toaster-consumer-impl {
- when "/config:modules/config:module/config:type = 'toaster-consumer-impl'";
- rpcx:rpc-context-instance "make-hash-brown-toast-rpc";
+ case kitchen-service-impl {
+ when "/config:modules/config:module/config:type = 'kitchen-service-impl'";
+
+ rpcx:rpc-context-instance "make-scrambled-with-wheat-rpc";
}
}
- identity make-hash-brown-toast-rpc;
+ identity make-scrambled-with-wheat-rpc;
- rpc make-hash-brown-toast {
+ rpc make-scrambled-with-wheat {
+ description
+ "Shortcut JMX call to make breakfast with scrambled eggs and wheat toast for testing.";
+
input {
uses rpcx:rpc-context-ref {
refine context-instance {
- rpcx:rpc-context-instance make-hash-brown-toast-rpc;
+ rpcx:rpc-context-instance make-scrambled-with-wheat-rpc;
}
}
- leaf doneness {
- type uint16;
- }
}
+
output {
leaf result {
type boolean;
+++ /dev/null
-// vi: set smarttab et sw=4 tabstop=4:
-module toaster-consumer {
-
- yang-version 1;
- namespace "urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer";
- prefix "toaster-consumer";
-
- import config { prefix config; revision-date 2013-04-05; }
-
- description
- "This module contains the base YANG definitions for
- toaster-consumer services.";
-
- revision "2014-01-31" {
- description
- "Initial revision.";
- }
-
- // This is the definition of a service
- identity toaster-consumer {
-
- base "config:service-type";
-
- config:java-class "org.opendaylight.controller.sample.toaster.provider.api.ToastConsumer";
- }
-}
\ No newline at end of file
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.opendaylight.controller.sample.toaster.provider.api.ToastConsumer;
+import org.opendaylight.controller.sample.kitchen.api.EggsType;
+import org.opendaylight.controller.sample.kitchen.api.KitchenService;
import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.HashBrown;
import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.WhiteBread;
import org.ops4j.pax.exam.Configuration;
import javax.inject.Inject;
import javax.management.MBeanServer;
import javax.management.ObjectName;
+
import java.lang.management.ManagementFactory;
import static org.junit.Assert.assertEquals;
@Inject
@Filter(timeout=60*1000)
- ToastConsumer toastConsumer;
+ KitchenService kitchenService;
@Configuration
public Option[] config() {
public void testToaster() throws Exception {
MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer();
- ObjectName consumerOn = new ObjectName("org.opendaylight.controller:instanceName=toaster-consumer-impl,type=RuntimeBean,moduleFactoryName=toaster-consumer-impl");
ObjectName providerOn = new ObjectName("org.opendaylight.controller:instanceName=toaster-provider-impl,type=RuntimeBean,moduleFactoryName=toaster-provider-impl");
long toastsMade = (long) platformMBeanServer.getAttribute(providerOn, "ToastsMade");
boolean toasts = true;
// Make toasts using OSGi service
- toasts &= toastConsumer.createToast(HashBrown.class, 4);
- toasts &= toastConsumer.createToast(WhiteBread.class, 8);
-
- // Make toast using JMX/config-subsystem
- toasts &= (Boolean)platformMBeanServer.invoke(consumerOn, "makeHashBrownToast", new Object[]{4}, new String[]{Integer.class.getName()});
+ toasts &= kitchenService.makeBreakfast( EggsType.SCRAMBLED, HashBrown.class, 4);
+ toasts &= kitchenService.makeBreakfast( EggsType.POACHED, WhiteBread.class, 8 );
- Assert.assertTrue("Not all toasts done by " + toastConsumer, toasts);
+ Assert.assertTrue("Not all toasts done by " + kitchenService, toasts);
// Verify toasts made count on provider via JMX/config-subsystem
toastsMade = (long) platformMBeanServer.getAttribute(providerOn, "ToastsMade");
- assertEquals(3, toastsMade);
+ assertEquals(2, toastsMade);
}
}
<snapshots>
<snapshot>
<required-capabilities>
- <capability>urn:opendaylight:l2:types?module=opendaylight-l2-types&revision=2013-08-27</capability>
+ <!-- <capability>urn:opendaylight:l2:types?module=opendaylight-l2-types&revision=2013-08-27</capability>-->
<capability>
urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&revision=2013-10-28
</capability>
urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl?module=opendaylight-sal-dom-broker-impl&revision=2013-10-28
</capability>
<capability>urn:opendaylight:params:xml:ns:yang:controller:logback:config?module=config-logging&revision=2013-07-16</capability>
- <capability>urn:opendaylight:yang:extension:yang-ext?module=yang-ext&revision=2013-07-09
- </capability>
+ <!-- <capability>urn:opendaylight:yang:extension:yang-ext?module=yang-ext&revision=2013-07-09</capability>-->
<capability>
urn:opendaylight:params:xml:ns:yang:controller:md:sal:common?module=opendaylight-md-sal-common&revision=2013-10-28
</capability>
<capability>http://netconfcentral.org/ns/toaster?module=toaster&revision=2009-11-20</capability>
- <capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer?module=toaster-consumer&revision=2014-01-31</capability>
- <capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer:impl?module=toaster-consumer-impl&revision=2014-01-31</capability>
- <capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider?module=toaster-provider&revision=2014-01-31</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:config:kitchen-service:impl?module=kitchen-service-impl&revision=2014-01-31</capability>
<capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider:impl?module=toaster-provider-impl&revision=2014-01-31</capability>
</required-capabilities>
<name>binding-rpc-broker</name>
</rpc-registry>
+ <data-broker>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
+ <name>ref_binding-data-broker</name>
+ </data-broker>
+
<notification-service>
<type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
binding:binding-notification-service
</module>
<module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer:impl">
- prefix:toaster-consumer-impl
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:kitchen-service:impl">
+ prefix:kitchen-service-impl
</type>
- <name>toaster-consumer-impl</name>
+ <name>kitchen-service-impl</name>
<rpc-registry>
<type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-rpc-registry</type>
</modules>
<services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <service>
+ <type xmlns:kitchen="urn:opendaylight:params:xml:ns:yang:controller:config:kitchen-service:impl">
+ kitchen:kitchen-service
+ </type>
+ <instance>
+ <name>kitchen-service</name>
+ <provider>/modules/module[type='kitchen-service-impl'][name='kitchen-service-impl']</provider>
+ </instance>
+ </service>
<service>
<type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">
dom:schema-service
package org.opendaylight.controller.config.yang.config.toaster_provider.impl;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
import org.opendaylight.controller.sample.toaster.provider.OpendaylightToaster;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.Toaster;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterData;
import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterService;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
// Register to md-sal
opendaylightToaster.setNotificationProvider(getNotificationServiceDependency());
- opendaylightToaster.setDataProvider(getDataBrokerDependency());
+
+ DataProviderService dataBrokerService = getDataBrokerDependency();
+ opendaylightToaster.setDataProvider(dataBrokerService);
+
+ final ListenerRegistration<DataChangeListener> dataChangeListenerRegistration =
+ dataBrokerService.registerDataChangeListener( OpendaylightToaster.TOASTER_IID, opendaylightToaster );
+
final BindingAwareBroker.RpcRegistration<ToasterService> rpcRegistration = getRpcRegistryDependency()
.addRpcImplementation(ToasterService.class, opendaylightToaster);
// Wrap toaster as AutoCloseable and close registrations to md-sal at
// close()
- final class AutoCloseableToaster implements AutoCloseable, ToasterData {
+ final class AutoCloseableToaster implements AutoCloseable {
@Override
public void close() throws Exception {
+ dataChangeListenerRegistration.close();
rpcRegistration.close();
runtimeReg.close();
opendaylightToaster.close();
log.info("Toaster provider (instance {}) torn down.", this);
}
-
- @Override
- public Toaster getToaster() {
- return opendaylightToaster.getToaster();
- }
}
AutoCloseable ret = new AutoCloseableToaster();
*/
package org.opendaylight.controller.sample.toaster.provider;
+import java.util.Arrays;
import java.util.Collections;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicLong;
import org.opendaylight.controller.config.yang.config.toaster_provider.impl.ToasterProviderRuntimeMXBean;
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.common.util.RpcErrors;
import org.opendaylight.controller.sal.common.util.Rpcs;
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.ToastDone.ToastStatus;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToastDoneBuilder;
import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.Toaster;
import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.Toaster.ToasterStatus;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.RestockToasterInput;
import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterBuilder;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterData;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterOutOfBreadBuilder;
+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.controller.sal.binding.api.data.DataChangeListener;
+import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.common.RpcError;
import org.opendaylight.yangtools.yang.common.RpcResult;
import com.google.common.util.concurrent.Futures;
-public class OpendaylightToaster implements ToasterData, ToasterService, ToasterProviderRuntimeMXBean, AutoCloseable {
+public class OpendaylightToaster implements ToasterService, ToasterProviderRuntimeMXBean,
+ DataChangeListener, AutoCloseable {
- private static final Logger log = LoggerFactory.getLogger(OpendaylightToaster.class);
- private static final InstanceIdentifier<Toaster> toasterIID = InstanceIdentifier.builder(Toaster.class).build();
+ private static final Logger LOG = LoggerFactory.getLogger(OpendaylightToaster.class);
- private static final DisplayString toasterManufacturer = new DisplayString("Opendaylight");
- private static final DisplayString toasterModelNumber = new DisplayString("Model 1 - Binding Aware");
+ public static final InstanceIdentifier<Toaster> TOASTER_IID = InstanceIdentifier.builder(Toaster.class).build();
+
+ 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 DataBrokerService dataProvider;
+
private final ExecutorService executor;
- private Future<RpcResult<Void>> currentTask;
+ // As you will see we are using multiple threads here. Therefore we need to be careful about concurrency.
+ // In this case we use the taskLock to provide synchronization for the current task.
+ private volatile Future<RpcResult<Void>> currentTask;
+ private final Object taskLock = new Object();
+
+ private final AtomicLong amountOfBreadInStock = new AtomicLong( 100 );
+
+ private final AtomicLong toastsMade = new AtomicLong(0);
+
+ // Thread safe holder for our darkness multiplier.
+ private final AtomicLong darknessFactor = new AtomicLong( 1000 );
public OpendaylightToaster() {
executor = Executors.newFixedThreadPool(1);
}
+ public void setNotificationProvider(NotificationProviderService salService) {
+ this.notificationProvider = salService;
+ }
+
+ public void setDataProvider(DataBrokerService salDataProvider) {
+ this.dataProvider = salDataProvider;
+ updateStatus();
+ }
+
+ /**
+ * Implemented from the AutoCloseable interface.
+ */
@Override
- public synchronized Toaster getToaster() {
- ToasterBuilder tb = new ToasterBuilder();
- tb //
- .setToasterManufacturer(toasterManufacturer) //
- .setToasterModelNumber(toasterModelNumber) //
- .setToasterStatus(currentTask == null ? ToasterStatus.Up : ToasterStatus.Down);
+ public void close() throws ExecutionException, InterruptedException {
+ // When we close this service we need to shutdown our executor!
+ executor.shutdown();
+ if (dataProvider != null) {
+ final DataModificationTransaction t = dataProvider.beginTransaction();
+ t.removeOperationalData(TOASTER_IID);
+ t.commit().get();
+ }
+ }
+
+ private Toaster buildToaster() {
+ // We don't need to synchronize on currentTask here b/c it's declared volatile and
+ // we're just doing a read.
+ boolean isUp = currentTask == null;
+
+ // 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.
+ ToasterBuilder tb = new ToasterBuilder();
+ tb.setToasterManufacturer(TOASTER_MANUFACTURER).setToasterModelNumber(TOASTER_MODEL_NUMBER)
+ .setToasterStatus(isUp ? ToasterStatus.Up : ToasterStatus.Down);
return tb.build();
}
+ /**
+ * Implemented from the DataChangeListener interface.
+ */
@Override
- public synchronized Future<RpcResult<Void>> cancelToast() {
- if (currentTask != null) {
- cancelToastImpl();
+ public void onDataChanged( DataChangeEvent<InstanceIdentifier<?>, DataObject> change ) {
+ DataObject dataObject = change.getUpdatedConfigurationData().get( TOASTER_IID );
+ if( dataObject instanceof Toaster )
+ {
+ Toaster toaster = (Toaster) dataObject;
+ Long darkness = toaster.getDarknessFactor();
+ if( darkness != null )
+ {
+ darknessFactor.set( darkness );
+ }
}
- return null;
}
+ /**
+ * RestConf RPC call implemented from the ToasterService interface.
+ */
@Override
- public synchronized Future<RpcResult<Void>> makeToast(MakeToastInput input) {
- log.debug("makeToast - Received input for toast");
- logToastInput(input);
- if (currentTask != null) {
- return inProgressError();
+ public Future<RpcResult<Void>> cancelToast() {
+ synchronized (taskLock) {
+ if (currentTask != null) {
+ currentTask.cancel(true);
+ currentTask = null;
+ }
}
- currentTask = executor.submit(new MakeToastTask(input));
- updateStatus();
- return currentTask;
+ // Always return success from the cancel toast call.
+ return Futures.immediateFuture(Rpcs.<Void> getRpcResult(true, Collections.<RpcError> emptySet()));
}
- private Future<RpcResult<Void>> inProgressError() {
- RpcResult<Void> result = Rpcs.<Void> getRpcResult(false, null, Collections.<RpcError> emptySet());
- return Futures.immediateFuture(result);
- }
+ /**
+ * RestConf RPC call implemented from the ToasterService interface.
+ */
+ @Override
+ public Future<RpcResult<Void>> makeToast(MakeToastInput input) {
+ LOG.info("makeToast: " + input);
- private void cancelToastImpl() {
- currentTask.cancel(true);
- ToastDoneBuilder toastDone = new ToastDoneBuilder();
- toastDone.setToastStatus(ToastStatus.Cancelled);
- notificationProvider.publish(toastDone.build());
- }
+ synchronized (taskLock) {
+ if (currentTask != null) {
+ // return an error since we are already toasting some toast.
+ LOG.info( "Toaster is already making toast" );
- public void setNotificationProvider(NotificationProviderService salService) {
- this.notificationProvider = salService;
- }
+ RpcResult<Void> result = Rpcs.<Void> getRpcResult(false, null, Arrays.asList(
+ RpcErrors.getRpcError( null, null, null, null,
+ "Toaster is busy", null, null ) ) );
+ return Futures.immediateFuture(result);
+ }
+ else if( outOfBread() ) {
+ RpcResult<Void> result = Rpcs.<Void> getRpcResult(false, null, Arrays.asList(
+ RpcErrors.getRpcError( null, null, null, null,
+ "Toaster is out of bread", null, null ) ) );
+ return Futures.immediateFuture(result);
+ }
+ else {
+ // Notice that we are moving the actual call to another thread,
+ // allowing this thread to return immediately.
+ // The MD-SAL design encourages asynchronus programming. If the
+ // caller needs to block until the call is
+ // complete then they can leverage the blocking methods on the
+ // Future interface.
+ currentTask = executor.submit(new MakeToastTask(input));
+ }
+ }
- public void setDataProvider(DataBrokerService salDataProvider) {
- this.dataProvider = salDataProvider;
updateStatus();
+ return currentTask;
}
- private void logToastInput(MakeToastInput input) {
- String toastType = input.getToasterToastType().getName();
- String toastDoneness = input.getToasterDoneness().toString();
- log.trace("Toast: {} doneness: {}", toastType, toastDoneness);
+ /**
+ * RestConf RPC call implemented from the ToasterService interface.
+ * Restocks the bread for the toaster, resets the toastsMade counter to 0, and sends a
+ * ToasterRestocked notification.
+ */
+ @Override
+ public Future<RpcResult<java.lang.Void>> restockToaster(RestockToasterInput input) {
+ LOG.info( "restockToaster: " + input );
+
+ synchronized( taskLock ) {
+ amountOfBreadInStock.set( input.getAmountOfBreadToStock() );
+
+ if( amountOfBreadInStock.get() > 0 ) {
+ ToasterRestocked reStockedNotification =
+ new ToasterRestockedBuilder().setAmountOfBread( input.getAmountOfBreadToStock() ).build();
+ notificationProvider.publish( reStockedNotification );
+ }
+ }
+
+ return Futures.immediateFuture(Rpcs.<Void> getRpcResult(true, Collections.<RpcError> emptySet()));
}
- private final AtomicLong toastsMade = new AtomicLong(0);
+ /**
+ * JMX RPC call implemented from the ToasterProviderRuntimeMXBean interface.
+ */
+ @Override
+ public void clearToastsMade() {
+ LOG.info( "clearToastsMade" );
+ toastsMade.set( 0 );
+ }
+ /**
+ * Accesssor method implemented from the ToasterProviderRuntimeMXBean interface.
+ */
@Override
public Long getToastsMade() {
return toastsMade.get();
private void updateStatus() {
if (dataProvider != null) {
final DataModificationTransaction t = dataProvider.beginTransaction();
- t.removeOperationalData(toasterIID);
- t.putOperationalData(toasterIID, getToaster());
+ t.removeOperationalData(TOASTER_IID);
+ t.putOperationalData(TOASTER_IID, buildToaster());
try {
t.commit().get();
} catch (InterruptedException | ExecutionException e) {
- log.warn("Failed to update toaster status, operational otherwise", e);
+ LOG.warn("Failed to update toaster status, operational otherwise", e);
}
} else {
- log.trace("No data provider configured, not updating status");
+ LOG.trace("No data provider configured, not updating status");
}
}
- @Override
- public void close() throws ExecutionException, InterruptedException {
- if (dataProvider != null) {
- final DataModificationTransaction t = dataProvider.beginTransaction();
- t.removeOperationalData(toasterIID);
- t.commit().get();
- }
+ private boolean outOfBread()
+ {
+ return amountOfBreadInStock.get() == 0;
}
private class MakeToastTask implements Callable<RpcResult<Void>> {
}
@Override
- public RpcResult<Void> call() throws InterruptedException {
- Thread.sleep(1000 * toastRequest.getToasterDoneness());
+ public RpcResult<Void> call() {
+ try
+ {
+ // make toast just sleeps for n secondn per doneness level.
+ long darknessFactor = OpendaylightToaster.this.darknessFactor.get();
+ Thread.sleep(darknessFactor * toastRequest.getToasterDoneness());
- ToastDoneBuilder notifyBuilder = new ToastDoneBuilder();
- notifyBuilder.setToastStatus(ToastStatus.Done);
- notificationProvider.publish(notifyBuilder.build());
- log.debug("Toast Done");
- logToastInput(toastRequest);
+ }
+ catch( InterruptedException e ) {
+ LOG.info( "Interrupted while making the toast" );
+ }
- currentTask = null;
toastsMade.incrementAndGet();
+
+ amountOfBreadInStock.getAndDecrement();
+ if( outOfBread() ) {
+ LOG.info( "Toaster is out of bread!" );
+
+ notificationProvider.publish( new ToasterOutOfBreadBuilder().build() );
+ }
+
+ synchronized (taskLock) {
+ currentTask = null;
+ }
+
updateStatus();
+ LOG.debug("Toast done");
+
return Rpcs.<Void> getRpcResult(true, null, Collections.<RpcError> emptySet());
}
}
prefix "toaster-provider-impl";
import config { prefix config; revision-date 2013-04-05; }
- import toaster-provider { prefix toaster-provider; revision-date 2014-01-31; }
+ import rpc-context { prefix rpcx; revision-date 2013-06-17; }
import opendaylight-md-sal-binding { prefix mdsal; revision-date 2013-10-28; }
description
"Initial revision.";
}
- // This is the definition of a service implementation
+ // This is the definition of the service implementation as a module identity.
identity toaster-provider-impl {
base config:module-type;
- config:provided-service toaster-provider:toaster-provider;
+
+ // Specifies the prefix for generated java classes.
config:java-name-prefix ToasterProvider;
}
+ // Augments the 'configuration' choice node under modules/module.
augment "/config:modules/config:module/config:configuration" {
case toaster-provider-impl {
when "/config:modules/config:module/config:type = 'toaster-provider-impl'";
augment "/config:modules/config:module/config:state" {
case toaster-provider-impl {
when "/config:modules/config:module/config:type = 'toaster-provider-impl'";
-
+
leaf toasts-made {
type uint32;
}
+
+ rpcx:rpc-context-instance "clear-toasts-made-rpc";
+ }
+ }
+
+ identity clear-toasts-made-rpc;
+ rpc clear-toasts-made {
+ description
+ "JMX call to clear the toasts-made counter.";
+
+ input {
+ uses rpcx:rpc-context-ref {
+ refine context-instance {
+ rpcx:rpc-context-instance clear-toasts-made-rpc;
+ }
+ }
}
}
}
+++ /dev/null
-// vi: set smarttab et sw=4 tabstop=4:
-module toaster-provider {
-
- yang-version 1;
- namespace "urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider";
- prefix "toaster-provider";
-
- import config { prefix config; revision-date 2013-04-05; }
-
- description
- "This module contains the base YANG definitions for
- toaster-provider services.";
-
- revision "2014-01-31" {
- description
- "Initial revision.";
- }
-
- // This is the definition of a service
- identity toaster-provider {
-
- base "config:service-type";
-
- config:java-class "org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterData";
- }
-}
\ No newline at end of file
"This variable indicates the current state of
the toaster.";
}
+
+ leaf darknessFactor {
+ type uint32;
+ config true;
+ default 1000;
+ description
+ "The darkness factor. Basically, the number of ms to multiple the doneness value by.";
+ }
} // container toaster
rpc make-toast {
if the toaster service is disabled.";
} // rpc cancel-toast
- notification toastDone {
- description
- "Indicates that the toast in progress has completed.";
- leaf toastStatus {
- type enumeration {
- enum "done" {
- value 0;
- description "The toast is done.";
- }
- enum "cancelled" {
- value 1;
- description
- "The toast was cancelled.";
- }
- enum "error" {
- value 2;
- description
- "The toaster service was disabled or
- the toaster is broken.";
- }
+ rpc restock-toaster {
+ description
+ "Restocks the toaster with the amount of bread specified.";
+
+ input {
+ leaf amountOfBreadToStock {
+ type uint32;
+ description
+ "Indicates the amount of bread to re-stock";
+ }
}
+ }
+
+ notification toasterOutOfBread {
+ description
+ "Indicates that the toaster has run of out bread.";
+ } // notification toasterOutOfStock
+
+ notification toasterRestocked {
+ description
+ "Indicates that the toaster has run of out bread.";
+ leaf amountOfBread {
+ type uint32;
description
- "Indicates the final toast status";
+ "Indicates the amount of bread that was re-stocked";
}
- } // notification toastDone
+ } // notification toasterOutOfStock
+
} // module toaster