org.opendaylight.controller.sal.core,
org.opendaylight.controller.sal.utils,
org.opendaylight.controller.sal.packet,
+ org.opendaylight.controller.sal.routing,
org.opendaylight.controller.switchmanager,
org.opendaylight.controller.topologymanager,
org.opendaylight.controller.clustering.services,
import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase;
import org.opendaylight.controller.sal.packet.IDataPacketService;
import org.opendaylight.controller.sal.packet.IListenDataPacket;
+import org.opendaylight.controller.sal.routing.IRouting;
import org.opendaylight.controller.switchmanager.ISwitchManager;
import org.opendaylight.controller.topologymanager.ITopologyManager;
import org.slf4j.Logger;
"setClusterContainerService", "unsetClusterContainerService")
.setRequired(true));
+ c.add(createContainerServiceDependency(containerName).setService(
+ IRouting.class).setCallbacks("setRouting","unsetRouting")
+ .setRequired(false));
+
// the Host Listener is optional
c.add(createContainerServiceDependency(containerName).setService(
IfHostListener.class).setCallbacks("setHostListener",
import org.opendaylight.controller.sal.packet.Packet;
import org.opendaylight.controller.sal.packet.PacketResult;
import org.opendaylight.controller.sal.packet.RawPacket;
+import org.opendaylight.controller.sal.routing.IRouting;
import org.opendaylight.controller.sal.utils.EtherTypes;
import org.opendaylight.controller.sal.utils.HexEncode;
import org.opendaylight.controller.sal.utils.NetUtils;
private ISwitchManager switchManager;
private ITopologyManager topologyManager;
private IDataPacketService dataPacketService;
+ private IRouting routing;
private IClusterContainerServices clusterContainerService;
private IConnectionManager connectionManager;
private Set<IfHostListener> hostListeners = new CopyOnWriteArraySet<IfHostListener>();
}
}
+ void setRouting(IRouting r) {
+ this.routing = r;
+ }
+
+ void unsetRouting(IRouting r) {
+ if (this.routing == r) {
+ this.routing = null;
+ }
+ }
+
void setHostListener(IfHostListener s) {
if (this.hostListeners != null) {
this.hostListeners.add(s);
if (host == null) {
// if we don't, know about the host, try to find it
- log.trace("Punted IP pkt from {}, sending bcast ARP event...",
+ log.trace("Punted IP pkt to {}, sending bcast ARP event...",
dIP);
/*
* unknown destination host, initiate bcast ARP request
*/
arpRequestReplyEvent.put(new ARPRequest(dIP, subnet), false);
- }else{
- // we know about the host, send the packet the right place
+ } else if (routing == null ||
+ routing.getRoute(p.getNode(), host.getnodeconnectorNode()) != null) {
+ /* if IRouting is available, make sure that this packet can get it's
+ * destination normally before teleporting it there. If it's not
+ * available, then assume it's reachable.
+ *
+ * TODO: come up with a way to do this in the absence of IRouting
+ */
+
+ log.trace("forwarding punted IP pkt to {} received at {}", dIP, p);
+
+ /* if we know where the host is and there's a path from where this
+ * packet was punted to where the host is, then deliver it to the
+ * host for now */
NodeConnector nc = host.getnodeConnector();
// re-encode the Ethernet packet (the parent of the IPv4 packet)
RawPacket rp = this.dataPacketService.encodeDataPacket(pkt.getParent());
rp.setOutgoingNodeConnector(nc);
this.dataPacketService.transmitDataPacket(rp);
+ } else {
+ log.trace("ignoring punted IP pkt to {} because there is no route from {}",
+ dIP, p);
}
}
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>commons.logback_settings</artifactId>
+ </dependency>
</dependencies>
</project>
--- /dev/null
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>commons.logback_settings</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ <scm>
+ <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+ <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+ <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:Main</url>
+ <tag>HEAD</tag>
+ </scm>
+ <parent>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>commons.parent</artifactId>
+ <version>1.0.1-SNAPSHOT</version>
+ <relativePath>../parent</relativePath>
+ </parent>
+</project>
<artifactId>jolokia-osgi</artifactId>
<version>${jolokia.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>commons.logback_settings</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>properties-maven-plugin</artifactId>
- <version>${propertymavenplugin.version}</version>
- <executions>
- <execution>
- <goals>
- <goal>set-system-properties</goal>
- </goals>
- <configuration>
- <properties>
- <property>
- <name>logback.configurationFile</name>
- <value>${project.parent.basedir}/logback.xml</value>
- </property>
- </properties>
- </configuration>
- </execution>
- </executions>
- </plugin>
- <plugin>
- <groupId>com.googlecode.maven-java-formatter-plugin</groupId>
- <artifactId>maven-java-formatter-plugin</artifactId>
- <version>0.3.1</version>
- <configuration>
- <compilerSource>1.6</compilerSource>
- <compilerCompliance>1.6</compilerCompliance>
- <compilerTargetPlatform>1.6</compilerTargetPlatform>
- <configFile>${project.parent.basedir}/sun_coding_style.xml</configFile>
- </configuration>
- </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>${failsafe.version}</version>
<configuration>
<argLine>${testvm.argLine}</argLine>
+ <systemProperties>
+ <property>
+ <name>logback.configurationFile</name>
+ <value>logback.xml</value>
+ </property>
+ </systemProperties>
</configuration>
<executions>
<execution>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire.version}</version>
+ <configuration>
+ <systemProperties>
+ <property>
+ <name>logback.configurationFile</name>
+ <value>logback.xml</value>
+ </property>
+ </systemProperties>
+ </configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
</goals>
</execution>
</executions>
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>commons.logback_settings</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ </dependency>
+ </dependencies>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
+++ /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>
-
- <root level="error">
- <appender-ref ref="STDOUT" />
- </root>
-</configuration>
+++ /dev/null
-<?xml version="1.0"?>\r
-<!DOCTYPE module PUBLIC\r
- "-//Puppy Crawl//DTD Check Configuration 1.2//EN"\r
- "http://www.puppycrawl.com/dtds/configuration_1_2.dtd">\r
-\r
-<module name="Checker">\r
- <module name="FileTabCharacter">\r
- <property name="eachLine" value="true"/>\r
- </module>\r
-\r
- <module name="RegexpSingleline">\r
- <!-- \s matches whitespace character, $ matches end of line. -->\r
- <property name="format" value="\s+$"/>\r
- <property name="message" value="Line has trailing spaces."/>\r
- </module>\r
-\r
-</module>\r
--- /dev/null
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-subsystem</artifactId>
+ <version>0.2.3-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>netty-event-executor-config</artifactId>
+ <description>Configuration Wrapper around netty's event executor</description>
+ <packaging>bundle</packaging>
+ <name>${project.artifactId}</name>
+ <prerequisites>
+ <maven>3.0.4</maven>
+ </prerequisites>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>threadpool-config-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+
+ <!--test dependencies -->
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-manager</artifactId>
+ <scope>test</scope>
+ <type>test-jar</type>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-manager</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-util</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.bgpcep</groupId>
+ <artifactId>mockito-configuration</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-maven-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
+ <Export-Package>
+ </Export-Package>
+ <Import-Package>
+ com.google.common.base,
+ org.opendaylight.controller.config.yang.threadpool,
+ io.netty.util.concurrent,
+ org.opendaylight.controller.config.api,
+ org.opendaylight.controller.config.api.annotations,
+ org.opendaylight.controller.config.api.runtime,
+ org.opendaylight.controller.config.spi,
+ org.slf4j,
+ org.osgi.framework
+ </Import-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <distributionManagement>
+ <site>
+ <id>${project.artifactId}</id>
+ <name>NETTY-EVENT-EXECUTOR-CONFIG Module site</name>
+ <url>${basedir}/target/site/${project.artifactId}</url>
+ </site>
+ </distributionManagement>
+
+</project>
\ No newline at end of file
--- /dev/null
+/**
+ * Generated file
+
+ * Generated from: yang module name: netty-event-executor yang module local name: netty-global-event-executor
+ * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+ * Generated at: Tue Nov 12 10:44:21 CET 2013
+ *
+ * Do not modify this file unless it is present under src/main directory
+ */
+package org.opendaylight.controller.config.yang.netty.eventexecutor;
+
+import io.netty.util.concurrent.AbstractEventExecutor;
+import io.netty.util.concurrent.EventExecutor;
+import io.netty.util.concurrent.EventExecutorGroup;
+import io.netty.util.concurrent.Future;
+import io.netty.util.concurrent.GlobalEventExecutor;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+*
+*/
+public final class GlobalEventExecutorModule extends
+ org.opendaylight.controller.config.yang.netty.eventexecutor.AbstractGlobalEventExecutorModule {
+
+ public GlobalEventExecutorModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier,
+ org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+ super(identifier, dependencyResolver);
+ }
+
+ public GlobalEventExecutorModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier,
+ org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
+ GlobalEventExecutorModule oldModule, java.lang.AutoCloseable oldInstance) {
+ super(identifier, dependencyResolver, oldModule, oldInstance);
+ }
+
+ @Override
+ public void validate() {
+ super.validate();
+ // Add custom validation for module attributes here.
+ }
+
+ @Override
+ public java.lang.AutoCloseable createInstance() {
+ return new GlobalEventExecutorCloseable(GlobalEventExecutor.INSTANCE);
+ }
+
+ static final private class GlobalEventExecutorCloseable extends AbstractEventExecutor implements AutoCloseable {
+
+ private EventExecutor executor;
+
+ public GlobalEventExecutorCloseable(EventExecutor executor) {
+ this.executor = executor;
+ }
+
+ @Override
+ public EventExecutorGroup parent() {
+ return this.executor.parent();
+ }
+
+ @Override
+ public boolean inEventLoop(Thread thread) {
+ return this.executor.inEventLoop(thread);
+ }
+
+ @Override
+ public boolean isShuttingDown() {
+ return this.executor.isShuttingDown();
+ }
+
+ @Override
+ public Future<?> shutdownGracefully(long quietPeriod, long timeout, TimeUnit unit) {
+ return this.executor.shutdownGracefully(quietPeriod, timeout, unit);
+ }
+
+ @Override
+ public Future<?> terminationFuture() {
+ return this.executor.terminationFuture();
+ }
+
+ @Override
+ public boolean isShutdown() {
+ return this.executor.isShutdown();
+ }
+
+ @Override
+ public boolean isTerminated() {
+ return this.executor.isTerminated();
+ }
+
+ @Override
+ public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
+ return this.executor.awaitTermination(timeout, unit);
+ }
+
+ @Override
+ public void execute(Runnable command) {
+ this.executor.execute(command);
+ }
+
+ @Override
+ public void close() throws Exception {
+ shutdownGracefully();
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override
+ public void shutdown() {
+ this.executor.shutdown();
+ }
+
+ }
+}
--- /dev/null
+/**
+* Generated file
+
+* Generated from: yang module name: netty-event-executor yang module local name: netty-global-event-executor
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Tue Nov 12 10:44:21 CET 2013
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.controller.config.yang.netty.eventexecutor;
+
+/**
+*
+*/
+public class GlobalEventExecutorModuleFactory extends org.opendaylight.controller.config.yang.netty.eventexecutor.AbstractGlobalEventExecutorModuleFactory
+{
+
+
+}
--- /dev/null
+// vi: set smarttab et sw=4 tabstop=4:
+module netty-event-executor {
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:controller:netty:eventexecutor";
+ prefix "netty-t";
+
+ import config { prefix config; revision-date 2013-04-05; }
+ import threadpool { prefix th; revision-date 2013-04-09; }
+
+ organization "Cisco Systems, Inc.";
+
+ contact "Milos Fabian <milfabia@cisco.com>";
+
+ description
+ "This module contains the base YANG definitions for NS-OS
+ thread-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 "2013-11-12" {
+ description
+ "Initial revision";
+ }
+
+ identity netty-global-event-executor {
+ base config:module-type;
+ config:provided-service th:netty-event-executor;
+ config:java-name-prefix GlobalEventExecutor;
+ }
+
+ augment "/config:modules/config:module/config:configuration" {
+ case netty-global-event-executor {
+ when "/config:modules/config:module/config:type = 'netty-global-event-executor'";
+
+ }
+ }
+
+
+}
--- /dev/null
+package org.opendaylight.controller.config.yang.netty.eventexecutor;
+
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.ObjectName;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.config.api.ConflictingVersionException;
+import org.opendaylight.controller.config.api.ValidationException;
+import org.opendaylight.controller.config.api.jmx.CommitStatus;
+import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
+import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
+import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
+
+public class GlobalEventExecutorModuleTest extends AbstractConfigTest {
+
+ private GlobalEventExecutorModuleFactory factory;
+ private final String instanceName = "netty1";
+
+ @Before
+ public void setUp() {
+ factory = new GlobalEventExecutorModuleFactory();
+ super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(factory));
+ }
+
+ @Test
+ public void testCreateBean() throws InstanceAlreadyExistsException, ValidationException,
+ ConflictingVersionException {
+ ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
+
+ createInstance(transaction, instanceName);
+ createInstance(transaction, instanceName + 2);
+ transaction.validateConfig();
+ CommitStatus status = transaction.commit();
+
+ assertBeanCount(2, factory.getImplementationName());
+ assertStatus(status, 2, 0, 0);
+ }
+
+ @Test
+ public void testReusingOldInstance() throws InstanceAlreadyExistsException, ConflictingVersionException,
+ ValidationException {
+
+ ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
+ createInstance(transaction, instanceName);
+
+ transaction.commit();
+
+ transaction = configRegistryClient.createTransaction();
+ assertBeanCount(1, factory.getImplementationName());
+ CommitStatus status = transaction.commit();
+
+ assertBeanCount(1, factory.getImplementationName());
+ assertStatus(status, 0, 0, 1);
+ }
+
+ private ObjectName createInstance(ConfigTransactionJMXClient transaction, String instanceName)
+ throws InstanceAlreadyExistsException {
+ ObjectName nameCreated = transaction.createModule(factory.getImplementationName(), instanceName);
+ transaction.newMBeanProxy(nameCreated, GlobalEventExecutorModuleMXBean.class);
+ return nameCreated;
+ }
+
+}
<module>threadpool-config-api</module>
<module>threadpool-config-impl</module>
<module>netty-threadgroup-config</module>
+ <module>netty-event-executor-config</module>
</modules>
<profiles>
org.opendaylight.controller.config.api.*,
com.google.common.eventbus,
io.netty.channel,
+ io.netty.util.concurrent
</Import-Package>
<Export-Package>
org.opendaylight.controller.config.threadpool,
base "config:service-type";
config:java-class "io.netty.channel.EventLoopGroup";
}
+
+ identity netty-event-executor {
+ description
+ "Configuration wrapper around netty's event executor";
+
+ base "config:service-type";
+ config:java-class "io.netty.util.concurrent.EventExecutor";
+ }
}
<artifactId>model-flow-management</artifactId>
<version>${mdsal.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller.md</groupId>
+ <artifactId>inventory-manager</artifactId>
+ <version>${mdsal.version}</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>yang-jmx-generator-plugin</artifactId>
<version>${config.version}</version>
</dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>yang-jmx-generator-it</artifactId>
- <version>${config.version}</version>
- </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>yang-store-api</artifactId>
<artifactId>yang-store-impl</artifactId>
<version>${config.version}</version>
</dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>yang-test</artifactId>
- <version>${config.version}</version>
- </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>logback-config</artifactId>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
- <artifactId>binding-generator-util</artifactId>
+ <artifactId>binding-generator-spi</artifactId>
<version>${yangtools.binding.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
- <artifactId>binding-model-api</artifactId>
+ <artifactId>binding-generator-api</artifactId>
<version>${yangtools.binding.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
- <artifactId>binding-generator-spi</artifactId>
+ <artifactId>binding-generator-impl</artifactId>
+ <version>${yangtools.binding.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>binding-generator-util</artifactId>
+ <version>${yangtools.binding.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>binding-model-api</artifactId>
<version>${yangtools.binding.version}</version>
</dependency>
<dependency>
</dependency>
</dependencies>
</profile>
+ <profile>
+ <id>integrationtests</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>2.8</version>
+ <executions>
+ <execution>
+ <id>copy</id>
+ <phase>package</phase>
+ <goals>
+ <goal>copy</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <artifactItems>
+ <artifactItem>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sanitytest</artifactId>
+ <version>${controller.version}</version>
+ <type>jar</type>
+ </artifactItem>
+ </artifactItems>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>exec-maven-plugin</artifactId>
+ <version>1.2.1</version>
+ <executions>
+ <execution>
+ <id>sanity-test</id>
+ <phase>package</phase>
+ <goals>
+ <goal>exec</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <executable>${java.home}/bin/java</executable>
+ <arguments>
+ <argument>-cp</argument>
+ <argument>./target/dependency/*</argument>
+ <argument>org.opendaylight.controller.distribution.Sanity</argument>
+ </arguments>
+ <environmentVariables>
+ <JAVA_HOME>
+ ${java.home}
+ </JAVA_HOME>
+ </environmentVariables>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
</profiles>
<artifactId>distribution.opendaylight</artifactId>
</execution>
</executions>
</plugin>
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-dependency-plugin</artifactId>
- <version>2.8</version>
- <executions>
- <execution>
- <id>copy</id>
- <phase>package</phase>
- <goals>
- <goal>copy</goal>
- </goals>
- </execution>
- </executions>
- <configuration>
- <artifactItems>
- <artifactItem>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sanitytest</artifactId>
- <version>${controller.version}</version>
- <type>jar</type>
- </artifactItem>
- </artifactItems>
- </configuration>
- </plugin>
-
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>exec-maven-plugin</artifactId>
- <version>1.2.1</version>
- <executions>
- <execution>
- <id>sanity-test</id>
- <phase>package</phase>
- <goals>
- <goal>exec</goal>
- </goals>
- </execution>
- </executions>
- <configuration>
- <executable>${java.home}/bin/java</executable>
- <arguments>
- <argument>-cp</argument>
- <argument>./target/dependency/*</argument>
- <argument>org.opendaylight.controller.distribution.Sanity</argument>
- </arguments>
- <environmentVariables>
- <JAVA_HOME>
- ${java.home}
- </JAVA_HOME>
- </environmentVariables>
- </configuration>
- </plugin>
</plugins>
</build>
</project>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>commons.logback_settings</artifactId>
+ </dependency>
</dependencies>
</project>
+++ /dev/null
-<configuration scan="true">\r
-\r
- <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">\r
- <encoder>\r
- <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n\r
- </pattern>\r
- </encoder>\r
- </appender>\r
-\r
- <root level="error">\r
- <appender-ref ref="STDOUT" />\r
- </root>\r
-</configuration>\r
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>commons.logback_settings</artifactId>
+ </dependency>
</dependencies>
</project>
+++ /dev/null
-<configuration scan="true">\r
-\r
- <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">\r
- <encoder>\r
- <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n\r
- </pattern>\r
- </encoder>\r
- </appender>\r
-\r
- <root level="error">\r
- <appender-ref ref="STDOUT" />\r
- </root>\r
-</configuration>\r
<configuration>
<instructions>
<Export-Package>
+ org.opendaylight.controller.datastore
</Export-Package>
<Import-Package>
javax.xml.bind.annotation,
org.opendaylight.controller.sal.topology,
org.opendaylight.controller.clustering.services,
org.opendaylight.controller.md.sal.common.api.data,
+ org.opendaylight.controller.sal.common.util,
org.opendaylight.yangtools.yang.binding,
org.osgi.service.component,
org.slf4j,
org.apache.commons.lang3.builder,
org.apache.commons.lang3.tuple,
org.eclipse.osgi.framework.console,
- org.osgi.framework
+ org.osgi.framework,
+ com.google.common.base
</Import-Package>
<Bundle-Activator>
org.opendaylight.controller.datastore.internal.Activator
public static final String OPERATIONAL_DATA_CACHE = "clustered_data_store.operational_data_cache";
public static final String CONFIGURATION_DATA_CACHE = "clustered_data_store.configuration_data_cache";
- private ConcurrentMap operationalDataCache;
- private ConcurrentMap configurationDataCache;
+ private final ConcurrentMap operationalDataCache;
+ private final ConcurrentMap configurationDataCache;
public ClusteredDataStoreImpl(IClusterGlobalServices clusterGlobalServices) throws CacheExistException, CacheConfigException {
Preconditions.checkNotNull(clusterGlobalServices, "clusterGlobalServices cannot be null");
- operationalDataCache = clusterGlobalServices.createCache(OPERATIONAL_DATA_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
+ operationalDataCache = getOrCreateCache(clusterGlobalServices, OPERATIONAL_DATA_CACHE);
if(operationalDataCache == null){
Preconditions.checkNotNull(operationalDataCache, "operationalDataCache cannot be null");
}
- configurationDataCache = clusterGlobalServices.createCache(CONFIGURATION_DATA_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
+ configurationDataCache = getOrCreateCache(clusterGlobalServices, CONFIGURATION_DATA_CACHE);
if(configurationDataCache == null){
Preconditions.checkNotNull(configurationDataCache, "configurationDataCache cannot be null");
return Rpcs.<Void>getRpcResult(true, null, _emptySet);
}
+
+ private ConcurrentMap getOrCreateCache(IClusterGlobalServices clusterGlobalServices, String name) throws CacheConfigException {
+ ConcurrentMap cache = clusterGlobalServices.getCache(name);
+
+ if(cache == null) {
+ try {
+ cache = clusterGlobalServices.createCache(name, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
+ } catch (CacheExistException e) {
+ cache = clusterGlobalServices.getCache(name);
+ }
+ }
+ return cache;
+ }
+
private class ClusteredDataStoreTransaction implements DataCommitTransaction<InstanceIdentifier<? extends Object>, Object> {
private final DataModification<InstanceIdentifier<? extends Object>,Object> modification;
}
}
+ @Test
+ public void constructor_WhenOperationalDataCacheIsAlreadyPresent_ShouldNotAttemptToCreateCache() throws CacheExistException, CacheConfigException {
+ IClusterGlobalServices mockClusterGlobalServices = mock(IClusterGlobalServices.class);
+
+ Mockito.<ConcurrentMap<?,?>>when(mockClusterGlobalServices.getCache(ClusteredDataStoreImpl.OPERATIONAL_DATA_CACHE)).thenReturn(new ConcurrentHashMap<Object, Object>());
+ Mockito.<ConcurrentMap<?,?>>when(mockClusterGlobalServices.getCache(ClusteredDataStoreImpl.CONFIGURATION_DATA_CACHE)).thenReturn(new ConcurrentHashMap<Object, Object>());
+
+ new ClusteredDataStoreImpl(mockClusterGlobalServices);
+
+ verify(mockClusterGlobalServices, never()).createCache(ClusteredDataStoreImpl.OPERATIONAL_DATA_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
+ }
+
+ @Test
+ public void constructor_WhenConfigurationDataCacheIsAlreadyPresent_ShouldNotAttemptToCreateCache() throws CacheExistException, CacheConfigException {
+ IClusterGlobalServices mockClusterGlobalServices = mock(IClusterGlobalServices.class);
+
+ Mockito.<ConcurrentMap<?,?>>when(mockClusterGlobalServices.getCache(ClusteredDataStoreImpl.OPERATIONAL_DATA_CACHE)).thenReturn(new ConcurrentHashMap<Object, Object>());
+ Mockito.<ConcurrentMap<?,?>>when(mockClusterGlobalServices.getCache(ClusteredDataStoreImpl.CONFIGURATION_DATA_CACHE)).thenReturn(new ConcurrentHashMap<Object, Object>());
+
+ new ClusteredDataStoreImpl(mockClusterGlobalServices);
+
+ verify(mockClusterGlobalServices, never()).createCache(ClusteredDataStoreImpl.CONFIGURATION_DATA_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
+ }
+
+
@Test
public void constructor_WhenPassedAValidClusteringServices_ShouldNotThrowAnyExceptions() throws CacheExistException, CacheConfigException {
IClusterGlobalServices mockClusterGlobalServices = createClusterGlobalServices();
+
+/*
+ * 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.datastore.internal;
import org.apache.felix.dm.Component;
<artifactId>clustered-datastore.integrationtest</artifactId>
<version>0.4.0-SNAPSHOT</version>
<dependencies>
+
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-common-api</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-common-util</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-common-impl</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-binding-broker-impl</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal</artifactId>
+ <version>0.5.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>clustering.services</artifactId>
+ <version>0.4.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-binding</artifactId>
+ </dependency>
+
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>protocol_plugins.stub</artifactId>
<version>0.4.1-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal</artifactId>
- <version>0.5.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>containermanager.it.implementation</artifactId>
<version>0.5.0-SNAPSHOT</version>
</dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>clustering.services</artifactId>
- <version>0.4.0-SNAPSHOT</version>
- </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>clustering.stub</artifactId>
<version>0.4.1-SNAPSHOT</version>
</dependency>
- </dependencies>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-common</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-common</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>concepts</artifactId>
+ <version>0.1.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <version>1.9.5</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>5.0.0</version>
+ </dependency>
+
+</dependencies>
<properties>
<!-- Sonar jacoco plugin to get integration test coverage info -->
<sonar.jacoco.reportPath>../implementation/target/jacoco.exec</sonar.jacoco.reportPath>
package org.opendaylight.controller.datastore;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.ops4j.pax.exam.Configuration;
import org.ops4j.pax.exam.util.PathUtils;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
-import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
import static org.ops4j.pax.exam.CoreOptions.junitBundles;
import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
import static org.ops4j.pax.exam.CoreOptions.options;
import static org.ops4j.pax.exam.CoreOptions.systemPackages;
import static org.ops4j.pax.exam.CoreOptions.systemProperty;
+import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.controller.md.sal.common.api.data.DataModification;
+import static org.mockito.Mockito.mock;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.when;
@RunWith(PaxExam.class)
public class ClusteredDataStoreIT {
// get the OSGI bundle context
@Inject
private BundleContext bc;
-
+ @Inject
+ private ClusteredDataStore clusteredDS;
// Configure the OSGi container
@Configuration
public Option[] config() {
systemProperty("osgi.console").value("2401"),
// Set the systemPackages (used by clustering)
systemPackages("sun.reflect", "sun.reflect.misc", "sun.misc"),
+ systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("DEBUG"),
// List framework bundles
mavenBundle("equinoxSDK381", "org.eclipse.equinox.console").versionAsInProject(),
mavenBundle("equinoxSDK381", "org.eclipse.equinox.util").versionAsInProject(),
mavenBundle("org.opendaylight.controller", "protocol_plugins.stub")
.versionAsInProject(),
+ //clustered-data-store-implementation dependencies
+ mavenBundle("com.google.guava", "guava")
+ .versionAsInProject(),
+ mavenBundle("org.opendaylight.controller", "sal-common-api")
+ .versionAsInProject(),
+ mavenBundle("org.opendaylight.controller", "sal-common-util")
+ .versionAsInProject(),
+ mavenBundle("org.opendaylight.controller", "sal-common-impl")
+ .versionAsInProject(),
+ mavenBundle("org.opendaylight.yangtools", "yang-binding")
+ .versionAsInProject(),
+
+
+ //sal-common-api dependencies
+ mavenBundle("org.opendaylight.controller", "sal-common")
+ .versionAsInProject(),
+ mavenBundle("org.opendaylight.yangtools", "yang-common")
+ .versionAsInProject(),
+ mavenBundle("org.opendaylight.yangtools", "concepts")
+ .versionAsInProject(),
+ mavenBundle("org.osgi", "org.osgi.core")
+ .versionAsInProject(),
+ //adding new maven bundles
+ mavenBundle("org.mockito", "mockito-all")
+ .versionAsInProject(),
+
// needed by hosttracker
mavenBundle("org.opendaylight.controller", "clustered-datastore-implementation")
.versionAsInProject(),
}
}
+ @Before
+ public void areWeReady() {
+ assertNotNull(bc);
+ boolean debugit = false;
+ Bundle b[] = bc.getBundles();
+ for (int i = 0; i < b.length; i++) {
+ int state = b[i].getState();
+ if (state != Bundle.ACTIVE && state != Bundle.RESOLVED) {
+ log.debug("Bundle:" + b[i].getSymbolicName() + " state:"
+ + stateToString(state));
+ debugit = true;
+ }
+ }
+ if (debugit) {
+ log.debug("Do some debugging because some bundle is "
+ + "unresolved");
+ }
+ }
+
+ @Test
+ public void testBundleContextClusteredDS_NotNull() throws Exception{
+ ServiceReference serviceReference = bc.getServiceReference(ClusteredDataStore.class);
+ ClusteredDataStore store = ClusteredDataStore.class.cast(bc.getService(serviceReference));
+ assertNotNull(store);
+ }
+
+ @Test
+ public void testInjected_ClusteredDS_NotNull(){
+ assertNotNull(clusteredDS);
+ }
+
@Test
- public void testDoNothing() throws Exception{
- assertTrue(true);
+ public void requestCommit_readConfigurationData_ShouldVerifyDataAndNoException(){
+ DataModification dataModification = mock(DataModification.class);
+ HashMap map = new HashMap();
+ List list = new ArrayList();
+ list.add("key");
+ InstanceIdentifier key = new InstanceIdentifier(list,String.class);
+ map.put(key, "value");
+ when(dataModification.getUpdatedConfigurationData()).thenReturn(map);
+ DataCommitTransaction dataCommitTrans = clusteredDS.requestCommit(dataModification);
+ dataCommitTrans.finish();
+ String value = (String)clusteredDS.readConfigurationData(key);
+ assertEquals("value",value);
}
+ @Test(expected = NullPointerException.class)
+ public void requestCommit_ShouldThrowException(){
+ DataModification dataModification = null;
+ DataCommitTransaction dataCommitTrans = clusteredDS.requestCommit(dataModification);
+ dataCommitTrans.finish();
+ }
+
+ @Test
+ public void requestCommit_readOperationalData_ShouldVerifyDataAndNoException(){
+ DataModification dataModification = mock(DataModification.class);
+ HashMap map = new HashMap();
+ List list = new ArrayList();
+ list.add("key");
+ InstanceIdentifier key = new InstanceIdentifier(list,String.class);
+ map.put(key, "value");
+ when(dataModification.getUpdatedOperationalData()).thenReturn(map);
+ DataCommitTransaction dataCommitTrans = clusteredDS.requestCommit(dataModification);
+ dataCommitTrans.finish();
+ String value = (String)clusteredDS.readOperationalData(key);
+ assertEquals("value",value);
+ }
+
+ @Test
+ public void requestCommit_readConfigurationData_NonExistingKey_ShouldVerifyNoMappedValueAndNoException(){
+ DataModification dataModification = mock(DataModification.class);
+ HashMap map = new HashMap();
+ List list = new ArrayList();
+ list.add("key");
+ InstanceIdentifier key = new InstanceIdentifier(list,String.class);
+ map.put(key, "value");
+ when(dataModification.getUpdatedConfigurationData()).thenReturn(map);
+ DataCommitTransaction dataCommitTrans = clusteredDS.requestCommit(dataModification);
+ dataCommitTrans.finish();
+ list = new ArrayList();
+ list.add("key1");
+ InstanceIdentifier key1 = new InstanceIdentifier(list,String.class);
+
+ String value = (String)clusteredDS.readConfigurationData(key1);
+ assertNull(value);
+ }
+
+ @Test
+ public void requestCommit_readOperationalData_NonExistingKey_ShouldVerifyNoMappedValueAndNoException(){
+ DataModification dataModification = mock(DataModification.class);
+ HashMap map = new HashMap();
+ List list = new ArrayList();
+ list.add("key");
+ InstanceIdentifier key = new InstanceIdentifier(list,String.class);
+ map.put(key, "value");
+ when(dataModification.getUpdatedOperationalData()).thenReturn(map);
+ DataCommitTransaction dataCommitTrans = clusteredDS.requestCommit(dataModification);
+ dataCommitTrans.finish();
+ list = new ArrayList();
+ list.add("key1");
+ InstanceIdentifier key1 = new InstanceIdentifier(list,String.class);
+
+ String value = (String)clusteredDS.readOperationalData(key1);
+ assertNull(value);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void requestCommit_readConfigurationData_WithNullPathShouldThrowException(){
+ DataModification dataModification = mock(DataModification.class);
+ HashMap map = new HashMap();
+ List list = new ArrayList();
+ list.add("key");
+ InstanceIdentifier key = new InstanceIdentifier(list,String.class);
+ map.put(key, "value");
+ when(dataModification.getUpdatedConfigurationData()).thenReturn(map);
+ DataCommitTransaction dataCommitTrans = clusteredDS.requestCommit(dataModification);
+ dataCommitTrans.finish();
+ String value = (String)clusteredDS.readConfigurationData(null);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void requestCommit_readOperationalData_WithNullPathShouldThrowException(){
+ DataModification dataModification = mock(DataModification.class);
+ HashMap map = new HashMap();
+ List list = new ArrayList();
+ list.add("key");
+ InstanceIdentifier key = new InstanceIdentifier(list,String.class);
+ map.put(key, "value");
+ when(dataModification.getOriginalOperationalData()).thenReturn(map);
+ DataCommitTransaction dataCommitTrans = clusteredDS.requestCommit(dataModification);
+ dataCommitTrans.finish();
+ String value = (String)clusteredDS.readOperationalData(null);
+ }
}
--- /dev/null
+module opendaylight-group-statistics {
+ namespace "urn:opendaylight:group:statistics";
+ prefix groupstat;
+
+ import yang-ext {prefix ext; revision-date "2013-07-09";}
+ import opendaylight-inventory {prefix inv;revision-date "2013-08-19";}
+ import opendaylight-group-types {prefix group-types;revision-date "2013-10-18";}
+ import flow-capable-transaction {prefix tr;}
+
+ revision "2013-11-11" {
+ description "Initial revision of group statistics service";
+ }
+
+ // RPC calls
+ rpc get-all-group-statistics {
+ input {
+ uses inv:node-context-ref;
+ }
+ output {
+ list group-statistics {
+ uses group-types:group-statistics;
+ }
+ uses tr:transaction-aware;
+ }
+
+ }
+
+ rpc get-group-statistics {
+ input {
+ uses inv:node-context-ref;
+ leaf group-id{
+ type group-types:group-id;
+ }
+ }
+ output {
+ uses group-types:group-statistics;
+ uses tr:transaction-aware;
+ }
+
+ }
+
+ rpc get-group-description {
+ input {
+ uses inv:node-context-ref;
+ leaf group-id{
+ type group-types:group-id;
+ }
+ }
+ output {
+ uses group-types:group-desc-stats;
+ uses tr:transaction-aware;
+ }
+ }
+
+ rpc get-group-features {
+ input {
+ uses inv:node-context-ref;
+ leaf group-id{
+ type group-types:group-id;
+ }
+ }
+ output {
+ uses group-types:group-features;
+ uses tr:transaction-aware;
+ }
+ }
+
+
+ //Notification calls
+
+ notification group-statistics-updated {
+ uses group-types:group-statistics;
+ uses tr:transaction-aware;
+ }
+
+ notification group-desc-stats-updated {
+ uses group-types:group-desc-stats;
+ uses tr:transaction-aware;
+ }
+
+ notification group-features {
+ uses group-types:group-features;
+ uses tr:transaction-aware;
+ }
+}
--- /dev/null
+module opendaylight-meter-statistics {
+ namespace "urn:opendaylight:meter:statistics";
+ prefix meterstat;
+
+ import yang-ext {prefix ext; revision-date "2013-07-09";}
+ import opendaylight-inventory {prefix inv;revision-date "2013-08-19";}
+ import opendaylight-meter-types {prefix meter-types;revision-date "2013-09-18";}
+ import flow-capable-transaction {prefix tr;}
+
+
+ revision "2013-11-11" {
+ description "Initial revision of meter statistics service";
+ }
+
+ // RPC calls
+ rpc get-all-meter-statistics {
+ input {
+ uses inv:node-context-ref;
+ }
+ output {
+ list meter-statistics {
+ uses meter-types:meter-statistics;
+ uses tr:transaction-aware;
+ }
+ }
+
+ }
+
+ rpc get-meter-statistics {
+ description "RPC Method to send meter statistics request to the give switch for specific meter";
+ input {
+ uses inv:node-context-ref;
+ leaf meter-id{
+ type meter-types:meter-id;
+ }
+ }
+ output {
+ uses meter-types:meter-statistics;
+ uses tr:transaction-aware;
+ }
+
+ }
+
+ rpc get-meter-config-statistics {
+ input {
+ uses inv:node-context-ref;
+ leaf meter-id{
+ type meter-types:meter-id;
+ }
+ }
+ output {
+ uses meter-types:meter-config-stats;
+ uses tr:transaction-aware;
+ }
+ }
+
+ rpc get-meter-features {
+ input {
+ uses inv:node-context-ref;
+ leaf meter-id{
+ type meter-types:meter-id;
+ }
+ }
+ output {
+ uses meter-types:meter-features;
+ uses tr:transaction-aware;
+ }
+ }
+
+
+ //Notification calls
+
+ notification meter-statistics-updated {
+ uses meter-types:meter-statistics;
+ uses tr:transaction-aware;
+ }
+
+ notification meter-config-stats-updated {
+ uses meter-types:meter-config-stats;
+ uses tr:transaction-aware;
+ }
+
+ notification meter-features {
+ uses meter-types:meter-features;
+ uses tr:transaction-aware;
+ }
+}
<module>compatibility</module>
<module>sal-zeromq-connector</module>
- <module>test</module>
</modules>
<modules>
<module>sal-binding-it</module>
<module>clustered-data-store/integrationtest</module>
+ <module>test</module>
</modules>
</profile>
</profiles>
<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.jacoco</groupId>
- <artifactId>jacoco-maven-plugin</artifactId>
- <versionRange>[0.0,)</versionRange>
- <goals>
- <goal>prepare-agent</goal>
- <goal>pre-test</goal>
- <goal>post-test</goal>
- </goals>
- </pluginExecutionFilter>
- <action>
- <ignore />
- </action>
- </pluginExecution>
- </pluginExecutions>
- </lifecycleMappingMetadata>
- </configuration>
- </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
- <groupId>
- org.opendaylight.yangtools
- </groupId>
- <artifactId>
- yang-maven-plugin
- </artifactId>
- <versionRange>
- [0.5,)
- </versionRange>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-maven-plugin</artifactId>
+ <versionRange>[0,)</versionRange>
+ <goals>
+ <goal>generate-sources</goal>
+ </goals>
+ </pluginExecutionFilter>
+ <action>
+ <ignore/>
+ </action>
+ </pluginExecution>
+ <pluginExecution>
+ <pluginExecutionFilter>
+ <groupId>net.alchim31.maven</groupId>
+ <artifactId>scala-maven-plugin</artifactId>
+ <versionRange>[0,)</versionRange>
<goals>
- <goal>
- generate-sources
- </goal>
+ <goal>compile</goal>
+ <goal>testCompile</goal>
</goals>
</pluginExecutionFilter>
<action>
- <ignore></ignore>
+ <ignore/>
</action>
</pluginExecution>
<pluginExecution>
<pluginExecutionFilter>
<groupId>org.jacoco</groupId>
- <artifactId>
- jacoco-maven-plugin
- </artifactId>
- <versionRange>
- [0.5.3.201107060350,)
- </versionRange>
+ <artifactId>jacoco-maven-plugin</artifactId>
+ <versionRange>[0,)</versionRange>
<goals>
<goal>prepare-agent</goal>
</goals>
</pluginExecutionFilter>
<action>
- <ignore></ignore>
+ <ignore/>
</action>
</pluginExecution>
</pluginExecutions>
<build>
<plugins>
+
<plugin>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-maven-plugin</artifactId>
</dependency>
</dependencies>
</plugin>
+
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
<version>${osgi.core.version}</version>
+ <scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>javassist</artifactId>
<version>3.17.1-GA</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>binding-generator-impl</artifactId>
+ <version>0.6.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-parser-impl</artifactId>
+ <version>0.5.9-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-core-api</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-broker-impl</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <scope>runtime</scope>
+ </dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<groupId>org.eclipse.xtend</groupId>
<artifactId>org.eclipse.xtend.lib</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.eclipse.xtend</groupId>
+ <artifactId>org.eclipse.xtend.standalone</artifactId>
+ <version>2.4.3</version>
+ <scope>runtime</scope>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-config</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller.model</groupId>
+ <artifactId>model-flow-service</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-impl</artifactId>
+ <version>0.5.9-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-model-util</artifactId>
+ <version>0.5.9-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ <version>${slf4j.version}</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</project>
import static extension org.opendaylight.controller.sal.binding.codegen.YangtoolsMappingHelper.*
import static extension org.opendaylight.controller.sal.binding.codegen.RuntimeCodeSpecification.*
import java.util.HashSet
-import static org.opendaylight.controller.sal.binding.impl.osgi.ClassLoaderUtils.*
+import static org.opendaylight.controller.sal.binding.impl.util.ClassLoaderUtils.*
import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory
import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory.NotificationInvoker
import java.util.Set
import org.opendaylight.yangtools.yang.binding.BaseIdentity
import com.google.common.collect.Multimap
import com.google.common.collect.HashMultimap
-import static org.opendaylight.controller.sal.binding.impl.osgi.ClassLoaderUtils.*
+import static org.opendaylight.controller.sal.binding.impl.util.ClassLoaderUtils.*
import java.util.concurrent.Executors
import java.util.Collections
import org.opendaylight.yangtools.yang.binding.DataObject
+import org.opendaylight.controller.sal.binding.impl.connect.dom.ConnectorActivator
class BindingAwareBrokerImpl implements BindingAwareBroker, AutoCloseable {
private static val log = LoggerFactory.getLogger(BindingAwareBrokerImpl)
ServiceRegistration<DataBrokerService> dataConsumerRegistration
- private HashMapDataStore store = new HashMapDataStore();
+ ConnectorActivator connectorActivator
+
public new(BundleContext bundleContext) {
_brokerBundleContext = bundleContext;
notifyConsumerRegistration = brokerBundleContext.registerService(NotificationService, notifyBroker, brokerProperties)
dataProviderRegistration = brokerBundleContext.registerService(DataProviderService, dataBroker, brokerProperties)
dataConsumerRegistration = brokerBundleContext.registerService(DataBrokerService, dataBroker, brokerProperties)
-
-
- getDataBroker().registerDataReader(root, store);
- getDataBroker().registerCommitHandler(root, store)
-
+
+ connectorActivator = new ConnectorActivator(dataBroker,brokerBundleContext);
+ connectorActivator.start();
log.info("MD-SAL: Binding Aware Broker Started");
}
--- /dev/null
+package org.opendaylight.controller.sal.binding.impl;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+
+import org.opendaylight.controller.md.sal.common.api.data.DataReader;
+import org.opendaylight.controller.md.sal.common.impl.service.AbstractDataBroker;
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.controller.sal.binding.impl.util.BindingAwareDataReaderRouter;
+import org.opendaylight.controller.sal.common.DataStoreIdentifier;
+import org.opendaylight.yangtools.concepts.Registration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.DataRoot;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+
+public class DataBrokerImpl extends AbstractDataBroker<InstanceIdentifier<? extends DataObject>, DataObject, DataChangeListener> implements
+ DataProviderService {
+
+ public DataBrokerImpl() {
+ setDataReadRouter(new BindingAwareDataReaderRouter());
+ }
+
+ @Override
+ public DataTransactionImpl beginTransaction() {
+ return new DataTransactionImpl(this);
+ }
+
+ @Override
+ public <T extends DataRoot> T getData(DataStoreIdentifier store, Class<T> rootType) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public <T extends DataRoot> T getData(DataStoreIdentifier store, T filter) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, Class<T> rootType) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, T filter) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public RpcResult<DataRoot> editCandidateData(DataStoreIdentifier store, DataRoot changeSet) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Future<RpcResult<Void>> commit(DataStoreIdentifier store) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public DataObject getData(InstanceIdentifier<? extends DataObject> data) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public DataObject getConfigurationData(InstanceIdentifier<?> data) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void registerChangeListener(InstanceIdentifier<? extends DataObject> path, DataChangeListener changeListener) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void unregisterChangeListener(InstanceIdentifier<? extends DataObject> path,
+ DataChangeListener changeListener) {
+ // TODO Auto-generated method stub
+
+ }
+
+
+}
\ No newline at end of file
+++ /dev/null
-package org.opendaylight.controller.sal.binding.impl
-
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler
-import org.opendaylight.controller.sal.binding.api.data.DataChangeListener
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.opendaylight.controller.md.sal.common.api.TransactionStatus
-import org.opendaylight.controller.md.sal.common.api.data.DataReader
-import org.opendaylight.yangtools.concepts.AbstractObjectRegistration
-import org.opendaylight.yangtools.concepts.ListenerRegistration
-import com.google.common.collect.Multimap
-import static com.google.common.base.Preconditions.*;
-import java.util.List
-import com.google.common.collect.HashMultimap
-import java.util.concurrent.ExecutorService
-import java.util.concurrent.Callable
-import org.opendaylight.yangtools.yang.common.RpcResult
-import org.opendaylight.controller.sal.common.util.Rpcs
-import java.util.Collections
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction
-import java.util.ArrayList
-import org.opendaylight.controller.sal.binding.impl.util.BindingAwareDataReaderRouter
-import org.opendaylight.yangtools.concepts.CompositeObjectRegistration
-import java.util.Arrays
-
-class DataBrokerImpl extends DeprecatedDataAPISupport implements DataProviderService {
-
- @Property
- var ExecutorService executor;
-
- val dataReadRouter = new BindingAwareDataReaderRouter;
-
- Multimap<InstanceIdentifier, DataChangeListenerRegistration> listeners = HashMultimap.create();
- Multimap<InstanceIdentifier, DataCommitHandlerRegistration> commitHandlers = HashMultimap.create();
-
- override beginTransaction() {
- return new DataTransactionImpl(this);
- }
-
- override readConfigurationData(InstanceIdentifier<? extends DataObject> path) {
- return dataReadRouter.readConfigurationData(path);
- }
-
- override readOperationalData(InstanceIdentifier<? extends DataObject> path) {
- return dataReadRouter.readOperationalData(path);
- }
-
- override registerCommitHandler(InstanceIdentifier<? extends DataObject> path,
- DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject> commitHandler) {
- val registration = new DataCommitHandlerRegistration(path,commitHandler,this);
- commitHandlers.put(path,registration)
- return registration;
- }
-
- override registerDataChangeListener(InstanceIdentifier<? extends DataObject> path, DataChangeListener listener) {
- val reg = new DataChangeListenerRegistration(path, listener, this);
- listeners.put(path, reg);
- return reg;
- }
-
- override registerDataReader(InstanceIdentifier<? extends DataObject> path,DataReader<InstanceIdentifier<? extends DataObject>,DataObject> reader) {
-
- val confReg = dataReadRouter.registerConfigurationReader(path,reader);
- val dataReg = dataReadRouter.registerOperationalReader(path,reader);
-
- return new CompositeObjectRegistration(reader,Arrays.asList(confReg,dataReg));
- }
-
- protected def removeListener(DataChangeListenerRegistration registration) {
- listeners.remove(registration.path, registration);
- }
-
- protected def removeCommitHandler(DataCommitHandlerRegistration registration) {
- commitHandlers.remove(registration.path, registration);
- }
-
- protected def getActiveCommitHandlers() {
- return commitHandlers.entries.map[ value.instance].toSet
- }
-
- protected def commit(DataTransactionImpl transaction) {
- checkNotNull(transaction);
- transaction.changeStatus(TransactionStatus.SUBMITED);
- val task = new TwoPhaseCommit(transaction, this);
- return executor.submit(task);
- }
-
-}
-
-package class DataChangeListenerRegistration extends AbstractObjectRegistration<DataChangeListener> implements ListenerRegistration<DataChangeListener> {
-
- DataBrokerImpl dataBroker;
-
- @Property
- val InstanceIdentifier<?> path;
-
- new(InstanceIdentifier<?> path, DataChangeListener instance, DataBrokerImpl broker) {
- super(instance)
- dataBroker = broker;
- _path = path;
- }
-
- override protected removeRegistration() {
- dataBroker.removeListener(this);
- dataBroker = null;
- }
-
-}
-
-package class DataCommitHandlerRegistration //
-extends AbstractObjectRegistration<DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject>> {
-
- DataBrokerImpl dataBroker;
-
- @Property
- val InstanceIdentifier<?> path;
-
- new(InstanceIdentifier<?> path, DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject> instance,
- DataBrokerImpl broker) {
- super(instance)
- dataBroker = broker;
- _path = path;
- }
-
- override protected removeRegistration() {
- dataBroker.removeCommitHandler(this);
- dataBroker = null;
- }
-
-}
-
-package class TwoPhaseCommit implements Callable<RpcResult<TransactionStatus>> {
-
- val DataTransactionImpl transaction;
- val DataBrokerImpl dataBroker;
-
- new(DataTransactionImpl transaction, DataBrokerImpl broker) {
- this.transaction = transaction;
- this.dataBroker = broker;
- }
-
- override call() throws Exception {
-
- val Iterable<DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject>> commitHandlers = dataBroker.activeCommitHandlers;
-
- // requesting commits
- val List<DataCommitTransaction<InstanceIdentifier<? extends DataObject>, DataObject>> handlerTransactions = new ArrayList();
- try {
- for (handler : commitHandlers) {
- handlerTransactions.add(handler.requestCommit(transaction));
- }
- } catch (Exception e) {
- return rollback(handlerTransactions,e);
- }
- val List<RpcResult<Void>> results = new ArrayList();
- try {
- for (subtransaction : handlerTransactions) {
- results.add(subtransaction.finish());
- }
- } catch (Exception e) {
- return rollback(handlerTransactions,e);
- }
-
- return Rpcs.getRpcResult(true, TransactionStatus.COMMITED, Collections.emptySet());
- }
-
- def rollback(List<DataCommitTransaction<InstanceIdentifier<? extends DataObject>, DataObject>> transactions,Exception e) {
- for (transaction : transactions) {
- transaction.rollback()
- }
- // FIXME return encoutered error.
- return Rpcs.getRpcResult(false, TransactionStatus.FAILED, Collections.emptySet());
- }
-}
package org.opendaylight.controller.sal.binding.impl;
-import java.util.concurrent.Future;
-
import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
-import org.opendaylight.controller.md.sal.common.impl.AbstractDataModification;
-import org.opendaylight.controller.md.sal.common.impl.ListenerRegistry;
+import org.opendaylight.controller.md.sal.common.impl.service.AbstractDataTransaction;
import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction.DataTransactionListener;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.concepts.util.ListenerRegistry;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.common.RpcResult;
-
-public class DataTransactionImpl extends AbstractDataModification<InstanceIdentifier<? extends DataObject>, DataObject>
- implements DataModificationTransaction {
-
- private final Object identifier;
-
- private TransactionStatus status;
- private ListenerRegistry<DataTransactionListener> listeners;
-
- final DataBrokerImpl broker;
+public class DataTransactionImpl extends AbstractDataTransaction<InstanceIdentifier<? extends DataObject>, DataObject>
+ implements DataModificationTransaction {
+ private final ListenerRegistry<DataTransactionListener> listeners = new ListenerRegistry<DataTransactionListener>();
+
+
+
public DataTransactionImpl(DataBrokerImpl dataBroker) {
super(dataBroker);
- identifier = new Object();
- broker = dataBroker;
- status = TransactionStatus.NEW;
- listeners = new ListenerRegistry<>();
- }
-
- @Override
- public Future<RpcResult<TransactionStatus>> commit() {
- return broker.commit(this);
- }
-
- @Override
- public DataObject readConfigurationData(
- org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject> path) {
- return broker.readConfigurationData(path);
- }
-
- @Override
- public DataObject readOperationalData(InstanceIdentifier<? extends DataObject> path) {
- return broker.readOperationalData(path);
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((broker == null) ? 0 : broker.hashCode());
- result = prime * result + ((identifier == null) ? 0 : identifier.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- DataTransactionImpl other = (DataTransactionImpl) obj;
- if (broker == null) {
- if (other.broker != null)
- return false;
- } else if (!broker.equals(other.broker))
- return false;
- if (identifier == null) {
- if (other.identifier != null)
- return false;
- } else if (!identifier.equals(other.identifier))
- return false;
- return true;
- }
-
- @Override
- public TransactionStatus getStatus() {
- return status;
- }
-
- @Override
- public Object getIdentifier() {
- return identifier;
}
@Override
return listeners.register(listener);
}
- public void changeStatus(TransactionStatus status) {
- this.status = status;
- Iterable<ListenerRegistration<DataTransactionListener>> listenersToNotify = listeners.getListeners();
- for (ListenerRegistration<DataTransactionListener> listenerRegistration : listenersToNotify) {
+ protected void onStatusChange(TransactionStatus status) {
+ for (ListenerRegistration<DataTransactionListener> listenerRegistration : listeners) {
listenerRegistration.getInstance().onStatusUpdated(this, status);
}
}
-}
+}
\ No newline at end of file
--- /dev/null
+package org.opendaylight.controller.sal.binding.impl.connect.dom;
+
+import java.util.Collections;
+import java.util.Map.Entry;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+import org.opendaylight.controller.config.api.jmx.CommitStatus;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
+import org.opendaylight.controller.md.sal.common.api.data.DataModification;
+import org.opendaylight.controller.md.sal.common.api.data.DataReader;
+import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction;
+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.Rpcs;
+import org.opendaylight.controller.sal.core.api.data.DataBrokerService;
+import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+
+import com.google.common.base.Preconditions;
+
+public class BindingIndependentDataServiceConnector implements //
+ RuntimeDataProvider, //
+ DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject> {
+
+ private static final InstanceIdentifier<? extends DataObject> ROOT = InstanceIdentifier.builder().toInstance();
+
+ private BindingIndependentMappingService mappingService;
+
+ private DataBrokerService biDataService;
+
+ private DataProviderService baDataService;
+
+ @Override
+ public DataObject readOperationalData(InstanceIdentifier<? extends DataObject> path) {
+ // TODO Auto-generated method stub
+ org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path);
+ CompositeNode result = biDataService.readOperationalData(biPath);
+ return mappingService.dataObjectFromDataDom(path, result);
+ }
+
+ @Override
+ public DataObject readConfigurationData(InstanceIdentifier<? extends DataObject> path) {
+ org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path);
+ CompositeNode result = biDataService.readConfigurationData(biPath);
+ return mappingService.dataObjectFromDataDom(path, result);
+ }
+
+ @Override
+ public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction<InstanceIdentifier<? extends DataObject>, DataObject> requestCommit(
+ DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification) {
+
+ DataModificationTransaction translated = translateTransaction(modification);
+ return new WrappedTransaction(translated, modification);
+ }
+
+ private DataModificationTransaction translateTransaction(
+ DataModification<InstanceIdentifier<? extends DataObject>, DataObject> source) {
+ DataModificationTransaction target = biDataService.beginTransaction();
+ for (Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry : source.getUpdatedConfigurationData()
+ .entrySet()) {
+ Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> biEntry = mappingService
+ .toDataDom(entry);
+ target.putConfigurationData(biEntry.getKey(), biEntry.getValue());
+ }
+ for (Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry : source.getUpdatedOperationalData()
+ .entrySet()) {
+ Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> biEntry = mappingService
+ .toDataDom(entry);
+ target.putOperationalData(biEntry.getKey(), biEntry.getValue());
+ }
+ for(InstanceIdentifier<? extends DataObject> entry : source.getRemovedConfigurationData()) {
+ org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry);
+ target.removeConfigurationData(biEntry);
+ }
+ for(InstanceIdentifier<? extends DataObject> entry : source.getRemovedOperationalData()) {
+ org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry);
+ target.removeOperationalData(biEntry);
+ }
+ return target;
+ }
+
+ private class WrappedTransaction implements
+ DataCommitTransaction<InstanceIdentifier<? extends DataObject>, DataObject> {
+
+ private DataModificationTransaction backing;
+ private DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification;
+
+ public WrappedTransaction(DataModificationTransaction backing,
+ DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification) {
+ this.backing = backing;
+ this.modification = modification;
+ }
+
+ @Override
+ public DataModification<InstanceIdentifier<? extends DataObject>, DataObject> getModification() {
+ return modification;
+ }
+
+ @Override
+ public RpcResult<Void> finish() throws IllegalStateException {
+ Future<RpcResult<TransactionStatus>> result = backing.commit();
+ try {
+ RpcResult<TransactionStatus> biresult = result.get();
+ } catch (InterruptedException e) {
+ throw new IllegalStateException("", e);
+ } catch (ExecutionException e) {
+ throw new IllegalStateException("", e);
+ }
+ return Rpcs.<Void> getRpcResult(true, null, Collections.<RpcError> emptySet());
+ }
+
+ @Override
+ public RpcResult<Void> rollback() throws IllegalStateException {
+ // backing.cancel();
+ return Rpcs.<Void> getRpcResult(true, null, Collections.<RpcError> emptySet());
+ }
+
+ }
+
+ public DataBrokerService getBiDataService() {
+ return biDataService;
+ }
+
+ public void setBiDataService(DataBrokerService biDataService) {
+ this.biDataService = biDataService;
+ }
+
+ public DataProviderService getBaDataService() {
+ return baDataService;
+ }
+
+ public void setBaDataService(DataProviderService baDataService) {
+ this.baDataService = baDataService;
+ }
+
+ public void start() {
+ baDataService.registerDataReader(ROOT, this);
+ baDataService.registerCommitHandler(ROOT, this);
+ }
+
+ public void setMappingService(BindingIndependentMappingService mappingService) {
+ this.mappingService = mappingService;
+ }
+
+}
--- /dev/null
+package org.opendaylight.controller.sal.binding.impl.connect.dom;
+
+import java.util.Map.Entry;
+
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+
+public interface BindingIndependentMappingService {
+
+ CompositeNode toDataDom(DataObject data);
+
+ Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> toDataDom(
+ Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry);
+
+ org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toDataDom(InstanceIdentifier<? extends DataObject> path);
+
+ DataObject dataObjectFromDataDom(InstanceIdentifier<? extends DataObject> path, CompositeNode result);
+}
--- /dev/null
+package org.opendaylight.controller.sal.binding.impl.connect.dom;
+
+public class BindingIndependentRpcConnector {
+
+}
--- /dev/null
+package org.opendaylight.controller.sal.binding.impl.connect.dom
+
+import org.opendaylight.yangtools.yang.common.QName
+import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleContext
+import java.util.List
+import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder
+import org.opendaylight.yangtools.sal.binding.model.api.Type
+import org.opendaylight.yangtools.yang.model.api.SchemaNode
+import java.util.Map
+import org.opendaylight.yangtools.yang.model.api.SchemaPath
+import org.opendaylight.yangtools.yang.model.api.SchemaContext
+import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil
+import org.opendaylight.yangtools.binding.generator.util.Types
+import java.util.HashMap
+import org.opendaylight.yangtools.yang.data.api.CompositeNode
+import org.opendaylight.yangtools.yang.binding.DataContainer
+import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
+import org.opendaylight.yangtools.sal.binding.model.api.GeneratedProperty
+import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType
+import java.util.Collections
+import java.util.ArrayList
+import org.opendaylight.yangtools.yang.data.api.Node
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode
+import org.opendaylight.yangtools.sal.binding.generator.impl.BindingGeneratorImpl
+import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
+import org.opendaylight.yangtools.yang.model.api.NotificationDefinition
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition
+import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition
+import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
+import org.opendaylight.yangtools.yang.binding.DataObject
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates
+import org.opendaylight.yangtools.yang.model.util.ExtendedType
+import org.opendaylight.yangtools.sal.binding.model.api.GeneratedTransferObject
+import com.google.common.collect.FluentIterable
+import org.opendaylight.yangtools.yang.data.api.SimpleNode
+import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil
+import org.opendaylight.controller.sal.binding.impl.util.ClassLoaderUtils
+import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition
+
+class BindingMapping {
+
+ val Map<Type, GeneratedTypeBuilder> typeToDefinition = new HashMap();
+ val Map<Type, SchemaNode> typeToSchemaNode = new HashMap();
+
+ def QName getSchemaNode(Class<?> cls) {
+ val ref = Types.typeForClass(cls);
+ return typeToSchemaNode.get(ref)?.QName;
+ }
+
+ def void updateBinding(SchemaContext schemaContext, ModuleContext moduleBindingContext) {
+ updateBindingFor(moduleBindingContext.childNodes, schemaContext);
+
+ }
+
+ def org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toDataDom(
+ InstanceIdentifier<? extends DataObject> obj) {
+ val pathArguments = obj.path;
+ var Class<? extends DataObject> parent;
+ val dataDomArgs = new ArrayList<PathArgument>();
+ for (pathArgument : pathArguments) {
+ dataDomArgs.add(pathArgument.toDataDomPathArgument(parent));
+ parent = pathArgument.type;
+ }
+
+ return new org.opendaylight.yangtools.yang.data.api.InstanceIdentifier(dataDomArgs);
+ }
+
+
+
+ def DataObject dataObjectFromDataDom(InstanceIdentifier<? extends DataObject> identifier, CompositeNode node) {
+ if (node == null) {
+ return null;
+ }
+ val targetClass = identifier.targetType;
+ val classLoader = targetClass.classLoader;
+ val ref = Types.typeForClass(targetClass);
+ val targetType = typeToDefinition.get(ref);
+ val targetSchema = typeToSchemaNode.get(ref);
+ return node.toDataObject(classLoader, targetType.toInstance, targetSchema);
+
+ }
+
+ def dispatch PathArgument toDataDomPathArgument(IdentifiableItem argument, Class<? extends DataObject> parent) {
+ val Class rawType = argument.type;
+ val ref = Types.typeForClass(rawType);
+ val schemaType = typeToSchemaNode.get(ref);
+ val qname = schemaType.QName
+
+ val Object key = argument.key;
+ val predicates = key.toPredicates(schemaType as ListSchemaNode);
+
+ return new NodeIdentifierWithPredicates(qname, predicates);
+ }
+
+ def dispatch PathArgument toDataDomPathArgument(Item<?> argument, Class<? extends DataObject> parent) {
+ val ref = Types.typeForClass(argument.type);
+ val qname = typeToSchemaNode.get(ref).QName
+ return new NodeIdentifier(qname);
+ }
+
+ def Map<QName, Object> toPredicates(Object identifier, ListSchemaNode node) {
+ val keyDefinitions = node.keyDefinition;
+ val map = new HashMap<QName, Object>();
+ for (keydef : keyDefinitions) {
+ val keyNode = node.getDataChildByName(keydef) as LeafSchemaNode;
+ val value = identifier.getSimpleValue(keydef, keyNode.type);
+ map.put(keydef, value.value);
+ }
+ return map;
+ }
+
+ def void updateBindingFor(Map<SchemaPath, GeneratedTypeBuilder> map, SchemaContext module) {
+ for (entry : map.entrySet) {
+ val schemaNode = SchemaContextUtil.findDataSchemaNode(module, entry.key);
+ typeToDefinition.put(entry.value, entry.value);
+ typeToSchemaNode.put(entry.value, schemaNode)
+ }
+ }
+
+ def CompositeNode toCompositeNode(DataContainer data) {
+ val type = data.implementedInterface;
+ val typeRef = Types.typeForClass(type);
+ val schemaNode = typeToSchemaNode.get(typeRef);
+ val generatedType = typeToDefinition.get(typeRef);
+
+ return data.toDataDom(schemaNode, generatedType);
+ }
+
+ private def dispatch CompositeNode toDataDom(DataContainer data, ContainerSchemaNode node,
+ GeneratedTypeBuilder builder) {
+ val subnodes = data.toDataDomComponents(node);
+ return new CompositeNodeTOImpl(node.QName, null, subnodes);
+ }
+
+ private def dispatch CompositeNode toDataDom(DataContainer data, NotificationDefinition node,
+ GeneratedTypeBuilder builder) {
+ val subnodes = data.toDataDomComponents(node);
+ return new CompositeNodeTOImpl(node.QName, null, subnodes);
+ }
+
+ private def dispatch CompositeNode toDataDom(DataContainer data, ListSchemaNode node,
+ GeneratedTypeBuilder builder) {
+ val subnodes = data.toDataDomComponents(node);
+ return new CompositeNodeTOImpl(node.QName, null, subnodes);
+ }
+
+ private def List<Node<?>> toDataDomComponents(DataContainer data, DataNodeContainer node) {
+ val subnodes = new ArrayList<Node<?>>();
+ for (childNode : node.childNodes) {
+ val value = childNode.dataDomFromParent(data);
+ if (value !== null) {
+ subnodes.addAll(value);
+ }
+ }
+ return subnodes;
+ }
+
+ private def List<Node<?>> dataDomFromParent(DataSchemaNode node, DataContainer container) {
+ if (node.augmenting) {
+ return Collections.emptyList();
+ }
+ return dataDomFromParentImpl(node, container);
+ }
+
+ private def dispatch List<Node<?>> dataDomFromParentImpl(LeafSchemaNode node, DataContainer container) {
+ val value = container.getSimpleValue(node.QName, node.type);
+ if (value !== null) {
+ return Collections.<Node<?>>singletonList(value);
+ }
+ return Collections.emptyList();
+ }
+
+ private def dispatch List<Node<?>> dataDomFromParentImpl(LeafListSchemaNode node, DataContainer container) {
+ val values = container.getSimpleValues(node);
+ if (values !== null) {
+ //val it = new ArrayList<Node<?>>();
+ //for (value : values) {
+ //}
+
+ }
+ return Collections.emptyList();
+ }
+
+ def getSimpleValues(DataContainer container, LeafListSchemaNode node) {
+ return Collections.emptyList();
+ }
+
+ private def dispatch List<Node<?>> dataDomFromParentImpl(ListSchemaNode node, DataContainer container) {
+ val qname = node.QName;
+ val values = container.<List>getValue(qname, List) as List<? extends DataContainer>;
+ if (values === null) {
+ return Collections.emptyList;
+ }
+ val it = new ArrayList<Node<?>>();
+ for (value : values) {
+ add(value.toCompositeNode());
+ }
+
+ return it;
+ }
+
+ private def dispatch List<Node<?>> dataDomFromParentImpl(ChoiceNode node, DataContainer container) {
+ }
+
+ private def dispatch List<Node<?>> serializeValueImpl(List<?> list, GeneratedTypeBuilder builder,
+ ListSchemaNode node) {
+ val it = new ArrayList<Node<?>>();
+ for (value : list) {
+
+ val serVal = value.serializeValueImpl(builder, node);
+ if (serVal !== null) {
+ addAll(serVal);
+ }
+ }
+ return it;
+ }
+
+ private def dispatch Node<?> getSimpleValue(Object container, QName name, ExtendedType type) {
+ getSimpleValue(container, name, type.baseType);
+ }
+
+ private def dispatch Node<?> getSimpleValue(Object container, QName name, StringTypeDefinition type) {
+ val value = container.getValue(name, String);
+ if(value === null) return null;
+ return new SimpleNodeTOImpl(name, null, value);
+ }
+
+ private def dispatch Node<?> getSimpleValue(Object container, QName name, TypeDefinition<?> type) {
+ val value = container.getValue(name, Object);
+ if(value === null) return null;
+ return new SimpleNodeTOImpl(name, null, value);
+ }
+
+ private def dispatch Node<?> getSimpleValue(Object container, QName name, BooleanTypeDefinition type) {
+ val value = container.getValue(name, Boolean);
+ if(value === null) return null;
+ return new SimpleNodeTOImpl(name, null, value);
+ }
+
+ private def dispatch Node<?> getSimpleValue(Object container, QName name, BinaryTypeDefinition type) {
+ val Object value = container.getValue(name, Object); //Constants.BYTES_CLASS);
+ if(value === null) return null;
+ return new SimpleNodeTOImpl(name, null, value);
+ }
+
+ private def <T> T getValue(Object object, QName node, Class<T> type) {
+ val methodName = BindingGeneratorImpl.getterMethodName(node.localName, Types.typeForClass(type));
+ var clz = object.class;
+ if (object instanceof DataContainer) {
+ clz = (object as DataContainer).implementedInterface;
+ }
+ val method = clz.getMethod(methodName);
+ if (method === null) {
+ return null;
+ }
+ val value = method.invoke(object);
+ if (value === null) {
+ return null;
+ }
+ if (type.isAssignableFrom(value.class)) {
+ return value as T;
+ }
+ return value.getEncapsulatedValue(type);
+ }
+
+ private def <T> T getEncapsulatedValue(Object value, Class<T> type) {
+ val method = value.class.getMethod("getValue");
+ if (method !== null && type.isAssignableFrom(method.returnType)) {
+ return method.invoke(value) as T;
+ }
+ return null;
+ }
+
+ private def dispatch List<Node<?>> serializeValueImpl(DataContainer data, GeneratedTypeBuilder builder,
+ SchemaNode node) {
+ return Collections.<Node<?>>singletonList(data.toDataDom(node, builder));
+ }
+
+ private def dispatch List<Node<?>> serializeValueImpl(Object object, GeneratedTypeBuilder builder,
+ SchemaNode node) {
+ }
+
+ def DataObject toDataObject(CompositeNode node, ClassLoader loader, GeneratedType type, SchemaNode schema) {
+
+ // Nasty reflection hack (for now)
+ val builderClass = loader.loadClass(type.builderFQN);
+ val builder = builderClass.newInstance;
+ val buildMethod = builderClass.getMethod("build");
+
+ node.fillDataObject(builder, loader, type, schema);
+
+ return buildMethod.invoke(builder) as DataObject;
+ }
+
+ def dispatch void fillDataObject(CompositeNode node, Object builder, ClassLoader loader, GeneratedType type,
+ ListSchemaNode schema) {
+
+ if (schema.keyDefinition !== null && !schema.keyDefinition.empty) {
+
+ val value = node.keyToBindingKey(loader, type, schema);
+ builder.setProperty("key", value);
+ }
+ }
+
+ def dispatch void fillDataObject(CompositeNode node, Object builder, ClassLoader loader, GeneratedType type,
+ ContainerSchemaNode schema) {
+ }
+
+
+ def Object keyToBindingKey(CompositeNode node, ClassLoader loader, GeneratedType type, ListSchemaNode schema) {
+ val keyClass = loader.loadClass(type.keyFQN);
+ val constructor = keyClass.constructors.get(0);
+ val keyType = type.keyTypeProperties;
+ val args = new ArrayList();
+ for (key : schema.keyDefinition) {
+ val keyProperty = keyType.get(BindingGeneratorUtil.parseToClassName(key.localName));
+ val domKeyValue = node.getFirstSimpleByName(key);
+ val keyValue = domKeyValue.deserializeSimpleValue(loader, keyProperty.returnType,
+ schema.getDataChildByName(key));
+ args.add(keyValue);
+ }
+ return ClassLoaderUtils.construct(constructor, args);
+ }
+
+ def dispatch Object deserializeSimpleValue(SimpleNode<? extends Object> node, ClassLoader loader, Type type,
+ LeafSchemaNode node2) {
+ deserializeSimpleValueImpl(node, loader, type, node2.type);
+ }
+
+ def dispatch Object deserializeSimpleValue(SimpleNode<? extends Object> node, ClassLoader loader, Type type,
+ LeafListSchemaNode node2) {
+ deserializeSimpleValueImpl(node, loader, type, node2.type);
+ }
+
+ def dispatch Object deserializeSimpleValueImpl(SimpleNode<? extends Object> node, ClassLoader loader, Type type,
+ ExtendedType definition) {
+ deserializeSimpleValueImpl(node, loader, type, definition.baseType);
+ }
+
+ def dispatch Object deserializeSimpleValueImpl(SimpleNode<? extends Object> node, ClassLoader loader, Type type,
+ StringTypeDefinition definition) {
+ if (type instanceof GeneratedTransferObject) {
+ val cls = loader.getClassForType(type);
+ val const = cls.getConstructor(String);
+ val str = String.valueOf(node.value);
+ return const.newInstance(str);
+ }
+ return node.value;
+ }
+
+ def Class<?> getClassForType(ClassLoader loader, Type type) {
+ loader.loadClass(type.fullyQualifiedName);
+ }
+
+ def dispatch Object deserializeSimpleValueImpl(SimpleNode<? extends Object> node, ClassLoader loader, Type type,
+ TypeDefinition definition) {
+ throw new UnsupportedOperationException("TODO: auto-generated method stub")
+ }
+
+ def Map<String, GeneratedProperty> getKeyTypeProperties(GeneratedType type) {
+ val method = FluentIterable.from(type.methodDefinitions).findFirst[name == "getKey"]
+ val key = method.returnType as GeneratedTransferObject;
+ val ret = new HashMap<String, GeneratedProperty>();
+ for (prop : key.properties) {
+ ret.put(prop.name, prop);
+ }
+ return ret;
+ }
+
+ def void setProperty(Object object, String property, Object value) {
+ val cls = object.class;
+ val valMethod = cls.getMethod("set" + property.toFirstUpper, value.class);
+ if (valMethod != null)
+ valMethod.invoke(object, value);
+ }
+
+ def String getBuilderFQN(Type type) '''«type.fullyQualifiedName»Builder'''
+
+ def String getKeyFQN(Type type) '''«type.fullyQualifiedName»Key'''
+
+}
+
+@Data
+class PropertyCapture {
+
+ @Property
+ val Type returnType;
+ @Property
+ val String name;
+
+}
--- /dev/null
+package org.opendaylight.controller.sal.binding.impl.connect.dom;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.controller.sal.core.api.Broker;
+import org.opendaylight.controller.sal.core.api.Provider;
+import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
+import org.opendaylight.controller.sal.core.api.data.DataBrokerService;
+import org.opendaylight.controller.sal.core.api.model.SchemaService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+
+public class ConnectorActivator implements Provider, ServiceTrackerCustomizer<Broker, Broker> {
+
+ BindingIndependentDataServiceConnector dataConnector;
+ BindingIndependentMappingService mappingService;
+
+ private final DataProviderService baDataService;
+ private BundleContext context;
+
+ private ServiceTracker<Broker, Broker> brokerTracker;
+
+ public ConnectorActivator(DataProviderService dataService, BundleContext context) {
+ baDataService = dataService;
+ this.context = context;
+ brokerTracker = new ServiceTracker<>(context, Broker.class, this);
+ }
+
+ @Override
+ public Collection<ProviderFunctionality> getProviderFunctionality() {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public void onSessionInitiated(ProviderSession session) {
+
+ MappingServiceImpl mappingImpl = new MappingServiceImpl();
+ mappingImpl.setSchemaService(session.getService(SchemaService.class));
+ mappingImpl.start();
+
+ mappingService = mappingImpl;
+ dataConnector = new BindingIndependentDataServiceConnector();
+ dataConnector.setBaDataService(baDataService);
+ dataConnector.setBiDataService(session.getService(DataBrokerService.class));
+ dataConnector.setMappingService(mappingService);
+ dataConnector.start();
+ }
+
+ @Override
+ public Broker addingService(ServiceReference<Broker> reference) {
+ Broker br= context.getService(reference);
+ br.registerProvider(this, context);
+ return br;
+ }
+
+ @Override
+ public void modifiedService(ServiceReference<Broker> reference, Broker service) {
+ // NOOP
+ }
+
+ @Override
+ public void removedService(ServiceReference<Broker> reference, Broker service) {
+ // NOOP
+ }
+
+ public void start() {
+ brokerTracker.open();
+ }
+}
--- /dev/null
+package org.opendaylight.controller.sal.binding.impl.connect.dom;
+
+public class Constants {
+ public static final Class<byte[]> BYTES_CLASS = byte[].class;
+}
--- /dev/null
+package org.opendaylight.controller.sal.binding.impl.connect.dom
+
+import org.opendaylight.controller.sal.core.api.model.SchemaServiceListener
+import org.opendaylight.yangtools.yang.model.api.SchemaContext
+import org.opendaylight.yangtools.sal.binding.model.api.CodeGenerator
+import org.opendaylight.yangtools.sal.binding.generator.impl.BindingGeneratorImpl
+import org.opendaylight.yangtools.sal.binding.generator.api.BindingGenerator
+import org.opendaylight.yangtools.yang.data.api.CompositeNode
+import org.opendaylight.yangtools.yang.binding.DataObject
+import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
+import java.util.Collections
+import java.util.Map.Entry
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
+import java.util.AbstractMap.SimpleEntry
+import org.opendaylight.controller.sal.core.api.model.SchemaService
+
+class MappingServiceImpl implements SchemaServiceListener, BindingIndependentMappingService {
+
+ var extension BindingMapping mapping = new BindingMapping;
+
+ @Property
+ BindingGeneratorImpl binding;
+
+ @Property
+ SchemaService schemaService;
+
+ override onGlobalContextUpdated(SchemaContext arg0) {
+ recreateBindingContext(arg0);
+ }
+
+ def recreateBindingContext(SchemaContext schemaContext) {
+ val newBinding = new BindingGeneratorImpl();
+ newBinding.generateTypes(schemaContext);
+ val newMapping = new BindingMapping();
+ for (entry : newBinding.moduleContexts.entrySet) {
+ val module = entry.key;
+ val context = entry.value;
+
+ newMapping.updateBinding(schemaContext, context);
+ }
+ mapping = newMapping
+ }
+
+ override CompositeNode toDataDom(DataObject data) {
+ mapping.toCompositeNode(data);
+ }
+
+ override Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> toDataDom(
+ Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry) {
+ val key = mapping.toDataDom(entry.key);
+ val data = mapping.toCompositeNode(entry.value);
+ return new SimpleEntry(key, data);
+ }
+
+ override org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toDataDom(
+ InstanceIdentifier<? extends DataObject> path) {
+ return mapping.toDataDom(path);
+ }
+
+ override dataObjectFromDataDom(InstanceIdentifier<? extends DataObject> path, CompositeNode result) {
+ return mapping.dataObjectFromDataDom(path,result);
+ }
+
+ public def void start() {
+ schemaService.registerSchemaServiceListener(this);
+ recreateBindingContext(schemaService.globalContext);
+ }
+}
-package org.opendaylight.controller.sal.binding.impl.osgi;
+package org.opendaylight.controller.sal.binding.impl.util;
import java.util.concurrent.Callable;
+
import static com.google.common.base.Preconditions.*;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+
+import org.opendaylight.yangtools.yang.binding.Identifier;
+
public class ClassLoaderUtils {
public static <V> V withClassLoader(ClassLoader cls,Callable<V> function) throws Exception {
throw new Exception(e);
}
}
+
+ public static Object construct(Constructor<? extends Object> constructor, ArrayList<Object> objects) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+ Object[] initargs = objects.toArray(new Object[]{});
+ return constructor.newInstance(initargs);
+ }
}
\ No newline at end of file
--- /dev/null
+package org.opendaylight.controller.sal.binding.test.connect.dom;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+import org.junit.Before;
+import org.junit.Test;
+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.DataProviderService;
+import org.opendaylight.controller.sal.binding.impl.DataBrokerImpl;
+import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentDataServiceConnector;
+import org.opendaylight.controller.sal.binding.impl.connect.dom.MappingServiceImpl;
+import org.opendaylight.controller.sal.core.api.data.DataBrokerService;
+import org.opendaylight.controller.sal.dom.broker.impl.HashMapDataStore;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.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.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+
+public class BrokerIntegrationTest {
+
+ DataBrokerService biDataService;
+ DataProviderService baDataService;
+ private MappingServiceImpl mappingServiceImpl;
+ private MappingServiceImpl mappingService;
+ private DataBrokerImpl baDataImpl;
+ private org.opendaylight.controller.sal.dom.broker.DataBrokerImpl biDataImpl;
+ private ListeningExecutorService executor;
+ private BindingIndependentDataServiceConnector connectorServiceImpl;
+ private HashMapDataStore dataStore;
+
+
+ @Before
+ public void setUp() {
+ executor = MoreExecutors.sameThreadExecutor();
+ baDataImpl = new DataBrokerImpl();
+ baDataService = baDataImpl;
+ baDataImpl.setExecutor(executor);
+
+ biDataImpl = new org.opendaylight.controller.sal.dom.broker.DataBrokerImpl();
+ biDataService = biDataImpl;
+ biDataImpl.setExecutor(executor);
+
+ dataStore = new HashMapDataStore();
+ org.opendaylight.yangtools.yang.data.api.InstanceIdentifier treeRoot = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder().toInstance();
+ biDataImpl.registerConfigurationReader(treeRoot, dataStore);
+ biDataImpl.registerOperationalReader(treeRoot, dataStore);
+ biDataImpl.registerCommitHandler(treeRoot, dataStore);
+
+ mappingServiceImpl = new MappingServiceImpl();
+ mappingService = mappingServiceImpl;
+
+
+ connectorServiceImpl = new BindingIndependentDataServiceConnector();
+ connectorServiceImpl.setBaDataService(baDataService);
+ connectorServiceImpl.setBiDataService(biDataService);
+ connectorServiceImpl.setMappingService(mappingServiceImpl);
+ connectorServiceImpl.start();
+
+ String[] yangFiles = new String[] { "yang-ext.yang", "ietf-inet-types.yang", "ietf-yang-types.yang",
+ "node-inventory.yang" };
+
+ mappingService.onGlobalContextUpdated(MappingServiceTest.getContext(yangFiles));
+ }
+
+ @Test
+ public void simpleModifyOperation() throws Exception {
+
+ DataModificationTransaction transaction = baDataService.beginTransaction();
+ assertNotNull(transaction);
+
+ NodeRef node1 = createNodeRef("0");
+ DataObject node = baDataService.readConfigurationData(node1.getValue());
+ assertNull(node);
+ Node nodeData1 = createNode("0");
+
+ transaction.putConfigurationData(node1.getValue(), nodeData1);
+ Future<RpcResult<TransactionStatus>> commitResult = transaction.commit();
+ assertNotNull(commitResult);
+
+ RpcResult<TransactionStatus> result = commitResult.get();
+
+ assertNotNull(result);
+ assertNotNull(result.getResult());
+ assertEquals(TransactionStatus.COMMITED, result.getResult());
+
+ Node readedData = (Node) baDataService.readConfigurationData(node1.getValue());
+ assertNotNull(readedData);
+ assertEquals(nodeData1.getKey(), readedData.getKey());
+
+
+ DataModificationTransaction transaction2 = baDataService.beginTransaction();
+ assertNotNull(transaction);
+
+ transaction2.removeConfigurationData(node1.getValue());
+
+ Future<RpcResult<TransactionStatus>> commitResult2 = transaction2.commit();
+ assertNotNull(commitResult2);
+
+ RpcResult<TransactionStatus> result2 = commitResult2.get();
+
+ assertNotNull(result2);
+ assertNotNull(result2.getResult());
+ assertEquals(TransactionStatus.COMMITED, result2.getResult());
+
+ DataObject readedData2 = baDataService.readConfigurationData(node1.getValue());
+ assertNull(readedData2);
+ }
+
+ private static NodeRef createNodeRef(String string) {
+ NodeKey key = new NodeKey(new NodeId(string));
+ InstanceIdentifier<Node> path = InstanceIdentifier.builder().node(Nodes.class).node(Node.class, key)
+ .toInstance();
+ return new NodeRef(path);
+ }
+
+ private static Node createNode(String string) {
+ NodeBuilder ret = new NodeBuilder();
+ ret.setId(new NodeId(string));
+ ret.setKey(new NodeKey(ret.getId()));
+ return ret.build();
+ }
+}
--- /dev/null
+package org.opendaylight.controller.sal.binding.test.connect.dom;
+
+import static org.junit.Assert.*;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+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.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentMappingService;
+import org.opendaylight.controller.sal.binding.impl.connect.dom.MappingServiceImpl;
+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.NodesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
+import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleContext;
+import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+
+public class MappingServiceTest {
+
+ private static final QName NODES = QName.create("urn:opendaylight:inventory", "2013-08-19", "nodes");
+ private static final QName NODE = QName.create(NODES,"node");
+ private static final QName ID = QName.create(NODES,"id");
+
+ BindingIndependentMappingService service;
+ private MappingServiceImpl impl;
+
+ @Before
+ public void setUp() {
+ impl = new MappingServiceImpl();
+ service = impl;
+ }
+
+ @Test
+ public void baDataToBiData() throws Exception {
+
+ String[] yangFiles = new String[] { "yang-ext.yang", "ietf-inet-types.yang", "ietf-yang-types.yang",
+ "node-inventory.yang" };
+
+ SchemaContext ctx = getContext(yangFiles);
+
+ impl.onGlobalContextUpdated(ctx);
+
+ NodesBuilder nodes = new NodesBuilder();
+
+ List<Node> nodeList = new ArrayList<>();
+ nodeList.add(createChildNode("foo"));
+ nodeList.add(createChildNode("bar"));
+
+ nodes.setNode(nodeList);
+ Nodes nodesTO = nodes.build();
+ CompositeNode xmlNodes = service.toDataDom(nodesTO);
+ assertNotNull(xmlNodes);
+ List<CompositeNode> invNodes = xmlNodes.getCompositesByName(NODE);
+ assertNotNull(invNodes);
+ assertEquals(2, invNodes.size());
+ }
+
+ @Test
+ public void instanceIdentifierTest() throws Exception {
+
+ String[] yangFiles = new String[] { "yang-ext.yang", "ietf-inet-types.yang", "ietf-yang-types.yang",
+ "node-inventory.yang" };
+ SchemaContext ctx = getContext(yangFiles);
+ impl.onGlobalContextUpdated(ctx);
+
+ NodeKey nodeKey = new NodeKey(new NodeId("foo"));
+ InstanceIdentifier<Node> path = InstanceIdentifier.builder().node(Nodes.class).child(Node.class, nodeKey).toInstance();
+ org.opendaylight.yangtools.yang.data.api.InstanceIdentifier result = service.toDataDom(path);
+ assertNotNull(result);
+ assertEquals(2, result.getPath().size());
+ }
+
+ public static SchemaContext getContext(String[] yangFiles) {
+
+ ClassLoader loader = MappingServiceTest.class.getClassLoader();
+
+ List<InputStream> streams = new ArrayList<>();
+ for (String string : yangFiles) {
+ InputStream stream = loader.getResourceAsStream("META-INF/yang/" + string);
+ streams.add(stream);
+
+ }
+ YangParserImpl parser = new YangParserImpl();
+
+ Set<Module> modules = parser.parseYangModelsFromStreams(streams);
+ return parser.resolveSchemaContext(modules);
+ }
+
+ private Node createChildNode(String id) {
+ NodeBuilder node = new NodeBuilder();
+ NodeId nodeId = new NodeId(id);
+
+ node.setId(nodeId);
+ node.setKey(new NodeKey(nodeId));
+
+ FlowCapableNodeBuilder aug = new FlowCapableNodeBuilder();
+ aug.setManufacturer(id);
+ node.addAugmentation(FlowCapableNode.class, aug.build());
+
+ return node.build();
+ }
+
+}
<version>1.0-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools.thirdparty</groupId>
+ <artifactId>antlr4-runtime-osgi-nohead</artifactId>
+ <version>4.0</version>
+ </dependency>
</dependencies>
</project>
mavenBundle(CONTROLLER, "sal-common-api").versionAsInProject(), //
mavenBundle(CONTROLLER, "sal-common-impl").versionAsInProject(), //
+ mavenBundle("org.apache.commons", "commons-lang3").versionAsInProject(),
mavenBundle("com.google.guava", "guava").versionAsInProject(), //
mavenBundle(YANGTOOLS + ".thirdparty", "xtend-lib-osgi").versionAsInProject() //
);
mavenBundle(CONTROLLER, "sal-binding-config").versionAsInProject(),
mavenBundle(CONTROLLER, "sal-binding-broker-impl").versionAsInProject(), //
mavenBundle("org.javassist", "javassist").versionAsInProject(), //
- mavenBundle(CONTROLLER, "sal-common-util").versionAsInProject() //
- );
+ mavenBundle(CONTROLLER, "sal-common-util").versionAsInProject(), //
+
+ mavenBundle(YANGTOOLS, "yang-data-api").versionAsInProject(), //
+ mavenBundle(YANGTOOLS, "yang-data-impl").versionAsInProject(), //
+ mavenBundle(YANGTOOLS, "yang-model-api").versionAsInProject(), //
+ mavenBundle(YANGTOOLS, "yang-model-util").versionAsInProject(), //
+ mavenBundle(YANGTOOLS, "yang-parser-api").versionAsInProject(),
+ mavenBundle(YANGTOOLS, "yang-parser-impl").versionAsInProject(),
+
+
+ mavenBundle(YANGTOOLS, "binding-generator-spi").versionAsInProject(), //
+ mavenBundle(YANGTOOLS, "binding-model-api").versionAsInProject(), //
+ mavenBundle(YANGTOOLS, "binding-generator-util").versionAsInProject(),
+ mavenBundle(YANGTOOLS, "yang-parser-impl").versionAsInProject(),
+ mavenBundle(YANGTOOLS, "binding-type-provider").versionAsInProject(),
+ mavenBundle(YANGTOOLS, "binding-generator-api").versionAsInProject(),
+ mavenBundle(YANGTOOLS, "binding-generator-spi").versionAsInProject(),
+ mavenBundle(YANGTOOLS, "binding-generator-impl").versionAsInProject(),
+
+
+ mavenBundle(CONTROLLER, "sal-core-api").versionAsInProject().update(), //
+ mavenBundle(CONTROLLER, "sal-broker-impl").versionAsInProject(), //
+ mavenBundle(CONTROLLER, "sal-core-spi").versionAsInProject().update(), //
+
+ mavenBundle(YANGTOOLS + ".thirdparty", "antlr4-runtime-osgi-nohead").versionAsInProject() //
+ );
}
import org.ops4j.pax.exam.Option;
import org.ops4j.pax.exam.junit.PaxExam;
import org.ops4j.pax.exam.options.DefaultCompositeOption;
+import org.ops4j.pax.exam.util.PathUtils;
import org.osgi.framework.BundleContext;
@RunWith(PaxExam.class)
public Option[] config() {
return options(systemProperty("osgi.console").value("2401"), mavenBundle("org.slf4j", "slf4j-api")
.versionAsInProject(), //
+ systemProperty("logback.configurationFile").value(
+ "file:" + PathUtils.getBaseDir()
+ + "/src/test/resources/logback.xml"),
mavenBundle("org.slf4j", "log4j-over-slf4j").versionAsInProject(), //
mavenBundle("ch.qos.logback", "logback-core").versionAsInProject(), //
mavenBundle("ch.qos.logback", "logback-classic").versionAsInProject(), //
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.core.api.Broker;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.common.RpcResult;
+import com.google.inject.Inject;
+
public class DataServiceTest extends AbstractTest {
protected DataBrokerService consumerDataService;
+
+
+ @Inject
+ Broker broker2;
@Before
public void setUp() throws Exception {
assertNotNull(result.getResult());
assertEquals(TransactionStatus.COMMITED, result.getResult());
- DataObject readedData = consumerDataService.readConfigurationData(node1.getValue());
+ Node readedData = (Node) consumerDataService.readConfigurationData(node1.getValue());
assertNotNull(readedData);
- assertEquals(nodeData1, readedData);
+ assertEquals(nodeData1.getKey(), readedData.getKey());
DataModificationTransaction transaction2 = consumerDataService.beginTransaction();
private static Node createNode(String string) {
NodeBuilder ret = new NodeBuilder();
- ret.setId(new NodeId(string));
+ NodeId id = new NodeId(string);
+ ret.setKey(new NodeKey(id));
+ ret.setId(id);
return ret.build();
}
}
<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>sal-parent</artifactId>
- <version>1.0-SNAPSHOT</version>
- </parent>
- <artifactId>sal-common-impl</artifactId>
- <packaging>bundle</packaging>
- <scm>
- <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
- <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
- <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
- </scm>
+ 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>sal-parent</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>sal-common-impl</artifactId>
+ <packaging>bundle</packaging>
+ <scm>
+ <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+ <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+ <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
+ </scm>
- <dependencies>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-common-api</artifactId>
- <version>1.0-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>com.google.guava</groupId>
- <artifactId>guava</artifactId>
- </dependency>
- <dependency>
- <groupId>org.eclipse.xtend</groupId>
- <artifactId>org.eclipse.xtend.lib</artifactId>
- </dependency>
- </dependencies>
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-common-api</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-common-util</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.xtend</groupId>
+ <artifactId>org.eclipse.xtend.lib</artifactId>
+ </dependency>
+ </dependencies>
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.felix</groupId>
- <artifactId>maven-bundle-plugin</artifactId>
- <configuration>
- <instructions>
- <Export-Package>
- org.opendaylight.controller.md.sal.common.impl,
- org.opendaylight.controller.md.sal.common.impl.*
- </Export-Package>
- </instructions>
- </configuration>
- </plugin>
- </plugins>
- </build>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Export-Package>
+ org.opendaylight.controller.md.sal.common.impl,
+ org.opendaylight.controller.md.sal.common.impl.*
+ </Export-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.eclipse.xtend</groupId>
+ <artifactId>xtend-maven-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
</project>
package org.opendaylight.controller.md.sal.common.impl;
+import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.NEW;
+
import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.opendaylight.controller.md.sal.common.api.data.DataModification;
import org.opendaylight.controller.md.sal.common.api.data.DataReader;
-import org.opendaylight.yangtools.concepts.Path;
-
-import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.NEW;
public abstract class AbstractDataModification<P /* extends Path<P> */, D> implements DataModification<P, D> {
@Override
public final void putRuntimeData(P path, D data) {
- putRuntimeData(path, data);
+ putOperationalData(path, data);
}
@Override
@Override
public D readOperationalData(P path) {
FluentIterable<D> dataBits = FluentIterable //
- .from(getReaders(configReaders, path)).transform(operationalRead(path));
+ .from(getReaders(operationalReaders, path)).transform(operationalRead(path));
return merge(path,dataBits);
}
--- /dev/null
+package org.opendaylight.controller.md.sal.common.impl.service
+
+import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus
+import org.opendaylight.controller.md.sal.common.api.data.DataReader
+import org.opendaylight.yangtools.concepts.AbstractObjectRegistration
+import org.opendaylight.yangtools.concepts.ListenerRegistration
+import com.google.common.collect.Multimap
+import static com.google.common.base.Preconditions.*;
+import java.util.List
+import com.google.common.collect.HashMultimap
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Callable
+import org.opendaylight.yangtools.yang.common.RpcResult
+import java.util.Collections
+import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction
+import java.util.ArrayList
+import org.opendaylight.yangtools.concepts.CompositeObjectRegistration
+import java.util.Arrays
+import org.opendaylight.controller.md.sal.common.api.data.DataProvisionService
+import org.opendaylight.controller.md.sal.common.api.data.DataModificationTransactionFactory
+import org.opendaylight.controller.md.sal.common.api.data.DataChangePublisher
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeListener
+import org.opendaylight.controller.sal.common.util.Rpcs
+import org.opendaylight.controller.md.sal.common.impl.AbstractDataModification
+import java.util.concurrent.Future
+import org.opendaylight.controller.md.sal.common.impl.routing.AbstractDataReadRouter
+import org.opendaylight.yangtools.concepts.Path
+import org.slf4j.LoggerFactory
+
+abstract class AbstractDataBroker<P extends Path<P>,D,DCL extends DataChangeListener<P,D>> implements
+DataModificationTransactionFactory<P, D>, //
+DataReader<P, D>, //
+DataChangePublisher<P, D, DCL>, //
+DataProvisionService<P,D> {
+
+ @Property
+ var ExecutorService executor;
+
+ @Property
+ var AbstractDataReadRouter<P,D> dataReadRouter;
+
+ Multimap<P, DataChangeListenerRegistration<P,D,DCL>> listeners = HashMultimap.create();
+ Multimap<P, DataCommitHandlerRegistration<P,D>> commitHandlers = HashMultimap.create();
+
+
+ public new() {
+
+ }
+
+ override final readConfigurationData(P path) {
+ return dataReadRouter.readConfigurationData(path);
+ }
+
+ override final readOperationalData(P path) {
+ return dataReadRouter.readOperationalData(path);
+ }
+
+ override final registerCommitHandler(P path,
+ DataCommitHandler<P, D> commitHandler) {
+ val registration = new DataCommitHandlerRegistration(path,commitHandler,this);
+ commitHandlers.put(path,registration)
+ return registration;
+ }
+
+ override final def registerDataChangeListener(P path, DCL listener) {
+ val reg = new DataChangeListenerRegistration(path, listener, this);
+ listeners.put(path, reg);
+ return reg;
+ }
+
+ final def registerDataReader(P path,DataReader<P,D> reader) {
+
+ val confReg = dataReadRouter.registerConfigurationReader(path,reader);
+ val dataReg = dataReadRouter.registerOperationalReader(path,reader);
+
+ return new CompositeObjectRegistration(reader,Arrays.asList(confReg,dataReg));
+ }
+
+ protected final def removeListener(DataChangeListenerRegistration<P,D,DCL> registration) {
+ listeners.remove(registration.path, registration);
+ }
+
+ protected final def removeCommitHandler(DataCommitHandlerRegistration<P,D> registration) {
+ commitHandlers.remove(registration.path, registration);
+ }
+
+ protected final def getActiveCommitHandlers() {
+ return commitHandlers.entries.map[ value.instance].toSet
+ }
+
+ package final def Future<RpcResult<TransactionStatus>> commit(AbstractDataTransaction<P,D> transaction) {
+ checkNotNull(transaction);
+ transaction.changeStatus(TransactionStatus.SUBMITED);
+ val task = new TwoPhaseCommit(transaction, this);
+ return executor.submit(task);
+ }
+
+}
+
+package class DataChangeListenerRegistration<P extends Path<P>,D,DCL extends DataChangeListener<P,D>> extends AbstractObjectRegistration<DCL> implements ListenerRegistration<DCL> {
+
+ AbstractDataBroker<P,D,DCL> dataBroker;
+
+ @Property
+ val P path;
+
+ new(P path, DCL instance, AbstractDataBroker<P,D,DCL> broker) {
+ super(instance)
+ dataBroker = broker;
+ _path = path;
+ }
+
+ override protected removeRegistration() {
+ dataBroker.removeListener(this);
+ dataBroker = null;
+ }
+
+}
+
+package class DataCommitHandlerRegistration<P extends Path<P>,D>
+extends AbstractObjectRegistration<DataCommitHandler<P, D>> {
+
+ AbstractDataBroker<P,D,?> dataBroker;
+
+ @Property
+ val P path;
+
+ new(P path, DataCommitHandler<P, D> instance,
+ AbstractDataBroker<P,D,?> broker) {
+ super(instance)
+ dataBroker = broker;
+ _path = path;
+ }
+
+ override protected removeRegistration() {
+ dataBroker.removeCommitHandler(this);
+ dataBroker = null;
+ }
+
+}
+
+package class TwoPhaseCommit<P extends Path<P>,D> implements Callable<RpcResult<TransactionStatus>> {
+
+ private static val log = LoggerFactory.getLogger(TwoPhaseCommit);
+
+ val AbstractDataTransaction<P,D> transaction;
+ val AbstractDataBroker<P,D,?> dataBroker;
+
+ new(AbstractDataTransaction<P,D> transaction, AbstractDataBroker<P,D,?> broker) {
+ this.transaction = transaction;
+ this.dataBroker = broker;
+ }
+
+ override call() throws Exception {
+
+ val Iterable<DataCommitHandler<P, D>> commitHandlers = dataBroker.activeCommitHandlers;
+
+ // requesting commits
+ val List<DataCommitTransaction<P, D>> handlerTransactions = new ArrayList();
+ try {
+ for (handler : commitHandlers) {
+ handlerTransactions.add(handler.requestCommit(transaction));
+ }
+ } catch (Exception e) {
+ log.error("Request Commit failded",e);
+ return rollback(handlerTransactions,e);
+ }
+ val List<RpcResult<Void>> results = new ArrayList();
+ try {
+ for (subtransaction : handlerTransactions) {
+ results.add(subtransaction.finish());
+ }
+ } catch (Exception e) {
+ log.error("Finish Commit failed",e);
+ return rollback(handlerTransactions,e);
+ }
+
+ return Rpcs.getRpcResult(true, TransactionStatus.COMMITED, Collections.emptySet());
+ }
+
+ def rollback(List<DataCommitTransaction<P, D>> transactions,Exception e) {
+ for (transaction : transactions) {
+ transaction.rollback()
+ }
+ // FIXME return encountered error.
+ return Rpcs.getRpcResult(false, TransactionStatus.FAILED, Collections.emptySet());
+ }
+}
+
+public abstract class AbstractDataTransaction<P extends Path<P>, D> extends AbstractDataModification<P, D> {
+
+ @Property
+ private val Object identifier;
+
+
+ var TransactionStatus status;
+
+
+ var AbstractDataBroker<P, D, ?> broker;
+
+ protected new (AbstractDataBroker<P,D,?> dataBroker) {
+ super(dataBroker);
+ _identifier = new Object();
+ broker = dataBroker;
+ status = TransactionStatus.NEW;
+ //listeners = new ListenerRegistry<>();
+ }
+
+ override commit() {
+ return broker.commit(this);
+ }
+
+ override readConfigurationData(P path) {
+ return broker.readConfigurationData(path);
+ }
+
+ override readOperationalData(P path) {
+ return broker.readOperationalData(path);
+ }
+
+ override hashCode() {
+ return identifier.hashCode;
+ }
+
+ override equals(Object obj) {
+ if (this === obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ val other = (obj as AbstractDataTransaction<P,D>) ;
+ if (broker == null) {
+ if (other.broker != null)
+ return false;
+ } else if (!broker.equals(other.broker))
+ return false;
+ if (identifier == null) {
+ if (other.identifier != null)
+ return false;
+ } else if (!identifier.equals(other.identifier))
+ return false;
+ return true;
+ }
+
+ override TransactionStatus getStatus() {
+ return status;
+ }
+
+
+ protected abstract def void onStatusChange(TransactionStatus status);
+
+ public def changeStatus(TransactionStatus status) {
+ this.status = status;
+ onStatusChange(status);
+ }
+
+}
<artifactId>sal-common-util</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
+
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-impl</artifactId>
+ <version>0.5.9-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-impl</artifactId>
import org.opendaylight.controller.sal.core.api.model.SchemaService;
import org.opendaylight.controller.sal.core.api.mount.MountProvisionService;
import org.opendaylight.controller.sal.core.api.mount.MountService;
+import org.opendaylight.controller.sal.dom.broker.impl.HashMapDataStore;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
public class BrokerActivator implements BundleActivator {
+ private static final InstanceIdentifier ROOT = InstanceIdentifier.builder().toInstance();
BrokerImpl broker;
private ServiceRegistration<Broker> brokerReg;
private ServiceRegistration<SchemaService> schemaReg;
private MountPointManagerImpl mountService;
private ServiceRegistration<MountService> mountReg;
private ServiceRegistration<MountProvisionService> mountProviderReg;
+ private HashMapDataStore hashMapStore;
@Override
public void start(BundleContext context) throws Exception {
Hashtable<String, String> emptyProperties = new Hashtable<String, String>();
broker = new BrokerImpl();
broker.setBundleContext(context);
- brokerReg = context.registerService(Broker.class, broker, emptyProperties);
+
schemaService = new SchemaServiceImpl();
schemaService.setContext(context);
schemaReg = context.registerService(SchemaService.class, schemaService, new Hashtable<String, String>());
dataService = new DataBrokerImpl();
+ dataService.setExecutor(broker.getExecutor());
+
dataReg = context.registerService(DataBrokerService.class, dataService, emptyProperties);
dataProviderReg = context.registerService(DataProviderService.class, dataService, emptyProperties);
+ hashMapStore = new HashMapDataStore();
+
+ dataService.registerConfigurationReader(ROOT, hashMapStore);
+ dataService.registerCommitHandler(ROOT, hashMapStore);
+ dataService.registerOperationalReader(ROOT, hashMapStore);
+
mountService = new MountPointManagerImpl();
mountService.setDataBroker(dataService);
mountReg = context.registerService(MountService.class, mountService, emptyProperties);
mountProviderReg = context.registerService(MountProvisionService.class, mountService, emptyProperties);
+
+ brokerReg = context.registerService(Broker.class, broker, emptyProperties);
}
@Override
--- /dev/null
+package org.opendaylight.controller.sal.dom.broker;
+
+import org.opendaylight.controller.md.sal.common.api.data.DataReader;
+import org.opendaylight.controller.md.sal.common.impl.service.AbstractDataBroker;
+import org.opendaylight.controller.sal.common.DataStoreIdentifier;
+import org.opendaylight.controller.sal.core.api.data.DataChangeListener;
+import org.opendaylight.controller.sal.core.api.data.DataProviderService;
+import org.opendaylight.controller.sal.core.api.data.DataValidator;
+import org.opendaylight.controller.sal.dom.broker.impl.DataReaderRouter;
+import org.opendaylight.yangtools.concepts.Registration;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+
+public class DataBrokerImpl extends AbstractDataBroker<InstanceIdentifier, CompositeNode, DataChangeListener> implements
+ DataProviderService {
+
+ public DataBrokerImpl() {
+ setDataReadRouter(new DataReaderRouter());
+ }
+
+ @Override
+ public DataTransactionImpl beginTransaction() {
+ return new DataTransactionImpl(this);
+ }
+
+ @Override
+ public Registration<DataReader<InstanceIdentifier, CompositeNode>> registerConfigurationReader(
+ InstanceIdentifier path, DataReader<InstanceIdentifier, CompositeNode> reader) {
+ return getDataReadRouter().registerConfigurationReader(path, reader);
+ }
+
+ @Override
+ public Registration<DataReader<InstanceIdentifier, CompositeNode>> registerOperationalReader(
+ InstanceIdentifier path, DataReader<InstanceIdentifier, CompositeNode> reader) {
+ return getDataReadRouter().registerOperationalReader(path, reader);
+ }
+
+ @Deprecated
+ @Override
+ public void addValidator(DataStoreIdentifier store, DataValidator validator) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Deprecated
+ @Override
+ public void removeValidator(DataStoreIdentifier store, DataValidator validator) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Deprecated
+ @Override
+ public void addRefresher(DataStoreIdentifier store, DataRefresher refresher) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Deprecated
+ @Override
+ public void removeRefresher(DataStoreIdentifier store, DataRefresher refresher) {
+ // TODO Auto-generated method stub
+
+ }
+
+}
\ No newline at end of file
+++ /dev/null
-package org.opendaylight.controller.sal.dom.broker
-
-import org.opendaylight.controller.sal.core.api.data.DataProviderService
-import org.opendaylight.controller.sal.common.DataStoreIdentifier
-import org.opendaylight.controller.sal.core.api.data.DataProviderService.DataRefresher
-import org.opendaylight.controller.sal.core.api.data.DataValidator
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
-import org.opendaylight.controller.sal.dom.broker.impl.DataReaderRouter
-import org.opendaylight.controller.sal.core.api.data.DataChangeListener
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler
-import org.opendaylight.yangtools.yang.data.api.CompositeNode
-import org.opendaylight.controller.md.sal.common.api.data.DataReader
-
-class DataBrokerImpl implements DataProviderService {
-
- val readRouter = new DataReaderRouter();
-
- override addRefresher(DataStoreIdentifier store, DataRefresher refresher) {
- // NOOP
- }
-
- override addValidator(DataStoreIdentifier store, DataValidator validator) {
- // NOOP
- }
-
- override beginTransaction() {
- // NOOP
- }
-
- override readConfigurationData(InstanceIdentifier path) {
- readRouter.readConfigurationData(path)
- }
-
- override readOperationalData(InstanceIdentifier path) {
- readRouter.readOperationalData(path)
- }
-
- override registerConfigurationReader(InstanceIdentifier path, DataReader<InstanceIdentifier, CompositeNode> reader) {
- readRouter.registerConfigurationReader(path, reader);
- }
-
- override registerOperationalReader(InstanceIdentifier path, DataReader<InstanceIdentifier, CompositeNode> reader) {
- readRouter.registerOperationalReader(path, reader);
- }
-
- override removeRefresher(DataStoreIdentifier store, DataRefresher refresher) {
- // NOOP
- }
-
- override removeValidator(DataStoreIdentifier store, DataValidator validator) {
- // NOOP
- }
-
- override registerDataChangeListener(InstanceIdentifier path, DataChangeListener listener) {
- // NOOP
- }
-
- override registerCommitHandler(InstanceIdentifier path,
- DataCommitHandler<InstanceIdentifier, CompositeNode> commitHandler) {
- // NOOP
- }
-
-}
--- /dev/null
+package org.opendaylight.controller.sal.dom.broker;
+
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.impl.service.AbstractDataTransaction;
+import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.concepts.util.ListenerRegistry;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+
+public class DataTransactionImpl extends AbstractDataTransaction<InstanceIdentifier, CompositeNode>
+ implements DataModificationTransaction {
+ private final ListenerRegistry<DataTransactionListener> listeners = new ListenerRegistry<DataTransactionListener>();
+
+
+
+ public DataTransactionImpl(DataBrokerImpl dataBroker) {
+ super(dataBroker);
+ }
+
+ @Override
+ public ListenerRegistration<DataTransactionListener> registerListener(DataTransactionListener listener) {
+ return listeners.register(listener);
+ }
+
+ protected void onStatusChange(TransactionStatus status) {
+ for (ListenerRegistration<DataTransactionListener> listenerRegistration : listeners) {
+ listenerRegistration.getInstance().onStatusUpdated(this, status);
+ }
+ }
+}
\ No newline at end of file
class DataReaderRouter extends AbstractDataReadRouter<InstanceIdentifier, CompositeNode> {
override protected merge(InstanceIdentifier path, Iterable<CompositeNode> data) {
- return data.iterator.next
+ val iterator = data.iterator;
+ if(iterator.hasNext) {
+ return data.iterator.next
+ }
+ return null;
}
}
--- /dev/null
+package org.opendaylight.controller.sal.dom.broker.impl
+
+import org.opendaylight.yangtools.yang.data.api.CompositeNode
+import java.util.Map
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
+import java.util.Map.Entry
+import java.util.HashSet
+import java.util.ArrayList
+import org.opendaylight.yangtools.yang.data.api.Node
+import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
+
+class DataUtils {
+
+ static def CompositeNode read(Map<InstanceIdentifier, CompositeNode> map, InstanceIdentifier path) {
+ val root = map.get(path);
+ val childs = map.getChilds(path);
+ if(root === null && childs.empty) {
+ return null;
+ }
+
+ return merge(path, root, childs);
+ }
+
+ static def CompositeNode merge(InstanceIdentifier path, CompositeNode node,
+ HashSet<Entry<InstanceIdentifier, CompositeNode>> entries) {
+ val it = new ArrayList<Node<?>>();
+ val qname = path.path.last.nodeType;
+ if (node != null) {
+ addAll(node.children);
+ }
+ for (entry : entries) {
+ val nesting = entry.key.path.size - path.path.size;
+ if (nesting === 1) {
+ add(entry.value);
+ }
+ }
+ return new CompositeNodeTOImpl(qname, null, it);
+ }
+
+ static def getChilds(Map<InstanceIdentifier, CompositeNode> map, InstanceIdentifier path) {
+ val it = new HashSet<Entry<InstanceIdentifier, CompositeNode>>();
+ for (entry : map.entrySet) {
+ if (path.contains(entry.key)) {
+ add(entry);
+ }
+ }
+ return it;
+ }
+
+}
-package org.opendaylight.controller.sal.binding.impl
+package org.opendaylight.controller.sal.dom.broker.impl
import org.opendaylight.controller.md.sal.common.api.data.DataReader
-import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider
import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.opendaylight.yangtools.yang.binding.DataObject
import org.opendaylight.controller.md.sal.common.api.data.DataModification
import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction
import org.opendaylight.yangtools.yang.common.RpcResult
import java.util.concurrent.ConcurrentHashMap
import org.opendaylight.controller.sal.common.util.Rpcs
import java.util.Collections
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
+import org.opendaylight.yangtools.yang.data.api.CompositeNode
+import static extension org.opendaylight.controller.sal.dom.broker.impl.DataUtils.*;
class HashMapDataStore //
implements //
-RuntimeDataProvider, DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject> {
+DataReader<InstanceIdentifier, CompositeNode>, DataCommitHandler<InstanceIdentifier, CompositeNode> {
- val Map<InstanceIdentifier<? extends DataObject>,DataObject> configuration = new ConcurrentHashMap();
- val Map<InstanceIdentifier<? extends DataObject>,DataObject> operational = new ConcurrentHashMap();
+ val Map<InstanceIdentifier, CompositeNode> configuration = new ConcurrentHashMap();
+ val Map<InstanceIdentifier, CompositeNode> operational = new ConcurrentHashMap();
-
- override readConfigurationData(InstanceIdentifier<? extends DataObject> path) {
- configuration.get(path);
+ override readConfigurationData(InstanceIdentifier path) {
+ configuration.read(path);
}
- override readOperationalData(InstanceIdentifier<? extends DataObject> path) {
- operational.get(path);
+ override readOperationalData(InstanceIdentifier path) {
+ operational.read(path);
}
+
+
- override requestCommit(DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification) {
- return new HashMapDataStoreTransaction(modification,this);
+
+ override requestCommit(DataModification<InstanceIdentifier, CompositeNode> modification) {
+ return new HashMapDataStoreTransaction(modification, this);
}
-
+
def RpcResult<Void> rollback(HashMapDataStoreTransaction transaction) {
- return Rpcs.getRpcResult(true,null,Collections.emptySet);
+ return Rpcs.getRpcResult(true, null, Collections.emptySet);
}
-
+
def RpcResult<Void> finish(HashMapDataStoreTransaction transaction) {
val modification = transaction.modification;
configuration.putAll(modification.updatedConfigurationData);
operational.putAll(modification.updatedOperationalData);
-
- for(removal : modification.removedConfigurationData) {
+
+ for (removal : modification.removedConfigurationData) {
configuration.remove(removal);
}
- for(removal : modification.removedOperationalData) {
+ for (removal : modification.removedOperationalData) {
operational.remove(removal);
}
- return Rpcs.getRpcResult(true,null,Collections.emptySet);
+ return Rpcs.getRpcResult(true, null, Collections.emptySet);
}
}
class HashMapDataStoreTransaction implements //
-DataCommitTransaction<InstanceIdentifier<? extends DataObject>, DataObject> {
+DataCommitTransaction<InstanceIdentifier, CompositeNode> {
@Property
- val DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification
+ val DataModification<InstanceIdentifier, CompositeNode> modification
@Property
val HashMapDataStore datastore;
-
-
+
new(
- DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modify,
+ DataModification<InstanceIdentifier, CompositeNode> modify,
HashMapDataStore store
) {
_modification = modify;
<artifactId>yang-data-impl</artifactId>
<version>0.5.9-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-broker-impl</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <scope>test</scope>
+ <type>jar</type>
+ </dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependencies>
<packaging>bundle</packaging>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Bundle-Activator>org.opendaylight.controller.sal.connect.netconf.NetconfProvider</Bundle-Activator>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
</project>
--- /dev/null
+package org.opendaylight.controller.sal.connect.netconf;
+
+import java.net.URI;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+
+public class InventoryUtils {
+
+ private static final URI INVENTORY_NAMESPACE = URI.create("urn:opendaylight:inventory");
+ private static final Date INVENTORY_REVISION = date();
+ public static final QName INVENTORY_NODES = new QName(INVENTORY_NAMESPACE, INVENTORY_REVISION, "nodes");
+ public static final QName INVENTORY_NODE = new QName(INVENTORY_NAMESPACE, INVENTORY_REVISION, "node");
+ public static final QName INVENTORY_ID = new QName(INVENTORY_NAMESPACE, INVENTORY_REVISION, "id");
+
+ public static final InstanceIdentifier INVENTORY_PATH = InstanceIdentifier.builder().node(INVENTORY_NODES)
+ .toInstance();
+ public static final QName NETCONF_INVENTORY_MOUNT = null;
+
+
+
+ private static Date date() {
+ SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
+ try {
+ return formatter.parse("2013-08-19");
+ } catch (ParseException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+
+
+}
--- /dev/null
+package org.opendaylight.controller.sal.connect.netconf
+
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
+import org.opendaylight.controller.md.sal.common.api.data.DataReader
+import org.opendaylight.yangtools.yang.data.api.CompositeNode
+import org.opendaylight.controller.netconf.client.NetconfClient
+import org.opendaylight.controller.sal.core.api.RpcImplementation
+import static extension org.opendaylight.controller.sal.connect.netconf.NetconfMapping.*
+import java.net.InetSocketAddress
+import org.opendaylight.yangtools.yang.data.api.Node
+import org.opendaylight.yangtools.yang.data.api.SimpleNode
+import org.opendaylight.yangtools.yang.common.QName
+import java.util.Collections
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcher
+import org.opendaylight.yangtools.concepts.Registration
+
+class NetconfDevice implements DataReader<InstanceIdentifier, CompositeNode>, RpcImplementation {
+
+ var NetconfClient client;
+
+ @Property
+ var InetSocketAddress socketAddress;
+
+ @Property
+ val MountProvisionInstance mountInstance;
+
+ @Property
+ val InstanceIdentifier path;
+
+ Registration<DataReader<InstanceIdentifier,CompositeNode>> operReaderReg
+
+ Registration<DataReader<InstanceIdentifier,CompositeNode>> confReaderReg
+
+ public new(MountProvisionInstance mount,InstanceIdentifier path) {
+ _mountInstance = mount;
+ _path = path;
+ }
+
+ def start(NetconfClientDispatcher dispatcher) {
+ client = new NetconfClient("sal-netconf-connector", socketAddress, dispatcher);
+
+ confReaderReg = mountInstance.registerConfigurationReader(path,this);
+ operReaderReg = mountInstance.registerOperationalReader(path,this);
+ }
+
+ override readConfigurationData(InstanceIdentifier path) {
+ val result = invokeRpc(NETCONF_GET_CONFIG_QNAME, wrap(NETCONF_GET_CONFIG_QNAME, path.toFilterStructure()));
+ val data = result.result.getFirstCompositeByName(NETCONF_DATA_QNAME);
+ return data?.findNode(path) as CompositeNode;
+ }
+
+ override readOperationalData(InstanceIdentifier path) {
+ val result = invokeRpc(NETCONF_GET_QNAME, wrap(NETCONF_GET_QNAME, path.toFilterStructure()));
+ val data = result.result.getFirstCompositeByName(NETCONF_DATA_QNAME);
+ return data?.findNode(path) as CompositeNode;
+ }
+
+ override getSupportedRpcs() {
+ Collections.emptySet;
+ }
+
+ override invokeRpc(QName rpc, CompositeNode input) {
+ val message = rpc.toRpcMessage(input);
+ val result = client.sendMessage(message);
+ return result.toRpcResult();
+ }
+
+ def Node<?> findNode(CompositeNode node, InstanceIdentifier identifier) {
+
+ var Node<?> current = node;
+ for (arg : identifier.path) {
+ if (current instanceof SimpleNode<?>) {
+ return null;
+ } else if (current instanceof CompositeNode) {
+ val currentComposite = (current as CompositeNode);
+
+ current = currentComposite.getFirstCompositeByName(arg.nodeType);
+ if (current == null) {
+ current = currentComposite.getFirstSimpleByName(arg.nodeType);
+ }
+ if (current == null) {
+ return null;
+ }
+ }
+ }
+ return current;
+ }
+
+ public def stop() {
+ confReaderReg?.close()
+ operReaderReg?.close()
+ }
+
+}
--- /dev/null
+package org.opendaylight.controller.sal.connect.netconf
+
+import org.opendaylight.controller.sal.core.api.Broker.ProviderSession
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionService
+import org.opendaylight.controller.md.sal.common.api.data.DataProvisionService
+import org.opendaylight.controller.sal.core.api.data.DataProviderService
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
+import org.opendaylight.yangtools.yang.common.QName
+import static org.opendaylight.controller.sal.connect.netconf.InventoryUtils.*;
+import static extension org.opendaylight.controller.sal.connect.netconf.NetconfInventoryUtils.*;
+
+import org.opendaylight.controller.sal.core.api.data.DataChangeListener
+import org.opendaylight.yangtools.yang.data.api.CompositeNode
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent
+import java.util.Map
+import java.util.concurrent.ConcurrentHashMap
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcher
+import java.io.OptionalDataException
+import com.google.common.base.Optional
+import java.net.SocketAddress
+import java.net.InetSocketAddress
+
+class NetconfDeviceManager {
+
+ val Map<InstanceIdentifier, NetconfDevice> devices = new ConcurrentHashMap;
+
+ var ProviderSession session;
+
+ @Property
+ var DataProviderService dataService;
+
+ @Property
+ var MountProvisionService mountService;
+
+ val nodeUpdateListener = new NetconfInventoryListener(this);
+
+
+ @Property
+ var NetconfClientDispatcher dispatcher;
+
+ def void start() {
+ dataService?.registerDataChangeListener(INVENTORY_PATH, nodeUpdateListener);
+ if(dispatcher == null) {
+ dispatcher = new NetconfClientDispatcher(Optional.absent);
+ }
+ }
+
+ def netconfNodeAdded(InstanceIdentifier path, CompositeNode node) {
+ val address = node.endpointAddress;
+ val port = Integer.parseInt(node.endpointPort);
+ netconfNodeAdded(path,new InetSocketAddress(address,port))
+
+ }
+
+ def netconfNodeAdded(InstanceIdentifier path, InetSocketAddress address) {
+
+ val mountPointPath = path;
+ val mountPoint = mountService.createOrGetMountPoint(mountPointPath);
+ val localPath = InstanceIdentifier.builder().toInstance;
+ val netconfDevice = new NetconfDevice(mountPoint,localPath);
+ netconfDevice.setSocketAddress(address);
+ netconfDevice.start(dispatcher);
+ }
+
+ def netconfNodeRemoved(InstanceIdentifier path) {
+
+ }
+
+}
+
+class NetconfInventoryListener implements DataChangeListener {
+
+ val NetconfDeviceManager manager;
+
+ new(NetconfDeviceManager manager) {
+ this.manager = manager;
+ }
+
+ override onDataChanged(DataChangeEvent<InstanceIdentifier, CompositeNode> change) {
+
+ //manager.netconfNodeAdded(path, change);
+ }
+}
--- /dev/null
+package org.opendaylight.controller.sal.connect.netconf;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+
+public class NetconfInventoryUtils {
+
+
+ public static final QName NETCONF_MOUNT = null;
+ public static final QName NETCONF_ENDPOINT = null;
+ public static final QName NETCONF_ENDPOINT_ADDRESS = null;
+ public static final QName NETCONF_ENDPOINT_PORT = null;
+
+
+ public static String getEndpointAddress(CompositeNode node) {
+ return node.getCompositesByName(NETCONF_ENDPOINT).get(0).getFirstSimpleByName(NETCONF_ENDPOINT_ADDRESS).getValue().toString();
+ }
+
+ public static String getEndpointPort(CompositeNode node) {
+ return node.getCompositesByName(NETCONF_ENDPOINT).get(0).getFirstSimpleByName(NETCONF_ENDPOINT_PORT).getValue().toString();
+ }
+}
--- /dev/null
+package org.opendaylight.controller.sal.connect.netconf
+
+import org.opendaylight.controller.netconf.api.NetconfMessage
+import org.opendaylight.yangtools.yang.data.api.CompositeNode
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
+import org.opendaylight.yangtools.yang.common.QName
+import org.opendaylight.yangtools.yang.common.RpcResult
+import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
+import java.net.URI
+import java.util.Collections
+import org.opendaylight.yangtools.yang.data.api.Node
+import org.opendaylight.yangtools.yang.data.impl.NodeUtils
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates
+import java.util.ArrayList
+import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
+import java.util.concurrent.atomic.AtomicInteger
+import org.w3c.dom.Document
+import org.w3c.dom.Element
+import org.opendaylight.controller.sal.common.util.Rpcs
+
+class NetconfMapping {
+
+ public static val NETCONF_URI = URI.create("urn:ietf:params:xml:ns:netconf:base:1.0")
+ public static val NETCONF_QNAME = new QName(NETCONF_URI,null,"netconf");
+ public static val NETCONF_RPC_QNAME = new QName(NETCONF_QNAME,"rpc");
+ public static val NETCONF_GET_QNAME = new QName(NETCONF_QNAME,"get");
+ public static val NETCONF_GET_CONFIG_QNAME = new QName(NETCONF_QNAME,"get-config");
+ public static val NETCONF_RPC_REPLY_QNAME = new QName(NETCONF_QNAME,"rpc-reply");
+ public static val NETCONF_OK_QNAME = new QName(NETCONF_QNAME,"ok");
+ public static val NETCONF_DATA_QNAME = new QName(NETCONF_QNAME,"data");
+
+
+ static val messageId = new AtomicInteger(0);
+
+
+
+ static def Node<?> toFilterStructure(InstanceIdentifier identifier) {
+ var Node<?> previous = null;
+ for (component : identifier.path.reverse) {
+ val Node<?> current = component.toNode(previous);
+ previous = current;
+ }
+ return previous;
+ }
+
+ static def dispatch Node<?> toNode(NodeIdentifierWithPredicates argument, Node<?> node) {
+ val list = new ArrayList<Node<?>>();
+ for( arg : argument.keyValues.entrySet) {
+ list.add = new SimpleNodeTOImpl(arg.key,null,arg.value);
+ }
+ return new CompositeNodeTOImpl(argument.nodeType,null,list)
+ }
+
+ static def dispatch Node<?> toNode(PathArgument argument, Node<?> node) {
+ if(node != null) {
+ return new CompositeNodeTOImpl(argument.nodeType,null,Collections.singletonList(node));
+ } else {
+ return new SimpleNodeTOImpl(argument.nodeType,null,null);
+ }
+ }
+
+ static def CompositeNode toCompositeNode(NetconfMessage message) {
+ return message.toRpcResult().result;
+ }
+
+ static def NetconfMessage toRpcMessage(QName rpc, CompositeNode node) {
+ val rpcPayload = wrap(NETCONF_RPC_QNAME,node);
+ val w3cPayload = NodeUtils.buildShadowDomTree(rpcPayload);
+ w3cPayload.documentElement.setAttribute("message-id","m-"+ messageId.andIncrement);
+ return new NetconfMessage(w3cPayload);
+ }
+
+ static def RpcResult<CompositeNode> toRpcResult(NetconfMessage message) {
+ val rawRpc = message.document.toCompositeNode() as CompositeNode;
+ //rawRpc.
+
+ return Rpcs.getRpcResult(true,rawRpc,Collections.emptySet());
+ }
+
+
+ static def wrap(QName name,Node<?> node) {
+ if(node != null) {
+ return new CompositeNodeTOImpl(name,null,Collections.singletonList(node));
+ }
+ else {
+ return new CompositeNodeTOImpl(name,null,Collections.emptyList());
+ }
+ }
+
+
+ public static def Node<?> toCompositeNode(Document document) {
+ return XmlDocumentUtils.toCompositeNode(document) as Node<?>
+ }
+}
--- /dev/null
+package org.opendaylight.controller.sal.connect.netconf;
+
+import java.util.Hashtable;
+
+import org.opendaylight.controller.sal.core.api.AbstractProvider;
+import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
+import org.opendaylight.controller.sal.core.api.data.DataProviderService;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionService;
+import org.osgi.framework.BundleContext;
+
+public class NetconfProvider extends AbstractProvider {
+
+ private NetconfDeviceManager netconfDeviceManager;
+
+ @Override
+ protected void startImpl(BundleContext context) {
+ netconfDeviceManager = new NetconfDeviceManager();
+ context.registerService(NetconfDeviceManager.class, netconfDeviceManager, new Hashtable<String,String>());
+ }
+
+
+ @Override
+ public void onSessionInitiated(ProviderSession session) {
+ MountProvisionService mountService = session.getService(MountProvisionService.class);
+
+
+ netconfDeviceManager.setMountService(mountService);
+ netconfDeviceManager.start();
+ }
+
+ @Override
+ protected void stopImpl(BundleContext context) {
+
+ }
+}
--- /dev/null
+package org.opendaylight.controller.sal.connect.netconf;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl;
+import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+public class XmlDocumentUtils {
+
+ public static CompositeNode toCompositeNode(Document doc) {
+ return (CompositeNode) toCompositeNode(doc.getDocumentElement());
+ }
+
+ private static Node<?> toCompositeNode(Element element) {
+ String orgNamespace = element.getNamespaceURI();
+ URI biNamespace = null;
+ if (orgNamespace != null) {
+ biNamespace = URI.create(orgNamespace);
+ }
+ QName qname = new QName(biNamespace, element.getLocalName());
+
+ List<Node<?>> values = new ArrayList<>();
+ NodeList nodes = element.getChildNodes();
+ boolean isSimpleObject = false;
+ String value = null;
+ for (int i = 0; i < nodes.getLength(); i++) {
+ org.w3c.dom.Node child = nodes.item(i);
+ if (child instanceof Element) {
+ isSimpleObject = false;
+ values.add(toCompositeNode((Element) child));
+ }
+ if (!isSimpleObject && child instanceof org.w3c.dom.Text) {
+ value = element.getTextContent();
+ if (value.matches(".*\\w.*")) {
+ isSimpleObject = true;
+ break;
+ }
+ }
+ }
+
+ if (isSimpleObject) {
+ return new SimpleNodeTOImpl<>(qname, null, value);
+ }
+ return new CompositeNodeTOImpl(qname, null, values);
+ }
+}
--- /dev/null
+package org.opendaylight.controller.sal.connector.netconf.test;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.*;
+import io.netty.channel.ChannelFuture;
+import io.netty.util.HashedWheelTimer;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.management.ManagementFactory;
+import java.net.InetSocketAddress;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import javax.net.ssl.SSLContext;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
+import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
+import org.opendaylight.controller.config.spi.ModuleFactory;
+import org.opendaylight.controller.config.yang.store.api.YangStoreException;
+import org.opendaylight.controller.config.yang.store.impl.HardcodedYangStoreService;
+import org.opendaylight.controller.config.yang.test.impl.DepTestImplModuleFactory;
+import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModuleFactory;
+import org.opendaylight.controller.config.yang.test.impl.TestImplModuleFactory;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.client.NetconfClient;
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.NetconfOperationServiceFactoryImpl;
+import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
+import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
+import org.opendaylight.controller.netconf.impl.NetconfServerSessionListenerFactory;
+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.util.test.XmlFileLoader;
+import org.opendaylight.controller.sal.connect.netconf.InventoryUtils;
+import org.opendaylight.controller.sal.connect.netconf.NetconfDevice;
+import org.opendaylight.controller.sal.connect.netconf.NetconfDeviceManager;
+import org.opendaylight.controller.sal.connect.netconf.NetconfInventoryUtils;
+import org.opendaylight.controller.sal.core.api.data.DataBrokerService;
+import org.opendaylight.controller.sal.core.api.data.DataProviderService;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionService;
+import org.opendaylight.controller.sal.dom.broker.DataBrokerImpl;
+import org.opendaylight.controller.sal.dom.broker.MountPointManagerImpl;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+
+public class MountTest extends AbstractConfigTest {
+
+ private static final InetSocketAddress tcpAddress = new InetSocketAddress("127.0.0.1", 12023);
+ private static final InetSocketAddress tlsAddress = new InetSocketAddress("127.0.0.1", 12024);
+ private static final URI NETCONF_MONITORING_NS = URI.create("urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring");
+
+ private static final QName NETCONF_MONITORING = new QName(NETCONF_MONITORING_NS, new Date(2010,10,04), "ietf-netconf-monitoring");
+ private static final QName NETCONF_MONITORING_STATE = new QName(NETCONF_MONITORING,"netconf-state");
+
+
+ private NetconfMessage getConfig, getConfigCandidate, editConfig, closeSession;
+ private DefaultCommitNotificationProducer commitNot;
+ private NetconfServerDispatcher dispatch;
+ private DataProviderService dataBroker;
+ private MountPointManagerImpl mountManager;
+ private NetconfDeviceManager netconfManager;
+
+ private static QName CONFIG_MODULES = new QName(
+ URI.create("urn:opendaylight:params:xml:ns:yang:controller:config"), null, "modules");
+ private static QName CONFIG_SERVICES = new QName(
+ URI.create("urn:opendaylight:params:xml:ns:yang:controller:config"), null, "modules");
+
+ private NetconfClient createSession(final InetSocketAddress address, NetconfClientDispatcher dispatcher) throws InterruptedException {
+ final NetconfClient netconfClient = new NetconfClient("test " + address.toString(), address, 5000, dispatcher);
+ return netconfClient;
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(getModuleFactories().toArray(
+ new ModuleFactory[0])));
+
+ loadMessages();
+
+ NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
+ factoriesListener.onAddNetconfOperationServiceFactory(new NetconfOperationServiceFactoryImpl(getYangStore()));
+
+ commitNot = new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
+
+ dispatch = createDispatcher(Optional.<SSLContext> absent(), factoriesListener);
+ ChannelFuture s = dispatch.createServer(tcpAddress);
+ s.await();
+
+ dataBroker = new DataBrokerImpl();
+ mountManager = new MountPointManagerImpl();
+ mountManager.setDataBroker(dataBroker);
+ netconfManager = new NetconfDeviceManager();
+
+ netconfManager.setMountService(mountManager);
+ netconfManager.setDataService(dataBroker);
+ netconfManager.start();
+
+ try (NetconfClient netconfClient = createSession(tcpAddress, netconfManager.getDispatcher())) {
+ // send edit_config.xml
+ final Document rpcReply = netconfClient.sendMessage(this.editConfig).getDocument();
+ assertNotNull(rpcReply);
+ }
+ }
+
+
+ protected List<ModuleFactory> getModuleFactories() {
+ return getModuleFactoriesS();
+ }
+
+ static List<ModuleFactory> getModuleFactoriesS() {
+ return Lists.newArrayList(new TestImplModuleFactory(), new DepTestImplModuleFactory(),
+ new NetconfTestImplModuleFactory());
+ }
+
+ private void loadMessages() throws IOException, SAXException, ParserConfigurationException {
+ this.editConfig = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/edit_config.xml");
+ this.getConfig = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/getConfig.xml");
+ this.getConfigCandidate = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/getConfig_candidate.xml");
+ this.closeSession = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/closeSession.xml");
+ }
+
+ private NetconfServerDispatcher createDispatcher(Optional<SSLContext> sslC,
+ NetconfOperationServiceFactoryListenerImpl factoriesListener) {
+ SessionIdProvider idProvider = new SessionIdProvider();
+ NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory(
+ new HashedWheelTimer(5000, TimeUnit.MILLISECONDS), factoriesListener, idProvider);
+
+ NetconfServerSessionListenerFactory listenerFactory = new NetconfServerSessionListenerFactory(
+ factoriesListener, commitNot, idProvider);
+
+ return new NetconfServerDispatcher(sslC, serverNegotiatorFactory, listenerFactory);
+ }
+
+ private HardcodedYangStoreService getYangStore() throws YangStoreException, IOException {
+ final Collection<InputStream> yangDependencies = getBasicYangs();
+ return new HardcodedYangStoreService(yangDependencies);
+ }
+
+ private Collection<InputStream> getBasicYangs() throws IOException {
+ List<String> paths = Arrays.asList("/META-INF/yang/config.yang", "/META-INF/yang/rpc-context.yang",
+ "/META-INF/yang/config-test.yang", "/META-INF/yang/config-test-impl.yang",
+ "/META-INF/yang/ietf-inet-types.yang");
+ final Collection<InputStream> yangDependencies = new ArrayList<>();
+ for (String path : paths) {
+ final InputStream is = Preconditions
+ .checkNotNull(getClass().getResourceAsStream(path), path + " not found");
+ yangDependencies.add(is);
+ }
+ return yangDependencies;
+ }
+
+ @Test
+ public void test() {
+ // MountProvisionInstance mount =
+ // Mockito.mock(MountProvisionInstance.class);
+ InstanceIdentifier path = InstanceIdentifier.builder(InventoryUtils.INVENTORY_PATH)
+ .node(InventoryUtils.INVENTORY_NODE).toInstance();
+ netconfManager.netconfNodeAdded(path, tcpAddress);
+ InstanceIdentifier mountPointPath = path;
+ MountProvisionInstance mountPoint = mountManager.getMountPoint(mountPointPath);
+
+ CompositeNode data = mountPoint.readOperationalData(InstanceIdentifier.builder().node(CONFIG_MODULES)
+ .toInstance());
+ assertNotNull(data);
+ assertEquals(CONFIG_MODULES, data.getNodeType());
+
+ CompositeNode data2 = mountPoint.readOperationalData(InstanceIdentifier.builder().toInstance());
+ assertNotNull(data2);
+
+ InstanceIdentifier fullPath = InstanceIdentifier.builder(mountPointPath).node(CONFIG_MODULES).toInstance();
+
+ CompositeNode data3 = dataBroker.readOperationalData(fullPath);
+ assertNotNull(data3);
+ assertEquals(CONFIG_MODULES, data.getNodeType());
+ }
+
+}
--- /dev/null
+package org.opendaylight.controller.sal.rest.api;
+
+public class Draft02 {
+ public static class MediaTypes {
+ public static final String API = "application/yang.api";
+ public static final String DATASTORE = "application/yang.datastore";
+ public static final String DATA = "application/yang.data";
+ public static final String OPERATION = "application/yang.operation";
+ public static final String PATCH = "application/yang.patch";
+ public static final String PATCH_STATUS = "application/yang.patch-status";
+ public static final String STREAM = "application/yang.stream";
+ }
+
+ public static class Paths {
+
+ }
+}
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
import org.opendaylight.controller.sal.restconf.impl.StructuredData;
+import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
/**
* Section 5 for details on each URI.
* <ul>
* <li><b>/restconf</b> - {@link #getRoot()}
- * <ul><li><b>/datastore</b> - {@link #readAllData()}
+ * <ul><li><b>/config</b>
+ * <li><b>/operational</b> - {@link #readAllData()} - Added in Draft02
+ * <li><b>/datastore</b> - {@link #readAllData()}
* <ul>
* <li>/(top-level-data-nodes) (config=true or false)
* </ul>
* </ul>
*/
@Path("/")
-public interface RestconfService {
+public interface RestconfService extends RestconfServiceLegacy {
public static final String XML = "+xml";
public static final String JSON = "+json";
@GET
public Object getRoot();
+
@GET
- @Path("/datastore")
+ @Path("/modules")
@Produces({API+JSON,API+XML})
- public Object readAllData();
+ public StructuredData getModules();
+ @POST
+ @Path("/operations/{identifier}")
+ @Produces({Draft02.MediaTypes.API+JSON,Draft02.MediaTypes.API+XML,API+JSON,API+XML})
+ public StructuredData invokeRpc(@PathParam("identifier") String identifier, CompositeNode payload);
+
+
@GET
- @Path("/datastore/{identifier:.+}")
- @Produces({API+JSON,API+XML})
- public StructuredData readData(@PathParam("identifier") String identifier);
+ @Path("/config/{identifier:.+}")
+ @Produces({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML})
+ public StructuredData readConfigurationData(@PathParam("identifier") String identifier);
+
+
@PUT
- @Path("/datastore/{identifier:.+}")
+ @Path("/config/{identifier:.+}")
@Produces({API+JSON,API+XML})
- public Object createConfigurationData(@PathParam("identifier") String identifier, CompositeNode payload);
+ public RpcResult<TransactionStatus> createConfigurationData(@PathParam("identifier") String identifier, CompositeNode payload);
@POST
- @Path("/datastore/{identifier:.+}")
+ @Path("/config/{identifier:.+}")
@Produces({API+JSON,API+XML})
- public Object updateConfigurationData(@PathParam("identifier") String identifier, CompositeNode payload);
+ public RpcResult<TransactionStatus> updateConfigurationData(@PathParam("identifier") String identifier, CompositeNode payload);
@GET
- @Path("/modules")
+ @Path("/operational/{identifier:.+}")
+ @Produces({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML})
+ public StructuredData readOperationalData(@PathParam("identifier") String identifier);
+
+ @PUT
+ @Path("/operational/{identifier:.+}")
@Produces({API+JSON,API+XML})
- public Object getModules();
+ public RpcResult<TransactionStatus> createOperationalData(@PathParam("identifier") String identifier, CompositeNode payload);
@POST
- @Path("/operations/{identifier}")
+ @Path("/operational/{identifier:.+}")
@Produces({API+JSON,API+XML})
- public StructuredData invokeRpc(@PathParam("identifier") String identifier, CompositeNode payload);
+ public RpcResult<TransactionStatus> updateOperationalData(@PathParam("identifier") String identifier, CompositeNode payload);
+
+
}
--- /dev/null
+package org.opendaylight.controller.sal.rest.api;
+
+import static org.opendaylight.controller.sal.restconf.impl.MediaTypes.API;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.sal.restconf.impl.StructuredData;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+
+public interface RestconfServiceLegacy {
+
+ public static final String XML = "+xml";
+ public static final String JSON = "+json";
+
+ @Deprecated
+ @GET
+ @Path("/datastore")
+ @Produces({API+JSON,API+XML})
+ public StructuredData readAllData();
+
+ @Deprecated
+ @GET
+ @Path("/datastore/{identifier:.+}")
+ @Produces({API+JSON,API+XML})
+ public StructuredData readData(@PathParam("identifier") String identifier);
+
+ @Deprecated
+ @PUT
+ @Path("/datastore/{identifier:.+}")
+ @Produces({API+JSON,API+XML})
+ public RpcResult<TransactionStatus> createConfigurationDataLegacy(@PathParam("identifier") String identifier, CompositeNode payload);
+
+ @Deprecated
+ @POST
+ @Path("/datastore/{identifier:.+}")
+ @Produces({API+JSON,API+XML})
+ public RpcResult<TransactionStatus> updateConfigurationDataLegacy(@PathParam("identifier") String identifier, CompositeNode payload);
+
+}
return future.get;
}
- def commitConfigurationDataUpdate(InstanceIdentifier path, CompositeNode payload) {
+ def commitConfigurationDataPut(InstanceIdentifier path, CompositeNode payload) {
val transaction = dataService.beginTransaction;
transaction.putConfigurationData(path, payload);
return transaction.commit()
}
- def commitConfigurationDataCreate(InstanceIdentifier path, CompositeNode payload) {
+ def commitOperationalDataPut(InstanceIdentifier path, CompositeNode payload) {
val transaction = dataService.beginTransaction;
- transaction.putConfigurationData(path, payload);
+ transaction.putOperationalData(path, payload);
return transaction.commit()
}
import static com.google.common.base.Preconditions.*
import org.opendaylight.controller.sal.core.api.model.SchemaServiceListener
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition
+import java.util.concurrent.ConcurrentHashMap
class ControllerContext implements SchemaServiceListener {
private val BiMap<URI, String> uriToModuleName = HashBiMap.create();
private val Map<String, URI> moduleNameToUri = uriToModuleName.inverse();
+ private val Map<QName,RpcDefinition> qnameToRpc = new ConcurrentHashMap();
+
private new() {
if (INSTANCE != null) {
}
}
- public def QName toRpcQName(String name) {
+ public def QName toQName(String name) {
+ val module = name.toModuleName;
+ val node = name.toNodeName;
+ val namespace = moduleNameToUri.get(module);
+ return new QName(namespace,null,node);
}
override onGlobalContextUpdated(SchemaContext context) {
this.schemas = context;
+ for(operation : context.operations) {
+ val qname = new QName(operation.QName.namespace,null,operation.QName.localName);
+ qnameToRpc.put(qname,operation);
+ }
+ }
+
+ def ContainerSchemaNode getRpcOutputSchema(QName name) {
+ qnameToRpc.get(name)?.output;
}
}
override readAllData() {
// return broker.readOperationalData("".toInstanceIdentifier.getInstanceIdentifier);
- throw new UnsupportedOperationException("TODO: auto-generated method stub")
+ throw new UnsupportedOperationException("Reading all data is currently not supported.")
}
override getModules() {
}
override getRoot() {
- throw new UnsupportedOperationException("TODO: auto-generated method stub")
-
+ return null;
}
override readData(String identifier) {
}
override createConfigurationData(String identifier, CompositeNode payload) {
-// return broker.commitConfigurationDataCreate(identifier.toInstanceIdentifier.getInstanceIdentifier, payload);
- throw new UnsupportedOperationException("TODO: auto-generated method stub")
+ val identifierWithSchemaNode = identifier.toInstanceIdentifier
+ return broker.commitConfigurationDataPut(identifierWithSchemaNode.instanceIdentifier,payload).get();
}
override updateConfigurationData(String identifier, CompositeNode payload) {
-// return broker.commitConfigurationDataCreate(identifier.toInstanceIdentifier.getInstanceIdentifier, payload);
- throw new UnsupportedOperationException("TODO: auto-generated method stub")
+ val identifierWithSchemaNode = identifier.toInstanceIdentifier
+ return broker.commitConfigurationDataPut(identifierWithSchemaNode.instanceIdentifier,payload).get();
}
override invokeRpc(String identifier, CompositeNode payload) {
- val rpcResult = broker.invokeRpc(identifier.toRpcQName, payload);
- return new StructuredData(rpcResult.result, identifier.toInstanceIdentifier.getSchemaNode)
+ val rpc = identifier.toQName;
+ val rpcResult = broker.invokeRpc(rpc, payload);
+ val schema = controllerContext.getRpcOutputSchema(rpc);
+ return new StructuredData(rpcResult.result, schema);
+ }
+
+ override readConfigurationData(String identifier) {
+ val instanceIdentifierWithSchemaNode = identifier.toInstanceIdentifier
+ val data = broker.readOperationalData(instanceIdentifierWithSchemaNode.getInstanceIdentifier);
+ return new StructuredData(data, instanceIdentifierWithSchemaNode.schemaNode)
+ }
+
+ override readOperationalData(String identifier) {
+ val instanceIdentifierWithSchemaNode = identifier.toInstanceIdentifier
+ val data = broker.readOperationalData(instanceIdentifierWithSchemaNode.getInstanceIdentifier);
+ return new StructuredData(data, instanceIdentifierWithSchemaNode.schemaNode)
+ }
+
+ override updateConfigurationDataLegacy(String identifier, CompositeNode payload) {
+ updateConfigurationData(identifier,payload);
+ }
+
+ override createConfigurationDataLegacy(String identifier, CompositeNode payload) {
+ createConfigurationData(identifier,payload);
+ }
+
+ override createOperationalData(String identifier, CompositeNode payload) {
+ val identifierWithSchemaNode = identifier.toInstanceIdentifier
+ return broker.commitOperationalDataPut(identifierWithSchemaNode.instanceIdentifier,payload).get();
+ }
+
+ override updateOperationalData(String identifier, CompositeNode payload) {
+ val identifierWithSchemaNode = identifier.toInstanceIdentifier
+ return broker.commitOperationalDataPut(identifierWithSchemaNode.instanceIdentifier,payload).get();
}
}
<artifactId>logback-classic</artifactId>
<version>1.0.9</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools.thirdparty</groupId>
+ <artifactId>antlr4-runtime-osgi-nohead</artifactId>
+ <version>4.0</version>
+ </dependency>
</dependencies>
</project>
import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
import static org.ops4j.pax.exam.CoreOptions.options;
import static org.ops4j.pax.exam.CoreOptions.systemProperty;
+import org.ops4j.pax.exam.util.PathUtils;
@RunWith(PaxExam.class)
public class ToasterTest {
public static final String ODL = "org.opendaylight.controller";
public static final String YANG = "org.opendaylight.yangtools";
+ public static final String CONTROLLER = "org.opendaylight.controller";
+ public static final String YANGTOOLS = "org.opendaylight.yangtools";
+
+
public static final String SAMPLE = "org.opendaylight.controller.samples";
@Test
@Configuration
public Option[] config() {
return options(systemProperty("osgi.console").value("2401"),
+ systemProperty("logback.configurationFile").value(
+ "file:" + PathUtils.getBaseDir()
+ + "/src/test/resources/logback.xml"),
mavenBundle("org.slf4j", "slf4j-api").versionAsInProject(), //
mavenBundle("org.slf4j", "log4j-over-slf4j").versionAsInProject(), //
mavenBundle("ch.qos.logback", "logback-core").versionAsInProject(), //
mavenBundle("ch.qos.logback", "logback-classic").versionAsInProject(), //
- mavenBundle(ODL, "sal-binding-api").versionAsInProject(), //
- mavenBundle(ODL, "sal-binding-config").versionAsInProject(),
- mavenBundle(ODL, "sal-binding-broker-impl").versionAsInProject(), //
mavenBundle(ODL, "sal-common").versionAsInProject(), //
mavenBundle(ODL, "sal-common-api").versionAsInProject(),//
mavenBundle(ODL, "config-api").versionAsInProject(), //
mavenBundle(ODL, "config-manager").versionAsInProject(), //
mavenBundle("commons-io", "commons-io").versionAsInProject(),
+ mavenBundle("org.apache.commons", "commons-lang3").versionAsInProject(),
+ mavenBundle(CONTROLLER, "sal-binding-api").versionAsInProject(), //
+ mavenBundle(CONTROLLER, "sal-binding-config").versionAsInProject(),
+ mavenBundle(CONTROLLER, "sal-binding-broker-impl").versionAsInProject(), //
+ mavenBundle("org.javassist", "javassist").versionAsInProject(), //
+ mavenBundle(CONTROLLER, "sal-common-util").versionAsInProject(), //
+
+ mavenBundle(YANGTOOLS, "yang-data-api").versionAsInProject(), //
+ mavenBundle(YANGTOOLS, "yang-data-impl").versionAsInProject(), //
+ mavenBundle(YANGTOOLS, "yang-model-api").versionAsInProject(), //
+ mavenBundle(YANGTOOLS, "yang-model-util").versionAsInProject(), //
+ mavenBundle(YANGTOOLS, "yang-parser-api").versionAsInProject(),
+ mavenBundle(YANGTOOLS, "yang-parser-impl").versionAsInProject(),
+
+
+ mavenBundle(YANGTOOLS, "binding-generator-spi").versionAsInProject(), //
+ mavenBundle(YANGTOOLS, "binding-model-api").versionAsInProject(), //
+ mavenBundle(YANGTOOLS, "binding-generator-util").versionAsInProject(),
+ mavenBundle(YANGTOOLS, "yang-parser-impl").versionAsInProject(),
+ mavenBundle(YANGTOOLS, "binding-type-provider").versionAsInProject(),
+ mavenBundle(YANGTOOLS, "binding-generator-api").versionAsInProject(),
+ mavenBundle(YANGTOOLS, "binding-generator-spi").versionAsInProject(),
+ mavenBundle(YANGTOOLS, "binding-generator-impl").versionAsInProject(),
+
+
+ mavenBundle(CONTROLLER, "sal-core-api").versionAsInProject().update(), //
+ mavenBundle(CONTROLLER, "sal-broker-impl").versionAsInProject(), //
+ mavenBundle(CONTROLLER, "sal-core-spi").versionAsInProject().update(), //
+
+ mavenBundle(YANGTOOLS + ".thirdparty", "antlr4-runtime-osgi-nohead").versionAsInProject(), //
mavenBundle(SAMPLE, "sample-toaster").versionAsInProject(), //
mavenBundle(SAMPLE, "sample-toaster-consumer").versionAsInProject(), //
<configuration scan="true">
+
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
<spring.version>3.1.3.RELEASE</spring.version>
<jersey.version>1.17</jersey.version>
<spring-security.version>3.1.3.RELEASE</spring-security.version>
+ <netconf.version>0.2.2-SNAPSHOT</netconf.version>
+ <config.version>0.2.2-SNAPSHOT</config.version>
</properties>
<build>
<version>1.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-netconf-connector</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-it</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller.thirdparty</groupId>
+ <artifactId>exificient</artifactId>
+ <version>0.9.2</version>
+ </dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-container-native</artifactId>
<version>${exam.version}</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>io.netty</groupId>
+ <artifactId>netty-all</artifactId>
+ <version>4.0.10.Final</version>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-link-mvn</artifactId>
<artifactId>org.apache.catalina.filters.CorsFilter</artifactId>
<version>7.0.42</version>
</dependency>
+
+
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-api</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-manager</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-util</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>yang-jmx-generator</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>yang-store-api</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>yang-store-impl</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>logback-config</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-persister-api</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-persister-file-adapter</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-api</artifactId>
+ <version>${netconf.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-impl</artifactId>
+ <version>${netconf.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-util</artifactId>
+ <version>${netconf.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-client</artifactId>
+ <version>${netconf.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-mapping-api</artifactId>
+ <version>${netconf.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-netconf-connector</artifactId>
+ <version>${netconf.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-persister-impl</artifactId>
+ <version>${netconf.version}</version>
+ </dependency>
</dependencies>
</project>
package org.opendaylight.controller.test.restconf.it;
+import static junit.framework.Assert.assertEquals;
import static org.junit.Assert.*;
import static org.ops4j.pax.exam.CoreOptions.junitBundles;
import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
import static org.ops4j.pax.exam.CoreOptions.systemProperty;
import static org.ops4j.pax.exam.CoreOptions.maven;
+import java.net.InetSocketAddress;
+import java.net.URI;
import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
import javax.inject.Inject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.sal.connect.netconf.InventoryUtils;
+import org.opendaylight.controller.sal.connect.netconf.NetconfDeviceManager;
+import org.opendaylight.controller.sal.connect.netconf.NetconfInventoryUtils;
+import org.opendaylight.controller.sal.core.api.data.DataBrokerService;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionService;
import org.opendaylight.controller.test.sal.binding.it.TestHelper;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.ops4j.pax.exam.Configuration;
import org.ops4j.pax.exam.CoreOptions;
import org.ops4j.pax.exam.Option;
public static final String YANG = "org.opendaylight.yangtools";
public static final String SAMPLE = "org.opendaylight.controller.samples";
+ private static QName CONFIG_MODULES = new QName(
+ URI.create("urn:opendaylight:params:xml:ns:yang:controller:config"), null, "modules");
+ private static QName CONFIG_SERVICES = new QName(
+ URI.create("urn:opendaylight:params:xml:ns:yang:controller:config"), null, "modules");
+ @Inject
+ BundleContext context;
+
+ @Inject
+ MountProvisionService mountService;
+
+ @Inject
+ DataBrokerService dataBroker;
+
+ @Inject
+ NetconfDeviceManager netconfManager;
+
@Test
public void properInitialized() throws Exception {
- Thread.sleep(30*60*1000); // Waiting for services to get wired.
- assertTrue(true);
- // assertTrue(consumer.createToast(WhiteBread.class, 5));
+ Map<QName, String> arg = Collections.singletonMap(InventoryUtils.INVENTORY_ID, "foo");
- }
+ InstanceIdentifier path = InstanceIdentifier.builder(InventoryUtils.INVENTORY_PATH)
+ .nodeWithKey(InventoryUtils.INVENTORY_NODE, InventoryUtils.INVENTORY_ID, "foo").toInstance();
- // @Inject
- // BindingAwareBroker broker;
+ netconfManager.netconfNodeAdded(path, new InetSocketAddress("127.0.0.1", 8383));
- // @Inject
- // ToastConsumer consumer;
+
+ InstanceIdentifier mountPointPath = path;
+
+ /** We retrive a mountpoint **/
+ MountProvisionInstance mountPoint = mountService.getMountPoint(mountPointPath);
+ CompositeNode data = mountPoint.readOperationalData(InstanceIdentifier.builder().node(CONFIG_MODULES)
+ .toInstance());
+ assertNotNull(data);
+ assertEquals(CONFIG_MODULES, data.getNodeType());
- @Inject
- BundleContext ctx;
+ CompositeNode data2 = mountPoint.readOperationalData(InstanceIdentifier.builder().toInstance());
+ assertNotNull(data2);
+
+ InstanceIdentifier fullPath = InstanceIdentifier.builder(mountPointPath).node(CONFIG_MODULES).toInstance();
+
+ CompositeNode data3 = dataBroker.readOperationalData(fullPath);
+ assertNotNull(data3);
+ assertEquals(CONFIG_MODULES, data.getNodeType());
+
+ //Thread.sleep(30 * 60 * 1000); // Waiting for services to get wired.
+ //assertTrue(true);
+ // assertTrue(consumer.createToast(WhiteBread.class, 5));
+ }
@Configuration
public Option[] config() {
mdSalCoreBundles(),
baseModelBundles(),
flowCapableModelBundles(),
+ configMinumumBundles(),
// mavenBundle(ODL,
// "sal-binding-broker-impl").versionAsInProject().update(), //
// mavenBundle(SAMPLE,
// "zeromq-test-provider").versionAsInProject(), //
mavenBundle(ODL, "sal-rest-connector").versionAsInProject(), //
+ mavenBundle(ODL, "sal-netconf-connector").versionAsInProject(), //
mavenBundle(YANG, "concepts").versionAsInProject(),
mavenBundle(YANG, "yang-binding").versionAsInProject(), //
mavenBundle(YANG, "yang-model-util").versionAsInProject(), //
mavenBundle(YANG, "yang-parser-api").versionAsInProject(),
mavenBundle(YANG, "yang-parser-impl").versionAsInProject(),
+
mavenBundle(YANG + ".thirdparty", "xtend-lib-osgi").versionAsInProject(), //
mavenBundle(YANG + ".thirdparty", "antlr4-runtime-osgi-nohead").versionAsInProject(), //
mavenBundle("com.google.guava", "guava").versionAsInProject(), //
// earlier.
systemProperty("osgi.bundles.defaultStartLevel").value("4"),
+ systemProperty("netconf.tcp.address").value("127.0.0.1"),
+ systemProperty("netconf.tcp.port").value("8383"),
+
// Set the systemPackages (used by clustering)
systemPackages("sun.reflect", "sun.reflect.misc", "sun.misc"),
+
+ mavenBundle("org.apache.servicemix.bundles", "org.apache.servicemix.bundles.xerces", "2.11.0_1"),
+ mavenBundle("org.eclipse.birt.runtime.3_7_1", "org.apache.xml.resolver", "1.2.0"),
+
mavenBundle("org.slf4j", "jcl-over-slf4j").versionAsInProject(),
mavenBundle("org.slf4j", "slf4j-api").versionAsInProject(),
mavenBundle("org.slf4j", "log4j-over-slf4j").versionAsInProject(),
// mavenBundle("commons-fileupload",
// "commons-fileupload").versionAsInProject(),
+ mavenBundle("io.netty", "netty-handler").versionAsInProject(),
+ mavenBundle("io.netty", "netty-codec").versionAsInProject(),
+ mavenBundle("io.netty", "netty-buffer").versionAsInProject(),
+ mavenBundle("io.netty", "netty-transport").versionAsInProject(),
+ mavenBundle("io.netty", "netty-common").versionAsInProject(),
+
+ mavenBundle(ODL, "config-api").versionAsInProject(),
+ mavenBundle(ODL, "config-manager").versionAsInProject(),
+ mavenBundle(ODL, "config-util").versionAsInProject(),
+ mavenBundle(ODL, "yang-jmx-generator").versionAsInProject(),
+ mavenBundle(ODL, "yang-store-api").versionAsInProject(),
+ mavenBundle(ODL, "yang-store-impl").versionAsInProject(),
+ mavenBundle(ODL, "logback-config").versionAsInProject(),
+ mavenBundle(ODL, "config-persister-api").versionAsInProject(),
+ // mavenBundle(ODL,"config-persister-file-adapter").versionAsInProject(),
+ mavenBundle(ODL, "netconf-api").versionAsInProject(),
+ mavenBundle(ODL, "netconf-impl").versionAsInProject(),
+ mavenBundle(ODL, "netconf-client").versionAsInProject(),
+ mavenBundle(ODL, "netconf-util").versionAsInProject(),
+ mavenBundle(ODL + ".thirdparty", "ganymed", "1.0-SNAPSHOT"),
+ mavenBundle(ODL, "netconf-mapping-api").versionAsInProject(),
+ mavenBundle(ODL, "config-netconf-connector").versionAsInProject(),
+ mavenBundle(ODL, "config-persister-impl").versionAsInProject(),
+
+ mavenBundle("org.opendaylight.bgpcep", "framework").versionAsInProject(),
+ mavenBundle("org.opendaylight.bgpcep", "util").versionAsInProject(),
+ mavenBundle(YANG, "binding-generator-spi").versionAsInProject(), //
+ mavenBundle(YANG, "binding-model-api").versionAsInProject(), //
+ mavenBundle(YANG, "binding-generator-util").versionAsInProject(),
+ mavenBundle(YANG, "yang-parser-impl").versionAsInProject(),
+ mavenBundle(YANG, "binding-type-provider").versionAsInProject(),
+
+ mavenBundle("org.opendaylight.controller.thirdparty", "exificient", "0.9.2"),
+
mavenBundle("equinoxSDK381", "javax.servlet").versionAsInProject(),
mavenBundle("equinoxSDK381", "javax.servlet.jsp").versionAsInProject(),
mavenBundle("equinoxSDK381", "org.eclipse.equinox.ds").versionAsInProject(),
<version>${bgpcep.version}</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>commons.logback_settings</artifactId>
+ </dependency>
</dependencies>
<build>
org.opendaylight.controller.netconf.client,
org.opendaylight.controller.netconf.util.osgi,
org.opendaylight.controller.netconf.util.xml,
+ io.netty.channel,
+ io.netty.channel.nio,
+ io.netty.util.concurrent,
org.osgi.framework,
org.slf4j,
org.w3c.dom,
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.collect.Sets;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
import org.opendaylight.controller.config.persist.api.Persister;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.api.jmx.CommitJMXNotification;
private final InetSocketAddress address;
private final NetconfClientDispatcher dispatcher;
+ private final EventLoopGroup nettyThreadgroup;
private NetconfClient netconfClient;
this.address = address;
this.mbeanServer = mbeanServer;
this.timeout = timeout;
- this.dispatcher = new NetconfClientDispatcher(Optional.<SSLContext>absent());
+
+ this.nettyThreadgroup = new NioEventLoopGroup();
+ this.dispatcher = new NetconfClientDispatcher(Optional.<SSLContext>absent(), nettyThreadgroup, nettyThreadgroup);
}
public void init() throws InterruptedException {
}
try {
- dispatcher.close();
+ nettyThreadgroup.shutdownGracefully();
} catch (Exception e) {
- logger.warn("Unable to close netconf client dispatcher {}", dispatcher, e);
+ logger.warn("Unable to close netconf client thread group {}", dispatcher, e);
}
// unregister from JMX
--- /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 org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
+
+/**
+ * Class extending {@link NetconfClientSessionListener} to provide notification capability.
+ */
+public abstract class AbstractNetconfClientNotifySessionListener extends NetconfClientSessionListener {
+ /*
+ * Maybe some capabilities could be expressed as internal NetconfClientSessionListener handlers.
+ * It would enable NetconfClient functionality to be extended by using namespace handlers.
+ * So far let just enable notification capability by extending and let parent class intact.
+ */
+
+ /**
+ * As class purpose is to provide notification capability to session listener
+ * onMessage method is not allowed to be further overridden.
+ * {@see #onNotification(NetconfClientSession, NetconfMessage)}
+ *
+ * @param session {@see NetconfClientSessionListener#onMessage(NetconfClientSession, NetconfMessage)}
+ * @param message {@see NetconfClientSessionListener#onMessage(NetconfClientSession, NetconfMessage)}
+ */
+ @Override
+ public final synchronized void onMessage(NetconfClientSession session, NetconfMessage message) {
+ if (isNotification(message)) {
+ onNotification(session, message);
+ } else {
+ super.onMessage(session, message);
+ }
+ }
+
+ /**
+ * Method intended to customize notification processing.
+ *
+ * @param session {@see NetconfClientSessionListener#onMessage(NetconfClientSession, NetconfMessage)}
+ * @param message {@see NetconfClientSessionListener#onMessage(NetconfClientSession, NetconfMessage)}
+ */
+ public abstract void onNotification(NetconfClientSession session, NetconfMessage message);
+
+ private boolean isNotification(NetconfMessage message) {
+ XmlElement xmle = XmlElement.fromDomDocument(message.getDocument());
+ return XmlNetconfConstants.NOTIFICATION_ELEMENT_NAME.equals(xmle.getName()) ;
+ }
+}
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
+import io.netty.channel.EventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.util.HashedWheelTimer;
import io.netty.util.concurrent.Future;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.api.NetconfSession;
import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
-import org.opendaylight.controller.netconf.util.AbstractChannelInitializer;
+import org.opendaylight.controller.netconf.util.AbstractSslChannelInitializer;
import org.opendaylight.protocol.framework.AbstractDispatcher;
import org.opendaylight.protocol.framework.ReconnectStrategy;
import org.opendaylight.protocol.framework.SessionListener;
private final Optional<SSLContext> maybeContext;
private final NetconfClientSessionNegotiatorFactory negotatorFactory;
- public NetconfClientDispatcher(final Optional<SSLContext> maybeContext) {
+ public NetconfClientDispatcher(final Optional<SSLContext> maybeContext, EventLoopGroup bossGroup, EventLoopGroup workerGroup) {
+ super(bossGroup, workerGroup);
this.maybeContext = Preconditions.checkNotNull(maybeContext);
this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(new HashedWheelTimer());
}
}
private void initialize(SocketChannel ch, Promise<NetconfClientSession> promise) {
- new ClientChannelInitializer(maybeContext, negotatorFactory, sessionListener).initialize(ch, promise);
+ new ClientSslChannelInitializer(maybeContext, negotatorFactory, sessionListener).initialize(ch, promise);
}
});
}
- private static class ClientChannelInitializer extends AbstractChannelInitializer {
+ private static class ClientSslChannelInitializer extends AbstractSslChannelInitializer {
private final NetconfClientSessionNegotiatorFactory negotiatorFactory;
private final NetconfClientSessionListener sessionListener;
- private ClientChannelInitializer(Optional<SSLContext> maybeContext,
- NetconfClientSessionNegotiatorFactory negotiatorFactory, NetconfClientSessionListener sessionListener) {
+ private ClientSslChannelInitializer(Optional<SSLContext> maybeContext,
+ NetconfClientSessionNegotiatorFactory negotiatorFactory, NetconfClientSessionListener sessionListener) {
super(maybeContext);
this.negotiatorFactory = negotiatorFactory;
this.sessionListener = sessionListener;
--- /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;
+
+public class NetconfSshClientDispatcher extends NetconfClientDispatcher {
+
+ public NetconfSshClientDispatcher(EventLoopGroup bossGroup, EventLoopGroup workerGroup) {
+ super(null, bossGroup, workerGroup);
+ }
+}
<artifactId>netconf-client</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>commons.logback_settings</artifactId>
+ </dependency>
</dependencies>
<build>
io.netty.util.concurrent,
io.netty.buffer,
io.netty.handler.codec,
+ io.netty.channel.nio,
javax.management,
javax.net.ssl,
javax.xml.namespace,
import com.google.common.base.Optional;
import io.netty.channel.ChannelFuture;
+import io.netty.channel.EventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.util.concurrent.Promise;
import org.opendaylight.controller.netconf.api.NetconfSession;
import org.opendaylight.controller.netconf.impl.util.DeserializerExceptionHandler;
-import org.opendaylight.controller.netconf.util.AbstractChannelInitializer;
+import org.opendaylight.controller.netconf.util.AbstractSslChannelInitializer;
import org.opendaylight.protocol.framework.AbstractDispatcher;
import javax.net.ssl.SSLContext;
public class NetconfServerDispatcher extends AbstractDispatcher<NetconfSession, NetconfServerSessionListener> {
- private final ServerChannelInitializer initializer;
+ private final ServerSslChannelInitializer initializer;
- public NetconfServerDispatcher(final Optional<SSLContext> maybeContext,
- NetconfServerSessionNegotiatorFactory serverNegotiatorFactory,
- NetconfServerSessionListenerFactory listenerFactory) {
- this.initializer = new ServerChannelInitializer(maybeContext, serverNegotiatorFactory, listenerFactory);
+ public NetconfServerDispatcher(ServerSslChannelInitializer serverChannelInitializer, EventLoopGroup bossGroup,
+ EventLoopGroup workerGroup) {
+ super(bossGroup, workerGroup);
+ this.initializer = serverChannelInitializer;
}
- // FIXME change headers for all new source code files
-
// TODO test create server with same address twice
public ChannelFuture createServer(InetSocketAddress address) {
});
}
- private static class ServerChannelInitializer extends AbstractChannelInitializer {
+ public static class ServerSslChannelInitializer extends AbstractSslChannelInitializer {
private final NetconfServerSessionNegotiatorFactory negotiatorFactory;
private final NetconfServerSessionListenerFactory listenerFactory;
- private ServerChannelInitializer(Optional<SSLContext> maybeContext,
- NetconfServerSessionNegotiatorFactory negotiatorFactory,
- NetconfServerSessionListenerFactory listenerFactory) {
+ public ServerSslChannelInitializer(Optional<SSLContext> maybeContext,
+ NetconfServerSessionNegotiatorFactory negotiatorFactory,
+ NetconfServerSessionListenerFactory listenerFactory) {
super(maybeContext);
this.negotiatorFactory = negotiatorFactory;
this.listenerFactory = listenerFactory;
package org.opendaylight.controller.netconf.impl.osgi;
import com.google.common.base.Optional;
+import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.util.HashedWheelTimer;
import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
private NetconfOperationServiceFactoryTracker factoriesTracker;
private DefaultCommitNotificationProducer commitNot;
private NetconfServerDispatcher dispatch;
+ private NioEventLoopGroup eventLoopGroup;
@Override
public void start(final BundleContext context) throws Exception {
NetconfServerSessionListenerFactory listenerFactory = new NetconfServerSessionListenerFactory(
factoriesListener, commitNot, idProvider);
+ eventLoopGroup = new NioEventLoopGroup();
+
if (maybeTCPAddress.isPresent()) {
Optional<SSLContext> maybeSSLContext = Optional.absent();
InetSocketAddress address = maybeTCPAddress.get();
- dispatch = new NetconfServerDispatcher(maybeSSLContext, serverNegotiatorFactory, listenerFactory);
+ NetconfServerDispatcher.ServerSslChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerSslChannelInitializer(
+ maybeSSLContext, serverNegotiatorFactory, listenerFactory);
+ dispatch = new NetconfServerDispatcher(serverChannelInitializer, eventLoopGroup, eventLoopGroup);
logger.info("Starting TCP netconf server at {}", address);
dispatch.createServer(address);
if (maybeTLSConfiguration.isPresent()) {
Optional<SSLContext> maybeSSLContext = Optional.of(maybeTLSConfiguration.get().getSslContext());
InetSocketAddress address = maybeTLSConfiguration.get().getAddress();
- dispatch = new NetconfServerDispatcher(maybeSSLContext, serverNegotiatorFactory, listenerFactory);
+ NetconfServerDispatcher.ServerSslChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerSslChannelInitializer(
+ maybeSSLContext, serverNegotiatorFactory, listenerFactory);
+ dispatch = new NetconfServerDispatcher(serverChannelInitializer, eventLoopGroup, eventLoopGroup);
logger.info("Starting TLS netconf server at {}", address);
dispatch.createServer(address);
logger.info("Shutting down netconf because YangStoreService service was removed");
commitNot.close();
- dispatch.close();
+ eventLoopGroup.shutdownGracefully();
}
}
import com.google.common.base.Optional;
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 org.apache.commons.io.IOUtils;
import org.junit.After;
public class ConcurrentClientsTest {
private static final int CONCURRENCY = 16;
- public static final NetconfClientDispatcher NETCONF_CLIENT_DISPATCHER = new NetconfClientDispatcher(Optional.<SSLContext>absent());
+ private static EventLoopGroup nettyGroup = new NioEventLoopGroup();
+ public static final NetconfClientDispatcher NETCONF_CLIENT_DISPATCHER = new NetconfClientDispatcher(
+ Optional.<SSLContext> absent(), nettyGroup, nettyGroup);
+
@Mock
private YangStoreService yangStoreService;
@Mock
private DefaultCommitNotificationProducer commitNot;
private NetconfServerDispatcher dispatch;
+
@Before
public void setUp() throws Exception {
{ // init mocks
NetconfServerSessionListenerFactory listenerFactory = new NetconfServerSessionListenerFactory(
factoriesListener, commitNot, idProvider);
- dispatch = new NetconfServerDispatcher(Optional.<SSLContext> absent(), serverNegotiatorFactory, listenerFactory);
+ NetconfServerDispatcher.ServerSslChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerSslChannelInitializer(
+ Optional.<SSLContext> absent(), serverNegotiatorFactory, listenerFactory);
+ dispatch = new NetconfServerDispatcher(serverChannelInitializer, nettyGroup, nettyGroup);
ChannelFuture s = dispatch.createServer(netconfAddress);
s.await();
@AfterClass
public static void tearDownStatic() {
- NETCONF_CLIENT_DISPATCHER.close();
+ nettyGroup.shutdownGracefully();
}
private NetconfOperationServiceFactory mockOpF() {
@After
public void cleanUp() throws Exception {
commitNot.close();
- dispatch.close();
}
@Test
package org.opendaylight.controller.netconf.impl;
-import java.lang.management.ManagementFactory;
-import java.net.InetSocketAddress;
-
-import javax.net.ssl.SSLContext;
-
+import com.google.common.base.Optional;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.util.HashedWheelTimer;
+import org.junit.After;
+import org.junit.Before;
import org.junit.Test;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListener;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
-import com.google.common.base.Optional;
-
-import io.netty.channel.ChannelFuture;
-import io.netty.util.HashedWheelTimer;
+import javax.net.ssl.SSLContext;
+import java.lang.management.ManagementFactory;
+import java.net.InetSocketAddress;
public class NetconfDispatcherImplTest {
+ private EventLoopGroup nettyGroup;
+
+ @Before
+ public void setUp() throws Exception {
+ nettyGroup = new NioEventLoopGroup();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ nettyGroup.shutdownGracefully();
+ }
+
@Test
public void test() throws Exception {
NetconfServerSessionListenerFactory listenerFactory = new NetconfServerSessionListenerFactory(
factoriesListener, commitNot, idProvider);
- NetconfServerDispatcher dispatch = new NetconfServerDispatcher(Optional.<SSLContext> absent(),
- serverNegotiatorFactory, listenerFactory);
+ NetconfServerDispatcher.ServerSslChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerSslChannelInitializer(Optional.<SSLContext>absent(), serverNegotiatorFactory, listenerFactory);
+
+
+ NetconfServerDispatcher dispatch = new NetconfServerDispatcher(
+ serverChannelInitializer, nettyGroup, nettyGroup);
InetSocketAddress addr = new InetSocketAddress("127.0.0.1", 8333);
ChannelFuture s = dispatch.createServer(addr);
commitNot.close();
- dispatch.close();
}
}
<artifactId>mockito-configuration</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>commons.logback_settings</artifactId>
+ </dependency>
</dependencies>
<build>
import com.google.common.base.Optional;
import io.netty.channel.ChannelFuture;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.util.HashedWheelTimer;
import org.junit.After;
import org.junit.Before;
private DefaultCommitNotificationProducer commitNot;
private NetconfServerDispatcher dispatchS;
+ private EventLoopGroup nettyThreadgroup;
+
@Before
public void setUp() throws Exception {
commitNot = new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
+ nettyThreadgroup = new NioEventLoopGroup();
+
dispatchS = createDispatcher(Optional.of(getSslContext()), factoriesListener);
ChannelFuture s = dispatchS.createServer(tlsAddress);
s.await();
NetconfServerSessionListenerFactory listenerFactory = new NetconfServerSessionListenerFactory(
factoriesListener, commitNot, idProvider);
- return new NetconfServerDispatcher(sslC, serverNegotiatorFactory, listenerFactory);
+ NetconfServerDispatcher.ServerSslChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerSslChannelInitializer(
+ sslC, serverNegotiatorFactory, listenerFactory);
+ return new NetconfServerDispatcher(serverChannelInitializer, nettyThreadgroup, nettyThreadgroup);
}
@After
public void tearDown() throws Exception {
commitNot.close();
- dispatchS.close();
+ nettyThreadgroup.shutdownGracefully();
}
private SSLContext getSslContext() throws KeyStoreException, NoSuchAlgorithmException, CertificateException,
@Test
public void testSecure() throws Exception {
- try (NetconfClientDispatcher dispatch = new NetconfClientDispatcher(Optional.of(getSslContext()));
- NetconfClient netconfClient = new NetconfClient("tls-client", tlsAddress, 4000, dispatch)) {
+ NetconfClientDispatcher dispatch = new NetconfClientDispatcher(Optional.of(getSslContext()), nettyThreadgroup, nettyThreadgroup);
+ try (NetconfClient netconfClient = new NetconfClient("tls-client", tlsAddress, 4000, dispatch)) {
}
}
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 org.junit.After;
-import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
closeSession, startExi, stopExi;
private DefaultCommitNotificationProducer commitNot;
private NetconfServerDispatcher dispatch;
+ private EventLoopGroup nettyThreadgroup;
- private static NetconfClientDispatcher NETCONF_CLIENT_DISPATCHER = new NetconfClientDispatcher(Optional.<SSLContext>absent());
+ private NetconfClientDispatcher clientDispatcher;
@Before
public void setUp() throws Exception {
NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
factoriesListener.onAddNetconfOperationServiceFactory(new NetconfOperationServiceFactoryImpl(getYangStore()));
+ nettyThreadgroup = new NioEventLoopGroup();
+
commitNot = new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
dispatch = createDispatcher(Optional.<SSLContext> absent(), factoriesListener);
ChannelFuture s = dispatch.createServer(tcpAddress);
s.await();
+
+ clientDispatcher = new NetconfClientDispatcher(Optional.<SSLContext>absent(), nettyThreadgroup, nettyThreadgroup);
}
private NetconfServerDispatcher createDispatcher(Optional<SSLContext> sslC,
NetconfServerSessionListenerFactory listenerFactory = new NetconfServerSessionListenerFactory(
factoriesListener, commitNot, idProvider);
- return new NetconfServerDispatcher(sslC, serverNegotiatorFactory, listenerFactory);
+ NetconfServerDispatcher.ServerSslChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerSslChannelInitializer(
+ sslC, serverNegotiatorFactory, listenerFactory);
+ return new NetconfServerDispatcher(serverChannelInitializer, nettyThreadgroup, nettyThreadgroup);
}
@After
public void tearDown() throws Exception {
commitNot.close();
- dispatch.close();
- }
-
- @AfterClass
- public static void tearDownStatic() {
- NETCONF_CLIENT_DISPATCHER.close();
+ nettyThreadgroup.shutdownGracefully();
}
private void loadMessages() throws IOException, SAXException, ParserConfigurationException {
@Test
public void testNetconfClientDemonstration() throws Exception {
- try (NetconfClient netconfClient = new NetconfClient("client", tcpAddress, 4000, NETCONF_CLIENT_DISPATCHER)) {
+ try (NetconfClient netconfClient = new NetconfClient("client", tcpAddress, 4000, clientDispatcher)) {
Set<String> capabilitiesFromNetconfServer = netconfClient.getCapabilities();
long sessionId = netconfClient.getSessionId();
@Test
public void testTwoSessions() throws Exception {
- try (NetconfClient netconfClient = new NetconfClient("1", tcpAddress, 4000, NETCONF_CLIENT_DISPATCHER)) {
- try (NetconfClient netconfClient2 = new NetconfClient("2", tcpAddress, 4000, NETCONF_CLIENT_DISPATCHER)) {
+ try (NetconfClient netconfClient = new NetconfClient("1", tcpAddress, 4000, clientDispatcher)) {
+ try (NetconfClient netconfClient2 = new NetconfClient("2", tcpAddress, 4000, clientDispatcher)) {
}
}
}
// final InputStream resourceAsStream =
// AbstractListenerTest.class.getResourceAsStream(fileName);
// assertNotNull(resourceAsStream);
- try (NetconfClient netconfClient = new NetconfClient("test", tcpAddress, 5000, NETCONF_CLIENT_DISPATCHER)) {
+ try (NetconfClient netconfClient = new NetconfClient("test", tcpAddress, 5000, clientDispatcher)) {
// IOUtils.copy(resourceAsStream, netconfClient.getStream());
// netconfClient.getOutputStream().write(NetconfMessageFactory.endOfMessage);
// server should not write anything back
}
private NetconfClient createSession(final InetSocketAddress address, final String expected) throws Exception {
- final NetconfClient netconfClient = new NetconfClient("test " + address.toString(), address, 5000, NETCONF_CLIENT_DISPATCHER);
+ final NetconfClient netconfClient = new NetconfClient("test " + address.toString(), address, 5000, clientDispatcher);
assertEquals(expected, Long.toString(netconfClient.getSessionId()));
return netconfClient;
}
package org.opendaylight.controller.netconf.util;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLEngine;
-
-import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.api.NetconfSession;
-import org.opendaylight.controller.netconf.util.handler.FramingMechanismHandlerFactory;
-import org.opendaylight.controller.netconf.util.handler.NetconfMessageAggregator;
-import org.opendaylight.controller.netconf.util.messages.FramingMechanism;
-import org.opendaylight.controller.netconf.util.messages.NetconfMessageFactory;
-import org.opendaylight.protocol.framework.ProtocolHandlerFactory;
-import org.opendaylight.protocol.framework.ProtocolMessageDecoder;
-import org.opendaylight.protocol.framework.ProtocolMessageEncoder;
-
-import com.google.common.base.Optional;
-
-import io.netty.channel.ChannelHandler;
import io.netty.channel.socket.SocketChannel;
-import io.netty.handler.ssl.SslHandler;
import io.netty.util.concurrent.Promise;
+import org.opendaylight.controller.netconf.api.NetconfSession;
public abstract class AbstractChannelInitializer {
- private final Optional<SSLContext> maybeContext;
- private final NetconfHandlerFactory handlerFactory;
-
- public AbstractChannelInitializer(Optional<SSLContext> maybeContext) {
- this.maybeContext = maybeContext;
- this.handlerFactory = new NetconfHandlerFactory(new NetconfMessageFactory());
- }
-
- public void initialize(SocketChannel ch, Promise<? extends NetconfSession> promise) {
- if (maybeContext.isPresent()) {
- initSsl(ch);
- }
-
- ch.pipeline().addLast("aggregator", new NetconfMessageAggregator(FramingMechanism.EOM));
- ch.pipeline().addLast(handlerFactory.getDecoders());
- initializeAfterDecoder(ch, promise);
- ch.pipeline().addLast("frameEncoder", FramingMechanismHandlerFactory.createHandler(FramingMechanism.EOM));
- ch.pipeline().addLast(handlerFactory.getEncoders());
- }
+ public abstract void initialize(SocketChannel ch, Promise<? extends NetconfSession> promise);
protected abstract void initializeAfterDecoder(SocketChannel ch, Promise<? extends NetconfSession> promise);
- private void initSsl(SocketChannel ch) {
- SSLEngine sslEngine = maybeContext.get().createSSLEngine();
- initSslEngine(sslEngine);
- final SslHandler handler = new SslHandler(sslEngine);
- ch.pipeline().addLast("ssl", handler);
- }
-
- protected abstract void initSslEngine(SSLEngine sslEngine);
-
- private static final class NetconfHandlerFactory extends ProtocolHandlerFactory<NetconfMessage> {
-
- public NetconfHandlerFactory(final NetconfMessageFactory msgFactory) {
- super(msgFactory);
- }
-
- @Override
- public ChannelHandler[] getEncoders() {
- return new ChannelHandler[] { new ProtocolMessageEncoder(this.msgFactory) };
- }
-
- @Override
- public ChannelHandler[] getDecoders() {
- return new ChannelHandler[] { new ProtocolMessageDecoder(this.msgFactory) };
- }
- }
}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.netconf.util;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.api.NetconfSession;
+import org.opendaylight.controller.netconf.util.handler.FramingMechanismHandlerFactory;
+import org.opendaylight.controller.netconf.util.handler.NetconfMessageAggregator;
+import org.opendaylight.controller.netconf.util.messages.FramingMechanism;
+import org.opendaylight.controller.netconf.util.messages.NetconfMessageFactory;
+import org.opendaylight.protocol.framework.ProtocolHandlerFactory;
+import org.opendaylight.protocol.framework.ProtocolMessageDecoder;
+import org.opendaylight.protocol.framework.ProtocolMessageEncoder;
+
+import com.google.common.base.Optional;
+
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.handler.ssl.SslHandler;
+import io.netty.util.concurrent.Promise;
+
+public abstract class AbstractSslChannelInitializer extends AbstractChannelInitializer {
+
+ private final Optional<SSLContext> maybeContext;
+ private final NetconfHandlerFactory handlerFactory;
+
+ public AbstractSslChannelInitializer(Optional<SSLContext> maybeContext) {
+ this.maybeContext = maybeContext;
+ this.handlerFactory = new NetconfHandlerFactory(new NetconfMessageFactory());
+ }
+
+ @Override
+ public void initialize(SocketChannel ch, Promise<? extends NetconfSession> promise) {
+ if (maybeContext.isPresent()) {
+ initSsl(ch);
+ }
+
+ ch.pipeline().addLast("aggregator", new NetconfMessageAggregator(FramingMechanism.EOM));
+ ch.pipeline().addLast(handlerFactory.getDecoders());
+ initializeAfterDecoder(ch, promise);
+ ch.pipeline().addLast("frameEncoder", FramingMechanismHandlerFactory.createHandler(FramingMechanism.EOM));
+ ch.pipeline().addLast(handlerFactory.getEncoders());
+ }
+
+ private void initSsl(SocketChannel ch) {
+ SSLEngine sslEngine = maybeContext.get().createSSLEngine();
+ initSslEngine(sslEngine);
+ final SslHandler handler = new SslHandler(sslEngine);
+ ch.pipeline().addLast("ssl", handler);
+ }
+
+ protected abstract void initSslEngine(SSLEngine sslEngine);
+
+ private static final class NetconfHandlerFactory extends ProtocolHandlerFactory<NetconfMessage> {
+
+ public NetconfHandlerFactory(final NetconfMessageFactory msgFactory) {
+ super(msgFactory);
+ }
+
+ @Override
+ public ChannelHandler[] getEncoders() {
+ return new ChannelHandler[] { new ProtocolMessageEncoder(this.msgFactory) };
+ }
+
+ @Override
+ public ChannelHandler[] getDecoders() {
+ return new ChannelHandler[] { new ProtocolMessageDecoder(this.msgFactory) };
+ }
+ }
+}
public static final String RPC_REPLY_KEY = "rpc-reply";
public static final String RPC_ERROR = "rpc-error";
public static final String NAME_KEY = "name";
+ public static final String NOTIFICATION_ELEMENT_NAME = "notification";
+
//
//
public static final String RFC4741_TARGET_NAMESPACE = "urn:ietf:params:xml:ns:netconf:base:1.0";
JSONTokener jt = new JSONTokener(result);
JSONObject json = new JSONObject(jt);
JSONArray subnetConfigs = json.getJSONArray("subnetConfig");
- Assert.assertEquals(subnetConfigs.length(), 0);
+ Assert.assertEquals(subnetConfigs.length(), 1); // should only get the default subnet
// Test GET subnet1 expecting 404
result = getJsonResult(baseURL + "default/subnet/" + name1);
--- /dev/null
+<?xml version="1.0"?>
+<enunciate label="full" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="http://enunciate.codehaus.org/schemas/enunciate-1.26.xsd">
+
+ <services> </services>
+
+ <modules>
+ <!-- Disable doc generation -->
+ <docs disabled="true"/>
+
+ <!-- Disable all the client generation tools -->
+ <basic-app disabled="true" />
+ <c disabled="true" />
+ <csharp disabled="true" />
+ <jaxws-client disabled="true" />
+ <jaxws-ri disabled="true" />
+ <jaxws-support disabled="true" />
+ <obj-c disabled="true" />
+ <ruby disabled="true"/>
+ <php disabled="true"/>
+
+ <!-- enable only the java clients -->
+ <xml disabled="false" />
+ <java-client disabled="false"/>
+ </modules>
+
+ <api-classes>
+ <include pattern="org.opendaylight.controller.**"/>
+ </api-classes>
+
+ <api-import pattern="org.opendaylight.controller.**"/>
+</enunciate>
--- /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.1-SNAPSHOT</version>
+ <relativePath>../../commons/opendaylight</relativePath>
+ </parent>
+ <scm>
+ <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+ <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+ <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:Main</url>
+ <tag>HEAD</tag>
+ </scm>
+
+ <artifactId>northbound.client</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ <packaging>pom</packaging>
+
+ <properties>
+ <docs.output.dir>${project.build.directory}/rest-api-docs</docs.output.dir>
+ <java-client>${project.build.directory}/enunciate/build/java-client/full-client.jar</java-client>
+ <java-client-sources>${project.build.directory}/enunciate/build/java-client/full-client-sources.jar</java-client-sources>
+ <json-client>${project.build.directory}/enunciate/build/java-client/full-json-client.jar</json-client>
+ <json-client-sources>${project.build.directory}/enunciate/build/java-client/full-json-client-sources.jar</json-client-sources>
+ </properties>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.enunciate</groupId>
+ <artifactId>maven-enunciate-plugin</artifactId>
+ <version>${enunciate.version}</version>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <version>1.5</version>
+ <executions>
+ <execution>
+ <phase>install</phase>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <target>
+ <taskdef resource="net/sf/antcontrib/antcontrib.properties"
+ classpathref="maven.plugin.classpath" />
+ <patternset id="rest.paths">
+ <include name="**/target/site/wsdocs/**"/>
+ <exclude name="**/java-client/**"/>
+ </patternset>
+
+ <echo message="======== Assembling enunciate docs ========"/>
+ <!-- cleanup existing generated files -->
+ <delete dir="${docs.output.dir}"/>
+ <delete file="${docs.output.dir}.zip"/>
+ <mkdir dir="${docs.output.dir}"/>
+ <!-- copy enunciate docs to stage -->
+ <copy todir="${docs.output.dir}">
+ <fileset dir="${basedir}/../../..">
+ <patternset refid="rest.paths"/>
+ </fileset>
+ <mapper type="regexp"
+ from="^(.*)/([^/]+)/target/site/wsdocs/(.*)$$"
+ to="\2/\3"/>
+ </copy>
+ <!-- generate index.html -->
+ <!-- append header -->
+ <echo file="${docs.output.dir}/index.html" append="true">
+<![CDATA[
+<html>
+ <head>
+ <title> OpenDaylight REST API Documentation </title>
+ </head>
+ <body>
+ <h2>OpenDaylight REST API Documentation</h2>
+ <p> OpenDaylight supports the following <a href="http://en.wikipedia.org/wiki/Representational_State_Transfer">Representational State Transfer (REST)</a> APIs: </p>
+ <h4>
+]]>
+ </echo>
+ <dirset id="nbset" dir="${docs.output.dir}">
+ <include name="*"/>
+ </dirset>
+ <pathconvert pathsep="&#36;{line.separator}"
+ property="nbs"
+ refid="nbset"/>
+ <echo file="${docs.output.dir}/index.html"
+ append="true"
+ message="${nbs}"/>
+ <replaceregexp file="${docs.output.dir}/index.html"
+ match="^\${docs.output.dir}/(.*)$"
+ replace="&lt;li&gt;&lt;a href=\1/index.html&gt; \1 &lt;/a&gt;&lt;/li&gt;"
+ byline="true"/>
+
+ <!-- append footer -->
+ <echo file="${docs.output.dir}/index.html" append="true">
+<![CDATA[
+ </h4>
+ <i>---</i>
+ </body>
+</html>
+]]>
+ </echo>
+ <!-- archive all the docs excluding whatever is not needed -->
+ <echo message="======== Archiving enunciate docs ========"/>
+ <zip destfile="${docs.output.dir}.zip">
+ <zipfileset dir="${docs.output.dir}"/>
+ </zip>
+
+ <echo message="======== Build successful ========"/>
+ <echo message="REST docs archive: ${docs.output.dir}.zip"/>
+ </target>
+ </configuration>
+ <dependencies>
+ <dependency>
+ <groupId>ant-contrib</groupId>
+ <artifactId>ant-contrib</artifactId>
+ <version>20020829</version>
+ </dependency>
+ </dependencies>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-install-plugin</artifactId>
+ <version>2.5</version>
+ <configuration>
+ <packaging>jar</packaging>
+ <groupId>${project.groupId}</groupId>
+ <version>${project.version}</version>
+ </configuration>
+ <executions>
+ <execution>
+ <!-- skip default install -->
+ <id>default-install</id>
+ <phase>install</phase>
+ <goals>
+ <goal>install</goal>
+ </goals>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </execution>
+ <execution>
+ <!-- install full java client -->
+ <id>install-full-client</id>
+ <phase>install</phase>
+ <goals>
+ <goal>install-file</goal>
+ </goals>
+ <configuration>
+ <artifactId>${project.artifactId}.full-client</artifactId>
+ <file>${java-client}</file>
+ <sources>${java-client-sources}</sources>
+ </configuration>
+ </execution>
+ <execution>
+ <!-- install full java json client -->
+ <id>install-full-json-client</id>
+ <phase>install</phase>
+ <goals>
+ <goal>install-file</goal>
+ </goals>
+ <configuration>
+ <artifactId>${project.artifactId}.full-json-client</artifactId>
+ <file>${json-client}</file>
+ <sources>${json-client-sources}</sources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <version>2.5</version>
+ <configuration>
+ <packaging>jar</packaging>
+ <generatePom>true</generatePom>
+ <groupId>${project.groupId}</groupId>
+ <version>${project.version}</version>
+ <url>${project.distributionManagement.repository.url}</url>
+ </configuration>
+ <executions>
+ <execution>
+ <!-- skip default deploy -->
+ <id>default-deploy</id>
+ <phase>deploy</phase>
+ <goals>
+ <goal>deploy</goal>
+ </goals>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </execution>
+ <execution>
+ <!-- deploy full java client -->
+ <id>deploy-full-client</id>
+ <phase>deploy</phase>
+ <goals>
+ <goal>deploy-file</goal>
+ </goals>
+ <configuration>
+ <artifactId>${project.artifactId}.full-client</artifactId>
+ <file>${java-client}</file>
+ <sources>${java-client-sources}</sources>
+ </configuration>
+ </execution>
+ <execution>
+ <!-- deploy full java json client -->
+ <id>deploy-full-json-client</id>
+ <phase>deploy</phase>
+ <goals>
+ <goal>deploy-file</goal>
+ </goals>
+ <configuration>
+ <artifactId>${project.artifactId}.full-json-client</artifactId>
+ <file>${json-client}</file>
+ <sources>${json-client-sources}</sources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>org.codehaus.enunciate</groupId>
+ <artifactId>enunciate-core-annotations</artifactId>
+ <version>${enunciate.version}</version>
+ </dependency>
+
+ <!-- add dependency on all northbound bundles -->
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>connectionmanager.northbound</artifactId>
+ <version>0.1.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>controllermanager.northbound</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>flowprogrammer.northbound</artifactId>
+ <version>0.4.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>hosttracker.northbound</artifactId>
+ <version>0.4.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>networkconfig.bridgedomain.northbound</artifactId>
+ <version>0.0.2-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>networkconfig.neutron.northbound</artifactId>
+ <version>0.4.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>forwarding.staticrouting.northbound</artifactId>
+ <version>0.4.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>statistics.northbound</artifactId>
+ <version>0.4.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>subnets.northbound</artifactId>
+ <version>0.4.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>switchmanager.northbound</artifactId>
+ <version>0.4.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>topology.northbound</artifactId>
+ <version>0.4.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>usermanager.northbound</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ </dependency>
+ </dependencies>
+</project>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal</artifactId>
- <version>0.5.1-SNAPSHOT</version>
+ <version>0.6.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
throw new AsynchronousCloseException();
}
- inBuffer.flip();
- msgs = factory.parseMessages(inBuffer);
- if (inBuffer.hasRemaining()) {
- inBuffer.compact();
- } else {
+ try {
+ inBuffer.flip();
+ msgs = factory.parseMessages(inBuffer);
+ if (inBuffer.hasRemaining()) {
+ inBuffer.compact();
+ } else {
+ inBuffer.clear();
+ }
+ } catch (Exception e) {
inBuffer.clear();
+ logger.debug("Caught exception: ", e);
}
return msgs;
}
peerNetData.position(), peerNetData.limit());
}
- peerAppData.flip();
- msgs = factory.parseMessages(peerAppData);
- if (peerAppData.hasRemaining()) {
- peerAppData.compact();
- } else {
+ try {
+ peerAppData.flip();
+ msgs = factory.parseMessages(peerAppData);
+ if (peerAppData.hasRemaining()) {
+ peerAppData.compact();
+ } else {
+ peerAppData.clear();
+ }
+ } catch (Exception e) {
peerAppData.clear();
+ logger.debug("Caught exception: ", e);
}
this.socket.register(this.selector, SelectionKey.OP_READ, this);
}
if (msgs == null) {
- logger.info("{} is down", this);
- reportSwitchStateChange(false);
return;
}
for (OFMessage msg : msgs) {
OFType type = msg.getType();
switch (type) {
case HELLO:
- // send feature request
- OFMessage featureRequest = factory.getMessage(OFType.FEATURES_REQUEST);
- asyncFastSend(featureRequest);
- this.state = SwitchState.WAIT_FEATURES_REPLY;
- startSwitchTimer();
+ sendFeaturesRequest();
break;
case ECHO_REQUEST:
OFEchoReply echoReply = (OFEchoReply) factory.getMessage(OFType.ECHO_REPLY);
// respond immediately
asyncSendNow(echoReply, msg.getXid());
+
+ // send features request if not sent yet
+ sendFeaturesRequest();
break;
case ECHO_REPLY:
this.probeSent = false;
return this.sid;
}
+ private void sendFeaturesRequest() {
+ if (!isOperational() && (this.state != SwitchState.WAIT_FEATURES_REPLY)) {
+ // send feature request
+ OFMessage featureRequest = factory.getMessage(OFType.FEATURES_REQUEST);
+ asyncFastSend(featureRequest);
+ this.state = SwitchState.WAIT_FEATURES_REPLY;
+ startSwitchTimer();
+ }
+ }
+
private void processFeaturesReply(OFFeaturesReply reply) {
if (this.state == SwitchState.WAIT_FEATURES_REPLY) {
this.sid = reply.getDatapathId();
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import org.opendaylight.controller.protocol_plugin.openflow.vendorextension.v6extension.V6FlowMod;
import org.opendaylight.controller.protocol_plugin.openflow.vendorextension.v6extension.V6Match;
import org.opendaylight.controller.sal.action.ActionType;
import org.opendaylight.controller.sal.action.Controller;
import org.opendaylight.controller.sal.action.Drop;
+import org.opendaylight.controller.sal.action.Enqueue;
import org.opendaylight.controller.sal.action.Flood;
import org.opendaylight.controller.sal.action.FloodAll;
import org.opendaylight.controller.sal.action.HwPath;
return flow;
}
+ private static final Map<Integer, Class<? extends Action>> actionMap = new HashMap<Integer, Class<? extends Action>>() {
+ private static final long serialVersionUID = 1L;
+ {
+ put(1 << 0, Output.class);
+ put(1 << 1, SetVlanId.class);
+ put(1 << 2, SetVlanPcp.class);
+ put(1 << 3, PopVlan.class);
+ put(1 << 4, SetDlSrc.class);
+ put(1 << 5, SetDlDst.class);
+ put(1 << 6, SetNwSrc.class);
+ put(1 << 7, SetNwDst.class);
+ put(1 << 8, SetNwTos.class);
+ put(1 << 9, SetTpSrc.class);
+ put(1 << 10, SetTpDst.class);
+ put(1 << 11, Enqueue.class);
+ }
+ };
+
+ /**
+ * Returns the supported flow actions for the netwrok node given the bitmask
+ * representing the actions the Openflow 1.0 switch supports
+ *
+ * @param ofActionBitmask
+ * OF 1.0 action bitmask
+ * @return The correspondent list of SAL Action classes
+ */
+ public static List<Class<? extends Action>> getFlowActions(int ofActionBitmask) {
+ List<Class<? extends Action>> list = new ArrayList<Class<? extends Action>>();
+
+ for (int i = 0; i < Integer.SIZE; i++) {
+ int index = 1 << i;
+ if ((index & ofActionBitmask) > 0) {
+ if (actionMap.containsKey(index)) {
+ list.add(actionMap.get(index));
+ }
+ }
+ }
+ // Add implicit SAL actions
+ list.add(Controller.class);
+ list.add(SwPath.class);
+ list.add(HwPath.class);
+ list.add(Drop.class);
+
+ return list;
+ }
+
}
import org.opendaylight.controller.protocol_plugin.openflow.core.IMessageListener;
import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitch;
import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitchStateListener;
+import org.opendaylight.controller.sal.action.SupportedFlowActions;
import org.opendaylight.controller.sal.connection.ConnectionLocality;
import org.opendaylight.controller.sal.connection.IPluginOutConnectionService;
-import org.opendaylight.controller.sal.core.Actions;
import org.opendaylight.controller.sal.core.Buffers;
import org.opendaylight.controller.sal.core.Capabilities;
import org.opendaylight.controller.sal.core.ContainerFlow;
props.add(c);
}
int act = sw.getActions();
- Actions a = new Actions(act);
+ SupportedFlowActions a = new SupportedFlowActions(FlowConverter.getFlowActions(act));
if (a != null) {
props.add(a);
}
--- /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.sal.action;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.opendaylight.controller.sal.core.NodeConnector;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class Enqueue extends Action {
+ private static final long serialVersionUID = 1L;
+ @XmlElement
+ private NodeConnector port;
+
+ /* Dummy constructor for JAXB */
+ @SuppressWarnings("unused")
+ private Enqueue() {
+ }
+
+ public Enqueue(NodeConnector port) {
+ type = ActionType.ENQUEUE;
+ this.port = port;
+ }
+
+ public NodeConnector getPort() {
+ return port;
+ }
+}
--- /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.sal.action;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+
+import org.opendaylight.controller.sal.core.Property;
+
+/**
+ * @file SupportedFlowActions.java
+ *
+ * @brief Class representing the supported flow actions
+ *
+ * Describes the supported flow actions
+ */
+
+@XmlAccessorType(XmlAccessType.NONE)
+public class SupportedFlowActions extends Property {
+ private static final long serialVersionUID = 1L;
+ public static final String SupportedFlowActionsPropName = "supportedFlowActions";
+ private List<Class<? extends Action>> actions;
+
+ private SupportedFlowActions() {
+ super(SupportedFlowActionsPropName);
+ this.actions = new ArrayList<Class<? extends Action>>();
+ }
+
+ public SupportedFlowActions(List<Class<? extends Action>> actions) {
+ super(SupportedFlowActionsPropName);
+ this.actions = new ArrayList<Class<? extends Action>>(actions);
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + ((actions == null) ? 0 : actions.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!super.equals(obj)) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ SupportedFlowActions other = (SupportedFlowActions) obj;
+ if (actions == null) {
+ if (other.actions != null) {
+ return false;
+ }
+ } else if (!actions.equals(other.actions)) {
+ return false;
+ }
+ return true;
+ }
+
+ public List<Class<? extends Action>> getActions() {
+ return new ArrayList<Class<? extends Action>>(this.actions);
+ }
+
+ @XmlElement(name = "value")
+ @Override
+ public String getStringValue() {
+ List<String> nameList = new ArrayList<String>();
+ for (Class<? extends Action> clazz : actions) {
+ nameList.add(clazz.getSimpleName());
+ }
+ Collections.sort(nameList);
+ return nameList.toString();
+ }
+
+ @Override
+ public Property clone() {
+ return new SupportedFlowActions(this.actions);
+ }
+
+ @Override
+ public String toString() {
+ return this.getStringValue();
+ }
+}
* @brief Class representing actions
*
* Describes supported actions
+ * @Deprecated This class is OF 1.0 specific. Use SupportedFlowActions instead.
*/
-
+@Deprecated
@XmlRootElement
@XmlAccessorType(XmlAccessType.NONE)
public class Actions extends Property {
@Override
public boolean equals(Object obj) {
- if (this == obj)
+ if (this == obj) {
return true;
- if (!super.equals(obj))
+ }
+ if (!super.equals(obj)) {
return false;
- if (getClass() != obj.getClass())
+ }
+ if (getClass() != obj.getClass()) {
return false;
+ }
Actions other = (Actions) obj;
- if (actionsValue != other.actionsValue)
+ if (actionsValue != other.actionsValue) {
return false;
+ }
return true;
}
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>commons.logback_settings</artifactId>
+ </dependency>
</dependencies>
</project>
<artifactId>junit</artifactId>
</dependency>
<dependency>
- <groupId>equinoxSDK381</groupId>
- <artifactId>org.apache.felix.gogo.runtime</artifactId>
+ <groupId>equinoxSDK381</groupId>
+ <artifactId>org.apache.felix.gogo.runtime</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>commons.logback_settings</artifactId>
</dependency>
</dependencies>
</project>
private boolean isDefaultContainer = true;
private static final int REPLACE_RETRY = 1;
+ /* Information about the default subnet. If there have been no configured subnets, i.e.,
+ * subnets.size() == 0 or subnetsConfigList.size() == 0, then this subnet will be the
+ * only subnet returned. As soon as a user-configured subnet is created this one will
+ * vanish.
+ */
+ protected static SubnetConfig DEFAULT_SUBNETCONFIG;
+ protected static Subnet DEFAULT_SUBNET;
+ protected static String DEFAULT_SUBNET_NAME = "default (cannot be modifed)";
+ static{
+ DEFAULT_SUBNETCONFIG = new SubnetConfig(DEFAULT_SUBNET_NAME, "0.0.0.0/0", new ArrayList<String>());
+ DEFAULT_SUBNET = new Subnet(DEFAULT_SUBNETCONFIG);
+ }
+
public void notifySubnetChange(Subnet sub, boolean add) {
synchronized (switchManagerAware) {
for (Object subAware : switchManagerAware) {
@Override
public List<SubnetConfig> getSubnetsConfigList() {
- return new ArrayList<SubnetConfig>(subnetsConfigList.values());
+ // if there are no subnets, return the default subnet
+ if(subnetsConfigList.size() == 0){
+ return Collections.singletonList(DEFAULT_SUBNETCONFIG);
+ }else{
+ return new ArrayList<SubnetConfig>(subnetsConfigList.values());
+ }
}
@Override
public SubnetConfig getSubnetConfig(String subnet) {
- return subnetsConfigList.get(subnet);
+ // if there are no subnets, return the default subnet
+ if(subnetsConfigList.size() == 0 && subnet == DEFAULT_SUBNET_NAME){
+ return DEFAULT_SUBNETCONFIG;
+ }else{
+ return subnetsConfigList.get(subnet);
+ }
}
private List<SpanConfig> getSpanConfigList(Node node) {
@Override
public Subnet getSubnetByNetworkAddress(InetAddress networkAddress) {
+ // if there are no subnets, return the default subnet
+ if (subnets.size() == 0) {
+ return DEFAULT_SUBNET;
+ }
+
Subnet sub;
Set<InetAddress> indices = subnets.keySet();
for (InetAddress i : indices) {
+++ /dev/null
-<configuration scan="true">\r
-\r
- <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">\r
- <encoder>\r
- <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n\r
- </pattern>\r
- </encoder>\r
- </appender>\r
-\r
- <root level="error">\r
- <appender-ref ref="STDOUT" />\r
- </root>\r
-</configuration>\r
*/
@RequestMapping(value = "/users", method = RequestMethod.POST)
@ResponseBody
- public String saveLocalUserConfig(@RequestParam(required = true) String json,
+ public Status saveLocalUserConfig(@RequestParam(required = true) String json,
@RequestParam(required = true) String action, HttpServletRequest request) {
IUserManager userManager = (IUserManager) ServiceHelper.getGlobalInstance(IUserManager.class, this);
if (userManager == null) {
- return "Internal Error";
+ return new Status(StatusCode.NOSERVICE, "User Manager unavailable");
}
if (!authorize(userManager, UserLevel.NETWORKADMIN, request)) {
- return "Operation not permitted";
+ return new Status(StatusCode.UNAUTHORIZED, "Operation not permitted");
}
Gson gson = new Gson();
Status result = (action.equals("add")) ? userManager.addLocalUser(config) : userManager.removeLocalUser(config);
if (result.isSuccess()) {
- String userAction = (action.equals("add")) ? "added" : "removed";
if (action.equals("add")) {
- String userRoles = "";
- for (String userRole : config.getRoles()) {
- userRoles = userRoles + userRole + ",";
- }
- DaylightWebUtil.auditlog("User", request.getUserPrincipal().getName(), userAction, config.getUser()
- + " as " + userRoles.substring(0, userRoles.length() - 1));
+ DaylightWebUtil.auditlog("User", request.getUserPrincipal().getName(), "added", config.getUser()
+ + " as " + config.getRoles().toString());
} else {
- DaylightWebUtil.auditlog("User", request.getUserPrincipal().getName(), userAction, config.getUser());
+ DaylightWebUtil.auditlog("User", request.getUserPrincipal().getName(), "removed", config.getUser());
}
- return "Success";
}
- return result.getDescription();
+ return result;
}
+ @RequestMapping(value = "/user/modify", method = RequestMethod.POST)
+ @ResponseBody
+ public Status modifyUser(@RequestParam(required = true) String json,
+ @RequestParam(required = true) String action, HttpServletRequest request) {
+
+ IUserManager userManager = (IUserManager) ServiceHelper.getGlobalInstance(IUserManager.class, this);
+ if (userManager == null) {
+ return new Status(StatusCode.NOSERVICE, "User Manager unavailable");
+ }
+
+ if (!authorize(userManager, UserLevel.NETWORKADMIN, request)) {
+ return new Status(StatusCode.UNAUTHORIZED, "Operation not permitted");
+ }
+
+ UserConfig newConfig = gson.fromJson(json, UserConfig.class);
+ List<UserConfig> currentUserConfig = userManager.getLocalUserList();
+ String password = null;
+ String user = newConfig.getUser();
+ for (UserConfig userConfig : currentUserConfig) {
+ if(userConfig.getUser().equals(user)){
+ password = userConfig.getPassword();
+ break;
+ }
+ }
+ if (password == null) {
+ String msg = String.format("User %s not found in configuration database", user);
+ return new Status(StatusCode.NOTFOUND, msg);
+ }
+
+ //While modifying a user role, the password is not provided from GUI for any user.
+ //The password is stored in hash mode, hence it cannot be retrieved and added to UserConfig object
+ //The hashed password is injected below to the json string containing username and new roles before
+ //converting to UserConfig object.
+ json = json.replace("\"roles\"", "\"password\":\""+ password + "\",\"roles\"");
+ Gson gson = new Gson();
+ newConfig = gson.fromJson(json, UserConfig.class);
+
+ Status result = userManager.modifyLocalUser(newConfig);
+ if (result.isSuccess()) {
+ DaylightWebUtil.auditlog("Roles of", request.getUserPrincipal().getName(), "updated", newConfig.getUser()
+ + " to " + newConfig.getRoles().toString());
+ }
+ return result;
+ }
+
+
@RequestMapping(value = "/users/{username}", method = RequestMethod.POST)
@ResponseBody
- public String removeLocalUser(@PathVariable("username") String userName, HttpServletRequest request) {
+ public Status removeLocalUser(@PathVariable("username") String userName, HttpServletRequest request) {
- String username = request.getUserPrincipal().getName();
- if (username.equals(userName)) {
- return "Invalid Request: User cannot delete itself";
+ String loggedInUser = request.getUserPrincipal().getName();
+ if (loggedInUser.equals(userName)) {
+ String msg = "Invalid Request: User cannot delete itself";
+ return new Status(StatusCode.NOTALLOWED, msg);
}
IUserManager userManager = (IUserManager) ServiceHelper.getGlobalInstance(IUserManager.class, this);
if (userManager == null) {
- return "Internal Error";
+ return new Status(StatusCode.NOSERVICE, "User Manager unavailable");
}
if (!authorize(userManager, UserLevel.NETWORKADMIN, request)) {
- return "Operation not permitted";
+ return new Status(StatusCode.UNAUTHORIZED, "Operation not permitted");
}
- Status result = userManager.removeLocalUser(userName);
- if (result.isSuccess()) {
+ Status status = userManager.removeLocalUser(userName);
+ if (status.isSuccess()) {
DaylightWebUtil.auditlog("User", request.getUserPrincipal().getName(), "removed", userName);
- return "Success";
+ return status;
}
- return result.getDescription();
+ return status;
}
@RequestMapping(value = "/users/password/{username}", method = RequestMethod.POST)
}
if (status.isSuccess()) {
- DaylightWebUtil.auditlog("User", request.getUserPrincipal().getName(), " changed password for User ",
+ DaylightWebUtil.auditlog("User", request.getUserPrincipal().getName(), "changed password for",
username);
}
return status;
close : "one_main_admin_id_modal_remove_close",
password : 'one_main_admin_id_modal_remove_password'
},
+ modify : {
+ user : "one_main_admin_id_modal_modify_user",
+ },
password : {
modal : 'one_main_admin_id_modal_password_modal',
submit : 'one_main_admin_id_modal_password_submit',
add : {
user : "one_main_admin_id_add_user"
}
+ },
+ registry :{
+
},
address : {
root : "/admin",
users : "/users",
+ modifyUser : "/user/modify",
password : '/admin/users/password/'
},
modal : {
$.getJSON(one.main.admin.address.root
+ one.main.admin.address.users, function(data) {
var body = one.main.admin.data.users(data);
+ one.main.admin.registry["users"] = data;
var $body = one.main.admin.body.users(body);
callback($body);
});
remove : {
modal : {
initialize : function(id) {
- var h3 = "Edit User";
+ var h3 = "Manage user - " + id;
var footer = one.main.admin.remove.footer();
var $body = one.main.admin.remove.body();
var $modal = one.lib.modal.spawn(one.main.admin.id.modal.user,
$('#'+one.main.admin.id.modal.remove.close, $modal).click(function() {
$modal.modal('hide');
});
+ // close binding
+ $('#'+one.main.admin.id.modal.modify.user, $modal).click(function() {
+ one.main.admin.add.modal.initialize(id, true);
+ });
// remove binding
$('#' + one.main.admin.id.modal.remove.user, $modal).click(function() {
one.main.admin.remove.modal.ajax(id, function(result) {
- if (result == 'Success') {
+ if (result.description == 'Success') {
$modal.modal('hide');
// body inject
var $admin = $('#'+one.main.admin.id.modal.main);
one.lib.modal.inject.body($admin, $body);
});
} else {
- alert("Failed to remove user: " + result);
+ alert("Failed to remove user: " + result.description);
}
});
});
one.main.admin.id.modal.remove.user, "btn-danger", "");
var $removeButton = one.lib.dashlet.button.button(removeButton);
footer.push($removeButton);
+ var modifyButton = one.lib.dashlet.button.single("Change Role",
+ one.main.admin.id.modal.modify.user, "btn-success", "");
+ var $modifyButton = one.lib.dashlet.button.button(modifyButton);
+ footer.push($modifyButton);
var change = one.lib.dashlet.button.single('Change Password',
one.main.admin.id.modal.remove.password, 'btn-success', '');
var $change = one.lib.dashlet.button.button(change);
},
add : {
modal : {
- initialize : function() {
- var h3 = "Add User";
- var footer = one.main.admin.add.footer();
- var $body = one.main.admin.add.body();
+ initialize : function(id, edit) {
+ var h3 = edit? "Change Role of user " + id:"Add User";
+ var footer = one.main.admin.add.footer(edit);
+ var $body = one.main.admin.add.body(id, edit);
var $modal = one.lib.modal.spawn(one.main.admin.id.modal.user,
h3, $body, footer);
// close binding
});
// add binding
$('#' + one.main.admin.id.modal.add.user, $modal).click(function() {
- one.main.admin.add.modal.add($modal, function(result) {
- if (result == 'Success') {
+ one.main.admin.add.modal.add($modal, edit, function(result) {
+ if (result.description == 'Success') {
$modal.modal('hide');
// body inject
var $admin = $('#'+one.main.admin.id.modal.main);
one.main.admin.ajax.users(function($body) {
- one.lib.modal.inject.body($admin, $body);
+ one.lib.modal.inject.body($admin, $body);
});
} else {
- alert("Failed to add user: "+result);
+ var action = edit? "edit" :"add";
+ alert("Failed to "+ action +" user: "+result.description);
}
});
});
$modal.modal();
},
- add : function($modal, callback) {
+ add : function($modal, edit, callback) {
var user = {};
user['user'] = $modal.find(
'#' + one.main.admin.id.modal.add.form.name).val();
- user['password'] = $modal.find(
- '#' + one.main.admin.id.modal.add.form.password).val();
+ if (!edit) {
+ user['password'] = $modal.find(
+ '#' + one.main.admin.id.modal.add.form.password).val();
+ }
roles = new Array();
roles[0] = $modal.find(
'#' + one.main.admin.id.modal.add.form.role).find(
'option:selected').attr('value');
user['roles'] = roles;
- // password check
- var verify = $('#'+one.main.admin.id.modal.add.form.verify).val();
- if (user.password != verify) {
- alert('Passwords do not match');
- return false;
+ if (!edit) {
+ // password check
+ var verify = $('#'+one.main.admin.id.modal.add.form.verify).val();
+ if (user.password != verify) {
+ alert('Passwords do not match');
+ return false;
+ }
}
-
var resource = {};
resource['json'] = JSON.stringify(user);
resource['action'] = 'add'
- one.main.admin.add.modal.ajax(resource, callback);
+ one.main.admin.add.modal.ajax(resource, edit, callback);
},
- ajax : function(data, callback) {
- $.post(one.main.admin.address.root
- + one.main.admin.address.users, data, function(data) {
- callback(data);
- });
+ ajax : function(data, edit, callback) {
+ if(edit) {
+ $.post(one.main.admin.address.root
+ + one.main.admin.address.modifyUser, data, function(data) {
+ callback(data);
+ });
+ } else {
+ $.post(one.main.admin.address.root
+ + one.main.admin.address.users, data, function(data) {
+ callback(data);
+ });
+ }
}
},
- body : function() {
+ body : function(id, edit) {
var $form = $(document.createElement('form'));
var $fieldset = $(document.createElement('fieldset'));
+ var users = one.main.admin.registry["users"];
+ var currentUser;
+ if(edit) {
+ $(users).each(function(index, val) {
+ if(val.user == id){
+ currentUser = val;
+ }
+ });
+ }
+
// user
var $label = one.lib.form.label('Username');
var $input = one.lib.form.input('Username');
$input.attr('id', one.main.admin.id.modal.add.form.name);
+ if(edit) {
+ $input.attr("disabled",true);
+ $input.val(id);
+ }
$fieldset.append($label).append($input);
- // password
- var $label = one.lib.form.label('Password');
- var $input = one.lib.form.input('Password');
- $input.attr('id', one.main.admin.id.modal.add.form.password);
- $input.attr('type', 'password');
- $fieldset.append($label).append($input);
- // password verify
- var $label = one.lib.form.label('Verify Password');
- var $input = one.lib.form.input('Verify Password');
- $input.attr('id', one.main.admin.id.modal.add.form.verify);
- $input.attr('type', 'password');
- $fieldset.append($label).append($input);
+ if(!edit) {
+ // password
+ var $label = one.lib.form.label('Password');
+ var $input = one.lib.form.input('Password');
+ $input.attr('id', one.main.admin.id.modal.add.form.password);
+ $input.attr('type', 'password');
+ $fieldset.append($label).append($input);
+ // password verify
+ var $label = one.lib.form.label('Verify Password');
+ var $input = one.lib.form.input('Verify Password');
+ $input.attr('id', one.main.admin.id.modal.add.form.verify);
+ $input.attr('type', 'password');
+ $fieldset.append($label).append($input);
+ }
// roles
var $label = one.lib.form.label('Roles');
var options = {
};
var $select = one.lib.form.select.create(options);
$select.attr('id', one.main.admin.id.modal.add.form.role);
+ if(edit) {
+ $select.children().each(function() {
+ this.selected = (this.text == options[currentUser.roles[0]]);
+ });
+ }
+
$fieldset.append($label).append($select);
$form.append($fieldset);
return $form;
},
- footer : function() {
+ footer : function(edit) {
var footer = [];
- var addButton = one.lib.dashlet.button.single("Add User",
+ var buttonText = edit ? "Update User" : "Add User";
+
+ var addButton = one.lib.dashlet.button.single(buttonText,
one.main.admin.id.modal.add.user, "btn-primary", "");
var $addButton = one.lib.dashlet.button.button(addButton);
footer.push($addButton);
});
/** MAIN PAGE LOAD */
-one.main.menu.load();
+one.main.menu.load();
\ No newline at end of file
<module>opendaylight/commons/checkstyle</module>
<module>opendaylight/commons/opendaylight</module>
<module>opendaylight/commons/parent</module>
+ <module>opendaylight/commons/logback_settings</module>
</modules>
<profiles>
<module>opendaylight/distribution/sanitytest/</module>
</modules>
</profile>
+ <profile>
+ <id>docs</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ </activation>
+ <modules>
+ <module>opendaylight/northbound/java-client</module>
+ </modules>
+ </profile>
</profiles>
</project>