--- /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";
+ }
}
<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;
+ }
+}
import java.util.List;
import java.util.Set;
+import javax.activation.UnsupportedDataTypeException;
+
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
import org.opendaylight.yangtools.yang.data.api.Node;
import org.opendaylight.yangtools.yang.data.api.SimpleNode;
public void write(JsonWriter writer, CompositeNode data, DataNodeContainer schema) throws IOException {
writer.beginObject();
- writeChildrenOfParent(writer, data, schema);
+
+ if (schema instanceof ContainerSchemaNode) {
+ writeContainer(writer, (CompositeNode) data, (ContainerSchemaNode) schema);
+ } else if (schema instanceof ListSchemaNode) {
+ writeList(writer, (CompositeNode) data, (ListSchemaNode) schema);
+ } else {
+ throw new UnsupportedDataTypeException(
+ "Schema can be ContainerSchemaNode or ListSchemaNode. Other types are not supported yet.");
+ }
+
writer.endObject();
+
foundLeafLists.clear();
foundLists.clear();
}
for (Node<?> child : parent.getChildren()) {
DataSchemaNode childSchema = findSchemaForNode(child, parentSchema.getChildNodes());
+ if (childSchema == null) {
+ throw new UnsupportedDataTypeException("Probably the data node \"" + child.getNodeType().getLocalName()
+ + "\" is not conform to schema");
+ }
+
if (childSchema instanceof ContainerSchemaNode) {
writeContainer(writer, (CompositeNode) child, (ContainerSchemaNode) childSchema);
} else if (childSchema instanceof ListSchemaNode) {
}
} else if (childSchema instanceof LeafSchemaNode) {
writeLeaf(writer, (SimpleNode<?>) child, (LeafSchemaNode) childSchema);
+ } else {
+ throw new UnsupportedDataTypeException("Schema can be ContainerSchemaNode, ListSchemaNode, "
+ + "LeafListSchemaNode, or LeafSchemaNode. Other types are not supported yet.");
}
}
} else if (type instanceof BooleanTypeDefinition) {
writer.value(Boolean.parseBoolean(value));
} else if (type instanceof EmptyTypeDefinition) {
- writer.value("[null]");
+ writer.beginArray();
+ writer.nullValue();
+ writer.endArray();
} else {
writer.value(value);
}
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);
+ }
+}
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();
}
}
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";