<artifactId>ietf-netconf-monitoring</artifactId>
<version>${netconf.version}</version>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>ietf-netconf-monitoring-extension</artifactId>
+ <version>${netconf.version}</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-persister-impl</artifactId>
import ietf-inet-types {prefix inet; revision-date "2010-09-24";}
import ietf-yang-types {prefix yang; revision-date "2010-09-24";}
+ import opendaylight-queue-types {prefix queue-types; revision-date "2013-09-25";}
revision "2013-09-25" {
description "Initial revision of Port Inventory model";
uses flow-capable-port;
}
+ grouping queues {
+ list queue {
+ key "queue-id";
+ uses queue-types:queue-packet;
+ }
+ }
+
grouping flow-capable-port {
uses common-port;
units "kbps";
description "Max port bit rate in kbps";
}
+
+ uses queues;
}
grouping port-mod {
description "Initial revision of Queue Inventory model";
}
+ typedef queue-id {
+ type yang:counter32;
+ description "id for the specific queue.";
+ }
+
typedef queue-properties {
type enumeration {
enum min_rate;
}
}
-
-
grouping queue-prop-max-rate {
leaf queue-id {
- type uint32;
+ type queue-id;
description "id for the specific queue.";
}
--- /dev/null
+module opendaylight-queue-statistics {
+ namespace "urn:opendaylight:queue:statistics";
+ prefix queuestat;
+
+ import flow-capable-transaction {prefix tr;}
+ import yang-ext {prefix ext; revision-date "2013-07-09";}
+ import ietf-yang-types {prefix yang; revision-date "2010-09-24";}
+ import opendaylight-inventory {prefix inv;revision-date "2013-08-19";}
+ import flow-node-inventory {prefix flow-node;revision-date "2013-08-19";}
+ import opendaylight-queue-types {prefix queue-types;revision-date "2013-09-25";}
+ import opendaylight-statistics-types {prefix stat-types;revision-date "2013-09-25";}
+
+ contact
+ "Anilkumar Vishnoi
+ Email: avishnoi@in.ibm.com";
+
+ revision "2013-12-16" {
+ description "Initial revision of queue statistics model";
+ }
+
+ //Augment queue statistics data to the flow-capable-node-connector
+ augment "/inv:nodes/inv:node/inv:node-connector/flow-node:queue" {
+ ext:augment-identifier "flow-capable-node-connector-queue-statistics-data";
+ uses flow-capable-node-connector-queue-statistics;
+ }
+
+ grouping flow-capable-node-connector-queue-statistics {
+ container flow-capable-node-connector-queue-statistics {
+ //config "false";
+ uses stat-types:generic-queue-statistics;
+ }
+ }
+
+ //RPC calls to fetch queue statistics
+ grouping queue-id-and-statistics-map {
+ list queue-id-and-statistics-map {
+ key "queue-id node-connector-id";
+ leaf queue-id {
+ type queue-types:queue-id;
+ }
+ leaf node-connector-id {
+ type inv:node-connector-id;
+ }
+
+ uses stat-types:generic-queue-statistics;
+ }
+ }
+
+ rpc get-all-queues-statistics-from-all-ports {
+ description "Get statistics for all the queues attached to all the ports from the node";
+ input {
+ uses inv:node-context-ref;
+ }
+ output {
+ uses queue-id-and-statistics-map;
+ uses tr:transaction-aware;
+ }
+ }
+
+ rpc get-all-queues-statistics-from-given-port {
+ description "Get statistics for all queues for given port of the node";
+ input {
+ uses inv:node-context-ref;
+ leaf node-connector-id {
+ type inv:node-connector-id;
+ }
+ }
+ output {
+ uses queue-id-and-statistics-map;
+ uses tr:transaction-aware;
+ }
+ }
+
+ rpc get-queue-statistics-from-given-port {
+ description "Get statistics for given queues from given port of the node";
+ input {
+ uses inv:node-context-ref;
+ leaf node-connector-id {
+ type inv:node-connector-id;
+ }
+ leaf queue-id {
+ type queue-types:queue-id;
+ }
+ }
+ output {
+ uses queue-id-and-statistics-map;
+ uses tr:transaction-aware;
+ }
+ }
+
+ //Notification for port statistics update
+
+ notification queue-statistics-update {
+ leaf moreReplies {
+ type boolean;
+ }
+ uses inv:node;
+ uses queue-id-and-statistics-map;
+ uses tr:transaction-aware;
+ }
+}
revision "2013-09-25" {
description "Initial revision of flow service";
- }
+ }
+
+ grouping duration {
+ container duration {
+ leaf second {
+ type yang:counter32;
+ }
+ leaf nanosecond {
+ type yang:counter32;
+ }
+ }
+ }
grouping node-connector-statistics {
container packets {
leaf collision-count {
type uint64;
}
-
- container duration {
- leaf second {
- type yang:counter32;
- }
- leaf nanosecond {
- type yang:counter32;
- }
- }
+ uses duration;
}
grouping generic-statistics {
leaf byte-count {
type yang:counter64;
}
-
- container duration {
- leaf second {
- type yang:counter64;
- }
- leaf nanosecond {
- type yang:counter64;
- }
- }
- }
+ uses duration;
+ }
grouping generic-table-statistics {
description "Generic grouping holding generic statistics related to switch table";
}
}
+ grouping generic-queue-statistics {
+ description "Generic statistics of switch port attached queues.";
+ leaf transmitted-bytes {
+ type yang:counter64;
+ }
+
+ leaf transmitted-packets {
+ type yang:counter64;
+ }
+
+ leaf transmission-errors {
+ type yang:counter64;
+ }
+ uses duration;
+ }
+
}
\ No newline at end of file
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
</plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <version>1.8</version>
+ <executions>
+ <execution>
+ <id>add-source</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>add-source</goal>
+ </goals>
+ <configuration>
+ <sources>
+ <source>${project.build.directory}/generated-sources/config</source>
+ <source>${project.build.directory}/generated-sources/sal</source>
+ </sources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
--- /dev/null
+package org.opendaylight.controller.sal.binding.api;
+
+public interface RpcAvailabilityListener {
+
+}
import org.opendaylight.controller.config.yang.md.sal.binding.statistics.DataBrokerRuntimeMXBeanImpl;\r
import org.opendaylight.controller.md.sal.common.impl.routing.AbstractDataReadRouter;\r
import org.opendaylight.controller.sal.binding.impl.DataBrokerImpl;\r
-import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentDataServiceConnector;\r
+import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector;\r
import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentMappingService;\r
import org.opendaylight.controller.sal.core.api.Broker;\r
import org.opendaylight.controller.sal.core.api.data.DataProviderService;\r
BindingIndependentMappingService mappingService = getMappingServiceDependency();\r
\r
if (domBroker != null && mappingService != null) {\r
- BindingIndependentDataServiceConnector runtimeMapping = new BindingIndependentDataServiceConnector();\r
+ BindingIndependentConnector runtimeMapping = new BindingIndependentConnector();\r
runtimeMapping.setMappingService(mappingService);\r
runtimeMapping.setBaDataService(dataBindingBroker);\r
domBroker.registerProvider(runtimeMapping, getBundleContext());\r
import javassist.ClassPool;
+import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder;
import org.opendaylight.controller.sal.binding.dom.serializer.impl.RuntimeGeneratedMappingServiceImpl;
import org.osgi.framework.BundleContext;
@Override
public java.lang.AutoCloseable createInstance() {
RuntimeGeneratedMappingServiceImpl service = new RuntimeGeneratedMappingServiceImpl();
- ClassPool pool = new ClassPool(); // Should be default singleton
- service.setPool(pool);
+ service.setPool(SingletonHolder.CLASS_POOL);
service.start(getBundleContext());
return service;
}
if (field == null) throw new UnsupportedOperationException(
"Unable to set routing table. Table field does not exists");
field.set(target,routingTable);
-
}
}
--- /dev/null
+package org.opendaylight.controller.sal.binding.codegen.impl;
+
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
+import org.opendaylight.controller.sal.binding.spi.RpcRouter;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import static org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper.*;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.HashMap;
+
+import org.opendaylight.controller.sal.binding.spi.RpcRoutingTable;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
+import org.opendaylight.yangtools.yang.binding.RpcImplementation;
+import org.opendaylight.controller.md.sal.common.api.routing.MutableRoutingTable;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChange;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
+import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.concepts.util.ListenerRegistry;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+public class RpcRouterCodegenInstance<T extends RpcService> implements //
+ RpcRouter<T>, RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(RpcRouterCodegenInstance.class);
+
+ private T defaultService;
+
+ private final Class<T> serviceType;
+
+ private final T invocationProxy;
+
+ private final Set<Class<? extends BaseIdentity>> contexts;
+
+ private final ListenerRegistry<RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>>> listeners;
+
+ private final Map<Class<? extends BaseIdentity>, RpcRoutingTableImpl<? extends BaseIdentity, T>> routingTables;
+
+ public RpcRouterCodegenInstance(Class<T> type, T routerImpl, Set<Class<? extends BaseIdentity>> contexts,
+ Set<Class<? extends DataContainer>> inputs) {
+ this.listeners = ListenerRegistry.create();
+ this.serviceType = type;
+ this.invocationProxy = routerImpl;
+ this.contexts = ImmutableSet.copyOf(contexts);
+ Map<Class<? extends BaseIdentity>, RpcRoutingTableImpl<? extends BaseIdentity, T>> mutableRoutingTables = new HashMap<>();
+ for (Class<? extends BaseIdentity> ctx : contexts) {
+ RpcRoutingTableImpl<? extends BaseIdentity, T> table = new RpcRoutingTableImpl<>(ctx);
+ Map invokerView = table.getRoutes();
+ setRoutingTable((RpcService) invocationProxy, ctx, invokerView);
+ mutableRoutingTables.put(ctx, table);
+ table.registerRouteChangeListener(this);
+ }
+ this.routingTables = ImmutableMap.copyOf(mutableRoutingTables);
+ }
+
+ @Override
+ public Class<T> getServiceType() {
+ return serviceType;
+ }
+
+ @Override
+ public T getInvocationProxy() {
+ return invocationProxy;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <C extends BaseIdentity> RpcRoutingTable<C, T> getRoutingTable(Class<C> routeContext) {
+ return (RpcRoutingTable<C, T>) routingTables.get(routeContext);
+ }
+
+ @Override
+ public T getDefaultService() {
+ return defaultService;
+ }
+
+ @Override
+ public Set<Class<? extends BaseIdentity>> getContexts() {
+ return contexts;
+ }
+
+ @Override
+ public <L extends RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>>> ListenerRegistration<L> registerRouteChangeListener(
+ L listener) {
+ return listeners.registerWithType(listener);
+ }
+
+ @Override
+ public void onRouteChange(RouteChange<Class<? extends BaseIdentity>, InstanceIdentifier<?>> change) {
+ for (ListenerRegistration<RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>>> listener : listeners) {
+ try {
+ listener.getInstance().onRouteChange(change);
+ } catch (Exception e) {
+ LOG.error("Error occured during invoker listener {}", listener.getInstance(), e);
+ }
+ }
+ }
+
+ @Override
+ public T getService(Class<? extends BaseIdentity> context, InstanceIdentifier<?> path) {
+ return routingTables.get(context).getRoute(path);
+ }
+
+ @Override
+ public RoutedRpcRegistration<T> addRoutedRpcImplementation(T service) {
+ return new RoutedRpcRegistrationImpl(service);
+ }
+
+ @Override
+ public RpcRegistration<T> registerDefaultService(T service) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ private class RoutedRpcRegistrationImpl extends AbstractObjectRegistration<T> implements RoutedRpcRegistration<T> {
+
+ public RoutedRpcRegistrationImpl(T instance) {
+ super(instance);
+ }
+
+ @Override
+ public Class<T> getServiceType() {
+ return serviceType;
+ }
+
+ @Override
+ public void registerPath(Class<? extends BaseIdentity> context, InstanceIdentifier<?> path) {
+ routingTables.get(context).updateRoute(path, getInstance());
+ }
+
+ @Override
+ public void unregisterPath(Class<? extends BaseIdentity> context, InstanceIdentifier<?> path) {
+ routingTables.get(context).removeRoute(path, getInstance());
+
+ }
+
+ @Override
+ public void registerInstance(Class<? extends BaseIdentity> context, InstanceIdentifier<?> instance) {
+ registerPath(context, instance);
+ }
+
+ @Override
+ public void unregisterInstance(Class<? extends BaseIdentity> context, InstanceIdentifier<?> instance) {
+ unregisterPath(context, instance);
+ }
+
+ @Override
+ protected void removeRegistration() {
+
+ }
+ }
+}
+++ /dev/null
-package org.opendaylight.controller.sal.binding.codegen.impl
-
-import org.opendaylight.yangtools.yang.binding.RpcService
-import org.opendaylight.controller.sal.binding.spi.RpcRouter
-import org.opendaylight.yangtools.yang.binding.BaseIdentity
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import static extension org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper.*
-import java.util.Set
-import java.util.HashMap
-import org.opendaylight.controller.sal.binding.spi.RpcRoutingTable
-import org.opendaylight.yangtools.yang.binding.DataContainer
-import org.opendaylight.yangtools.yang.binding.RpcImplementation
-
-class RpcRouterCodegenInstance<T extends RpcService> implements RpcRouter<T> {
-
- @Property
- val T invocationProxy
-
- @Property
- val RpcImplementation invokerDelegate;
-
- @Property
- val Class<T> serviceType
-
- @Property
- val Set<Class<? extends BaseIdentity>> contexts
-
- @Property
- val Set<Class<? extends DataContainer>> supportedInputs;
-
- val routingTables = new HashMap<Class<? extends BaseIdentity>, RpcRoutingTableImpl<? extends BaseIdentity, ? extends RpcService>>;
-
- @Property
- var T defaultService
-
- new(Class<T> type, T routerImpl, Set<Class<? extends BaseIdentity>> contexts,
- Set<Class<? extends DataContainer>> inputs) {
- _serviceType = type
- _invocationProxy = routerImpl
- _invokerDelegate = routerImpl as RpcImplementation
- _contexts = contexts
- _supportedInputs = inputs;
-
- for (ctx : contexts) {
- val table = XtendHelper.createRoutingTable(ctx)
- invocationProxy.setRoutingTable(ctx, table.routes);
- routingTables.put(ctx, table);
- }
- }
-
- override <C extends BaseIdentity> getRoutingTable(Class<C> table) {
- routingTables.get(table) as RpcRoutingTable<C,T>
- }
-
- override getService(Class<? extends BaseIdentity> context, InstanceIdentifier<?> path) {
- val table = getRoutingTable(context);
- return table.getRoute(path);
- }
-
- override <T extends DataContainer> invoke(Class<T> type, T input) {
- return invokerDelegate.invoke(type, input);
- }
-
-}
--- /dev/null
+package org.opendaylight.controller.sal.binding.codegen.impl;
+
+import org.opendaylight.controller.sal.binding.spi.RpcRoutingTable;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublisher;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
+import org.opendaylight.controller.md.sal.common.impl.routing.RoutingUtils;
+import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.concepts.Mutable;
+
+class RpcRoutingTableImpl<C extends BaseIdentity, S extends RpcService> //
+implements //
+ Mutable, //
+ RpcRoutingTable<C, S>, //
+ RouteChangePublisher<Class<? extends BaseIdentity>, InstanceIdentifier<?>> {
+
+ private final Class<C> identifier;
+ private final ConcurrentMap<InstanceIdentifier<?>, S> routes;
+ private final Map<InstanceIdentifier<?>, S> unmodifiableRoutes;
+
+ private RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>> listener;
+ private S defaultRoute;
+
+ public RpcRoutingTableImpl(Class<C> identifier) {
+ super();
+ this.identifier = identifier;
+ this.routes = new ConcurrentHashMap<>();
+ this.unmodifiableRoutes = Collections.unmodifiableMap(routes);
+ }
+
+ @Override
+ public void setDefaultRoute(S target) {
+ defaultRoute = target;
+ }
+
+ @Override
+ public S getDefaultRoute() {
+ return defaultRoute;
+ }
+
+ @Override
+ public <L extends RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>>> ListenerRegistration<L> registerRouteChangeListener(
+ L listener) {
+ return (ListenerRegistration<L>) new SingletonListenerRegistration<L>(listener);
+ }
+
+ @Override
+ public Class<C> getIdentifier() {
+ return identifier;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public void updateRoute(InstanceIdentifier<?> path, S service) {
+ S previous = this.routes.put(path, service);
+ @SuppressWarnings("rawtypes")
+ RouteChangeListener listenerCapture = listener;
+ if (previous == null && listenerCapture != null) {
+ listenerCapture.onRouteChange(RoutingUtils.announcementChange(identifier, path));
+ }
+ }
+
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public void removeRoute(InstanceIdentifier<?> path) {
+ S previous = this.routes.remove(path);
+ @SuppressWarnings("rawtypes")
+ RouteChangeListener listenerCapture = listener;
+ if (previous != null && listenerCapture != null) {
+ listenerCapture.onRouteChange(RoutingUtils.removalChange(identifier, path));
+ }
+ }
+
+ public void removeRoute(InstanceIdentifier<?> path, S service) {
+ @SuppressWarnings("rawtypes")
+ RouteChangeListener listenerCapture = listener;
+ if (routes.remove(path, service) && listenerCapture != null) {
+ listenerCapture.onRouteChange(RoutingUtils.removalChange(identifier, path));
+ }
+ }
+
+ @Override
+ public S getRoute(InstanceIdentifier<?> nodeInstance) {
+ S route = routes.get(nodeInstance);
+ if (route != null) {
+ return route;
+ }
+ return getDefaultRoute();
+ }
+
+ @Override
+ public Map<InstanceIdentifier<?>, S> getRoutes() {
+ return unmodifiableRoutes;
+ }
+
+ protected void removeAllReferences(S service) {
+
+ }
+
+ private class SingletonListenerRegistration<L extends RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>>> extends
+ AbstractObjectRegistration<L>
+ implements ListenerRegistration<L> {
+
+ public SingletonListenerRegistration(L instance) {
+ super(instance);
+ listener = instance;
+ }
+
+ @Override
+ protected void removeRegistration() {
+ listener = null;
+ }
+ }
+}
\ No newline at end of file
+++ /dev/null
-package org.opendaylight.controller.sal.binding.codegen.impl
-
-import org.opendaylight.controller.sal.binding.spi.RpcRoutingTable
-import org.opendaylight.yangtools.yang.binding.BaseIdentity
-import org.opendaylight.yangtools.yang.binding.RpcService
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import java.util.Map
-import org.opendaylight.yangtools.yang.binding.DataObject
-import java.util.HashMap
-
-class RpcRoutingTableImpl<C extends BaseIdentity,S extends RpcService> implements RpcRoutingTable<C,S>{
-
- @Property
- val Class<C> identifier;
-
- @Property
- var S defaultRoute;
-
- @Property
- val Map<InstanceIdentifier<? extends DataObject>,S> routes;
-
- new(Class<C> ident, Map<InstanceIdentifier<? extends DataObject>,S> route) {
- _identifier = ident
- _routes = route
- }
-
- new(Class<C> ident) {
- _identifier = ident
- _routes = new HashMap
- }
-
-
- override getRoute(InstanceIdentifier<? extends Object> nodeInstance) {
- val ret = routes.get(nodeInstance);
- if(ret !== null) {
- return ret;
- }
- return defaultRoute;
- }
-
- override removeRoute(InstanceIdentifier<? extends Object> path) {
- routes.remove(path);
- }
-
- @SuppressWarnings("rawtypes")
- override updateRoute(InstanceIdentifier<? extends Object> path, S service) {
- routes.put(path as InstanceIdentifier<? extends DataObject>,service);
- }
-}
\ No newline at end of file
import static extension org.opendaylight.controller.sal.binding.codegen.YangtoolsMappingHelper.*
import static extension org.opendaylight.controller.sal.binding.codegen.RuntimeCodeSpecification.*
import java.util.HashSet
-import static org.opendaylight.controller.sal.binding.impl.util.ClassLoaderUtils.*
+import static org.opendaylight.yangtools.concepts.util.ClassLoaderUtils.*
import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory
import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory.NotificationInvoker
import java.util.Set
import org.opendaylight.yangtools.yang.binding.DataContainer
import org.opendaylight.yangtools.yang.binding.RpcImplementation
import org.opendaylight.controller.sal.binding.codegen.util.JavassistUtils
+import org.opendaylight.controller.sal.binding.impl.util.ClassLoaderUtils
+import javassist.LoaderClassPath
class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator, NotificationInvokerFactory {
val extension JavassistUtils utils;
val Map<Class<? extends NotificationListener>, RuntimeGeneratedInvokerPrototype> invokerClasses;
- public new(ClassPool pool) {
+
+ new(ClassPool pool) {
classPool = pool;
utils = new JavassistUtils(pool);
invokerClasses = new WeakHashMap();
BROKER_NOTIFICATION_LISTENER = org.opendaylight.controller.sal.binding.api.NotificationListener.asCtClass;
+ pool.appendClassPath(new LoaderClassPath(RpcService.classLoader));
}
override <T extends RpcService> getDirectProxyFor(Class<T> iface) {
- val supertype = iface.asCtClass
- val targetCls = createClass(iface.directProxyName, supertype) [
- field(DELEGATE_FIELD, iface);
- implementMethodsFrom(supertype) [
- body = '''
- {
- if(«DELEGATE_FIELD» == null) {
+ val T instance = withClassLoaderAndLock(iface.classLoader,lock) [|
+ val proxyName = iface.directProxyName;
+ val potentialClass = ClassLoaderUtils.tryToLoadClassWithTCCL(proxyName)
+ if(potentialClass != null) {
+ return potentialClass.newInstance as T;
+ }
+ val supertype = iface.asCtClass
+ val createdCls = createClass(iface.directProxyName, supertype) [
+ field(DELEGATE_FIELD, iface);
+ implementsType(RpcImplementation.asCtClass)
+ implementMethodsFrom(supertype) [
+ body = '''
+ {
+ if(«DELEGATE_FIELD» == null) {
+ throw new java.lang.IllegalStateException("No provider is processing supplied message");
+ }
+ return ($r) «DELEGATE_FIELD».«it.name»($$);
+ }
+ '''
+ ]
+ implementMethodsFrom(RpcImplementation.asCtClass) [
+ body = '''
+ {
throw new java.lang.IllegalStateException("No provider is processing supplied message");
+ return ($r) null;
}
- return ($r) «DELEGATE_FIELD».«it.name»($$);
- }
- '''
+ '''
+ ]
]
+ return createdCls.toClass(iface.classLoader).newInstance as T
]
- return targetCls.toClass(iface.classLoader).newInstance as T
+ return instance;
}
override <T extends RpcService> getRouterFor(Class<T> iface) {
- val instance = <RpcRouterCodegenInstance<T>>withClassLoaderAndLock(iface.classLoader,lock) [ |
+ val metadata = withClassLoader(iface.classLoader) [|
+ val supertype = iface.asCtClass
+ return supertype.rpcMetadata;
+ ]
+
+ val instance = <T>withClassLoaderAndLock(iface.classLoader,lock) [ |
val supertype = iface.asCtClass
- val metadata = supertype.rpcMetadata;
+ val routerName = iface.routerName;
+ val potentialClass = ClassLoaderUtils.tryToLoadClassWithTCCL(routerName)
+ if(potentialClass != null) {
+ return potentialClass.newInstance as T;
+ }
+
val targetCls = createClass(iface.routerName, supertype) [
- addInterface(RpcImplementation.asCtClass)
+
field(DELEGATE_FIELD, iface)
//field(REMOTE_INVOKER_FIELD,iface);
+ implementsType(RpcImplementation.asCtClass)
for (ctx : metadata.contexts) {
field(ctx.routingTableField, Map)
}
]
implementMethodsFrom(RpcImplementation.asCtClass) [
- switch (name) {
- case "getSupportedInputs":
- body = '''
- {
- throw new java.lang.UnsupportedOperationException("Not implemented yet");
- return ($r) null;
- }'''
- case "invoke": {
- val tmpBody = '''
- {
- «FOR input : metadata.supportedInputs SEPARATOR " else "»
- «val rpcMetadata = metadata.rpcInputs.get(input)»
- if(«input.name».class.equals($1)) {
- return ($r) this.«rpcMetadata.methodName»((«input.name») $2);
- }
- «ENDFOR»
- throw new java.lang.IllegalArgumentException("Not supported message type");
- return ($r) null;
- }
- '''
- body = tmpBody
- }
+ body = '''
+ {
+ throw new java.lang.IllegalStateException("No provider is processing supplied message");
+ return ($r) null;
}
+ '''
]
]
- val instance = targetCls.toClass(iface.classLoader,iface.protectionDomain).newInstance as T
- return new RpcRouterCodegenInstance(iface, instance, metadata.contexts,metadata.supportedInputs);
+ return targetCls.toClass(iface.classLoader,iface.protectionDomain).newInstance as T
+
];
- return instance;
+ return new RpcRouterCodegenInstance(iface, instance, metadata.contexts,metadata.supportedInputs);
}
private def RpcServiceMetadata getRpcMetadata(CtClass iface) {
--- /dev/null
+package org.opendaylight.controller.sal.binding.codegen.impl;
+
+import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator;
+import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory;
+
+import javassist.ClassPool;
+
+public class SingletonHolder {
+
+ public static final ClassPool CLASS_POOL = new ClassPool();
+ public static final org.opendaylight.controller.sal.binding.codegen.impl.RuntimeCodeGenerator RPC_GENERATOR_IMPL = new org.opendaylight.controller.sal.binding.codegen.impl.RuntimeCodeGenerator(CLASS_POOL);
+ public static final RuntimeCodeGenerator RPC_GENERATOR = RPC_GENERATOR_IMPL;
+ public static final NotificationInvokerFactory INVOKER_FACTORY = RPC_GENERATOR_IMPL.getInvokerFactory();
+}
});
return ret;
} catch (Exception e) {
- LOG.error("Could not find augmentable for {}", augmentation, e);
+ LOG.debug("Could not find augmentable for {} using {}", augmentation, augmentation.getClassLoader(), e);
return null;
}
}
import org.opendaylight.yangtools.yang.data.api.Node
import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
+import org.opendaylight.yangtools.yang.binding.RpcService
+import java.util.Set
+import org.opendaylight.yangtools.yang.common.QName
+import com.google.common.collect.FluentIterable
+import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil
class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingService, SchemaServiceListener, AutoCloseable {
@Property
val ConcurrentMap<Type, SchemaNode> typeToSchemaNode = new ConcurrentHashMap();
+
+ @Property
+ val ConcurrentMap<Type,Set<QName>> serviceTypeToRpc = new ConcurrentHashMap();
val promisedTypeDefinitions = HashMultimap.<Type, SettableFuture<GeneratedTypeBuilder>>create;
registry.onModuleContextAdded(schemaContext, entry.key, entry.value);
binding.pathToType.putAll(entry.value.childNodes)
- //val module = entry.key;
+ val module = entry.key;
val context = entry.value;
updateBindingFor(context.childNodes, schemaContext);
updateBindingFor(context.cases, schemaContext);
+ val namespace = BindingGeneratorUtil.moduleNamespaceToPackageName(module);
+
+ if(!module.rpcs.empty) {
+ val rpcs = FluentIterable.from(module.rpcs).transform[QName].toSet
+ val serviceClass = new ReferencedTypeImpl(namespace,BindingGeneratorUtil.parseToClassName(module.name)+"Service");
+ serviceTypeToRpc.put(serviceClass,rpcs);
+ }
val typedefs = context.typedefs;
for (typedef : typedefs.entrySet) {
}
override dataObjectFromDataDom(InstanceIdentifier<? extends DataObject> path, CompositeNode node) {
- return tryDeserialization[ |
- if (node == null) {
- return null;
- }
- val targetType = path.targetType
- val transformer = registry.getCodecForDataObject(targetType);
- val ret = transformer.deserialize(node)?.value as DataObject;
- return ret;
- ]
+ dataObjectFromDataDom(path.targetType,node) as DataObject;
}
override fromDataDom(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry) {
listenerRegistration = ctx.registerService(SchemaServiceListener, this, new Hashtable<String, String>());
}
}
+
+ override getRpcQNamesFor(Class<? extends RpcService> service) {
+ return serviceTypeToRpc.get(new ReferencedTypeImpl(service.package.name,service.simpleName));
+ }
private def getSchemaWithRetry(Type type) {
val typeDef = typeToSchemaNode.get(type);
override close() throws Exception {
listenerRegistration?.unregister();
}
+
+ override dataObjectFromDataDom(Class<? extends DataContainer> container, CompositeNode domData) {
+ return tryDeserialization[ |
+ if (domData == null) {
+ return null;
+ }
+ val transformer = registry.getCodecForDataObject(container);
+ val ret = transformer.deserialize(domData)?.value as DataObject;
+ return ret;
+ ]
+ }
}
import javassist.ClassPool
import org.osgi.framework.BundleContext
import java.util.Map
-import java.util.HashMap
import javassist.LoaderClassPath
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker
import java.util.Hashtable
import java.util.WeakHashMap
import javax.annotation.concurrent.GuardedBy
import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry
+import org.opendaylight.yangtools.concepts.ListenerRegistration
+import org.opendaylight.yangtools.concepts.util.ListenerRegistry
-class BindingAwareBrokerImpl implements BindingAwareBroker, RpcProviderRegistry, AutoCloseable {
+class BindingAwareBrokerImpl extends RpcProviderRegistryImpl implements BindingAwareBroker, AutoCloseable {
private static val log = LoggerFactory.getLogger(BindingAwareBrokerImpl)
private InstanceIdentifier<? extends DataObject> root = InstanceIdentifier.builder().toInstance();
- private static val clsPool = ClassPool.getDefault()
- public static var RuntimeCodeGenerator generator;
-
- /**
- * Map of all Managed Direct Proxies
- *
- */
- private val Map<Class<? extends RpcService>, RpcProxyContext> managedProxies = new ConcurrentHashMap();
-
- /**
- *
- * Map of all available Rpc Routers
- *
- *
- */
- private val Map<Class<? extends RpcService>, RpcRouter<? extends RpcService>> rpcRouters = new WeakHashMap();
-
@Property
private var NotificationProviderService notifyBroker
@Property
var BundleContext brokerBundleContext
- ServiceRegistration<NotificationProviderService> notifyProviderRegistration
-
- ServiceRegistration<NotificationService> notifyConsumerRegistration
-
- ServiceRegistration<DataProviderService> dataProviderRegistration
-
- ServiceRegistration<DataBrokerService> dataConsumerRegistration
-
- private val proxyGenerationLock = new ReentrantLock;
-
- private val routerGenerationLock = new ReentrantLock;
-
public new(BundleContext bundleContext) {
_brokerBundleContext = bundleContext;
}
def start() {
log.info("Starting MD-SAL: Binding Aware Broker");
- initGenerator();
-
- val executor = Executors.newCachedThreadPool;
-
- // Initialization of notificationBroker
- log.info("Starting MD-SAL: Binding Aware Notification Broker");
-
- log.info("Starting MD-SAL: Binding Aware Data Broker");
-
- log.info("Starting MD-SAL: Binding Aware Data Broker");
- log.info("MD-SAL: Binding Aware Broker Started");
}
- def initGenerator() {
- // YANG Binding Class Loader
- clsPool.appendClassPath(new LoaderClassPath(RpcService.classLoader));
- generator = new RuntimeCodeGenerator(clsPool);
- }
override registerConsumer(BindingAwareConsumer consumer, BundleContext bundleCtx) {
val ctx = consumer.createContext(bundleCtx)
private def createContext(BindingAwareProvider provider, BundleContext providerCtx) {
new OsgiProviderContext(providerCtx, this)
}
-
- /**
- * Returns a Managed Direct Proxy for supplied class
- *
- * Managed direct proxy is a generated proxy class conforming to the supplied interface
- * which delegates all calls to the backing delegate.
- *
- * Proxy does not do any validation, null pointer checks or modifies data in any way, it
- * is only use to avoid exposing direct references to backing implementation of service.
- *
- * If proxy class does not exist for supplied service class it will be generated automatically.
- */
- private def <T extends RpcService> getManagedDirectProxy(Class<T> service) {
- var RpcProxyContext existing = null
-
- if ((existing = managedProxies.get(service)) != null) {
- return existing.proxy
- }
- return withLock(proxyGenerationLock) [ |
- val maybeProxy = managedProxies.get(service);
- if (maybeProxy !== null) {
- return maybeProxy.proxy;
- }
-
-
- val proxyInstance = generator.getDirectProxyFor(service)
- val rpcProxyCtx = new RpcProxyContext(proxyInstance.class)
- val properties = new Hashtable<String, String>()
- rpcProxyCtx.proxy = proxyInstance as RpcService
- properties.salServiceType = SAL_SERVICE_TYPE_CONSUMER_PROXY
- rpcProxyCtx.registration = brokerBundleContext.registerService(service, rpcProxyCtx.proxy as T, properties)
- managedProxies.put(service, rpcProxyCtx)
- return rpcProxyCtx.proxy
- ]
- }
-
- private static def <T> T withLock(ReentrantLock lock, Callable<T> method) {
- try {
- lock.lock();
- val ret = method.call;
- return ret;
- } finally {
- lock.unlock();
- }
- }
-
- /**
- * Registers RPC Implementation
- *
- */
- override <T extends RpcService> addRpcImplementation(Class<T> type, T service) {
- checkNotNull(type, "Service type should not be null")
- checkNotNull(service, "Service type should not be null")
-
- val proxy = getManagedDirectProxy(type)
- checkState(proxy.delegate === null, "The Service for type %s is already registered", type)
-
- proxy.delegate = service;
- return new RpcServiceRegistrationImpl<T>(type, service, this);
- }
-
- override <T extends RpcService> RoutedRpcRegistration<T> addRoutedRpcImplementation(Class<T> type, T service) {
- checkNotNull(type, "Service type should not be null")
- checkNotNull(service, "Service type should not be null")
-
- val router = resolveRpcRouter(type);
- checkState(router !== null)
- return new RoutedRpcRegistrationImpl<T>(service, router, this)
- }
- override <T extends RpcService> getRpcService(Class<T> service) {
- checkNotNull(service, "Service should not be null");
- return getManagedDirectProxy(service) as T;
- }
-
- private def <T extends RpcService> RpcRouter<T> resolveRpcRouter(Class<T> type) {
-
- val router = rpcRouters.get(type);
- if (router !== null) {
- return router as RpcRouter<T>;
- }
-
- // We created Router
- return withLock(routerGenerationLock) [ |
- val maybeRouter = rpcRouters.get(type);
- if (maybeRouter !== null) {
- return maybeRouter as RpcRouter<T>;
- }
-
- val newRouter = generator.getRouterFor(type);
- checkState(newRouter !== null);
- rpcRouters.put(type, newRouter);
- // We create / update Direct Proxy for router
- val proxy = getManagedDirectProxy(type);
- proxy.delegate = newRouter.invocationProxy
- return newRouter;
- ]
-
- }
-
- protected def <T extends RpcService> void registerPath(RoutedRpcRegistrationImpl<T> registration,
- Class<? extends BaseIdentity> context, InstanceIdentifier<? extends Object> path) {
-
- val router = registration.router;
- val paths = registration.registeredPaths;
-
- val routingTable = router.getRoutingTable(context)
- checkState(routingTable != null);
-
- // Updating internal structure of registration
- routingTable.updateRoute(path, registration.instance)
-
- // Update routing table / send announce to message bus
- val success = paths.put(context, path);
- }
-
- protected def <T extends RpcService> void unregisterPath(RoutedRpcRegistrationImpl<T> registration,
- Class<? extends BaseIdentity> context, InstanceIdentifier<? extends Object> path) {
-
- val router = registration.router;
- val paths = registration.registeredPaths;
-
- val routingTable = router.getRoutingTable(context)
- checkState(routingTable != null);
-
- // Updating internal structure of registration
- val target = routingTable.getRoute(path)
- checkState(target === registration.instance)
- routingTable.removeRoute(path)
- checkState(paths.remove(context, path));
- }
-
- protected def <T extends RpcService> void unregisterRoutedRpcService(RoutedRpcRegistrationImpl<T> registration) {
-
- val router = registration.router;
- val paths = registration.registeredPaths;
-
- for (ctxMap : registration.registeredPaths.entries) {
- val context = ctxMap.key
- val routingTable = router.getRoutingTable(context)
- val path = ctxMap.value
- routingTable.removeRoute(path)
- }
- }
-
- protected def <T extends RpcService> void unregisterRpcService(RpcServiceRegistrationImpl<T> registration) {
-
- val type = registration.serviceType;
-
- val proxy = managedProxies.get(type);
- if (proxy.proxy.delegate === registration.instance) {
- proxy.proxy.delegate = null;
- }
- }
-
- def createDelegate(Class<? extends RpcService> type) {
- getManagedDirectProxy(type);
- }
-
- def getRpcRouters() {
- return Collections.unmodifiableMap(rpcRouters);
- }
-
- override close() {
- dataConsumerRegistration.unregister()
- dataProviderRegistration.unregister()
- notifyConsumerRegistration.unregister()
- notifyProviderRegistration.unregister()
- }
-
-}
-
-class RoutedRpcRegistrationImpl<T extends RpcService> extends AbstractObjectRegistration<T> implements RoutedRpcRegistration<T> {
-
- @Property
- private val BindingAwareBrokerImpl broker;
-
- @Property
- private val RpcRouter<T> router;
-
- @Property
- private val Multimap<Class<? extends BaseIdentity>, InstanceIdentifier<?>> registeredPaths = HashMultimap.create();
-
- private var closed = false;
-
- new(T instance, RpcRouter<T> backingRouter, BindingAwareBrokerImpl broker) {
- super(instance)
- _router = backingRouter;
- _broker = broker;
- }
-
- override protected removeRegistration() {
- closed = true
- broker.unregisterRoutedRpcService(this)
- }
-
- override registerInstance(Class<? extends BaseIdentity> context, InstanceIdentifier<? extends Object> instance) {
- registerPath(context, instance);
- }
-
- override unregisterInstance(Class<? extends BaseIdentity> context, InstanceIdentifier<? extends Object> instance) {
- unregisterPath(context, instance);
- }
-
- override registerPath(Class<? extends BaseIdentity> context, InstanceIdentifier<? extends Object> path) {
- checkClosed()
- broker.registerPath(this, context, path);
- }
-
- override unregisterPath(Class<? extends BaseIdentity> context, InstanceIdentifier<? extends Object> path) {
- checkClosed()
- broker.unregisterPath(this, context, path);
- }
-
- override getServiceType() {
- return router.serviceType;
- }
-
- private def checkClosed() {
- if (closed)
- throw new IllegalStateException("Registration was closed.");
- }
-
-}
-
-class RpcServiceRegistrationImpl<T extends RpcService> extends AbstractObjectRegistration<T> implements RpcRegistration<T> {
-
- private var BindingAwareBrokerImpl broker;
-
- @Property
- val Class<T> serviceType;
-
- public new(Class<T> type, T service, BindingAwareBrokerImpl broker) {
- super(service);
- this._serviceType = type;
- this.broker = broker;
- }
-
- override protected removeRegistration() {
- broker.unregisterRpcService(this);
- broker = null;
+ override close() throws Exception {
+
}
-}
+}
\ No newline at end of file
import org.opendaylight.yangtools.concepts.ListenerRegistration\r
import org.opendaylight.yangtools.concepts.Registration\r
import org.opendaylight.yangtools.yang.binding.Notification\r
-import org.slf4j.LoggerFactory\r
-\r
+import org.slf4j.LoggerFactory\rimport org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder
+
class NotificationBrokerImpl implements NotificationProviderService, AutoCloseable {\r
\r
val Multimap<Class<? extends Notification>, NotificationListener<?>> listeners;\r
@Property\r
var ExecutorService executor;\r
\r
+ new() {\r
+ listeners = HashMultimap.create()\r
+ }\r
+\r
+ @Deprecated\r
new(ExecutorService executor) {\r
listeners = HashMultimap.create()\r
this.executor = executor;\r
\r
override registerNotificationListener(\r
org.opendaylight.yangtools.yang.binding.NotificationListener listener) {\r
- val invoker = BindingAwareBrokerImpl.generator.invokerFactory.invokerFor(listener);\r
+ val invoker = SingletonHolder.INVOKER_FACTORY.invokerFor(listener);\r
for (notifyType : invoker.supportedNotifications) {\r
listeners.put(notifyType, invoker.invocationProxy)\r
}\r
val ref = services.iterator().next() as ServiceReference<T>;
return bundleContext.getService(ref) as T;
} else {
- broker.createDelegate(module);
- return getRpcService(module);
+ return broker.getRpcService(module);
}
} catch (InvalidSyntaxException e) {
log.error("Created filter was invalid:", e.message, e)
--- /dev/null
+package org.opendaylight.controller.sal.binding.impl;
+
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.HashMap;
+import java.util.Set;
+import java.util.WeakHashMap;
+
+import javax.swing.tree.ExpandVetoException;
+
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChange;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublisher;
+import org.opendaylight.controller.md.sal.common.impl.routing.RoutingUtils;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
+import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator;
+import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper;
+import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder;
+import org.opendaylight.controller.sal.binding.spi.RpcContextIdentifier;
+import org.opendaylight.controller.sal.binding.spi.RpcRouter;
+import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
+import org.opendaylight.yangtools.concepts.Identifiable;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.concepts.util.ListenerRegistry;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+
+import static com.google.common.base.Preconditions.*;
+
+public class RpcProviderRegistryImpl implements //
+ RpcProviderRegistry, //
+ RouteChangePublisher<RpcContextIdentifier, InstanceIdentifier<?>> {
+
+ private RuntimeCodeGenerator rpcFactory = SingletonHolder.RPC_GENERATOR_IMPL;
+
+ private final Map<Class<? extends RpcService>, RpcService> publicProxies = new WeakHashMap<>();
+ private final Map<Class<? extends RpcService>, RpcRouter<?>> rpcRouters = new WeakHashMap<>();
+ private final ListenerRegistry<RouteChangeListener<RpcContextIdentifier, InstanceIdentifier<?>>> routeChangeListeners = ListenerRegistry
+ .create();
+
+ @Override
+ public final <T extends RpcService> RoutedRpcRegistration<T> addRoutedRpcImplementation(Class<T> type,
+ T implementation) throws IllegalStateException {
+ return getRpcRouter(type).addRoutedRpcImplementation(implementation);
+ }
+
+ @Override
+ public final <T extends RpcService> RpcRegistration<T> addRpcImplementation(Class<T> type, T implementation)
+ throws IllegalStateException {
+ RpcRouter<T> potentialRouter = (RpcRouter<T>) rpcRouters.get(type);
+ if (potentialRouter != null) {
+ checkState(potentialRouter.getDefaultService() == null,
+ "Default service for routed RPC already registered.");
+ return potentialRouter.registerDefaultService(implementation);
+ }
+ T publicProxy = getRpcService(type);
+ RpcService currentDelegate = RuntimeCodeHelper.getDelegate(publicProxy);
+ checkState(currentDelegate == null, "Rpc service is already registered");
+ RuntimeCodeHelper.setDelegate(publicProxy, implementation);
+ return new RpcProxyRegistration<T>(type, implementation, this);
+ }
+
+ @Override
+ public final <T extends RpcService> T getRpcService(Class<T> type) {
+
+ RpcService potentialProxy = publicProxies.get(type);
+ if (potentialProxy != null) {
+ return (T) potentialProxy;
+ }
+ T proxy = rpcFactory.getDirectProxyFor(type);
+ publicProxies.put(type, proxy);
+ return proxy;
+ }
+
+ private <T extends RpcService> RpcRouter<T> getRpcRouter(Class<T> type) {
+ RpcRouter<?> potentialRouter = rpcRouters.get(type);
+ if (potentialRouter != null) {
+ return (RpcRouter<T>) potentialRouter;
+ }
+ RpcRouter<T> router = rpcFactory.getRouterFor(type);
+ router.registerRouteChangeListener(new RouteChangeForwarder(type));
+ RuntimeCodeHelper.setDelegate(getRpcService(type), router.getInvocationProxy());
+ rpcRouters.put(type, router);
+ return router;
+ }
+
+ public <L extends RouteChangeListener<RpcContextIdentifier, InstanceIdentifier<?>>> ListenerRegistration<L> registerRouteChangeListener(
+ L listener) {
+ return (ListenerRegistration<L>) routeChangeListeners.register(listener);
+ }
+
+ public RuntimeCodeGenerator getRpcFactory() {
+ return rpcFactory;
+ }
+
+ public void setRpcFactory(RuntimeCodeGenerator rpcFactory) {
+ this.rpcFactory = rpcFactory;
+ }
+
+ private class RouteChangeForwarder<T extends RpcService> implements
+ RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>> {
+
+ private final Class<T> type;
+
+ public RouteChangeForwarder(Class<T> type) {
+ this.type = type;
+ }
+
+ @Override
+ public void onRouteChange(RouteChange<Class<? extends BaseIdentity>, InstanceIdentifier<?>> change) {
+ Map<RpcContextIdentifier, Set<InstanceIdentifier<?>>> announcements = new HashMap<>();
+ for (Entry<Class<? extends BaseIdentity>, Set<InstanceIdentifier<?>>> entry : change.getAnnouncements()
+ .entrySet()) {
+ RpcContextIdentifier key = RpcContextIdentifier.contextFor(type, entry.getKey());
+ announcements.put(key, entry.getValue());
+ }
+ Map<RpcContextIdentifier, Set<InstanceIdentifier<?>>> removals = new HashMap<>();
+ for (Entry<Class<? extends BaseIdentity>, Set<InstanceIdentifier<?>>> entry : change.getRemovals()
+ .entrySet()) {
+ RpcContextIdentifier key = RpcContextIdentifier.contextFor(type, entry.getKey());
+ removals.put(key, entry.getValue());
+ }
+ RouteChange<RpcContextIdentifier, InstanceIdentifier<?>> toPublish = RoutingUtils
+ .<RpcContextIdentifier, InstanceIdentifier<?>> change(announcements, removals);
+ for (ListenerRegistration<RouteChangeListener<RpcContextIdentifier, InstanceIdentifier<?>>> listener : routeChangeListeners) {
+ try {
+ listener.getInstance().onRouteChange(toPublish);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ public static class RpcProxyRegistration<T extends RpcService> extends AbstractObjectRegistration<T> implements
+ RpcRegistration<T> {
+
+ private final Class<T> serviceType;
+ private RpcProviderRegistryImpl registry;
+
+ public RpcProxyRegistration(Class<T> type, T service, RpcProviderRegistryImpl registry) {
+ super(service);
+ serviceType = type;
+ }
+
+ @Override
+ public Class<T> getServiceType() {
+ return serviceType;
+ }
+
+ @Override
+ protected void removeRegistration() {
+ if (registry != null) {
+ T publicProxy = registry.getRpcService(serviceType);
+ RpcService currentDelegate = RuntimeCodeHelper.getDelegate(publicProxy);
+ if (currentDelegate == getInstance()) {
+ RuntimeCodeHelper.setDelegate(publicProxy, null);
+ }
+ registry = null;
+ }
+ }
+ }
+}
package org.opendaylight.controller.sal.binding.impl.connect.dom;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.Set;
+import java.util.WeakHashMap;
+import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
+
import org.opendaylight.controller.md.sal.common.api.RegistrationListener;
import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction;
import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandlerRegistration;
import org.opendaylight.controller.md.sal.common.api.data.DataModification;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChange;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider;
+import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl;
+import org.opendaylight.controller.sal.binding.spi.RpcContextIdentifier;
+import org.opendaylight.controller.sal.binding.spi.RpcRouter;
import org.opendaylight.controller.sal.common.util.Rpcs;
import org.opendaylight.controller.sal.core.api.Provider;
import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.concepts.Registration;
+import org.opendaylight.yangtools.concepts.util.ClassLoaderUtils;
import org.opendaylight.yangtools.yang.binding.Augmentable;
import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.BindingMapping;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.RpcInput;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.RpcError;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-public class BindingIndependentDataServiceConnector implements //
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableSet;
+
+import static com.google.common.base.Preconditions.*;
+import static org.opendaylight.yangtools.concepts.util.ClassLoaderUtils.*;
+
+public class BindingIndependentConnector implements //
RuntimeDataProvider, //
- Provider, AutoCloseable {
+ Provider, //
+ AutoCloseable {
- private final Logger LOG = LoggerFactory.getLogger(BindingIndependentDataServiceConnector.class);
+ private final Logger LOG = LoggerFactory.getLogger(BindingIndependentConnector.class);
private static final InstanceIdentifier<? extends DataObject> ROOT = InstanceIdentifier.builder().toInstance();
private Registration<DataCommitHandler<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode>> biCommitHandlerRegistration;
+ private RpcProvisionRegistry biRpcRegistry;
+ private RpcProviderRegistryImpl baRpcRegistry;
+
+ private ListenerRegistration<DomToBindingRpcForwardingManager> domToBindingRpcManager;
+ // private ListenerRegistration<BindingToDomRpcForwardingManager>
+ // bindingToDomRpcManager;
+
+ private Function<InstanceIdentifier<?>, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier> toDOMInstanceIdentifier = new Function<InstanceIdentifier<?>, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier>() {
+
+ @Override
+ public org.opendaylight.yangtools.yang.data.api.InstanceIdentifier apply(InstanceIdentifier<?> input) {
+ return mappingService.toDataDom(input);
+ }
+
+ };
+
@Override
public DataObject readOperationalData(InstanceIdentifier<? extends DataObject> path) {
try {
org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path);
-
-
+
CompositeNode result = biDataService.readOperationalData(biPath);
Class<? extends DataObject> targetType = path.getTargetType();
-
- if(Augmentation.class.isAssignableFrom(targetType)) {
+
+ if (Augmentation.class.isAssignableFrom(targetType)) {
path = mappingService.fromDataDom(biPath);
Class<? extends Augmentation<?>> augmentType = (Class<? extends Augmentation<?>>) targetType;
DataObject parentTo = mappingService.dataObjectFromDataDom(path, result);
- if(parentTo instanceof Augmentable<?>) {
+ if (parentTo instanceof Augmentable<?>) {
return (DataObject) ((Augmentable) parentTo).getAugmentation(augmentType);
}
-
+
}
return mappingService.dataObjectFromDataDom(path, result);
-
+
} catch (DeserializationException e) {
throw new IllegalStateException(e);
}
this.baDataService = baDataService;
}
+ public RpcProviderRegistry getRpcRegistry() {
+ return baRpcRegistry;
+ }
+
+ public void setRpcRegistry(RpcProviderRegistryImpl rpcRegistry) {
+ this.baRpcRegistry = rpcRegistry;
+ }
+
public void start() {
baDataService.registerDataReader(ROOT, this);
baCommitHandlerRegistration = baDataService.registerCommitHandler(ROOT, bindingToDomCommitHandler);
biCommitHandlerRegistration = biDataService.registerCommitHandler(ROOT_BI, domToBindingCommitHandler);
baDataService.registerCommitHandlerListener(domToBindingCommitHandler);
+
+ if (baRpcRegistry != null && biRpcRegistry != null) {
+ domToBindingRpcManager = baRpcRegistry.registerRouteChangeListener(new DomToBindingRpcForwardingManager());
+
+ }
}
public void setMappingService(BindingIndependentMappingService mappingService) {
start();
}
+ public <T extends RpcService> void onRpcRouterCreated(Class<T> serviceType, RpcRouter<T> router) {
+
+ }
+
+ public void setDomRpcRegistry(RpcProvisionRegistry registry) {
+ biRpcRegistry = registry;
+ }
+
@Override
public void close() throws Exception {
if (baCommitHandlerRegistration != null) {
return forwardedTransaction;
}
}
+
+ private class DomToBindingRpcForwardingManager implements
+ RouteChangeListener<RpcContextIdentifier, InstanceIdentifier<?>> {
+
+ private final Map<Class<? extends RpcService>, DomToBindingRpcForwarder> forwarders = new WeakHashMap<>();
+
+ @Override
+ public void onRouteChange(RouteChange<RpcContextIdentifier, InstanceIdentifier<?>> change) {
+ for (Entry<RpcContextIdentifier, Set<InstanceIdentifier<?>>> entry : change.getAnnouncements().entrySet()) {
+ bindingRoutesAdded(entry);
+ }
+ }
+
+ private void bindingRoutesAdded(Entry<RpcContextIdentifier, Set<InstanceIdentifier<?>>> entry) {
+ Class<? extends BaseIdentity> context = entry.getKey().getRoutingContext();
+ Class<? extends RpcService> service = entry.getKey().getRpcService();
+ if (context != null) {
+ getRpcForwarder(service, context).registerPaths(context, service, entry.getValue());
+ }
+ }
+
+ private DomToBindingRpcForwarder getRpcForwarder(Class<? extends RpcService> service,
+ Class<? extends BaseIdentity> context) {
+ DomToBindingRpcForwarder potential = forwarders.get(service);
+ if (potential != null) {
+ return potential;
+ }
+ if (context == null) {
+ potential = new DomToBindingRpcForwarder(service);
+ } else {
+ potential = new DomToBindingRpcForwarder(service, context);
+ }
+ forwarders.put(service, potential);
+ return potential;
+ }
+
+ }
+
+ private class DomToBindingRpcForwarder implements RpcImplementation {
+
+ private final Set<QName> supportedRpcs;
+ private final WeakReference<Class<? extends RpcService>> rpcServiceType;
+ private Set<org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration> registrations;
+
+ public DomToBindingRpcForwarder(Class<? extends RpcService> service) {
+ this.rpcServiceType = new WeakReference<Class<? extends RpcService>>(service);
+ this.supportedRpcs = mappingService.getRpcQNamesFor(service);
+ for (QName rpc : supportedRpcs) {
+ biRpcRegistry.addRpcImplementation(rpc, this);
+ }
+ registrations = ImmutableSet.of();
+ }
+
+ public DomToBindingRpcForwarder(Class<? extends RpcService> service, Class<? extends BaseIdentity> context) {
+ this.rpcServiceType = new WeakReference<Class<? extends RpcService>>(service);
+ this.supportedRpcs = mappingService.getRpcQNamesFor(service);
+ registrations = new HashSet<>();
+ for (QName rpc : supportedRpcs) {
+ registrations.add(biRpcRegistry.addRoutedRpcImplementation(rpc, this));
+ }
+ registrations = ImmutableSet.copyOf(registrations);
+ }
+
+ public void registerPaths(Class<? extends BaseIdentity> context, Class<? extends RpcService> service,
+ Set<InstanceIdentifier<?>> set) {
+ QName ctx = BindingReflections.findQName(context);
+ for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier path : FluentIterable.from(set).transform(
+ toDOMInstanceIdentifier)) {
+ for (org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration reg : registrations) {
+ reg.registerPath(ctx, path);
+ }
+ }
+ }
+
+ public void removePaths(Class<? extends BaseIdentity> context, Class<? extends RpcService> service,
+ Set<InstanceIdentifier<?>> set) {
+ QName ctx = BindingReflections.findQName(context);
+ for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier path : FluentIterable.from(set).transform(
+ toDOMInstanceIdentifier)) {
+ for (org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration reg : registrations) {
+ reg.unregisterPath(ctx, path);
+ }
+ }
+ }
+
+ @Override
+ public Set<QName> getSupportedRpcs() {
+ return supportedRpcs;
+ }
+
+ @Override
+ public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode domInput) {
+ checkArgument(rpc != null);
+ checkArgument(domInput != null);
+
+ Class<? extends RpcService> rpcType = rpcServiceType.get();
+ checkState(rpcType != null);
+ RpcService rpcService = baRpcRegistry.getRpcService(rpcType);
+ checkState(rpcService != null);
+ CompositeNode domUnwrappedInput = domInput.getFirstCompositeByName(QName.create(rpc, "input"));
+ try {
+ return resolveInvocationStrategy(rpc, rpcType).invokeOn(rpcService, domUnwrappedInput);
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ private RpcInvocationStrategy resolveInvocationStrategy(final QName rpc,
+ final Class<? extends RpcService> rpcType) throws Exception {
+ return ClassLoaderUtils.withClassLoader(rpcType.getClassLoader(), new Callable<RpcInvocationStrategy>() {
+ @Override
+ public RpcInvocationStrategy call() throws Exception {
+ String methodName = BindingMapping.getMethodName(rpc);
+ Method targetMethod = null;
+ for (Method possibleMethod : rpcType.getMethods()) {
+ if (possibleMethod.getName().equals(methodName)
+ && BindingReflections.isRpcMethod(possibleMethod)) {
+ targetMethod = possibleMethod;
+ break;
+ }
+ }
+ checkState(targetMethod != null, "Rpc method not found");
+ Optional<Class<?>> outputClass = BindingReflections.resolveRpcOutputClass(targetMethod);
+ Optional<Class<? extends DataContainer>> inputClass = BindingReflections
+ .resolveRpcInputClass(targetMethod);
+
+ RpcInvocationStrategy strategy = null;
+ if (outputClass.isPresent()) {
+ if (inputClass.isPresent()) {
+ strategy = new DefaultInvocationStrategy(targetMethod, outputClass.get(), inputClass.get());
+ } else {
+ strategy = new NoInputNoOutputInvocationStrategy(targetMethod);
+ }
+ } else {
+ strategy = null;
+ }
+ return strategy;
+ }
+
+ });
+ }
+ }
+
+ private abstract class RpcInvocationStrategy {
+
+ protected final Method targetMethod;
+
+ public RpcInvocationStrategy(Method targetMethod) {
+ this.targetMethod = targetMethod;
+ }
+
+ public abstract RpcResult<CompositeNode> uncheckedInvoke(RpcService rpcService, CompositeNode domInput)
+ throws Exception;
+
+ public RpcResult<CompositeNode> invokeOn(RpcService rpcService, CompositeNode domInput) throws Exception {
+ return uncheckedInvoke(rpcService, domInput);
+ }
+ }
+
+ private class DefaultInvocationStrategy extends RpcInvocationStrategy {
+
+ @SuppressWarnings("rawtypes")
+ private WeakReference<Class> inputClass;
+
+ @SuppressWarnings("rawtypes")
+ private WeakReference<Class> outputClass;
+
+ public DefaultInvocationStrategy(Method targetMethod, Class<?> outputClass,
+ Class<? extends DataContainer> inputClass) {
+ super(targetMethod);
+ this.outputClass = new WeakReference(outputClass);
+ this.inputClass = new WeakReference(inputClass);
+ }
+
+ @Override
+ public RpcResult<CompositeNode> uncheckedInvoke(RpcService rpcService, CompositeNode domInput) throws Exception {
+ DataContainer bindingInput = mappingService.dataObjectFromDataDom(inputClass.get(), domInput);
+ Future<RpcResult<?>> result = (Future<RpcResult<?>>) targetMethod.invoke(rpcService, bindingInput);
+ if (result == null) {
+ return Rpcs.getRpcResult(false);
+ }
+ RpcResult<?> bindingResult = result.get();
+ return Rpcs.getRpcResult(true);
+ }
+
+ }
+
+ private class NoInputNoOutputInvocationStrategy extends RpcInvocationStrategy {
+
+ public NoInputNoOutputInvocationStrategy(Method targetMethod) {
+ super(targetMethod);
+ }
+
+ public RpcResult<CompositeNode> uncheckedInvoke(RpcService rpcService, CompositeNode domInput) throws Exception {
+ Future<RpcResult<Void>> result = (Future<RpcResult<Void>>) targetMethod.invoke(rpcService);
+ RpcResult<Void> bindingResult = result.get();
+ return Rpcs.getRpcResult(bindingResult.isSuccessful(), bindingResult.getErrors());
+ }
+
+ }
}
package org.opendaylight.controller.sal.binding.impl.connect.dom;
import java.util.Map.Entry;
+import java.util.Set;
-import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
public interface BindingIndependentMappingService {
DataObject dataObjectFromDataDom(InstanceIdentifier<? extends DataObject> path, CompositeNode result) throws DeserializationException;
InstanceIdentifier<?> fromDataDom(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry) throws DeserializationException;
+
+ Set<QName> getRpcQNamesFor(Class<? extends RpcService> service);
+
+ DataContainer dataObjectFromDataDom(Class<? extends DataContainer> inputClass, CompositeNode domInput);
}
--- /dev/null
+package org.opendaylight.controller.sal.binding.spi;
+
+public class RoutingContext {
+
+}
--- /dev/null
+package org.opendaylight.controller.sal.binding.spi;
+
+import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+
+public final class RpcContextIdentifier implements Immutable{
+
+ public final Class<? extends RpcService> rpcService;
+ public final Class<? extends BaseIdentity> routingContext;
+
+ private RpcContextIdentifier(Class<? extends RpcService> rpcService, Class<? extends BaseIdentity> routingContext) {
+ super();
+ this.rpcService = rpcService;
+ this.routingContext = routingContext;
+ }
+
+ public Class<? extends RpcService> getRpcService() {
+ return rpcService;
+ }
+
+ public Class<? extends BaseIdentity> getRoutingContext() {
+ return routingContext;
+ }
+
+ public static final RpcContextIdentifier contextForGlobalRpc(Class<? extends RpcService> serviceType) {
+ return new RpcContextIdentifier(serviceType, null);
+ }
+
+ public static final RpcContextIdentifier contextFor(Class<? extends RpcService> serviceType,Class<? extends BaseIdentity> routingContext) {
+ return new RpcContextIdentifier(serviceType, routingContext);
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((routingContext == null) ? 0 : routingContext.hashCode());
+ result = prime * result + ((rpcService == null) ? 0 : rpcService.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ RpcContextIdentifier other = (RpcContextIdentifier) obj;
+ if (routingContext == null) {
+ if (other.routingContext != null)
+ return false;
+ } else if (!routingContext.equals(other.routingContext))
+ return false;
+ if (rpcService == null) {
+ if (other.rpcService != null)
+ return false;
+ } else if (!rpcService.equals(other.rpcService))
+ return false;
+ return true;
+ }
+
+}
import java.util.Set;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublisher;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
import org.opendaylight.yangtools.yang.binding.BaseIdentity;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.RpcImplementation;
* Type of RpcService for which router provides routing information
* and route selection.
*/
-public interface RpcRouter<T extends RpcService> extends RpcImplementation{
+public interface RpcRouter<T extends RpcService> extends //
+ RouteChangePublisher<Class<? extends BaseIdentity>, InstanceIdentifier<?>> {
/**
* Returns a type of RpcService which is served by this instance of router.
* @return default instance responsible for processing RPCs.
*/
T getDefaultService();
-
- /**
- *
- */
- void setDefaultService(T service);
Set<Class<? extends BaseIdentity>> getContexts();
+
+ RoutedRpcRegistration<T> addRoutedRpcImplementation(T service);
+
+ RpcRegistration<T> registerDefaultService(T service);
}
import org.junit.Before;
import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
import org.opendaylight.controller.sal.binding.impl.DataBrokerImpl;
-import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentDataServiceConnector;
+import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector;
import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentMappingService;
import org.opendaylight.controller.sal.binding.test.util.BindingBrokerTestFactory;
import org.opendaylight.controller.sal.binding.test.util.BindingTestContext;
assertNotNull(product);
assertNotNull(product.getInvocationProxy());
- assertNotNull(product.getSupportedInputs());
- assertTrue(product.getSupportedInputs().contains(SimpleInput.class));
- assertTrue(product.getSupportedInputs().contains(InheritedContextInput.class));
assertEquals("2 fields should be generated.", 2, product.getInvocationProxy().getClass().getFields().length);
verifyRouting(product);
import javassist.ClassPool;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
import org.opendaylight.controller.sal.binding.dom.serializer.impl.RuntimeGeneratedMappingServiceImpl;
+import org.opendaylight.controller.sal.binding.impl.BindingAwareBrokerImpl;
import org.opendaylight.controller.sal.binding.impl.DataBrokerImpl;
-import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentDataServiceConnector;
+import org.opendaylight.controller.sal.binding.impl.NotificationBrokerImpl;
+import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector;
import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentMappingService;
import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
import org.opendaylight.controller.sal.core.api.data.DataStore;
+import org.opendaylight.controller.sal.dom.broker.BrokerImpl;
import org.opendaylight.controller.sal.dom.broker.impl.DataStoreStatsWrapper;
import org.opendaylight.controller.sal.dom.broker.impl.HashMapDataStore;
+import org.opendaylight.controller.sal.dom.broker.impl.RpcRouterImpl;
import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareDataStoreAdapter;
import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import static com.google.common.base.Preconditions.*;
-public class BindingTestContext {
+public class BindingTestContext implements AutoCloseable {
public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier TREE_ROOT = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
private static final Logger LOG = LoggerFactory.getLogger(BindingTestContext.class);
private RuntimeGeneratedMappingServiceImpl mappingServiceImpl;
+
+
+ private BindingAwareBrokerImpl baBrokerImpl;
private DataBrokerImpl baDataImpl;
+ private NotificationBrokerImpl baNotifyImpl;
+ private BindingIndependentConnector baConnectDataServiceImpl;
+
private org.opendaylight.controller.sal.dom.broker.DataBrokerImpl biDataImpl;
-
- private BindingIndependentDataServiceConnector connectorServiceImpl;
+ private BrokerImpl biBrokerImpl;
private HashMapDataStore rawDataStore;
private SchemaAwareDataStoreAdapter schemaAwareDataStore;
private DataStoreStatsWrapper dataStoreStats;
private final ClassPool classPool;
private final boolean startWithSchema;
+
protected BindingTestContext(ListeningExecutorService executor, ClassPool classPool, boolean startWithSchema) {
this.executor = executor;
baDataImpl.setExecutor(executor);
}
+ public void startBindingBroker() {
+ checkState(executor != null,"Executor needs to be set");
+ checkState(baDataImpl != null,"Binding Data Broker must be started");
+ checkState(baNotifyImpl != null, "Notification Service must be started");
+ baBrokerImpl = new BindingAwareBrokerImpl(null);
+
+ baBrokerImpl.setDataBroker(baDataImpl);
+ baBrokerImpl.setNotifyBroker(baNotifyImpl);
+
+ baBrokerImpl.start();
+ }
+
public void startBindingToDomDataConnector() {
checkState(baDataImpl != null,"Binding Data Broker needs to be started");
checkState(biDataImpl != null,"DOM Data Broker needs to be started.");
checkState(mappingServiceImpl != null,"DOM Mapping Service needs to be started.");
- connectorServiceImpl = new BindingIndependentDataServiceConnector();
- connectorServiceImpl.setBaDataService(baDataImpl);
- connectorServiceImpl.setBiDataService(biDataImpl);
- connectorServiceImpl.setMappingService(mappingServiceImpl);
- connectorServiceImpl.start();
+ baConnectDataServiceImpl = new BindingIndependentConnector();
+ baConnectDataServiceImpl.setRpcRegistry(baBrokerImpl);
+ baConnectDataServiceImpl.setDomRpcRegistry(getDomRpcRegistry());
+ baConnectDataServiceImpl.setBaDataService(baDataImpl);
+ baConnectDataServiceImpl.setBiDataService(biDataImpl);
+ baConnectDataServiceImpl.setMappingService(mappingServiceImpl);
+ baConnectDataServiceImpl.start();
}
public void startBindingToDomMappingService() {
public void start() {
startBindingDataBroker();
+ startBindingNotificationBroker();
+ startBindingBroker();
startDomDataBroker();
startDomDataStore();
+ startDomBroker();
startBindingToDomMappingService();
startBindingToDomDataConnector();
if(startWithSchema) {
}
}
+ private void startDomBroker() {
+ checkState(executor != null);
+ biBrokerImpl = new BrokerImpl();
+ biBrokerImpl.setExecutor(executor);
+ biBrokerImpl.setRouter(new RpcRouterImpl("test"));
+ }
+
+ public void startBindingNotificationBroker() {
+ checkState(executor != null);
+ baNotifyImpl = new NotificationBrokerImpl(executor);
+
+ }
+
public void loadYangSchemaFromClasspath() {
String[] files = getAllYangFilesOnClasspath();
updateYangSchema(files);
dataStoreStats.getRequestCommitCount(), dataStoreStats.getRequestCommitTotalTime(),
dataStoreStats.getRequestCommitAverageTime());
}
+
+ public RpcProviderRegistry getBindingRpcRegistry() {
+ return baBrokerImpl;
+ }
+
+ public RpcProvisionRegistry getDomRpcRegistry() {
+ if(biBrokerImpl == null) {
+ return null;
+ }
+ return biBrokerImpl.getRouter();
+ }
+
+ public RpcImplementation getDomRpcInvoker() {
+ return biBrokerImpl.getRouter();
+ }
+
+ @Override
+ public void close() throws Exception {
+
+ }
}
--- /dev/null
+package org.opendaylight.controller.sal.binding.test.connect.dom;
+
+import java.math.BigInteger;
+import java.util.Collections;
+import java.util.concurrent.Future;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+import org.opendaylight.controller.sal.binding.test.util.BindingBrokerTestFactory;
+import org.opendaylight.controller.sal.binding.test.util.BindingTestContext;
+import org.opendaylight.controller.sal.common.util.Rpcs;
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.NodeFlowRemoved;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeContext;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl;
+
+import static junit.framework.Assert.*;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Multimap;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.MoreExecutors;
+
+public class CrossBrokerRpcTest {
+
+ protected RpcProviderRegistry baRpcRegistry;
+ protected RpcProvisionRegistry biRpcRegistry;
+ private BindingTestContext testContext;
+ private RpcImplementation biRpcInvoker;
+ private MessageCapturingFlowService flowService;
+
+ public static final NodeId NODE_A = new NodeId("a");
+ public static final NodeId NODE_B = new NodeId("b");
+ public static final NodeId NODE_C = new NodeId("c");
+ public static final NodeId NODE_D = new NodeId("d");
+
+ public static final InstanceIdentifier<Node> BA_NODE_A_ID = createBANodeIdentifier(NODE_A);
+ public static final InstanceIdentifier<Node> BA_NODE_B_ID = createBANodeIdentifier(NODE_B);
+ public static final InstanceIdentifier<Node> BA_NODE_C_ID = createBANodeIdentifier(NODE_C);
+ public static final InstanceIdentifier<Node> BA_NODE_D_ID = createBANodeIdentifier(NODE_D);
+
+ public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier BI_NODE_A_ID = createBINodeIdentifier(NODE_A);
+ public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier BI_NODE_B_ID = createBINodeIdentifier(NODE_B);
+ public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier BI_NODE_C_ID = createBINodeIdentifier(NODE_C);
+ public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier BI_NODE_D_ID = createBINodeIdentifier(NODE_D);
+
+ private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id");
+ private static final QName ADD_FLOW_QNAME = QName.create(NodeFlowRemoved.QNAME, "add-flow");
+ private static final QName REMOVE_FLOW_QNAME = QName.create(NodeFlowRemoved.QNAME, "remove-flow");
+ private static final QName UPDATE_FLOW_QNAME = QName.create(NodeFlowRemoved.QNAME, "update-flow");
+
+ @Before
+ public void setup() {
+ BindingBrokerTestFactory testFactory = new BindingBrokerTestFactory();
+ testFactory.setExecutor(MoreExecutors.sameThreadExecutor());
+ testFactory.setStartWithParsedSchema(true);
+ testContext = testFactory.getTestContext();
+
+ testContext.start();
+ baRpcRegistry = testContext.getBindingRpcRegistry();
+ biRpcRegistry = testContext.getDomRpcRegistry();
+ biRpcInvoker = testContext.getDomRpcInvoker();
+ assertNotNull(baRpcRegistry);
+ assertNotNull(biRpcRegistry);
+
+ flowService = MessageCapturingFlowService.create(baRpcRegistry);
+
+ }
+
+ @Test
+ public void bindingRoutedRpcProvider_DomInvokerTest() {
+
+ flowService//
+ .registerPath(NodeContext.class, BA_NODE_A_ID) //
+ .registerPath(NodeContext.class, BA_NODE_B_ID) //
+ .setAddFlowResult(addFlowResult(true, 10));
+
+ SalFlowService baFlowInvoker = baRpcRegistry.getRpcService(SalFlowService.class);
+ assertNotSame(flowService, baFlowInvoker);
+
+ AddFlowInput addFlowA = addFlow(BA_NODE_A_ID) //
+ .setPriority(100).setBarrier(true).build();
+
+ CompositeNode addFlowDom = toDomRpc(ADD_FLOW_QNAME, addFlowA);
+ assertNotNull(addFlowDom);
+ RpcResult<CompositeNode> domResult = biRpcInvoker.invokeRpc(ADD_FLOW_QNAME, addFlowDom);
+ assertNotNull(domResult);
+ assertTrue("DOM result is successful.", domResult.isSuccessful());
+ assertTrue("Bidning Add Flow RPC was captured.", flowService.getReceivedAddFlows().containsKey(BA_NODE_A_ID));
+ assertEquals(addFlowA, flowService.getReceivedAddFlows().get(BA_NODE_A_ID).iterator().next());
+ }
+
+ public void bindingRpcInvoker_DomRoutedProviderTest() {
+
+ }
+
+ private CompositeNode toDomRpcInput(DataObject addFlowA) {
+ return testContext.getBindingToDomMappingService().toDataDom(addFlowA);
+ }
+
+ @After
+ public void teardown() throws Exception {
+ testContext.close();
+ }
+
+ private static InstanceIdentifier<Node> createBANodeIdentifier(NodeId node) {
+ return InstanceIdentifier.builder(Nodes.class).child(Node.class, new NodeKey(node)).toInstance();
+ }
+
+ private static org.opendaylight.yangtools.yang.data.api.InstanceIdentifier createBINodeIdentifier(NodeId node) {
+ return org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder().node(Nodes.QNAME)
+ .nodeWithKey(Node.QNAME, NODE_ID_QNAME, node.getValue()).toInstance();
+ }
+
+ private Future<RpcResult<AddFlowOutput>> addFlowResult(boolean success, long xid) {
+ AddFlowOutput output = new AddFlowOutputBuilder() //
+ .setTransactionId(new TransactionId(BigInteger.valueOf(xid))).build();
+ RpcResult<AddFlowOutput> result = Rpcs.getRpcResult(success, output, ImmutableList.<RpcError> of());
+ return Futures.immediateFuture(result);
+ }
+
+ private static AddFlowInputBuilder addFlow(InstanceIdentifier<Node> nodeId) {
+ AddFlowInputBuilder builder = new AddFlowInputBuilder();
+ builder.setNode(new NodeRef(nodeId));
+ return builder;
+ }
+
+ private CompositeNode toDomRpc(QName rpcName, AddFlowInput addFlowA) {
+ return new CompositeNodeTOImpl(rpcName, null,
+ Collections.<org.opendaylight.yangtools.yang.data.api.Node<?>> singletonList(toDomRpcInput(addFlowA)));
+ }
+}
--- /dev/null
+package org.opendaylight.controller.sal.binding.test.connect.dom;
+
+import static junit.framework.Assert.assertNotNull;
+
+import java.util.concurrent.Future;
+
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowOutput;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
+
+public class MessageCapturingFlowService implements SalFlowService, AutoCloseable {
+
+ private Future<RpcResult<AddFlowOutput>> addFlowResult;
+ private Future<RpcResult<RemoveFlowOutput>> removeFlowResult;
+ private Future<RpcResult<UpdateFlowOutput>> updateFlowResult;
+
+ private final Multimap<InstanceIdentifier<?>, AddFlowInput> receivedAddFlows = HashMultimap.create();
+ private final Multimap<InstanceIdentifier<?>, RemoveFlowInput> receivedRemoveFlows = HashMultimap.create();
+ private final Multimap<InstanceIdentifier<?>, UpdateFlowInput> receivedUpdateFlows = HashMultimap.create();
+ private RoutedRpcRegistration<SalFlowService> registration;
+
+ @Override
+ public Future<RpcResult<AddFlowOutput>> addFlow(AddFlowInput arg0) {
+ receivedAddFlows.put(arg0.getNode().getValue(), arg0);
+ return addFlowResult;
+ }
+
+ @Override
+ public Future<RpcResult<RemoveFlowOutput>> removeFlow(RemoveFlowInput arg0) {
+ receivedRemoveFlows.put(arg0.getNode().getValue(), arg0);
+ return removeFlowResult;
+ }
+
+ @Override
+ public Future<RpcResult<UpdateFlowOutput>> updateFlow(UpdateFlowInput arg0) {
+ receivedUpdateFlows.put(arg0.getNode().getValue(), arg0);
+ return updateFlowResult;
+ }
+
+ public Future<RpcResult<AddFlowOutput>> getAddFlowResult() {
+ return addFlowResult;
+ }
+
+ public MessageCapturingFlowService setAddFlowResult(Future<RpcResult<AddFlowOutput>> addFlowResult) {
+ this.addFlowResult = addFlowResult;
+ return this;
+ }
+
+ public Future<RpcResult<RemoveFlowOutput>> getRemoveFlowResult() {
+ return removeFlowResult;
+ }
+
+ public MessageCapturingFlowService setRemoveFlowResult(Future<RpcResult<RemoveFlowOutput>> removeFlowResult) {
+ this.removeFlowResult = removeFlowResult;
+ return this;
+ }
+
+ public Future<RpcResult<UpdateFlowOutput>> getUpdateFlowResult() {
+ return updateFlowResult;
+ }
+
+ public MessageCapturingFlowService setUpdateFlowResult(Future<RpcResult<UpdateFlowOutput>> updateFlowResult) {
+ this.updateFlowResult = updateFlowResult;
+ return this;
+ }
+
+ public Multimap<InstanceIdentifier<?>, AddFlowInput> getReceivedAddFlows() {
+ return receivedAddFlows;
+ }
+
+ public Multimap<InstanceIdentifier<?>, RemoveFlowInput> getReceivedRemoveFlows() {
+ return receivedRemoveFlows;
+ }
+
+ public Multimap<InstanceIdentifier<?>, UpdateFlowInput> getReceivedUpdateFlows() {
+ return receivedUpdateFlows;
+ }
+
+ public MessageCapturingFlowService registerTo(RpcProviderRegistry registry) {
+ registration = registry.addRoutedRpcImplementation(SalFlowService.class, this);
+ assertNotNull(registration);
+ return this;
+ }
+
+ public void close() throws Exception {
+ registration.close();
+ }
+
+ public MessageCapturingFlowService registerPath(Class<? extends BaseIdentity> context, InstanceIdentifier<?> path) {
+ registration.registerPath(context, path);
+ return this;
+ }
+
+ public MessageCapturingFlowService unregisterPath(Class<? extends BaseIdentity> context, InstanceIdentifier<?> path) {
+ registration.unregisterPath(context, path);
+ return this;
+ }
+
+ public static MessageCapturingFlowService create() {
+ return new MessageCapturingFlowService();
+ }
+
+ public static MessageCapturingFlowService create(RpcProviderRegistry registry) {
+ MessageCapturingFlowService ret = new MessageCapturingFlowService();
+ ret.registerTo(registry);
+ return ret;
+ }
+
+
+}
\ No newline at end of file
mavenBundle(CONTROLLER, "config-persister-api").versionAsInProject(), //
mavenBundle(CONTROLLER, "netconf-api").versionAsInProject(), //
mavenBundle(CONTROLLER, "ietf-netconf-monitoring").versionAsInProject(), //
+ mavenBundle(CONTROLLER, "ietf-netconf-monitoring-extension").versionAsInProject(), //
mavenBundle(CONTROLLER, "netconf-monitoring").versionAsInProject(), //
mavenBundle(CONTROLLER, "netconf-client").versionAsInProject(), //
public interface RouteChangePublisher<C,P> {
- ListenerRegistration<RouteChangeListener<C,P>> registerRouteChangeListener(RouteChangeListener<C,P> listener);
+ <L extends RouteChangeListener<C,P>> ListenerRegistration<L> registerRouteChangeListener(L listener);
}
--- /dev/null
+package org.opendaylight.controller.md.sal.common.impl.routing;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChange;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+public class RoutingUtils {
+
+ public static <C,P> RouteChange<C,P> removalChange(C context,P path) {
+ final ImmutableMap<C, Set<P>> announcements = ImmutableMap.<C,Set<P>>of();
+ final ImmutableMap<C, Set<P>> removals = ImmutableMap.<C,Set<P>>of(context, ImmutableSet.of(path));
+ return new RouteChangeImpl<C,P>(announcements, removals);
+ }
+
+ public static <C,P> RouteChange<C,P> announcementChange(C context,P path) {
+ final ImmutableMap<C, Set<P>> announcements = ImmutableMap.<C,Set<P>>of(context, ImmutableSet.of(path));
+ final ImmutableMap<C, Set<P>> removals = ImmutableMap.<C,Set<P>>of();
+ return new RouteChangeImpl<C,P>(announcements, removals);
+ }
+
+
+ public static <C,P> RouteChange<C,P> change(Map<C, Set<P>> announcements,
+ Map<C, Set<P>> removals) {
+ final ImmutableMap<C, Set<P>> immutableAnnouncements = ImmutableMap.<C,Set<P>>copyOf(announcements);
+ final ImmutableMap<C, Set<P>> immutableRemovals = ImmutableMap.<C,Set<P>>copyOf(removals);
+ return new RouteChangeImpl<C,P>(immutableAnnouncements, immutableRemovals);
+ }
+
+
+ private static class RouteChangeImpl<C,P> implements RouteChange<C, P> {
+ private final Map<C, Set<P>> removal;
+ private final Map<C, Set<P>> announcement;
+
+ public RouteChangeImpl(ImmutableMap<C, Set<P>> removal, ImmutableMap<C, Set<P>> announcement) {
+ super();
+ this.removal = removal;
+ this.announcement = announcement;
+ }
+
+ @Override
+ public Map<C, Set<P>> getAnnouncements() {
+ return announcement;
+ }
+
+ @Override
+ public Map<C, Set<P>> getRemovals() {
+ return removal;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((announcement == null) ? 0 : announcement.hashCode());
+ result = prime * result + ((removal == null) ? 0 : removal.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ RouteChangeImpl other = (RouteChangeImpl) obj;
+ if (announcement == null) {
+ if (other.announcement != null)
+ return false;
+ } else if (!announcement.equals(other.announcement))
+ return false;
+ if (removal == null) {
+ if (other.removal != null) {
+ return false;
+ }
+ } else if (!removal.equals(other.removal))
+ return false;
+ return true;
+ }
+ }
+
+
+
+}
<artifactId>concepts</artifactId>
<version>0.1.1-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
</dependencies>
<packaging>bundle</packaging>
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+
+import org.opendaylight.yangtools.concepts.Immutable;
import org.opendaylight.yangtools.yang.common.RpcError;
import org.opendaylight.yangtools.yang.common.RpcResult;
+import com.google.common.collect.ImmutableList;
+
public class Rpcs {
+
+ public static <T> RpcResult<T> getRpcResult(boolean successful) {
+ RpcResult<T> ret = new RpcResultTO<T>(successful, null, ImmutableList.<RpcError>of());
+ return ret;
+ }
+
public static <T> RpcResult<T> getRpcResult(boolean successful, T result,
Collection<RpcError> errors) {
RpcResult<T> ret = new RpcResultTO<T>(successful, result, errors);
return ret;
}
- private static class RpcResultTO<T> implements RpcResult<T>, Serializable {
+ public static <T> RpcResult<T> getRpcResult(boolean successful, Collection<RpcError> errors) {
+ return new RpcResultTO<T>(successful, null, errors);
+ }
+
+ private static class RpcResultTO<T> implements RpcResult<T>, Serializable, Immutable {
private final Collection<RpcError> errors;
private final T result;
Collection<RpcError> errors) {
this.successful = successful;
this.result = result;
- this.errors = Collections.unmodifiableList(new ArrayList<RpcError>(
- errors));
+ this.errors = ImmutableList.copyOf(errors);
}
@Override
import org.opendaylight.controller.sal.dom.broker.spi.RpcRouter
import org.opendaylight.yangtools.concepts.ListenerRegistration
import org.opendaylight.controller.sal.core.api.RpcRegistrationListener
+import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry
+import org.opendaylight.controller.sal.core.api.RpcImplementation
-public class BrokerImpl implements Broker, AutoCloseable {
+public class BrokerImpl implements Broker, RpcProvisionRegistry, AutoCloseable {
private static val log = LoggerFactory.getLogger(BrokerImpl);
// Broker Generic Context
deactivator?.close();
}
+ override addRpcImplementation(QName rpcType, RpcImplementation implementation) throws IllegalArgumentException {
+ router.addRpcImplementation(rpcType,implementation);
+ }
+
+ override addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation) {
+ router.addRoutedRpcImplementation(rpcType,implementation);
+ }
+
}
import org.opendaylight.controller.sal.core.api.RpcRegistrationListener
import org.slf4j.LoggerFactory
import org.opendaylight.yangtools.concepts.util.ListenerRegistry
+import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
class RpcRouterImpl implements RpcRouter, Identifiable<String> {
}
override addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation) {
+ checkNotNull(rpcType, "Rpc Type should not be null");
+ checkNotNull(implementation, "Implementation should not be null.");
+ val reg = new RoutedRpcRegistrationImpl(rpcType, implementation, this);
+ implementations.put(rpcType, reg)
+
+ for (listener : rpcRegistrationListeners.listeners) {
+ try {
+ listener.instance.onRpcImplementationAdded(rpcType);
+ } catch (Exception e) {
+ log.error("Unhandled exception during invoking listener", e);
+ }
+ }
+
+ return reg;
}
override addRpcImplementation(QName rpcType, RpcImplementation implementation) throws IllegalArgumentException {
override protected removeRegistration() {
router.remove(this);
}
+}
+class RoutedRpcRegistrationImpl extends RpcRegistrationImpl implements RoutedRpcRegistration {
+
+
+ new(QName type, RpcImplementation instance, RpcRouterImpl router) {
+ super(type,instance,router)
+ }
+ override protected removeRegistration() {
+ router.remove(this);
+ }
+ override registerPath(QName context, InstanceIdentifier path) {
+ //
+
+ }
+
+ override unregisterPath(QName context, InstanceIdentifier path) {
+ //
+ }
}
this.schema = null;
}
- protected CompositeNode mergeData(InstanceIdentifier path, CompositeNode stored, CompositeNode modified, boolean config) {
+ protected CompositeNode mergeData(InstanceIdentifier path, CompositeNode stored, CompositeNode modified,
+ boolean config) {
long startTime = System.nanoTime();
try {
- DataSchemaNode node = schemaNodeFor(path);
- return YangDataOperations.merge(node,stored,modified,config);
+ DataSchemaNode node = schemaNodeFor(path);
+ return YangDataOperations.merge(node, stored, modified, config);
} finally {
- //System.out.println("Merge time: " + ((System.nanoTime() - startTime) / 1000.0d));
+ // System.out.println("Merge time: " + ((System.nanoTime() -
+ // startTime) / 1000.0d));
}
}
-
-
+
private DataSchemaNode schemaNodeFor(InstanceIdentifier path) {
- checkState(schema != null,"YANG Schema is not available");
+ checkState(schema != null, "YANG Schema is not available");
return YangSchemaUtils.getSchemaNode(schema, path);
}
DataModification<InstanceIdentifier, CompositeNode> original) {
// NOOP for now
NormalizedDataModification normalized = new NormalizedDataModification(original);
- for (Entry<InstanceIdentifier,CompositeNode> entry : original.getUpdatedConfigurationData().entrySet()) {
+ for (Entry<InstanceIdentifier, CompositeNode> entry : original.getUpdatedConfigurationData().entrySet()) {
normalized.putConfigurationData(entry.getKey(), entry.getValue());
}
- for (Entry<InstanceIdentifier,CompositeNode> entry : original.getUpdatedOperationalData().entrySet()) {
+ for (Entry<InstanceIdentifier, CompositeNode> entry : original.getUpdatedOperationalData().entrySet()) {
normalized.putOperationalData(entry.getKey(), entry.getValue());
}
for (InstanceIdentifier entry : original.getRemovedConfigurationData()) {
normalized.removeConfigurationData(entry);
}
- for(InstanceIdentifier entry : original.getRemovedOperationalData()) {
+ for (InstanceIdentifier entry : original.getRemovedOperationalData()) {
normalized.removeOperationalData(entry);
}
return normalized;
}
}
}
-
+
private class NormalizedDataModification extends AbstractDataModification<InstanceIdentifier, CompositeNode> {
private Object identifier;
identifier = original;
status = TransactionStatus.NEW;
}
-
+
@Override
public Object getIdentifier() {
return this.identifier;
}
-
+
@Override
public TransactionStatus getStatus() {
return status;
public Future<RpcResult<TransactionStatus>> commit() {
throw new UnsupportedOperationException("Commit should not be invoked on this");
}
-
+
@Override
- protected CompositeNode mergeConfigurationData(InstanceIdentifier path,CompositeNode stored, CompositeNode modified) {
- return mergeData(path,stored, modified,true);
+ protected CompositeNode mergeConfigurationData(InstanceIdentifier path, CompositeNode stored,
+ CompositeNode modified) {
+ return mergeData(path, stored, modified, true);
}
-
+
@Override
- protected CompositeNode mergeOperationalData(InstanceIdentifier path,CompositeNode stored, CompositeNode modified) {
+ protected CompositeNode mergeOperationalData(InstanceIdentifier path, CompositeNode stored,
+ CompositeNode modified) {
// TODO Auto-generated method stub
- return mergeData(path,stored,modified,false);
+ return mergeData(path, stored, modified, false);
}
-
}
}
--- /dev/null
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URLEncoder;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.Future;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.glassfish.jersey.test.TestProperties;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider;
+import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider;
+import org.opendaylight.controller.sal.restconf.impl.BrokerFacade;
+import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
+import org.opendaylight.controller.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+import com.google.common.base.Charsets;
+
+public class ReadConfAndOperDataTest extends JerseyTest {
+
+ private static ControllerContext controllerContext;
+ private static BrokerFacade brokerFacade;
+ private static RestconfImpl restconfImpl;
+ private static final MediaType MEDIA_TYPE_DRAFT02 = new MediaType("application", "yang.data+xml");
+
+ @BeforeClass
+ public static void init() throws FileNotFoundException {
+ Set<Module> allModules = TestUtils.loadModules(RestconfImplTest.class.getResource("/full-versions/yangs")
+ .getPath());
+ SchemaContext schemaContext = TestUtils.loadSchemaContext(allModules);
+ controllerContext = ControllerContext.getInstance();
+ controllerContext.setSchemas(schemaContext);
+ brokerFacade = mock(BrokerFacade.class);
+ restconfImpl = RestconfImpl.getInstance();
+ restconfImpl.setBroker(brokerFacade);
+ restconfImpl.setControllerContext(controllerContext);
+ }
+
+ @Before
+ public void logs() {
+ List<LogRecord> loggedRecords = getLoggedRecords();
+ for (LogRecord l : loggedRecords) {
+ System.out.println(l.getMessage());
+ }
+ }
+
+ @Test
+ public void testReadConfigurationData() throws UnsupportedEncodingException, FileNotFoundException {
+
+ String uri = createUri("/config/", "ietf-interfaces:interfaces/interface/eth0");
+
+ InputStream xmlStream = RestconfImplTest.class.getResourceAsStream("/parts/ietf-interfaces_interfaces.xml");
+ CompositeNode loadedCompositeNode = TestUtils.loadCompositeNode(xmlStream);
+ when(brokerFacade.readConfigurationData(any(InstanceIdentifier.class))).thenReturn(loadedCompositeNode);
+
+ Response response = target(uri).request(MEDIA_TYPE_DRAFT02).get();
+ assertEquals(200, response.getStatus());
+
+ uri = createUri("/config/", "ietf-interfaces:interfaces/interface/example");
+ when(brokerFacade.readConfigurationData(any(InstanceIdentifier.class))).thenReturn(null);
+
+ response = target(uri).request(MEDIA_TYPE_DRAFT02).get();
+ assertEquals(404, response.getStatus());
+ }
+
+ @Test
+ public void testReadOperationalData() throws UnsupportedEncodingException, FileNotFoundException {
+ String uri = createUri("/operational/", "ietf-interfaces:interfaces/interface/eth0");
+
+ InputStream xmlStream = RestconfImplTest.class.getResourceAsStream("/parts/ietf-interfaces_interfaces.xml");
+ CompositeNode loadedCompositeNode = TestUtils.loadCompositeNode(xmlStream);
+ when(brokerFacade.readOperationalData(any(InstanceIdentifier.class))).thenReturn(loadedCompositeNode);
+
+ Response response = target(uri).request(MEDIA_TYPE_DRAFT02).get();
+ assertEquals(200, response.getStatus());
+
+ uri = createUri("/config/", "ietf-interfaces:interfaces/interface/example");
+ when(brokerFacade.readConfigurationData(any(InstanceIdentifier.class))).thenReturn(null);
+
+ response = target(uri).request(MEDIA_TYPE_DRAFT02).get();
+ assertEquals(404, response.getStatus());
+ }
+
+ private String createUri(String prefix, String encodedPart) throws UnsupportedEncodingException {
+ return URI.create(prefix + URLEncoder.encode(encodedPart, Charsets.US_ASCII.name()).toString()).toASCIIString();
+ }
+
+ @Override
+ protected Application configure() {
+ enable(TestProperties.LOG_TRAFFIC);
+ enable(TestProperties.DUMP_ENTITY);
+ enable(TestProperties.RECORD_LOG_LEVEL);
+ set(TestProperties.RECORD_LOG_LEVEL, Level.ALL.intValue());
+
+ ResourceConfig resourceConfig = new ResourceConfig();
+ resourceConfig = resourceConfig.registerInstances(restconfImpl, StructuredDataToXmlProvider.INSTANCE,
+ XmlToCompositeNodeProvider.INSTANCE);
+ return resourceConfig;
+ }
+}
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.aggregate.flow.statistics.AggregateFlowStatistics;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.queue.rev130925.QueueId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.features.GroupFeatures;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStats;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterFeatures;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericQueueStatistics;
import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericStatistics;
import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericTableStatistics;
import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.NodeConnectorStatistics;
private final Map<Short,GenericTableStatistics> flowTableAndStatisticsMap =
new HashMap<Short,GenericTableStatistics>();
+ private final Map<NodeConnectorId,Map<QueueId,GenericQueueStatistics>> NodeConnectorAndQueuesStatsMap =
+ new HashMap<NodeConnectorId,Map<QueueId,GenericQueueStatistics>>();
+
public NodeStatistics(){
}
public Map<NodeConnectorId, NodeConnectorStatistics> getNodeConnectorStats() {
return nodeConnectorStats;
}
+
+ public Map<NodeConnectorId, Map<QueueId, GenericQueueStatistics>> getNodeConnectorAndQueuesStatsMap() {
+ return NodeConnectorAndQueuesStatsMap;
+ }
}
import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetAllPortsStatisticsInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetAllPortsStatisticsOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetAllQueuesStatisticsFromAllPortsInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetAllQueuesStatisticsFromAllPortsOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsService;
import org.opendaylight.yangtools.concepts.Registration;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.NotificationListener;
private OpendaylightFlowTableStatisticsService flowTableStatsService;
+ private OpendaylightQueueStatisticsService queueStatsService;
+
private final MultipartMessageManager multipartMessageManager = new MultipartMessageManager();
private Thread statisticsRequesterThread;
flowTableStatsService = StatisticsManagerActivator.getProviderContext().
getRpcService(OpendaylightFlowTableStatisticsService.class);
+ queueStatsService = StatisticsManagerActivator.getProviderContext().
+ getRpcService(OpendaylightQueueStatisticsService.class);
+
statisticsRequesterThread = new Thread( new Runnable(){
@Override
sendAllPortStatisticsRequest(targetNodeRef);
sendAllFlowTablesStatisticsRequest(targetNodeRef);
+
+ sendAllQueueStatsFromAllNodeConnector (targetNodeRef);
}catch(Exception e){
spLogger.error("Exception occured while sending statistics requests : {}",e);
@SuppressWarnings("unused")
Future<RpcResult<GetAllMeterConfigStatisticsOutput>> response =
meterStatsService.getAllMeterConfigStatistics(input.build());
-
}
+ private void sendAllQueueStatsFromAllNodeConnector(NodeRef targetNode) {
+ GetAllQueuesStatisticsFromAllPortsInputBuilder input = new GetAllQueuesStatisticsFromAllPortsInputBuilder();
+
+ input.setNode(targetNode);
+
+ @SuppressWarnings("unused")
+ Future<RpcResult<GetAllQueuesStatisticsFromAllPortsOutput>> response =
+ queueStatsService.getAllQueuesStatisticsFromAllPorts(input.build());
+ }
+
public ConcurrentMap<NodeId, NodeStatistics> getStatisticsCache() {
return statisticsCache;
}
import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsListener;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMap;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.statistics.FlowTableStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.Queue;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.queue.rev130925.QueueId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupDescStatsUpdated;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupFeaturesUpdated;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupStatisticsUpdated;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterConfigStatsBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterFeaturesBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericQueueStatistics;
import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericStatistics;
import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsData;
import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsDataBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.PortStatisticsUpdate;
import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.flow.capable.node.connector.statistics.FlowCapableNodeConnectorStatisticsBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsDataBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.QueueStatisticsUpdate;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.flow.capable.node.connector.queue.statistics.FlowCapableNodeConnectorQueueStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.queue.id.and.statistics.map.QueueIdAndStatisticsMap;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
import org.slf4j.Logger;
OpendaylightMeterStatisticsListener,
OpendaylightFlowStatisticsListener,
OpendaylightPortStatisticsListener,
- OpendaylightFlowTableStatisticsListener{
+ OpendaylightFlowTableStatisticsListener,
+ OpendaylightQueueStatisticsListener{
public final static Logger sucLogger = LoggerFactory.getLogger(StatisticsUpdateCommiter.class);
flowStatisticsData.setFlowStatistics(flowStatistics.build());
- sucLogger.info("Flow : {}",flowRule.toString());
- sucLogger.info("Statistics to augment : {}",flowStatistics.build().toString());
+ sucLogger.debug("Flow : {}",flowRule.toString());
+ sucLogger.debug("Statistics to augment : {}",flowStatistics.build().toString());
InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key)
.augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
}
}
+ @Override
+ public void onQueueStatisticsUpdate(QueueStatisticsUpdate notification) {
+ NodeKey key = new NodeKey(notification.getId());
+ sucLogger.info("Received queue stats update : {}",notification.toString());
+
+ //Add statistics to local cache
+ ConcurrentMap<NodeId, NodeStatistics> cache = this.statisticsManager.getStatisticsCache();
+ if(!cache.containsKey(notification.getId())){
+ cache.put(notification.getId(), new NodeStatistics());
+ }
+
+ List<QueueIdAndStatisticsMap> queuesStats = notification.getQueueIdAndStatisticsMap();
+ for(QueueIdAndStatisticsMap swQueueStats : queuesStats){
+
+ if(!cache.get(notification.getId()).getNodeConnectorAndQueuesStatsMap().containsKey(swQueueStats.getNodeConnectorId())){
+ cache.get(notification.getId()).getNodeConnectorAndQueuesStatsMap().put(swQueueStats.getNodeConnectorId(), new HashMap<QueueId,GenericQueueStatistics>());
+ }
+
+ FlowCapableNodeConnectorQueueStatisticsDataBuilder queueStatisticsDataBuilder = new FlowCapableNodeConnectorQueueStatisticsDataBuilder();
+
+ FlowCapableNodeConnectorQueueStatisticsBuilder queueStatisticsBuilder = new FlowCapableNodeConnectorQueueStatisticsBuilder();
+
+ queueStatisticsBuilder.fieldsFrom(swQueueStats);
+
+ queueStatisticsDataBuilder.setFlowCapableNodeConnectorQueueStatistics(queueStatisticsBuilder.build());
+
+ cache.get(notification.getId()).getNodeConnectorAndQueuesStatsMap()
+ .get(swQueueStats.getNodeConnectorId())
+ .put(swQueueStats.getQueueId(), queueStatisticsBuilder.build());
+
+
+ DataModificationTransaction it = this.statisticsManager.startChange();
+
+ InstanceIdentifier<Queue> queueRef
+ = InstanceIdentifier.builder(Nodes.class)
+ .child(Node.class, key)
+ .child(NodeConnector.class, new NodeConnectorKey(swQueueStats.getNodeConnectorId()))
+ .augmentation(FlowCapableNodeConnector.class)
+ .child(Queue.class, new QueueKey(swQueueStats.getQueueId())).toInstance();
+
+ QueueBuilder queueBuilder = new QueueBuilder();
+ queueBuilder.addAugmentation(FlowCapableNodeConnectorQueueStatisticsData.class, queueStatisticsDataBuilder.build());
+ queueBuilder.setKey(new QueueKey(swQueueStats.getQueueId()));
+
+ sucLogger.info("Augmenting queue statistics {} of queue {} to port {}"
+ ,queueStatisticsDataBuilder.build().toString(),
+ swQueueStats.getQueueId(),
+ swQueueStats.getNodeConnectorId());
+
+ it.putOperationalData(queueRef, queueBuilder.build());
+ it.commit();
+
+ }
+
+ }
+
@Override
public void onFlowStatisticsUpdated(FlowStatisticsUpdated notification) {
// TODO Auto-generated method stub
}
return true;
}
+
}
package org.opendaylight.controller.netconf.confignetconfconnector.osgi;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
import com.google.common.collect.Sets;
+import org.opendaylight.controller.config.api.LookupRegistry;
import org.opendaylight.controller.config.util.ConfigRegistryJMXClient;
import org.opendaylight.controller.config.yang.store.api.YangStoreException;
import org.opendaylight.controller.config.yang.store.api.YangStoreService;
import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot;
+import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
import org.opendaylight.controller.netconf.mapping.api.Capability;
String netconfSessionIdForReporting) throws YangStoreException {
yangStoreSnapshot = yangStoreService.getYangStoreSnapshot();
+ checkConsistencyBetweenYangStoreAndConfig(jmxClient, yangStoreSnapshot);
+
transactionProvider = new TransactionProvider(jmxClient, netconfSessionIdForReporting);
operationProvider = new NetconfOperationProvider(yangStoreSnapshot, jmxClient, transactionProvider,
netconfSessionIdForReporting);
capabilities = setupCapabilities(yangStoreSnapshot);
}
+
+ @VisibleForTesting
+ static void checkConsistencyBetweenYangStoreAndConfig(LookupRegistry jmxClient, YangStoreSnapshot yangStoreSnapshot) {
+ Set<String> missingModulesFromConfig = Sets.newHashSet();
+
+ Set<String> modulesSeenByConfig = jmxClient.getAvailableModuleFactoryQNames();
+ Map<String, Map<String, ModuleMXBeanEntry>> moduleMXBeanEntryMap = yangStoreSnapshot.getModuleMXBeanEntryMap();
+
+ for (Map<String, ModuleMXBeanEntry> moduleNameToMBE : moduleMXBeanEntryMap.values()) {
+ for (ModuleMXBeanEntry moduleMXBeanEntry : moduleNameToMBE.values()) {
+ String moduleSeenByYangStore = moduleMXBeanEntry.getYangModuleQName().toString();
+ if(modulesSeenByConfig.contains(moduleSeenByYangStore) == false)
+ missingModulesFromConfig.add(moduleSeenByYangStore);
+ }
+ }
+
+ Preconditions
+ .checkState(
+ missingModulesFromConfig.isEmpty(),
+ "There are inconsistencies between configuration subsystem and yangstore in terms of discovered yang modules, yang modules missing from config subsystem but present in yangstore: %s, %sAll modules present in config: %s",
+ missingModulesFromConfig, System.lineSeparator(), modulesSeenByConfig);
+
+ }
+
@Override
public void close() {
yangStoreSnapshot.close();
--- /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.netconf.confignetconfconnector.osgi;
+
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.matchers.JUnitMatchers;
+import org.opendaylight.controller.config.api.LookupRegistry;
+import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot;
+import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
+import org.opendaylight.yangtools.yang.common.QName;
+
+import java.net.URI;
+import java.util.Date;
+import java.util.Map;
+import java.util.Set;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+public class NetconfOperationServiceImplTest {
+
+ private Date date = new Date(0);
+
+ @Test
+ public void testCheckConsistencyBetweenYangStoreAndConfig_ok() throws Exception {
+ NetconfOperationServiceImpl.checkConsistencyBetweenYangStoreAndConfig(
+ mockJmxClient("qname1", "qname2"),
+ mockYangStoreSnapshot("qname2", "qname1"));
+ }
+
+ @Test
+ public void testCheckConsistencyBetweenYangStoreAndConfig_ok2() throws Exception {
+ NetconfOperationServiceImpl.checkConsistencyBetweenYangStoreAndConfig(
+ mockJmxClient("qname1", "qname2", "qname4", "qname5"),
+ mockYangStoreSnapshot("qname2", "qname1"));
+ }
+
+ @Test
+ public void testCheckConsistencyBetweenYangStoreAndConfig_ok3() throws Exception {
+ NetconfOperationServiceImpl.checkConsistencyBetweenYangStoreAndConfig(
+ mockJmxClient(),
+ mockYangStoreSnapshot());
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testCheckConsistencyBetweenYangStoreAndConfig_yangStoreMore() throws Exception {
+ try {
+ NetconfOperationServiceImpl.checkConsistencyBetweenYangStoreAndConfig(mockJmxClient("qname1"),
+ mockYangStoreSnapshot("qname2", "qname1"));
+ } catch (IllegalStateException e) {
+ String message = e.getMessage();
+ Assert.assertThat(
+ message,
+ JUnitMatchers
+ .containsString(" missing from config subsystem but present in yangstore: [(namespace?revision=1970-01-01)qname2]"));
+ Assert.assertThat(
+ message,
+ JUnitMatchers
+ .containsString("All modules present in config: [(namespace?revision=1970-01-01)qname1]"));
+ throw e;
+ }
+ }
+
+ private YangStoreSnapshot mockYangStoreSnapshot(String... qnames) {
+ YangStoreSnapshot mock = mock(YangStoreSnapshot.class);
+
+ Map<String, Map<String, ModuleMXBeanEntry>> map = Maps.newHashMap();
+
+ Map<String, ModuleMXBeanEntry> innerMap = Maps.newHashMap();
+
+ int i = 1;
+ for (String qname : qnames) {
+ innerMap.put(Integer.toString(i++), mockMBeanEntry(qname));
+ }
+
+ map.put("1", innerMap);
+
+ doReturn(map).when(mock).getModuleMXBeanEntryMap();
+
+ return mock;
+ }
+
+ private ModuleMXBeanEntry mockMBeanEntry(String qname) {
+ ModuleMXBeanEntry mock = mock(ModuleMXBeanEntry.class);
+ QName q = getQName(qname);
+ doReturn(q).when(mock).getYangModuleQName();
+ return mock;
+ }
+
+ private QName getQName(String qname) {
+ return new QName(URI.create("namespace"), date, qname);
+ }
+
+ private LookupRegistry mockJmxClient(String... visibleQNames) {
+ LookupRegistry mock = mock(LookupRegistry.class);
+ Set<String> qnames = Sets.newHashSet();
+ for (String visibleQName : visibleQNames) {
+ QName q = getQName(visibleQName);
+ qnames.add(q.toString());
+ }
+ doReturn(qnames).when(mock).getAvailableModuleFactoryQNames();
+ return mock;
+ }
+}
org.opendaylight.controller.netconf.client,
org.opendaylight.controller.netconf.util.osgi,
org.opendaylight.controller.netconf.util.xml,
+ org.opendaylight.controller.netconf.util.messages,
io.netty.channel,
io.netty.channel.nio,
io.netty.util.concurrent,
package org.opendaylight.controller.netconf.persist.impl;
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
import io.netty.channel.EventLoopGroup;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetSocketAddress;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.annotation.concurrent.Immutable;
+
import org.opendaylight.controller.config.api.ConflictingVersionException;
import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.client.NetconfClient;
import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.controller.netconf.util.messages.NetconfMessageAdditionalHeader;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
-import javax.annotation.concurrent.Immutable;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.InetSocketAddress;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
@Immutable
public class ConfigPusher {
long deadline = pollingStart + timeout;
+ String additionalHeader = NetconfMessageAdditionalHeader.toString("unknown", address.getAddress().getHostAddress(),
+ Integer.toString(address.getPort()), "tcp", Optional.of("persister"));
+
Set<String> latestCapabilities = new HashSet<>();
while (System.currentTimeMillis() < deadline) {
attempt++;
- NetconfClientDispatcher netconfClientDispatcher = new NetconfClientDispatcher(nettyThreadgroup, nettyThreadgroup);
+ NetconfClientDispatcher netconfClientDispatcher = new NetconfClientDispatcher(nettyThreadgroup,
+ nettyThreadgroup, additionalHeader);
NetconfClient netconfClient;
try {
netconfClient = new NetconfClient(this.toString(), address, delay, netconfClientDispatcher);
--- /dev/null
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <artifactId>netconf-subsystem</artifactId>
+ <groupId>org.opendaylight.controller</groupId>
+ <version>0.2.3-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>ietf-netconf-monitoring-extension</artifactId>
+ <name>${project.artifactId}</name>
+ <packaging>bundle</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>ietf-netconf-monitoring</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ </dependencies>
+
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-maven-plugin</artifactId>
+ <version>${yangtools.version}</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>generate-sources</goal>
+ </goals>
+ <configuration>
+ <yangFilesRootDir>src/main/yang</yangFilesRootDir>
+ <codeGenerators>
+ <generator>
+ <codeGeneratorClass>
+ org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl
+ </codeGeneratorClass>
+ <outputBaseDir>
+ target/generated-sources/monitoring
+ </outputBaseDir>
+ </generator>
+ </codeGenerators>
+ <inspectDependencies>true</inspectDependencies>
+ </configuration>
+ </execution>
+ </executions>
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>maven-sal-api-gen-plugin</artifactId>
+ <version>${yangtools.binding.version}</version>
+ </dependency>
+ </dependencies>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <version>1.7</version>
+ <executions>
+ <execution>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>add-source</goal>
+ </goals>
+ <configuration>
+ <sources>
+ <source>target/generated-sources/sal</source>
+ </sources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Import-Package>
+ com.google.common.collect,
+ org.opendaylight.yangtools.yang.binding,
+ org.opendaylight.yangtools.yang.common,
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004,
+ </Import-Package>
+ <Export-Package>
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210,
+ </Export-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
\ No newline at end of file
--- /dev/null
+module ietf-netconf-monitoring-extension {
+
+ yang-version 1;
+
+ namespace
+ "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring-extension";
+
+ prefix ncme;
+
+ import ietf-netconf-monitoring {
+ prefix ncm;
+ }
+
+ revision "2013-12-10" {
+ description "Initial revision.";
+
+ }
+
+ identity netconf-tcp {
+ base ncm:transport;
+ description
+ "NETCONF over TCP.";
+ }
+
+ augment "/ncm:netconf-state/ncm:sessions/ncm:session" {
+ leaf session-identifier {
+ type string;
+ }
+ }
+
+}
\ No newline at end of file
<groupId>${project.groupId}</groupId>
<artifactId>ietf-netconf-monitoring</artifactId>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>ietf-netconf-monitoring-extension</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.bgpcep</groupId>
package org.opendaylight.controller.netconf.api;
-import com.google.common.base.Optional;
import org.w3c.dom.Document;
+import com.google.common.base.Optional;
+
/**
* NetconfMessage represents a wrapper around org.w3c.dom.Document. Needed for
* implementing ProtocolMessage interface.
import io.netty.util.HashedWheelTimer;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
+
import java.io.Closeable;
import java.net.InetSocketAddress;
+
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.api.NetconfSession;
import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.base.Optional;
+
public class NetconfClientDispatcher extends AbstractDispatcher<NetconfClientSession, NetconfClientSessionListener> implements Closeable {
private static final Logger logger = LoggerFactory.getLogger(NetconfClient.class);
public NetconfClientDispatcher(EventLoopGroup bossGroup, EventLoopGroup workerGroup) {
super(bossGroup, workerGroup);
timer = new HashedWheelTimer();
- this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer);
+ this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.<String>absent());
+ }
+
+ public NetconfClientDispatcher(EventLoopGroup bossGroup, EventLoopGroup workerGroup, String additionalHeader) {
+ super(bossGroup, workerGroup);
+ timer = new HashedWheelTimer();
+ this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.of(additionalHeader));
}
public Future<NetconfClientSession> createClient(InetSocketAddress address,
package org.opendaylight.controller.netconf.client;
-import com.google.common.base.Preconditions;
import io.netty.channel.Channel;
import io.netty.util.Timer;
import io.netty.util.concurrent.Promise;
+
+import java.io.IOException;
+import java.io.InputStream;
+
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.api.NetconfSessionPreferences;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.opendaylight.protocol.framework.SessionNegotiatorFactory;
import org.xml.sax.SAXException;
-import java.io.IOException;
-import java.io.InputStream;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
public class NetconfClientSessionNegotiatorFactory implements SessionNegotiatorFactory {
private final Timer timer;
- public NetconfClientSessionNegotiatorFactory(Timer timer) {
+ private final Optional<String> additionalHeader;
+
+ public NetconfClientSessionNegotiatorFactory(Timer timer, Optional<String> additionalHeader) {
this.timer = timer;
+ this.additionalHeader = additionalHeader;
}
private static NetconfMessage loadHelloMessageTemplate() {
public SessionNegotiator getSessionNegotiator(SessionListenerFactory sessionListenerFactory, Channel channel,
Promise promise) {
// Hello message needs to be recreated every time
- NetconfSessionPreferences proposal = new NetconfSessionPreferences(loadHelloMessageTemplate());
+ NetconfMessage helloMessage = loadHelloMessageTemplate();
+ if(this.additionalHeader.isPresent()) {
+ helloMessage = new NetconfMessage(helloMessage.getDocument(), additionalHeader.get());
+ }
+ NetconfSessionPreferences proposal = new NetconfSessionPreferences(helloMessage);
return new NetconfClientSessionNegotiator(proposal, promise, channel, timer,
sessionListenerFactory.getSessionListener());
}
import io.netty.util.HashedWheelTimer;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
+
import java.io.IOException;
import java.net.InetSocketAddress;
+
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.api.NetconfSession;
import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
import org.opendaylight.protocol.framework.SessionListener;
import org.opendaylight.protocol.framework.SessionListenerFactory;
+import com.google.common.base.Optional;
+
public class NetconfSshClientDispatcher extends NetconfClientDispatcher {
private AuthenticationHandler authHandler;
super(bossGroup, workerGroup);
this.authHandler = authHandler;
this.timer = new HashedWheelTimer();
- this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer);
+ this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.<String>absent());
+ }
+
+ public NetconfSshClientDispatcher(AuthenticationHandler authHandler, EventLoopGroup bossGroup,
+ EventLoopGroup workerGroup, String additionalHeader) {
+ super(bossGroup, workerGroup, additionalHeader);
+ this.authHandler = authHandler;
+ this.timer = new HashedWheelTimer();
+ this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.of(additionalHeader));
}
public Future<NetconfClientSession> createClient(InetSocketAddress address,
<groupId>${project.groupId}</groupId>
<artifactId>ietf-netconf-monitoring</artifactId>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>ietf-netconf-monitoring-extension</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netconf-util</artifactId>
org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state,
org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions,
org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas,
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210,
+ org.opendaylight.yangtools.yang.binding,
</Import-Package>
</instructions>
</configuration>
package org.opendaylight.controller.netconf.impl;
-import com.google.common.base.Preconditions;
import io.netty.channel.Channel;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
import org.opendaylight.controller.netconf.api.NetconfSession;
import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
import org.opendaylight.protocol.framework.SessionListener;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.DomainName;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Host;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.NetconfTcp;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.Session1;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.Session1Builder;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfSsh;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.Transport;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import com.google.common.base.Preconditions;
public class NetconfServerSession extends NetconfSession implements NetconfManagementSession {
builder.setOutNotifications(new ZeroBasedCounter32(0L));
builder.setKey(new SessionKey(getSessionId()));
+
+ Session1Builder builder1 = new Session1Builder();
+ builder1.setSessionIdentifier(header.getSessionType());
+ builder.addAugmentation(Session1.class, builder1.build());
+
return builder.build();
}
private Class<? extends Transport> getTransportForString(String transport) {
switch(transport) {
case "ssh" : return NetconfSsh.class;
- // TODO what about tcp
- case "tcp" : return NetconfSsh.class;
+ case "tcp" : return NetconfTcp.class;
default: throw new IllegalArgumentException("Unknown transport type " + transport);
}
}
package org.opendaylight.controller.netconf.impl;
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
import io.netty.channel.Channel;
import io.netty.util.Timer;
import io.netty.util.concurrent.Promise;
+
+import java.net.InetSocketAddress;
+
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.api.NetconfServerSessionPreferences;
+import org.opendaylight.controller.netconf.impl.util.AdditionalHeaderUtil;
import org.opendaylight.controller.netconf.util.AbstractNetconfSessionNegotiator;
import org.opendaylight.protocol.framework.SessionListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import com.google.common.base.Optional;
public class NetconfServerSessionNegotiator extends
AbstractNetconfSessionNegotiator<NetconfServerSessionPreferences, NetconfServerSession> {
static final Logger logger = LoggerFactory.getLogger(NetconfServerSessionNegotiator.class);
- private static final AdditionalHeader DEFAULT_HEADER = new AdditionalHeader();
-
protected NetconfServerSessionNegotiator(NetconfServerSessionPreferences sessionPreferences,
Promise<NetconfServerSession> promise, Channel channel, Timer timer, SessionListener sessionListener) {
super(sessionPreferences, promise, channel, timer, sessionListener);
AdditionalHeader parsedHeader;
if (additionalHeader.isPresent()) {
- parsedHeader = new AdditionalHeader(additionalHeader.get());
+ parsedHeader = AdditionalHeaderUtil.fromString(additionalHeader.get());
} else {
- parsedHeader = DEFAULT_HEADER;
+ parsedHeader = new AdditionalHeader("unknown", ((InetSocketAddress)channel.localAddress()).getHostString(),
+ "tcp", "client");
}
logger.debug("Additional header from hello parsed as {} from {}", parsedHeader, additionalHeader);
return new NetconfServerSession(sessionListener, channel, sessionPreferences.getSessionId(), parsedHeader);
}
- static class AdditionalHeader {
+ public static class AdditionalHeader {
- private static final Pattern pattern = Pattern
- .compile("\\[(?<username>[^;]+);(?<address>[0-9\\.]+)[:/](?<port>[0-9]+);(?<transport>[a-z]+)[^\\]]+\\]");
private final String username;
private final String address;
private final String transport;
+ private final String sessionIdentifier;
- public AdditionalHeader(String addHeaderAsString) {
- addHeaderAsString = addHeaderAsString.trim();
- Matcher matcher = pattern.matcher(addHeaderAsString);
- Preconditions.checkArgument(matcher.matches(), "Additional header in wrong format %s, expected %s",
- addHeaderAsString, pattern);
- this.username = matcher.group("username");
- this.address = matcher.group("address");
- this.transport = matcher.group("transport");
- }
-
- private AdditionalHeader() {
- this.username = this.address = "unknown";
- this.transport = "ssh";
+ public AdditionalHeader(String userName, String hostAddress, String transport, String sessionIdentifier) {
+ this.address = hostAddress;
+ this.username = userName;
+ this.transport = transport;
+ this.sessionIdentifier = sessionIdentifier;
}
String getUsername() {
return transport;
}
+ String getSessionType() {
+ return sessionIdentifier;
+ }
+
@Override
public String toString() {
final StringBuffer sb = new StringBuffer("AdditionalHeader{");
return sb.toString();
}
}
+
}
--- /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.netconf.impl.util;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.opendaylight.controller.netconf.impl.NetconfServerSessionNegotiator.AdditionalHeader;
+
+import com.google.common.base.Preconditions;
+
+public class AdditionalHeaderUtil {
+
+ private static final Pattern pattern = Pattern
+ .compile("\\[(?<username>[^;]+);(?<address>[0-9\\.]+)[:/](?<port>[0-9]+);(?<transport>[a-z]+)[^\\]]+\\]");
+ private static final Pattern customHeaderPattern = Pattern
+ .compile("\\[(?<username>[^;]+);(?<address>[0-9\\.]+)[:/](?<port>[0-9]+);(?<transport>[a-z]+);(?<sessionIdentifier>[a-z]+)[^\\]]+\\]");
+
+ public static AdditionalHeader fromString(String additionalHeader) {
+ additionalHeader = additionalHeader.trim();
+ Matcher matcher = pattern.matcher(additionalHeader);
+ Matcher matcher2 = customHeaderPattern.matcher(additionalHeader);
+ Preconditions.checkArgument(matcher.matches(), "Additional header in wrong format %s, expected %s",
+ additionalHeader, pattern);
+ String username = matcher.group("username");
+ String address = matcher.group("address");
+ String transport = matcher.group("transport");
+ String sessionIdentifier = "client";
+ if (matcher2.matches()) {
+ sessionIdentifier = matcher2.group("sessionIdentifier");
+ }
+ return new AdditionalHeader(username, address, transport, sessionIdentifier);
+ }
+
+}
package org.opendaylight.controller.netconf.impl;
import junit.framework.Assert;
+
import org.junit.Test;
+import org.opendaylight.controller.netconf.impl.util.AdditionalHeaderUtil;
public class AdditionalHeaderParserTest {
@Test
public void testParsing() throws Exception {
String s = "[netconf;10.12.0.102:48528;ssh;;;;;;]";
- NetconfServerSessionNegotiator.AdditionalHeader header = new NetconfServerSessionNegotiator.AdditionalHeader(s);
+ NetconfServerSessionNegotiator.AdditionalHeader header = AdditionalHeaderUtil.fromString(s);
Assert.assertEquals("netconf", header.getUsername());
Assert.assertEquals("10.12.0.102", header.getAddress());
Assert.assertEquals("ssh", header.getTransport());
@Test
public void testParsing2() throws Exception {
String s = "[tomas;10.0.0.0/10000;tcp;1000;1000;;/home/tomas;;]";
- NetconfServerSessionNegotiator.AdditionalHeader header = new NetconfServerSessionNegotiator.AdditionalHeader(s);
+ NetconfServerSessionNegotiator.AdditionalHeader header = AdditionalHeaderUtil.fromString(s);
Assert.assertEquals("tomas", header.getUsername());
Assert.assertEquals("10.0.0.0", header.getAddress());
Assert.assertEquals("tcp", header.getTransport());
@Test(expected = IllegalArgumentException.class)
public void testParsingNoUsername() throws Exception {
String s = "[10.12.0.102:48528;ssh;;;;;;]";
- new NetconfServerSessionNegotiator.AdditionalHeader(s);
+ AdditionalHeaderUtil.fromString(s);
}
}
package org.opendaylight.controller.netconf.impl;
-import com.google.common.base.Optional;
-import com.google.common.collect.Sets;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.util.HashedWheelTimer;
+
+import java.io.DataOutputStream;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.lang.management.ManagementFactory;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import javax.management.ObjectName;
+
import org.apache.commons.io.IOUtils;
import org.junit.After;
import org.junit.AfterClass;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
-import javax.management.ObjectName;
-import java.io.DataOutputStream;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.lang.management.ManagementFactory;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
+import com.google.common.base.Optional;
+import com.google.common.collect.Sets;
public class ConcurrentClientsTest {
private static final int CONCURRENCY = 16;
private static EventLoopGroup nettyGroup = new NioEventLoopGroup();
- public static final NetconfClientDispatcher NETCONF_CLIENT_DISPATCHER = new NetconfClientDispatcher( nettyGroup, nettyGroup);
+ public static final NetconfClientDispatcher NETCONF_CLIENT_DISPATCHER =
+ new NetconfClientDispatcher( nettyGroup, nettyGroup);
@Mock
private YangStoreService yangStoreService;
*/
package org.opendaylight.controller.netconf.it;
-import com.google.common.base.Charsets;
-import com.google.common.base.Optional;
-import com.google.common.collect.Sets;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.util.HashedWheelTimer;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
import junit.framework.Assert;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.matchers.JUnitMatchers;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.util.Collection;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-import static org.mockito.Matchers.anyLong;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
+import com.google.common.base.Charsets;
+import com.google.common.base.Optional;
+import com.google.common.collect.Sets;
public class NetconfMonitoringITTest extends AbstractConfigTest {
org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924,
org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924,
org.osgi.util.tracker,
+ org.opendaylight.yangtools.yang.common,
org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state,
org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions,
org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004,
org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas,
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210,
+ org.opendaylight.yangtools.yang.binding,
</Import-Package>
</instructions>
</configuration>
*/
package org.opendaylight.controller.netconf.monitoring.xml.model;
-import com.google.common.base.Preconditions;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfSsh;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions.Session;
-
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlTransient;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.Session1;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions.Session;
+import org.opendaylight.yangtools.yang.common.QName;
+
final class MonitoringSession {
@XmlTransient
@XmlElement(name = "transport")
public String getTransport() {
- Preconditions.checkState(managementSession.getTransport() == NetconfSsh.class);
- return "netconf-ssh";
+ try {
+ QName qName = (QName) managementSession.getTransport().getField("QNAME").get(null);
+ return qName.getLocalName();
+ } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
+ throw new IllegalArgumentException("Unknown transport type " + managementSession.getTransport(), e);
+ }
+ }
+
+ @XmlElement(name= "session-identifier")
+ public String getSessionType() {
+ return managementSession.getAugmentation(Session1.class).getSessionIdentifier();
}
@XmlElement(name = "username")
*/
package org.opendaylight.controller.netconf.monitoring.xml;
-import com.google.common.collect.Lists;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import java.util.Date;
+
import org.junit.Test;
import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
import org.opendaylight.controller.netconf.monitoring.xml.model.NetconfState;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.DomainName;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Host;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.Session1;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfSsh;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Schemas;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.SchemasBuilder;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.ZeroBasedCounter32;
import org.w3c.dom.Element;
-import java.util.Date;
-
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
+import com.google.common.collect.Lists;
public class JaxBSerializerTest {
private Session getMockSession() {
Session mocked = mock(Session.class);
+ Session1 mockedSession1 = mock(Session1.class);
+ doReturn("client").when(mockedSession1).getSessionIdentifier();
doReturn(1L).when(mocked).getSessionId();
doReturn(new DateAndTime(new Date().toString())).when(mocked).getLoginTime();
doReturn(new Host(new DomainName("address/port"))).when(mocked).getSourceHost();
doReturn(new ZeroBasedCounter32(0L)).when(mocked).getOutRpcErrors();
doReturn(NetconfSsh.class).when(mocked).getTransport();
doReturn("username").when(mocked).getUsername();
+ doReturn(mockedSession1).when(mocked).getAugmentation(Session1.class);
return mocked;
}
}
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
-
import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.ssl.SslHandler;
import io.netty.util.Timeout;
import io.netty.util.Timer;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import io.netty.util.concurrent.Promise;
-
-import org.opendaylight.controller.netconf.api.NetconfSession;
import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.api.NetconfSession;
import org.opendaylight.controller.netconf.api.NetconfSessionPreferences;
import org.opendaylight.controller.netconf.util.handler.FramingMechanismHandlerFactory;
import org.opendaylight.controller.netconf.util.handler.NetconfMessageAggregator;
// TODO what time ?
private static final long INITIAL_HOLDTIMER = 1;
+
private static final Logger logger = LoggerFactory.getLogger(AbstractNetconfSessionNegotiator.class);
+ public static final String NAME_OF_EXCEPTION_HANDLER = "lastExceptionHandler";
protected final P sessionPreferences;
private final SessionListener sessionListener;
+ private Timeout timeout;
/**
* Possible states for Finite State Machine
}
@Override
- protected void startNegotiation() throws Exception {
+ protected void startNegotiation() {
final Optional<SslHandler> sslHandler = getSslHandler(channel);
if (sslHandler.isPresent()) {
Future<Channel> future = sslHandler.get().handshakeFuture();
final NetconfMessage helloMessage = this.sessionPreferences.getHelloMessage();
logger.debug("Session negotiation started with hello message {}", XmlUtil.toString(helloMessage.getDocument()));
- sendMessage(helloMessage);
- changeState(State.OPEN_WAIT);
+ channel.pipeline().addLast(NAME_OF_EXCEPTION_HANDLER, new ChannelHandler() {
+ @Override
+ public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
+ }
+
+ @Override
+ public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
+ }
+
+ @Override
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+ logger.warn("An exception occurred during negotiation on channel {}", channel.localAddress(), cause);
+ cancelTimeout();
+ negotiationFailed(cause);
+ changeState(State.FAILED);
+ }
+ });
- this.timer.newTimeout(new TimerTask() {
+ timeout = this.timer.newTimeout(new TimerTask() {
@Override
public void run(final Timeout timeout) throws Exception {
synchronized (this) {
"Session was not established after " + timeout);
negotiationFailed(cause);
changeState(State.FAILED);
- }
+ } else
+ channel.pipeline().remove(NAME_OF_EXCEPTION_HANDLER);
}
}
}, INITIAL_HOLDTIMER, TimeUnit.MINUTES);
+
+ sendMessage(helloMessage);
+ changeState(State.OPEN_WAIT);
+ }
+
+ private void cancelTimeout() {
+ if(timeout!=null)
+ timeout.cancel();
}
private void sendMessage(NetconfMessage message) {
--- /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.netconf.util.messages;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+
+/**
+ * Additional header can be used with hello message to carry information about
+ * session's connection. Provided information can be reported via netconf
+ * monitoring.
+ * <pre>
+ * It has pattern "[username; host-address:port; transport; session-identifier;]"
+ * username - name of account on a remote
+ * host-address - client's IP address
+ * port - port number
+ * transport - tcp, ssh
+ * session-identifier - persister, client
+ * Session-identifier is optional, others mandatory.
+ * </pre>
+ */
+public class NetconfMessageAdditionalHeader {
+
+ private static final String SC = ";";
+
+ public static String toString(String userName, String hostAddress, String port, String transport,
+ Optional<String> sessionIdentifier) {
+ Preconditions.checkNotNull(userName);
+ Preconditions.checkNotNull(hostAddress);
+ Preconditions.checkNotNull(port);
+ Preconditions.checkNotNull(transport);
+ String identifier = sessionIdentifier.isPresent() ? sessionIdentifier.get() : "";
+ return "[" + userName + SC + hostAddress + ":" + port + SC + transport + SC + identifier + SC + "]"
+ + System.lineSeparator();
+ }
+}
package org.opendaylight.controller.netconf.util.messages;
-import com.google.common.base.Charsets;
-import com.google.common.base.Optional;
-import com.google.common.collect.Lists;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.List;
+
import org.opendaylight.controller.netconf.api.NetconfDeserializerException;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.List;
+import com.google.common.base.Charsets;
+import com.google.common.base.Optional;
+import com.google.common.collect.Lists;
/**
* NetconfMessageFactory for (de)serializing DOM documents.
Comment comment = netconfMessage.getDocument().createComment("clientId:" + clientId.get());
netconfMessage.getDocument().appendChild(comment);
}
- final ByteBuffer msgBytes = Charsets.UTF_8.encode(xmlToString(netconfMessage.getDocument()));
+ ByteBuffer msgBytes;
+ if(netconfMessage.getAdditionalHeader().isPresent()) {
+ String header = netconfMessage.getAdditionalHeader().get();
+ logger.trace("Header of netconf message parsed \n{}", header);
+ msgBytes = Charsets.UTF_8.encode(header + xmlToString(netconfMessage.getDocument()));
+ } else {
+ msgBytes = Charsets.UTF_8.encode(xmlToString(netconfMessage.getDocument()));
+ }
String content = xmlToString(netconfMessage.getDocument());
logger.trace("Putting message \n{}", content);
<module>../../third-party/com.siemens.ct.exi</module>
<module>netconf-monitoring</module>
<module>ietf-netconf-monitoring</module>
+ <module>ietf-netconf-monitoring-extension</module>
</modules>
<profiles>
if (p == null) {
return false;
}
- if (this.isFlatLayer2()) {
- return true;
- }
- return this.nodeConnectors.contains(p);
+ return isFlatLayer2() || nodeConnectors.contains(p);
}
public boolean isMutualExclusive(Subnet otherSubnet) {
return DEFAULT_SUBNET;
}
- Subnet sub;
- Set<InetAddress> indices = subnets.keySet();
- for (InetAddress i : indices) {
- sub = subnets.get(i);
- if (sub.isSubnetOf(networkAddress)) {
- return sub;
+ for(Map.Entry<InetAddress,Subnet> subnetEntry : subnets.entrySet()) {
+ if(subnetEntry.getValue().isSubnetOf(networkAddress)) {
+ return subnetEntry.getValue();
}
}
return null;