<appauth.version>0.4.2-SNAPSHOT</appauth.version>
<!-- Controller Modules Versions -->
<arphandler.version>0.5.2-SNAPSHOT</arphandler.version>
+ <asm.version>4.1</asm.version>
<!-- Plugin Versions -->
<bouncycastle.version>1.50</bouncycastle.version>
<bundle.plugin.version>2.3.7</bundle.plugin.version>
<!-- OpenEXI third party lib for netconf-->
<exi.nagasena.version>0000.0002.0038.0-SNAPSHOT</exi.nagasena.version>
<failsafe.version>2.15</failsafe.version>
+ <feature.transaction.version>1.0.1</feature.transaction.version>
<felix.dependencymanager.shell.version>3.0.1</felix.dependencymanager.shell.version>
<felix.dependencymanager.version>3.1.0</felix.dependencymanager.version>
<felix.fileinstall.version>3.1.6</felix.fileinstall.version>
<jsr305.api.version>2.0.1</jsr305.api.version>
<jsr311.api.version>1.1.1</jsr311.api.version>
<junit.version>4.8.1</junit.version>
+ <karaf.version>3.0.1</karaf.version>
<logback.version>1.0.9</logback.version>
<logging.bridge.version>0.4.2-SNAPSHOT</logging.bridge.version>
<maven.compile.plugin.version>2.5.1</maven.compile.plugin.version>
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
<sonar.language>java</sonar.language>
<sonar.skippedModules>org.openflow.openflowj,net.sf.jung2</sonar.skippedModules>
+ <spifly.version>1.0.0</spifly.version>
<spring-osgi.version>1.2.1</spring-osgi.version>
+ <spring-security-karaf.version>3.1.4.RELEASE</spring-security-karaf.version>
<spring-security.version>3.1.3.RELEASE</spring-security.version>
<spring.version>3.1.3.RELEASE</spring.version>
<statistics.northbound.version>0.4.2-SNAPSHOT</statistics.northbound.version>
<artifactId>netconf-client</artifactId>
<version>${netconf.version}</version>
</dependency>
+
+ <!--Netconf config-->
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-config-dispatcher</artifactId>
+ <version>${netconf.version}</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netconf-impl</artifactId>
<phase>generate-sources</phase>
<configuration>
<sources>
+ <source>src/main/yang</source>
<source>${jmxGeneratorPath}</source>
<source>${salGeneratorPath}</source>
<source>${xtend.dstdir}</source>
</goals>
</pluginExecutionFilter>
<action>
- <ignore></ignore>
+ <execute></execute>
</action>
</pluginExecution>
<pluginExecution>
*/
protected ChannelFuture createServer(final InetSocketAddress address, final PipelineInitializer<S> initializer) {
final ServerBootstrap b = new ServerBootstrap();
- b.group(this.bossGroup, this.workerGroup);
- b.channel(NioServerSocketChannel.class);
- b.option(ChannelOption.SO_BACKLOG, 128);
b.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
initializer.initializeChannel(ch, new DefaultPromise<S>(executor));
}
});
- b.childOption(ChannelOption.SO_KEEPALIVE, true);
+ b.option(ChannelOption.SO_BACKLOG, 128);
+ b.childOption(ChannelOption.SO_KEEPALIVE, true);
customizeBootstrap(b);
+ if (b.group() == null) {
+ b.group(bossGroup, workerGroup);
+ }
+ try {
+ b.channel(NioServerSocketChannel.class);
+ } catch (IllegalStateException e) {
+ LOG.trace("Not overriding channelFactory on bootstrap {}", b, e);
+ }
+
// Bind and start to accept incoming connections.
final ChannelFuture f = b.bind(address);
LOG.debug("Initiated server {} at {}.", f, address);
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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
+-->
+<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/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-plugin-parent</artifactId>
+ <version>0.2.5-SNAPSHOT</version>
+ <relativePath>../config-plugin-parent</relativePath>
+ </parent>
+
+ <artifactId>netconf-config-dispatcher</artifactId>
+ <packaging>bundle</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>config-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>netconf-client</artifactId>
+ <version>${netconf.version}</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Export-Package>org.opendaylight.controller.config.yang.config.netconf,
+ org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.netconf.rev140408,</Export-Package>
+ <Import-Package>*</Import-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-maven-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
+</project>
--- /dev/null
+/*
+ * Copyright (c) 2014 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.config.yang.config.netconf.client.dispatcher;
+
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
+
+/**
+*
+*/
+public final class NetconfClientDispatcherModule extends org.opendaylight.controller.config.yang.config.netconf.client.dispatcher.AbstractNetconfClientDispatcherModule
+ {
+
+ public NetconfClientDispatcherModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+ super(identifier, dependencyResolver);
+ }
+
+ public NetconfClientDispatcherModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
+ NetconfClientDispatcherModule oldModule, java.lang.AutoCloseable oldInstance) {
+
+ super(identifier, dependencyResolver, oldModule, oldInstance);
+ }
+
+ @Override
+ protected void customValidation(){
+ }
+
+ @Override
+ public java.lang.AutoCloseable createInstance() {
+ return new NetconfClientDispatcherImpl(getBossThreadGroupDependency(), getWorkerThreadGroupDependency(), getTimerDependency());
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 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.config.yang.config.netconf.client.dispatcher;
+
+/**
+*
+*/
+public class NetconfClientDispatcherModuleFactory extends org.opendaylight.controller.config.yang.config.netconf.client.dispatcher.AbstractNetconfClientDispatcherModuleFactory
+{
+
+
+}
--- /dev/null
+// vi: set smarttab et sw=4 tabstop=4:
+module odl-netconf-cfg {
+
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:controller:config:netconf";
+ prefix "cfg-net";
+
+ import config { prefix config; revision-date 2013-04-05; }
+
+ description
+ "This module contains the base YANG definitions for
+ netconf related services.
+
+ Copyright (c)2013 Cisco Systems, Inc. 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";
+
+ revision "2014-04-08" {
+ description
+ "Initial revision.";
+ }
+
+ identity netconf-client-dispatcher {
+
+ base "config:service-type";
+ config:java-class "org.opendaylight.controller.netconf.client.NetconfClientDispatcher";
+ }
+}
\ No newline at end of file
--- /dev/null
+// vi: set smarttab et sw=4 tabstop=4:
+module odl-netconfig-client-cfg {
+
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:controller:config:netconf:client:dispatcher";
+ prefix "cfg-net-client";
+
+ import config { prefix config; revision-date 2013-04-05; }
+ import odl-netconf-cfg { prefix cfg-net; revision-date 2014-04-08; }
+ import netty {prefix netty; }
+
+ description
+ "This module contains the base YANG definitions for
+ netconf-client-dispatcher implementation.
+
+ Copyright (c)2013 Cisco Systems, Inc. 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";
+
+ revision "2014-04-08" {
+ description
+ "Initial revision.";
+ }
+
+ identity netconf-client-dispatcher {
+ base config:module-type;
+ config:provided-service cfg-net:netconf-client-dispatcher;
+ config:java-name-prefix NetconfClientDispatcher;
+ }
+
+ augment "/config:modules/config:module/config:configuration" {
+ case netconf-client-dispatcher {
+ when "/config:modules/config:module/config:type = 'netconf-client-dispatcher'";
+
+ container boss-thread-group {
+ uses config:service-ref {
+ refine type {
+ config:required-identity netty:netty-threadgroup;
+ }
+ }
+ }
+
+ container worker-thread-group {
+ uses config:service-ref {
+ refine type {
+ config:required-identity netty:netty-threadgroup;
+ }
+ }
+ }
+
+ container timer {
+ uses config:service-ref {
+ refine type {
+ config:required-identity netty:netty-timer;
+ }
+ }
+ }
+ }
+ }
+
+}
\ No newline at end of file
base "config:service-type";
config:java-class "io.netty.util.Timer";
}
-}
\ No newline at end of file
+
+ identity channel-factory {
+ description
+ "Configuration wrapper around netty's channel factory";
+
+ base "config:service-type";
+ config:java-class "io.netty.bootstrap.ChannelFactory";
+ }
+}
<module>yang-test-plugin</module>
<module>shutdown-api</module>
<module>shutdown-impl</module>
+ <module>netconf-config-dispatcher</module>
<module>config-module-archetype</module>
</modules>
<artifactId>gmaven-plugin</artifactId>
<version>1.0</version>
</plugin>
- <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
- <plugin>
- <groupId>org.eclipse.m2e</groupId>
- <artifactId>lifecycle-mapping</artifactId>
- <version>1.0.0</version>
- <configuration>
- <lifecycleMappingMetadata>
- <pluginExecutions>
- <pluginExecution>
- <pluginExecutionFilter>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-maven-plugin</artifactId>
- <versionRange>[0.5.7-SNAPSHOT,)</versionRange>
- <goals>
- <goal>generate-sources</goal>
- </goals>
- </pluginExecutionFilter>
- <action>
- <ignore></ignore>
- </action>
- </pluginExecution>
- </pluginExecutions>
- </lifecycleMappingMetadata>
- </configuration>
- </plugin>
<plugin>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-maven-plugin</artifactId>
</dependencies>
- <build>
- <plugins>
- <plugin>
- <artifactId>maven-compiler-plugin</artifactId>
- <version>3.1</version>
- <configuration>
- <compilerId>groovy-eclipse-compiler</compilerId>
- <verbose>false</verbose>
- </configuration>
- <dependencies>
-
- <dependency>
- <groupId>org.codehaus.groovy</groupId>
- <artifactId>groovy-eclipse-batch</artifactId>
- <version>2.1.8-01</version>
- </dependency>
- <dependency>
- <groupId>org.codehaus.groovy</groupId>
- <artifactId>groovy-eclipse-compiler</artifactId>
- <version>2.8.0-01</version>
- </dependency>
- </dependencies>
- </plugin>
-
- </plugins>
- </build>
</project>
public static String toString(ModuleField moduleField) {
StringBuilder builder = new StringBuilder();
builder.append(" ");
- builder.append("protected final "
+ builder.append("public static final "
+ JmxAttribute.class.getCanonicalName() + " "
+ moduleField.getName() + "JmxAttribute = new "
+ JmxAttribute.class.getCanonicalName() + "(\""
+++ /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.config.yangjmxgenerator.plugin.gofactory
-import com.google.common.base.Optional
-import org.opendaylight.controller.config.api.DependencyResolver
-import org.opendaylight.controller.config.api.DynamicMBeanWithInstance
-import org.opendaylight.controller.config.api.ModuleIdentifier
-import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface
-import org.opendaylight.controller.config.api.annotations.Description
-import org.opendaylight.controller.config.spi.Module
-import org.opendaylight.controller.config.spi.ModuleFactory
-import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry
-import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.AbstractFactoryTemplate
-import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.TemplateFactory
-import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Annotation
-import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Field
-import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.*
-import org.opendaylight.yangtools.yang.common.QName
-import org.osgi.framework.BundleContext
-
-public class AbsFactoryGeneratedObjectFactory {
-
- public GeneratedObject toGeneratedObject(ModuleMXBeanEntry mbe, Optional<String> copyright) {
- FullyQualifiedName absFactoryFQN = new FullyQualifiedName(mbe.packageName, mbe.abstractFactoryName)
- FullyQualifiedName moduleFQN = new FullyQualifiedName(mbe.packageName, mbe.stubModuleName)
- Optional<String> classJavaDoc = Optional.fromNullable(mbe.getNullableDescription())
-
- AbstractFactoryTemplate abstractFactoryTemplate = TemplateFactory.abstractFactoryTemplateFromMbe(mbe)
- Optional<String> header = abstractFactoryTemplate.headerString;
- List<FullyQualifiedName> providedServices = mbe.providedServices.keySet().collect {
- FullyQualifiedName.fromString(it)
- }
-
-
- return toGeneratedObject(absFactoryFQN, copyright,
- header, classJavaDoc, mbe.yangModuleQName,
- mbe.globallyUniqueName,
- providedServices,
- moduleFQN,
- abstractFactoryTemplate.fields)
- }
-
- public GeneratedObject toGeneratedObject(FullyQualifiedName absFactoryFQN, Optional<String> copyright,
- Optional<String> header, Optional<String> classJavaDoc, QName yangModuleQName,
- String globallyUniqueName,
- List<FullyQualifiedName> providedServices,
- FullyQualifiedName moduleFQN,
- List<Field> moduleFields) {
- JavaFileInputBuilder b = new JavaFileInputBuilder()
- Annotation moduleQNameAnnotation = Annotation.createModuleQNameANnotation(yangModuleQName)
- b.addClassAnnotation(moduleQNameAnnotation)
-
- b.setFqn(absFactoryFQN)
- b.setTypeName(TypeName.absClassType)
-
- b.setCopyright(copyright);
- b.setHeader(header);
- b.setClassJavaDoc(classJavaDoc);
- b.addImplementsFQN(new FullyQualifiedName(ModuleFactory))
- if (classJavaDoc.isPresent()) {
- b.addClassAnnotation("@${Description.canonicalName}(value=\"${classJavaDoc.get()}\")")
- }
-
- b.addToBody("public static final java.lang.String NAME = \"${globallyUniqueName}\";")
- b.addToBody("private static final java.util.Set<Class<? extends ${AbstractServiceInterface.canonicalName}>> serviceIfcs;")
-
- b.addToBody("@Override\n public final String getImplementationName() { \n return NAME; \n}")
-
- b.addToBody(getServiceIfcsInitialization(providedServices))
-
- // createModule
- b.addToBody("""
- @Override
- public ${Module.canonicalName} createModule(String instanceName, ${DependencyResolver.canonicalName} dependencyResolver, ${BundleContext.canonicalName} bundleContext) {
- return instantiateModule(instanceName, dependencyResolver, bundleContext);
- }
- """)
-
- b.addToBody(getCreateModule(moduleFQN, moduleFields))
-
- b.addToBody("""
- public ${moduleFQN} instantiateModule(String instanceName, ${DependencyResolver.canonicalName} dependencyResolver, ${moduleFQN} oldModule, ${AutoCloseable.canonicalName} oldInstance, ${BundleContext.canonicalName} bundleContext) {
- return new ${moduleFQN}(new ${ModuleIdentifier.canonicalName}(NAME, instanceName), dependencyResolver, oldModule, oldInstance);
- }
- """)
-
- b.addToBody("""
- public ${moduleFQN} instantiateModule(String instanceName, ${DependencyResolver.canonicalName} dependencyResolver, ${BundleContext.canonicalName} bundleContext) {
- return new ${moduleFQN}(new ${ModuleIdentifier.canonicalName}(NAME, instanceName), dependencyResolver);
- }
- """)
-
- b.addToBody("""
- public ${moduleFQN} handleChangedClass(${DynamicMBeanWithInstance.canonicalName} old) throws Exception {
- throw new UnsupportedOperationException("Class reloading is not supported");
- }
- """)
-
- b.addToBody("""
- @Override
- public java.util.Set<${moduleFQN}> getDefaultModules(org.opendaylight.controller.config.api.DependencyResolverFactory dependencyResolverFactory, ${BundleContext.canonicalName} bundleContext) {
- return new java.util.HashSet<${moduleFQN}>();
- }
- """)
-
- return new GeneratedObjectBuilder(b.build()).toGeneratedObject()
- }
-
- private static String getCreateModule(FullyQualifiedName moduleFQN, List<Field> moduleFields) {
- String result = """
- @Override
- public ${Module.canonicalName} createModule(String instanceName, ${DependencyResolver.canonicalName} dependencyResolver, ${DynamicMBeanWithInstance.canonicalName} old, ${BundleContext.canonicalName} bundleContext) throws Exception {
- ${moduleFQN} oldModule = null;
- try {
- oldModule = (${moduleFQN}) old.getModule();
- } catch(Exception e) {
- return handleChangedClass(old);
- }
- ${moduleFQN} module = instantiateModule(instanceName, dependencyResolver, oldModule, old.getInstance(), bundleContext);
- """
- result += moduleFields.collect{"module.set${it.name}(oldModule.get${it.name}());"}.join("\n")
- result += """
- return module;
- }
- """
- return result
- }
-
- private static String getServiceIfcsInitialization(List<FullyQualifiedName> providedServices) {
- String generic = "Class<? extends ${AbstractServiceInterface.canonicalName}>"
-
- String result = """static {
- java.util.Set<${generic}> serviceIfcs2 = new java.util.HashSet<${generic}>();
- """
- result += providedServices.collect{"serviceIfcs2.add(${it}.class);"}.join("\n")
- result += """serviceIfcs = java.util.Collections.unmodifiableSet(serviceIfcs2);
- }
- """
-
- // add isModuleImplementingServiceInterface and getImplementedServiceIntefaces methods
-
- result += """
- @Override
- public final boolean isModuleImplementingServiceInterface(Class<? extends ${AbstractServiceInterface.canonicalName}> serviceInterface) {
- for (Class<?> ifc: serviceIfcs) {
- if (serviceInterface.isAssignableFrom(ifc)){
- return true;
- }
- }
- return false;
- }
-
- @Override
- public java.util.Set<Class<? extends ${AbstractServiceInterface.canonicalName}>> getImplementedServiceIntefaces() {
- return serviceIfcs;
- }
- """
-
- return result
- }
-
-}
--- /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.config.yangjmxgenerator.plugin.gofactory;
+
+import static java.lang.String.format;
+
+import com.google.common.base.Optional;
+import java.util.ArrayList;
+import java.util.List;
+import org.opendaylight.controller.config.api.DependencyResolver;
+import org.opendaylight.controller.config.api.DynamicMBeanWithInstance;
+import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface;
+import org.opendaylight.controller.config.api.annotations.Description;
+import org.opendaylight.controller.config.spi.Module;
+import org.opendaylight.controller.config.spi.ModuleFactory;
+import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.AbstractFactoryTemplate;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.TemplateFactory;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Annotation;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Field;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.FullyQualifiedName;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.GeneratedObject;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.GeneratedObjectBuilder;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.JavaFileInputBuilder;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.TypeName;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.osgi.framework.BundleContext;
+
+public class AbsFactoryGeneratedObjectFactory {
+
+ public GeneratedObject toGeneratedObject(ModuleMXBeanEntry mbe, Optional<String> copyright) {
+ FullyQualifiedName absFactoryFQN = new FullyQualifiedName(mbe.getPackageName(), mbe.getAbstractFactoryName());
+ FullyQualifiedName moduleFQN = new FullyQualifiedName(mbe.getPackageName(), mbe.getStubModuleName());
+ Optional<String> classJavaDoc = Optional.fromNullable(mbe.getNullableDescription());
+
+ AbstractFactoryTemplate abstractFactoryTemplate = TemplateFactory.abstractFactoryTemplateFromMbe(mbe);
+ Optional<String> header = abstractFactoryTemplate.getHeaderString();
+
+ List<FullyQualifiedName> providedServices = new ArrayList<>();
+ for(String providedService: mbe.getProvidedServices().keySet()) {
+ providedServices.add(FullyQualifiedName.fromString(providedService));
+ }
+
+ return toGeneratedObject(absFactoryFQN, copyright,
+ header, classJavaDoc, mbe.getYangModuleQName(),
+ mbe.getGloballyUniqueName(),
+ providedServices,
+ moduleFQN,
+ abstractFactoryTemplate.getFields());
+ }
+
+ public GeneratedObject toGeneratedObject(FullyQualifiedName absFactoryFQN, Optional<String> copyright,
+ Optional<String> header, Optional<String> classJavaDoc, QName yangModuleQName,
+ String globallyUniqueName,
+ List<FullyQualifiedName> providedServices,
+ FullyQualifiedName moduleFQN,
+ List<Field> moduleFields) {
+ JavaFileInputBuilder b = new JavaFileInputBuilder();
+ Annotation moduleQNameAnnotation = Annotation.createModuleQNameANnotation(yangModuleQName);
+ b.addClassAnnotation(moduleQNameAnnotation);
+
+ b.setFqn(absFactoryFQN);
+ b.setTypeName(TypeName.absClassType);
+
+ b.setCopyright(copyright);
+ b.setHeader(header);
+ b.setClassJavaDoc(classJavaDoc);
+ b.addImplementsFQN(new FullyQualifiedName(ModuleFactory.class));
+ if (classJavaDoc.isPresent()) {
+ b.addClassAnnotation(format("@%s(value=\"%s\")", Description.class.getCanonicalName(), classJavaDoc.get()));
+ }
+
+ b.addToBody(format("public static final java.lang.String NAME = \"%s\";", globallyUniqueName));
+ b.addToBody(format("private static final java.util.Set<Class<? extends %s>> serviceIfcs;",
+ AbstractServiceInterface.class.getCanonicalName()));
+
+ b.addToBody("@Override\n public final String getImplementationName() { \n return NAME; \n}");
+
+ b.addToBody(getServiceIfcsInitialization(providedServices));
+
+ // createModule
+ b.addToBody(format("\n"+
+ "@Override\n"+
+ "public %s createModule(String instanceName, %s dependencyResolver, %s bundleContext) {\n"+
+ "return instantiateModule(instanceName, dependencyResolver, bundleContext);\n"+
+ "}\n",
+ Module.class.getCanonicalName(), DependencyResolver.class.getCanonicalName(), BundleContext.class.getCanonicalName()));
+
+ b.addToBody(getCreateModule(moduleFQN, moduleFields));
+
+ b.addToBody(format("\n"+
+ "public %s instantiateModule(String instanceName, %s dependencyResolver, %s oldModule, %s oldInstance, %s bundleContext) {\n"+
+ "return new %s(new %s(NAME, instanceName), dependencyResolver, oldModule, oldInstance);\n"+
+ "}\n",
+ moduleFQN, DependencyResolver.class.getCanonicalName(), moduleFQN, AutoCloseable.class.getCanonicalName(),
+ BundleContext.class.getCanonicalName(), moduleFQN, ModuleIdentifier.class.getCanonicalName()));
+
+ b.addToBody(format("\n"+
+ "public %s instantiateModule(String instanceName, %s dependencyResolver, %s bundleContext) {\n"+
+ "return new %s(new %s(NAME, instanceName), dependencyResolver);\n"+
+ "}\n", moduleFQN, DependencyResolver.class.getCanonicalName(), BundleContext.class.getCanonicalName(),
+ moduleFQN, ModuleIdentifier.class.getCanonicalName()
+ ));
+
+ b.addToBody(format("\n"+
+ "public %s handleChangedClass(%s old) throws Exception {\n"+
+ "throw new UnsupportedOperationException(\"Class reloading is not supported\");\n"+
+ "}\n", moduleFQN, DynamicMBeanWithInstance.class.getCanonicalName()));
+
+ b.addToBody(format("\n"+
+ "@Override\n"+
+ "public java.util.Set<%s> getDefaultModules(org.opendaylight.controller.config.api.DependencyResolverFactory dependencyResolverFactory, %s bundleContext) {\n"+
+ "return new java.util.HashSet<%s>();\n"+
+ "}\n", moduleFQN, BundleContext.class.getCanonicalName(), moduleFQN));
+
+ return new GeneratedObjectBuilder(b.build()).toGeneratedObject();
+ }
+
+ private static String getCreateModule(FullyQualifiedName moduleFQN, List<Field> moduleFields) {
+ String result = "\n"+
+ "@Override\n"+
+ format("public %s createModule(String instanceName, %s dependencyResolver, %s old, %s bundleContext) throws Exception {\n",
+ Module.class.getCanonicalName(),DependencyResolver.class.getCanonicalName(),
+ DynamicMBeanWithInstance.class.getCanonicalName(),BundleContext.class.getCanonicalName())+
+ format("%s oldModule = null;\n",moduleFQN)+
+ "try {\n"+
+ format("oldModule = (%s) old.getModule();\n",moduleFQN)+
+ "} catch(Exception e) {\n"+
+ "return handleChangedClass(old);\n"+
+ "}\n"+
+ format("%s module = instantiateModule(instanceName, dependencyResolver, oldModule, old.getInstance(), bundleContext);\n", moduleFQN);
+
+ for(Field field: moduleFields) {
+ result += format("module.set%s(oldModule.get%1$s());\n", field.getName());
+ }
+
+ result += "\n"+
+ "return module;\n"+
+ "}\n";
+ return result;
+ }
+
+ private static String getServiceIfcsInitialization(List<FullyQualifiedName> providedServices) {
+ String generic = format("Class<? extends %s>", AbstractServiceInterface.class.getCanonicalName());
+
+ String result = format("static {\n"+
+ "java.util.Set<%1$s> serviceIfcs2 = new java.util.HashSet<%1$s>();\n", generic);
+
+ for(FullyQualifiedName fqn: providedServices) {
+ result += format("serviceIfcs2.add(%s.class);\n", fqn);
+ }
+ result += "serviceIfcs = java.util.Collections.unmodifiableSet(serviceIfcs2);\n"+
+ "}\n";
+
+ // add isModuleImplementingServiceInterface and getImplementedServiceIntefaces methods
+
+ result += format("\n"+
+ "@Override\n"+
+ "public final boolean isModuleImplementingServiceInterface(Class<? extends %1$s> serviceInterface) {\n"+
+ "for (Class<?> ifc: serviceIfcs) {\n"+
+ "if (serviceInterface.isAssignableFrom(ifc)){\n"+
+ "return true;\n"+
+ "}\n"+
+ "}\n"+
+ "return false;\n"+
+ "}\n"+
+ "\n"+
+ "@Override\n"+
+ "public java.util.Set<Class<? extends %1$s>> getImplementedServiceIntefaces() {\n"+
+ "return serviceIfcs;\n"+
+ "}\n", AbstractServiceInterface.class.getCanonicalName());
+
+ return result;
+ }
+
+}
+++ /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.config.yangjmxgenerator.plugin.gofactory
-import com.google.common.base.Optional
-import org.opendaylight.controller.config.api.DependencyResolver
-import org.opendaylight.controller.config.api.ModuleIdentifier
-import org.opendaylight.controller.config.api.annotations.Description
-import org.opendaylight.controller.config.api.runtime.RootRuntimeBeanRegistrator
-import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry
-import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.AbstractModuleTemplate
-import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.TemplateFactory
-import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Annotation
-import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.IdentityRefModuleField
-import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Method
-import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.ModuleField
-import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.*
-import org.opendaylight.yangtools.yang.common.QName
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-
-public class AbsModuleGeneratedObjectFactory {
-
- public GeneratedObject toGeneratedObject(ModuleMXBeanEntry mbe, Optional<String> copyright) {
- FullyQualifiedName abstractFQN = new FullyQualifiedName(mbe.getPackageName(), mbe.getAbstractModuleName())
- Optional<String> classJavaDoc = Optional.fromNullable(mbe.getNullableDescription())
- AbstractModuleTemplate abstractModuleTemplate = TemplateFactory.abstractModuleTemplateFromMbe(mbe)
- Optional<String> header = abstractModuleTemplate.headerString;
- List<FullyQualifiedName> implementedInterfaces = abstractModuleTemplate.getTypeDeclaration().getImplemented().collect {
- FullyQualifiedName.fromString(it)
- }
- Optional<FullyQualifiedName> maybeRegistratorType
- if (abstractModuleTemplate.isRuntime()) {
- maybeRegistratorType = Optional.of(FullyQualifiedName.fromString(abstractModuleTemplate.getRegistratorType()))
- } else {
- maybeRegistratorType = Optional.absent()
- }
-
- return toGeneratedObject(abstractFQN, copyright, header, classJavaDoc, implementedInterfaces,
- abstractModuleTemplate.getModuleFields(), maybeRegistratorType, abstractModuleTemplate.getMethods(),
- mbe.yangModuleQName
- )
- }
-
- public GeneratedObject toGeneratedObject(FullyQualifiedName abstractFQN,
- Optional<String> copyright,
- Optional<String> header,
- Optional<String> classJavaDoc,
- List<FullyQualifiedName> implementedInterfaces,
- List<ModuleField> moduleFields,
- Optional<FullyQualifiedName> maybeRegistratorType,
- List<Method> methods,
- QName yangModuleQName) {
- JavaFileInputBuilder b = new JavaFileInputBuilder()
-
- Annotation moduleQNameAnnotation = Annotation.createModuleQNameANnotation(yangModuleQName)
- b.addClassAnnotation(moduleQNameAnnotation)
-
- b.setFqn(abstractFQN)
- b.setTypeName(TypeName.absClassType)
-
- b.setCopyright(copyright);
- b.setHeader(header);
- b.setClassJavaDoc(classJavaDoc);
- implementedInterfaces.each { b.addImplementsFQN(it) }
- if (classJavaDoc.isPresent()) {
- b.addClassAnnotation("@${Description.canonicalName}(value=\"${classJavaDoc.get()}\")")
- }
-
- // add logger:
- b.addToBody(getLogger(abstractFQN));
-
- b.addToBody("//attributes start");
-
- b.addToBody(moduleFields.collect { it.toString() }.join("\n"))
-
- b.addToBody("//attributes end");
-
-
- b.addToBody(getCommonFields(abstractFQN));
-
-
- b.addToBody(getNewConstructor(abstractFQN))
- b.addToBody(getCopyFromOldConstructor(abstractFQN))
-
- b.addToBody(getRuntimeRegistratorCode(maybeRegistratorType))
- b.addToBody(getValidationMethods(moduleFields))
-
- b.addToBody(getCachesOfResolvedDependencies(moduleFields))
- b.addToBody(getCachesOfResolvedIdentityRefs(moduleFields))
- b.addToBody(getGetInstance(moduleFields))
- b.addToBody(getReuseLogic(moduleFields, abstractFQN))
- b.addToBody(getEqualsAndHashCode(abstractFQN))
-
- b.addToBody(getMethods(methods))
-
- return new GeneratedObjectBuilder(b.build()).toGeneratedObject()
- }
-
- private static String getMethods(List<Method> methods) {
- String result = """
- // getters and setters
- """
- result += methods.collect{it.toString()}.join("\n")
- return result
- }
-
- private static String getEqualsAndHashCode(FullyQualifiedName abstractFQN) {
- return """
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- ${abstractFQN.typeName} that = (${abstractFQN.typeName}) o;
- return identifier.equals(that.identifier);
- }
-
- @Override
- public int hashCode() {
- return identifier.hashCode();
- }
- """
- }
-
- private static String getReuseLogic(List<ModuleField> moduleFields, FullyQualifiedName abstractFQN) {
- String result = """
- public boolean canReuseInstance(${abstractFQN.typeName} oldModule){
- // allow reusing of old instance if no parameters was changed
- return isSame(oldModule);
- }
-
- public ${AutoCloseable.canonicalName} reuseInstance(${AutoCloseable.canonicalName} oldInstance){
- // implement if instance reuse should be supported. Override canReuseInstance to change the criteria.
- return oldInstance;
- }
- """
- // isSame method that detects changed fields
- result += """
- public boolean isSame(${abstractFQN.typeName} other) {
- if (other == null) {
- throw new IllegalArgumentException("Parameter 'other' is null");
- }
- """
- // loop through fields, do deep equals on each field
- result += moduleFields.collect { field ->
- if (field.isListOfDependencies()) {
- return """
- if (${field.name}Dependency.equals(other.${field.name}Dependency) == false) {
- return false;
- }
- for (int idx = 0; idx < ${field.name}Dependency.size(); idx++) {
- if (${field.name}Dependency.get(idx) != other.${field.name}Dependency.get(idx)) {
- return false;
- }
- }
- """
- } else if (field.isDependent()) {
- return """
- if (${field.name}Dependency != other.${field.name}Dependency) { // reference to dependency must be same
- return false;
- }
- """
- } else {
- return """
- if (java.util.Objects.deepEquals(${field.name}, other.${field.name}) == false) {
- return false;
- }
- """
- }
- }.join("\n")
-
-
- result += """
- return true;
- }
- """
-
- return result
- }
-
- private static String getGetInstance(List<ModuleField> moduleFields) {
- String result = """
- @Override
- public final ${AutoCloseable.canonicalName} getInstance() {
- if(instance==null) {
- """
- // create instance start
-
- // loop through dependent fields, use dependency resolver to instantiate dependencies. Do it in loop in case field represents list of dependencies.
- Map<ModuleField, String> resolveDependenciesMap = moduleFields.findAll {
- it.isDependent()
- }.collectEntries { ModuleField field ->
- [field, field.isList() ?
- """
- ${field.name}Dependency = new java.util.ArrayList<${field.dependency.sie.exportedOsgiClassName}>();
- for(javax.management.ObjectName dep : ${field.name}) {
- ${field.name}Dependency.add(dependencyResolver.resolveInstance(${
- field.dependency.sie.exportedOsgiClassName
- }.class, dep, ${field.name}JmxAttribute));
- }
- """
- :
- """
- ${field.name}Dependency = dependencyResolver.resolveInstance(${
- field.dependency.sie.exportedOsgiClassName
- }.class, ${field.name}, ${field.name}JmxAttribute);
- """
- ]
- }
- // wrap each field resolvation statement with if !=null when dependency is not mandatory
- def wrapWithNullCheckClosure = {Map<ModuleField, String> map, predicate -> map.collect { ModuleField key, String value ->
- predicate(key) ? """
- if(${key.name}!=null) {
- ${value}
- }
- """ : value
- }.join("\n")
- }
-
- result += wrapWithNullCheckClosure(resolveDependenciesMap, {ModuleField key ->
- key.getDependency().isMandatory() == false} )
-
- // add code to inject dependency resolver to fields that support it
- Map<ModuleField, String> injectDepsMap = moduleFields.findAll { it.needsDepResolver }.collectEntries { field ->
- if (field.isList()) {
- return [field,"""
- for(${field.genericInnerType} candidate : ${field.name}) {
- candidate.injectDependencyResolver(dependencyResolver);
- }
- """]
- } else {
- return [field, "${field.name}.injectDependencyResolver(dependencyResolver);"]
- }
- }
-
- result += wrapWithNullCheckClosure(injectDepsMap, {true})
-
- // identity refs need to be injected with dependencyResolver and base class
- Map<ModuleField, String> resolveIdentityMap = moduleFields.findAll { it.isIdentityRef() }.collectEntries { IdentityRefModuleField field ->
- [field,
- "set${field.attributeName}(${field.name}.resolveIdentity(dependencyResolver, ${field.identityBaseClass}.class));"]
- }
-
- result += wrapWithNullCheckClosure(resolveIdentityMap, {true})
-
- // create instance end: reuse and recreate logic
- result += """
- if(oldInstance!=null && canReuseInstance(oldModule)) {
- instance = reuseInstance(oldInstance);
- } else {
- if(oldInstance!=null) {
- try {
- oldInstance.close();
- } catch(Exception e) {
- logger.error("An error occurred while closing old instance " + oldInstance, e);
- }
- }
- instance = createInstance();
- if (instance == null) {
- throw new IllegalStateException("Error in createInstance - null is not allowed as return value");
- }
- }
- }
- return instance;
- }
- public abstract ${AutoCloseable.canonicalName} createInstance();
- """
- return result
- }
-
- private static String getCommonFields(FullyQualifiedName abstractFQN) {
- return """
- private final ${abstractFQN.typeName} oldModule;
- private final ${AutoCloseable.canonicalName} oldInstance;
- private ${AutoCloseable.canonicalName} instance;
- private final ${DependencyResolver.canonicalName} dependencyResolver;
- private final ${ModuleIdentifier.canonicalName} identifier;
- @Override
- public ${ModuleIdentifier.canonicalName} getIdentifier() {
- return identifier;
- }
- """
- }
-
- private static String getCachesOfResolvedIdentityRefs(List<ModuleField> moduleFields) {
- return moduleFields.findAll { it.isIdentityRef() }.collect { IdentityRefModuleField field ->
- "private ${field.identityClassType} ${field.identityClassName};"
- }.join("\n")
- }
-
- private static String getCachesOfResolvedDependencies(List<ModuleField> moduleFields) {
- return moduleFields.findAll { it.dependent }.collect { field ->
- if (field.isList()) {
- return """
- private java.util.List<${field.dependency.sie.exportedOsgiClassName}> ${
- field.name
- }Dependency = new java.util.ArrayList<${field.dependency.sie.exportedOsgiClassName}>();
- protected final java.util.List<${field.dependency.sie.exportedOsgiClassName}> get${
- field.attributeName
- }Dependency(){
- return ${field.name}Dependency;
- }
- """
- } else {
- return """
- private ${field.dependency.sie.exportedOsgiClassName} ${field.name}Dependency;
- protected final ${field.dependency.sie.exportedOsgiClassName} get${field.attributeName}Dependency(){
- return ${field.name}Dependency;
- }
- """
- }
- }.join("\n")
- }
-
- private static String getRuntimeRegistratorCode(Optional<FullyQualifiedName> maybeRegistratorType) {
- if (maybeRegistratorType.isPresent()) {
- String registratorType = maybeRegistratorType.get()
-
- return """
- private ${registratorType} rootRuntimeBeanRegistratorWrapper;
-
- public ${registratorType} getRootRuntimeBeanRegistratorWrapper(){
- return rootRuntimeBeanRegistratorWrapper;
- }
-
- @Override
- public void setRuntimeBeanRegistrator(${RootRuntimeBeanRegistrator.canonicalName} rootRuntimeRegistrator){
- this.rootRuntimeBeanRegistratorWrapper = new ${registratorType}(rootRuntimeRegistrator);
- }
- """
- } else {
- return ""
- }
- }
-
- private static String getValidationMethods(List<ModuleField> moduleFields) {
- String result = """
- @Override
- public void validate() {
- """
- // validate each mandatory dependency
- List<String> lines = moduleFields.findAll{(it.dependent && it.dependency.mandatory)}.collect { field ->
- if (field.isList()) {
- return "" +
- "for(javax.management.ObjectName dep : ${field.name}) {\n" +
- " dependencyResolver.validateDependency(${field.dependency.sie.fullyQualifiedName}.class, dep, ${field.name}JmxAttribute);\n" +
- "}\n"
- } else {
- return "dependencyResolver.validateDependency(${field.dependency.sie.fullyQualifiedName}.class, ${field.name}, ${field.name}JmxAttribute);"
- }
- }
- result += lines.findAll { it.isEmpty() == false }.join("\n")
- result += """
- customValidation();
- }
-
- protected void customValidation(){
- }
- """
- return result
- }
-
- private static String getLogger(FullyQualifiedName fqn) {
- return "private static final ${Logger.canonicalName} logger = ${LoggerFactory.canonicalName}.getLogger(${fqn.toString()}.class);"
- }
-
- // assumes that each parameter name corresponds to an field in this class, constructs lines setting this.field = field;
- private static String getConstructorStart(FullyQualifiedName fqn,
- LinkedHashMap<String, String> parameters, String after) {
- return "public ${fqn.typeName}(" +
- parameters.collect { it.key + " " + it.value }.join(",") +
- ") {\n" +
- parameters.values().collect { "this.${it}=${it};\n" }.join() +
- after +
- "}\n"
- }
-
- private static String getNewConstructor(FullyQualifiedName abstractFQN) {
- LinkedHashMap<String, String> parameters = [
- (ModuleIdentifier.canonicalName): "identifier",
- (DependencyResolver.canonicalName): "dependencyResolver"
- ]
- String setToNulls = ["oldInstance", "oldModule"].collect { "this.${it}=null;\n" }.join()
- return getConstructorStart(abstractFQN, parameters, setToNulls)
- }
-
- private static String getCopyFromOldConstructor(FullyQualifiedName abstractFQN) {
- LinkedHashMap<String, String> parameters = [
- (ModuleIdentifier.canonicalName): "identifier",
- (DependencyResolver.canonicalName): "dependencyResolver",
- (abstractFQN.typeName): "oldModule",
- (AutoCloseable.canonicalName): "oldInstance"
- ]
- return getConstructorStart(abstractFQN, parameters, "")
- }
-}
--- /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.config.yangjmxgenerator.plugin.gofactory;
+
+import static java.lang.String.format;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Optional;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import org.opendaylight.controller.config.api.DependencyResolver;
+import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.api.annotations.Description;
+import org.opendaylight.controller.config.api.runtime.RootRuntimeBeanRegistrator;
+import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.AbstractModuleTemplate;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.TemplateFactory;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Annotation;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.IdentityRefModuleField;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Method;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.ModuleField;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.FullyQualifiedName;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.GeneratedObject;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.GeneratedObjectBuilder;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.JavaFileInputBuilder;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.TypeName;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AbsModuleGeneratedObjectFactory {
+
+ public GeneratedObject toGeneratedObject(ModuleMXBeanEntry mbe, Optional<String> copyright) {
+ FullyQualifiedName abstractFQN = new FullyQualifiedName(mbe.getPackageName(), mbe.getAbstractModuleName());
+ Optional<String> classJavaDoc = Optional.fromNullable(mbe.getNullableDescription());
+ AbstractModuleTemplate abstractModuleTemplate = TemplateFactory.abstractModuleTemplateFromMbe(mbe);
+ Optional<String> header = abstractModuleTemplate.getHeaderString();
+
+ List<FullyQualifiedName> implementedInterfaces = new ArrayList<>();
+ for(String implemented: abstractModuleTemplate.getTypeDeclaration().getImplemented()) {
+ implementedInterfaces.add(FullyQualifiedName.fromString(implemented));
+ }
+ Optional<FullyQualifiedName> maybeRegistratorType;
+ if (abstractModuleTemplate.isRuntime()) {
+ maybeRegistratorType = Optional.of(FullyQualifiedName.fromString(abstractModuleTemplate.getRegistratorType()));
+ } else {
+ maybeRegistratorType = Optional.absent();
+ }
+
+ return toGeneratedObject(abstractFQN, copyright, header, classJavaDoc, implementedInterfaces,
+ abstractModuleTemplate.getModuleFields(), maybeRegistratorType, abstractModuleTemplate.getMethods(),
+ mbe.getYangModuleQName());
+ }
+
+ public GeneratedObject toGeneratedObject(FullyQualifiedName abstractFQN,
+ Optional<String> copyright,
+ Optional<String> header,
+ Optional<String> classJavaDoc,
+ List<FullyQualifiedName> implementedInterfaces,
+ List<ModuleField> moduleFields,
+ Optional<FullyQualifiedName> maybeRegistratorType,
+ List<? extends Method> methods,
+ QName yangModuleQName) {
+ JavaFileInputBuilder b = new JavaFileInputBuilder();
+
+ Annotation moduleQNameAnnotation = Annotation.createModuleQNameANnotation(yangModuleQName);
+ b.addClassAnnotation(moduleQNameAnnotation);
+
+ b.setFqn(abstractFQN);
+ b.setTypeName(TypeName.absClassType);
+
+ b.setCopyright(copyright);
+ b.setHeader(header);
+ b.setClassJavaDoc(classJavaDoc);
+ for(FullyQualifiedName implemented: implementedInterfaces) {
+ b.addImplementsFQN(implemented);
+ }
+ if (classJavaDoc.isPresent()) {
+ b.addClassAnnotation(format("@%s(value=\"%s\")", Description.class.getCanonicalName(), classJavaDoc.get()));
+ }
+
+ // add logger:
+ b.addToBody(getLogger(abstractFQN));
+
+ b.addToBody("//attributes start");
+ for(ModuleField moduleField: moduleFields) {
+ b.addToBody(moduleField.toString() +"\n");
+ }
+
+ b.addToBody("//attributes end");
+
+
+ b.addToBody(getCommonFields(abstractFQN));
+
+
+ b.addToBody(getNewConstructor(abstractFQN));
+ b.addToBody(getCopyFromOldConstructor(abstractFQN));
+
+ b.addToBody(getRuntimeRegistratorCode(maybeRegistratorType));
+ b.addToBody(getValidationMethods(moduleFields));
+
+ b.addToBody(getCachesOfResolvedDependencies(moduleFields));
+ b.addToBody(getCachesOfResolvedIdentityRefs(moduleFields));
+ b.addToBody(getGetInstance(moduleFields));
+ b.addToBody(getReuseLogic(moduleFields, abstractFQN));
+ b.addToBody(getEqualsAndHashCode(abstractFQN));
+
+ b.addToBody(getMethods(methods));
+
+ return new GeneratedObjectBuilder(b.build()).toGeneratedObject();
+ }
+
+ private static String getMethods(List<? extends Method> methods) {
+ String result = "\n// getters and setters\n";
+ for(Method method: methods) {
+ result += method.toString()+"\n";
+ }
+ return result;
+ }
+
+ private static String getEqualsAndHashCode(FullyQualifiedName abstractFQN) {
+ return "\n"+
+ "@Override\n"+
+ "public boolean equals(Object o) {\n"+
+ "if (this == o) return true;\n"+
+ "if (o == null || getClass() != o.getClass()) return false;\n"+
+ format("%s that = (%1$s) o;\n", abstractFQN.getTypeName())+
+ "return identifier.equals(that.identifier);\n"+
+ "}\n"+
+ "\n"+
+ "@Override\n"+
+ "public int hashCode() {\n"+
+ "return identifier.hashCode();\n"+
+ "}\n";
+ }
+
+ private static String getReuseLogic(List<ModuleField> moduleFields, FullyQualifiedName abstractFQN) {
+ String result = "\n"+
+ format("public boolean canReuseInstance(%s oldModule){\n", abstractFQN.getTypeName())+
+ "// allow reusing of old instance if no parameters was changed\n"+
+ "return isSame(oldModule);\n"+
+ "}\n"+
+ "\n"+
+ format("public %s reuseInstance(%1$s oldInstance){\n", AutoCloseable.class.getCanonicalName())+
+ "// implement if instance reuse should be supported. Override canReuseInstance to change the criteria.\n"+
+ "return oldInstance;\n"+
+ "}\n";
+ // isSame method that detects changed fields
+ result += "\n"+
+ format("public boolean isSame(%s other) {\n", abstractFQN.getTypeName())+
+ "if (other == null) {\n"+
+ "throw new IllegalArgumentException(\"Parameter 'other' is null\");\n"+
+ "}\n";
+ // loop through fields, do deep equals on each field
+
+ for (ModuleField moduleField : moduleFields) {
+ if (moduleField.isListOfDependencies()) {
+ result += format(
+ "if (%1$sDependency.equals(other.%1$sDependency) == false) {\n"+
+ "return false;\n"+
+ "}\n"+
+ "for (int idx = 0; idx < %1$sDependency.size(); idx++) {\n"+
+ "if (%1$sDependency.get(idx) != other.%1$sDependency.get(idx)) {\n"+
+ "return false;\n"+
+ "}\n"+
+ "}\n" ,moduleField.getName());
+ } else if (moduleField.isDependent()) {
+ result += format(
+ "if (%sDependency != other.%1$sDependency) { // reference to dependency must be same\n"+
+ "return false;\n"+
+ "}\n",moduleField.getName());
+ } else {
+ result += format(
+ "if (java.util.Objects.deepEquals(%s, other.%1$s) == false) {\n"+
+ "return false;\n"+
+ "}\n", moduleField.getName());
+ }
+ }
+ result += "\n"+
+ "return true;\n"+
+ "}\n";
+
+ return result;
+ }
+
+ private static String getGetInstance(List<ModuleField> moduleFields) {
+ String result = "\n"+
+ "@Override\n"+
+ format("public final %s getInstance() {\n", AutoCloseable.class.getCanonicalName())+
+ "if(instance==null) {\n";
+ // create instance start
+
+ // loop through dependent fields, use dependency resolver to instantiate dependencies. Do it in loop in case field represents list of dependencies.
+ Map<ModuleField, String> resolveDependenciesMap = new HashMap<>();
+ for(ModuleField moduleField: moduleFields) {
+ if (moduleField.isDependent()) {
+ String str;
+ String osgi = moduleField.getDependency().getSie().getExportedOsgiClassName();
+ if (moduleField.isList()) {
+ str = format(
+ "%sDependency = new java.util.ArrayList<%s>();\n"+
+ "for(javax.management.ObjectName dep : %1$s) {\n"+
+ "%1$sDependency.add(dependencyResolver.resolveInstance(%2$s.class, dep, %1$sJmxAttribute));\n"+
+ "}\n", moduleField.getName(), osgi);
+ } else {
+ str = format(
+ "%1$sDependency = dependencyResolver.resolveInstance(%2$s.class, %1$s, %1$sJmxAttribute);",
+ moduleField.getName(), osgi);
+ }
+ resolveDependenciesMap.put(moduleField, str);
+ }
+ }
+
+ // wrap each field resolvation statement with if !=null when dependency is not mandatory
+ for (Map.Entry<ModuleField, String> entry : resolveDependenciesMap.entrySet()) {
+ if (entry.getKey().getDependency().isMandatory() == false) {
+ result += format("if (%s!=null) {\n%s;\n}", entry.getKey().getName(), entry.getValue());
+ } else {
+ result += entry.getValue();
+ }
+ }
+
+ // add code to inject dependency resolver to fields that support it
+ for(ModuleField moduleField: moduleFields) {
+ if (moduleField.isNeedsDepResolver()) {
+ result += format("if (%s!=null){\n", moduleField.getName());
+ if (moduleField.isList()) {
+ result += format(
+ "for(%s candidate : %s) {\n"+
+ "candidate.injectDependencyResolver(dependencyResolver);\n"+
+ "}\n", moduleField.getGenericInnerType(), moduleField.getName());
+ } else {
+ result += format("%s.injectDependencyResolver(dependencyResolver);\n", moduleField.getName());
+ }
+ result += "}\n";
+ }
+ }
+
+ // identity refs need to be injected with dependencyResolver and base class
+ for (ModuleField moduleField : moduleFields) {
+ if (moduleField.isIdentityRef()) {
+ result += format("if (%s!=null) {", moduleField.getName());
+ result += format("set%s(%s.resolveIdentity(dependencyResolver, %s.class));",
+ moduleField.getAttributeName(), moduleField.getName(),
+ ((IdentityRefModuleField)moduleField).getIdentityBaseClass());
+ result += "}\n";
+ }
+ }
+
+ // create instance end: reuse and recreate logic
+ result += "if(oldInstance!=null && canReuseInstance(oldModule)) {\n"+
+ "instance = reuseInstance(oldInstance);\n"+
+ "} else {\n"+
+ "if(oldInstance!=null) {\n"+
+ "try {\n"+
+ "oldInstance.close();\n"+
+ "} catch(Exception e) {\n"+
+ "logger.error(\"An error occurred while closing old instance \" + oldInstance, e);\n"+
+ "}\n"+
+ "}\n"+
+ "instance = createInstance();\n"+
+ "if (instance == null) {\n"+
+ "throw new IllegalStateException(\"Error in createInstance - null is not allowed as return value\");\n"+
+ "}\n"+
+ "}\n"+
+ "}\n"+
+ "return instance;\n"+
+ "}\n"+
+ format("public abstract %s createInstance();\n", AutoCloseable.class.getCanonicalName());
+
+ return result;
+ }
+
+ private static String getCommonFields(FullyQualifiedName abstractFQN) {
+ return "\n"+
+ format("private final %s oldModule;\n", abstractFQN.getTypeName())+
+ format("private final %s oldInstance;\n", AutoCloseable.class.getCanonicalName())+
+ format("private %s instance;\n", AutoCloseable.class.getCanonicalName())+
+ format("private final %s dependencyResolver;\n", DependencyResolver.class.getCanonicalName())+
+ format("private final %s identifier;\n", ModuleIdentifier.class.getCanonicalName())+
+ "@Override\n"+
+ format("public %s getIdentifier() {\n", ModuleIdentifier.class.getCanonicalName())+
+ "return identifier;\n"+
+ "}\n";
+ }
+
+ private static String getCachesOfResolvedIdentityRefs(List<ModuleField> moduleFields) {
+ StringBuilder result = new StringBuilder();
+ for (ModuleField moduleField : moduleFields) {
+ if (moduleField.isIdentityRef()) {
+ IdentityRefModuleField field = (IdentityRefModuleField) moduleField;
+ result.append(format("private %s %s;\n", field.getIdentityClassType(), field.getIdentityClassName()));
+ }
+ }
+ return result.toString();
+ }
+
+ private static String getCachesOfResolvedDependencies(List<ModuleField> moduleFields) {
+ StringBuilder result = new StringBuilder();
+ for (ModuleField moduleField: moduleFields) {
+ if (moduleField.isDependent()) {
+ String osgi = moduleField.getDependency().getSie().getExportedOsgiClassName();
+ if (moduleField.isList()) {
+ result
+ .append(format("private java.util.List<%s> %sDependency = new java.util.ArrayList<%s>();", osgi, moduleField.getName(), osgi))
+ .append(format("protected final java.util.List<%s> get%sDependency(){\n", osgi, moduleField.getAttributeName()))
+ .append(format("return %sDependency;\n", moduleField.getName()))
+ .append("}\n");
+ } else {
+ result.append(format(
+ "private %s %sDependency;\n"+
+ "protected final %s get%sDependency(){\n"+
+ "return %sDependency;\n"+
+ "}",
+ osgi, moduleField.getName(), osgi, moduleField.getAttributeName(), moduleField.getName()));
+ }
+ }
+ }
+ return result.toString();
+ }
+
+ private static String getRuntimeRegistratorCode(Optional<FullyQualifiedName> maybeRegistratorType) {
+ if (maybeRegistratorType.isPresent()) {
+ String registratorType = maybeRegistratorType.get().toString();
+
+ return "\n"+
+ format("private %s rootRuntimeBeanRegistratorWrapper;\n", registratorType)+
+ "\n"+
+ format("public %s getRootRuntimeBeanRegistratorWrapper(){\n", registratorType)+
+ "return rootRuntimeBeanRegistratorWrapper;\n"+
+ "}\n"+
+ "\n"+
+ "@Override\n"+
+ format("public void setRuntimeBeanRegistrator(%s rootRuntimeRegistrator){\n", RootRuntimeBeanRegistrator.class.getCanonicalName())+
+ format("this.rootRuntimeBeanRegistratorWrapper = new %s(rootRuntimeRegistrator);\n", registratorType)+
+ "}\n";
+ } else {
+ return "";
+ }
+ }
+
+ private static String getValidationMethods(List<ModuleField> moduleFields) {
+ String result = "\n"+
+ "@Override\n"+
+ "public void validate() {\n";
+ // validate each mandatory dependency
+ for(ModuleField moduleField: moduleFields) {
+ if (moduleField.isDependent() && moduleField.getDependency().isMandatory()) {
+ if (moduleField.isList()) {
+ result += "" +
+ format("for(javax.management.ObjectName dep : %s) {\n", moduleField.getName()) +
+ format(" dependencyResolver.validateDependency(%s.class, dep, %sJmxAttribute);\n",
+ moduleField.getDependency().getSie().getFullyQualifiedName(), moduleField.getName()) +
+ "}\n";
+ } else {
+ result += format("dependencyResolver.validateDependency(%s.class, %s, %sJmxAttribute);",
+ moduleField.getDependency().getSie().getFullyQualifiedName(), moduleField.getName(), moduleField.getName());
+ }
+ }
+ }
+ result += "\n"+
+ "customValidation();\n"+
+ "}\n"+
+ "\n"+
+ "protected void customValidation() {\n"+
+ "}\n";
+ return result;
+ }
+
+ private static String getLogger(FullyQualifiedName fqn) {
+ return format("private static final %s logger = %s.getLogger(%s.class);",
+ Logger.class.getCanonicalName(), LoggerFactory.class.getCanonicalName(), fqn);
+ }
+
+ // assumes that each parameter name corresponds to an field in this class, constructs lines setting this.field = field;
+ private static String getConstructorStart(FullyQualifiedName fqn,
+ LinkedHashMap<String, String> parameters, String after) {
+ String paramString = Joiner.on(",").withKeyValueSeparator(" ").join(parameters);
+ String setters = "";
+ for (String paramName : parameters.values()) {
+ setters += format("this.%s = %1$s;\n", paramName);
+ }
+ return format("public %s(", fqn.getTypeName()) +
+ paramString +
+ ") {\n" +
+ setters +
+ after +
+ "}\n";
+ }
+
+ private static String getNewConstructor(FullyQualifiedName abstractFQN) {
+ LinkedHashMap<String, String> parameters = new LinkedHashMap<>();
+ parameters.put(ModuleIdentifier.class.getCanonicalName(), "identifier");
+ parameters.put(DependencyResolver.class.getCanonicalName(), "dependencyResolver");
+
+ String setToNulls = "this.oldInstance=null;\n;" +
+ "this.oldModule=null;\n";
+ return getConstructorStart(abstractFQN, parameters, setToNulls);
+ }
+
+ private static String getCopyFromOldConstructor(FullyQualifiedName abstractFQN) {
+ LinkedHashMap<String, String> parameters = new LinkedHashMap<>();
+ parameters.put(ModuleIdentifier.class.getCanonicalName(), "identifier");
+ parameters.put(DependencyResolver.class.getCanonicalName(), "dependencyResolver");
+ parameters.put(abstractFQN.getTypeName(), "oldModule");
+ parameters.put(AutoCloseable.class.getCanonicalName(), "oldInstance");
+ return getConstructorStart(abstractFQN, parameters, "");
+ }
+}
+++ /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.config.yangjmxgenerator.plugin.gofactory
-
-import com.google.common.base.Optional
-import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.FtlTemplate
-import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.FullyQualifiedName
-import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.GeneratedObject
-import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.GeneratedObjectBuilder
-import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.JavaFileInputBuilder
-
-public class GenericGeneratedObjectFactory {
-
- public GeneratedObject toGeneratedObject(FtlTemplate template, Optional<String> copyright) {
- JavaFileInputBuilder b = new JavaFileInputBuilder();
- b.setHeader(template.headerString)
- b.setFqn(new FullyQualifiedName(template.packageName, template.typeDeclaration.name))
- b.setClassJavaDoc(template.maybeJavadoc)
- template.annotations.each { b.addClassAnnotation(it) }
- // type declaration
- template.typeDeclaration.extended.each { b.addExtendsFQN(FullyQualifiedName.fromString(it)) }
- template.typeDeclaration.implemented.each { b.addImplementsFQN(FullyQualifiedName.fromString(it)) }
- b.setCopyright(copyright);
- b.setTypeName(template.typeDeclaration.toTypeName())
- // fields
- template.fields.each { b.addToBody(it.toString()) }
- // constructors
- template.constructors.each { b.addToBody(it.toString()) }
- // methods
- template.methods.each { b.addToBody(it.toString()) }
-
- return new GeneratedObjectBuilder(b.build()).toGeneratedObject();
- }
-}
--- /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.config.yangjmxgenerator.plugin.gofactory;
+
+import com.google.common.base.Optional;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.FtlTemplate;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Annotation;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Constructor;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Field;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Method;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.FullyQualifiedName;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.GeneratedObject;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.GeneratedObjectBuilder;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.JavaFileInputBuilder;
+
+public class GenericGeneratedObjectFactory {
+
+ public GeneratedObject toGeneratedObject(FtlTemplate template, Optional<String> copyright) {
+ JavaFileInputBuilder b = new JavaFileInputBuilder();
+ b.setHeader(template.getHeaderString());
+ b.setFqn(new FullyQualifiedName(template.getPackageName(), template.getTypeDeclaration().getName()));
+ b.setClassJavaDoc(template.getMaybeJavadoc());
+ for (Annotation annotation : template.getAnnotations()) {
+ b.addClassAnnotation(annotation);
+ }
+ // type declaration
+ for (String extended : template.getTypeDeclaration().getExtended()) {
+ b.addExtendsFQN(FullyQualifiedName.fromString(extended));
+ }
+ for (String implemented : template.getTypeDeclaration().getImplemented()) {
+ b.addImplementsFQN(FullyQualifiedName.fromString(implemented));
+ }
+ b.setCopyright(copyright);
+ b.setTypeName(template.getTypeDeclaration().toTypeName());
+ // fields
+ for (Field field : template.getFields()) {
+ b.addToBody(field.toString());
+ }
+ // constructors
+ for (Constructor constructor : template.getConstructors()) {
+ b.addToBody(constructor.toString());
+ }
+ // methods
+ for (Method method : template.getMethods()) {
+ b.addToBody(method.toString());
+ }
+ return new GeneratedObjectBuilder(b.build()).toGeneratedObject();
+ }
+}
File[] sourceFiles = sourceDirectory.listFiles();
for (File sourceFile: sourceFiles) {
- if(sourceFile.getName().endsWith("Module.java") || sourceFile.getName().endsWith("ModuleFactory.java")) {
- File stubFile = new File(sourceFile.getPath().replace(".java", "Stub.txt"));
- if (stubFile.exists()) {
- try {
- rewrite(sourceFile, FileUtils.readFileToString(stubFile));
- } catch (IOException e) {
- getLog().error("Error while reading/writing to files.", e);
+ if (sourceFile.getName().endsWith(".java")) {
+ String sourceContent;
+ try {
+ sourceContent = FileUtils.readFileToString(sourceFile);
+ } catch (IOException e) {
+ getLog().error("Cannot read " + sourceFile.getAbsolutePath(), e);
+ continue;
+ }
+ if (sourceFile.getName().endsWith("Module.java") || sourceFile.getName().endsWith("ModuleFactory.java")) {
+ File stubFile = new File(sourceFile.getPath().replace(".java", "Stub.txt"));
+ if (stubFile.exists()) {
+ String stubContent = null;
+ try {
+ stubContent = FileUtils.readFileToString(stubFile);
+ } catch (IOException e) {
+ getLog().error("Cannot read " + stubFile.getAbsolutePath(), e);
+ }
+ if (stubContent != null) {
+ sourceContent = rewriteStub(sourceContent, stubContent);
+ }
}
}
+ // remove copyright headers as they can contain timestamp
+ sourceContent = removeCopyrights(sourceContent);
+
+ // replace the file content
+ try {
+ FileUtils.write(sourceFile, sourceContent);
+ } catch (IOException e) {
+ getLog().error("Cannot write " + sourceFile.getAbsolutePath(), e);
+ }
}
+
}
}
- private static void rewrite(File sourceFile, String replaceTODOWith) throws IOException {
- String source = FileUtils.readFileToString(sourceFile);
- String target = Pattern.compile("^.*TODO.*\n.*throw new java.lang.UnsupportedOperationException.*$", Pattern.MULTILINE).matcher(source).replaceFirst(replaceTODOWith);
- FileUtils.write(sourceFile, target);
+ private static Pattern MULTILINE_COMMENT_PATTERN = Pattern.compile("/\\*.*\\*/", Pattern.MULTILINE | Pattern.DOTALL);
+ private static String removeCopyrights(String source) {
+ String target = MULTILINE_COMMENT_PATTERN.matcher(source).replaceAll("\n");
+ //FileUtils.write(sourceFile, target);
+ return target;
+ }
+
+ private static Pattern UNSUPPORTED_OP_PATTERN = Pattern.compile("^.*TODO.*\n.*throw new java.lang.UnsupportedOperationException.*$", Pattern.MULTILINE);
+
+ private static String rewriteStub(String source, String replaceTODOWith) {
+ String target = UNSUPPORTED_OP_PATTERN.matcher(source).replaceFirst(replaceTODOWith);
+ return target;
}
}
-/*
-* 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.config.yang.test.impl;
public class DepTestImplModule extends org.opendaylight.controller.config.yang.test.impl.AbstractDepTestImplModule {
public DepTestImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
-/*
-* 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
-*/
-/*
-* Generated file
-*
-* Generated from: yang module name: config-test-impl yang module local name: impl-dep
-* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
-* Generated at: Fri Apr 25 11:50:32 CEST 2014
-*
-* Do not modify this file unless it is present under src/main directory
-*/
+
+
package org.opendaylight.controller.config.yang.test.impl;
public class DepTestImplModuleFactory extends org.opendaylight.controller.config.yang.test.impl.AbstractDepTestImplModuleFactory {
-/*
-* 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.config.yang.test.impl;
public class IdentityTestModule extends org.opendaylight.controller.config.yang.test.impl.AbstractIdentityTestModule {
public IdentityTestModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
-/*
-* 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
-*/
-/*
-* Generated file
-*
-* Generated from: yang module name: config-test-impl yang module local name: impl-identity-test
-* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
-* Generated at: Fri Apr 25 11:50:32 CEST 2014
-*
-* Do not modify this file unless it is present under src/main directory
-*/
+
+
package org.opendaylight.controller.config.yang.test.impl;
public class IdentityTestModuleFactory extends org.opendaylight.controller.config.yang.test.impl.AbstractIdentityTestModuleFactory {
-/*
-* 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.config.yang.test.impl;
public class NetconfTestImplModule extends org.opendaylight.controller.config.yang.test.impl.AbstractNetconfTestImplModule {
public NetconfTestImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
-/*
-* 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
-*/
-/*
-* Generated file
-*
-* Generated from: yang module name: config-test-impl yang module local name: impl-netconf
-* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
-* Generated at: Fri Apr 25 11:50:32 CEST 2014
-*
-* Do not modify this file unless it is present under src/main directory
-*/
+
+
package org.opendaylight.controller.config.yang.test.impl;
public class NetconfTestImplModuleFactory extends org.opendaylight.controller.config.yang.test.impl.AbstractNetconfTestImplModuleFactory {
-/*
- * 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.config.yang.test.impl;
import com.google.common.collect.Lists;
-/*
-* 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.config.yang.test.impl;
public class TestImplModule extends org.opendaylight.controller.config.yang.test.impl.AbstractTestImplModule {
public TestImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
-/*
-* 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
-*/
-/*
-* Generated file
-*
-* Generated from: yang module name: config-test-impl yang module local name: impl
-* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
-* Generated at: Fri Apr 25 11:50:32 CEST 2014
-*
-* Do not modify this file unless it is present under src/main directory
-*/
+
+
package org.opendaylight.controller.config.yang.test.impl;
public class TestImplModuleFactory extends org.opendaylight.controller.config.yang.test.impl.AbstractTestImplModuleFactory {
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<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">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>commons.opendaylight</artifactId>
+ <version>1.4.2-SNAPSHOT</version>
+ <relativePath>../../commons/opendaylight</relativePath>
+ </parent>
+ <artifactId>distribution.opendaylight-karaf</artifactId>
+ <packaging>pom</packaging>
+ <prerequisites>
+ <maven>3.0</maven>
+ </prerequisites>
+
+ <dependencies>
+ <dependency>
+ <!-- scope is compile so all features (there is only one) are installed
+ into startup.properties and the feature repo itself is not installed -->
+ <groupId>org.apache.karaf.features</groupId>
+ <artifactId>framework</artifactId>
+ <version>${karaf.version}</version>
+ <type>kar</type>
+ </dependency>
+ <!-- scope is runtime so the feature repo is listed in the features
+ service config file, and features may be installed using the
+ karaf-maven-plugin configuration -->
+ <!-- dependencies commented out till we can get them in
+ <dependency>
+ <groupId>org.apache.karaf.features</groupId>
+ <artifactId>standard</artifactId>
+ <version>${karaf.version}</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>controller-features</artifactId>
+ <version>${project.version}</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>features-file</artifactId>
+ <version>${yangtools.version}</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
+ -->
+ </dependencies>
+
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.eclipse.m2e</groupId>
+ <artifactId>lifecycle-mapping</artifactId>
+ <version>1.0.0</version>
+ <configuration>
+ <lifecycleMappingMetadata>
+ <pluginExecutions>
+ <pluginExecution>
+ <pluginExecutionFilter>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <versionRange>[0,)</versionRange>
+ <goals>
+ <goal>cleanVersions</goal>
+ </goals>
+ </pluginExecutionFilter>
+ <action>
+ <ignore></ignore>
+ </action>
+ </pluginExecution>
+ <pluginExecution>
+ <pluginExecutionFilter>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <versionRange>[0,)</versionRange>
+ <goals>
+ <goal>copy</goal>
+ <goal>unpack</goal>
+ </goals>
+ </pluginExecutionFilter>
+ <action>
+ <ignore></ignore>
+ </action>
+ </pluginExecution>
+ <pluginExecution>
+ <pluginExecutionFilter>
+ <groupId>org.apache.karaf.tooling</groupId>
+ <artifactId>karaf-maven-plugin</artifactId>
+ <versionRange>[0,)</versionRange>
+ <goals>
+ <goal>commands-generate-help</goal>
+ </goals>
+ </pluginExecutionFilter>
+ <action>
+ <ignore></ignore>
+ </action>
+ </pluginExecution>
+ <pluginExecution>
+ <pluginExecutionFilter>
+ <groupId>org.fusesource.scalate</groupId>
+ <artifactId>maven-scalate-plugin</artifactId>
+ <versionRange>[0,)</versionRange>
+ <goals>
+ <goal>sitegen</goal>
+ </goals>
+ </pluginExecutionFilter>
+ <action>
+ <ignore></ignore>
+ </action>
+ </pluginExecution>
+ <pluginExecution>
+ <pluginExecutionFilter>
+ <groupId>org.apache.servicemix.tooling</groupId>
+ <artifactId>depends-maven-plugin</artifactId>
+ <versionRange>[0,)</versionRange>
+ <goals>
+ <goal>generate-depends-file</goal>
+ </goals>
+ </pluginExecutionFilter>
+ <action>
+ <ignore></ignore>
+ </action>
+ </pluginExecution>
+ </pluginExecutions>
+ </lifecycleMappingMetadata>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.karaf.tooling</groupId>
+ <artifactId>karaf-maven-plugin</artifactId>
+ <version>${karaf.version}</version>
+ <extensions>true</extensions>
+ <configuration>
+ <!-- no startupFeatures -->
+ <bootFeatures>
+ <feature>standard</feature>
+ </bootFeatures>
+ <!-- no installedFeatures -->
+ </configuration>
+ <executions>
+ <execution>
+ <id>process-resources</id>
+ <goals>
+ <goal>install-kars</goal>
+ </goals>
+ <phase>process-resources</phase>
+ </execution>
+ <execution>
+ <id>package</id>
+ <goals>
+ <goal>instance-create-archive</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <version>${checkstyle.version}</version>
+ <configuration>
+ <excludes>**\/target\/,**\/bin\/,**\/target-ide\/,**\/configuration\/initial\/</excludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <scm>
+ <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+ <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+ <tag>HEAD</tag>
+ <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:Main</url>
+ </scm>
+</project>
--- /dev/null
+<Context crossContext="true" sessionCookiePath="/" useHttpOnly="false"/>
--- /dev/null
+<snapshot>
+ <required-capabilities>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:netty?module=netty&revision=2013-11-19</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:netty:eventexecutor?module=netty-event-executor&revision=2013-11-12</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:netty:threadgroup?module=threadgroup&revision=2013-11-07</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:netty:timer?module=netty-timer&revision=2013-11-19</capability>
+ </required-capabilities>
+ <configuration>
+
+ <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <module>
+ <type xmlns:netty="urn:opendaylight:params:xml:ns:yang:controller:netty:threadgroup">netty:netty-threadgroup-fixed</type>
+ <name>global-boss-group</name>
+ </module>
+ <module>
+ <type xmlns:netty="urn:opendaylight:params:xml:ns:yang:controller:netty:threadgroup">netty:netty-threadgroup-fixed</type>
+ <name>global-worker-group</name>
+ </module>
+ <module>
+ <type xmlns:netty="urn:opendaylight:params:xml:ns:yang:controller:netty:timer">netty:netty-hashed-wheel-timer</type>
+ <name>global-timer</name>
+ </module>
+ <module>
+ <type xmlns:netty="urn:opendaylight:params:xml:ns:yang:controller:netty:eventexecutor">netty:netty-global-event-executor</type>
+ <name>singleton</name>
+ </module>
+ </modules>
+
+ <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <service>
+ <type xmlns:netty="urn:opendaylight:params:xml:ns:yang:controller:netty">netty:netty-threadgroup</type>
+ <instance>
+ <name>global-boss-group</name>
+ <provider>/modules/module[type='netty-threadgroup-fixed'][name='global-boss-group']</provider>
+ </instance>
+ <instance>
+ <name>global-worker-group</name>
+ <provider>/modules/module[type='netty-threadgroup-fixed'][name='global-worker-group']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:netty="urn:opendaylight:params:xml:ns:yang:controller:netty">netty:netty-event-executor</type>
+ <instance>
+ <name>global-event-executor</name>
+ <provider>/modules/module[type='netty-global-event-executor'][name='singleton']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:netty="urn:opendaylight:params:xml:ns:yang:controller:netty">netty:netty-timer</type>
+ <instance>
+ <name>global-timer</name>
+ <provider>/modules/module[type='netty-hashed-wheel-timer'][name='global-timer']</provider>
+ </instance>
+ </service>
+ </services>
+ </data>
+
+ </configuration>
+</snapshot>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ 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
+-->
+<snapshot>
+ <configuration>
+ <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:schema-service-singleton</type>
+ <name>yang-schema-service</name>
+ </module>
+ <!-- To enable use of new in-memory datastore and new implementations
+ of data brokers, comment out all parts of this
+ xml which are marked with DATA-BROKER and uncomment all parts
+ of this xml which are marked with NEW-DATA-BROKER
+ -->
+ <!-- DATA-BROKER start-->
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:hash-map-data-store</type>
+ <name>hash-map-data-store</name>
+ </module>
+ <!-- DATA BROKER end -->
+ <!-- NEW-DATA-BROKER start -->
+ <!--
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:dom-inmemory-data-broker</type>
+ <name>async-data-broker</name>
+ <schema-service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
+ <name>yang-schema-service</name>
+ </schema-service>
+ </module>
+ -->
+ <!-- NEW-DATA-BROKER end -->
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:dom-broker-impl</type>
+ <name>dom-broker</name>
+ <!-- DATA-BROKER start -->
+ <data-store xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-data-store</type>
+ <!-- to switch to the clustered data store, comment out the hash-map-data-store <name> and uncomment the cluster-data-store one -->
+ <name>hash-map-data-store</name>
+ <!-- <name>cluster-data-store</name> -->
+ </data-store>
+ <!-- DATA-BROKER end -->
+ <!-- NEW-DATA-BROKER start -->
+ <!--
+ <async-data-broker>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
+ <name>async-data-broker</name>
+ </async-data-broker>
+ -->
+ <!-- NEW-DATA-BROKER end -->
+ </module>
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-broker-impl</type>
+ <name>binding-broker-impl</name>
+ <notification-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-notification-service</type>
+ <name>binding-notification-broker</name>
+ </notification-service>
+ <data-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
+ <name>binding-data-broker</name>
+ </data-broker>
+ </module>
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:runtime-generated-mapping</type>
+ <name>runtime-mapping-singleton</name>
+ </module>
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-notification-broker</type>
+ <name>binding-notification-broker</name>
+ </module>
+ <!-- DATA-BROKER start -->
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-data-broker</type>
+ <name>binding-data-broker</name>
+ <dom-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
+ <name>dom-broker</name>
+ </dom-broker>
+ <mapping-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding:binding-dom-mapping-service</type>
+ <name>runtime-mapping-singleton</name>
+ </mapping-service>
+ </module>
+ <!-- DATA-BROKER end -->
+ <!-- NEW-DATA-BROKER start -->
+ <!--
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-data-compatible-broker</type>
+ <name>binding-data-broker</name>
+ <dom-async-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
+ <name>dom-broker</name>
+ </dom-async-broker>
+ <binding-mapping-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding:binding-dom-mapping-service</type>
+ <name>runtime-mapping-singleton</name>
+ </binding-mapping-service>
+ </module>
+ -->
+ <!-- NEW-DATA-BROKER end -->
+ </modules>
+ <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
+ <instance>
+ <name>yang-schema-service</name>
+ <provider>/modules/module[type='schema-service-singleton'][name='yang-schema-service']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-notification-service</type>
+ <instance>
+ <name>binding-notification-broker</name>
+ <provider>/modules/module[type='binding-notification-broker'][name='binding-notification-broker']</provider>
+ </instance>
+ </service>
+ <!-- DATA-BROKER start -->
+ <service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-data-store</type>
+ <instance>
+ <name>hash-map-data-store</name>
+ <provider>/modules/module[type='hash-map-data-store'][name='hash-map-data-store']</provider>
+ </instance>
+ </service>
+ <!-- DATA-BROKER end -->
+ <!-- NEW-DATA-BROKER start -->
+ <!--
+ <service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
+ <instance>
+ <name>async-data-broker</name>
+ <provider>/modules/module[type='dom-inmemory-data-broker'][name='async-data-broker']</provider>
+ </instance>
+ </service>
+ -->
+ <!-- NEW-DATA-BROKER end -->
+ <service>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
+ <instance>
+ <name>binding-osgi-broker</name>
+ <provider>/modules/module[type='binding-broker-impl'][name='binding-broker-impl']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-rpc-registry</type>
+ <instance>
+ <name>binding-rpc-broker</name>
+ <provider>/modules/module[type='binding-broker-impl'][name='binding-broker-impl']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:binding-impl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding-impl:binding-dom-mapping-service</type>
+ <instance>
+ <name>runtime-mapping-singleton</name>
+ <provider>/modules/module[type='runtime-generated-mapping'][name='runtime-mapping-singleton']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
+ <instance>
+ <name>dom-broker</name>
+ <provider>/modules/module[type='dom-broker-impl'][name='dom-broker']</provider>
+ </instance>
+ </service>
+
+ <service>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
+ <instance>
+ <name>binding-data-broker</name>
+ <!-- DATA-BROKER start -->
+ <provider>/modules/module[type='binding-data-broker'][name='binding-data-broker']</provider>
+ <!-- DATA-BROKER end -->
+ <!-- NEW-DATA-BROKER start -->
+ <!--
+ <provider>/modules/module[type='binding-data-compatible-broker'][name='binding-data-broker']</provider>
+ -->
+ <!-- NEW-DATA-BROKER end -->
+ </instance>
+ </service>
+
+ </services>
+ </data>
+ </configuration>
+ <required-capabilities>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:netty:eventexecutor?module=netty-event-executor&revision=2013-11-12</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:threadpool?module=threadpool&revision=2013-04-09</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&revision=2013-10-28</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom?module=opendaylight-md-sal-dom&revision=2013-10-28</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl?module=opendaylight-sal-binding-broker-impl&revision=2013-10-28</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl?module=opendaylight-sal-dom-broker-impl&revision=2013-10-28</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:common?module=opendaylight-md-sal-common&revision=2013-10-28</capability>
+ </required-capabilities>
+</snapshot>
--- /dev/null
+<snapshot>
+ <configuration>
+ <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote:rpc">prefix:remote-zeromq-rpc-server</type>
+ <name>remoter</name>
+ <port xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote:rpc">5666</port>
+ <dom-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote:rpc">
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">prefix:dom-broker-osgi-registry</type>
+ <name>dom-broker</name>
+ </dom-broker>
+ </module>
+ </modules>
+ <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ </services>
+ </data>
+ </configuration>
+
+ <required-capabilities>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom?module=opendaylight-md-sal-dom&revision=2013-10-28</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl?module=opendaylight-sal-dom-broker-impl&revision=2013-10-28</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:common?module=opendaylight-md-sal-common&revision=2013-10-28</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote:rpc?module=odl-sal-dom-rpc-remote-cfg&revision=2013-10-28</capability>
+ </required-capabilities>
+</snapshot>
+
--- /dev/null
+<snapshot>
+ <configuration>
+ <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider:impl">
+ prefix:toaster-provider-impl
+ </type>
+ <name>toaster-provider-impl</name>
+
+ <rpc-registry>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-rpc-registry</type>
+ <name>binding-rpc-broker</name>
+ </rpc-registry>
+
+ <notification-service>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
+ binding:binding-notification-service
+ </type>
+ <name>binding-notification-broker</name>
+ </notification-service>
+ </module>
+
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer:impl">
+ prefix:toaster-consumer-impl
+ </type>
+ <name>toaster-consumer-impl</name>
+
+ <rpc-registry>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-rpc-registry</type>
+ <name>binding-rpc-broker</name>
+ </rpc-registry>
+
+ <notification-service>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
+ binding:binding-notification-service
+ </type>
+ <name>binding-notification-broker</name>
+ </notification-service>
+ </module>
+ </modules>
+
+ <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <service>
+ <type xmlns:toaster="urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider">toaster:toaster-provider</type>
+ <instance>
+ <name>toaster-provider</name>
+ <provider>/modules/module[type='toaster-provider-impl'][name='toaster-provider-impl']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:toaster="urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer">toaster:toaster-consumer</type>
+ <instance>
+ <name>toaster-consumer</name>
+ <provider>/modules/module[type='toaster-consumer-impl'][name='toaster-consumer-impl']</provider>
+ </instance>
+ </service>
+ </services>
+ </data>
+
+ </configuration>
+
+ <required-capabilities>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&revision=2013-10-28</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer?module=toaster-consumer&revision=2014-01-31</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer:impl?module=toaster-consumer-impl&revision=2014-01-31</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider?module=toaster-provider&revision=2014-01-31</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider:impl?module=toaster-provider-impl&revision=2014-01-31</capability>
+ </required-capabilities>
+
+</snapshot>
+
--- /dev/null
+ <configuration scan="true">
+
+ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <pattern>%date{"yyyy-MM-dd HH:mm:ss.SSS z"} [%thread] %-5level %logger{36} - %msg%n</pattern>
+ </encoder>
+ </appender>
+ <appender name="opendaylight.log" class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>logs/opendaylight.log</file>
+
+ <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+ <fileNamePattern>logs/opendaylight.%d.log.zip</fileNamePattern>
+ <maxHistory>1</maxHistory>
+ </rollingPolicy>
+
+ <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+ <maxFileSize>10MB</maxFileSize>
+ </triggeringPolicy>
+
+ <encoder>
+ <pattern>%date{"yyyy-MM-dd HH:mm:ss.SSS z"} [%thread] %-5level %logger{35} - %msg%n</pattern>
+ </encoder>
+ </appender>
+ <appender name="audit-file" class="ch.qos.logback.core.FileAppender">
+ <file>logs/audit.log</file>
+ <append>true</append>
+ <encoder>
+ <pattern>%date{"yyyy-MM-dd HH:mm:ss.SSS z"} %msg %n</pattern>
+ </encoder>
+ </appender>
+ <root level="error">
+ <appender-ref ref="STDOUT" />
+ <appender-ref ref="opendaylight.log" />
+ </root>
+
+ <!-- Base log level -->
+ <logger name="org.opendaylight" level="INFO"/>
+
+
+ <!-- Controller log level -->
+ <logger name="org.opendaylight.controller" level="INFO"/>
+
+ <!-- OSGi logging bridge -->
+ <logger name="org.opendaylight.controller.logging.bridge" level="WARN"/>
+ <logger name="org.opendaylight.controller.logging.bridge.internal" level="WARN"/>
+
+ <!-- Netty -->
+ <logger name="io.netty" level="WARN"/>
+
+ <!-- Openflow Protocol Plugin -->
+ <logger name="org.opendaylight.controller.protocol_plugin.openflow" level="INFO"/>
+ <logger name="org.opendaylight.controller.protocol_plugin.openflow.internal.DiscoveryService" level="INFO"/>
+ <logger name="org.opendaylight.controller.protocol_plugin.openflow.internal.InventoryService" level="INFO"/>
+ <logger name="org.opendaylight.controller.protocol_plugin.openflow.internal.InventoryServiceShim" level="INFO"/>
+ <logger name="org.opendaylight.controller.protocol_plugin.openflow.internal.TopologyServices" level="INFO"/>
+ <logger name="org.opendaylight.controller.protocol_plugin.openflow.internal.TopologyServiceShim" level="INFO"/>
+ <logger name="org.opendaylight.controller.protocol_plugin.openflow.core.internal.Controller" level="INFO"/>
+ <logger name="org.opendaylight.controller.protocol_plugin.openflow.core.internal.SwitchHandler" level="INFO"/>
+ <logger name="org.opendaylight.controller.protocol_plugin.openflow.core.internal.SwitchIOSecureService" level="INFO"/>
+ <!-- SAL -->
+ <logger name="org.opendaylight.controller.sal" level="INFO"/>
+ <logger name="org.opendaylight.controller.sal.implementation" level="INFO"/>
+ <logger name="org.opendaylight.controller.sal.implementation.internal.Inventory" level="INFO"/>
+ <logger name="org.opendaylight.controller.sal.implementation.internal.Topology" level="INFO"/>
+ <!-- remoterpc router and remoterpc routing table -->
+ <logger name="org.opendaylight.controller.sal.connector.remoterpc" level="INFO" />
+ <!-- Functional Modules -->
+ <logger name="org.opendaylight.controller.arphandler" level="INFO"/>
+ <logger name="org.opendaylight.controller.hosttracker" level="INFO"/>
+ <logger name="org.opendaylight.controller.routing" level="INFO"/>
+ <logger name="org.opendaylight.controller.forwardingrulesmanager" level="INFO"/>
+ <logger name="org.opendaylight.controller.forwarding.ipswitch" level="INFO"/>
+ <logger name="org.opendaylight.controller.switchmanager" level="INFO"/>
+ <logger name="org.opendaylight.controller.topologymanager" level="INFO"/>
+ <logger name="org.opendaylight.controller.usermanager" level="INFO"/>
+ <!-- Web modules -->
+ <logger name="org.opendaylight.controller.web" level="INFO"/>
+
+ <!--
+ Unsynchronized controller startup causes models to crop up in random
+ order, which results in temporary inability to fully resolve a model,
+ which is usually resolved. Do not flood console, but keep the messages,
+ as they may be indicating and error.
+ -->
+ <logger name="org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort" level="INFO" additivity="false">
+ <appender-ref ref="opendaylight.log"/>
+ </logger>
+
+ <!-- To debug MD-SAL schema loading issues, uncomment this -->
+ <!--logger name="org.opendaylight.yangtools.yang.parser.impl.util.URLSchemaContextResolver" level="DEBUG"/>
+ <logger name="org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl" level="TRACE"/-->
+
+ <!-- additivity=false ensures analytics data only goes to the analytics log -->
+ <logger name="audit" level="INFO" additivity="false">
+ <appender-ref ref="audit-file"/>
+ </logger>
+</configuration>
--- /dev/null
+############################################################
+# Configuration file for tomcat logging
+############################################################
+# Handlers:
+# "handlers" specifies a comma separated list of log Handler
+# classes. These handlers will be installed during VM startup.
+# Note that these classes must be on the system classpath.
+# Following line configures a ConsoleHandler and a FileHandler
+
+handlers= java.util.logging.FileHandler,java.util.logging.ConsoleHandler
+
+############################################################
+# Handler specific properties
+# Describes specific configuration info for Handlers
+# JUL does not support rolling file handler based on date
+# For now we will keep count of files to 5 with rolling size of 10MB
+############################################################
+
+java.util.logging.FileHandler.pattern = logs/tomcat%g.log
+java.util.logging.FileHandler.limit = 104857600
+java.util.logging.FileHandler.count = 5
+java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter
+java.util.logging.FileHandler.append = true
+java.util.logging.FileHandler.level = INFO
+
+# Limit the message that are printed on the console to SEVERE and above.
+java.util.logging.ConsoleHandler.level = WARNING
+java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
+
+# SimpleFormatter output format to print one-line log message like this:
+# <YYYY>-<MM>-<DD> <HH>:<MM>:<SS> <TimeZone> [<SOURCE>] ><LOG_LEVEL> <LOGGER> <MESSAGE> <THROWABLE>
+#
+java.util.logging.SimpleFormatter.format=%1$tF %1$tT %1$tZ [%3$s] %4$s %2$s %5$s%6$s%n
+
+############################################################
+# Facility specific properties.
+# Provides extra control for each logger.
+############################################################
+
+# For example, set the com.xyz.foo logger to only log SEVERE
+# messages
+#org.apache.catalina = SEVERE
--- /dev/null
+<?xml version='1.0' encoding='utf-8'?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<Server>
+ <!--APR library loader. Documentation at /docs/apr.html -->
+ <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
+ <!--Initialize Jasper prior to webapps are loaded. Documentation at /docs/jasper-howto.html -->
+ <Listener className="org.apache.catalina.core.JasperListener" />
+ <!-- Prevent memory leaks due to use of particular java/javax APIs-->
+ <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
+ <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
+ <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
+
+ <Service name="Catalina">
+ <Connector port="8080" protocol="HTTP/1.1"
+ connectionTimeout="20000"
+ redirectPort="8443" />
+
+<!--
+ Please remove the comments around the following Connector tag to enable HTTPS Authentication support.
+ Remember to add a valid keystore in the configuration folder.
+ More info : http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
+-->
+
+ <!--
+ <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
+ maxThreads="150" scheme="https" secure="true"
+ clientAuth="false" sslProtocol="TLS"
+ keystoreFile="configuration/keystore"
+ keystorePass="changeit"/>
+ -->
+
+ <Engine name="Catalina" defaultHost="localhost">
+ <Host name="localhost" appBase=""
+ unpackWARs="false" autoDeploy="false"
+ deployOnStartup="false" createDirs="false">
+<!-- <Realm className="org.opendaylight.controller.security.ControllerCustomRealm" />
+ <Valve className="org.apache.catalina.authenticator.SingleSignOn" />
+ -->
+ <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
+ prefix="web_access_log_" suffix=".txt" resolveHosts="false"
+ rotatable="true" fileDateFormat="yyyy-MM"
+ pattern="%{yyyy-MM-dd HH:mm:ss.SSS z}t - [%a] - %r"/>
+ </Host>
+ </Engine>
+ </Service>
+</Server>
--- /dev/null
+# Extra packages to import from the boot class loader
+org.osgi.framework.system.packages.extra=sun.reflect,sun.reflect.misc,sun.misc,sun.nio.ch
+
+# https://bugs.eclipse.org/bugs/show_bug.cgi?id=325578
+# Extend the framework to avoid the resources to be presented with
+# a URL of type bundleresource: but to be presented as file:
+osgi.hook.configurators.include=org.eclipse.virgo.kernel.equinox.extensions.hooks.ExtensionsHookConfigurator
+
+# Embedded Tomcat configuration File
+org.eclipse.gemini.web.tomcat.config.path=configuration/tomcat-server.xml
+org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true
+
+# Use Equinox as default OSGi Framework Implementation
+karaf.framework=equinox
+
+# Netconf startup configuration
+netconf.tcp.address=127.0.0.1
+netconf.tcp.port=8383
+
+netconf.tcp.client.address=127.0.0.1
+netconf.tcp.client.port=8383
+
+netconf.ssh.address=0.0.0.0
+netconf.ssh.port=1830
+netconf.ssh.pk.path = ./configuration/RSA.pk
+
+
+netconf.config.persister.active=1,2
+# read startup configuration
+netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.xml.XmlDirectoryStorageAdapter
+netconf.config.persister.1.properties.directoryStorage=configuration/initial/
+
+# include only xml files, files with other extensions will be skipped, multiple extensions are permitted e.g. netconf.config.persister.1.properties.includeExtensions=xml,cfg,config
+netconf.config.persister.1.properties.includeExtensions=xml
+netconf.config.persister.1.readonly=true
+
+netconf.config.persister.2.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.xml.XmlFileStorageAdapter
+netconf.config.persister.2.properties.fileStorage=configuration/current/controller.currentconfig.xml
+netconf.config.persister.2.properties.numberOfBackups=1
+
+# logback configuration
+logback.configurationFile=configuration/logback.xml
+
+# Container configuration
+container.profile = Container
+
+# Connection manager configuration
+connection.scheme = ANY_CONTROLLER_ONE_MASTER
+
+# Open Flow related system parameters
+# TCP port on which the controller is listening (default 6633)
+# of.listenPort=6633
+# IP address of the controller (default: wild card)
+# of.address = 127.0.0.1
+# The time (in milliseconds) the controller will wait for a response after sending a Barrier Request or a Statistic Request message (default 2000 msec)
+# of.messageResponseTimer=2000
+# The switch liveness timeout value (default 60500 msec)
+# of.switchLivenessTimeout=60500
+# The size of the queue holding pending statistics requests (default 64). For large networks of n switches, it is recommended to set the queue size to n
+# of.statsQueueSize = 64
+# The flow statistics polling interval in second (default 10 sec)
+# of.flowStatsPollInterval=10
+# The port statistics polling interval in second (default 5 sec)
+# of.portStatsPollInterval=5
+# The description statistics polling interval in second (default 60 sec)
+# of.descStatsPollInterval=60
+# The table statistics polling interval in second (default 10 sec)
+# of.tableStatsPollInterval=10
+# The maximum number of asynchronous messages can be sent before sending a Barrier Request (default 100)
+# of.barrierMessagePriorCount=100
+# The interval which determines how often the discovery packets should be sent (default 300 sec)
+# of.discoveryInterval=300
+# The timeout multiple of discovery interval
+# of.discoveryTimeoutMultiple=2
+# For newly added ports, allow one more retry if the elapsed time exceeds this threshold (default 30 sec)
+# of.discoveryThreshold=30
+# The maximum number of ports handled in one discovery batch (default 512)
+# of.discoveryBatchMaxPorts=512
+
+# OVSDB configuration
+# ovsdb plugin supports both active and passive connections. It listens on port 6640 by default for Active connections.
+ovsdb.listenPort=6640
+
+# ovsdb creates Openflow nodes/bridges. This configuration configures the bridge's Openflow version.
+# default Openflow version = 1.0, we also support 1.3.
+# ovsdb.of.version=1.3
+
+# TLS configuration
+# To enable TLS, set secureChannelEnabled=true and specify the location of controller Java KeyStore and TrustStore files.
+# The Java KeyStore contains controller's private key and certificate. The Java TrustStore contains the trusted certificate
+# entries, including switches' Certification Authority (CA) certificates. For example,
+# secureChannelEnabled=true
+# controllerKeyStore=./configuration/ctlKeyStore
+# controllerKeyStorePassword=xxxxxxxx (this password should match the password used for KeyStore generation and at least 6 characters)
+# controllerTrustStore=./configuration/ctlTrustStore
+# controllerTrustStorePassword=xxxxxxxx (this password should match the password used for TrustStore generation and at least 6 characters)
+
+secureChannelEnabled=false
+controllerKeyStore=
+controllerKeyStorePassword=
+controllerTrustStore=
+controllerTrustStorePassword=
+
+# User Manager configurations
+enableStrongPasswordCheck = false
+
+#Jolokia configurations
+org.jolokia.listenForHttpService=false
+
+# Logging configuration for Tomcat-JUL logging
+java.util.logging.config.file=configuration/tomcat-logging.properties
+
+#Hosttracker hostsdb key scheme setting
+hosttracker.keyscheme=IP
\ No newline at end of file
--- /dev/null
+org.opendaylight.controller.version = 0.1
+org.opendaylight.controller.build.scm.version = ${buildNumber}
+org.opendaylight.controller.build.user = ${env.USER}
+org.opendaylight.controller.build.workspace = **********
+org.opendaylight.controller.build.timestamp = ${timestamp}
+org.opendaylight.controller.build.machine = **********
<groupId>org.opendaylight.controller</groupId>
<artifactId>netconf-client</artifactId>
</dependency>
+
+ <!--Netconf config-->
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-config-dispatcher</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netconf-impl</artifactId>
netconf.ssh.address=0.0.0.0
netconf.ssh.port=1830
netconf.ssh.pk.path = ./configuration/RSA.pk
+netconf.ssh.default.user = netconf
+netconf.ssh.default.password = netconf
netconf.config.persister.active=1,2
<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:schema-service-singleton</type>
<name>yang-schema-service</name>
</module>
- <!-- To enable use of new in-memory datastore and new implementations
- of data brokers, comment out all parts of this
- xml which are marked with DATA-BROKER and uncomment all parts
- of this xml which are marked with NEW-DATA-BROKER
- -->
- <!-- DATA-BROKER start-->
- <module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:hash-map-data-store</type>
- <name>hash-map-data-store</name>
- </module>
- <!-- DATA BROKER end -->
- <!-- NEW-DATA-BROKER start -->
- <!--
<module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:dom-inmemory-data-broker</type>
- <name>async-data-broker</name>
- <schema-service>
- <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
- <name>yang-schema-service</name>
- </schema-service>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:runtime-generated-mapping</type>
+ <name>runtime-mapping-singleton</name>
</module>
- -->
- <!-- NEW-DATA-BROKER end -->
<module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:dom-broker-impl</type>
- <name>dom-broker</name>
- <!-- DATA-BROKER start -->
- <data-store xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">
- <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-data-store</type>
- <!-- to switch to the clustered data store, comment out the hash-map-data-store <name> and uncomment the cluster-data-store one -->
- <name>hash-map-data-store</name>
- <!-- <name>cluster-data-store</name> -->
- </data-store>
- <!-- DATA-BROKER end -->
- <!-- NEW-DATA-BROKER start -->
- <!--
- <async-data-broker>
- <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
- <name>async-data-broker</name>
- </async-data-broker>
- -->
- <!-- NEW-DATA-BROKER end -->
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-notification-broker</type>
+ <name>binding-notification-broker</name>
</module>
<module>
<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-broker-impl</type>
<name>binding-data-broker</name>
</data-broker>
</module>
+
+ <!--
+ Tree-based in-memory data store. This is the data store which is currently
+ recommended for single-node deployments.
+ -->
<module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:runtime-generated-mapping</type>
- <name>runtime-mapping-singleton</name>
- </module>
- <module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-notification-broker</type>
- <name>binding-notification-broker</name>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:dom-inmemory-data-broker</type>
+ <name>inmemory-data-broker</name>
+ <schema-service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
+ <name>yang-schema-service</name>
+ </schema-service>
</module>
- <!-- DATA-BROKER start -->
<module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-data-broker</type>
- <name>binding-data-broker</name>
- <dom-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
- <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
- <name>dom-broker</name>
- </dom-broker>
- <mapping-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
- <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding:binding-dom-mapping-service</type>
- <name>runtime-mapping-singleton</name>
- </mapping-service>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:dom-broker-impl</type>
+ <name>inmemory-dom-broker</name>
+ <async-data-broker>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
+ <name>inmemory-data-broker</name>
+ </async-data-broker>
</module>
- <!-- DATA-BROKER end -->
- <!-- NEW-DATA-BROKER start -->
- <!--
<module>
<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-data-compatible-broker</type>
- <name>binding-data-broker</name>
+ <name>inmemory-binding-data-broker</name>
<dom-async-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
<type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
<name>dom-broker</name>
<name>runtime-mapping-singleton</name>
</binding-mapping-service>
</module>
- -->
- <!-- NEW-DATA-BROKER end -->
</modules>
<services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
- <service>
- <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
- <instance>
- <name>yang-schema-service</name>
- <provider>/modules/module[type='schema-service-singleton'][name='yang-schema-service']</provider>
- </instance>
- </service>
- <service>
- <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-notification-service</type>
- <instance>
- <name>binding-notification-broker</name>
- <provider>/modules/module[type='binding-notification-broker'][name='binding-notification-broker']</provider>
- </instance>
- </service>
- <!-- DATA-BROKER start -->
- <service>
- <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-data-store</type>
- <instance>
- <name>hash-map-data-store</name>
- <provider>/modules/module[type='hash-map-data-store'][name='hash-map-data-store']</provider>
- </instance>
- </service>
- <!-- DATA-BROKER end -->
- <!-- NEW-DATA-BROKER start -->
- <!--
- <service>
- <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
- <instance>
- <name>async-data-broker</name>
- <provider>/modules/module[type='dom-inmemory-data-broker'][name='async-data-broker']</provider>
- </instance>
- </service>
- -->
- <!-- NEW-DATA-BROKER end -->
- <service>
- <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
- <instance>
- <name>binding-osgi-broker</name>
- <provider>/modules/module[type='binding-broker-impl'][name='binding-broker-impl']</provider>
- </instance>
- </service>
- <service>
- <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-rpc-registry</type>
- <instance>
- <name>binding-rpc-broker</name>
- <provider>/modules/module[type='binding-broker-impl'][name='binding-broker-impl']</provider>
- </instance>
- </service>
- <service>
- <type xmlns:binding-impl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding-impl:binding-dom-mapping-service</type>
- <instance>
- <name>runtime-mapping-singleton</name>
- <provider>/modules/module[type='runtime-generated-mapping'][name='runtime-mapping-singleton']</provider>
- </instance>
- </service>
- <service>
- <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
- <instance>
- <name>dom-broker</name>
- <provider>/modules/module[type='dom-broker-impl'][name='dom-broker']</provider>
- </instance>
- </service>
+ <service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
+ <instance>
+ <name>yang-schema-service</name>
+ <provider>/modules/module[type='schema-service-singleton'][name='yang-schema-service']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:binding-impl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding-impl:binding-dom-mapping-service</type>
+ <instance>
+ <name>runtime-mapping-singleton</name>
+ <provider>/modules/module[type='runtime-generated-mapping'][name='runtime-mapping-singleton']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-notification-service</type>
+ <instance>
+ <name>binding-notification-broker</name>
+ <provider>/modules/module[type='binding-notification-broker'][name='binding-notification-broker']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
+ <instance>
+ <name>binding-osgi-broker</name>
+ <provider>/modules/module[type='binding-broker-impl'][name='binding-broker-impl']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-rpc-registry</type>
+ <instance>
+ <name>binding-rpc-broker</name>
+ <provider>/modules/module[type='binding-broker-impl'][name='binding-broker-impl']</provider>
+ </instance>
+ </service>
- <service>
- <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
- <instance>
- <name>binding-data-broker</name>
- <!-- DATA-BROKER start -->
- <provider>/modules/module[type='binding-data-broker'][name='binding-data-broker']</provider>
- <!-- DATA-BROKER end -->
- <!-- NEW-DATA-BROKER start -->
- <!--
- <provider>/modules/module[type='binding-data-compatible-broker'][name='binding-data-broker']</provider>
- -->
- <!-- NEW-DATA-BROKER end -->
- </instance>
- </service>
+ <service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
+ <instance>
+ <name>dom-broker</name>
+ <provider>/modules/module[type='dom-broker-impl'][name='inmemory-dom-broker']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
+ <instance>
+ <name>binding-data-broker</name>
+ <provider>/modules/module[type='binding-data-compatible-broker'][name='inmemory-binding-data-broker']</provider>
+ </instance>
+ </service>
+
+ <service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
+ <instance>
+ <name>inmemory-data-broker</name>
+ <provider>/modules/module[type='dom-inmemory-data-broker'][name='inmemory-data-broker']</provider>
+ </instance>
+ </service>
</services>
</data>
</configuration>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ 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
+-->
+<snapshot>
+ <configuration>
+ <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+
+ <!-- Netconf dispatcher to be used by all netconf-connectors -->
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:client:dispatcher">prefix:netconf-client-dispatcher</type>
+ <name>global-netconf-dispatcher</name>
+ <boss-thread-group xmlns="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:client:dispatcher">
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netty">prefix:netty-threadgroup</type>
+ <name>global-boss-group</name>
+ </boss-thread-group>
+ <worker-thread-group xmlns="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:client:dispatcher">
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netty">prefix:netty-threadgroup</type>
+ <name>global-worker-group</name>
+ </worker-thread-group>
+ <timer xmlns="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:client:dispatcher">
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netty">prefix:netty-timer</type>
+ <name>global-timer</name>
+ </timer>
+ </module>
+
+ <!-- Loopback connection to netconf server in controller using netconf-connector -->
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">prefix:sal-netconf-connector</type>
+ <name>controller-config</name>
+ <address xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">127.0.0.1</address>
+ <port xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">1830</port>
+ <username xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">admin</username>
+ <password xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">admin</password>
+ <tcp-only xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">false</tcp-only>
+ <event-executor xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netty">prefix:netty-event-executor</type>
+ <name>global-event-executor</name>
+ </event-executor>
+ <dom-registry xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">prefix:dom-broker-osgi-registry</type>
+ <name>dom-broker</name>
+ </dom-registry>
+ <client-dispatcher xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:netconf">prefix:netconf-client-dispatcher</type>
+ <name>global-netconf-dispatcher</name>
+ </client-dispatcher>
+ </module>
+ </modules>
+
+ <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <service>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:netconf">prefix:netconf-client-dispatcher</type>
+ <instance>
+ <name>global-netconf-dispatcher</name>
+ <provider>/modules/module[type='netconf-client-dispatcher'][name='global-netconf-dispatcher']</provider>
+ </instance>
+ </service>
+ </services>
+
+ </data>
+ </configuration>
+ <required-capabilities>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf?module=odl-sal-netconf-connector-cfg&revision=2013-10-28</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:config:netconf:client:dispatcher?module=odl-netconfig-client-cfg&revision=2014-04-08</capability>
+ </required-capabilities>
+</snapshot>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- vi: set et smarttab sw=4 tabstop=4: -->
-<!--
- 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
--->
-<snapshot>
- <configuration>
- <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
- <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
- <module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">prefix:sal-netconf-connector</type>
- <name>controller-config</name>
- <port xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">1830</port>
- <username xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">admin</username>
- <worker-thread-group xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netty">prefix:netty-threadgroup</type>
- <name>global-worker-group</name>
- </worker-thread-group>
- <address xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">127.0.0.1</address>
- <tcp-only xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">false</tcp-only>
- <event-executor xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netty">prefix:netty-event-executor</type>
- <name>global-event-executor</name>
- </event-executor>
- <password xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">admin</password>
- <boss-thread-group xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netty">prefix:netty-threadgroup</type>
- <name>global-boss-group</name>
- </boss-thread-group>
- <dom-registry xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">prefix:dom-broker-osgi-registry</type>
- <name>dom-broker</name>
- </dom-registry>
- </module>
- </modules>
- </data>
- </configuration>
- <required-capabilities>
- <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf?module=odl-sal-netconf-connector-cfg&revision=2013-10-28</capability>
- </required-capabilities>
-</snapshot>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
- <dependency>
- <groupId>org.eclipse.xtend</groupId>
- <artifactId>org.eclipse.xtend.lib</artifactId>
- </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>forwardingrulesmanager</artifactId>
</instructions>
</configuration>
</plugin>
- <plugin>
- <groupId>org.eclipse.xtend</groupId>
- <artifactId>xtend-maven-plugin</artifactId>
- </plugin>
</plugins>
</build>
<scm>
--- /dev/null
+/**
+ * Copyright (c) 2014 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.md.frm.compatibility;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opendaylight.controller.forwardingrulesmanager.FlowConfig;
+import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager;
+import org.opendaylight.controller.sal.compatibility.NodeMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.Flows;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.FlowsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowKey;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ConfigurationReader implements FlowManagementReader {
+
+ private final static Logger LOG = LoggerFactory.getLogger(ConfigurationReader.class);
+
+ private IForwardingRulesManager manager;
+
+ @Override
+ public Flows readAllFlows() {
+ List<FlowConfig> staticFlows = this.manager.getStaticFlows();
+ List<Flow> flowMap = new ArrayList<Flow>(staticFlows.size());
+
+ for (FlowConfig conf : staticFlows) {
+ flowMap.add(FlowConfigMapping.toConfigurationFlow(conf));
+ }
+ final FlowsBuilder flowsBuilder = new FlowsBuilder();
+ return (flowsBuilder.setFlow(flowMap)).build();
+ }
+
+ @Override
+ public Flow readFlow(final FlowKey key) {
+ try {
+ final FlowConfig flowConf =
+ this.manager.getStaticFlow(String.valueOf(key.getId()), NodeMapping.toADNode(key.getNode()));
+ return FlowConfigMapping.toConfigurationFlow(flowConf);
+ } catch (Exception e) {
+ String errMsg = MessageFormat.format("readFlow by key {} fail", key);
+ LOG.error(errMsg, e);
+ throw new RuntimeException(errMsg, e);
+ }
+ }
+
+ public IForwardingRulesManager getManager() {
+ return this.manager;
+ }
+
+ public void setManager(final IForwardingRulesManager manager) {
+ this.manager = manager;
+ }
+}
--- /dev/null
+/**
+ * Copyright (c) 2014 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.md.frm.compatibility;
+
+import java.util.Collections;
+
+import org.opendaylight.controller.forwardingrulesmanager.FlowConfig;
+import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager;
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
+import org.opendaylight.controller.md.sal.common.api.data.DataModification;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider;
+import org.opendaylight.controller.sal.common.util.Arguments;
+import org.opendaylight.controller.sal.common.util.Rpcs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.Flows;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowKey;
+import org.opendaylight.yangtools.concepts.Registration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.Identifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
+
+public class FRMRuntimeDataProvider implements RuntimeDataProvider, DataCommitHandler<InstanceIdentifier<? extends DataObject>,DataObject> {
+
+ private final static InstanceIdentifier<Flows> FLOWS_PATH = InstanceIdentifier.<Flows> builder(Flows.class).toInstance();
+
+ private final FlowManagementReader configuration = new ConfigurationReader();
+ private DataChangeListener<InstanceIdentifier<? extends DataObject>, DataObject> changeListener;
+ private DataProviderService dataService;
+ private IForwardingRulesManager manager;
+
+ public Registration<DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject>> init() {
+ return this.dataService.registerCommitHandler(FRMRuntimeDataProvider.FLOWS_PATH, this);
+ }
+
+ @Override
+ public DataObject readConfigurationData(final InstanceIdentifier<? extends DataObject> path) {
+ return this.readFrom(this.configuration, path);
+ }
+
+ @Override
+ public DataObject readOperationalData(final InstanceIdentifier<? extends DataObject> path) {
+ return this.readFrom(this.configuration, path);
+ }
+
+ public DataObject readFrom(final FlowManagementReader store, final InstanceIdentifier<? extends DataObject> path) {
+ if (Objects.equal(FRMRuntimeDataProvider.FLOWS_PATH, path)) {
+ return store.readAllFlows();
+ }
+ if (FRMRuntimeDataProvider.FLOWS_PATH.contains(path)) {
+ return store.readFlow(this.toFlowKey(path));
+ }
+ return null;
+ }
+
+ @Override
+ public FlowCommitTransaction requestCommit(final DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification) {
+ return new FlowCommitTransaction(this, modification);
+ }
+
+ public FlowKey toFlowKey(final InstanceIdentifier<? extends DataObject> identifier) {
+ Preconditions.<InstanceIdentifier<? extends DataObject>> checkNotNull(identifier);
+
+ Iterable<PathArgument> path = identifier.getPathArguments();
+ PathArgument get = path.iterator().next();
+ final Identifier itemKey = Arguments.<IdentifiableItem> checkInstanceOf(get, IdentifiableItem.class).getKey();
+ return Arguments.<FlowKey> checkInstanceOf(itemKey, FlowKey.class);
+ }
+
+ public RpcResult<Void> finish(final FlowCommitTransaction transaction) {
+ Iterable<FlowConfig> toRemove = transaction.getToRemove();
+ for (final FlowConfig flow : toRemove) {
+ this.manager.removeStaticFlow(flow.getName(), flow.getNode());
+ }
+ Iterable<FlowConfig> toUpdate = transaction.getToUpdate();
+ for (final FlowConfig flow : toUpdate) {
+ this.manager.removeStaticFlow(flow.getName(), flow.getNode());
+ this.manager.addStaticFlow(flow);
+ }
+ return Rpcs.<Void> getRpcResult(true, null, Collections.<RpcError> emptySet());
+ }
+
+ public RpcResult<Void> rollback(final FlowCommitTransaction transaction) {
+ return null;
+ }
+
+ public DataProviderService getDataService() {
+ return this.dataService;
+ }
+
+ public void setDataService(final DataProviderService dataService) {
+ this.dataService = dataService;
+ }
+
+ public DataChangeListener<InstanceIdentifier<? extends DataObject>, DataObject> getChangeListener() {
+ return this.changeListener;
+ }
+
+ public void setChangeListener(final DataChangeListener<InstanceIdentifier<? extends DataObject>, DataObject> changeListener) {
+ this.changeListener = changeListener;
+ }
+
+ public IForwardingRulesManager getManager() {
+ return this.manager;
+ }
+
+ public void setManager(final IForwardingRulesManager manager) {
+ this.manager = manager;
+ }
+}
+++ /dev/null
-/*
- * Copyright (c) 2014 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.md.frm.compatibility
-
-import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler
-import org.opendaylight.controller.md.sal.common.api.data.DataModification
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowKey
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.Flows
-import org.opendaylight.controller.md.sal.common.api.data.DataChangeListener
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.FlowsBuilder
-import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager
-import static com.google.common.base.Preconditions.*;
-import static extension org.opendaylight.controller.md.frm.compatibility.FlowConfigMapping.*;
-import static extension org.opendaylight.controller.sal.compatibility.NodeMapping.*;
-import org.opendaylight.controller.sal.common.util.Arguments
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem
-import org.opendaylight.yangtools.yang.common.RpcResult
-import org.opendaylight.controller.forwardingrulesmanager.FlowConfig
-import java.util.HashSet
-import org.opendaylight.controller.sal.common.util.Rpcs
-import java.util.Collections
-import org.opendaylight.yangtools.yang.common.RpcError
-
-class FRMRuntimeDataProvider implements RuntimeDataProvider, DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject> {
-
- static val FLOWS_PATH = InstanceIdentifier.builder(Flows).toInstance;
-
- @Property
- var DataProviderService dataService;
-
- @Property
- var DataChangeListener changeListener;
-
- @Property
- var IForwardingRulesManager manager;
-
- FlowManagementReader configuration = new ConfigurationReader();
-
- def init() {
- //dataService.registerDataChangeListener(FLOWS_PATH, changeListener);
- dataService.registerCommitHandler(FLOWS_PATH, this);
- }
-
- override readConfigurationData(InstanceIdentifier<? extends DataObject> path) {
- return readFrom(configuration, path);
- }
-
- override DataObject readOperationalData(InstanceIdentifier<? extends DataObject> path) {
- return readFrom(configuration, path);
- }
-
- def DataObject readFrom(FlowManagementReader store, InstanceIdentifier<? extends DataObject> path) {
- if (FLOWS_PATH == path) {
- return store.readAllFlows();
- }
- if (FLOWS_PATH.contains(path)) {
- return store.readFlow(path.toFlowKey());
- }
- return null;
- }
-
- override FlowCommitTransaction requestCommit(
- DataModification modification) {
- return new FlowCommitTransaction(this,modification);
- }
-
- def toFlowKey(InstanceIdentifier<? extends DataObject> identifier) {
- checkNotNull(identifier)
- val item = Arguments.checkInstanceOf(identifier.path.get(1),IdentifiableItem);
- val key = Arguments.checkInstanceOf(item.key,FlowKey)
- return key;
- }
-
- def RpcResult<Void> finish(FlowCommitTransaction transaction) {
- for(flw: transaction.toRemove) {
- manager.removeStaticFlow(flw.name,flw.node)
- }
-
- for(flw: transaction.toUpdate) {
- manager.removeStaticFlow(flw.name,flw.node);
- manager.addStaticFlow(flw);
- }
-
- return Rpcs.<Void>getRpcResult(true,null,Collections.<RpcError>emptySet())
- }
-
- def RpcResult<Void> rollback(FlowCommitTransaction transaction) {
- // NOOP: We did not changed any state.
- }
-
-}
-
-class ConfigurationReader implements FlowManagementReader {
-
- @Property
- var IForwardingRulesManager manager;
-
- override Flows readAllFlows() {
- val it = new FlowsBuilder();
- flow = manager.staticFlows.map[
- toConfigurationFlow();
- ]
- return it.build();
- }
-
- override readFlow(FlowKey key) {
- val flowCfg = manager.getStaticFlow(String.valueOf(key.id), key.node.toADNode());
- return flowCfg.toConfigurationFlow;
- }
-}
-
-public static class FlowCommitTransaction implements DataCommitTransaction<InstanceIdentifier<? extends DataObject>, DataObject> {
-
- @Property
- val DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification;
-
- @Property
- val FRMRuntimeDataProvider flowManager;
-
- @Property
- val toAdd = new HashSet<FlowConfig>();
-
- @Property
- var Iterable<FlowConfig> toUpdate
-
- @Property
- var Iterable<FlowConfig> toRemove
-
-
- new(FRMRuntimeDataProvider flowManager,DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification) {
- super();
- _flowManager = flowManager;
- _modification = modification;
- processModification();
- }
-
- override finish() throws IllegalStateException {
- return flowManager.finish(this);
- }
-
- override rollback() throws IllegalStateException
-{
- return flowManager.rollback(this);
- }
-
- def processModification() {
- val updated = modification.updatedConfigurationData.entrySet;
-
- val _toUpdate = updated.filter[key.isFlowPath].map[
- return (value as Flow).toFlowConfig
- ]
- toUpdate = _toUpdate as Iterable<FlowConfig>
-
-
- val _toRemove = modification.removedConfigurationData.filter[isFlowPath].map[
- toFlowConfig
- ]
- toRemove = _toRemove as Iterable<FlowConfig>
-
- }
-}
--- /dev/null
+/**
+ * Copyright (c) 2014 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.md.frm.compatibility;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.opendaylight.controller.forwardingrulesmanager.FlowConfig;
+import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.DataModification;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+public class FlowCommitTransaction implements DataCommitTransaction<InstanceIdentifier<? extends DataObject>, DataObject> {
+
+ private final DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification;
+ private final HashSet<FlowConfig> toAdd = new HashSet<FlowConfig>();
+ private final FRMRuntimeDataProvider flowManager;
+ private Iterable<FlowConfig> toUpdate;
+ private Iterable<FlowConfig> toRemove;
+
+ public FlowCommitTransaction(
+ final FRMRuntimeDataProvider flowManager,
+ final DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification) {
+ this.flowManager = flowManager;
+ this.modification = modification;
+ this.processModification();
+ }
+
+ @Override
+ public RpcResult<Void> finish() throws IllegalStateException {
+ return this.flowManager.finish(this);
+ }
+
+ @Override
+ public RpcResult<Void> rollback() throws IllegalStateException {
+ return this.flowManager.rollback(this);
+ }
+
+ public void processModification() {
+ final Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> updated =
+ this.modification.getUpdatedConfigurationData().entrySet();
+ final List<FlowConfig> forUpdate = new ArrayList<FlowConfig>(updated.size());
+
+ if (updated != null && !(updated.isEmpty())) {
+ for (Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry : updated) {
+ if (FlowConfigMapping.isFlowPath(entry.getKey())) {
+ forUpdate.add(FlowConfigMapping.toFlowConfig((Flow) entry.getValue()));
+ }
+ }
+ }
+ this.toUpdate = Collections.unmodifiableCollection(forUpdate);
+
+ final Set<InstanceIdentifier<? extends DataObject>> removedConfigurationData =
+ this.modification.getRemovedConfigurationData();
+ final List<FlowConfig> forRemove = new ArrayList<FlowConfig>(removedConfigurationData.size());
+
+ if (removedConfigurationData != null && !(removedConfigurationData.isEmpty())) {
+ for (InstanceIdentifier<? extends DataObject> data : removedConfigurationData) {
+ if (FlowConfigMapping.isFlowPath(data)) {
+ forRemove.add(FlowConfigMapping.toFlowConfig(data));
+ }
+ }
+ }
+ this.toRemove = Collections.unmodifiableCollection(forRemove);
+ }
+
+ @Override
+ public DataModification<InstanceIdentifier<? extends DataObject>, DataObject> getModification() {
+ return this.modification;
+ }
+
+ public FRMRuntimeDataProvider getFlowManager() {
+ return this.flowManager;
+ }
+
+ public HashSet<FlowConfig> getToAdd() {
+ return this.toAdd;
+ }
+
+ public Iterable<FlowConfig> getToUpdate() {
+ return this.toUpdate;
+ }
+
+ public Iterable<FlowConfig> getToRemove() {
+ return this.toRemove;
+ }
+}
--- /dev/null
+/**
+ * Copyright (c) 2014 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.md.frm.compatibility;
+
+import java.text.MessageFormat;
+import java.util.Iterator;
+
+import org.opendaylight.controller.forwardingrulesmanager.FlowConfig;
+import org.opendaylight.controller.sal.compatibility.MDFlowMapping;
+import org.opendaylight.controller.sal.compatibility.NodeMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowAdded;
+import org.opendaylight.yangtools.yang.binding.Identifiable;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FlowConfigMapping {
+
+ private final static Logger LOG = LoggerFactory.getLogger(FlowConfigMapping.class);
+
+ /* nodes/node/flow -> 0 / 1 / 2 */
+ private static final int FLOW_KEY_IDENTIFIER_DEEP = 2;
+
+ public static Flow toConfigurationFlow(final FlowConfig sourceCfg) {
+ final FlowAdded source = MDFlowMapping.flowAdded(sourceCfg.getFlow());
+ final FlowBuilder flowBuilder = new FlowBuilder();
+ flowBuilder.setInstructions(source.getInstructions());
+ flowBuilder.setCookie(source.getCookie());
+ flowBuilder.setHardTimeout(source.getHardTimeout());
+ flowBuilder.setIdleTimeout(source.getIdleTimeout());
+ flowBuilder.setMatch(source.getMatch());
+ flowBuilder.setNode(source.getNode());
+
+ FlowKey flowKey =
+ new FlowKey(Long.valueOf(sourceCfg.getName()), flowBuilder.getNode());
+ flowBuilder.setKey(flowKey);
+ return flowBuilder.build();
+ }
+
+ public static FlowConfig toFlowConfig(final Flow sourceCfg) {
+ try {
+ final FlowConfig flowConfig = new FlowConfig();
+ flowConfig.setName(String.valueOf(sourceCfg.getId()));
+ flowConfig.setNode(NodeMapping.toADNode(sourceCfg.getNode()));
+ return flowConfig;
+ } catch (Exception e) {
+ String errMsg = MessageFormat.format("Convert from Flow {} to FlowConfig fail", sourceCfg);
+ LOG.error(errMsg, e);
+ throw new RuntimeException(errMsg, e);
+ }
+ }
+
+ public static FlowConfig toFlowConfig(final InstanceIdentifier<? extends Object> identifier) {
+ try {
+ PathArgument pathArg = FlowConfigMapping.getSecondPathArgumentFromPath(identifier);
+ if (pathArg != null) {
+ final FlowConfig flowConfig = new FlowConfig();
+ FlowKey key = ((IdentifiableItem<Flow, FlowKey>) pathArg).getKey();
+ flowConfig.setName(String.valueOf(key.getId()));
+ flowConfig.setNode(NodeMapping.toADNode(key.getNode()));
+ return flowConfig;
+ }
+ return null;
+ } catch (Exception e) {
+ String errMsg = MessageFormat.format("Convert from InstanceIdentifier {} to FlowConfig fail", identifier);
+ LOG.error(errMsg, e);
+ throw new RuntimeException(errMsg, e);
+ }
+ }
+
+ public static boolean isFlowPath(final InstanceIdentifier<? extends Object> path) {
+ PathArgument pathArg = FlowConfigMapping.getSecondPathArgumentFromPath(path);
+ if (pathArg == null) {
+ return false;
+ }
+ if (pathArg instanceof IdentifiableItem<?,?>) {
+ final Identifiable<?> key = ((IdentifiableItem<?, ? extends Identifiable<?>>) pathArg).getKey();
+ if ((key instanceof FlowKey)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static PathArgument getSecondPathArgumentFromPath(final InstanceIdentifier<? extends Object> path) {
+ if (path != null && path.getPathArguments() != null) {
+ Iterator<PathArgument> iterator = path.getPathArguments().iterator();
+ int deep = 0;
+ while (iterator.hasNext()) {
+ PathArgument pathArg = iterator.next();
+ if (deep == FlowConfigMapping.FLOW_KEY_IDENTIFIER_DEEP) {
+ return pathArg;
+ }
+ deep++;
+ }
+ }
+ return null;
+ }
+}
+++ /dev/null
-/*
- * Copyright (c) 2014 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.md.frm.compatibility
-
-import org.opendaylight.controller.forwardingrulesmanager.FlowConfig
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowBuilder
-
-import static extension org.opendaylight.controller.sal.compatibility.NodeMapping.*
-import static org.opendaylight.controller.sal.compatibility.MDFlowMapping.*
-import static org.opendaylight.controller.sal.compatibility.ToSalConversionsUtils.*
-
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowKey
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem
-import org.opendaylight.yangtools.yang.binding.Identifiable
-
-class FlowConfigMapping {
-
- static def toConfigurationFlow(FlowConfig sourceCfg) {
- val source = flowAdded(sourceCfg.flow);
- val it = new FlowBuilder();
- instructions = source.instructions;
- cookie = source.cookie;
- hardTimeout = source.hardTimeout
- idleTimeout = source.idleTimeout
- match = source.match
- node = source.node
- key = new FlowKey(Long.parseLong(sourceCfg.name),node);
- return it.build();
- }
-
- static def toFlowConfig(Flow sourceCfg) {
- val it = new FlowConfig;
- name = String.valueOf(sourceCfg.id);
- node = sourceCfg.node.toADNode();
-
- return it
- }
-
- static def toFlowConfig(InstanceIdentifier<?> identifier) {
- val it = new FlowConfig()
- val FlowKey key = ((identifier.path.get(2) as IdentifiableItem<Flow,FlowKey>).key)
- name = String.valueOf(key.id);
- node = key.node.toADNode();
-
- return it;
- }
-
- static def boolean isFlowPath(InstanceIdentifier<?> path) {
- if(path.path.size < 2) return false;
- if (path.path.get(2) instanceof IdentifiableItem<?,?>) {
- val IdentifiableItem<?,? extends Identifiable<?>> item = path.path.get(2) as IdentifiableItem<?,? extends Identifiable<?>>;
- val Identifiable<?> key = item.key;
- if (key instanceof FlowKey) {
- return true;
- }
- }
- return false;
- }
-}
-/*
+/**
* Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
--- /dev/null
+/*
+ * Copyright (c) 2014 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.sal.compatibility.topology;
+
+import static org.opendaylight.controller.sal.compatibility.topology.TopologyMapping.toAdEdge;
+import static org.opendaylight.controller.sal.compatibility.topology.TopologyMapping.toTopoEdgeUpdate;
+
+import java.util.Map.Entry;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.opendaylight.controller.md.sal.binding.util.TypeSafeDataReader;
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.controller.sal.core.UpdateType;
+import org.opendaylight.controller.sal.topology.IPluginOutTopologyService;
+import org.opendaylight.controller.sal.topology.TopoEdgeUpdate;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TopologyCommitHandler implements DataChangeListener {
+ private static final Logger LOG = LoggerFactory.getLogger(TopologyCommitHandler.class);
+
+ private IPluginOutTopologyService topologyPublisher;
+
+ private final DataProviderService dataService;
+
+ public TopologyCommitHandler(final DataProviderService dataService, final IPluginOutTopologyService topologyPub) {
+ this.topologyPublisher = topologyPub;
+ this.dataService = dataService;
+ }
+
+ @Override
+ public void onDataChanged(final DataChangeEvent<InstanceIdentifier<?>, DataObject> modification) {
+ CopyOnWriteArrayList<TopoEdgeUpdate> msg = new CopyOnWriteArrayList<TopoEdgeUpdate>();
+ try {
+ TypeSafeDataReader reader = TypeSafeDataReader.forReader(dataService);
+ InstanceIdentifier<Topology> topologyPath = InstanceIdentifier.builder(NetworkTopology.class)
+ .child(Topology.class, new TopologyKey(new TopologyId("flow:1"))).build();
+ Topology topology = reader.readOperationalData(topologyPath);
+
+ for (Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry : modification
+ .getCreatedOperationalData().entrySet()) {
+ if (entry.getValue() instanceof Link
+ && modification.getCreatedOperationalData().containsKey(entry.getKey())) {
+ msg.add(toTopoEdgeUpdate(toAdEdge((Link) entry.getValue(), topology), UpdateType.ADDED, reader));
+ }
+ }
+
+ for (Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry : modification
+ .getUpdatedOperationalData().entrySet()) {
+ if (entry.getValue() instanceof Link) {
+ msg.add(toTopoEdgeUpdate(toAdEdge((Link) entry.getValue(), topology), UpdateType.CHANGED, reader));
+ }
+ }
+ for (InstanceIdentifier<? extends DataObject> path : modification.getRemovedOperationalData()) {
+ if (path.getTargetType() == Link.class) {
+ Link link = (Link) modification.getOriginalOperationalData().get(path);
+ msg.add(toTopoEdgeUpdate(toAdEdge(link, topology), UpdateType.CHANGED, reader));
+ }
+
+ }
+
+ if (topologyPublisher != null && msg != null && !msg.isEmpty()) {
+ topologyPublisher.edgeUpdate(msg);
+ }
+
+ } catch (Exception e) {
+ LOG.error("Exception caught", e);
+ }
+ }
+
+ protected IPluginOutTopologyService getTopologyPublisher() {
+ return topologyPublisher;
+ }
+
+ protected void setTopologyPublisher(final IPluginOutTopologyService topologyPublisher) {
+ this.topologyPublisher = topologyPublisher;
+ }
+
+}
+++ /dev/null
-/*
- * Copyright (c) 2014 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.sal.compatibility.topology
-
-import com.google.common.collect.FluentIterable
-import java.util.concurrent.CopyOnWriteArrayList
-import org.opendaylight.controller.md.sal.binding.util.TypeSafeDataReader
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler
-import org.opendaylight.controller.md.sal.common.api.data.DataModification
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService
-import org.opendaylight.controller.sal.core.UpdateType
-import org.opendaylight.controller.sal.topology.IPluginOutTopologyService
-import org.opendaylight.controller.sal.topology.TopoEdgeUpdate
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import static extension org.opendaylight.controller.sal.compatibility.topology.TopologyMapping.*
-import org.slf4j.LoggerFactory
-
-class TopologyCommitHandler implements DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject> {
- static val LOG = LoggerFactory.getLogger(TopologyCommitHandler);
- @Property
- IPluginOutTopologyService topologyPublisher;
-
- @Property
- DataProviderService dataService;
-
- new(DataProviderService dataService) {
- _topologyPublisher = topologyPublisher
- _dataService = dataService
- }
-
- override requestCommit(DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification) {
- val msg = new CopyOnWriteArrayList<TopoEdgeUpdate>()
- try {
- val reader = TypeSafeDataReader.forReader(dataService)
- val topologyPath = InstanceIdentifier.builder(NetworkTopology).child(Topology, new TopologyKey(new TopologyId("flow:1"))).toInstance
- val topology = reader.readOperationalData(topologyPath)
- val adds = FluentIterable.from(modification.createdOperationalData.entrySet)
- .filter[value instanceof Link]
- .transform[(value as Link).toAdEdge(topology).toTopoEdgeUpdate(UpdateType.ADDED,reader)]
- .toList
- val updates = FluentIterable.from(modification.updatedOperationalData.entrySet)
- .filter[!modification.createdOperationalData.containsKey(key) && (value instanceof Link)]
- .transform[(value as Link).toAdEdge(topology).toTopoEdgeUpdate(UpdateType.ADDED,reader)] // Evidently the ADSAL does not expect edge 'CHANGED"
- .toList
- val removes = FluentIterable.from(modification.removedOperationalData)
- .transform[reader.readOperationalData(it as InstanceIdentifier<DataObject>)]
- .filter[it instanceof Link]
- .transform[(it as Link).toAdEdge(topology).toTopoEdgeUpdate(UpdateType.REMOVED,reader)]
- .toList
- msg.addAll(adds)
- msg.addAll(updates)
- msg.addAll(removes)
- } catch (Exception e) {
- LOG.error("Exception caught",e)
- }
- return new TopologyTransaction(modification,topologyPublisher,dataService,msg)
- }
-}
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey
import org.opendaylight.yangtools.yang.binding.DataObject
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.opendaylight.yangtools.concepts.Registration
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link
import org.slf4j.LoggerFactory
+import org.opendaylight.yangtools.concepts.ListenerRegistration
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener
class TopologyProvider implements AutoCloseable{
static val LOG = LoggerFactory.getLogger(TopologyProvider);
@Property
DataProviderService dataService;
- Registration<DataCommitHandler<InstanceIdentifier<? extends DataObject>,DataObject>> commitHandlerRegistration;
-
+ ListenerRegistration<DataChangeListener> listenerRegistration
+
+
def void start() {
}
LOG.error("dataService not set");
return;
}
- commitHandler = new TopologyCommitHandler(dataService)
- commitHandler.setTopologyPublisher(topologyPublisher)
+ commitHandler = new TopologyCommitHandler(dataService,topologyPublisher);
val InstanceIdentifier<? extends DataObject> path = InstanceIdentifier.builder(NetworkTopology)
.child(Topology,new TopologyKey(new TopologyId("flow:1")))
.child(Link)
.toInstance();
- commitHandlerRegistration = dataService.registerCommitHandler(path,commitHandler);
+ listenerRegistration = dataService.registerDataChangeListener(path,commitHandler);
LOG.info("TopologyProvider started")
}
override close() throws Exception {
- commitHandlerRegistration.close
+ listenerRegistration.close
}
def setTopologyPublisher(IPluginOutTopologyService topologyPublisher) {
+++ /dev/null
-/*
- * Copyright (c) 2014 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.sal.compatibility.topology
-
-import java.util.Collections
-import java.util.List
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction
-import org.opendaylight.controller.md.sal.common.api.data.DataModification
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService
-import org.opendaylight.controller.sal.topology.IPluginOutTopologyService
-import org.opendaylight.controller.sal.topology.TopoEdgeUpdate
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.opendaylight.yangtools.yang.common.RpcResult
-import org.slf4j.LoggerFactory
-
-class TopologyTransaction implements DataCommitTransaction<InstanceIdentifier<?extends DataObject>, DataObject> {
- static val LOG = LoggerFactory.getLogger(TopologyTransaction);
- @Property
- val DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification;
-
- @Property
- IPluginOutTopologyService topologyPublisher;
-
- @Property
- DataProviderService dataService;
- @Property
- List<TopoEdgeUpdate> edgeUpdates;
-
- new(DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification,IPluginOutTopologyService topologyPublisher,
- DataProviderService dataService,List<TopoEdgeUpdate> edgeUpdates) {
- _modification = modification;
- _topologyPublisher = topologyPublisher
- _dataService = dataService
- _edgeUpdates = edgeUpdates
- }
- override finish() throws IllegalStateException {
-
- if(topologyPublisher != null && _edgeUpdates != null && !edgeUpdates.empty) {
- topologyPublisher.edgeUpdate(edgeUpdates)
- }
-
- return new RpcResultTo()
- }
-
- override getModification() {
- return _modification;
- }
-
- override rollback() throws IllegalStateException {
- // NOOP
- }
-}
-class RpcResultTo implements RpcResult<Void> {
-
- override getErrors() {
- return Collections.emptySet
- }
-
- override getResult() {
- return null;
- }
-
- override isSuccessful() {
- return true;
- }
-
-}
</instructions>
</configuration>
</plugin>
- <plugin>
- <groupId>org.eclipse.xtend</groupId>
- <artifactId>xtend-maven-plugin</artifactId>
- </plugin>
</plugins>
</build>
--- /dev/null
+/**
+ * Copyright (c) 2014 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.frm;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ *
+ * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ */
+public abstract class AbstractChangeListener implements DataChangeListener {
+
+ private final AtomicLong txNum = new AtomicLong();
+ private String transactionId;
+
+ @Override
+ public void onDataChanged(DataChangeEvent<InstanceIdentifier<?>, DataObject> changeEvent) {
+ this.transactionId = this.newTransactionIdentifier().toString();
+
+ final Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> createdEntries =
+ changeEvent.getCreatedConfigurationData().entrySet();
+ final Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> updatedEntries =
+ new HashSet<Entry<InstanceIdentifier<? extends DataObject>, DataObject>>();
+
+ Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> updateConfigEntrySet =
+ changeEvent.getUpdatedConfigurationData().entrySet();
+ updatedEntries.addAll(updateConfigEntrySet);
+ updatedEntries.removeAll(createdEntries);
+
+ final Set<InstanceIdentifier<? extends DataObject>> removeEntriesInstanceIdentifiers =
+ changeEvent.getRemovedConfigurationData();
+
+ for (final Entry<InstanceIdentifier<? extends DataObject>, DataObject> createdEntry : createdEntries) {
+ InstanceIdentifier<? extends DataObject> c_key = createdEntry.getKey();
+ DataObject c_value = createdEntry.getValue();
+ this.add(c_key, c_value);
+ }
+
+ for (final Entry<InstanceIdentifier<?>, DataObject> updatedEntrie : updatedEntries) {
+ Map<InstanceIdentifier<? extends DataObject>, DataObject> origConfigData =
+ changeEvent.getOriginalConfigurationData();
+
+ InstanceIdentifier<? extends Object> u_key = updatedEntrie.getKey();
+ final DataObject originalFlow = origConfigData.get(u_key);
+ final DataObject updatedFlow = updatedEntrie.getValue();
+ this.update(u_key, originalFlow, updatedFlow);
+ }
+
+ for (final InstanceIdentifier<?> instanceId : removeEntriesInstanceIdentifiers) {
+ Map<InstanceIdentifier<? extends DataObject>, DataObject> origConfigData =
+ changeEvent.getOriginalConfigurationData();
+
+ final DataObject removeValue = origConfigData.get(instanceId);
+ this.remove(instanceId, removeValue);
+ }
+ }
+
+ public String getTransactionId() {
+ return this.transactionId;
+ }
+
+ private Object newTransactionIdentifier() {
+ return "DOM-" + txNum.getAndIncrement();
+ }
+
+ protected abstract void validate() throws IllegalStateException;
+
+ protected abstract void remove(
+ final InstanceIdentifier<? extends DataObject> identifier,
+ final DataObject remove);
+
+ protected abstract void update(
+ final InstanceIdentifier<? extends DataObject> identifier,
+ final DataObject original, final DataObject update);
+
+ protected abstract void add(
+ final InstanceIdentifier<? extends DataObject> identifier,
+ final DataObject add);
+}
+++ /dev/null
-/*
- * Copyright (c) 2014 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.frm
-
-import java.util.Collections
-import java.util.HashSet
-import java.util.Map.Entry
-import java.util.Set
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction
-import org.opendaylight.controller.md.sal.common.api.data.DataModification
-import org.opendaylight.controller.sal.common.util.Rpcs
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.opendaylight.yangtools.yang.common.RpcError
-
-abstract class AbstractTransaction implements DataCommitTransaction<InstanceIdentifier<?extends DataObject>, DataObject> {
-
- @Property
- val DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification;
-
- new(DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification) {
- _modification = modification;
- }
-
- def void validate() throws IllegalStateException
-
- override finish() throws IllegalStateException {
- validate()
- callRpcs();
- return Rpcs.getRpcResult(true, null, Collections.<RpcError>emptySet());
- }
-
- override getModification() {
- return _modification;
- }
-
- override rollback() throws IllegalStateException {
- rollbackRpcs();
- return Rpcs.getRpcResult(true, null, Collections.<RpcError>emptySet());
- }
-
- def private callRpcs() {
- val Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> createdEntries = _modification.getCreatedConfigurationData().entrySet();
-
- /*
- * This little dance is because updatedEntries contains both created and modified entries
- * The reason I created a new HashSet is because the collections we are returned are immutable.
- */
- val Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> updatedEntries = new HashSet<Entry<InstanceIdentifier<? extends DataObject>, DataObject>>();
- updatedEntries.addAll(_modification.getUpdatedConfigurationData().entrySet());
- updatedEntries.removeAll(createdEntries);
-
- val Set<InstanceIdentifier<? extends DataObject>> removeEntriesInstanceIdentifiers = _modification.getRemovedConfigurationData();
- for (Entry<InstanceIdentifier<? extends DataObject >, DataObject> entry : createdEntries) {
- add(entry.key,entry.value);
- }
- for (Entry<InstanceIdentifier<?>, DataObject> entry : updatedEntries) {
- val originalFlow = _modification.originalConfigurationData.get(entry.key);
- val updatedFlow = entry.value
- update(entry.key, originalFlow ,updatedFlow);
- }
-
- for (InstanceIdentifier<?> instanceId : removeEntriesInstanceIdentifiers ) {
- val removeValue = _modification.getOriginalConfigurationData.get(instanceId);
- remove(instanceId,removeValue);
- }
- }
-
- def void remove(InstanceIdentifier<?> identifier, DataObject remove)
-
- def void update(InstanceIdentifier<?> identifier, DataObject original, DataObject update)
-
- def void add(InstanceIdentifier<?> identifier, DataObject add)
-
- def private rollbackRpcs() {
- val Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> createdEntries = _modification.getCreatedConfigurationData().entrySet();
-
- /*
- * This little dance is because updatedEntries contains both created and modified entries
- * The reason I created a new HashSet is because the collections we are returned are immutable.
- */
- val Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> updatedEntries = new HashSet<Entry<InstanceIdentifier<? extends DataObject>, DataObject>>();
- updatedEntries.addAll(_modification.getUpdatedConfigurationData().entrySet());
- updatedEntries.removeAll(createdEntries);
-
- val Set<InstanceIdentifier<? >> removeEntriesInstanceIdentifiers = _modification.getRemovedConfigurationData();
- for (Entry<InstanceIdentifier<?>, DataObject> entry : createdEntries) {
- remove(entry.key,entry.value); // because we are rolling back, remove what we would have added.
- }
- for (Entry<InstanceIdentifier<?>, DataObject> entry : updatedEntries) {
- val originalFlow = _modification.originalConfigurationData.get(entry.key);
- val updatedFlow = entry.value
- update(entry.key, updatedFlow ,originalFlow);// because we are rolling back, replace the updated with the original
- }
-
- for (InstanceIdentifier<?> instanceId : removeEntriesInstanceIdentifiers ) {
- val removeValue = _modification.getOriginalConfigurationData.get(instanceId);
- add(instanceId,removeValue);// because we are rolling back, add what we would have removed.
- }
- }
-}
--- /dev/null
+/**
+ * Copyright (c) 2014 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.frm;
+
+import org.opendaylight.controller.frm.flow.FlowProvider;
+import org.opendaylight.controller.frm.group.GroupProvider;
+import org.opendaylight.controller.frm.meter.MeterProvider;
+import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareProvider;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FRMActivator extends AbstractBindingAwareProvider {
+
+ private final static Logger LOG = LoggerFactory.getLogger(FRMActivator.class);
+
+ private static FlowProvider flowProvider = new FlowProvider();
+ private static GroupProvider groupProvider = new GroupProvider();
+ private static MeterProvider meterProvider = new MeterProvider();
+
+ @Override
+ public void onSessionInitiated(final ProviderContext session) {
+ DataProviderService flowSalService = session.<DataProviderService>getSALService(DataProviderService.class);
+ FRMActivator.flowProvider.setDataService(flowSalService);
+ SalFlowService rpcFlowSalService = session.<SalFlowService>getRpcService(SalFlowService.class);
+ FRMActivator.flowProvider.setSalFlowService(rpcFlowSalService);
+ FRMActivator.flowProvider.start();
+ DataProviderService groupSalService = session.<DataProviderService>getSALService(DataProviderService.class);
+ FRMActivator.groupProvider.setDataService(groupSalService);
+ SalGroupService rpcGroupSalService = session.<SalGroupService>getRpcService(SalGroupService.class);
+ FRMActivator.groupProvider.setSalGroupService(rpcGroupSalService);
+ FRMActivator.groupProvider.start();
+ DataProviderService meterSalService = session.<DataProviderService>getSALService(DataProviderService.class);
+ FRMActivator.meterProvider.setDataService(meterSalService);
+ SalMeterService rpcMeterSalService = session.<SalMeterService>getRpcService(SalMeterService.class);
+ FRMActivator.meterProvider.setSalMeterService(rpcMeterSalService);
+ FRMActivator.meterProvider.start();
+ }
+
+ @Override
+ protected void stopImpl(final BundleContext context) {
+ try {
+ FRMActivator.flowProvider.close();
+ FRMActivator.groupProvider.close();
+ FRMActivator.meterProvider.close();
+ } catch (Throwable e) {
+ LOG.error("Unexpected error by stopping FRMActivator", e);
+ throw new RuntimeException(e);
+ }
+ }
+ }
\ No newline at end of file
+++ /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.frm
-
-import org.opendaylight.controller.frm.flow.FlowProvider
-import org.opendaylight.controller.frm.group.GroupProvider
-import org.opendaylight.controller.frm.meter.MeterProvider
-import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareProvider
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupService
-import org.osgi.framework.BundleContext
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService
-
-class FRMActivator extends AbstractBindingAwareProvider {
-
- static var FlowProvider provider = new FlowProvider();
- static var GroupProvider groupProvider = new GroupProvider();
- static var MeterProvider meterProvider = new MeterProvider();
-
- override onSessionInitiated(ProviderContext session) {
- provider.dataService = session.getSALService(DataProviderService)
- provider.salFlowService = session.getRpcService(SalFlowService);
- provider.start();
-
- groupProvider.dataService = session.getSALService(DataProviderService)
- groupProvider.salGroupService = session.getRpcService(SalGroupService)
- groupProvider.start();
-
- meterProvider.dataService = session.getSALService(DataProviderService)
- meterProvider.salMeterService = session.getRpcService(SalMeterService)
- meterProvider.start();
- }
-
- override protected stopImpl(BundleContext context) {
- provider.close();
- groupProvider.close();
- meterProvider.close();
- }
-
-}
--- /dev/null
+/**
+ * Copyright (c) 2014 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.frm.flow;
+
+import org.opendaylight.controller.frm.AbstractChangeListener;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
+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.FlowTableRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInputBuilder;
+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.UpdateFlowInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.OriginalFlow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.OriginalFlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.UpdatedFlow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.UpdatedFlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ */
+public class FlowChangeListener extends AbstractChangeListener {
+
+ private final static Logger LOG = LoggerFactory.getLogger(FlowChangeListener.class);
+
+ private final SalFlowService salFlowService;
+
+ public SalFlowService getSalFlowService() {
+ return this.salFlowService;
+ }
+
+ public FlowChangeListener(final SalFlowService manager) {
+ this.salFlowService = manager;
+ }
+
+ @Override
+ protected void validate() throws IllegalStateException {
+ FlowTransactionValidator.validate(this);
+ }
+
+ @Override
+ protected void remove(InstanceIdentifier<? extends DataObject> identifier, DataObject removeDataObj) {
+ if ((removeDataObj instanceof Flow)) {
+
+ final Flow flow = ((Flow) removeDataObj);
+ final InstanceIdentifier<Table> tableInstanceId = identifier.<Table> firstIdentifierOf(Table.class);
+ final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> firstIdentifierOf(Node.class);
+ final RemoveFlowInputBuilder builder = new RemoveFlowInputBuilder(flow);
+
+ builder.setFlowRef(new FlowRef(identifier));
+ builder.setNode(new NodeRef(nodeInstanceId));
+ builder.setFlowTable(new FlowTableRef(tableInstanceId));
+
+ Uri uri = new Uri(this.getTransactionId());
+ builder.setTransactionUri(uri);
+ this.salFlowService.removeFlow((RemoveFlowInput) builder.build());
+ LOG.debug("Transaction {} - Removed Flow has removed flow: {}", new Object[]{uri, removeDataObj});
+ }
+ }
+
+ @Override
+ protected void update(InstanceIdentifier<? extends DataObject> identifier, DataObject original, DataObject update) {
+ if (original instanceof Flow && update instanceof Flow) {
+
+ final Flow originalFlow = ((Flow) original);
+ final Flow updatedFlow = ((Flow) update);
+ final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node>firstIdentifierOf(Node.class);
+ final UpdateFlowInputBuilder builder = new UpdateFlowInputBuilder();
+
+ builder.setNode(new NodeRef(nodeInstanceId));
+ builder.setFlowRef(new FlowRef(identifier));
+
+ Uri uri = new Uri(this.getTransactionId());
+ builder.setTransactionUri(uri);
+
+ builder.setUpdatedFlow((UpdatedFlow) (new UpdatedFlowBuilder(updatedFlow)).build());
+ builder.setOriginalFlow((OriginalFlow) (new OriginalFlowBuilder(originalFlow)).build());
+
+ this.salFlowService.updateFlow((UpdateFlowInput) builder.build());
+ LOG.debug("Transaction {} - Update Flow has updated flow {} with {}", new Object[]{uri, original, update});
+ }
+ }
+
+ @Override
+ protected void add(InstanceIdentifier<? extends DataObject> identifier, DataObject addDataObj) {
+ if ((addDataObj instanceof Flow)) {
+
+ final Flow flow = ((Flow) addDataObj);
+ final InstanceIdentifier<Table> tableInstanceId = identifier.<Table> firstIdentifierOf(Table.class);
+ final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> firstIdentifierOf(Node.class);
+ final AddFlowInputBuilder builder = new AddFlowInputBuilder(flow);
+
+ builder.setNode(new NodeRef(nodeInstanceId));
+ builder.setFlowRef(new FlowRef(identifier));
+ builder.setFlowTable(new FlowTableRef(tableInstanceId));
+
+ Uri uri = new Uri(this.getTransactionId());
+ builder.setTransactionUri(uri);
+ this.salFlowService.addFlow((AddFlowInput) builder.build());
+ LOG.debug("Transaction {} - Add Flow has added flow: {}", new Object[]{uri, addDataObj});
+ }
+ }
+}
+++ /dev/null
-/*
- * Copyright (c) 2014 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.frm.flow
-
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler
-import org.opendaylight.controller.md.sal.common.api.data.DataModification
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService
-
-class FlowCommitHandler implements DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject> {
-
- @Property
- val SalFlowService salFlowService;
-
- new(SalFlowService manager) {
- _salFlowService = manager;
- }
-
- override requestCommit(DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification) {
- return new FlowTransaction(modification,salFlowService);
- }
-
-}
--- /dev/null
+/**
+ * Copyright (c) 2014 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.frm.flow;
+
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+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.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FlowProvider implements AutoCloseable {
+
+ private final static Logger LOG = LoggerFactory.getLogger(FlowProvider.class);
+
+ private SalFlowService salFlowService;
+ private DataProviderService dataService;
+
+ /* DataChangeListener */
+ private FlowChangeListener flowDataChangeListener;
+ ListenerRegistration<DataChangeListener> flowDataChangeListenerRegistration;
+
+ public void start() {
+ /* Build Path */
+ InstanceIdentifierBuilder<Nodes> nodesBuilder = InstanceIdentifier.<Nodes> builder(Nodes.class);
+ InstanceIdentifierBuilder<Node> nodeChild = nodesBuilder.<Node> child(Node.class);
+ InstanceIdentifierBuilder<FlowCapableNode> augmentFlowCapNode = nodeChild.<FlowCapableNode> augmentation(FlowCapableNode.class);
+ InstanceIdentifierBuilder<Table> tableChild = augmentFlowCapNode.<Table> child(Table.class);
+ InstanceIdentifierBuilder<Flow> flowChild = tableChild.<Flow> child(Flow.class);
+ final InstanceIdentifier<? extends DataObject> flowDataObjectPath = flowChild.toInstance();
+
+ /* DataChangeListener registration */
+ this.flowDataChangeListener = new FlowChangeListener(this.salFlowService);
+ this.flowDataChangeListenerRegistration = this.dataService.registerDataChangeListener(flowDataObjectPath, flowDataChangeListener);
+ LOG.info("Flow Config Provider started.");
+ }
+
+ protected DataModificationTransaction startChange() {
+ return this.dataService.beginTransaction();
+ }
+
+ @Override
+ public void close() throws Exception {
+ if(flowDataChangeListenerRegistration != null){
+ flowDataChangeListenerRegistration.close();
+ }
+ }
+
+ public void setDataService(final DataProviderService dataService) {
+ this.dataService = dataService;
+ }
+
+ public void setSalFlowService(final SalFlowService salFlowService) {
+ this.salFlowService = salFlowService;
+ }
+}
+++ /dev/null
-/*
- * Copyright (c) 2014 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.frm.flow
-
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode
-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.table.Flow
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node
-import org.opendaylight.yangtools.concepts.Registration
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.slf4j.LoggerFactory
-
-class FlowProvider implements AutoCloseable {
-
- @Property
- DataProviderService dataService;
-
- @Property
- SalFlowService salFlowService;
-
- FlowCommitHandler commitHandler
-
- Registration<DataCommitHandler<InstanceIdentifier<? extends DataObject>,DataObject>> commitHandlerRegistration;
-
- static val LOG = LoggerFactory.getLogger(FlowProvider);
-
- def void start() {
- commitHandler = new FlowCommitHandler(salFlowService)
- val InstanceIdentifier<? extends DataObject> path = InstanceIdentifier.builder(Nodes)
- .child(Node)
- .augmentation(FlowCapableNode)
- .child(Table)
- .child(Flow)
- .toInstance();
- commitHandlerRegistration = dataService.registerCommitHandler(path,commitHandler);
- LOG.info("Flow Config Provider started.");
- }
-
- protected def startChange() {
- return dataService.beginTransaction;
- }
-
- override close() throws Exception {
- throw new UnsupportedOperationException("TODO: auto-generated method stub")
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2014 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.frm.flow
-
-import org.opendaylight.controller.frm.AbstractTransaction
-import org.opendaylight.controller.md.sal.common.api.data.DataModification
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInputBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowTableRef
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInputBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInputBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.OriginalFlowBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.UpdatedFlowBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.Flow
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowRef
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri
-
-class FlowTransaction extends AbstractTransaction {
-
- @Property
- val SalFlowService salFlowService;
-
-
- new(DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification,SalFlowService salFlowService) {
- super(modification)
- _salFlowService = salFlowService;
- }
-
- override remove(InstanceIdentifier<?> instanceId, DataObject obj) {
- if(obj instanceof Flow) {
- val flow = (obj as Flow)
- val tableInstanceId = instanceId.firstIdentifierOf(Table);
- val nodeInstanceId = instanceId.firstIdentifierOf(Node);
- val builder = new RemoveFlowInputBuilder(flow);
- builder.setFlowRef(new FlowRef(instanceId));
- builder.setNode(new NodeRef(nodeInstanceId));
- builder.setFlowTable(new FlowTableRef(tableInstanceId));
- builder.setTransactionUri(new Uri(modification.getIdentifier() as String));
- _salFlowService.removeFlow(builder.build());
- }
- }
-
- override update(InstanceIdentifier<?> instanceId, DataObject originalObj, DataObject updatedObj) {
- if(originalObj instanceof Flow && updatedObj instanceof Flow) {
- val originalFlow = (originalObj as Flow)
- val updatedFlow = (updatedObj as Flow)
- val nodeInstanceId = instanceId.firstIdentifierOf(Node);
- val builder = new UpdateFlowInputBuilder();
- builder.setNode(new NodeRef(nodeInstanceId));
- builder.setFlowRef(new FlowRef(instanceId));
- val ufb = new UpdatedFlowBuilder(updatedFlow);
- builder.setUpdatedFlow((ufb.build()));
- builder.setTransactionUri(new Uri(modification.getIdentifier() as String));
- val ofb = new OriginalFlowBuilder(originalFlow);
- builder.setOriginalFlow(ofb.build());
- _salFlowService.updateFlow(builder.build());
-
- }
- }
-
- override add(InstanceIdentifier<?> instanceId, DataObject obj) {
- if(obj instanceof Flow) {
- val flow = (obj as Flow)
- val tableInstanceId = instanceId.firstIdentifierOf(Table);
- val nodeInstanceId = instanceId.firstIdentifierOf(Node);
- val builder = new AddFlowInputBuilder(flow);
- builder.setNode(new NodeRef(nodeInstanceId));
- builder.setTransactionUri(new Uri(modification.getIdentifier() as String));
- builder.setFlowRef(new FlowRef(instanceId));
- builder.setFlowTable(new FlowTableRef(tableInstanceId));
- _salFlowService.addFlow(builder.build());
- }
- }
-
- override validate() throws IllegalStateException {
- FlowTransactionValidator.validate(this)
- }
-}
-/*
+/**
* Copyright (c) 2014 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
public class FlowTransactionValidator {
- public static void validate(FlowTransaction transaction) throws IllegalStateException {
+ public static void validate(FlowChangeListener transaction) throws IllegalStateException {
// NOOP
}
-
}
--- /dev/null
+/**
+ * Copyright (c) 2014 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.frm.group;
+
+import org.opendaylight.controller.frm.AbstractChangeListener;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.AddGroupInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.AddGroupInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.RemoveGroupInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.RemoveGroupInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.UpdateGroupInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.UpdateGroupInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.OriginalGroup;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.OriginalGroupBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.UpdatedGroup;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.UpdatedGroupBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ */
+public class GroupChangeListener extends AbstractChangeListener {
+
+ private final static Logger LOG = LoggerFactory.getLogger(GroupChangeListener.class);
+
+ private final SalGroupService salGroupService;
+
+ public SalGroupService getSalGroupService() {
+ return this.salGroupService;
+ }
+
+ public GroupChangeListener(final SalGroupService manager) {
+ this.salGroupService = manager;
+ }
+
+ @Override
+ protected void validate() throws IllegalStateException {
+ GroupTransactionValidator.validate(this);
+ }
+
+ @Override
+ protected void remove(InstanceIdentifier<? extends DataObject> identifier, DataObject removeDataObj) {
+ if ((removeDataObj instanceof Group)) {
+
+ final Group group = ((Group) removeDataObj);
+ final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> firstIdentifierOf(Node.class);
+ final RemoveGroupInputBuilder builder = new RemoveGroupInputBuilder(group);
+
+ builder.setNode(new NodeRef(nodeInstanceId));
+ builder.setGroupRef(new GroupRef(identifier));
+
+ Uri uri = new Uri(this.getTransactionId());
+ builder.setTransactionUri(uri);
+ this.salGroupService.removeGroup((RemoveGroupInput) builder.build());
+ LOG.debug("Transaction {} - Remove Group has removed group: {}", new Object[]{uri, removeDataObj});
+ }
+ }
+
+ @Override
+ protected void update(InstanceIdentifier<? extends DataObject> identifier, DataObject original, DataObject update) {
+ if (original instanceof Group && update instanceof Group) {
+
+ final Group originalGroup = ((Group) original);
+ final Group updatedGroup = ((Group) update);
+ final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> firstIdentifierOf(Node.class);
+ final UpdateGroupInputBuilder builder = new UpdateGroupInputBuilder();
+
+ builder.setNode(new NodeRef(nodeInstanceId));
+ builder.setGroupRef(new GroupRef(identifier));
+
+ Uri uri = new Uri(this.getTransactionId());
+ builder.setTransactionUri(uri);
+
+ builder.setUpdatedGroup((UpdatedGroup) (new UpdatedGroupBuilder(updatedGroup)).build());
+ builder.setOriginalGroup((OriginalGroup) (new OriginalGroupBuilder(originalGroup)).build());
+
+ this.salGroupService.updateGroup((UpdateGroupInput) builder.build());
+ LOG.debug("Transaction {} - Update Group has updated group {} with group {}", new Object[]{uri, original, update});
+ }
+ }
+
+ @Override
+ protected void add(InstanceIdentifier<? extends DataObject> identifier, DataObject addDataObj) {
+ if ((addDataObj instanceof Group)) {
+ final Group group = ((Group) addDataObj);
+ final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> firstIdentifierOf(Node.class);
+ final AddGroupInputBuilder builder = new AddGroupInputBuilder(group);
+
+ builder.setNode(new NodeRef(nodeInstanceId));
+ builder.setGroupRef(new GroupRef(identifier));
+
+ Uri uri = new Uri(this.getTransactionId());
+ builder.setTransactionUri(uri);
+ this.salGroupService.addGroup((AddGroupInput) builder.build());
+ LOG.debug("Transaction {} - Add Group has added group: {}", new Object[]{uri, addDataObj});
+ }
+ }
+}
+++ /dev/null
-/*
- * Copyright (c) 2014 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.frm.group
-
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler
-import org.opendaylight.controller.md.sal.common.api.data.DataModification
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupService
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-
-class GroupCommitHandler implements DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject> {
-
- @Property
- val SalGroupService groupService;
-
- new(SalGroupService groupService) {
- _groupService = groupService;
- }
-
- override requestCommit(DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification) {
- return new GroupTransaction(modification,groupService);
- }
-
-}
--- /dev/null
+/**
+ * Copyright (c) 2014 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.frm.group;
+
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class GroupProvider implements AutoCloseable {
+
+ private final static Logger LOG = LoggerFactory.getLogger(GroupProvider.class);
+
+ private SalGroupService salGroupService;
+ private DataProviderService dataService;
+
+ /* DataChangeListener */
+ private GroupChangeListener groupDataChangeListener;
+ ListenerRegistration<DataChangeListener> groupDataChangeListenerRegistration;
+
+ public void start() {
+ /* Build Path */
+ InstanceIdentifierBuilder<Nodes> nodesBuilder = InstanceIdentifier.<Nodes> builder(Nodes.class);
+ InstanceIdentifierBuilder<Node> nodeChild = nodesBuilder.<Node> child(Node.class);
+ InstanceIdentifierBuilder<FlowCapableNode> augmentFlowCapNode = nodeChild.<FlowCapableNode> augmentation(FlowCapableNode.class);
+ InstanceIdentifierBuilder<Group> groupChild = augmentFlowCapNode.<Group> child(Group.class);
+ final InstanceIdentifier<? extends DataObject> groupDataObjectPath = groupChild.toInstance();
+
+ /* DataChangeListener registration */
+ this.groupDataChangeListener = new GroupChangeListener(this.salGroupService);
+ this.groupDataChangeListenerRegistration = this.dataService.registerDataChangeListener(groupDataObjectPath, groupDataChangeListener);
+ LOG.info("Group Config Provider started.");
+ }
+
+ protected DataModificationTransaction startChange() {
+ return this.dataService.beginTransaction();
+ }
+
+ public void close() throws Exception {
+ if(groupDataChangeListenerRegistration != null){
+ groupDataChangeListenerRegistration.close();
+ }
+ }
+
+ public void setDataService(final DataProviderService dataService) {
+ this.dataService = dataService;
+ }
+
+ public void setSalGroupService(final SalGroupService salGroupService) {
+ this.salGroupService = salGroupService;
+ }
+}
+++ /dev/null
-/*
- * Copyright (c) 2014 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.frm.group
-
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupService
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node
-import org.opendaylight.yangtools.concepts.Registration
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.slf4j.LoggerFactory
-
-class GroupProvider implements AutoCloseable {
-
- @Property
- DataProviderService dataService;
-
- @Property
- SalGroupService salGroupService;
-
- GroupCommitHandler commitHandler
-
- Registration<DataCommitHandler<InstanceIdentifier<? extends DataObject>,DataObject>> commitHandlerRegistration;
-
- static val LOG = LoggerFactory.getLogger(GroupProvider);
-
- def void start() {
- commitHandler = new GroupCommitHandler(salGroupService)
- val InstanceIdentifier<? extends DataObject> path = InstanceIdentifier.builder(Nodes)
- .child(Node)
- .augmentation(FlowCapableNode)
- .child(Group)
- .toInstance();
- commitHandlerRegistration = dataService.registerCommitHandler(path,commitHandler);
- LOG.info("Group Config Provider started.");
- }
-
- protected def startChange() {
- return dataService.beginTransaction;
- }
-
- override close() throws Exception {
- throw new UnsupportedOperationException("TODO: auto-generated method stub")
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2014 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.frm.group
-
-import org.opendaylight.controller.frm.AbstractTransaction
-import org.opendaylight.controller.md.sal.common.api.data.DataModification
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.AddGroupInputBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.RemoveGroupInputBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupService
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.UpdateGroupInputBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.OriginalGroupBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.UpdatedGroupBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupRef
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri
-
-class GroupTransaction extends AbstractTransaction {
-
- @Property
- val SalGroupService groupService;
-
- new(DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification,SalGroupService groupService) {
- super(modification)
- _groupService = groupService;
- }
-
- override remove(InstanceIdentifier<?> instanceId, DataObject obj) {
- if(obj instanceof Group) {
- val group = (obj as Group)
- val nodeInstanceId = instanceId.firstIdentifierOf(Node);
- val builder = new RemoveGroupInputBuilder(group);
- builder.setNode(new NodeRef(nodeInstanceId));
- builder.setTransactionUri(new Uri(modification.getIdentifier() as String));
- builder.setGroupRef(new GroupRef(instanceId));
- _groupService.removeGroup(builder.build());
- }
- }
-
- override update(InstanceIdentifier<?> instanceId, DataObject originalObj, DataObject updatedObj) {
- if(originalObj instanceof Group && updatedObj instanceof Group) {
- val originalGroup = (originalObj as Group)
- val updatedGroup = (updatedObj as Group)
- val nodeInstanceId = instanceId.firstIdentifierOf(Node);
- val builder = new UpdateGroupInputBuilder();
- builder.setNode(new NodeRef(nodeInstanceId));
- builder.setGroupRef(new GroupRef(instanceId));
- val ufb = new UpdatedGroupBuilder(updatedGroup);
- builder.setUpdatedGroup((ufb.build()));
- builder.setTransactionUri(new Uri(modification.getIdentifier() as String));
- val ofb = new OriginalGroupBuilder(originalGroup);
- builder.setOriginalGroup(ofb.build());
- _groupService.updateGroup(builder.build());
-
- }
- }
-
- override add(InstanceIdentifier<?> instanceId, DataObject obj) {
- if(obj instanceof Group) {
- val group = (obj as Group)
- val nodeInstanceId = instanceId.firstIdentifierOf(Node);
- val builder = new AddGroupInputBuilder(group);
- builder.setNode(new NodeRef(nodeInstanceId));
- builder.setGroupRef(new GroupRef(instanceId));
- builder.setTransactionUri(new Uri(modification.getIdentifier() as String));
- _groupService.addGroup(builder.build());
- }
- }
-
- override validate() throws IllegalStateException {
- GroupTransactionValidator.validate(this)
- }
-}
-/*
+/**
* Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
public class GroupTransactionValidator {
- public static void validate(GroupTransaction transaction) throws IllegalStateException {
+ public static void validate(GroupChangeListener transaction) throws IllegalStateException {
// NOOP
}
-
}
--- /dev/null
+/**
+ * Copyright (c) 2014 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.frm.meter;
+
+import org.opendaylight.controller.frm.AbstractChangeListener;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.AddMeterInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.AddMeterInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.RemoveMeterInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.RemoveMeterInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.UpdateMeterInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.UpdateMeterInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.meter.update.OriginalMeter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.meter.update.OriginalMeterBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.meter.update.UpdatedMeter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.meter.update.UpdatedMeterBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.Meter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterRef;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ */
+public class MeterChangeListener extends AbstractChangeListener {
+
+ private final static Logger LOG = LoggerFactory.getLogger(MeterChangeListener.class);
+
+ private final SalMeterService salMeterService;
+
+ public SalMeterService getSalMeterService() {
+ return this.salMeterService;
+ }
+
+ public MeterChangeListener(final SalMeterService manager) {
+ this.salMeterService = manager;
+ }
+
+ @Override
+ protected void validate() throws IllegalStateException {
+ MeterTransactionValidator.validate(this);
+ }
+
+ @Override
+ protected void remove(InstanceIdentifier<? extends DataObject> identifier, DataObject removeDataObj) {
+ if ((removeDataObj instanceof Meter)) {
+
+ final Meter meter = ((Meter) removeDataObj);
+ final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> firstIdentifierOf(Node.class);
+ final RemoveMeterInputBuilder builder = new RemoveMeterInputBuilder(meter);
+
+ builder.setNode(new NodeRef(nodeInstanceId));
+ builder.setMeterRef(new MeterRef(identifier));
+
+ Uri uri = new Uri(this.getTransactionId());
+ builder.setTransactionUri(uri);
+ this.salMeterService.removeMeter((RemoveMeterInput) builder.build());
+ LOG.debug("Transaction {} - Remove Meter has removed meter: {}", new Object[]{uri, removeDataObj});
+ }
+ }
+
+ @Override
+ protected void update(InstanceIdentifier<? extends DataObject> identifier, DataObject original, DataObject update) {
+ if (original instanceof Meter && update instanceof Meter) {
+
+ final Meter originalMeter = ((Meter) original);
+ final Meter updatedMeter = ((Meter) update);
+ final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> firstIdentifierOf(Node.class);
+ final UpdateMeterInputBuilder builder = new UpdateMeterInputBuilder();
+
+ builder.setNode(new NodeRef(nodeInstanceId));
+ builder.setMeterRef(new MeterRef(identifier));
+
+ Uri uri = new Uri(this.getTransactionId());
+ builder.setTransactionUri(uri);
+
+ builder.setUpdatedMeter((UpdatedMeter) (new UpdatedMeterBuilder(updatedMeter)).build());
+ builder.setOriginalMeter((OriginalMeter) (new OriginalMeterBuilder(originalMeter)).build());
+
+ this.salMeterService.updateMeter((UpdateMeterInput) builder.build());
+ LOG.debug("Transaction {} - Update Meter has updated meter {} with {}", new Object[]{uri, original, update});
+ }
+ }
+
+ @Override
+ protected void add(InstanceIdentifier<? extends DataObject> identifier, DataObject addDataObj) {
+ if ((addDataObj instanceof Meter)) {
+
+ final Meter meter = ((Meter) addDataObj);
+ final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> firstIdentifierOf(Node.class);
+ final AddMeterInputBuilder builder = new AddMeterInputBuilder(meter);
+
+ builder.setNode(new NodeRef(nodeInstanceId));
+ builder.setMeterRef(new MeterRef(identifier));
+
+ Uri uri = new Uri(this.getTransactionId());
+ builder.setTransactionUri(uri);
+ this.salMeterService.addMeter((AddMeterInput) builder.build());
+ LOG.debug("Transaction {} - Add Meter has added meter: {}", new Object[]{uri, addDataObj});
+ }
+ }
+}
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright (c) 2014 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.frm.meter
-
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler
-import org.opendaylight.controller.md.sal.common.api.data.DataModification
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-
-class FlowCommitHandler implements DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject> {
-
- @Property
- val SalMeterService salMeterService;
-
- new(SalMeterService manager) {
- _salMeterService = manager;
- }
-
- override requestCommit(DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification) {
- return new MeterTransaction(modification,salMeterService);
- }
-
-}
--- /dev/null
+/**
+ * Copyright (c) 2014 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.frm.meter;
+
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MeterProvider implements AutoCloseable {
+
+ private final static Logger LOG = LoggerFactory.getLogger(MeterProvider.class);
+
+ private DataProviderService dataService;
+ private SalMeterService salMeterService;
+
+ /* DataChangeListener */
+ private MeterChangeListener meterDataChangeListener;
+ ListenerRegistration<DataChangeListener> meterDataChangeListenerRegistration;
+
+ public void start() {
+ /* Build Path */
+ InstanceIdentifierBuilder<Nodes> nodesBuilder = InstanceIdentifier.<Nodes> builder(Nodes.class);
+ InstanceIdentifierBuilder<Node> nodeChild = nodesBuilder.<Node> child(Node.class);
+ InstanceIdentifierBuilder<FlowCapableNode> augmentFlowCapNode = nodeChild.<FlowCapableNode> augmentation(FlowCapableNode.class);
+ InstanceIdentifierBuilder<Meter> meterChild = augmentFlowCapNode.<Meter> child(Meter.class);
+ final InstanceIdentifier<? extends DataObject> meterDataObjectPath = meterChild.toInstance();
+
+ /* DataChangeListener registration */
+ this.meterDataChangeListener = new MeterChangeListener(this.salMeterService);
+ this.meterDataChangeListenerRegistration = this.dataService.registerDataChangeListener(meterDataObjectPath, meterDataChangeListener);
+ LOG.info("Meter Config Provider started.");
+ }
+
+ protected DataModificationTransaction startChange() {
+ return this.dataService.beginTransaction();
+ }
+
+ public void close() throws Exception {
+ if(meterDataChangeListenerRegistration != null){
+ meterDataChangeListenerRegistration.close();
+ }
+ }
+
+ public void setDataService(final DataProviderService dataService) {
+ this.dataService = dataService;
+ }
+
+ public void setSalMeterService(final SalMeterService salMeterService) {
+ this.salMeterService = salMeterService;
+ }
+}
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright (c) 2014 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.frm.meter
-
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService
-import org.opendaylight.yangtools.concepts.Registration
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.slf4j.LoggerFactory
-
-class MeterProvider implements AutoCloseable {
-
- @Property
- DataProviderService dataService;
-
- @Property
- SalMeterService salMeterService;
-
- FlowCommitHandler commitHandler
-
- Registration<DataCommitHandler<InstanceIdentifier<? extends DataObject>,DataObject>> commitHandlerRegistration;
-
- static val LOG = LoggerFactory.getLogger(MeterProvider);
-
- def void start() {
- commitHandler = new FlowCommitHandler(salMeterService)
- val InstanceIdentifier<? extends DataObject> path = InstanceIdentifier.builder(Nodes)
- .child(Node)
- .augmentation(FlowCapableNode)
- .child(Meter)
- .toInstance();
- commitHandlerRegistration = dataService.registerCommitHandler(path,commitHandler);
- LOG.info("Meter Config Provider started.");
- }
-
- protected def startChange() {
- return dataService.beginTransaction;
- }
-
- override close() throws Exception {
- throw new UnsupportedOperationException("TODO: auto-generated method stub")
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2014 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.frm.meter
-
-import org.opendaylight.controller.frm.AbstractTransaction
-import org.opendaylight.controller.md.sal.common.api.data.DataModification
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.AddMeterInputBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.RemoveMeterInputBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.UpdateMeterInputBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.meter.update.OriginalMeterBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.meter.update.UpdatedMeterBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.Meter
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterRef
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri
-
-class MeterTransaction extends AbstractTransaction {
-
- @Property
- val SalMeterService salMeterService;
-
- new(DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification,SalMeterService salMeterService) {
- super(modification)
- _salMeterService = salMeterService;
- }
-
- override remove(InstanceIdentifier<?> instanceId, DataObject obj) {
- if(obj instanceof Meter) {
- val meter = (obj as Meter)
- val nodeInstanceId = instanceId.firstIdentifierOf(Node);
- val builder = new RemoveMeterInputBuilder(meter);
- builder.setNode(new NodeRef(nodeInstanceId));
- builder.setMeterRef(new MeterRef(instanceId));
- builder.setTransactionUri(new Uri(modification.getIdentifier() as String));
- _salMeterService.removeMeter(builder.build());
- }
- }
-
- override update(InstanceIdentifier<?> instanceId, DataObject originalObj, DataObject updatedObj) {
- if(originalObj instanceof Meter && updatedObj instanceof Meter) {
- val originalMeter = (originalObj as Meter)
- val updatedMeter = (updatedObj as Meter)
- val nodeInstanceId = instanceId.firstIdentifierOf(Node);
- val builder = new UpdateMeterInputBuilder();
- builder.setNode(new NodeRef(nodeInstanceId));
- builder.setMeterRef(new MeterRef(instanceId));
- val ufb = new UpdatedMeterBuilder(updatedMeter);
- builder.setUpdatedMeter((ufb.build()));
- builder.setTransactionUri(new Uri(modification.getIdentifier() as String));
- val ofb = new OriginalMeterBuilder(originalMeter);
- builder.setOriginalMeter(ofb.build());
- _salMeterService.updateMeter(builder.build());
-
- }
- }
-
- override add(InstanceIdentifier<?> instanceId, DataObject obj) {
- if(obj instanceof Meter) {
- val meter = (obj as Meter)
- val nodeInstanceId = instanceId.firstIdentifierOf(Node);
- val builder = new AddMeterInputBuilder(meter);
- builder.setNode(new NodeRef(nodeInstanceId));
- builder.setMeterRef(new MeterRef(instanceId));
- builder.setTransactionUri(new Uri(modification.getIdentifier() as String));
- _salMeterService.addMeter(builder.build());
- }
- }
-
- override validate() throws IllegalStateException {
- MeterTransactionValidator.validate(this)
- }
-}
-/*
+/**
* Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
public class MeterTransactionValidator {
- public static void validate(MeterTransaction transaction) throws IllegalStateException {
+ public static void validate(MeterChangeListener transaction) throws IllegalStateException {
// NOOP
}
-
}
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
- <dependency>
- <groupId>org.eclipse.xtend</groupId>
- <artifactId>org.eclipse.xtend.lib</artifactId>
- </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-api</artifactId>
</instructions>
</configuration>
</plugin>
- <plugin>
- <groupId>org.eclipse.xtend</groupId>
- <artifactId>xtend-maven-plugin</artifactId>
- </plugin>
</plugins>
</build>
<scm>
--- /dev/null
+/**
+ * Copyright (c) 2014 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.md.inventory.manager;
+
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.yangtools.concepts.Registration;
+import org.opendaylight.yangtools.yang.binding.NotificationListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FlowCapableInventoryProvider implements AutoCloseable {
+
+ private final static Logger LOG = LoggerFactory.getLogger(FlowCapableInventoryProvider.class);
+
+ private DataProviderService dataService;
+ private NotificationProviderService notificationService;
+ private Registration<NotificationListener> listenerRegistration;
+ private final NodeChangeCommiter changeCommiter = new NodeChangeCommiter(FlowCapableInventoryProvider.this);
+
+ public void start() {
+ this.listenerRegistration = this.notificationService.registerNotificationListener(this.changeCommiter);
+ LOG.info("Flow Capable Inventory Provider started.");
+ }
+
+ protected DataModificationTransaction startChange() {
+ DataProviderService _dataService = this.dataService;
+ return _dataService.beginTransaction();
+ }
+
+ @Override
+ public void close() {
+ try {
+ LOG.info("Flow Capable Inventory Provider stopped.");
+ if (this.listenerRegistration != null) {
+ this.listenerRegistration.close();
+ }
+ } catch (Exception e) {
+ String errMsg = "Error by stop Flow Capable Inventory Provider.";
+ LOG.error(errMsg, e);
+ throw new RuntimeException(errMsg, e);
+ }
+ }
+
+ public DataProviderService getDataService() {
+ return this.dataService;
+ }
+
+ public void setDataService(final DataProviderService dataService) {
+ this.dataService = dataService;
+ }
+
+ public NotificationProviderService getNotificationService() {
+ return this.notificationService;
+ }
+
+ public void setNotificationService(
+ final NotificationProviderService notificationService) {
+ this.notificationService = notificationService;
+ }
+}
+++ /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.md.inventory.manager
-
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.OpendaylightInventoryListener
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRemoved
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorUpdated
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRemoved
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeUpdated
-import org.opendaylight.controller.sal.binding.api.NotificationProviderService
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService
-import org.opendaylight.yangtools.concepts.Registration
-import org.opendaylight.yangtools.yang.binding.NotificationListener
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorUpdated
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeUpdated
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey
-import static extension org.opendaylight.controller.md.inventory.manager.InventoryMapping.*
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
-import org.slf4j.LoggerFactory
-
-class FlowCapableInventoryProvider implements AutoCloseable {
-
-
- static val LOG = LoggerFactory.getLogger(FlowCapableInventoryProvider);
-
- @Property
- DataProviderService dataService;
-
- @Property
- NotificationProviderService notificationService;
- val NodeChangeCommiter changeCommiter = new NodeChangeCommiter(this);
-
- Registration<NotificationListener> listenerRegistration
-
- def void start() {
- listenerRegistration = notificationService.registerNotificationListener(changeCommiter);
- LOG.info("Flow Capable Inventory Provider started.");
-
- }
-
- protected def startChange() {
- return dataService.beginTransaction;
- }
-
- override close() {
- LOG.info("Flow Capable Inventory Provider stopped.");
- listenerRegistration?.close();
- }
-
-}
\ No newline at end of file
--- /dev/null
+/**
+ * Copyright (c) 2014 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.md.inventory.manager;
+
+import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareProvider;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.osgi.framework.BundleContext;
+
+public class InventoryActivator extends AbstractBindingAwareProvider {
+
+ private static FlowCapableInventoryProvider provider = new FlowCapableInventoryProvider();
+
+ @Override
+ public void onSessionInitiated(final ProviderContext session) {
+ DataProviderService salDataService = session.<DataProviderService> getSALService(DataProviderService.class);
+ NotificationProviderService salNotifiService =
+ session.<NotificationProviderService> getSALService(NotificationProviderService.class);
+ InventoryActivator.provider.setDataService(salDataService);
+ InventoryActivator.provider.setNotificationService(salNotifiService);
+ InventoryActivator.provider.start();
+ }
+
+ @Override
+ protected void stopImpl(final BundleContext context) {
+ InventoryActivator.provider.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.md.inventory.manager
-
-import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareProvider
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext
-import org.osgi.framework.BundleContext
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService
-import org.opendaylight.controller.sal.binding.api.NotificationProviderService
-
-class InventoryActivator extends AbstractBindingAwareProvider {
-
- static var FlowCapableInventoryProvider provider = new FlowCapableInventoryProvider();
-
- override onSessionInitiated(ProviderContext session) {
- provider.dataService = session.getSALService(DataProviderService)
- provider.notificationService = session.getSALService(NotificationProviderService)
- provider.start();
- }
-
- override protected stopImpl(BundleContext context) {
- provider.close();
- }
-
-}
--- /dev/null
+/**
+ * Copyright (c) 2014 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.md.inventory.manager;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowNodeConnector;
+
+public class InventoryMapping {
+
+ public static FlowCapableNodeConnector toInventoryAugment(final FlowNodeConnector updated) {
+ if ((updated instanceof FlowCapableNodeConnector)) {
+ return ((FlowCapableNodeConnector) updated);
+ }
+ final FlowCapableNodeConnectorBuilder builder = new FlowCapableNodeConnectorBuilder();
+ builder.setAdvertisedFeatures(updated.getAdvertisedFeatures());
+ builder.setConfiguration(updated.getConfiguration());
+ builder.setCurrentFeature(updated.getCurrentFeature());
+ builder.setCurrentSpeed(updated.getCurrentSpeed());
+ builder.setHardwareAddress(updated.getHardwareAddress());
+ builder.setMaximumSpeed(updated.getMaximumSpeed());
+ builder.setName(updated.getName());
+ builder.setPeerFeatures(updated.getPeerFeatures());
+ builder.setPortNumber(updated.getPortNumber());
+ builder.setState(updated.getState());
+ builder.setSupported(updated.getSupported());
+ return builder.build();
+ }
+
+ public static FlowCapableNode toInventoryAugment(final FlowNode source) {
+ if ((source instanceof FlowCapableNode)) {
+ return ((FlowCapableNode) source);
+ }
+ return (new FlowCapableNodeBuilder(source)).build();
+ }
+}
+++ /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.md.inventory.manager
-
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowNodeConnector
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowNode
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeBuilder
-
-class InventoryMapping {
-
- static def FlowCapableNodeConnector toInventoryAugment(FlowNodeConnector updated) {
- if (updated instanceof FlowCapableNodeConnector) {
- return updated as FlowCapableNodeConnector;
- }
- val it = new FlowCapableNodeConnectorBuilder();
- advertisedFeatures = updated.advertisedFeatures
- configuration = updated.configuration
- currentFeature = updated.currentFeature
- currentSpeed = updated.currentSpeed
- hardwareAddress = updated.hardwareAddress
- maximumSpeed = updated.maximumSpeed
- name = updated.name
- peerFeatures = updated.peerFeatures
- portNumber = updated.portNumber
- state = updated.state
- supported = updated.supported
- return build();
- }
-
- static def FlowCapableNode toInventoryAugment(FlowNode source) {
- if (source instanceof FlowCapableNode) {
- return source as FlowCapableNode;
- }
- val it = new FlowCapableNodeBuilder(source);
- return build();
- }
-
-}
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRemoved;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorUpdated;
-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.NodeRemoved;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeUpdated;
import com.google.common.base.Objects;
-@SuppressWarnings("all")
public class NodeChangeCommiter implements OpendaylightInventoryListener {
+
private final static Logger LOG = LoggerFactory.getLogger(NodeChangeCommiter.class);
private final FlowCapableInventoryProvider manager;
final NodeConnectorRef ref = connector.getNodeConnectorRef();
final FlowCapableNodeConnectorUpdated flowConnector = connector
.getAugmentation(FlowCapableNodeConnectorUpdated.class);
- final DataModificationTransaction it = this.getManager().startChange();
+ final DataModificationTransaction it = this.manager.startChange();
final NodeConnectorBuilder data = new NodeConnectorBuilder(connector);
NodeConnectorId id = connector.getId();
NodeConnectorKey nodeConnectorKey = new NodeConnectorKey(id);
data.addAugmentation(FlowCapableNodeConnector.class, augment);
}
InstanceIdentifier<? extends Object> value = ref.getValue();
- String string = value.toString();
- String plus = ("updating node connector : " + string);
- NodeChangeCommiter.LOG.debug(plus);
- InstanceIdentifier<? extends Object> value1 = ref.getValue();
+ NodeChangeCommiter.LOG.debug("updating node connector : {}.", value);
NodeConnector build = data.build();
- it.putOperationalData((value1), build);
+ it.putOperationalData((value), build);
Future<RpcResult<TransactionStatus>> commitResult = it.commit();
try {
commitResult.get();
public synchronized void onNodeRemoved(final NodeRemoved node) {
final NodeRef ref = node.getNodeRef();
- FlowCapableInventoryProvider manager = this.getManager();
- final DataModificationTransaction it = manager.startChange();
- InstanceIdentifier<? extends Object> value = ref.getValue();
- String string = value.toString();
- String plus = ("removing node : " + string);
- NodeChangeCommiter.LOG.debug(plus);
- InstanceIdentifier<? extends Object> value1 = ref.getValue();
- it.removeOperationalData((value1));
+ final DataModificationTransaction it = this.manager.startChange();
+ NodeChangeCommiter.LOG.debug("removing node : {}", ref.getValue());
+ it.removeOperationalData((ref.getValue()));
Future<RpcResult<TransactionStatus>> commitResult = it.commit();
try {
commitResult.get();
final NodeRef ref = node.getNodeRef();
final FlowCapableNodeUpdated flowNode = node
.<FlowCapableNodeUpdated> getAugmentation(FlowCapableNodeUpdated.class);
- FlowCapableInventoryProvider manager = this.getManager();
- final DataModificationTransaction it = manager.startChange();
- NodeBuilder nodeBuilder = new NodeBuilder(node);
- final NodeBuilder data = nodeBuilder;
- NodeId id = node.getId();
- NodeKey nodeKey = new NodeKey(id);
- data.setKey(nodeKey);
+ final DataModificationTransaction it = this.manager.startChange();
+ final NodeBuilder nodeBuilder = new NodeBuilder(node);
+ nodeBuilder.setKey(new NodeKey(node.getId()));
boolean equals = Objects.equal(flowNode, null);
if (equals) {
return;
}
final FlowCapableNode augment = InventoryMapping.toInventoryAugment(flowNode);
- data.addAugmentation(FlowCapableNode.class, augment);
+ nodeBuilder.addAugmentation(FlowCapableNode.class, augment);
InstanceIdentifier<? extends Object> value = ref.getValue();
InstanceIdentifierBuilder<Node> builder = InstanceIdentifier.<Node> builder(((InstanceIdentifier<Node>) value));
InstanceIdentifierBuilder<FlowCapableNode> augmentation = builder
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
- <pluginExecution>
- <pluginExecutionFilter>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-maven-plugin</artifactId>
- <versionRange>[0,)</versionRange>
- <goals>
- <goal>generate-sources</goal>
- </goals>
- </pluginExecutionFilter>
- <action>
- <ignore></ignore>
- </action>
- </pluginExecution>
<pluginExecution>
<pluginExecutionFilter>
<groupId>net.alchim31.maven</groupId>
try {
final DataObject dataObject = normalizedNode.isPresent() ? codec.toBinding(path,
normalizedNode.get()) : null;
- if(dataObject != null) {
+ if (dataObject != null) {
updateCache(store, path, dataObject);
}
return Optional.fromNullable(dataObject);
.toNormalizedNode(path, data);
org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalizedPath = normalized.getKey();
+ ensureParentsByMerge(writeTransaction, store, normalized.getKey(), path);
+ LOG.debug("Tx: {} : Putting data {}",getDelegate().getIdentifier(),normalized.getKey());
+ writeTransaction.put(store, normalized.getKey(), normalized.getValue());
+ }
+
+ protected void doMergeWithEnsureParents(final DOMDataReadWriteTransaction writeTransaction,
+ final LogicalDatastoreType store, final InstanceIdentifier<?> path, final DataObject data) {
+ invalidateCache(store, path);
+ final Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, NormalizedNode<?, ?>> normalized = codec
+ .toNormalizedNode(path, data);
+
+ org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalizedPath = normalized.getKey();
+ ensureParentsByMerge(writeTransaction, store, normalized.getKey(), path);
+ LOG.debug("Tx: {} : Merge data {}",getDelegate().getIdentifier(),normalized.getKey());
+ writeTransaction.merge(store, normalized.getKey(), normalized.getValue());
+ }
+
+ private void ensureParentsByMerge(final DOMDataReadWriteTransaction writeTransaction,
+ final LogicalDatastoreType store,
+ final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalizedPath,
+ final InstanceIdentifier<?> path) {
List<PathArgument> currentArguments = new ArrayList<>();
DataNormalizationOperation<?> currentOp = codec.getDataNormalizer().getRootOperation();
Iterator<PathArgument> iterator = normalizedPath.getPath().iterator();
writeTransaction.merge(store, currentPath, currentOp.createDefault(currentArg));
}
}
- //LOG .info("Tx: {} : Putting data {}",getDelegate().getIdentifier(),normalized.getKey());
- writeTransaction.put(store, normalized.getKey(), normalized.getValue());
}
protected void doMerge(final DOMDataWriteTransaction writeTransaction, final LogicalDatastoreType store,
*/
package org.opendaylight.controller.md.sal.binding.impl;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
import java.util.AbstractMap.SimpleEntry;
+import java.util.LinkedList;
+import java.util.List;
import java.util.Map.Entry;
+import java.util.concurrent.Callable;
import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationException;
import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer;
+import org.opendaylight.yangtools.concepts.util.ClassLoaderUtils;
import org.opendaylight.yangtools.yang.binding.Augmentation;
+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.InstanceIdentifier.Item;
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
public class BindingToNormalizedNodeCodec implements SchemaContextListener {
public org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toNormalized(
final InstanceIdentifier<? extends DataObject> binding) {
- final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier legacyPath = bindingToLegacy.toDataDom(binding);
- final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized = legacyToNormalized.toNormalized(legacyPath);
- LOG.trace("InstanceIdentifier Path {} Serialization: Legacy representation {}, Normalized representation: {}",binding,legacyPath,normalized);
- return normalized;
+
+ // Used instance-identifier codec do not support serialization of last path
+ // argument if it is Augmentation (behaviour expected by old datastore)
+ // in this case, we explicitly check if last argument is augmentation
+ // to process it separately
+ if (isAugmentationIdentifier(binding)) {
+ return toNormalizedAugmented(binding);
+ }
+ return toNormalizedImpl(binding);
}
public Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, NormalizedNode<?, ?>> toNormalizedNode(
public Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, NormalizedNode<?, ?>> toNormalizedNode(
final Entry<org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject>, DataObject> binding) {
- Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> legacyEntry = bindingToLegacy.toDataDom(binding);
- Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, NormalizedNode<?, ?>> normalizedEntry = legacyToNormalized.toNormalized(legacyEntry);
- LOG.trace("Serialization of {}, Legacy Representation: {}, Normalized Representation: {}",binding,legacyEntry,normalizedEntry);
- if(Augmentation.class.isAssignableFrom(binding.getKey().getTargetType())) {
-
- for(DataContainerChild<? extends PathArgument, ?> child : ((DataContainerNode<?>) normalizedEntry.getValue()).getValue()) {
- if(child instanceof AugmentationNode) {
- ImmutableList<PathArgument> childArgs = ImmutableList.<PathArgument>builder()
- .addAll(normalizedEntry.getKey().getPath())
- .add(child.getIdentifier())
- .build();
- org.opendaylight.yangtools.yang.data.api.InstanceIdentifier childPath = new org.opendaylight.yangtools.yang.data.api.InstanceIdentifier(childArgs);
- return new SimpleEntry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, NormalizedNode<?, ?>>(childPath,child);
- }
+ Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> legacyEntry = bindingToLegacy
+ .toDataDom(binding);
+ Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, NormalizedNode<?, ?>> normalizedEntry = legacyToNormalized
+ .toNormalized(legacyEntry);
+ LOG.trace("Serialization of {}, Legacy Representation: {}, Normalized Representation: {}", binding,
+ legacyEntry, normalizedEntry);
+ if (Augmentation.class.isAssignableFrom(binding.getKey().getTargetType())) {
+
+ for (DataContainerChild<? extends PathArgument, ?> child : ((DataContainerNode<?>) normalizedEntry
+ .getValue()).getValue()) {
+ if (child instanceof AugmentationNode) {
+ ImmutableList<PathArgument> childArgs = ImmutableList.<PathArgument> builder()
+ .addAll(normalizedEntry.getKey().getPath()).add(child.getIdentifier()).build();
+ org.opendaylight.yangtools.yang.data.api.InstanceIdentifier childPath = new org.opendaylight.yangtools.yang.data.api.InstanceIdentifier(
+ childArgs);
+ return new SimpleEntry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, NormalizedNode<?, ?>>(
+ childPath, child);
+ }
}
}
return normalizedEntry;
-
}
public InstanceIdentifier<? extends DataObject> toBinding(
final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized)
throws DeserializationException {
+ PathArgument lastArgument = Iterables.getLast(normalized.getPath());
+ // Used instance-identifier codec do not support serialization of last path
+ // argument if it is AugmentationIdentifier (behaviour expected by old datastore)
+ // in this case, we explicitly check if last argument is augmentation
+ // to process it separately
+ if (lastArgument instanceof AugmentationIdentifier) {
+ return toBindingAugmented(normalized);
+ }
+ return toBindingImpl(normalized);
+ }
+
+ private InstanceIdentifier<? extends DataObject> toBindingAugmented(
+ final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized) throws DeserializationException {
+ InstanceIdentifier<? extends DataObject> potential = toBindingImpl(normalized);
+ // Shorthand check, if codec already supports deserialization
+ // of AugmentationIdentifier we will return
+ if(isAugmentationIdentifier(potential)) {
+ return potential;
+ }
+
+ AugmentationIdentifier lastArgument = (AugmentationIdentifier) Iterables.getLast(normalized.getPath());
+
+ // Here we employ small trick - Binding-aware Codec injects an pointer to augmentation class
+ // if child is referenced - so we will reference child and then shorten path.
+ for (QName child : lastArgument.getPossibleChildNames()) {
+ org.opendaylight.yangtools.yang.data.api.InstanceIdentifier childPath = new org.opendaylight.yangtools.yang.data.api.InstanceIdentifier(
+ ImmutableList.<PathArgument> builder()
+ .addAll(normalized.getPath()).add(new NodeIdentifier(child)).build());
+ try {
+
+ InstanceIdentifier<? extends DataObject> potentialPath = shortenToLastAugment(toBindingImpl(childPath));
+ return potentialPath;
+ } catch (Exception e) {
+ LOG.trace("Unable to deserialize aug. child path for {}",childPath,e);
+ }
+ }
+ return toBindingImpl(normalized);
+ }
+
+ private InstanceIdentifier<? extends DataObject> toBindingImpl(
+ final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized)
+ throws DeserializationException {
org.opendaylight.yangtools.yang.data.api.InstanceIdentifier legacyPath;
try {
legacyPath = legacyToNormalized.toLegacy(normalized);
} catch (DataNormalizationException e) {
- throw new IllegalStateException("Could not denormalize path.",e);
+ throw new IllegalStateException("Could not denormalize path.", e);
}
- LOG.trace("InstanceIdentifier Path Deserialization: Legacy representation {}, Normalized representation: {}",legacyPath,normalized);
+ LOG.trace("InstanceIdentifier Path Deserialization: Legacy representation {}, Normalized representation: {}",
+ legacyPath, normalized);
return bindingToLegacy.fromDataDom(legacyPath);
}
public DataObject toBinding(final InstanceIdentifier<?> path, final NormalizedNode<?, ?> normalizedNode)
throws DeserializationException {
- return bindingToLegacy.dataObjectFromDataDom(path, (CompositeNode) DataNormalizer.toLegacy(normalizedNode));
+ CompositeNode legacy = null;
+ if(isAugmentationIdentifier(path) && normalizedNode instanceof AugmentationNode) {
+ QName augIdentifier = BindingReflections.findQName(path.getTargetType());
+ ContainerNode virtualNode = Builders.containerBuilder() //
+ .withNodeIdentifier(new NodeIdentifier(augIdentifier)) //
+ .withChild((DataContainerChild<?, ?>) normalizedNode) //
+ .build();
+ legacy = (CompositeNode) DataNormalizer.toLegacy(virtualNode);
+ } else {
+ legacy = (CompositeNode) DataNormalizer.toLegacy(normalizedNode);
+ }
+
+ return bindingToLegacy.dataObjectFromDataDom(path, legacy);
}
public DataNormalizer getDataNormalizer() {
legacyToNormalized = new DataNormalizer(arg0);
}
+ private org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toNormalizedAugmented(
+ final InstanceIdentifier<?> augPath) {
+ org.opendaylight.yangtools.yang.data.api.InstanceIdentifier processed = toNormalizedImpl(augPath);
+ // If used instance identifier codec added supports for deserialization
+ // of last AugmentationIdentifier we will just reuse it
+ if(isAugmentationIdentifier(processed)) {
+ return processed;
+ }
+ // Here we employ small trick - DataNormalizer injecst augmentation identifier if child is
+ // also part of the path (since using a child we can safely identify augmentation)
+ // so, we scan augmentation for children add it to path
+ // and use original algorithm, then shorten it to last augmentation
+ for (@SuppressWarnings("rawtypes") Class augChild : getAugmentationChildren(augPath.getTargetType())) {
+ @SuppressWarnings("unchecked")
+ InstanceIdentifier<?> childPath = augPath.child(augChild);
+ org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized = toNormalizedImpl(childPath);
+ org.opendaylight.yangtools.yang.data.api.InstanceIdentifier potentialDiscovered = shortenToLastAugmentation(normalized);
+ if (potentialDiscovered != null) {
+ return potentialDiscovered;
+ }
+ }
+ return processed;
+ }
+
+
+
+ private org.opendaylight.yangtools.yang.data.api.InstanceIdentifier shortenToLastAugmentation(
+ final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized) {
+ int position = 0;
+ int foundPosition = -1;
+ for (PathArgument arg : normalized.getPath()) {
+ position++;
+ if (arg instanceof AugmentationIdentifier) {
+ foundPosition = position;
+ }
+ }
+ if (foundPosition > 0) {
+ return new org.opendaylight.yangtools.yang.data.api.InstanceIdentifier(normalized.getPath().subList(0,
+ foundPosition));
+ }
+ return null;
+ }
+
+ private InstanceIdentifier<? extends DataObject> shortenToLastAugment(
+ final InstanceIdentifier<? extends DataObject> binding) {
+ int position = 0;
+ int foundPosition = -1;
+ for(org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument arg : binding.getPathArguments()) {
+ position++;
+ if (isAugmentation(arg.getType())) {
+ foundPosition = position;
+ }
+ }
+ return InstanceIdentifier.create(Iterables.limit(binding.getPathArguments(), foundPosition));
+ }
+
+
+
+ private org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toNormalizedImpl(
+ final InstanceIdentifier<? extends DataObject> binding) {
+ final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier legacyPath = bindingToLegacy
+ .toDataDom(binding);
+ final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized = legacyToNormalized
+ .toNormalized(legacyPath);
+ return normalized;
+ }
+
+ @SuppressWarnings("unchecked")
+ private Iterable<Class<? extends DataObject>> getAugmentationChildren(final Class<?> targetType) {
+ List<Class<? extends DataObject>> ret = new LinkedList<>();
+ for (Method method : targetType.getMethods()) {
+ Class<?> entity = getYangModeledType(method);
+ if (entity != null) {
+ ret.add((Class<? extends DataObject>) entity);
+ }
+ }
+ return ret;
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ private Class<? extends DataObject> getYangModeledType(final Method method) {
+ if (method.getName().equals("getClass") || !method.getName().startsWith("get")
+ || method.getParameterTypes().length > 0) {
+ return null;
+ }
+
+ Class<?> returnType = method.getReturnType();
+ if (DataContainer.class.isAssignableFrom(returnType)) {
+ return (Class) returnType;
+ } else if (List.class.isAssignableFrom(returnType)) {
+ try {
+ return ClassLoaderUtils.withClassLoader(method.getDeclaringClass().getClassLoader(),
+ new Callable<Class>() {
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ public Class call() throws Exception {
+ Type listResult = ClassLoaderUtils.getFirstGenericParameter(method
+ .getGenericReturnType());
+ if (listResult instanceof Class
+ && DataObject.class.isAssignableFrom((Class) listResult)) {
+ return (Class<?>) listResult;
+ }
+ return null;
+ }
+
+ });
+ } catch (Exception e) {
+ LOG.debug("Could not get YANG modeled entity for {}", method, e);
+ return null;
+ }
+
+ }
+ return null;
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ private static InstanceIdentifier<?> toWildcarded(final InstanceIdentifier<?> orig) {
+ List<org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument> wildArgs = new LinkedList<>();
+ for (org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument arg : orig.getPathArguments()) {
+ wildArgs.add(new Item(arg.getType()));
+ }
+ return InstanceIdentifier.create(wildArgs);
+ }
+
+
+ private static boolean isAugmentation(final Class<? extends DataObject> type) {
+ return Augmentation.class.isAssignableFrom(type);
+ }
+
+ private static boolean isAugmentationIdentifier(final InstanceIdentifier<?> path) {
+ return Augmentation.class.isAssignableFrom(path.getTargetType());
+ }
+
+ private boolean isAugmentationIdentifier(final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier processed) {
+ return Iterables.getLast(processed.getPath()) instanceof AugmentationIdentifier;
+ }
}
private class ForwardedBackwardsCompatibleTransacion extends
AbstractForwardedTransaction<DOMDataReadWriteTransaction> implements DataModificationTransaction {
+ private final ListenerRegistry<DataTransactionListener> listeners = ListenerRegistry.create();
private final Map<InstanceIdentifier<? extends DataObject>, DataObject> updated = new HashMap<>();
private final Map<InstanceIdentifier<? extends DataObject>, DataObject> created = new HashMap<>();
private final Set<InstanceIdentifier<? extends DataObject>> removed = new HashSet<>();
@Override
public void putOperationalData(final InstanceIdentifier<? extends DataObject> path, final DataObject data) {
- posponedRemovedOperational.remove(path);
- doPutWithEnsureParents(getDelegate(), LogicalDatastoreType.OPERATIONAL, path, data);
+ boolean previouslyRemoved = posponedRemovedOperational.remove(path);
+ if(previouslyRemoved) {
+ doPutWithEnsureParents(getDelegate(), LogicalDatastoreType.OPERATIONAL, path, data);
+ } else {
+ doMergeWithEnsureParents(getDelegate(), LogicalDatastoreType.OPERATIONAL, path, data);
+ }
}
@Override
public void putConfigurationData(final InstanceIdentifier<? extends DataObject> path, final DataObject data) {
- posponedRemovedConfiguration.remove(path);
+ boolean previouslyRemoved = posponedRemovedConfiguration.remove(path);
DataObject originalObj = readConfigurationData(path);
if (originalObj != null) {
original.put(path, originalObj);
created.put(path, data);
}
updated.put(path, data);
- doPutWithEnsureParents(getDelegate(), LogicalDatastoreType.CONFIGURATION, path, data);
+ if(previouslyRemoved) {
+ doPutWithEnsureParents(getDelegate(), LogicalDatastoreType.CONFIGURATION, path, data);
+ } else {
+ doMergeWithEnsureParents(getDelegate(), LogicalDatastoreType.CONFIGURATION, path, data);
+ }
}
@Override
private void changeStatus(final TransactionStatus status) {
LOG.trace("Transaction {} changed status to {}", getIdentifier(), status);
this.status = status;
+
+ for(ListenerRegistration<DataTransactionListener> listener : listeners) {
+ try {
+ listener.getInstance().onStatusUpdated(this, status);
+ } catch (Exception e) {
+ LOG.error("Error during invoking transaction listener {}",listener.getInstance(),e);
+ }
+ }
}
@Override
doDelete(getDelegate(), LogicalDatastoreType.OPERATIONAL, path);
}
- final ListenableFuture<RpcResult<TransactionStatus>> f = ForwardedBackwardsCompatibleDataBroker.this.commit(this);
-
changeStatus(TransactionStatus.SUBMITED);
+ final ListenableFuture<RpcResult<TransactionStatus>> f = ForwardedBackwardsCompatibleDataBroker.this.commit(this);
+
Futures.addCallback(f, new FutureCallback<RpcResult<TransactionStatus>>() {
@Override
public void onSuccess(final RpcResult<TransactionStatus> result) {
@Override
public ListenerRegistration<DataTransactionListener> registerListener(final DataTransactionListener listener) {
- throw new UnsupportedOperationException();
+ return listeners.register(listener);
}
}
public static final int CORE_NOTIFICATION_THREADS = 4;
public static final int MAX_NOTIFICATION_THREADS = 32;
+ // block caller thread after MAX_NOTIFICATION_THREADS + MAX_NOTIFICATION_QUEUE_SIZE pending notifications
+ public static final int MAX_NOTIFICATION_QUEUE_SIZE = 10;
public static final int NOTIFICATION_THREAD_LIFE = 15;
private static ListeningExecutorService NOTIFICATION_EXECUTOR = null;
public static synchronized final ListeningExecutorService getDefaultNotificationExecutor() {
if (NOTIFICATION_EXECUTOR == null) {
- // Overriding the queue since we need an unbounded queue
- // and threadpoolexecutor would not create new threads if the queue is not full
- BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>() {
+ // Overriding the queue:
+ // ThreadPoolExecutor would not create new threads if the queue is not full, thus adding
+ // occurs in RejectedExecutionHandler.
+ // This impl saturates threadpool first, then queue. When both are full caller will get blocked.
+ BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>(MAX_NOTIFICATION_QUEUE_SIZE) {
@Override
public boolean offer(Runnable r) {
- if (size() <= 1) {
- // if the queue is empty (or has just 1), no need to rampup the threads
- return super.offer(r);
- } else {
- // if the queue is not empty, force the queue to return false.
- // threadpoolexecutor will spawn a new thread if the queue.offer returns false.
- return false;
- }
+ // ThreadPoolExecutor will spawn a new thread after core size is reached only if the queue.offer returns false.
+ return false;
}
};
try {
executor.getQueue().put(r);
} catch (InterruptedException e) {
- e.printStackTrace();
+ Thread.currentThread().interrupt();// set interrupt flag after clearing
+ throw new IllegalStateException(e);
}
}
});
--- /dev/null
+/*
+ * Copyright (c) 2014 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.sal.binding.codegen.impl;
+
+import com.google.common.util.concurrent.ListeningExecutorService;
+import java.lang.reflect.Field;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Ignore
+public class SingletonHolderTest {
+ private static final Logger logger = LoggerFactory.getLogger(SingletonHolderTest.class);
+
+ @Test
+ public void testNotificationExecutor() throws Exception {
+ ListeningExecutorService executor = SingletonHolder.getDefaultNotificationExecutor();
+ ThreadPoolExecutor tpExecutor = (ThreadPoolExecutor) setAccessible(executor.getClass().getDeclaredField("delegate")).get(executor);
+ BlockingQueue<Runnable> queue = tpExecutor.getQueue();
+
+ for (int idx = 0; idx < 100; idx++) {
+ final int idx2 = idx;
+ logger.info("Adding {}\t{}\t{}", idx, queue.size(), tpExecutor.getActiveCount());
+ executor.execute(new Runnable() {
+
+ @Override
+ public void run() {
+ logger.info("in {}", idx2);
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ logger.info("out {}", idx2);
+ }
+ });
+ }
+ executor.shutdown();
+ executor.awaitTermination(10, TimeUnit.SECONDS);
+ }
+
+ private static Field setAccessible(Field field) {
+ field.setAccessible(true);
+ return field;
+ }
+}
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-binding</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-broker-impl</artifactId>
<type>test-jar</type>
<scope>test</scope>
</dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-binding</artifactId>
- </dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-management</artifactId>
</dependencies>
<build>
<plugins>
- <plugin>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-maven-plugin</artifactId>
- <executions>
- <execution>
- <goals>
- <goal>generate-sources</goal>
- </goals>
- <configuration>
- <codeGenerators>
- <generator>
- <codeGeneratorClass>org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl</codeGeneratorClass>
- <outputBaseDir>${salGeneratorPath}</outputBaseDir>
- </generator>
- </codeGenerators>
- <inspectDependencies>true</inspectDependencies>
- </configuration>
- </execution>
- </executions>
- </plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
</execution>
</executions>
</plugin>
+ <plugin>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>generate-sources</goal>
+ </goals>
+ <configuration>
+ <codeGenerators>
+ <generator>
+ <codeGeneratorClass>org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl</codeGeneratorClass>
+ <outputBaseDir>${salGeneratorPath}</outputBaseDir>
+ </generator>
+ </codeGenerators>
+ <inspectDependencies>true</inspectDependencies>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
</plugins>
</build>
<scm>
--- /dev/null
+/*
+ * Copyright (c) 2014 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.sal.binding.test.bugfix;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.concurrent.TimeUnit;
+
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import com.google.common.util.concurrent.SettableFuture;
+
+public class WriteParentListenAugmentTest extends AbstractDataServiceTest {
+
+ private static final String NODE_ID = "node:1";
+
+ private static final NodeKey NODE_KEY = new NodeKey(new NodeId(NODE_ID));
+ private static final InstanceIdentifier<Node> NODE_INSTANCE_ID_BA = InstanceIdentifier.builder(Nodes.class) //
+ .child(Node.class, NODE_KEY).toInstance();
+
+ private static final InstanceIdentifier<FlowCapableNode> AUGMENT_WILDCARDED_PATH = InstanceIdentifier
+ .builder(Nodes.class).child(Node.class).augmentation(FlowCapableNode.class).toInstance();
+
+ private static final InstanceIdentifier<FlowCapableNode> AUGMENT_NODE_PATH = InstanceIdentifier
+ .builder(Nodes.class).child(Node.class, NODE_KEY).augmentation(FlowCapableNode.class).toInstance();
+
+ @Test
+ public void writeNodeListenAugment() throws Exception {
+
+ final SettableFuture<DataChangeEvent<InstanceIdentifier<?>, DataObject>> event = SettableFuture.create();
+
+ ListenerRegistration<DataChangeListener> dclRegistration = baDataService.registerDataChangeListener(
+ AUGMENT_WILDCARDED_PATH, new DataChangeListener() {
+
+ @Override
+ public void onDataChanged(final DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
+ event.set(change);
+ }
+ });
+
+ DataModificationTransaction modification = baDataService.beginTransaction();
+
+ Node node = new NodeBuilder() //
+ .setKey(NODE_KEY) //
+ .addAugmentation(FlowCapableNode.class, flowCapableNode("one")).build();
+ modification.putOperationalData(NODE_INSTANCE_ID_BA, node);
+ modification.commit().get();
+
+ DataChangeEvent<InstanceIdentifier<?>, DataObject> receivedEvent = event.get(1000, TimeUnit.MILLISECONDS);
+ assertTrue(receivedEvent.getCreatedOperationalData().containsKey(AUGMENT_NODE_PATH));
+
+ dclRegistration.close();
+
+ DataModificationTransaction mod2 = baDataService.beginTransaction();
+ mod2.putOperationalData(AUGMENT_NODE_PATH, flowCapableNode("two"));
+ mod2.commit().get();
+
+ FlowCapableNode readedAug = (FlowCapableNode) baDataService.readOperationalData(AUGMENT_NODE_PATH);
+ assertEquals("two", readedAug.getDescription());
+
+ }
+
+ private FlowCapableNode flowCapableNode(final String description) {
+ return new FlowCapableNodeBuilder() //
+ .setDescription(description) //
+ .build();
+ }
+}
\ No newline at end of file
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
public final class ImmutableDataChangeEvent<P extends Path<P>, D> implements DataChangeEvent<P,D> {
originalOperational.putAll(Maps.filterKeys(data.getOriginalOperationalData(), keyFilter));
createdOperational.putAll(Maps.filterKeys(data.getCreatedOperationalData(), keyFilter));
createdConfiguration.putAll(Maps.filterKeys(data.getCreatedConfigurationData(), keyFilter));
+ removedOperational.addAll(Sets.filter(data.getRemovedOperationalData(), keyFilter));
+ removedConfiguration.addAll(Sets.filter(data.getRemovedConfigurationData(), keyFilter));
return this;
}
Builder eventBuilder = builder(potentialScope) //
.setBefore(beforeCont) //
- .setAfter(afterCont);
+ .setAfter(afterCont)
+ .addUpdated(path, beforeCont, afterCont);
for (DOMImmutableDataChangeEvent childChange : childChanges) {
eventBuilder.merge(childChange);
}
final Collection<Node> listeners, final NormalizedNode<PathArgument, ?> node,
final SimpleEventFactory eventFactory) {
- DOMImmutableDataChangeEvent event = eventFactory.create(path, node);
-
- if (!listeners.isEmpty()) {
+ final DOMImmutableDataChangeEvent event = eventFactory.create(path, node);
+ DOMImmutableDataChangeEvent propagateEvent = event;
// We have listeners for this node or it's children, so we will try
// to do additional processing
- if (node instanceof NormalizedNodeContainer<?, ?, ?>) {
- // Node has children, so we will try to resolve it's children
- // changes.
- @SuppressWarnings("unchecked")
- NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>> container = (NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>>) node;
- for (NormalizedNode<PathArgument, ?> child : container.getValue()) {
- PathArgument childId = child.getIdentifier();
- Collection<Node> childListeners = getListenerChildrenWildcarded(listeners, childId);
- if (!childListeners.isEmpty()) {
- resolveSameEventRecursivelly(append(path, childId), childListeners, child, eventFactory);
- }
- }
+ if (node instanceof NormalizedNodeContainer<?, ?, ?>) {
+ Builder eventBuilder = builder(DataChangeScope.BASE);
+ eventBuilder.merge(event);
+ eventBuilder.setBefore(event.getOriginalSubtree());
+ eventBuilder.setAfter(event.getUpdatedSubtree());
+
+ // Node has children, so we will try to resolve it's children
+ // changes.
+ @SuppressWarnings("unchecked")
+ NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>> container = (NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>>) node;
+ for (NormalizedNode<PathArgument, ?> child : container.getValue()) {
+ PathArgument childId = child.getIdentifier();
+ Collection<Node> childListeners = getListenerChildrenWildcarded(listeners, childId);
+ eventBuilder.merge(resolveSameEventRecursivelly(append(path, childId), childListeners, child, eventFactory));
}
+ propagateEvent = eventBuilder.build();
+ } else {
+ // We do not dispatch leaf events since Binding Aware components do not support them.
+ propagateEvent = builder(DataChangeScope.BASE).build();
+ }
+ if (!listeners.isEmpty()) {
addPartialTask(listeners, event);
}
- return event;
+ return propagateEvent;
}
private DOMImmutableDataChangeEvent resolveSubtreeChangeEvent(final InstanceIdentifier path,
Builder one = builder(DataChangeScope.ONE).setBefore(before.getData()).setAfter(after.getData());
- Builder subtree = builder(DataChangeScope.SUBTREE);
+ Builder subtree = builder(DataChangeScope.SUBTREE).setBefore(before.getData()).setAfter(after.getData());
for (NodeModification childMod : modification.getModifications()) {
PathArgument childId = childMod.getIdentifier();
import static com.google.common.base.Preconditions.checkArgument;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetNodeBuilder;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapEntryNodeBuilder;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableOrderedLeafSetNodeBuilder;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableOrderedMapNodeBuilder;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableUnkeyedListEntryNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.AugmentationSchemaProxy;
import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
} else if (schemaNode instanceof ChoiceNode) {
return new ChoiceModificationStrategy((ChoiceNode) schemaNode);
} else if (schemaNode instanceof LeafListSchemaNode) {
- return new LeafSetEntryModificationStrategy((LeafListSchemaNode) schemaNode);
+ return fromLeafListSchemaNode((LeafListSchemaNode) schemaNode);
} else if (schemaNode instanceof LeafSchemaNode) {
return new LeafModificationStrategy((LeafSchemaNode) schemaNode);
}
return new UnorderedMapModificationStrategy(schemaNode);
}
+ private static SchemaAwareApplyOperation fromLeafListSchemaNode(final LeafListSchemaNode schemaNode) {
+ if(schemaNode.isUserOrdered()) {
+ return new OrderedLeafSetModificationStrategy(schemaNode);
+ } else {
+ return new UnorderedLeafSetModificationStrategy(schemaNode);
+ }
+ }
+
+
public static SchemaAwareApplyOperation from(final DataNodeContainer resolvedTree,
final AugmentationTarget augSchemas, final AugmentationIdentifier identifier) {
AugmentationSchema augSchema = null;
DataNodeContainerModificationStrategy<AugmentationSchema> {
protected AugmentationModificationStrategy(final AugmentationSchema schema, final DataNodeContainer resolved) {
- super(schema, AugmentationNode.class);
+ super(createAugmentProxy(schema,resolved), AugmentationNode.class);
// FIXME: Use resolved children instead of unresolved.
}
}
- public static class LeafSetModificationStrategy extends NormalizedNodeContainerModificationStrategy {
+ public static class UnorderedLeafSetModificationStrategy extends NormalizedNodeContainerModificationStrategy {
private final Optional<ModificationApplyOperation> entryStrategy;
@SuppressWarnings({ "unchecked", "rawtypes" })
- protected LeafSetModificationStrategy(final LeafListSchemaNode schema) {
+ protected UnorderedLeafSetModificationStrategy(final LeafListSchemaNode schema) {
super((Class) LeafSetNode.class);
entryStrategy = Optional.<ModificationApplyOperation> of(new LeafSetEntryModificationStrategy(schema));
}
}
+ public static class OrderedLeafSetModificationStrategy extends NormalizedNodeContainerModificationStrategy {
+
+ private final Optional<ModificationApplyOperation> entryStrategy;
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ protected OrderedLeafSetModificationStrategy(final LeafListSchemaNode schema) {
+ super((Class) LeafSetNode.class);
+ entryStrategy = Optional.<ModificationApplyOperation> of(new LeafSetEntryModificationStrategy(schema));
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ protected NormalizedNodeContainerBuilder createBuilder(final PathArgument identifier) {
+ return ImmutableOrderedLeafSetNodeBuilder.create().withNodeIdentifier((NodeIdentifier) identifier);
+ }
+
+ @Override
+ public Optional<ModificationApplyOperation> getChild(final PathArgument identifier) {
+ if (identifier instanceof NodeWithValue) {
+ return entryStrategy;
+ }
+ return Optional.absent();
+ }
+
+ }
+
public static class UnkeyedListModificationStrategy extends SchemaAwareApplyOperation {
private final Optional<ModificationApplyOperation> entryStrategy;
}
+ public static AugmentationSchema createAugmentProxy(final AugmentationSchema schema, final DataNodeContainer resolved) {
+ Set<DataSchemaNode> realChildSchemas = new HashSet<>();
+ for(DataSchemaNode augChild : schema.getChildNodes()) {
+ realChildSchemas.add(resolved.getDataChildByName(augChild.getQName()));
+ }
+ return new AugmentationSchemaProxy(schema, realChildSchemas);
+ }
+
}
<artifactId>netconf-client</artifactId>
<version>${netconf.version}</version>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>netconf-config-dispatcher</artifactId>
+ </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>sal-common-util</artifactId>
import static org.opendaylight.controller.config.api.JmxAttributeValidationException.checkCondition;
import static org.opendaylight.controller.config.api.JmxAttributeValidationException.checkNotNull;
-import io.netty.channel.EventLoopGroup;
+
+import io.netty.util.HashedWheelTimer;
import io.netty.util.concurrent.GlobalEventExecutor;
import java.io.File;
import java.util.concurrent.Executors;
import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
-import org.opendaylight.controller.netconf.client.NetconfSshClientDispatcher;
-import org.opendaylight.controller.netconf.util.handler.ssh.authentication.AuthenticationHandler;
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
+import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration;
+import org.opendaylight.controller.netconf.client.conf.NetconfClientConfigurationBuilder;
import org.opendaylight.controller.netconf.util.handler.ssh.authentication.LoginPassword;
import org.opendaylight.controller.sal.connect.netconf.NetconfDevice;
+import org.opendaylight.controller.sal.connect.netconf.NetconfDeviceListener;
import org.opendaylight.protocol.framework.ReconnectStrategy;
import org.opendaylight.protocol.framework.TimedReconnectStrategy;
import org.opendaylight.yangtools.yang.model.util.repo.AbstractCachingSchemaSourceProvider;
checkNotNull(getBetweenAttemptsTimeoutMillis(), betweenAttemptsTimeoutMillisJmxAttribute);
checkCondition(getBetweenAttemptsTimeoutMillis() > 0, "must be > 0", betweenAttemptsTimeoutMillisJmxAttribute);
+ // FIXME BUG-944 remove backwards compatibility
+ if(getClientDispatcher() == null) {
+ checkCondition(getBossThreadGroup() != null, "Client dispatcher was not set, thread groups have to be set instead", bossThreadGroupJmxAttribute);
+ checkCondition(getWorkerThreadGroup() != null, "Client dispatcher was not set, thread groups have to be set instead", workerThreadGroupJmxAttribute);
+ }
+
+ // Check username + password in case of ssh
+ if(getTcpOnly() == false) {
+ checkNotNull(getUsername(), usernameJmxAttribute);
+ checkNotNull(getPassword(), passwordJmxAttribute);
+ }
+
}
@Override
getDomRegistryDependency();
NetconfDevice device = new NetconfDevice(getIdentifier().getInstanceName());
- String addressValue = getAddress();
-
- Long connectionAttempts;
- if (getMaxConnectionAttempts() != null && getMaxConnectionAttempts() > 0) {
- connectionAttempts = getMaxConnectionAttempts();
- } else {
- logger.trace("Setting {} on {} to infinity", maxConnectionAttemptsJmxAttribute, this);
- connectionAttempts = null;
- }
- long clientConnectionTimeoutMillis = getConnectionTimeoutMillis();
- /*
- * Uncomment after Switch to IP Address
- if(getAddress().getIpv4Address() != null) {
- addressValue = getAddress().getIpv4Address().getValue();
- } else {
- addressValue = getAddress().getIpv6Address().getValue();
- }
- */
- double sleepFactor = 1.0;
- int minSleep = 1000;
- Long maxSleep = null;
- Long deadline = null;
- ReconnectStrategy strategy = new TimedReconnectStrategy(GlobalEventExecutor.INSTANCE, getBetweenAttemptsTimeoutMillis(),
- minSleep, sleepFactor, maxSleep, connectionAttempts, deadline);
-
- device.setReconnectStrategy(strategy);
-
- InetAddress addr = InetAddresses.forString(addressValue);
- InetSocketAddress socketAddress = new InetSocketAddress(addr , getPort().intValue());
+ device.setClientConfig(getClientConfig(device));
device.setProcessingExecutor(getGlobalProcessingExecutor());
- device.setSocketAddress(socketAddress);
device.setEventExecutor(getEventExecutorDependency());
- device.setDispatcher(createDispatcher(clientConnectionTimeoutMillis));
+ device.setDispatcher(getClientDispatcher() == null ? createDispatcher() : getClientDispatcherDependency());
device.setSchemaSourceProvider(getGlobalNetconfSchemaProvider(bundleContext));
getDomRegistryDependency().registerProvider(device, bundleContext);
}
private ExecutorService getGlobalProcessingExecutor() {
- if(GLOBAL_PROCESSING_EXECUTOR == null) {
-
- GLOBAL_PROCESSING_EXECUTOR = Executors.newCachedThreadPool();
-
- }
- return GLOBAL_PROCESSING_EXECUTOR;
+ return GLOBAL_PROCESSING_EXECUTOR == null ? Executors.newCachedThreadPool() : GLOBAL_PROCESSING_EXECUTOR;
}
private synchronized AbstractCachingSchemaSourceProvider<String, InputStream> getGlobalNetconfSchemaProvider(BundleContext bundleContext) {
return GLOBAL_NETCONF_SOURCE_PROVIDER;
}
- private NetconfClientDispatcher createDispatcher(long clientConnectionTimeoutMillis) {
- EventLoopGroup bossGroup = getBossThreadGroupDependency();
- EventLoopGroup workerGroup = getWorkerThreadGroupDependency();
- if(getTcpOnly()) {
- return new NetconfClientDispatcher( bossGroup, workerGroup, clientConnectionTimeoutMillis);
- } else {
- AuthenticationHandler authHandler = new LoginPassword(getUsername(),getPassword());
- return new NetconfSshClientDispatcher(authHandler , bossGroup, workerGroup, clientConnectionTimeoutMillis);
- }
+ // FIXME BUG-944 remove backwards compatibility
+ /**
+ * @deprecated Use getClientDispatcherDependency method instead to retrieve injected dispatcher.
+ * This one creates new instance of NetconfClientDispatcher and will be removed in near future.
+ */
+ @Deprecated
+ private NetconfClientDispatcher createDispatcher() {
+ return new NetconfClientDispatcherImpl(getBossThreadGroupDependency(), getWorkerThreadGroupDependency(), new HashedWheelTimer());
}
public void setBundleContext(BundleContext bundleContext) {
this.bundleContext = bundleContext;
}
+
+ public NetconfClientConfiguration getClientConfig(final NetconfDevice device) {
+ InetSocketAddress socketAddress = getSocketAddress();
+ ReconnectStrategy strategy = getReconnectStrategy();
+ long clientConnectionTimeoutMillis = getConnectionTimeoutMillis();
+
+ return NetconfClientConfigurationBuilder.create()
+ .withAddress(socketAddress)
+ .withConnectionTimeoutMillis(clientConnectionTimeoutMillis)
+ .withReconnectStrategy(strategy)
+ .withSessionListener(new NetconfDeviceListener(device))
+ .withAuthHandler(new LoginPassword(getUsername(),getPassword()))
+ .withProtocol(getTcpOnly() ?
+ NetconfClientConfiguration.NetconfClientProtocol.TCP :
+ NetconfClientConfiguration.NetconfClientProtocol.SSH)
+ .build();
+ }
+
+ private ReconnectStrategy getReconnectStrategy() {
+ Long connectionAttempts;
+ if (getMaxConnectionAttempts() != null && getMaxConnectionAttempts() > 0) {
+ connectionAttempts = getMaxConnectionAttempts();
+ } else {
+ logger.trace("Setting {} on {} to infinity", maxConnectionAttemptsJmxAttribute, this);
+ connectionAttempts = null;
+ }
+ double sleepFactor = 1.0;
+ int minSleep = 1000;
+ Long maxSleep = null;
+ Long deadline = null;
+
+ return new TimedReconnectStrategy(GlobalEventExecutor.INSTANCE, getBetweenAttemptsTimeoutMillis(),
+ minSleep, sleepFactor, maxSleep, connectionAttempts, deadline);
+ }
+
+ private InetSocketAddress getSocketAddress() {
+ /*
+ * Uncomment after Switch to IP Address
+ if(getAddress().getIpv4Address() != null) {
+ addressValue = getAddress().getIpv4Address().getValue();
+ } else {
+ addressValue = getAddress().getIpv6Address().getValue();
+ }
+ */
+ InetAddress inetAddress = InetAddresses.forString(getAddress());
+ return new InetSocketAddress(inetAddress, getPort().intValue());
+ }
}
import static org.opendaylight.controller.sal.connect.netconf.NetconfMapping.toRpcMessage;
import static org.opendaylight.controller.sal.connect.netconf.NetconfMapping.wrap;
+import com.google.common.base.Preconditions;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.net.URI;
import org.opendaylight.controller.md.sal.common.api.data.DataModification;
import org.opendaylight.controller.md.sal.common.api.data.DataReader;
import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration;
import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration;
import org.opendaylight.controller.sal.core.api.Provider;
private boolean rollbackSupported;
+ private NetconfClientConfiguration clientConfig;
public NetconfDevice(String name) {
this.name = name;
checkState(schemaSourceProvider != null, "Schema Source Provider must be set.");
checkState(eventExecutor != null, "Event executor must be set.");
- listener = new NetconfDeviceListener(this);
+ Preconditions.checkArgument(clientConfig.getSessionListener() instanceof NetconfDeviceListener);
+ listener = (NetconfDeviceListener) clientConfig.getSessionListener();
logger.info("Starting NETCONF Client {} for address {}", name, socketAddress);
- dispatcher.createClient(socketAddress, listener, reconnectStrategy);
+ dispatcher.createClient(clientConfig);
}
Optional<SchemaContext> getSchemaContext() {
logger.debug("Client capabilities {}", capabilities);
for (QName capability : capabilities) {
- it.addLeaf(NETCONF_INVENTORY_INITIAL_CAPABILITY, capability);
+ it.addLeaf(NETCONF_INVENTORY_INITIAL_CAPABILITY, capability.toString());
}
logger.debug("Update device state transaction " + transaction.getIdentifier()
public void setDispatcher(final NetconfClientDispatcher dispatcher) {
this.dispatcher = dispatcher;
}
+
+ public void setClientConfig(final NetconfClientConfiguration clientConfig) {
+ this.clientConfig = clientConfig;
+ }
+
}
class NetconfDeviceSchemaContextProvider {
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
-class NetconfDeviceListener implements NetconfClientSessionListener {
-
+public class NetconfDeviceListener implements NetconfClientSessionListener {
private static final class Request {
final UncancellableFuture<RpcResult<CompositeNode>> future;
final NetconfMessage request;
SchemaContext schemaContext = ctx.get();
Set<NotificationDefinition> notifications = schemaContext.getNotifications();
Document document = message.getDocument();
- return XmlDocumentUtils.notificationToDomNodes(document, Optional.fromNullable(notifications));
+ return XmlDocumentUtils.notificationToDomNodes(document, Optional.fromNullable(notifications), ctx.get());
}
return null;
}
rawRpc = it.toInstance();
// sys(xmlData)
} else {
- rawRpc = (CompositeNode) toCompositeNode(message.getDocument());
+ rawRpc = (CompositeNode) toCompositeNode(message, context);
}
else {
rawRpc = (CompositeNode) toCompositeNode(message.getDocument());
return Optional.of(schemaBody);
}
}
- logger.warn("YANG shcema was not successfully retrieved.");
+ logger.warn("YANG shcema was not successfully retrieved. Errors: {}", schemaReply.getErrors());
} catch (InterruptedException | ExecutionException e) {
logger.warn("YANG shcema was not successfully retrieved.", e);
}
import threadpool {prefix th;}
import netty {prefix netty;}
import opendaylight-md-sal-dom {prefix dom;}
+ import odl-netconf-cfg { prefix cfg-net; revision-date 2014-04-08; }
description
"Service definition for Binding Aware MD-SAL.";
-
+
revision "2013-10-28" {
description
"Initial revision";
leaf address {
type string;
}
-
+
leaf port {
type uint32;
}
augment "/config:modules/config:module/config:configuration" {
case sal-netconf-connector {
when "/config:modules/config:module/config:type = 'sal-netconf-connector'";
-
+
leaf address {
type string;
}
leaf port {
type uint32;
}
-
+
leaf tcp-only {
type boolean;
}
leaf username {
type string;
}
-
+
leaf password {
type string;
}
+
container dom-registry {
uses config:service-ref {
refine type {
}
}
+ // FIXME BUG-944 remove backwards compatibility
+ // Deprecated, replaced by client dispatcher.
+ // This dependency will be removed in near future and all configurations of netconf-connector need to be changed to use dispatcher dependency.
container boss-thread-group {
uses config:service-ref {
refine type {
+ mandatory false;
config:required-identity netty:netty-threadgroup;
}
}
}
+ // FIXME BUG-944 remove backwards compatibility
+ // Deprecated, replaced by client dispatcher.
+ // This dependency will be removed in near future and all configurations of netconf-connector need to be changed to use dispatcher dependency.
container worker-thread-group {
uses config:service-ref {
refine type {
+ mandatory false;
config:required-identity netty:netty-threadgroup;
}
}
}
}
+ // Replaces thread group dependencies
+ container client-dispatcher {
+ uses config:service-ref {
+ refine type {
+ mandatory false;
+ config:required-identity cfg-net:netconf-client-dispatcher;
+ }
+ }
+ }
+
leaf connection-timeout-millis {
description "Specifies timeout in milliseconds after which connection must be established.";
type uint32;
default 0; // retry forever
}
-
leaf between-attempts-timeout-millis {
description "Timeout in milliseconds to wait between connection attempts.";
type uint16;
}
if (node instanceof CompositeNodeWrapper) {
if ((node as CompositeNodeWrapper).changeAllowed) {
- normalizeNode(node as CompositeNodeWrapper, schema, null, mountPoint)
+ try {
+ normalizeNode(node as CompositeNodeWrapper, schema, null, mountPoint)
+ } catch (NumberFormatException e) {
+ throw new ResponseException(BAD_REQUEST,e.message)
+ }
}
return (node as CompositeNodeWrapper).unwrap()
}
--- /dev/null
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.FileNotFoundException;
+
+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.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.sal.rest.impl.JsonToCompositeNodeProvider;
+import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider;
+import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider;
+import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider;
+import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
+import org.opendaylight.controller.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+public class CodecsExceptionsCatchingTest extends JerseyTest {
+
+ private static RestconfImpl restConf;
+ private static ControllerContext controllerContext = ControllerContext.getInstance();
+
+ @BeforeClass
+ public static void init() throws FileNotFoundException {
+ restConf = RestconfImpl.getInstance();
+ controllerContext = ControllerContext.getInstance();
+ SchemaContext schemaContext = TestUtils.loadSchemaContext("/decoding-exception/yang");
+ controllerContext.setGlobalSchema(schemaContext);
+ restConf.setControllerContext(controllerContext);
+ }
+
+ @Override
+ protected Application configure() {
+ /* enable/disable Jersey logs to console */
+ // 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(restConf, StructuredDataToXmlProvider.INSTANCE,
+ StructuredDataToJsonProvider.INSTANCE, XmlToCompositeNodeProvider.INSTANCE,
+ JsonToCompositeNodeProvider.INSTANCE);
+ return resourceConfig;
+ }
+
+ @Test
+ public void StringToNumberConversionError() {
+ Response response = target("/config/number:cont").request(MediaType.APPLICATION_XML).put(
+ Entity.entity("<cont xmlns=\"number\"><lf>3f</lf></cont>", MediaType.APPLICATION_XML));
+ String exceptionMessage = response.readEntity(String.class);
+ assertTrue(exceptionMessage.contains("Incorrect lexical representation of Integer value: 3f"));
+ }
+}
\ No newline at end of file
--- /dev/null
+ module number {
+
+ namespace "number";
+ prefix "number";
+
+ revision 2014-04-24 {
+ }
+
+
+
+ container cont {
+ leaf lf {
+ type uint8;
+ }
+
+ }
+ }
</dependencies>
<build>
- <pluginManagement>
- <plugins>
- <!--This plugin's configuration is used to store Eclipse
- m2e settings only. It has no influence on the Maven build itself. -->
- <plugin>
- <groupId>org.eclipse.m2e</groupId>
- <artifactId>lifecycle-mapping</artifactId>
- <version>1.0.0</version>
- <configuration>
- <lifecycleMappingMetadata>
- <pluginExecutions>
- <pluginExecution>
- <pluginExecutionFilter>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-maven-plugin</artifactId>
- <versionRange>[0.5,)</versionRange>
- <goals>
- <goal>generate-sources</goal>
- </goals>
- </pluginExecutionFilter>
- <action>
- <ignore></ignore>
- </action>
- </pluginExecution>
- </pluginExecutions>
- </lifecycleMappingMetadata>
- </configuration>
- </plugin>
- </plugins>
- </pluginManagement>
<plugins>
<plugin>
<groupId>org.opendaylight.yangtools</groupId>
private static final Logger logger = LoggerFactory.getLogger(AbstractListeningStatsTracker.class);
private ListenerRegistration<?> reg;
- protected AbstractListeningStatsTracker(FlowCapableContext context, long lifetimeNanos) {
- super(context, lifetimeNanos);
+ protected AbstractListeningStatsTracker(FlowCapableContext context) {
+ super(context);
}
protected abstract InstanceIdentifier<?> listenPath();
abstract class AbstractStatsTracker<I, K> {
private static final Logger logger = LoggerFactory.getLogger(AbstractStatsTracker.class);
+
+ private static final int WAIT_FOR_REQUEST_CYCLE = 2;
+
private final FutureCallback<RpcResult<? extends TransactionAware>> callback =
new FutureCallback<RpcResult<? extends TransactionAware>>() {
@Override
private final Map<K, Long> trackedItems = new HashMap<>();
private final FlowCapableContext context;
- private final long lifetimeNanos;
+ private long requestCounter;
- protected AbstractStatsTracker(final FlowCapableContext context, final long lifetimeNanos) {
+ protected AbstractStatsTracker(final FlowCapableContext context) {
this.context = Preconditions.checkNotNull(context);
- this.lifetimeNanos = lifetimeNanos;
+ this.requestCounter = 0;
}
protected final InstanceIdentifierBuilder<Node> getNodeIdentifierBuilder() {
return context.startDataModification();
}
+ public final synchronized void increaseRequestCounter(){
+ this.requestCounter++;
+ }
protected abstract void cleanupSingleStat(DataModificationTransaction trans, K item);
protected abstract K updateSingleStat(DataModificationTransaction trans, I item);
+ public abstract void request();
public final synchronized void updateStats(List<I> list) {
- final Long expiryTime = System.nanoTime() + lifetimeNanos;
+
final DataModificationTransaction trans = startTransaction();
for (final I item : list) {
- trackedItems.put(updateSingleStat(trans, item), expiryTime);
+ trackedItems.put(updateSingleStat(trans, item), requestCounter);
}
trans.commit();
}
- public final synchronized void cleanup(final DataModificationTransaction trans, long now) {
+ /**
+ * Statistics will be cleaned up if not update in last two request cycles.
+ * @param trans
+ */
+ public final synchronized void cleanup(final DataModificationTransaction trans) {
for (Iterator<Entry<K, Long>> it = trackedItems.entrySet().iterator();it.hasNext();){
Entry<K, Long> e = it.next();
- if (now > e.getValue()) {
+ if (requestCounter >= e.getValue()+WAIT_FOR_REQUEST_CYCLE) {
cleanupSingleStat(trans, e.getKey());
it.remove();
}
*/
package org.opendaylight.controller.md.statistics.manager;
+import java.util.Collection;
import java.util.Map.Entry;
import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
final class FlowStatsTracker extends AbstractListeningStatsTracker<FlowAndStatisticsMapList, FlowStatsEntry> {
private static final Logger logger = LoggerFactory.getLogger(FlowStatsTracker.class);
private final OpendaylightFlowStatisticsService flowStatsService;
+ private FlowTableStatsTracker flowTableStats;
private int unaccountedFlowsCounter = 1;
- FlowStatsTracker(OpendaylightFlowStatisticsService flowStatsService, final FlowCapableContext context, long lifetimeNanos) {
- super(context, lifetimeNanos);
+ FlowStatsTracker(OpendaylightFlowStatisticsService flowStatsService, final FlowCapableContext context) {
+ super(context);
this.flowStatsService = flowStatsService;
}
+ FlowStatsTracker(OpendaylightFlowStatisticsService flowStatsService, final FlowCapableContext context, FlowTableStatsTracker flowTableStats) {
+ this(flowStatsService, context);
+ this.flowTableStats = flowTableStats;
+ }
@Override
protected void cleanupSingleStat(DataModificationTransaction trans, FlowStatsEntry item) {
return "Flow";
}
+ @Override
+ public void request() {
+ // FIXME: it does not make sense to trigger this before sendAllFlowTablesStatisticsRequest()
+ // comes back -- we do not have any tables anyway.
+ final Collection<TableKey> tables = flowTableStats.getTables();
+ logger.debug("Node {} supports {} table(s)", this.getNodeRef(), tables.size());
+ for (final TableKey key : tables) {
+ logger.debug("Send aggregate stats request for flow table {} to node {}", key.getId(), this.getNodeRef());
+ this.requestAggregateFlows(key);
+ }
+
+ this.requestAllFlowsAllTables();
+
+ }
public void requestAllFlowsAllTables() {
if (flowStatsService != null) {
final GetAllFlowsStatisticsFromAllFlowTablesInputBuilder input = new GetAllFlowsStatisticsFromAllFlowTablesInputBuilder();
private final Set<TableKey> tables = Collections.unmodifiableSet(privateTables);
private final OpendaylightFlowTableStatisticsService flowTableStatsService;
- FlowTableStatsTracker(OpendaylightFlowTableStatisticsService flowTableStatsService, final FlowCapableContext context, long lifetimeNanos) {
- super(context, lifetimeNanos);
+ FlowTableStatsTracker(OpendaylightFlowTableStatisticsService flowTableStatsService, final FlowCapableContext context) {
+ super(context);
this.flowTableStatsService = flowTableStatsService;
}
return item;
}
+ @Override
public void request() {
if (flowTableStatsService != null) {
final GetFlowTablesStatisticsInputBuilder input = new GetFlowTablesStatisticsInputBuilder();
private static final Logger logger = LoggerFactory.getLogger(GroupDescStatsTracker.class);
private final OpendaylightGroupStatisticsService groupStatsService;
- public GroupDescStatsTracker(OpendaylightGroupStatisticsService groupStatsService, final FlowCapableContext context, final long lifetimeNanos) {
- super(context, lifetimeNanos);
+ public GroupDescStatsTracker(OpendaylightGroupStatisticsService groupStatsService, final FlowCapableContext context) {
+ super(context);
this.groupStatsService = groupStatsService;
}
return "Group Descriptor";
}
+ @Override
public void request() {
if (groupStatsService != null) {
final GetGroupDescriptionInputBuilder input = new GetGroupDescriptionInputBuilder();
private static final Logger logger = LoggerFactory.getLogger(GroupStatsTracker.class);
private final OpendaylightGroupStatisticsService groupStatsService;
- GroupStatsTracker(OpendaylightGroupStatisticsService groupStatsService, FlowCapableContext context, long lifetimeNanos) {
- super(context, lifetimeNanos);
+ GroupStatsTracker(OpendaylightGroupStatisticsService groupStatsService, FlowCapableContext context) {
+ super(context);
this.groupStatsService = Preconditions.checkNotNull(groupStatsService);
}
return "Group";
}
+ @Override
public void request() {
final GetAllGroupStatisticsInputBuilder input = new GetAllGroupStatisticsInputBuilder();
input.setNode(getNodeRef());
private static final Logger logger = LoggerFactory.getLogger(MeterConfigStatsTracker.class);
private final OpendaylightMeterStatisticsService meterStatsService;
- protected MeterConfigStatsTracker(OpendaylightMeterStatisticsService meterStatsService, final FlowCapableContext context, long lifetimeNanos) {
- super(context, lifetimeNanos);
+ protected MeterConfigStatsTracker(OpendaylightMeterStatisticsService meterStatsService, final FlowCapableContext context) {
+ super(context);
this.meterStatsService = meterStatsService;
}
return item;
}
+ @Override
public void request() {
if (meterStatsService != null) {
GetAllMeterConfigStatisticsInputBuilder input = new GetAllMeterConfigStatisticsInputBuilder();
private static final Logger logger = LoggerFactory.getLogger(MeterStatsTracker.class);
private final OpendaylightMeterStatisticsService meterStatsService;
- MeterStatsTracker(OpendaylightMeterStatisticsService meterStatsService, final FlowCapableContext context, long lifetimeNanos) {
- super(context, lifetimeNanos);
+ MeterStatsTracker(OpendaylightMeterStatisticsService meterStatsService, final FlowCapableContext context) {
+ super(context);
this.meterStatsService = meterStatsService;
}
return item;
}
+ @Override
public void request() {
if (meterStatsService != null) {
GetAllMeterStatisticsInputBuilder input = new GetAllMeterStatisticsInputBuilder();
private static final Logger logger = LoggerFactory.getLogger(NodeConnectorStatsTracker.class);
private final OpendaylightPortStatisticsService portStatsService;
- NodeConnectorStatsTracker(final OpendaylightPortStatisticsService portStatsService, final FlowCapableContext context, long lifetimeNanos) {
- super(context, lifetimeNanos);
+ NodeConnectorStatsTracker(final OpendaylightPortStatisticsService portStatsService, final FlowCapableContext context) {
+ super(context);
this.portStatsService = portStatsService;
}
return item;
}
+ @Override
public void request() {
if (portStatsService != null) {
final GetAllNodeConnectorsStatisticsInputBuilder input = new GetAllNodeConnectorsStatisticsInputBuilder();
*/
package org.opendaylight.controller.md.statistics.manager;
-import java.util.Collection;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
private static final int NUMBER_OF_WAIT_CYCLES = 2;
private final MultipartMessageManager msgManager;
+ private final StatisticsRequestScheduler srScheduler;
private final InstanceIdentifier<Node> targetNodeIdentifier;
private final FlowStatsTracker flowStats;
private final FlowTableStatsTracker flowTableStats;
final OpendaylightGroupStatisticsService groupStatsService,
final OpendaylightMeterStatisticsService meterStatsService,
final OpendaylightPortStatisticsService portStatsService,
- final OpendaylightQueueStatisticsService queueStatsService) {
+ final OpendaylightQueueStatisticsService queueStatsService,
+ final StatisticsRequestScheduler srScheduler) {
this.dps = Preconditions.checkNotNull(dps);
this.targetNodeKey = Preconditions.checkNotNull(nodeKey);
+ this.srScheduler = Preconditions.checkNotNull(srScheduler);
this.targetNodeIdentifier = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey).build();
this.targetNodeRef = new NodeRef(targetNodeIdentifier);
final long lifetimeNanos = TimeUnit.MILLISECONDS.toNanos(STATS_COLLECTION_MILLIS * NUMBER_OF_WAIT_CYCLES);
msgManager = new MultipartMessageManager(lifetimeNanos);
- flowStats = new FlowStatsTracker(flowStatsService, this, lifetimeNanos);
- flowTableStats = new FlowTableStatsTracker(flowTableStatsService, this, lifetimeNanos);
- groupDescStats = new GroupDescStatsTracker(groupStatsService, this, lifetimeNanos);
- groupStats = new GroupStatsTracker(groupStatsService, this, lifetimeNanos);
- meterConfigStats = new MeterConfigStatsTracker(meterStatsService, this, lifetimeNanos);
- meterStats = new MeterStatsTracker(meterStatsService, this, lifetimeNanos);
- nodeConnectorStats = new NodeConnectorStatsTracker(portStatsService, this, lifetimeNanos);
- queueStats = new QueueStatsTracker(queueStatsService, this, lifetimeNanos);
+ flowTableStats = new FlowTableStatsTracker(flowTableStatsService, this);
+ flowStats = new FlowStatsTracker(flowStatsService, this, flowTableStats);
+ groupDescStats = new GroupDescStatsTracker(groupStatsService, this);
+ groupStats = new GroupStatsTracker(groupStatsService, this);
+ meterConfigStats = new MeterConfigStatsTracker(meterStatsService, this);
+ meterStats = new MeterStatsTracker(meterStatsService, this);
+ nodeConnectorStats = new NodeConnectorStatsTracker(portStatsService, this);
+ queueStats = new QueueStatsTracker(queueStatsService, this);
}
public NodeKey getTargetNodeKey() {
@Override
public DataModificationTransaction startDataModification() {
- return dps.beginTransaction();
+ DataModificationTransaction dmt = dps.beginTransaction();
+ dmt.registerListener(this.srScheduler);
+ return dmt;
}
public synchronized void updateGroupDescStats(TransactionAware transaction, List<GroupDescStats> list) {
public synchronized void updateAggregateFlowStats(TransactionAware transaction, AggregateFlowStatistics flowStats) {
final Short tableId = msgManager.isExpectedTableTransaction(transaction);
if (tableId != null) {
- final DataModificationTransaction trans = dps.beginTransaction();
+ final DataModificationTransaction trans = this.startDataModification();
InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
.augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
}
public synchronized void updateGroupFeatures(GroupFeatures notification) {
- final DataModificationTransaction trans = dps.beginTransaction();
+ final DataModificationTransaction trans = this.startDataModification();
final NodeBuilder nodeData = new NodeBuilder();
nodeData.setKey(targetNodeKey);
}
public synchronized void updateMeterFeatures(MeterFeatures features) {
- final DataModificationTransaction trans = dps.beginTransaction();
+ final DataModificationTransaction trans = this.startDataModification();
final NodeBuilder nodeData = new NodeBuilder();
nodeData.setKey(targetNodeKey);
}
public synchronized void cleanStaleStatistics() {
- final DataModificationTransaction trans = dps.beginTransaction();
- final long now = System.nanoTime();
-
- flowStats.cleanup(trans, now);
- groupDescStats.cleanup(trans, now);
- groupStats.cleanup(trans, now);
- meterConfigStats.cleanup(trans, now);
- meterStats.cleanup(trans, now);
- nodeConnectorStats.cleanup(trans, now);
- queueStats.cleanup(trans, now);
+ final DataModificationTransaction trans = this.startDataModification();
+
+ flowStats.cleanup(trans);
+ groupDescStats.cleanup(trans);
+ groupStats.cleanup(trans);
+ meterConfigStats.cleanup(trans);
+ meterStats.cleanup(trans);
+ nodeConnectorStats.cleanup(trans);
+ queueStats.cleanup(trans);
msgManager.cleanStaleTransactionIds();
trans.commit();
public synchronized void requestPeriodicStatistics() {
logger.debug("Send requests for statistics collection to node : {}", targetNodeKey);
- flowTableStats.request();
-
- // FIXME: it does not make sense to trigger this before sendAllFlowTablesStatisticsRequest()
- // comes back -- we do not have any tables anyway.
- final Collection<TableKey> tables = flowTableStats.getTables();
- logger.debug("Node {} supports {} table(s)", targetNodeKey, tables.size());
- for (final TableKey key : tables) {
- logger.debug("Send aggregate stats request for flow table {} to node {}", key.getId(), targetNodeKey);
- flowStats.requestAggregateFlows(key);
- }
-
- flowStats.requestAllFlowsAllTables();
- nodeConnectorStats.request();
- groupStats.request();
- groupDescStats.request();
- meterStats.request();
- meterConfigStats.request();
- queueStats.request();
+ this.srScheduler.addRequestToSchedulerQueue(flowTableStats);
+
+ this.srScheduler.addRequestToSchedulerQueue(flowStats);
+
+ this.srScheduler.addRequestToSchedulerQueue(nodeConnectorStats);
+
+ this.srScheduler.addRequestToSchedulerQueue(groupStats);
+
+ this.srScheduler.addRequestToSchedulerQueue(groupDescStats);
+
+ this.srScheduler.addRequestToSchedulerQueue(meterStats);
+
+ this.srScheduler.addRequestToSchedulerQueue(meterConfigStats);
+
+ this.srScheduler.addRequestToSchedulerQueue(queueStats);
}
-
+
public synchronized void start(final Timer timer) {
flowStats.start(dps);
groupDescStats.start(dps);
private static final Logger logger = LoggerFactory.getLogger(QueueStatsTracker.class);
private final OpendaylightQueueStatisticsService queueStatsService;
- QueueStatsTracker(OpendaylightQueueStatisticsService queueStatsService, final FlowCapableContext context, long lifetimeNanos) {
- super(context, lifetimeNanos);
+ QueueStatsTracker(OpendaylightQueueStatisticsService queueStatsService, final FlowCapableContext context) {
+ super(context);
this.queueStatsService = queueStatsService;
}
return queueEntry;
}
+ @Override
public void request() {
if (queueStatsService != null) {
GetAllQueuesStatisticsFromAllPortsInputBuilder input = new GetAllQueuesStatisticsFromAllPortsInputBuilder();
private OpendaylightFlowTableStatisticsService flowTableStatsService;
private OpendaylightQueueStatisticsService queueStatsService;
+
+ private final StatisticsRequestScheduler srScheduler;
public StatisticsProvider(final DataProviderService dataService) {
this.dps = Preconditions.checkNotNull(dataService);
+ this.srScheduler = new StatisticsRequestScheduler();
}
private final StatisticsListener updateCommiter = new StatisticsListener(StatisticsProvider.this);
portStatsService = rpcRegistry.getRpcService(OpendaylightPortStatisticsService.class);
flowTableStatsService = rpcRegistry.getRpcService(OpendaylightFlowTableStatisticsService.class);
queueStatsService = rpcRegistry.getRpcService(OpendaylightQueueStatisticsService.class);
-
+ this.srScheduler.start();
+
// Start receiving notifications
this.listenerRegistration = nps.registerNotificationListener(this.updateCommiter);
final NodeStatisticsHandler h = new NodeStatisticsHandler(dps, key,
flowStatsService, flowTableStatsService, groupStatsService,
- meterStatsService, portStatsService, queueStatsService);
+ meterStatsService, portStatsService, queueStatsService,srScheduler);
final NodeStatisticsHandler old = handlers.putIfAbsent(key.getId(), h);
if (old == null) {
spLogger.debug("Started node handler for {}", key.getId());
--- /dev/null
+/*
+ * Copyright IBM Corporation, 2013. 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.md.statistics.manager;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.TimeUnit;
+
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction.DataTransactionListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Main responsibility of the class is to check the MD-SAL data store read/write
+ * transaction accumulation level and send statistics request if number of pending
+ * read/write transactions are zero.
+ * @author avishnoi@in.ibm.com
+ *
+ */
+@SuppressWarnings("rawtypes")
+public class StatisticsRequestScheduler implements DataTransactionListener {
+
+ private static final Logger srsLogger = LoggerFactory.getLogger(StatisticsRequestScheduler.class);
+ private final Timer timer = new Timer("request-monitor", true);
+
+ // We need ordered retrieval, and O(1) contains operation
+ private final Map<AbstractStatsTracker,Integer> requestQueue =
+ Collections.synchronizedMap(new LinkedHashMap<AbstractStatsTracker,Integer>());
+
+ private Long PendingTransactions;
+
+ private long lastRequestTime = System.nanoTime();
+
+ private static final long REQUEST_MONITOR_INTERVAL = 1000;
+
+ private final TimerTask task = new TimerTask() {
+ @Override
+ public void run() {
+ long now = System.nanoTime();
+ if(now > lastRequestTime+TimeUnit.MILLISECONDS.toNanos(REQUEST_MONITOR_INTERVAL)){
+ requestStatistics();
+ }
+ }
+ };
+
+ public StatisticsRequestScheduler(){
+ PendingTransactions = (long) 0;
+ }
+
+ public void addRequestToSchedulerQueue(AbstractStatsTracker statsRequest){
+ requestQueue.put(statsRequest, null);
+ }
+
+ public AbstractStatsTracker getNextRequestFromSchedulerQueue(){
+ //Remove first element
+ AbstractStatsTracker stats = null;
+ synchronized(requestQueue){
+ Iterator<Map.Entry<AbstractStatsTracker, Integer>> nodesItr = requestQueue.entrySet().iterator();
+ if(nodesItr.hasNext()){
+ stats = nodesItr.next().getKey();
+ srsLogger.debug("{} chosen up for execution",stats.getNodeRef());
+ nodesItr.remove();
+ return stats;
+ }
+ }
+ return stats;
+ }
+
+ private void requestStatistics(){
+ AbstractStatsTracker stats = this.getNextRequestFromSchedulerQueue();
+ if(stats != null) {
+ stats.request();
+ stats.increaseRequestCounter();
+ }
+ }
+ @Override
+ public void onStatusUpdated(DataModificationTransaction transaction, TransactionStatus status) {
+
+ AbstractStatsTracker stats = null;
+ synchronized(PendingTransactions){
+ switch(status){
+ case SUBMITED:
+ this.PendingTransactions++;
+ break;
+ case COMMITED:
+ case FAILED:
+ this.PendingTransactions--;
+ if(PendingTransactions == 0){
+ lastRequestTime = System.nanoTime();
+ stats = this.getNextRequestFromSchedulerQueue();
+ }
+ srsLogger.debug("Pending MD-SAL transactions : {} & Scheduler queue size : {}",this.PendingTransactions,this.requestQueue.size());
+ break;
+ default:
+ break;
+ }
+ }
+ if(stats != null){
+ stats.request();
+ stats.increaseRequestCounter();
+ }
+ }
+
+ public void start(){
+ timer.schedule(task, 0, REQUEST_MONITOR_INTERVAL);
+ }
+}
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
<instructions>
- <Export-Package>org.opendaylight.controller.netconf.client,</Export-Package>
+ <Export-Package>org.opendaylight.controller.netconf.client.*,</Export-Package>
<Import-Package>com.google.common.base,
com.google.common.collect,
io.netty.channel,
+++ /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.client;
-
-import io.netty.util.concurrent.Future;
-import io.netty.util.concurrent.GlobalEventExecutor;
-
-import java.io.Closeable;
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.util.Set;
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.protocol.framework.NeverReconnectStrategy;
-import org.opendaylight.protocol.framework.ReconnectStrategy;
-import org.opendaylight.protocol.framework.TimedReconnectStrategy;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Preconditions;
-import com.google.common.base.Stopwatch;
-import com.google.common.collect.Sets;
-
-/**
- * @deprecated Use {@link NetconfClientDispatcher.createClient()} or {@link NetconfClientDispatcher.createReconnectingClient()} instead.
- */
-@Deprecated
-public class NetconfClient implements Closeable {
-
- private static final Logger logger = LoggerFactory.getLogger(NetconfClient.class);
-
- public static final int DEFAULT_CONNECT_TIMEOUT = 5000;
- private final NetconfClientDispatcher dispatch;
- private final String label;
- private final NetconfClientSession clientSession;
- private final NetconfClientSessionListener sessionListener;
- private final long sessionId;
- private final InetSocketAddress address;
-
- // TODO test reconnecting constructor
- public NetconfClient(String clientLabelForLogging, InetSocketAddress address, int connectionAttempts,
- int attemptMsTimeout, NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException {
- this(clientLabelForLogging, address, getReconnectStrategy(connectionAttempts, attemptMsTimeout),
- netconfClientDispatcher);
- }
-
- private NetconfClient(String clientLabelForLogging, InetSocketAddress address, ReconnectStrategy strat, NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException {
- this.label = clientLabelForLogging;
- dispatch = netconfClientDispatcher;
- sessionListener = new SimpleNetconfClientSessionListener();
- Future<NetconfClientSession> clientFuture = dispatch.createClient(address, sessionListener, strat);
- this.address = address;
- clientSession = get(clientFuture);
- this.sessionId = clientSession.getSessionId();
- }
-
- private NetconfClientSession get(Future<NetconfClientSession> clientFuture) throws InterruptedException {
- try {
- return clientFuture.get();
- } catch (CancellationException e) {
- throw new RuntimeException("Cancelling " + this, e);
- } catch (ExecutionException e) {
- throw new IllegalStateException("Unable to create " + this, e);
- }
- }
-
- public static NetconfClient clientFor(String clientLabelForLogging, InetSocketAddress address, ReconnectStrategy strategy, NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException {
- return new NetconfClient(clientLabelForLogging,address,strategy,netconfClientDispatcher);
- }
-
- public static NetconfClient clientFor(String clientLabelForLogging, InetSocketAddress address,
- ReconnectStrategy strategy, NetconfClientDispatcher netconfClientDispatcher, NetconfClientSessionListener listener) throws InterruptedException {
- return new NetconfClient(clientLabelForLogging,address,strategy,netconfClientDispatcher,listener);
- }
-
- public NetconfClient(String clientLabelForLogging, InetSocketAddress address, int connectTimeoutMs,
- NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException {
- this(clientLabelForLogging, address,
- new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE, connectTimeoutMs), netconfClientDispatcher);
- }
-
- public NetconfClient(String clientLabelForLogging, InetSocketAddress address,
- NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException {
- this(clientLabelForLogging, address, new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE,
- DEFAULT_CONNECT_TIMEOUT), netconfClientDispatcher);
- }
-
- public NetconfClient(String clientLabelForLogging, InetSocketAddress address, ReconnectStrategy strategy,
- NetconfClientDispatcher netconfClientDispatcher, NetconfClientSessionListener listener) throws InterruptedException{
- this.label = clientLabelForLogging;
- dispatch = netconfClientDispatcher;
- sessionListener = listener;
- Future<NetconfClientSession> clientFuture = dispatch.createClient(address, sessionListener, strategy);
- this.address = address;
- clientSession = get(clientFuture);
- this.sessionId = clientSession.getSessionId();
- }
-
- public Future<NetconfMessage> sendRequest(NetconfMessage message) {
- return ((SimpleNetconfClientSessionListener)sessionListener).sendRequest(message);
- }
-
- /**
- * @deprecated Use {@link sendRequest} instead
- */
- @Deprecated
- public NetconfMessage sendMessage(NetconfMessage message) throws ExecutionException, InterruptedException, TimeoutException {
- return sendMessage(message, 5, 1000);
- }
-
- /**
- * @deprecated Use {@link sendRequest} instead
- */
- @Deprecated
- public NetconfMessage sendMessage(NetconfMessage message, int attempts, int attemptMsDelay) throws ExecutionException, InterruptedException, TimeoutException {
- final Stopwatch stopwatch = new Stopwatch().start();
-
- try {
- return sendRequest(message).get(attempts * attemptMsDelay, TimeUnit.MILLISECONDS);
- } finally {
- stopwatch.stop();
- logger.debug("Total time spent waiting for response from {}: {} ms", address, stopwatch.elapsed(TimeUnit.MILLISECONDS));
- }
- }
-
- @Override
- public void close() throws IOException {
- clientSession.close();
- }
-
- public NetconfClientDispatcher getNetconfClientDispatcher() {
- return dispatch;
- }
-
- private static ReconnectStrategy getReconnectStrategy(int connectionAttempts, int attemptMsTimeout) {
- return new TimedReconnectStrategy(GlobalEventExecutor.INSTANCE, attemptMsTimeout, 1000, 1.0, null,
- Long.valueOf(connectionAttempts), null);
- }
-
- @Override
- public String toString() {
- final StringBuffer sb = new StringBuffer("NetconfClient{");
- sb.append("label=").append(label);
- sb.append(", sessionId=").append(sessionId);
- sb.append('}');
- return sb.toString();
- }
-
- public long getSessionId() {
- return sessionId;
- }
-
- public Set<String> getCapabilities() {
- Preconditions.checkState(clientSession != null, "Client was not initialized successfully");
- return Sets.newHashSet(clientSession.getServerCapabilities());
- }
-
- public NetconfClientSession getClientSession() {
- return clientSession;
- }
-}
/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2014 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.client;
-import com.google.common.base.Optional;
-import io.netty.channel.EventLoopGroup;
-import io.netty.channel.socket.SocketChannel;
-import io.netty.util.HashedWheelTimer;
import io.netty.util.concurrent.Future;
-import io.netty.util.concurrent.Promise;
-import org.opendaylight.controller.netconf.util.AbstractChannelInitializer;
-import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
-import org.opendaylight.protocol.framework.AbstractDispatcher;
-import org.opendaylight.protocol.framework.ReconnectStrategy;
-import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
-import org.opendaylight.protocol.framework.SessionListenerFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.Closeable;
-import java.net.InetSocketAddress;
-
-public class NetconfClientDispatcher extends AbstractDispatcher<NetconfClientSession, NetconfClientSessionListener> implements Closeable {
-
- private static final Logger logger = LoggerFactory.getLogger(NetconfClientDispatcher.class);
-
- private final NetconfClientSessionNegotiatorFactory negotiatorFactory;
- private final HashedWheelTimer timer;
-
- public NetconfClientDispatcher(EventLoopGroup bossGroup, EventLoopGroup workerGroup,
- long clientConnectionTimeoutMillis) {
- super(bossGroup, workerGroup);
- timer = new HashedWheelTimer();
- this.negotiatorFactory = new NetconfClientSessionNegotiatorFactory(timer,
- Optional.<NetconfHelloMessageAdditionalHeader> absent(), clientConnectionTimeoutMillis);
- }
-
- public NetconfClientDispatcher(EventLoopGroup bossGroup, EventLoopGroup workerGroup,
- NetconfHelloMessageAdditionalHeader additionalHeader, long connectionTimeoutMillis) {
- super(bossGroup, workerGroup);
- timer = new HashedWheelTimer();
- this.negotiatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.of(additionalHeader),
- connectionTimeoutMillis);
- }
-
- public Future<NetconfClientSession> createClient(InetSocketAddress address,
- final NetconfClientSessionListener sessionListener, ReconnectStrategy strat) {
-
- return super.createClient(address, strat, new PipelineInitializer<NetconfClientSession>() {
-
- @Override
- public void initializeChannel(final SocketChannel ch, final Promise<NetconfClientSession> promise) {
- initialize(ch, promise);
- }
-
- private void initialize(SocketChannel ch, Promise<NetconfClientSession> promise) {
- new ClientChannelInitializer(negotiatorFactory, sessionListener).initialize(ch, promise);
- }
- });
- }
-
- public Future<Void> createReconnectingClient(final InetSocketAddress address,
- final NetconfClientSessionListener listener,
- final ReconnectStrategyFactory connectStrategyFactory, final ReconnectStrategy reestablishStrategy) {
- final ClientChannelInitializer init = new ClientChannelInitializer(negotiatorFactory, listener);
-
- return super.createReconnectingClient(address, connectStrategyFactory, reestablishStrategy,
- new PipelineInitializer<NetconfClientSession>() {
- @Override
- public void initializeChannel(final SocketChannel ch, final Promise<NetconfClientSession> promise) {
- init.initialize(ch, promise);
- }
- });
- }
-
- private static final class ClientChannelInitializer extends AbstractChannelInitializer<NetconfClientSession> {
-
- private final NetconfClientSessionNegotiatorFactory negotiatorFactory;
- private final NetconfClientSessionListener sessionListener;
-
- private ClientChannelInitializer(NetconfClientSessionNegotiatorFactory negotiatorFactory,
- NetconfClientSessionListener sessionListener) {
- this.negotiatorFactory = negotiatorFactory;
- this.sessionListener = sessionListener;
- }
+import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration;
+import org.opendaylight.controller.netconf.client.conf.NetconfReconnectingClientConfiguration;
- @Override
- public void initialize(SocketChannel ch, Promise<NetconfClientSession> promise) {
- super.initialize(ch,promise);
- }
+public interface NetconfClientDispatcher {
- @Override
- protected void initializeSessionNegotiator(SocketChannel ch, Promise<NetconfClientSession> promise) {
- ch.pipeline().addAfter(NETCONF_MESSAGE_DECODER, AbstractChannelInitializer.NETCONF_SESSION_NEGOTIATOR,
- negotiatorFactory.getSessionNegotiator(
- new SessionListenerFactory<NetconfClientSessionListener>() {
- @Override
- public NetconfClientSessionListener getSessionListener() {
- return sessionListener;
- }
- }, ch, promise));
- }
- }
+ /**
+ *
+ * Create netconf client. Network communication has to be set up based on network protocol specified in clientConfiguration
+ *
+ * @param clientConfiguration
+ * @return netconf client based on provided configuration
+ */
+ Future<NetconfClientSession> createClient(NetconfClientConfiguration clientConfiguration);
- @Override
- public void close() {
- try {
- timer.stop();
- } catch (Exception e) {
- logger.debug("Ignoring exception while closing {}", timer, e);
- }
- }
+ Future<Void> createReconnectingClient(NetconfReconnectingClientConfiguration clientConfiguration);
}
--- /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.client;
+
+import java.io.Closeable;
+
+import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration;
+import org.opendaylight.controller.netconf.client.conf.NetconfReconnectingClientConfiguration;
+import org.opendaylight.protocol.framework.AbstractDispatcher;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.util.Timer;
+import io.netty.util.concurrent.Future;
+import io.netty.util.concurrent.Promise;
+
+public class NetconfClientDispatcherImpl extends AbstractDispatcher<NetconfClientSession, NetconfClientSessionListener>
+ implements NetconfClientDispatcher, Closeable {
+
+ private static final Logger logger = LoggerFactory.getLogger(NetconfClientDispatcherImpl.class);
+
+ private final Timer timer;
+
+ public NetconfClientDispatcherImpl(final EventLoopGroup bossGroup, final EventLoopGroup workerGroup, final Timer timer) {
+ super(bossGroup, workerGroup);
+ this.timer = timer;
+ }
+
+ @Override
+ public Future<NetconfClientSession> createClient(final NetconfClientConfiguration clientConfiguration) {
+ switch (clientConfiguration.getProtocol()) {
+ case TCP:
+ return createTcpClient(clientConfiguration);
+ case SSH:
+ return createSshClient(clientConfiguration);
+ }
+ throw new IllegalArgumentException("Unknown client protocol " + clientConfiguration.getProtocol());
+ }
+
+ @Override
+ public Future<Void> createReconnectingClient(final NetconfReconnectingClientConfiguration clientConfiguration) {
+ switch (clientConfiguration.getProtocol()) {
+ case TCP: return createReconnectingTcpClient(clientConfiguration);
+ case SSH: return createReconnectingSshClient(clientConfiguration);
+ default: throw new IllegalArgumentException("Unknown client protocol " + clientConfiguration.getProtocol());
+ }
+ }
+
+ private Future<NetconfClientSession> createTcpClient(final NetconfClientConfiguration currentConfiguration) {
+ logger.debug("Creating TCP client with configuration: {}", currentConfiguration);
+ return super.createClient(currentConfiguration.getAddress(), currentConfiguration.getReconnectStrategy(),
+ new PipelineInitializer<NetconfClientSession>() {
+
+ @Override
+ public void initializeChannel(final SocketChannel ch, final Promise<NetconfClientSession> promise) {
+ initialize(ch, promise);
+ }
+
+ private void initialize(final SocketChannel ch, final Promise<NetconfClientSession> promise) {
+ new TcpClientChannelInitializer(getNegotiatorFactory(currentConfiguration), currentConfiguration
+ .getSessionListener()).initialize(ch, promise);
+ }
+ });
+ }
+
+ private Future<Void> createReconnectingTcpClient(final NetconfReconnectingClientConfiguration currentConfiguration) {
+ logger.debug("Creating reconnecting TCP client with configuration: {}", currentConfiguration);
+ final TcpClientChannelInitializer init = new TcpClientChannelInitializer(getNegotiatorFactory(currentConfiguration),
+ currentConfiguration.getSessionListener());
+
+ return super.createReconnectingClient(currentConfiguration.getAddress(), currentConfiguration.getConnectStrategyFactory(),
+ currentConfiguration.getReconnectStrategy(), new PipelineInitializer<NetconfClientSession>() {
+ @Override
+ public void initializeChannel(final SocketChannel ch, final Promise<NetconfClientSession> promise) {
+ init.initialize(ch, promise);
+ }
+ });
+ }
+
+ private Future<NetconfClientSession> createSshClient(final NetconfClientConfiguration currentConfiguration) {
+ logger.debug("Creating SSH client with configuration: {}", currentConfiguration);
+ return super.createClient(currentConfiguration.getAddress(), currentConfiguration.getReconnectStrategy(),
+ new PipelineInitializer<NetconfClientSession>() {
+
+ @Override
+ public void initializeChannel(final SocketChannel ch,
+ final Promise<NetconfClientSession> sessionPromise) {
+ new SshClientChannelInitializer(currentConfiguration.getAuthHandler(),
+ getNegotiatorFactory(currentConfiguration), currentConfiguration.getSessionListener())
+ .initialize(ch, sessionPromise);
+ }
+
+ });
+ }
+
+ private Future<Void> createReconnectingSshClient(final NetconfReconnectingClientConfiguration currentConfiguration) {
+ logger.debug("Creating reconnecting SSH client with configuration: {}", currentConfiguration);
+ final SshClientChannelInitializer init = new SshClientChannelInitializer(currentConfiguration.getAuthHandler(),
+ getNegotiatorFactory(currentConfiguration), currentConfiguration.getSessionListener());
+
+ return super.createReconnectingClient(currentConfiguration.getAddress(), currentConfiguration.getConnectStrategyFactory(), currentConfiguration.getReconnectStrategy(),
+ new PipelineInitializer<NetconfClientSession>() {
+ @Override
+ public void initializeChannel(final SocketChannel ch, final Promise<NetconfClientSession> promise) {
+ init.initialize(ch, promise);
+ }
+ });
+ }
+
+ protected NetconfClientSessionNegotiatorFactory getNegotiatorFactory(final NetconfClientConfiguration cfg) {
+ return new NetconfClientSessionNegotiatorFactory(timer, cfg.getAdditionalHeader(),
+ cfg.getConnectionTimeoutMillis());
+ }
+}
package org.opendaylight.controller.netconf.client;
-import io.netty.channel.Channel;
+import java.util.Collection;
+
import org.opendaylight.controller.netconf.util.AbstractNetconfSession;
import org.opendaylight.controller.netconf.util.handler.NetconfEXICodec;
import org.opendaylight.controller.netconf.util.handler.NetconfEXIToMessageDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.Collection;
+import io.netty.channel.Channel;
public final class NetconfClientSession extends AbstractNetconfSession<NetconfClientSession, NetconfClientSessionListener> {
return capabilities;
}
-
@Override
protected NetconfClientSession thisInstance() {
return this;
package org.opendaylight.controller.netconf.client;
-import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
-import io.netty.util.Timer;
-import io.netty.util.concurrent.Promise;
+import java.util.Collection;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+
import org.opendaylight.controller.netconf.api.NetconfClientSessionPreferences;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.util.AbstractNetconfSessionNegotiator;
import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
import org.opendaylight.controller.netconf.util.messages.NetconfMessageUtil;
+import org.opendaylight.controller.netconf.util.messages.NetconfStartExiMessage;
import org.opendaylight.controller.netconf.util.xml.XMLNetconfUtil;
import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
-import javax.xml.xpath.XPathConstants;
-import javax.xml.xpath.XPathExpression;
+import io.netty.channel.Channel;
+import io.netty.util.Timer;
+import io.netty.util.concurrent.Promise;
public class NetconfClientSessionNegotiator extends
AbstractNetconfSessionNegotiator<NetconfClientSessionPreferences, NetconfClientSession, NetconfClientSessionListener>
@Override
protected void handleMessage(NetconfHelloMessage netconfMessage) throws NetconfDocumentedException {
- NetconfClientSession session = super.getSessionForHelloMessage(netconfMessage);
-
- if (shouldUseExi(netconfMessage.getDocument())){
- logger.debug("Netconf session: {} should use exi.", session);
- tryToStartExi(session);
+ final NetconfClientSession session = getSessionForHelloMessage(netconfMessage);
+ replaceHelloMessageInboundHandler(session);
+
+ // If exi should be used, try to initiate exi communication
+ // Call negotiationSuccessFul after exi negotiation is finished successfully or not
+ if (shouldUseExi(netconfMessage)) {
+ logger.debug("Netconf session {} should use exi.", session);
+ NetconfStartExiMessage startExiMessage = (NetconfStartExiMessage) sessionPreferences.getStartExiMessage();
+ tryToInitiateExi(session, startExiMessage);
+ // Exi is not supported, release session immediately
} else {
- logger.debug("Netconf session {} isn't capable using exi.", session);
+ logger.debug("Netconf session {} isn't capable of using exi.", session);
negotiationSuccessful(session);
}
}
- private boolean shouldUseExi(Document doc) {
- return containsExi10Capability(doc)
+ /**
+ * Initiates exi communication by sending start-exi message and waiting for positive/negative response.
+ *
+ * @param startExiMessage
+ */
+ void tryToInitiateExi(final NetconfClientSession session, final NetconfStartExiMessage startExiMessage) {
+ channel.pipeline().addAfter(AbstractChannelInitializer.NETCONF_MESSAGE_DECODER,
+ ExiConfirmationInboundHandler.EXI_CONFIRMED_HANDLER,
+ new ExiConfirmationInboundHandler(session, startExiMessage));
+
+ session.sendMessage(startExiMessage).addListener(new ChannelFutureListener() {
+ @Override
+ public void operationComplete(final ChannelFuture f) {
+ if (!f.isSuccess()) {
+ logger.warn("Failed to send start-exi message {} on session {}", startExiMessage, this, f.cause());
+ channel.pipeline().remove(ExiConfirmationInboundHandler.EXI_CONFIRMED_HANDLER);
+ } else {
+ logger.trace("Start-exi message {} sent to socket on session {}", startExiMessage, this);
+ }
+ }
+ });
+ }
+
+ private boolean shouldUseExi(NetconfHelloMessage helloMsg) {
+ return containsExi10Capability(helloMsg.getDocument())
&& containsExi10Capability(sessionPreferences.getHelloMessage().getDocument());
}
return false;
}
- private void tryToStartExi(final NetconfClientSession session) {
- final NetconfMessage startExi = sessionPreferences.getStartExiMessage();
- session.sendMessage(startExi).addListener(new ChannelFutureListener() {
- @Override
- public void operationComplete(final ChannelFuture f) {
- if (!f.isSuccess()) {
- logger.warn("Failed to send start-exi message {} on session {}", startExi, session, f.cause());
- } else {
- logger.trace("Start-exi message {} sent to socket on session {}", startExi, session);
- NetconfClientSessionNegotiator.this.channel.pipeline().addAfter(
- AbstractChannelInitializer.NETCONF_MESSAGE_DECODER, ExiConfirmationInboundHandler.EXI_CONFIRMED_HANDLER,
- new ExiConfirmationInboundHandler(session));
- }
- }
- });
- }
-
private long extractSessionId(Document doc) {
final Node sessionIdNode = (Node) XmlUtil.evaluateXPath(sessionIdXPath, doc, XPathConstants.NODE);
String textContent = sessionIdNode.getTextContent();
}
@Override
- protected NetconfClientSession getSession(NetconfClientSessionListener sessionListener, Channel channel, NetconfHelloMessage message) throws NetconfDocumentedException {
- return new NetconfClientSession(sessionListener, channel, extractSessionId(message.getDocument()),
- NetconfMessageUtil.extractCapabilitiesFromHello(message.getDocument()));
+ protected NetconfClientSession getSession(NetconfClientSessionListener sessionListener, Channel channel,
+ NetconfHelloMessage message) throws NetconfDocumentedException {
+ long sessionId = extractSessionId(message.getDocument());
+ Collection<String> capabilities = NetconfMessageUtil.extractCapabilitiesFromHello(message.getDocument());
+ return new NetconfClientSession(sessionListener, channel, sessionId, capabilities);
}
/**
private static final String EXI_CONFIRMED_HANDLER = "exiConfirmedHandler";
private final NetconfClientSession session;
+ private NetconfStartExiMessage startExiMessage;
- ExiConfirmationInboundHandler(NetconfClientSession session) {
+ ExiConfirmationInboundHandler(NetconfClientSession session, final NetconfStartExiMessage startExiMessage) {
this.session = session;
+ this.startExiMessage = startExiMessage;
}
@Override
if (NetconfMessageUtil.isOKMessage(netconfMessage)) {
logger.trace("Positive response on start-exi call received on session {}", session);
try {
- session.startExiCommunication(sessionPreferences.getStartExiMessage());
+ session.startExiCommunication(startExiMessage);
} catch (RuntimeException e) {
// Unable to add exi, continue without exi
logger.warn("Unable to start exi communication, Communication will continue without exi on session {}", session, e);
}
- // Error response
+ // Error response
} else if(NetconfMessageUtil.isErrorMessage(netconfMessage)) {
logger.warn(
"Error response to start-exi message {}, Communication will continue without exi on session {}",
XmlUtil.toString(netconfMessage.getDocument()), session);
- // Unexpected response to start-exi, throwing message away, continue without exi
+ // Unexpected response to start-exi, throwing message away, continue without exi
} else {
logger.warn(
"Unexpected response to start-exi message, should be ok, was {}, " +
negotiationSuccessful(session);
}
}
+
}
throw new IllegalStateException(e);
}
- NetconfClientSessionPreferences proposal = new NetconfClientSessionPreferences(helloMessage,startExiMessage);
+ NetconfClientSessionPreferences proposal = new NetconfClientSessionPreferences(helloMessage, startExiMessage);
return new NetconfClientSessionNegotiator(proposal, promise, channel, timer,
sessionListenerFactory.getSessionListener(),connectionTimeoutMillis);
}
+++ /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.client;
-
-import io.netty.channel.EventLoopGroup;
-import io.netty.channel.socket.SocketChannel;
-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.util.AbstractChannelInitializer;
-import org.opendaylight.controller.netconf.util.handler.ssh.SshHandler;
-import org.opendaylight.controller.netconf.util.handler.ssh.authentication.AuthenticationHandler;
-import org.opendaylight.controller.netconf.util.handler.ssh.client.Invoker;
-import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
-import org.opendaylight.protocol.framework.ReconnectStrategy;
-import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
-import org.opendaylight.protocol.framework.SessionListenerFactory;
-
-import com.google.common.base.Optional;
-
-public class NetconfSshClientDispatcher extends NetconfClientDispatcher {
-
- private final AuthenticationHandler authHandler;
- private final HashedWheelTimer timer;
- private final NetconfClientSessionNegotiatorFactory negotiatorFactory;
-
- public NetconfSshClientDispatcher(AuthenticationHandler authHandler, EventLoopGroup bossGroup,
- EventLoopGroup workerGroup, long connectionTimeoutMillis) {
- super(bossGroup, workerGroup, connectionTimeoutMillis);
- this.authHandler = authHandler;
- this.timer = new HashedWheelTimer();
- this.negotiatorFactory = new NetconfClientSessionNegotiatorFactory(timer,
- Optional.<NetconfHelloMessageAdditionalHeader> absent(), connectionTimeoutMillis);
- }
-
- public NetconfSshClientDispatcher(AuthenticationHandler authHandler, EventLoopGroup bossGroup,
- EventLoopGroup workerGroup, NetconfHelloMessageAdditionalHeader additionalHeader, long socketTimeoutMillis) {
- super(bossGroup, workerGroup, additionalHeader, socketTimeoutMillis);
- this.authHandler = authHandler;
- this.timer = new HashedWheelTimer();
- this.negotiatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.of(additionalHeader),
- socketTimeoutMillis);
- }
-
- @Override
- public Future<NetconfClientSession> createClient(InetSocketAddress address,
- final NetconfClientSessionListener sessionListener, ReconnectStrategy strat) {
- return super.createClient(address, strat, new PipelineInitializer<NetconfClientSession>() {
-
- @Override
- public void initializeChannel(SocketChannel arg0, Promise<NetconfClientSession> arg1) {
- new NetconfSshClientInitializer(authHandler, negotiatorFactory, sessionListener).initialize(arg0, arg1);
- }
-
- });
- }
-
- @Override
- public Future<Void> createReconnectingClient(final InetSocketAddress address,
- final NetconfClientSessionListener listener,
- final ReconnectStrategyFactory connectStrategyFactory, final ReconnectStrategy reestablishStrategy) {
- final NetconfSshClientInitializer init = new NetconfSshClientInitializer(authHandler, negotiatorFactory, listener);
-
- return super.createReconnectingClient(address, connectStrategyFactory, reestablishStrategy,
- new PipelineInitializer<NetconfClientSession>() {
- @Override
- public void initializeChannel(final SocketChannel ch, final Promise<NetconfClientSession> promise) {
- init.initialize(ch, promise);
- }
- });
- }
-
- private static final class NetconfSshClientInitializer extends AbstractChannelInitializer<NetconfClientSession> {
-
- private final AuthenticationHandler authenticationHandler;
- private final NetconfClientSessionNegotiatorFactory negotiatorFactory;
- private final NetconfClientSessionListener sessionListener;
-
- public NetconfSshClientInitializer(AuthenticationHandler authHandler,
- NetconfClientSessionNegotiatorFactory negotiatorFactory,
- final NetconfClientSessionListener sessionListener) {
- this.authenticationHandler = authHandler;
- this.negotiatorFactory = negotiatorFactory;
- this.sessionListener = sessionListener;
- }
-
- @Override
- public void initialize(SocketChannel ch, Promise<NetconfClientSession> promise) {
- try {
- Invoker invoker = Invoker.subsystem("netconf");
- ch.pipeline().addFirst(new SshHandler(authenticationHandler, invoker));
- super.initialize(ch,promise);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- @Override
- protected void initializeSessionNegotiator(SocketChannel ch,
- Promise<NetconfClientSession> promise) {
- ch.pipeline().addAfter(NETCONF_MESSAGE_DECODER, AbstractChannelInitializer.NETCONF_SESSION_NEGOTIATOR,
- negotiatorFactory.getSessionNegotiator(new SessionListenerFactory<NetconfClientSessionListener>() {
- @Override
- public NetconfClientSessionListener getSessionListener() {
- return sessionListener;
- }
- }, ch, promise));
- }
- }
-}
--- /dev/null
+/*
+ * Copyright (c) 2014 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.client;
+
+import io.netty.channel.socket.SocketChannel;
+import io.netty.util.concurrent.Promise;
+import org.opendaylight.controller.netconf.util.AbstractChannelInitializer;
+import org.opendaylight.controller.netconf.util.handler.ssh.SshHandler;
+import org.opendaylight.controller.netconf.util.handler.ssh.authentication.AuthenticationHandler;
+import org.opendaylight.controller.netconf.util.handler.ssh.client.Invoker;
+import org.opendaylight.protocol.framework.SessionListenerFactory;
+
+import java.io.IOException;
+
+final class SshClientChannelInitializer extends AbstractChannelInitializer<NetconfClientSession> {
+
+ private final AuthenticationHandler authenticationHandler;
+ private final NetconfClientSessionNegotiatorFactory negotiatorFactory;
+ private final NetconfClientSessionListener sessionListener;
+
+ public SshClientChannelInitializer(final AuthenticationHandler authHandler,
+ final NetconfClientSessionNegotiatorFactory negotiatorFactory,
+ final NetconfClientSessionListener sessionListener) {
+ this.authenticationHandler = authHandler;
+ this.negotiatorFactory = negotiatorFactory;
+ this.sessionListener = sessionListener;
+ }
+
+ @Override
+ public void initialize(final SocketChannel ch, final Promise<NetconfClientSession> promise) {
+ try {
+ final Invoker invoker = Invoker.subsystem("netconf");
+ ch.pipeline().addFirst(new SshHandler(authenticationHandler, invoker));
+ super.initialize(ch,promise);
+ } catch (final IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ protected void initializeSessionNegotiator(final SocketChannel ch,
+ final Promise<NetconfClientSession> promise) {
+ ch.pipeline().addAfter(NETCONF_MESSAGE_DECODER, AbstractChannelInitializer.NETCONF_SESSION_NEGOTIATOR,
+ negotiatorFactory.getSessionNegotiator(new SessionListenerFactory<NetconfClientSessionListener>() {
+ @Override
+ public NetconfClientSessionListener getSessionListener() {
+ return sessionListener;
+ }
+ }, ch, promise));
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 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.client;
+
+import io.netty.channel.socket.SocketChannel;
+import io.netty.util.concurrent.Promise;
+import org.opendaylight.controller.netconf.util.AbstractChannelInitializer;
+import org.opendaylight.protocol.framework.SessionListenerFactory;
+
+class TcpClientChannelInitializer extends AbstractChannelInitializer<NetconfClientSession> {
+
+ private final NetconfClientSessionNegotiatorFactory negotiatorFactory;
+ private final NetconfClientSessionListener sessionListener;
+
+ TcpClientChannelInitializer(final NetconfClientSessionNegotiatorFactory negotiatorFactory,
+ final NetconfClientSessionListener sessionListener) {
+ this.negotiatorFactory = negotiatorFactory;
+ this.sessionListener = sessionListener;
+ }
+
+ @Override
+ public void initialize(final SocketChannel ch, final Promise<NetconfClientSession> promise) {
+ super.initialize(ch, promise);
+ }
+
+ @Override
+ protected void initializeSessionNegotiator(final SocketChannel ch, final Promise<NetconfClientSession> promise) {
+ ch.pipeline().addAfter(NETCONF_MESSAGE_DECODER, AbstractChannelInitializer.NETCONF_SESSION_NEGOTIATOR,
+ negotiatorFactory.getSessionNegotiator(new SessionListenerFactory<NetconfClientSessionListener>() {
+ @Override
+ public NetconfClientSessionListener getSessionListener() {
+ return sessionListener;
+ }
+ }, ch, promise));
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 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.client.conf;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import org.opendaylight.controller.netconf.client.NetconfClientSessionListener;
+import org.opendaylight.controller.netconf.util.handler.ssh.authentication.AuthenticationHandler;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
+import org.opendaylight.protocol.framework.ReconnectStrategy;
+
+import java.net.InetSocketAddress;
+
+public class NetconfClientConfiguration {
+
+ private final NetconfClientProtocol clientProtocol;
+ private final InetSocketAddress address;
+ private final Long connectionTimeoutMillis;
+
+ private final NetconfHelloMessageAdditionalHeader additionalHeader;
+ private final NetconfClientSessionListener sessionListener;
+
+ private final ReconnectStrategy reconnectStrategy;
+
+ private final AuthenticationHandler authHandler;
+
+ NetconfClientConfiguration(final NetconfClientProtocol protocol, final InetSocketAddress address, final Long connectionTimeoutMillis, final NetconfHelloMessageAdditionalHeader additionalHeader, final NetconfClientSessionListener sessionListener, final ReconnectStrategy reconnectStrategy, final AuthenticationHandler authHandler) {
+ this.address = address;
+ this.connectionTimeoutMillis = connectionTimeoutMillis;
+ this.additionalHeader = additionalHeader;
+ this.sessionListener = sessionListener;
+ this.clientProtocol = protocol;
+ this.reconnectStrategy = reconnectStrategy;
+ this.authHandler = authHandler;
+ validateConfiguration();
+ }
+
+ public final InetSocketAddress getAddress() {
+ return address;
+ }
+
+ public final Long getConnectionTimeoutMillis() {
+ return connectionTimeoutMillis;
+ }
+
+ public final Optional<NetconfHelloMessageAdditionalHeader> getAdditionalHeader() {
+ return Optional.fromNullable(additionalHeader);
+ }
+
+ public final NetconfClientSessionListener getSessionListener() {
+ return sessionListener;
+ }
+
+ public final ReconnectStrategy getReconnectStrategy() {
+ return reconnectStrategy;
+ }
+
+ public final AuthenticationHandler getAuthHandler() {
+ return authHandler;
+ }
+
+ public NetconfClientProtocol getProtocol() {
+ return clientProtocol;
+ }
+
+ private void validateConfiguration() {
+ Preconditions.checkNotNull(clientProtocol, " ");
+ switch (clientProtocol) {
+ case SSH:
+ validateSshConfiguration();
+ // Fall through intentional (ssh validation is a superset of tcp validation)
+ case TCP:
+ validateTcpConfiguration();
+ }
+ }
+
+ protected void validateSshConfiguration() {
+ Preconditions.checkNotNull(authHandler, "authHandler");
+ }
+
+ protected void validateTcpConfiguration() {
+ Preconditions.checkNotNull(address, "address");
+ Preconditions.checkNotNull(clientProtocol, "clientProtocol");
+ Preconditions.checkNotNull(connectionTimeoutMillis, "connectionTimeoutMillis");
+ Preconditions.checkNotNull(sessionListener, "sessionListener");
+ Preconditions.checkNotNull(reconnectStrategy, "reconnectStrategy");
+ }
+
+ @Override
+ public final String toString() {
+ return buildToStringHelper().toString();
+ }
+
+ protected Objects.ToStringHelper buildToStringHelper() {
+ return Objects.toStringHelper(this)
+ .add("address", address)
+ .add("connectionTimeoutMillis", connectionTimeoutMillis)
+ .add("additionalHeader", additionalHeader)
+ .add("sessionListener", sessionListener)
+ .add("reconnectStrategy", reconnectStrategy)
+ .add("clientProtocol", clientProtocol)
+ .add("authHandler", authHandler);
+ }
+
+ public static enum NetconfClientProtocol {
+ TCP, SSH
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2014 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.client.conf;
+
+import org.opendaylight.controller.netconf.client.NetconfClientSessionListener;
+import org.opendaylight.controller.netconf.util.handler.ssh.authentication.AuthenticationHandler;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
+import org.opendaylight.protocol.framework.ReconnectStrategy;
+
+import java.net.InetSocketAddress;
+
+public class NetconfClientConfigurationBuilder {
+
+ public static final int DEFAULT_CONNECTION_TIMEOUT_MILLIS = 5000;
+ public static final NetconfClientConfiguration.NetconfClientProtocol DEFAULT_CLIENT_PROTOCOL = NetconfClientConfiguration.NetconfClientProtocol.TCP;
+
+ private InetSocketAddress address;
+ private long connectionTimeoutMillis = DEFAULT_CONNECTION_TIMEOUT_MILLIS;
+ private NetconfHelloMessageAdditionalHeader additionalHeader;
+ private NetconfClientSessionListener sessionListener;
+ private ReconnectStrategy reconnectStrategy;
+ private AuthenticationHandler authHandler;
+ private NetconfClientConfiguration.NetconfClientProtocol clientProtocol = DEFAULT_CLIENT_PROTOCOL;
+
+ protected NetconfClientConfigurationBuilder() {
+ }
+
+ public static NetconfClientConfigurationBuilder create() {
+ return new NetconfClientConfigurationBuilder();
+ }
+
+ public NetconfClientConfigurationBuilder withAddress(final InetSocketAddress address) {
+ this.address = address;
+ return this;
+ }
+
+ public NetconfClientConfigurationBuilder withConnectionTimeoutMillis(final long connectionTimeoutMillis) {
+ this.connectionTimeoutMillis = connectionTimeoutMillis;
+ return this;
+ }
+
+ public NetconfClientConfigurationBuilder withProtocol(final NetconfClientConfiguration.NetconfClientProtocol clientProtocol) {
+ this.clientProtocol = clientProtocol;
+ return this;
+ }
+
+ public NetconfClientConfigurationBuilder withAdditionalHeader(final NetconfHelloMessageAdditionalHeader additionalHeader) {
+ this.additionalHeader = additionalHeader;
+ return this;
+ }
+
+ public NetconfClientConfigurationBuilder withSessionListener(final NetconfClientSessionListener sessionListener) {
+ this.sessionListener = sessionListener;
+ return this;
+ }
+
+ public NetconfClientConfigurationBuilder withReconnectStrategy(final ReconnectStrategy reconnectStrategy) {
+ this.reconnectStrategy = reconnectStrategy;
+ return this;
+ }
+
+ public NetconfClientConfigurationBuilder withAuthHandler(final AuthenticationHandler authHandler) {
+ this.authHandler = authHandler;
+ return this;
+ }
+
+ final InetSocketAddress getAddress() {
+ return address;
+ }
+
+ final long getConnectionTimeoutMillis() {
+ return connectionTimeoutMillis;
+ }
+
+ final NetconfHelloMessageAdditionalHeader getAdditionalHeader() {
+ return additionalHeader;
+ }
+
+ final NetconfClientSessionListener getSessionListener() {
+ return sessionListener;
+ }
+
+ final ReconnectStrategy getReconnectStrategy() {
+ return reconnectStrategy;
+ }
+
+ final AuthenticationHandler getAuthHandler() {
+ return authHandler;
+ }
+
+ final NetconfClientConfiguration.NetconfClientProtocol getProtocol() {
+ return clientProtocol;
+ }
+
+ public NetconfClientConfiguration build() {
+ return new NetconfClientConfiguration(clientProtocol, address, connectionTimeoutMillis, additionalHeader, sessionListener, reconnectStrategy, authHandler);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 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.client.conf;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
+import org.opendaylight.controller.netconf.client.NetconfClientSessionListener;
+import org.opendaylight.controller.netconf.util.handler.ssh.authentication.AuthenticationHandler;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
+import org.opendaylight.protocol.framework.ReconnectStrategy;
+import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
+
+import java.net.InetSocketAddress;
+
+public final class NetconfReconnectingClientConfiguration extends NetconfClientConfiguration {
+
+ private final ReconnectStrategyFactory connectStrategyFactory;
+
+ NetconfReconnectingClientConfiguration(final NetconfClientProtocol clientProtocol, final InetSocketAddress address,
+ final Long connectionTimeoutMillis, final NetconfHelloMessageAdditionalHeader additionalHeader,
+ final NetconfClientSessionListener sessionListener, final ReconnectStrategy reconnectStrategy,
+ final ReconnectStrategyFactory connectStrategyFactory, final AuthenticationHandler authHandler) {
+ super(clientProtocol, address, connectionTimeoutMillis, additionalHeader, sessionListener, reconnectStrategy,
+ authHandler);
+ this.connectStrategyFactory = connectStrategyFactory;
+ validateReconnectConfiguration();
+ }
+
+ public ReconnectStrategyFactory getConnectStrategyFactory() {
+ return connectStrategyFactory;
+ }
+
+ private void validateReconnectConfiguration() {
+ Preconditions.checkNotNull(connectStrategyFactory);
+ }
+
+ @Override
+ protected Objects.ToStringHelper buildToStringHelper() {
+ return super.buildToStringHelper().add("connectStrategyFactory", connectStrategyFactory);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 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.client.conf;
+
+import java.net.InetSocketAddress;
+
+import org.opendaylight.controller.netconf.client.NetconfClientSessionListener;
+import org.opendaylight.controller.netconf.util.handler.ssh.authentication.AuthenticationHandler;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
+import org.opendaylight.protocol.framework.ReconnectStrategy;
+import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
+
+public class NetconfReconnectingClientConfigurationBuilder extends NetconfClientConfigurationBuilder {
+
+ private ReconnectStrategyFactory connectStrategyFactory;
+
+ private NetconfReconnectingClientConfigurationBuilder() {
+ }
+
+ public static NetconfReconnectingClientConfigurationBuilder create() {
+ return new NetconfReconnectingClientConfigurationBuilder();
+ }
+
+
+ public NetconfReconnectingClientConfigurationBuilder withConnectStrategyFactory(final ReconnectStrategyFactory connectStrategyFactory) {
+ this.connectStrategyFactory = connectStrategyFactory;
+ return this;
+ }
+
+ @Override
+ public NetconfReconnectingClientConfiguration build() {
+ return new NetconfReconnectingClientConfiguration(getProtocol(), getAddress(), getConnectionTimeoutMillis(), getAdditionalHeader(), getSessionListener(), getReconnectStrategy(), connectStrategyFactory, getAuthHandler());
+ }
+
+ // Override setter methods to return subtype
+
+ @Override
+ public NetconfReconnectingClientConfigurationBuilder withAddress(final InetSocketAddress address) {
+ return (NetconfReconnectingClientConfigurationBuilder) super.withAddress(address);
+ }
+
+ @Override
+ public NetconfReconnectingClientConfigurationBuilder withConnectionTimeoutMillis(final long connectionTimeoutMillis) {
+ return (NetconfReconnectingClientConfigurationBuilder) super.withConnectionTimeoutMillis(connectionTimeoutMillis);
+ }
+
+ @Override
+ public NetconfReconnectingClientConfigurationBuilder withAdditionalHeader(final NetconfHelloMessageAdditionalHeader additionalHeader) {
+ return (NetconfReconnectingClientConfigurationBuilder) super.withAdditionalHeader(additionalHeader);
+ }
+
+ @Override
+ public NetconfReconnectingClientConfigurationBuilder withSessionListener(final NetconfClientSessionListener sessionListener) {
+ return (NetconfReconnectingClientConfigurationBuilder) super.withSessionListener(sessionListener);
+ }
+
+ @Override
+ public NetconfReconnectingClientConfigurationBuilder withReconnectStrategy(final ReconnectStrategy reconnectStrategy) {
+ return (NetconfReconnectingClientConfigurationBuilder) super.withReconnectStrategy(reconnectStrategy);
+ }
+
+ @Override
+ public NetconfReconnectingClientConfigurationBuilder withAuthHandler(final AuthenticationHandler authHandler) {
+ return (NetconfReconnectingClientConfigurationBuilder) super.withAuthHandler(authHandler);
+ }
+
+ @Override
+ public NetconfReconnectingClientConfigurationBuilder withProtocol(NetconfClientConfiguration.NetconfClientProtocol clientProtocol) {
+ return (NetconfReconnectingClientConfigurationBuilder) super.withProtocol(clientProtocol);
+ }
+}
package org.opendaylight.controller.netconf.client.test;
-import io.netty.util.concurrent.Future;
-import io.netty.util.concurrent.GlobalEventExecutor;
-
import java.io.Closeable;
import java.io.IOException;
-import java.net.InetSocketAddress;
import java.util.Set;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import org.opendaylight.controller.netconf.client.NetconfClientSession;
import org.opendaylight.controller.netconf.client.NetconfClientSessionListener;
import org.opendaylight.controller.netconf.client.SimpleNetconfClientSessionListener;
-import org.opendaylight.protocol.framework.NeverReconnectStrategy;
-import org.opendaylight.protocol.framework.ReconnectStrategy;
+import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration;
import com.google.common.base.Preconditions;
import com.google.common.collect.Sets;
+import io.netty.util.concurrent.Future;
/**
private final NetconfClientSessionListener sessionListener;
private final long sessionId;
- private TestingNetconfClient(String clientLabel, InetSocketAddress address, ReconnectStrategy strat,
- NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException {
+ public TestingNetconfClient(String clientLabel,
+ NetconfClientDispatcher netconfClientDispatcher, final NetconfClientConfiguration config) throws InterruptedException {
this.label = clientLabel;
- sessionListener = new SimpleNetconfClientSessionListener();
- Future<NetconfClientSession> clientFuture = netconfClientDispatcher.createClient(address, sessionListener, strat);
+ sessionListener = config.getSessionListener();
+ Future<NetconfClientSession> clientFuture = netconfClientDispatcher.createClient(config);
clientSession = get(clientFuture);
this.sessionId = clientSession.getSessionId();
}
}
}
- public TestingNetconfClient(String clientLabelForLogging, InetSocketAddress address, int connectTimeoutMs,
- NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException {
- this(clientLabelForLogging, address,
- new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE, connectTimeoutMs), netconfClientDispatcher);
- }
-
- public TestingNetconfClient(String clientLabelForLogging, InetSocketAddress address,
- NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException {
- this(clientLabelForLogging, address, new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE,
- DEFAULT_CONNECT_TIMEOUT), netconfClientDispatcher);
- }
-
public Future<NetconfMessage> sendRequest(NetconfMessage message) {
return ((SimpleNetconfClientSessionListener)sessionListener).sendRequest(message);
}
Preconditions.checkState(clientSession != null, "Client was not initialized successfully");
return Sets.newHashSet(clientSession.getServerCapabilities());
}
-}
\ No newline at end of file
+}
package org.opendaylight.controller.netconf.impl;
-import com.google.common.base.Optional;
-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.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfServerSessionPreferences;
import org.opendaylight.controller.netconf.util.AbstractNetconfSessionNegotiator;
import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.net.InetSocketAddress;
+import com.google.common.base.Optional;
+
+import io.netty.channel.Channel;
+import io.netty.util.Timer;
+import io.netty.util.concurrent.Promise;
public class NetconfServerSessionNegotiator extends
AbstractNetconfSessionNegotiator<NetconfServerSessionPreferences, NetconfServerSession, NetconfServerSessionListener> {
super(sessionPreferences, promise, channel, timer, sessionListener, connectionTimeoutMillis);
}
+ @Override
+ protected void handleMessage(NetconfHelloMessage netconfMessage) throws NetconfDocumentedException {
+ NetconfServerSession session = getSessionForHelloMessage(netconfMessage);
+ replaceHelloMessageInboundHandler(session);
+ // Negotiation successful after all non hello messages were processed
+ negotiationSuccessful(session);
+ }
+
@Override
protected NetconfServerSession getSession(NetconfServerSessionListener sessionListener, Channel channel, NetconfHelloMessage message) {
Optional<NetconfHelloMessageAdditionalHeader> additionalHeader = message.getAdditionalHeader();
import static org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider.NetconfOperationProviderUtil.getNetconfSessionIdForReporting;
+import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
import java.util.Set;
public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorFactory<NetconfHelloMessage, NetconfServerSession, NetconfServerSessionListener> {
- private static final Set<String> DEFAULT_BASE_CAPABILITIES = ImmutableSet.of(
- XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_0
- // FIXME, Chunk framing causes ConcurrentClientsTest to fail, investigate
-// XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_1,
- // FIXME, EXI causing issues with sal-netconf-connector, investigate
-// XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_CAPABILITY_EXI_1_0
+ public static final Set<String> DEFAULT_BASE_CAPABILITIES = ImmutableSet.of(
+ XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_0,
+ XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_1,
+ XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_CAPABILITY_EXI_1_0
);
private final Timer timer;
private final DefaultCommitNotificationProducer commitNotificationProducer;
private final SessionMonitoringService monitoringService;
private static final Logger logger = LoggerFactory.getLogger(NetconfServerSessionNegotiatorFactory.class);
+ private final Set<String> baseCapabilities;
// TODO too many params, refactor
public NetconfServerSessionNegotiatorFactory(Timer timer, NetconfOperationProvider netconfOperationProvider,
SessionIdProvider idProvider, long connectionTimeoutMillis,
DefaultCommitNotificationProducer commitNot,
SessionMonitoringService monitoringService) {
+ this(timer, netconfOperationProvider, idProvider, connectionTimeoutMillis, commitNot, monitoringService, DEFAULT_BASE_CAPABILITIES);
+ }
+
+ // TODO too many params, refactor
+ public NetconfServerSessionNegotiatorFactory(Timer timer, NetconfOperationProvider netconfOperationProvider,
+ SessionIdProvider idProvider, long connectionTimeoutMillis,
+ DefaultCommitNotificationProducer commitNot,
+ SessionMonitoringService monitoringService, Set<String> baseCapabilities) {
this.timer = timer;
this.netconfOperationProvider = netconfOperationProvider;
this.idProvider = idProvider;
this.connectionTimeoutMillis = connectionTimeoutMillis;
this.commitNotificationProducer = commitNot;
this.monitoringService = monitoringService;
+ this.baseCapabilities = validateBaseCapabilities(baseCapabilities);
+ }
+
+ private ImmutableSet<String> validateBaseCapabilities(final Set<String> baseCapabilities) {
+ // Check base capabilities to be supported by the server
+ Sets.SetView<String> unknownBaseCaps = Sets.difference(baseCapabilities, DEFAULT_BASE_CAPABILITIES);
+ Preconditions.checkArgument(unknownBaseCaps.isEmpty(),
+ "Base capabilities that will be supported by netconf server have to be subset of %s, unknown base capabilities: %s",
+ DEFAULT_BASE_CAPABILITIES, unknownBaseCaps);
+
+ ImmutableSet.Builder<String> b = ImmutableSet.builder();
+ b.addAll(baseCapabilities);
+ // Base 1.0 capability is supported by default
+ b.add(XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_0);
+ return b.build();
}
/**
}
private NetconfHelloMessage createHelloMessage(long sessionId, CapabilityProvider capabilityProvider) throws NetconfDocumentedException {
- return NetconfHelloMessage.createServerHello(Sets.union(capabilityProvider.getCapabilities(), DEFAULT_BASE_CAPABILITIES), sessionId);
+ return NetconfHelloMessage.createServerHello(Sets.union(capabilityProvider.getCapabilities(), baseCapabilities), sessionId);
}
}
package org.opendaylight.controller.netconf.impl;
import static com.google.common.base.Preconditions.checkNotNull;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.doNothing;
import java.lang.management.ManagementFactory;
import java.net.InetSocketAddress;
import java.net.Socket;
-import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicLong;
import org.apache.commons.io.IOUtils;
import org.junit.After;
+import org.junit.AfterClass;
import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
+import org.opendaylight.controller.netconf.client.SimpleNetconfClientSessionListener;
+import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration;
+import org.opendaylight.controller.netconf.client.conf.NetconfClientConfigurationBuilder;
import org.opendaylight.controller.netconf.client.test.TestingNetconfClient;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
+import org.opendaylight.controller.netconf.util.messages.NetconfMessageUtil;
import org.opendaylight.controller.netconf.util.messages.NetconfStartExiMessage;
import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
+import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.opendaylight.protocol.framework.NeverReconnectStrategy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
-import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.util.HashedWheelTimer;
+import io.netty.util.concurrent.GlobalEventExecutor;
+@RunWith(Parameterized.class)
public class ConcurrentClientsTest {
+ private static final Logger logger = LoggerFactory.getLogger(ConcurrentClientsTest.class);
- private static final int CONCURRENCY = 16;
- private EventLoopGroup nettyGroup;
- private NetconfClientDispatcher netconfClientDispatcher;
+ private static ExecutorService clientExecutor;
- private final InetSocketAddress netconfAddress = new InetSocketAddress("127.0.0.1", 8303);
+ private static final int CONCURRENCY = 32;
+ private static final InetSocketAddress netconfAddress = new InetSocketAddress("127.0.0.1", 8303);
- static final Logger logger = LoggerFactory.getLogger(ConcurrentClientsTest.class);
+ private int nettyThreads;
+ private Class<? extends Runnable> clientRunnable;
+ private Set<String> serverCaps;
- private DefaultCommitNotificationProducer commitNot;
- private NetconfServerDispatcher dispatch;
+ public ConcurrentClientsTest(int nettyThreads, Class<? extends Runnable> clientRunnable, Set<String> serverCaps) {
+ this.nettyThreads = nettyThreads;
+ this.clientRunnable = clientRunnable;
+ this.serverCaps = serverCaps;
+ }
+ @Parameterized.Parameters()
+ public static Collection<Object[]> data() {
+ return Arrays.asList(new Object[][]{
+ {4, TestingNetconfClientRunnable.class, NetconfServerSessionNegotiatorFactory.DEFAULT_BASE_CAPABILITIES},
+ {1, TestingNetconfClientRunnable.class, NetconfServerSessionNegotiatorFactory.DEFAULT_BASE_CAPABILITIES},
+ // empty set of capabilities = only base 1.0 netconf capability
+ {4, TestingNetconfClientRunnable.class, Collections.emptySet()},
+ {4, TestingNetconfClientRunnable.class, getOnlyExiServerCaps()},
+ {4, TestingNetconfClientRunnable.class, getOnlyChunkServerCaps()},
+
+ {4, BlockingClientRunnable.class, getOnlyExiServerCaps()},
+ {1, BlockingClientRunnable.class, getOnlyExiServerCaps()},
+ });
+ }
+ private EventLoopGroup nettyGroup;
+ private NetconfClientDispatcher netconfClientDispatcher;
+
+ private DefaultCommitNotificationProducer commitNot;
HashedWheelTimer hashedWheelTimer;
+ private TestingNetconfOperation testingNetconfOperation;
public static SessionMonitoringService createMockedMonitoringService() {
SessionMonitoringService monitoring = mock(SessionMonitoringService.class);
return monitoring;
}
+ @BeforeClass
+ public static void setUpClientExecutor() {
+ clientExecutor = Executors.newFixedThreadPool(CONCURRENCY, new ThreadFactory() {
+ int i = 1;
+
+ @Override
+ public Thread newThread(final Runnable r) {
+ Thread thread = new Thread(r);
+ thread.setName("client-" + i++);
+ thread.setDaemon(true);
+ return thread;
+ }
+ });
+ }
+
@Before
public void setUp() throws Exception {
-
- nettyGroup = new NioEventLoopGroup();
- NetconfHelloMessageAdditionalHeader additionalHeader = new NetconfHelloMessageAdditionalHeader("uname", "10.10.10.1", "830", "tcp", "client");
- netconfClientDispatcher = new NetconfClientDispatcher( nettyGroup, nettyGroup, additionalHeader, 5000);
+ hashedWheelTimer = new HashedWheelTimer();
+ nettyGroup = new NioEventLoopGroup(nettyThreads);
+ netconfClientDispatcher = new NetconfClientDispatcherImpl(nettyGroup, nettyGroup, hashedWheelTimer);
NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
- factoriesListener.onAddNetconfOperationServiceFactory(mockOpF());
+
+ testingNetconfOperation = new TestingNetconfOperation();
+ factoriesListener.onAddNetconfOperationServiceFactory(new TestingOperationServiceFactory(testingNetconfOperation));
SessionIdProvider idProvider = new SessionIdProvider();
- hashedWheelTimer = new HashedWheelTimer();
NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory(
- hashedWheelTimer, factoriesListener, idProvider, 5000, commitNot, createMockedMonitoringService());
+ hashedWheelTimer, factoriesListener, idProvider, 5000, commitNot, createMockedMonitoringService(), serverCaps);
commitNot = new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
NetconfServerDispatcher.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerChannelInitializer(serverNegotiatorFactory);
- dispatch = new NetconfServerDispatcher(serverChannelInitializer, nettyGroup, nettyGroup);
+ final NetconfServerDispatcher dispatch = new NetconfServerDispatcher(serverChannelInitializer, nettyGroup, nettyGroup);
ChannelFuture s = dispatch.createServer(netconfAddress);
s.await();
@After
public void tearDown(){
+ commitNot.close();
hashedWheelTimer.stop();
- nettyGroup.shutdownGracefully();
+ try {
+ nettyGroup.shutdownGracefully().get();
+ } catch (InterruptedException | ExecutionException e) {
+ logger.warn("Ignoring exception while cleaning up after test", e);
+ }
}
- private NetconfOperationServiceFactory mockOpF() {
- return new NetconfOperationServiceFactory() {
- @Override
- public NetconfOperationService createService(String netconfSessionIdForReporting) {
- return new NetconfOperationService() {
- @Override
- public Set<Capability> getCapabilities() {
- return Collections.emptySet();
- }
-
- @Override
- public Set<NetconfOperation> getNetconfOperations() {
- return Sets.<NetconfOperation> newHashSet(new NetconfOperation() {
- @Override
- public HandlingPriority canHandle(Document message) {
- return XmlUtil.toString(message).contains(NetconfStartExiMessage.START_EXI) ?
- HandlingPriority.CANNOT_HANDLE :
- HandlingPriority.HANDLE_WITH_MAX_PRIORITY;
- }
-
- @Override
- public Document handle(Document requestMessage, NetconfOperationChainedExecution subsequentOperation) throws NetconfDocumentedException {
- try {
- return XmlUtil.readXmlToDocument("<test/>");
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
- });
- }
-
- @Override
- public void close() {
- }
- };
- }
- };
+ @AfterClass
+ public static void tearDownClientExecutor() {
+ clientExecutor.shutdownNow();
}
- @After
- public void cleanUp() throws Exception {
- commitNot.close();
- }
+ @Test(timeout = CONCURRENCY * 1000)
+ public void testConcurrentClients() throws Exception {
- @Test(timeout = 30 * 1000)
- public void multipleClients() throws Exception {
- List<TestingThread> threads = new ArrayList<>();
+ List<Future<?>> futures = Lists.newArrayListWithCapacity(CONCURRENCY);
- final int attempts = 5;
for (int i = 0; i < CONCURRENCY; i++) {
- TestingThread thread = new TestingThread(String.valueOf(i), attempts);
- threads.add(thread);
- thread.start();
+ futures.add(clientExecutor.submit(getInstanceOfClientRunnable()));
}
- for (TestingThread thread : threads) {
- thread.join();
- if(thread.thrownException.isPresent()) {
- Exception exception = thread.thrownException.get();
- logger.error("Thread for testing client failed", exception);
- fail("Client thread " + thread + " failed: " + exception.getMessage());
+ for (Future<?> future : futures) {
+ try {
+ future.get();
+ } catch (InterruptedException e) {
+ throw new IllegalStateException(e);
+ } catch (ExecutionException e) {
+ logger.error("Thread for testing client failed", e);
+ fail("Client failed: " + e.getMessage());
}
}
+
+ assertEquals(CONCURRENCY, testingNetconfOperation.getMessageCount());
}
- @Test(timeout = 30 * 1000)
- public void synchronizationTest() throws Exception {
- new BlockingThread("foo").run2();
+ public static Set<String> getOnlyExiServerCaps() {
+ return Sets.newHashSet(
+ XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_0,
+ XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_CAPABILITY_EXI_1_0
+ );
}
- @Test(timeout = 30 * 1000)
- public void multipleBlockingClients() throws Exception {
- List<BlockingThread> threads = new ArrayList<>();
- for (int i = 0; i < CONCURRENCY; i++) {
- BlockingThread thread = new BlockingThread(String.valueOf(i));
- threads.add(thread);
- thread.start();
+ public static Set<String> getOnlyChunkServerCaps() {
+ return Sets.newHashSet(
+ XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_0,
+ XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_1
+ );
+ }
+
+ public Runnable getInstanceOfClientRunnable() throws Exception {
+ return clientRunnable.getConstructor(ConcurrentClientsTest.class).newInstance(this);
+ }
+
+ /**
+ * Responds to all operations except start-exi and counts all requests
+ */
+ private static class TestingNetconfOperation implements NetconfOperation {
+
+ private final AtomicLong counter = new AtomicLong();
+
+ @Override
+ public HandlingPriority canHandle(Document message) {
+ return XmlUtil.toString(message).contains(NetconfStartExiMessage.START_EXI) ?
+ HandlingPriority.CANNOT_HANDLE :
+ HandlingPriority.HANDLE_WITH_MAX_PRIORITY;
}
- for (BlockingThread thread : threads) {
- thread.join();
- if(thread.thrownException.isPresent()) {
- Exception exception = thread.thrownException.get();
- logger.error("Thread for testing client failed", exception);
- fail("Client thread " + thread + " failed: " + exception.getMessage());
+ @Override
+ public Document handle(Document requestMessage, NetconfOperationChainedExecution subsequentOperation) throws NetconfDocumentedException {
+ try {
+ logger.info("Handling netconf message from test {}", XmlUtil.toString(requestMessage));
+ counter.getAndIncrement();
+ return XmlUtil.readXmlToDocument("<test/>");
+ } catch (Exception e) {
+ throw new RuntimeException(e);
}
}
+
+ public long getMessageCount() {
+ return counter.get();
+ }
}
- class BlockingThread extends Thread {
- private Optional<Exception> thrownException;
+ /**
+ * Hardcoded operation service factory
+ */
+ private static class TestingOperationServiceFactory implements NetconfOperationServiceFactory {
+ private final NetconfOperation[] operations;
- public BlockingThread(String name) {
- super("client-" + name);
+ public TestingOperationServiceFactory(final NetconfOperation... operations) {
+ this.operations = operations;
}
+ @Override
+ public NetconfOperationService createService(String netconfSessionIdForReporting) {
+ return new NetconfOperationService() {
+ @Override
+ public Set<Capability> getCapabilities() {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public Set<NetconfOperation> getNetconfOperations() {
+ return Sets.newHashSet(operations);
+ }
+
+ @Override
+ public void close() {}
+ };
+ }
+ }
+
+ /**
+ * Pure socket based blocking client
+ */
+ public final class BlockingClientRunnable implements Runnable {
+
@Override
public void run() {
try {
run2();
- thrownException = Optional.absent();
} catch (Exception e) {
- thrownException = Optional.of(e);
+ throw new IllegalStateException(Thread.currentThread().getName(), e);
}
}
}
}
- class TestingThread extends Thread {
-
- private final String clientId;
- private final int attempts;
- private Optional<Exception> thrownException;
-
- TestingThread(String clientId, int attempts) {
- this.clientId = clientId;
- this.attempts = attempts;
- setName("client-" + clientId);
- }
+ /**
+ * TestingNetconfClient based runnable
+ */
+ public final class TestingNetconfClientRunnable implements Runnable {
@Override
public void run() {
try {
- final TestingNetconfClient netconfClient = new TestingNetconfClient(clientId, netconfAddress, netconfClientDispatcher);
+ final TestingNetconfClient netconfClient =
+ new TestingNetconfClient(Thread.currentThread().getName(), netconfClientDispatcher, getClientConfig());
long sessionId = netconfClient.getSessionId();
- logger.info("Client with sessionid {} hello exchanged", sessionId);
+ logger.info("Client with session id {}: hello exchanged", sessionId);
final NetconfMessage getMessage = XmlFileLoader
.xmlFileToNetconfMessage("netconfMessages/getConfig.xml");
NetconfMessage result = netconfClient.sendRequest(getMessage).get();
- logger.info("Client with sessionid {} got result {}", sessionId, result);
+ logger.info("Client with session id {}: got result {}", sessionId, result);
+
+ Preconditions.checkState(NetconfMessageUtil.isErrorMessage(result) == false,
+ "Received error response: " + XmlUtil.toString(result.getDocument()) + " to request: "
+ + XmlUtil.toString(getMessage.getDocument()));
+
netconfClient.close();
- logger.info("Client with session id {} ended", sessionId);
- thrownException = Optional.absent();
+ logger.info("Client with session id {}: ended", sessionId);
} catch (final Exception e) {
- thrownException = Optional.of(e);
+ throw new IllegalStateException(Thread.currentThread().getName(), e);
}
}
+
+ private NetconfClientConfiguration getClientConfig() {
+ final NetconfClientConfigurationBuilder b = NetconfClientConfigurationBuilder.create();
+ b.withAddress(netconfAddress);
+ b.withAdditionalHeader(new NetconfHelloMessageAdditionalHeader("uname", "10.10.10.1", "830", "tcp",
+ "client"));
+ b.withSessionListener(new SimpleNetconfClientSessionListener());
+ b.withReconnectStrategy(new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE,
+ NetconfClientConfigurationBuilder.DEFAULT_CONNECTION_TIMEOUT_MILLIS));
+ return b.build();
+ }
}
}
</properties>
<dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>sal-binding-it</artifactId>
+ <exclusions>
+ <!-- FIXME see IdentityRefNetconfTest -->
+ <!-- Pax-url-aether contains guava classes e.g. ImmutableSet that clashes with guava and causes tests to fail-->
+ <exclusion>
+ <groupId>org.ops4j.pax.url</groupId>
+ <artifactId>pax-url-aether</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>commons.logback_settings</artifactId>
<artifactId>netty-config-api</artifactId>
<scope>test</scope>
</dependency>
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>sal-binding-it</artifactId>
- </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>yang-test</artifactId>
<forkCount>1</forkCount>
<reuseForks>false</reuseForks>
<perCoreThreadCount>false</perCoreThreadCount>
+ <classpathDependencyExcludes>
+ <classpathDependencyExcludes>com.google.collections:google-collections</classpathDependencyExcludes>
+ <classpathDependencyExcludes>org.ops4j.pax.url:pax-url-aether</classpathDependencyExcludes>
+ </classpathDependencyExcludes>
</configuration>
<executions>
<execution>
*/
package org.opendaylight.controller.netconf.it;
-import io.netty.channel.EventLoopGroup;
-import io.netty.channel.nio.NioEventLoopGroup;
-import io.netty.util.HashedWheelTimer;
+import java.net.InetSocketAddress;
+
import org.junit.After;
import org.junit.Before;
import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
+import org.opendaylight.controller.netconf.client.SimpleNetconfClientSessionListener;
+import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration;
+import org.opendaylight.controller.netconf.client.conf.NetconfClientConfigurationBuilder;
import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
import org.opendaylight.controller.netconf.impl.NetconfServerSessionNegotiatorFactory;
import org.opendaylight.controller.netconf.impl.SessionIdProvider;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService;
+import org.opendaylight.protocol.framework.NeverReconnectStrategy;
+
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.util.HashedWheelTimer;
+import io.netty.util.concurrent.GlobalEventExecutor;
public class AbstractNetconfConfigTest extends AbstractConfigTest {
- protected EventLoopGroup nettyThreadgroup;
+ private EventLoopGroup nettyThreadgroup;
private HashedWheelTimer hashedWheelTimer;
@Before
hashedWheelTimer = new HashedWheelTimer();
}
-
protected NetconfServerDispatcher createDispatcher(
NetconfOperationServiceFactoryListenerImpl factoriesListener, SessionMonitoringService sessionMonitoringService,
DefaultCommitNotificationProducer commitNotifier) {
return new NetconfServerDispatcher(serverChannelInitializer, nettyThreadgroup, nettyThreadgroup);
}
+ protected HashedWheelTimer getHashedWheelTimer() {
+ return hashedWheelTimer;
+ }
+
+ protected EventLoopGroup getNettyThreadgroup() {
+ return nettyThreadgroup;
+ }
@After
public void cleanUpTimer() {
nettyThreadgroup.shutdownGracefully();
}
+ public NetconfClientConfiguration getClientConfiguration(final InetSocketAddress tcpAddress, final int timeout) {
+ final NetconfClientConfigurationBuilder b = NetconfClientConfigurationBuilder.create();
+ b.withAddress(tcpAddress);
+ b.withSessionListener(new SimpleNetconfClientSessionListener());
+ b.withReconnectStrategy(new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE,
+ timeout));
+ b.withConnectionTimeoutMillis(timeout);
+ return b.build();
+ }
}
*/
package org.opendaylight.controller.netconf.it;
-import org.apache.commons.io.IOUtils;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreException;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreService;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreServiceImpl;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreSnapshot;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
-import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+import static org.junit.Assert.assertNotNull;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.HashSet;
import java.util.List;
-import static org.junit.Assert.assertNotNull;
+import org.apache.commons.io.IOUtils;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreException;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreService;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreServiceImpl;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreSnapshot;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
public class HardcodedYangStoreService implements YangStoreService {
import static org.opendaylight.controller.netconf.util.test.XmlUnitUtil.assertContainsElementWithName;
import static org.opendaylight.controller.netconf.util.test.XmlUnitUtil.assertElementsCount;
import static org.opendaylight.controller.netconf.util.xml.XmlUtil.readXmlToDocument;
-import io.netty.channel.ChannelFuture;
import java.io.IOException;
import java.io.InputStream;
import org.opendaylight.controller.netconf.api.jmx.CommitJMXNotification;
import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
import org.opendaylight.controller.netconf.client.test.TestingNetconfClient;
import org.opendaylight.controller.netconf.confignetconfconnector.osgi.NetconfOperationServiceFactoryImpl;
import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreException;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
+import io.netty.channel.ChannelFuture;
public class NetconfConfigPersisterITTest extends AbstractNetconfConfigTest {
private static final InetSocketAddress tcpAddress = new InetSocketAddress("127.0.0.1", 12023);
-
-
private NetconfClientDispatcher clientDispatcher;
-
- DefaultCommitNotificationProducer commitNotifier;
+ private DefaultCommitNotificationProducer commitNotifier;
@Before
public void setUp() throws Exception {
ChannelFuture s = dispatch.createServer(tcpAddress);
s.await();
- clientDispatcher = new NetconfClientDispatcher(nettyThreadgroup, nettyThreadgroup, 5000);
+ clientDispatcher = new NetconfClientDispatcherImpl(getNettyThreadgroup(), getNettyThreadgroup(), getHashedWheelTimer());
}
@After
VerifyingNotificationListener notificationVerifier = createCommitNotificationListener();
VerifyingPersister mockedAggregator = mockAggregator();
- try (TestingNetconfClient persisterClient = new TestingNetconfClient("persister", tcpAddress, 4000, clientDispatcher)) {
+ try (TestingNetconfClient persisterClient = new TestingNetconfClient("persister", clientDispatcher, getClientConfiguration(tcpAddress, 4000))) {
try (ConfigPersisterNotificationHandler configPersisterNotificationHandler = new ConfigPersisterNotificationHandler(
platformMBeanServer, mockedAggregator)) {
- try (TestingNetconfClient netconfClient = new TestingNetconfClient("client", tcpAddress, 4000, clientDispatcher)) {
+ try (TestingNetconfClient netconfClient = new TestingNetconfClient("client", clientDispatcher, getClientConfiguration(tcpAddress, 4000))) {
NetconfMessage response = netconfClient.sendMessage(loadGetConfigMessage());
assertContainsElementWithName(response.getDocument(), "modules");
assertContainsElementWithName(response.getDocument(), "services");
package org.opendaylight.controller.netconf.it;
-import io.netty.channel.ChannelFuture;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.management.ManagementFactory;
+import java.net.InetSocketAddress;
+import java.nio.file.Files;
+import java.util.Collection;
+import java.util.List;
+
+import junit.framework.Assert;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
import org.opendaylight.controller.config.spi.ModuleFactory;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
+import org.opendaylight.controller.netconf.client.SimpleNetconfClientSessionListener;
+import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration;
+import org.opendaylight.controller.netconf.client.conf.NetconfClientConfigurationBuilder;
import org.opendaylight.controller.netconf.client.test.TestingNetconfClient;
import org.opendaylight.controller.netconf.confignetconfconnector.osgi.NetconfOperationServiceFactoryImpl;
import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreException;
import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
-
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLContext;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.management.ManagementFactory;
-import java.net.InetSocketAddress;
-import java.security.KeyManagementException;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.UnrecoverableKeyException;
-import java.security.cert.CertificateException;
-import java.util.Collection;
-import java.util.List;
+import org.opendaylight.controller.netconf.ssh.NetconfSSHServer;
+import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider;
+import org.opendaylight.controller.netconf.ssh.authentication.PEMGenerator;
+import org.opendaylight.controller.netconf.util.handler.ssh.authentication.AuthenticationHandler;
+import org.opendaylight.controller.netconf.util.messages.NetconfMessageUtil;
+import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.opendaylight.controller.sal.authorization.AuthResultEnum;
+import org.opendaylight.controller.usermanager.IUserManager;
+import org.opendaylight.protocol.framework.NeverReconnectStrategy;
+
+import ch.ethz.ssh2.Connection;
+import io.netty.channel.ChannelFuture;
+import io.netty.util.concurrent.GlobalEventExecutor;
public class NetconfITSecureTest extends AbstractNetconfConfigTest {
private static final InetSocketAddress tlsAddress = new InetSocketAddress("127.0.0.1", 12024);
+ private static final InetSocketAddress tcpAddress = new InetSocketAddress("127.0.0.1", 12023);
private DefaultCommitNotificationProducer commitNot;
- private NetconfServerDispatcher dispatchS;
-
+ private NetconfSSHServer sshServer;
+ private NetconfMessage getConfig;
@Before
public void setUp() throws Exception {
- super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext,getModuleFactories().toArray(
+ this.getConfig = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/getConfig.xml");
+
+ super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext, getModuleFactories().toArray(
new ModuleFactory[0])));
NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
commitNot = new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
- dispatchS = createDispatcher(factoriesListener);
- ChannelFuture s = dispatchS.createServer(tlsAddress);
+ final NetconfServerDispatcher dispatchS = createDispatcher(factoriesListener);
+ ChannelFuture s = dispatchS.createServer(tcpAddress);
s.await();
+
+ sshServer = NetconfSSHServer.start(tlsAddress.getPort(), tcpAddress, getAuthProvider());
+ Thread thread = new Thread(sshServer);
+ thread.setDaemon(true);
+ thread.start();
}
private NetconfServerDispatcher createDispatcher(NetconfOperationServiceFactoryListenerImpl factoriesListener) {
@After
public void tearDown() throws Exception {
+ sshServer.stop();
commitNot.close();
}
- private SSLContext getSslContext() throws KeyStoreException, NoSuchAlgorithmException, CertificateException,
- IOException, UnrecoverableKeyException, KeyManagementException {
- final InputStream keyStore = getClass().getResourceAsStream("/keystore.jks");
- final InputStream trustStore = getClass().getResourceAsStream("/keystore.jks");
- SSLContext sslContext = SSLUtil.initializeSecureContext("password", keyStore, trustStore, KeyManagerFactory.getDefaultAlgorithm());
- keyStore.close();
- trustStore.close();
- return sslContext;
- }
-
private HardcodedYangStoreService getYangStore() throws YangStoreException, IOException {
final Collection<InputStream> yangDependencies = NetconfITTest.getBasicYangs();
return new HardcodedYangStoreService(yangDependencies);
@Test
public void testSecure() throws Exception {
- NetconfClientDispatcher dispatch = new NetconfClientDispatcher(nettyThreadgroup, nettyThreadgroup, 5000);
- try (TestingNetconfClient netconfClient = new TestingNetconfClient("tls-client", tlsAddress, 4000, dispatch)) {
-
+ NetconfClientDispatcher dispatch = new NetconfClientDispatcherImpl(getNettyThreadgroup(), getNettyThreadgroup(), getHashedWheelTimer());
+ try (TestingNetconfClient netconfClient = new TestingNetconfClient("testing-ssh-client", dispatch, getClientConfiguration())) {
+ NetconfMessage response = netconfClient.sendMessage(getConfig);
+ Assert.assertFalse("Unexpected error message " + XmlUtil.toString(response.getDocument()),
+ NetconfMessageUtil.isErrorMessage(response));
+
+ NetconfMessage gs = new NetconfMessage(XmlUtil.readXmlToDocument("<rpc message-id=\"2\"\n" +
+ " xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n" +
+ " <get-schema xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\">\n" +
+ " <identifier>config</identifier>\n" +
+ " </get-schema>\n" +
+ "</rpc>\n"));
+
+ response = netconfClient.sendMessage(gs);
+ Assert.assertFalse("Unexpected error message " + XmlUtil.toString(response.getDocument()),
+ NetconfMessageUtil.isErrorMessage(response));
}
}
+
+ public NetconfClientConfiguration getClientConfiguration() throws IOException {
+ final NetconfClientConfigurationBuilder b = NetconfClientConfigurationBuilder.create();
+ b.withAddress(tlsAddress);
+ b.withSessionListener(new SimpleNetconfClientSessionListener());
+ b.withReconnectStrategy(new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE, 5000));
+ b.withProtocol(NetconfClientConfiguration.NetconfClientProtocol.SSH);
+ b.withConnectionTimeoutMillis(5000);
+ b.withAuthHandler(getAuthHandler());
+ return b.build();
+ }
+
+ public AuthProvider getAuthProvider() throws Exception {
+ final IUserManager userManager = mock(IUserManager.class);
+ doReturn(AuthResultEnum.AUTH_ACCEPT).when(userManager).authenticate(anyString(), anyString());
+
+ final File privateKeyFile = Files.createTempFile("tmp-netconf-test", "pk").toFile();
+ privateKeyFile.deleteOnExit();
+ String privateKeyPEMString = PEMGenerator.generateTo(privateKeyFile);
+ return new AuthProvider(userManager, privateKeyPEMString);
+ }
+
+ public AuthenticationHandler getAuthHandler() throws IOException {
+ final AuthenticationHandler authHandler = mock(AuthenticationHandler.class);
+ doAnswer(new Answer() {
+ @Override
+ public Object answer(final InvocationOnMock invocation) throws Throwable {
+ Connection conn = (Connection) invocation.getArguments()[0];
+ conn.authenticateWithPassword("user", "pwd");
+ return null;
+ }
+ }).when(authHandler).authenticate(any(Connection.class));
+ doReturn("auth handler").when(authHandler).toString();
+ return authHandler;
+ }
}
package org.opendaylight.controller.netconf.it;
-import ch.ethz.ssh2.Connection;
-import ch.ethz.ssh2.Session;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-import io.netty.channel.ChannelFuture;
+import static java.util.Collections.emptyList;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.management.ManagementFactory;
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+
+import javax.management.ObjectName;
+import javax.xml.parsers.ParserConfigurationException;
+
import junit.framework.Assert;
+
import org.apache.commons.io.IOUtils;
import org.junit.After;
import org.junit.Before;
import org.opendaylight.controller.netconf.StubUserManager;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
import org.opendaylight.controller.netconf.client.test.TestingNetconfClient;
import org.opendaylight.controller.netconf.confignetconfconnector.osgi.NetconfOperationServiceFactoryImpl;
import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreException;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
-import javax.management.ObjectName;
-import javax.xml.parsers.ParserConfigurationException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.management.ManagementFactory;
-import java.net.InetSocketAddress;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeoutException;
+import ch.ethz.ssh2.Connection;
+import ch.ethz.ssh2.Session;
-import static java.util.Collections.emptyList;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import io.netty.channel.ChannelFuture;
public class NetconfITTest extends AbstractNetconfConfigTest {
private DefaultCommitNotificationProducer commitNot;
private NetconfServerDispatcher dispatch;
- private NetconfClientDispatcher clientDispatcher;
+ private NetconfClientDispatcherImpl clientDispatcher;
@Before
public void setUp() throws Exception {
ChannelFuture s = dispatch.createServer(tcpAddress);
s.await();
- clientDispatcher = new NetconfClientDispatcher(nettyThreadgroup, nettyThreadgroup, 5000);
+ clientDispatcher = new NetconfClientDispatcherImpl(getNettyThreadgroup(), getNettyThreadgroup(), getHashedWheelTimer());
}
private NetconfServerDispatcher createDispatcher(NetconfOperationServiceFactoryListenerImpl factoriesListener) {
@Test
public void testNetconfClientDemonstration() throws Exception {
- try (TestingNetconfClient netconfClient = new TestingNetconfClient("client", tcpAddress, 4000, clientDispatcher)) {
+ try (TestingNetconfClient netconfClient = new TestingNetconfClient("client", clientDispatcher, getClientConfiguration(tcpAddress, 4000))) {
Set<String> capabilitiesFromNetconfServer = netconfClient.getCapabilities();
long sessionId = netconfClient.getSessionId();
@Test
public void testTwoSessions() throws Exception {
- try (TestingNetconfClient netconfClient = new TestingNetconfClient("1", tcpAddress, 10000, clientDispatcher)) {
- try (TestingNetconfClient netconfClient2 = new TestingNetconfClient("2", tcpAddress, 10000, clientDispatcher)) {
+ try (TestingNetconfClient netconfClient = new TestingNetconfClient("1", clientDispatcher, getClientConfiguration(tcpAddress, 10000))) {
+ try (TestingNetconfClient netconfClient2 = new TestingNetconfClient("2", clientDispatcher, getClientConfiguration(tcpAddress, 10000))) {
}
}
}
}
private TestingNetconfClient createSession(final InetSocketAddress address, final String expected) throws Exception {
- final TestingNetconfClient netconfClient = new TestingNetconfClient("test " + address.toString(), address, 5000, clientDispatcher);
+ final TestingNetconfClient netconfClient = new TestingNetconfClient("test " + address.toString(), clientDispatcher, getClientConfiguration(address, 5000));
assertEquals(expected, Long.toString(netconfClient.getSessionId()));
return netconfClient;
}
try {
c = sess.getStdout().read(bytes);
} catch (IOException e) {
- e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
+ throw new IllegalStateException("IO exception while reading data on ssh bridge.");
}
logger.info("got data:" + bytes);
if (c == 0) {
*/
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 io.netty.channel.ChannelFuture;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.opendaylight.controller.netconf.util.test.XmlUnitUtil.assertContainsElementWithText;
+
+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 junit.framework.Assert;
+
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.opendaylight.controller.config.spi.ModuleFactory;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
-import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
import org.opendaylight.controller.netconf.client.test.TestingNetconfClient;
import org.opendaylight.controller.netconf.confignetconfconnector.osgi.NetconfOperationServiceFactoryImpl;
import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreException;
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 static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.opendaylight.controller.netconf.util.test.XmlUnitUtil.assertContainsElementWithText;
+import com.google.common.base.Charsets;
+import com.google.common.base.Optional;
+import com.google.common.collect.Sets;
+import io.netty.channel.ChannelFuture;
public class NetconfMonitoringITTest extends AbstractNetconfConfigTest {
private DefaultCommitNotificationProducer commitNot;
private NetconfServerDispatcher dispatch;
- private NetconfClientDispatcher clientDispatcher;
+ private NetconfClientDispatcherImpl clientDispatcher;
private NetconfMonitoringServiceImpl monitoringService;
ChannelFuture s = dispatch.createServer(tcpAddress);
s.await();
- clientDispatcher = new NetconfClientDispatcher(nettyThreadgroup, nettyThreadgroup, 5000);
+ clientDispatcher = new NetconfClientDispatcherImpl(getNettyThreadgroup(), getNettyThreadgroup(), getHashedWheelTimer());
}
private HardcodedYangStoreService getYangStore() throws YangStoreException, IOException {
@Test
public void testGetResponseFromMonitoring() throws Exception {
- try (TestingNetconfClient netconfClient = new TestingNetconfClient("client-monitoring", tcpAddress, 4000, clientDispatcher)) {
- try (TestingNetconfClient netconfClient2 = new TestingNetconfClient("client-monitoring2", tcpAddress, 4000, clientDispatcher)) {
+ try (TestingNetconfClient netconfClient = new TestingNetconfClient("client-monitoring", clientDispatcher, getClientConfiguration(tcpAddress, 4000))) {
+ try (TestingNetconfClient netconfClient2 = new TestingNetconfClient("client-monitoring2", clientDispatcher, getClientConfiguration(tcpAddress, 4000))) {
NetconfMessage response = netconfClient.sendMessage(loadGetMessage());
assertSessionElementsInResponse(response.getDocument(), 2);
}
/*
- * 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
- */
+* 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.it.pax;
import static org.junit.Assert.fail;
import static org.ops4j.pax.exam.CoreOptions.streamBundle;
import static org.ops4j.pax.exam.CoreOptions.systemPackages;
import static org.ops4j.pax.exam.CoreOptions.systemProperty;
-import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.util.HashedWheelTimer;
+import io.netty.util.Timer;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
-import javax.inject.Inject;
import javax.xml.parsers.ParserConfigurationException;
import org.junit.Assert;
import org.junit.matchers.JUnitMatchers;
import org.junit.runner.RunWith;
import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
+import org.opendaylight.controller.netconf.client.SimpleNetconfClientSessionListener;
+import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration;
+import org.opendaylight.controller.netconf.client.conf.NetconfClientConfigurationBuilder;
import org.opendaylight.controller.netconf.client.test.TestingNetconfClient;
import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.protocol.framework.NeverReconnectStrategy;
import org.ops4j.pax.exam.Configuration;
import org.ops4j.pax.exam.Option;
import org.ops4j.pax.exam.junit.PaxExam;
import com.google.common.base.Preconditions;
import com.google.common.base.Throwables;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.util.concurrent.GlobalEventExecutor;
+
@Ignore
@RunWith(PaxExam.class)
public class IdentityRefNetconfTest {
public static final int CLIENT_CONNECTION_TIMEOUT_MILLIS = 15000;
// Wait for controller to start
- @Inject
+
+ // FIXME move this (pax) test to different module
+ // pax jars contain guava classes that clash with real guava dependencies in non-pax tests
+ //
+ //@Inject
@Filter(timeout = 60 * 1000)
BindingAwareBroker broker;
public void testIdRef() throws Exception {
Preconditions.checkNotNull(broker, "Controller not initialized");
- NioEventLoopGroup nettyThreadgroup = new NioEventLoopGroup();
- NetconfClientDispatcher clientDispatcher = new NetconfClientDispatcher(nettyThreadgroup, nettyThreadgroup,
- CLIENT_CONNECTION_TIMEOUT_MILLIS);
NetconfMessage edit = xmlFileToNetconfMessage("netconfMessages/editConfig_identities.xml");
NetconfMessage commit = xmlFileToNetconfMessage("netconfMessages/commit.xml");
NetconfMessage getConfig = xmlFileToNetconfMessage("netconfMessages/getConfig.xml");
- try (TestingNetconfClient netconfClient = new TestingNetconfClient("client", tcpAddress, CLIENT_CONNECTION_TIMEOUT_MILLIS, clientDispatcher)) {
+ NioEventLoopGroup nettyThreadgroup = new NioEventLoopGroup();
+ Timer timer = new HashedWheelTimer();
+ NetconfClientDispatcherImpl clientDispatcher = new NetconfClientDispatcherImpl(nettyThreadgroup, nettyThreadgroup, timer);
+ try (TestingNetconfClient netconfClient = new TestingNetconfClient("client", clientDispatcher, getClientConfiguration(tcpAddress))) {
sendMessage(edit, netconfClient);
sendMessage(commit, netconfClient);
sendMessage(getConfig, netconfClient, "id-test",
clientDispatcher.close();
} catch (Exception e) {
fail(Throwables.getStackTraceAsString(e));
+ } finally {
+ nettyThreadgroup.shutdownGracefully().get();
+ timer.stop();
}
}
ParserConfigurationException {
return XmlFileLoader.xmlFileToNetconfMessage(fileName);
}
+
+ public NetconfClientConfiguration getClientConfiguration(final InetSocketAddress tcpAddress) {
+ final NetconfClientConfigurationBuilder b = NetconfClientConfigurationBuilder.create();
+ b.withAddress(tcpAddress);
+ b.withSessionListener(new SimpleNetconfClientSessionListener());
+ b.withReconnectStrategy(new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE,
+ CLIENT_CONNECTION_TIMEOUT_MILLIS));
+ b.withConnectionTimeoutMillis(CLIENT_CONNECTION_TIMEOUT_MILLIS);
+ return b.build();
+ }
}
package org.opendaylight.controller.netconf.mapping.api;
+import com.google.common.base.Objects;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
@Override
public int compareTo(HandlingPriority o) {
- if (this == o){
+ if (this == o) {
return 0;
}
- if (this.equals(CANNOT_HANDLE)){
+ if (isCannotHandle()) {
return -1;
}
- if (o.equals(CANNOT_HANDLE)){
+ if (o.isCannotHandle()) {
return 1;
}
if (priority < o.priority){
return -1;
}
- throw new IllegalStateException("Unexpected state");
+
+ throw new IllegalStateException("Unexpected state comparing " + this + " with " + o);
}
@Override
public int hashCode() {
return priority != null ? priority.hashCode() : 0;
}
+
+ @Override
+ public String toString() {
+ return Objects.toStringHelper(this)
+ .add("priority", priority)
+ .toString();
+ }
}
while (up) {
logger.trace("Starting new socket thread.");
try {
- SocketThread.start(ss.accept(), clientAddress, sesssionId.incrementAndGet(),authProvider);
+ SocketThread.start(ss.accept(), clientAddress, sesssionId.incrementAndGet(), authProvider);
} catch (IOException e) {
- logger.error("Exception occurred during socket thread initialization {}",e);
+ logger.error("Exception occurred during socket thread initialization {}", e);
}
}
}
*/
package org.opendaylight.controller.netconf.ssh.authentication;
+import java.io.IOException;
import org.opendaylight.controller.sal.authorization.AuthResultEnum;
-import org.opendaylight.controller.sal.authorization.UserLevel;
import org.opendaylight.controller.usermanager.IUserManager;
-import org.opendaylight.controller.usermanager.UserConfig;
-
-import java.util.ArrayList;
-import java.util.List;
-
import static com.google.common.base.Preconditions.checkNotNull;
public class AuthProvider implements AuthProviderInterface {
- private static IUserManager um; //FIXME static mutable state, no locks
- private static final String DEFAULT_USER = "netconf";
- private static final String DEFAULT_PASSWORD = "netconf";
+ private IUserManager um;
private final String pem;
- public AuthProvider(IUserManager ium, String pemCertificate) throws Exception {
+ public AuthProvider(IUserManager ium, String pemCertificate) throws IllegalArgumentException, IOException {
checkNotNull(pemCertificate, "Parameter 'pemCertificate' is null");
- AuthProvider.um = ium;
- if (AuthProvider.um == null) {
- throw new Exception("No usermanager service available.");
- }
-
- List<String> roles = new ArrayList<String>(1);
- roles.add(UserLevel.SYSTEMADMIN.toString());
- AuthProvider.um.addLocalUser(new UserConfig(DEFAULT_USER, DEFAULT_PASSWORD, roles)); //FIXME hardcoded auth
+ checkNotNull(ium, "No user manager service available.");
+ this.um = ium;
pem = pemCertificate;
}
@Override
public boolean authenticated(String username, String password) {
- if (AuthProvider.um == null) {
- throw new IllegalStateException("No usermanager service available.");
- }
- AuthResultEnum authResult = AuthProvider.um.authenticate(username, password);
+ AuthResultEnum authResult = this.um.authenticate(username, password);
return authResult.equals(AuthResultEnum.AUTH_ACCEPT) || authResult.equals(AuthResultEnum.AUTH_ACCEPT_LOC);
}
@Override
public void removeUserManagerService() {
- AuthProvider.um = null;
+ this.um = null;
}
@Override
public void addUserManagerService(IUserManager userManagerService) {
- AuthProvider.um = userManagerService;
+ this.um = userManagerService;
}
}
package org.opendaylight.controller.netconf.ssh.osgi;
import com.google.common.base.Optional;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.opendaylight.controller.netconf.ssh.NetconfSSHServer;
import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider;
import org.opendaylight.controller.netconf.ssh.authentication.PEMGenerator;
import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil;
+import org.opendaylight.controller.sal.authorization.UserLevel;
import org.opendaylight.controller.usermanager.IUserManager;
+import org.opendaylight.controller.usermanager.UserConfig;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.net.InetSocketAddress;
+import static com.google.common.base.Preconditions.checkNotNull;
/**
* Activator for netconf SSH bundle which creates SSH bridge between netconf client and netconf server. Activator
* starts SSH Server in its own thread. This thread is closed when activator calls stop() method. Server opens socket
- * and listen for client connections. Each client connection creation is handled in separate
+ * and listens for client connections. Each client connection creation is handled in separate
* {@link org.opendaylight.controller.netconf.ssh.threads.SocketThread} thread.
* This thread creates two additional threads {@link org.opendaylight.controller.netconf.ssh.threads.IOThread}
* forwarding data from/to client.IOThread closes servers session and server connection when it gets -1 on input stream.
private static final String EXCEPTION_MESSAGE = "Netconf ssh bridge is not available.";
private IUserManager iUserManager;
private BundleContext context = null;
+ private Optional<String> defaultPassword;
+ private Optional<String> defaultUser;
private ServiceTrackerCustomizer<IUserManager, IUserManager> customizer = new ServiceTrackerCustomizer<IUserManager, IUserManager>(){
@Override
@Override
public void stop(BundleContext context) throws IOException {
+ if (this.defaultUser.isPresent()){
+ this.iUserManager.removeLocalUser(this.defaultUser.get());
+ }
if (server != null){
server.stop();
logger.trace("Netconf SSH bridge is down ...");
}
}
private void startSSHServer() throws IllegalStateException, IOException {
+ checkNotNull(this.iUserManager, "No user manager service available.");
logger.trace("Starting netconf SSH bridge.");
Optional<InetSocketAddress> sshSocketAddressOptional = NetconfConfigUtil.extractSSHNetconfAddress(context, EXCEPTION_MESSAGE);
InetSocketAddress tcpSocketAddress = NetconfConfigUtil.extractTCPNetconfAddress(context,
EXCEPTION_MESSAGE, true);
if (sshSocketAddressOptional.isPresent()){
- String path = NetconfConfigUtil.getPrivateKeyPath(context);
- path = path.replace("\\", "/"); // FIXME: shouldn't this convert lines to system dependent path separator?
+ String path = FilenameUtils.separatorsToSystem(NetconfConfigUtil.getPrivateKeyPath(context));
if (path.equals("")){
throw new IllegalStateException("Missing netconf.ssh.pk.path key in configuration file.");
}
File privateKeyFile = new File(path);
String privateKeyPEMString = null;
if (privateKeyFile.exists() == false) {
- // generate & save to file
try {
privateKeyPEMString = PEMGenerator.generateTo(privateKeyFile);
} catch (Exception e) {
- logger.error("Exception occured while generating PEM string {}",e);
+ logger.error("Exception occurred while generating PEM string {}",e);
}
} else {
// read from file
}
AuthProvider authProvider = null;
try {
+ this.defaultPassword = NetconfConfigUtil.getSSHDefaultPassword(context);
+ this.defaultUser = NetconfConfigUtil.getSSHDefaultUser(context);
+ // Since there is no user data store yet (ldap, ...) this adds default user/password to UserManager
+ // if these parameters are set in netconf configuration file.
+ if (defaultUser.isPresent() &&
+ defaultPassword.isPresent()){
+ logger.trace(String.format("Default username and password for netconf ssh bridge found. Adding user %s to user manager.",defaultUser.get()));
+ List<String> roles = new ArrayList<String>(1);
+ roles.add(UserLevel.SYSTEMADMIN.toString());
+ iUserManager.addLocalUser(new UserConfig(defaultUser.get(), defaultPassword.get(), roles));
+ }
authProvider = new AuthProvider(iUserManager, privateKeyPEMString);
} catch (Exception e) {
logger.error("Error instantiating AuthProvider {}",e);
try {
conn.setPEMHostKey(authProvider.getPEMAsCharArray(), "netconf");
} catch (Exception e) {
- logger.debug("Server authentication setup failed.");
+ logger.warn("Server authentication setup failed.", e);
}
conn.setAuthenticationCallback(this);
conn.setServerConnectionCallback(this);
return sb.toString();
}
- protected <T extends ChannelHandler> T removeHandler(final Class<T> handlerType) {
- return this.channel.pipeline().remove(handlerType);
- }
-
- protected void replaceMessageDecoder(final ChannelHandler handler) {
+ protected final void replaceMessageDecoder(final ChannelHandler handler) {
replaceChannelHandler(AbstractChannelInitializer.NETCONF_MESSAGE_DECODER, handler);
}
- protected void replaceMessageEncoder(final ChannelHandler handler) {
+ protected final void replaceMessageEncoder(final ChannelHandler handler) {
replaceChannelHandler(AbstractChannelInitializer.NETCONF_MESSAGE_ENCODER, handler);
}
- protected void replaceMessageEncoderAfterNextMessage(final ChannelHandler handler) {
+ protected final void replaceMessageEncoderAfterNextMessage(final ChannelHandler handler) {
this.delayedEncoder = handler;
}
- protected void replaceChannelHandler(final String handlerName, final ChannelHandler handler) {
+ protected final void replaceChannelHandler(final String handlerName, final ChannelHandler handler) {
channel.pipeline().replace(handlerName, handlerName, handler);
}
}
final NetconfEXICodec exiCodec = new NetconfEXICodec(exiParams.getOptions());
addExiHandlers(exiCodec);
- logger.debug("EXI handlers added to pipeline on session {}", this);
+ logger.debug("Session {} EXI handlers added to pipeline", this);
}
protected abstract void addExiHandlers(NetconfEXICodec exiCodec);
import org.opendaylight.controller.netconf.util.handler.FramingMechanismHandlerFactory;
import org.opendaylight.controller.netconf.util.handler.NetconfChunkAggregator;
import org.opendaylight.controller.netconf.util.handler.NetconfMessageToXMLEncoder;
+import org.opendaylight.controller.netconf.util.handler.NetconfXMLToHelloMessageDecoder;
import org.opendaylight.controller.netconf.util.handler.NetconfXMLToMessageDecoder;
import org.opendaylight.controller.netconf.util.messages.FramingMechanism;
import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
}
@Override
- protected void startNegotiation() {
+ protected final void startNegotiation() {
final Optional<SslHandler> sslHandler = getSslHandler(channel);
if (sslHandler.isPresent()) {
Future<Channel> future = sslHandler.get().handshakeFuture();
// FIXME, make sessionPreferences return HelloMessage, move NetconfHelloMessage to API
sendMessage((NetconfHelloMessage)helloMessage);
+
+ replaceHelloMessageOutboundHandler();
changeState(State.OPEN_WAIT);
}
+
private void cancelTimeout() {
if(timeout!=null) {
timeout.cancel();
}
}
- @Override
- protected void handleMessage(NetconfHelloMessage netconfMessage) throws NetconfDocumentedException {
- S session = getSessionForHelloMessage(netconfMessage) ;
- negotiationSuccessful(session);
- }
-
protected final S getSessionForHelloMessage(NetconfHelloMessage netconfMessage) throws NetconfDocumentedException {
Preconditions.checkNotNull(netconfMessage, "netconfMessage");
final Document doc = netconfMessage.getDocument();
- replaceHelloMessageHandlers();
-
if (shouldUseChunkFraming(doc)) {
insertChunkFramingToPipeline();
}
/**
* Insert chunk framing handlers into the pipeline
*/
- protected void insertChunkFramingToPipeline() {
+ private void insertChunkFramingToPipeline() {
replaceChannelHandler(channel, AbstractChannelInitializer.NETCONF_MESSAGE_FRAME_ENCODER,
FramingMechanismHandlerFactory.createHandler(FramingMechanism.CHUNK));
replaceChannelHandler(channel, AbstractChannelInitializer.NETCONF_MESSAGE_AGGREGATOR,
new NetconfChunkAggregator());
}
- protected boolean shouldUseChunkFraming(Document doc) {
+ private boolean shouldUseChunkFraming(Document doc) {
return containsBase11Capability(doc)
&& containsBase11Capability(sessionPreferences.getHelloMessage().getDocument());
}
/**
- * Remove special handlers for hello message. Insert regular netconf xml message (en|de)coders.
+ * Remove special inbound handler for hello message. Insert regular netconf xml message (en|de)coders.
+ *
+ * Inbound hello message handler should be kept until negotiation is successful
+ * It caches any non-hello messages while negotiation is still in progress
+ */
+ protected final void replaceHelloMessageInboundHandler(final S session) {
+ ChannelHandler helloMessageHandler = replaceChannelHandler(channel, AbstractChannelInitializer.NETCONF_MESSAGE_DECODER, new NetconfXMLToMessageDecoder());
+
+ Preconditions.checkState(helloMessageHandler instanceof NetconfXMLToHelloMessageDecoder,
+ "Pipeline handlers misplaced on session: %s, pipeline: %s", session, channel.pipeline());
+ Iterable<NetconfMessage> netconfMessagesFromNegotiation =
+ ((NetconfXMLToHelloMessageDecoder) helloMessageHandler).getPostHelloNetconfMessages();
+
+ // Process messages received during negotiation
+ // The hello message handler does not have to be synchronized, since it is always call from the same thread by netty
+ // It means, we are now using the thread now
+ for (NetconfMessage message : netconfMessagesFromNegotiation) {
+ session.handleMessage(message);
+ }
+ }
+
+ /**
+ * Remove special outbound handler for hello message. Insert regular netconf xml message (en|de)coders.
*/
- protected void replaceHelloMessageHandlers() {
- replaceChannelHandler(channel, AbstractChannelInitializer.NETCONF_MESSAGE_DECODER, new NetconfXMLToMessageDecoder());
+ private void replaceHelloMessageOutboundHandler() {
replaceChannelHandler(channel, AbstractChannelInitializer.NETCONF_MESSAGE_ENCODER, new NetconfMessageToXMLEncoder());
}
protected abstract S getSession(L sessionListener, Channel channel, NetconfHelloMessage message) throws NetconfDocumentedException;
- protected synchronized void changeState(final State newState) {
+ private synchronized void changeState(final State newState) {
logger.debug("Changing state from : {} to : {}", state, newState);
Preconditions.checkState(isStateChangePermitted(state, newState), "Cannot change state from %s to %s", state,
newState);
private static final Logger LOG = LoggerFactory.getLogger(NetconfEXIToMessageDecoder.class);
-// private static final SAXTransformerFactory saxTransformerFactory = (SAXTransformerFactory)SAXTransformerFactory.newInstance();
-
private final NetconfEXICodec codec;
public NetconfEXIToMessageDecoder(final NetconfEXICodec codec) {
* the use of EXI, which means the next message needs to be decoded not by us, but rather
* by the XML decoder.
*/
- // If empty Byte buffer is passed to r.parse, EOFException is thrown
- if (in.readableBytes() == 0) {
+ // If empty Byte buffer is passed to r.parse, EOFException is thrown
+ if (in.isReadable() == false) {
LOG.debug("No more content in incoming buffer.");
return;
}
final DOMResult domResult = new DOMResult();
handler.setResult(domResult);
-
try (final InputStream is = new ByteBufInputStream(in)) {
r.parse(new InputSource(is));
}
*/
package org.opendaylight.controller.netconf.util.handler;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.ChannelHandlerContext;
* Customized NetconfXMLToMessageDecoder that reads additional header with
* session metadata from
* {@link org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage}
- * . Used by netconf server to retrieve information about session metadata.
+ *
+ *
+ * This handler should be replaced in pipeline by regular message handler as last step of negotiation.
+ * It serves as a message barrier and halts all non-hello netconf messages.
+ * Netconf messages after hello should be processed once the negotiation succeeded.
+ *
*/
public final class NetconfXMLToHelloMessageDecoder extends ByteToMessageDecoder {
private static final Logger LOG = LoggerFactory.getLogger(NetconfXMLToHelloMessageDecoder.class);
new byte[] { '\r', '\n', '[' },
new byte[] { '\n', '[' });
+ // State variables do not have to by synchronized
+ // Netty uses always the same (1) thread per pipeline
+ // We use instance of this per pipeline
+ private List<NetconfMessage> nonHelloMessages = Lists.newArrayList();
+ private boolean helloReceived = false;
+
@Override
@VisibleForTesting
public void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws IOException, SAXException, NetconfDocumentedException {
Document doc = XmlUtil.readXmlToDocument(new ByteArrayInputStream(bytes));
- final NetconfMessage message;
- if (additionalHeader != null) {
- message = new NetconfHelloMessage(doc, NetconfHelloMessageAdditionalHeader.fromString(additionalHeader));
+ final NetconfMessage message = getNetconfMessage(additionalHeader, doc);
+ if (message instanceof NetconfHelloMessage) {
+ Preconditions.checkState(helloReceived == false,
+ "Multiple hello messages received, unexpected hello: %s",
+ XmlUtil.toString(message.getDocument()));
+ out.add(message);
+ helloReceived = true;
+ // Non hello message, suspend the message and insert into cache
} else {
- message = new NetconfHelloMessage(doc);
+ Preconditions.checkState(helloReceived, "Hello message not received, instead received: %s",
+ XmlUtil.toString(message.getDocument()));
+ LOG.debug("Netconf message received during negotiation, caching {}",
+ XmlUtil.toString(message.getDocument()));
+ nonHelloMessages.add(message);
}
- out.add(message);
} finally {
in.discardReadBytes();
}
}
+ private NetconfMessage getNetconfMessage(final String additionalHeader, final Document doc) throws NetconfDocumentedException {
+ NetconfMessage msg = new NetconfMessage(doc);
+ if(NetconfHelloMessage.isHelloMessage(msg)) {
+ if (additionalHeader != null) {
+ return new NetconfHelloMessage(doc, NetconfHelloMessageAdditionalHeader.fromString(additionalHeader));
+ } else {
+ return new NetconfHelloMessage(doc);
+ }
+ }
+
+ return msg;
+ }
+
private int getAdditionalHeaderEndIndex(byte[] bytes) {
for (byte[] possibleEnd : POSSIBLE_ENDS) {
int idx = findByteSequence(bytes, possibleEnd);
return Charsets.UTF_8.decode(ByteBuffer.wrap(bytes)).toString();
}
+ /**
+ * @return Collection of NetconfMessages that were not hello, but were received during negotiation
+ */
+ public Iterable<NetconfMessage> getPostHelloNetconfMessages() {
+ return nonHelloMessages;
+ }
}
*/
package org.opendaylight.controller.netconf.util.handler;
-import io.netty.buffer.ByteBuf;
-import io.netty.buffer.ByteBufInputStream;
-import io.netty.buffer.ByteBufUtil;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.handler.codec.ByteToMessageDecoder;
-
-import java.io.IOException;
import java.util.List;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.slf4j.LoggerFactory;
import com.google.common.annotations.VisibleForTesting;
-import org.xml.sax.SAXException;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.ByteBufInputStream;
+import io.netty.buffer.ByteBufUtil;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.ByteToMessageDecoder;
public final class NetconfXMLToMessageDecoder extends ByteToMessageDecoder {
private static final Logger LOG = LoggerFactory.getLogger(NetconfXMLToMessageDecoder.class);
@Override
@VisibleForTesting
- public void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws IOException, SAXException {
+ public void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
+
if (in.readableBytes() != 0) {
LOG.trace("Received to decode: {}", ByteBufUtil.hexDump(in));
out.add(new NetconfMessage(XmlUtil.readXmlToDocument(new ByteBufInputStream(in))));
package org.opendaylight.controller.netconf.util.messages;
-import com.google.common.base.Optional;
-import com.google.common.collect.Sets;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfMessage;
+
+import java.util.Set;
+
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.util.exception.MissingNameSpaceException;
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.Document;
import org.w3c.dom.Element;
-import java.util.Set;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Sets;
/**
* NetconfMessage that can carry additional header with session metadata. See {@link org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader}
return additionalHeader== null ? Optional.<NetconfHelloMessageAdditionalHeader>absent() : Optional.of(additionalHeader);
}
- private static void checkHelloMessage(Document doc) throws NetconfDocumentedException {
- XmlElement.fromDomElementWithExpected(doc.getDocumentElement(), HELLO_TAG,
- XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
-
+ private static void checkHelloMessage(Document doc) {
+ Preconditions.checkArgument(isHelloMessage(doc),
+ "Hello message invalid format, should contain %s tag from namespace %s, but is: %s", HELLO_TAG,
+ XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0, XmlUtil.toString(doc));
}
public static NetconfHelloMessage createClientHello(Iterable<String> capabilities,
doc.getDocumentElement().appendChild(sessionIdElement);
return new NetconfHelloMessage(doc);
}
+
+ public static boolean isHelloMessage(final NetconfMessage msg) {
+ Document document = msg.getDocument();
+ return isHelloMessage(document);
+ }
+
+ private static boolean isHelloMessage(final Document document) {
+ XmlElement element = XmlElement.fromDomElement(document.getDocumentElement());
+ try {
+ return element.getName().equals(HELLO_TAG) &&
+ element.hasNamespace() &&
+ element.getNamespace().equals(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
+ } catch (MissingNameSpaceException e) {
+ // Cannot happen, since we check for hasNamespace
+ throw new IllegalStateException(e);
+ }
+ }
}
import com.google.common.base.Preconditions;
import io.netty.channel.Channel;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelFutureListener;
import org.opendaylight.controller.netconf.api.NetconfSession;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfMessage;
final NetconfDocumentedException sendErrorException) {
logger.trace("Sending error {}", sendErrorException.getMessage(), sendErrorException);
final Document errorDocument = createDocument(sendErrorException);
- session.sendMessage(new NetconfMessage(errorDocument));
+ ChannelFuture f = session.sendMessage(new NetconfMessage(errorDocument));
+ f.addListener(new SendErrorVerifyingListener(sendErrorException));
}
public static void sendErrorMessage(Channel channel, NetconfDocumentedException sendErrorException) {
logger.trace("Sending error {}", sendErrorException.getMessage(), sendErrorException);
final Document errorDocument = createDocument(sendErrorException);
- channel.writeAndFlush(new NetconfMessage(errorDocument));
+ ChannelFuture f = channel.writeAndFlush(new NetconfMessage(errorDocument));
+ f.addListener(new SendErrorVerifyingListener(sendErrorException));
}
public static void sendErrorMessage(NetconfSession session, NetconfDocumentedException sendErrorException,
final Document errorDocument = createDocument(sendErrorException);
logger.trace("Sending error {}", XmlUtil.toString(errorDocument));
tryToCopyAttributes(incommingMessage.getDocument(), errorDocument, sendErrorException);
- session.sendMessage(new NetconfMessage(errorDocument));
+ ChannelFuture f = session.sendMessage(new NetconfMessage(errorDocument));
+ f.addListener(new SendErrorVerifyingListener(sendErrorException));
}
private static void tryToCopyAttributes(final Document incommingDocument, final Document errorDocument,
return errorDocument;
}
+ /**
+ * Checks if netconf error was sent successfully.
+ */
+ private static final class SendErrorVerifyingListener implements ChannelFutureListener {
+ private final NetconfDocumentedException sendErrorException;
+
+ public SendErrorVerifyingListener(final NetconfDocumentedException sendErrorException) {
+ this.sendErrorException = sendErrorException;
+ }
+
+ @Override
+ public void operationComplete(final ChannelFuture channelFuture) throws Exception {
+ Preconditions.checkState(channelFuture.isSuccess(), "Unable to send exception {}", sendErrorException,
+ channelFuture.cause());
+ }
+ }
}
package org.opendaylight.controller.netconf.util.osgi;
import com.google.common.base.Optional;
+import com.google.common.base.Strings;
+import java.net.InetSocketAddress;
import org.osgi.framework.BundleContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-
-import java.net.InetSocketAddress;
-
import static com.google.common.base.Preconditions.checkNotNull;
public final class NetconfConfigUtil {
private static final String ADDRESS_SUFFIX_PROP = ".address";
private static final String CLIENT_PROP = ".client";
private static final String PRIVATE_KEY_PATH_PROP = ".pk.path";
+ private static final String SSH_DEFAULT_USER = ".default.user";
+ private static final String SSH_DEFAULT_PASSWORD = ".default.password";
private static final String CONNECTION_TIMEOUT_MILLIS_PROP = "connectionTimeoutMillis";
private static final long DEFAULT_TIMEOUT_MILLIS = 5000;
public static String getPrivateKeyPath(BundleContext context){
return getPropertyValue(context,PREFIX_PROP + InfixProp.ssh +PRIVATE_KEY_PATH_PROP);
}
+ public static Optional<String> getSSHDefaultUser(BundleContext context){
+ return getOptionalPropertyValue(context,PREFIX_PROP + InfixProp.ssh +SSH_DEFAULT_USER);
+ }
+ public static Optional<String> getSSHDefaultPassword(BundleContext context){
+ return getOptionalPropertyValue(context,PREFIX_PROP + InfixProp.ssh +SSH_DEFAULT_PASSWORD);
+ }
+
private static String getPropertyValue(BundleContext context, String propertyName){
String propertyValue = context.getProperty(propertyName);
if (propertyValue == null){
}
return propertyValue;
}
+ private static Optional<String> getOptionalPropertyValue(BundleContext context, String propertyName){
+ String propertyValue = context.getProperty(propertyName);
+ if (Strings.isNullOrEmpty(propertyValue)){
+ return Optional.absent();
+ }
+ return Optional.fromNullable(propertyValue);
+ }
/**
* @param context
* from which properties are being read.
public boolean removeVIP(String name){
for(VIP vip: this.vips){
if(vip.getName().equals(name)){
- this.members.remove(vip);
+ this.vips.remove(vip);
return true;
}
}
* only subnet returned. As soon as a user-configured subnet is created this one will
* vanish.
*/
+ private static final String DISABLE_DEFAULT_SUBNET_PROP = "switchmanager.disableDefaultSubnetGateway";
+ private static final String DISABLE_DEFAULT_SUBNET_PROP_VAL = System.getProperty(DISABLE_DEFAULT_SUBNET_PROP);
+ private static final boolean USE_DEFAULT_SUBNET_GW = !Boolean.valueOf(DISABLE_DEFAULT_SUBNET_PROP_VAL);
protected static final SubnetConfig DEFAULT_SUBNETCONFIG;
protected static final Subnet DEFAULT_SUBNET;
protected static final String DEFAULT_SUBNET_NAME = "default (cannot be modifed)";
@Override
public List<SubnetConfig> getSubnetsConfigList() {
// if there are no subnets, return the default subnet
- if(subnetsConfigList.size() == 0){
+ if (USE_DEFAULT_SUBNET_GW && subnetsConfigList.isEmpty()) {
return Collections.singletonList(DEFAULT_SUBNETCONFIG);
- }else{
+ } else {
return new ArrayList<SubnetConfig>(subnetsConfigList.values());
}
}
@Override
public SubnetConfig getSubnetConfig(String subnet) {
// if there are no subnets, return the default subnet
- if(subnetsConfigList.isEmpty() && subnet.equalsIgnoreCase(DEFAULT_SUBNET_NAME)){
+ if (USE_DEFAULT_SUBNET_GW && subnetsConfigList.isEmpty() && subnet.equalsIgnoreCase(DEFAULT_SUBNET_NAME)) {
return DEFAULT_SUBNETCONFIG;
- }else{
+ } else {
return subnetsConfigList.get(subnet);
}
}
<module>opendaylight/commons/opendaylight</module>
<module>opendaylight/commons/parent</module>
<module>opendaylight/commons/logback_settings</module>
+
+ <!-- Karaf Distribution
+ <module>feature</module>
+ <module>opendaylight/dummy-console</module> -->
+ <module>opendaylight/distribution/opendaylight-karaf</module>
</modules>
<scm>
<connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>