From: Giovanni Meo Date: Thu, 7 Nov 2013 14:10:26 +0000 (+0000) Subject: Merge "Bug:129 Connection Manager Dashlet" X-Git-Tag: jenkins-controller-bulk-release-prepare-only-2-1~468 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=6668a20ff21282576d2d408d9b1ce4cf9ba0c9ac;hp=1020a160c8f41c6993813ca9f4939148b47887fa Merge "Bug:129 Connection Manager Dashlet" --- diff --git a/README.OPENDAYLIGHT b/README.OPENDAYLIGHT index e85aa31b7b..78d54a7e87 100644 --- a/README.OPENDAYLIGHT +++ b/README.OPENDAYLIGHT @@ -21,12 +21,20 @@ HOW TO BUILD ============ In order to build it's required to have JDK 1.7+ and Maven 3+, to get a build going it's needed to: -1) Choose the distribution, from within opendaylight/distribution -2) Go in the directory and run +1) From the root directory run "mvn clean install" -3) On succesfull completion go in the target directory to pick the zip -file of the distribution or controller can be executed right from -there going into the distribution directory. +2) On succesfull completion go in the directory: +"opendaylight/distribution/opendaylight/target" + +to pick the zip file of the distribution or controller can be executed +right from there going into the distribution directory. + +Please note that this way no integration tests but only UT will be +executed, if you are planning on committing code be aware that the +code will be tested also for Integrations tests hence make sure before +submitting a patch to build using the command: + "mvn clean install -Pintegrationtests" +to get IT executed. HOW TO RELEASE ARTIFACTS ======================== diff --git a/opendaylight/commons/checkstyle/src/main/resources/controller/checkstyle.xml b/opendaylight/commons/checkstyle/src/main/resources/controller/checkstyle.xml index c810d6523a..57f169db73 100644 --- a/opendaylight/commons/checkstyle/src/main/resources/controller/checkstyle.xml +++ b/opendaylight/commons/checkstyle/src/main/resources/controller/checkstyle.xml @@ -18,6 +18,7 @@ + diff --git a/opendaylight/config/pom.xml b/opendaylight/config/pom.xml index 949c283f7d..9db5b76988 100755 --- a/opendaylight/config/pom.xml +++ b/opendaylight/config/pom.xml @@ -25,12 +25,26 @@ config-persister-file-adapter yang-jmx-generator yang-jmx-generator-plugin - yang-jmx-generator-it yang-store-api yang-store-impl yang-test logback-config + threadpool-config-api + threadpool-config-impl + + + + integrationtests + + false + + + yang-jmx-generator-it + + + + UTF-8 1.7 diff --git a/opendaylight/config/threadpool-config-api/pom.xml b/opendaylight/config/threadpool-config-api/pom.xml new file mode 100644 index 0000000000..b991b69213 --- /dev/null +++ b/opendaylight/config/threadpool-config-api/pom.xml @@ -0,0 +1,51 @@ + + + org.opendaylight.controller + config-subsystem + 0.2.2-SNAPSHOT + + 4.0.0 + threadpool-config-api + ${project.artifactId} + bundle + + 3.0.4 + + + + + org.opendaylight.controller + config-api + + + com.google.guava + guava + + + + + + + org.apache.felix + maven-bundle-plugin + + + + org.opendaylight.controller.config.api.*, + com.google.common.eventbus, + + + org.opendaylight.controller.config.threadpool, + org.opendaylight.controller.config.yang.threadpool + + + + + + org.opendaylight.yangtools + yang-maven-plugin + + + + \ No newline at end of file diff --git a/opendaylight/config/threadpool-config-api/src/main/java/org/opendaylight/controller/config/threadpool/ScheduledThreadPool.java b/opendaylight/config/threadpool-config-api/src/main/java/org/opendaylight/controller/config/threadpool/ScheduledThreadPool.java new file mode 100644 index 0000000000..bf6c016d35 --- /dev/null +++ b/opendaylight/config/threadpool-config-api/src/main/java/org/opendaylight/controller/config/threadpool/ScheduledThreadPool.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.config.threadpool; + +import java.util.concurrent.ScheduledExecutorService; + +/** + * Interface representing scheduled {@link ThreadPool}. + */ +public interface ScheduledThreadPool extends ThreadPool { + + @Override + public ScheduledExecutorService getExecutor(); +} \ No newline at end of file diff --git a/opendaylight/config/threadpool-config-api/src/main/java/org/opendaylight/controller/config/threadpool/ThreadPool.java b/opendaylight/config/threadpool-config-api/src/main/java/org/opendaylight/controller/config/threadpool/ThreadPool.java new file mode 100644 index 0000000000..701b0bcdf8 --- /dev/null +++ b/opendaylight/config/threadpool-config-api/src/main/java/org/opendaylight/controller/config/threadpool/ThreadPool.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.config.threadpool; + +import java.util.concurrent.ExecutorService; + +/** + * Interface representing thread pool. + */ +public interface ThreadPool { + + public ExecutorService getExecutor(); + + public int getMaxThreadCount(); +} \ No newline at end of file diff --git a/opendaylight/config/threadpool-config-api/src/main/yang/threadpool.yang b/opendaylight/config/threadpool-config-api/src/main/yang/threadpool.yang new file mode 100644 index 0000000000..14a20fdebc --- /dev/null +++ b/opendaylight/config/threadpool-config-api/src/main/yang/threadpool.yang @@ -0,0 +1,77 @@ +// vi: set smarttab et sw=4 tabstop=4: +module threadpool { + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:controller:threadpool"; + prefix "th"; + + import config { prefix config; revision-date 2013-04-05; } + + organization "Cisco Systems, Inc."; + + contact "Robert Varga "; + + description + "This module contains the base YANG definitions for + 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-04-09" { + description + "Added eventbus service."; + } + + revision "2013-04-05" { + description + "Updated with YANG extension for Java class specification."; + } + + revision "2013-04-03" { + description + "Initial revision by Anton Tkacik, Tomas Olvecky and + Robert Varga."; + } + + identity eventbus { + description + "Service representing an event bus. The service acts as message + router between event producers and event consumers"; + + base "config:service-type"; + config:java-class "com.google.common.eventbus.EventBus"; + } + + identity threadfactory { + description + "Service representing a ThreadFactory instance. It is directly + useful in Java world, where various library pieces need to create + threads and you may want to inject a customized thread + implementation."; + + base "config:service-type"; + config:java-class "java.util.concurrent.ThreadFactory"; + } + + identity threadpool { + description + "A simple pool of threads able to execute work."; + + base "config:service-type"; + config:java-class "org.opendaylight.controller.config.threadpool.ThreadPool"; + } + + identity scheduled-threadpool { + description + "An extension of the simple pool of threads able to schedule + work to be executed at some point in time."; + + base "threadpool"; + config:java-class "org.opendaylight.controller.config.threadpool.ScheduledThreadPool"; + } + +} diff --git a/opendaylight/config/threadpool-config-impl/pom.xml b/opendaylight/config/threadpool-config-impl/pom.xml new file mode 100644 index 0000000000..12279781a2 --- /dev/null +++ b/opendaylight/config/threadpool-config-impl/pom.xml @@ -0,0 +1,76 @@ + + + org.opendaylight.controller + config-subsystem + 0.2.2-SNAPSHOT + + 4.0.0 + threadpool-config-impl + ${project.artifactId} + bundle + + 3.0.4 + + + + + ${project.groupId} + config-api + + + ${project.groupId} + threadpool-config-api + ${project.version} + + + com.google.guava + guava + + + org.slf4j + slf4j-api + + + + + + + org.apache.felix + maven-bundle-plugin + + + + org.opendaylight.controller.config.threadpool.util, + javax.annotation.*, + org.opendaylight.controller.config.yang.threadpool.impl, + + + org.opendaylight.controller.config.api.*, + org.opendaylight.controller.config.spi.*, + org.opendaylight.controller.config.threadpool, + org.opendaylight.controller.config.yang.threadpool, + javax.management, + org.osgi.framework, + org.slf4j, + com.google.common.* + + + org.opendaylight.controller.config.threadpool.util + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + org.opendaylight.yangtools + yang-maven-plugin + + + + + \ No newline at end of file diff --git a/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/threadpool/util/CloseableAsyncEventBus.java b/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/threadpool/util/CloseableAsyncEventBus.java new file mode 100644 index 0000000000..93a08daa5d --- /dev/null +++ b/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/threadpool/util/CloseableAsyncEventBus.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.config.threadpool.util; + +import com.google.common.eventbus.AsyncEventBus; +import com.google.common.eventbus.DeadEvent; +import com.google.common.eventbus.Subscribe; + +import java.io.Closeable; +import java.io.IOException; + +import org.opendaylight.controller.config.threadpool.ThreadPool; +import org.opendaylight.controller.config.yang.threadpool.impl.AsyncEventBusRuntimeMXBean; +import org.opendaylight.controller.config.yang.threadpool.impl.AsyncEventBusRuntimeRegistration; +import org.opendaylight.controller.config.yang.threadpool.impl.AsyncEventBusRuntimeRegistrator; + +/** + * Closeable version of {@link AsyncEventBus}. + */ +public class CloseableAsyncEventBus extends AsyncEventBus implements Closeable { + private final ThreadPool threadPool; + private final AsyncEventBusRuntimeRegistration rootRegistration; + + public CloseableAsyncEventBus(String identifier, ThreadPool threadPool, + AsyncEventBusRuntimeRegistrator rootRegistrator) { + super(identifier, threadPool.getExecutor()); + this.threadPool = threadPool; + rootRegistration = rootRegistrator.register(new AsyncEventBusRuntimeMXBean() { + private long deadEventsCounter = 0; + + @Subscribe + public void increaseDeadEvents(DeadEvent deadEvent) { + deadEventsCounter++; + } + + @Override + public Long countDeadEvents() { + return deadEventsCounter; + } + + }); + } + + public ThreadPool getThreadPool() { + return threadPool; + } + + @Override + public void close() throws IOException { + rootRegistration.close(); + } + +} diff --git a/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/threadpool/util/CloseableEventBus.java b/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/threadpool/util/CloseableEventBus.java new file mode 100644 index 0000000000..b6dd77dbf3 --- /dev/null +++ b/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/threadpool/util/CloseableEventBus.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.config.threadpool.util; + +import java.io.Closeable; + +import org.opendaylight.controller.config.yang.threadpool.impl.EventBusRuntimeMXBean; +import org.opendaylight.controller.config.yang.threadpool.impl.EventBusRuntimeRegistration; +import org.opendaylight.controller.config.yang.threadpool.impl.EventBusRuntimeRegistrator; + +import com.google.common.eventbus.DeadEvent; +import com.google.common.eventbus.EventBus; +import com.google.common.eventbus.Subscribe; + +/** + * Closeable {@link EventBus}. + */ +public class CloseableEventBus extends EventBus implements Closeable { + + private final EventBusRuntimeRegistration rootRegistration; + + public CloseableEventBus(String identifier, EventBusRuntimeRegistrator rootRegistrator) { + super(identifier); + rootRegistration = rootRegistrator.register(new EventBusRuntimeMXBean() { + private long deadEventsCounter = 0; + + @Subscribe + public void increaseDeadEvents(DeadEvent deadEvent) { + deadEventsCounter++; + } + + @Override + public Long countDeadEvents() { + return deadEventsCounter; + } + }); + + } + + @Override + public void close() { + rootRegistration.close(); + + } +} diff --git a/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/threadpool/util/FixedThreadPoolWrapper.java b/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/threadpool/util/FixedThreadPoolWrapper.java new file mode 100644 index 0000000000..ca034434d5 --- /dev/null +++ b/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/threadpool/util/FixedThreadPoolWrapper.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.config.threadpool.util; + +import java.io.Closeable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; + +import org.opendaylight.controller.config.threadpool.ThreadPool; + +/** + * Implementation of {@link ThreadPool} using fixed number of threads wraps + * {@link ExecutorService}. + */ +public class FixedThreadPoolWrapper implements ThreadPool, Closeable { + + private final ThreadPoolExecutor executor; + + public FixedThreadPoolWrapper(int threadCount, ThreadFactory factory) { + this.executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(threadCount, factory); + executor.prestartAllCoreThreads(); + } + + @Override + public ExecutorService getExecutor() { + return Executors.unconfigurableExecutorService(executor); + } + + @Override + public void close() { + executor.shutdown(); + } + + @Override + public int getMaxThreadCount() { + return executor.getMaximumPoolSize(); + } + + public void setMaxThreadCount(int maxThreadCount) { + executor.setCorePoolSize(maxThreadCount); + executor.setMaximumPoolSize(maxThreadCount); + } +} diff --git a/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/threadpool/util/FlexibleThreadPoolWrapper.java b/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/threadpool/util/FlexibleThreadPoolWrapper.java new file mode 100644 index 0000000000..3dfa6e2bc7 --- /dev/null +++ b/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/threadpool/util/FlexibleThreadPoolWrapper.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.config.threadpool.util; + +import java.io.Closeable; +import java.io.IOException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import org.opendaylight.controller.config.threadpool.ThreadPool; + +/** + * Implementation of {@link ThreadPool} using flexible number of threads wraps + * {@link ExecutorService}. + */ +public class FlexibleThreadPoolWrapper implements ThreadPool, Closeable { + private final ThreadPoolExecutor executor; + + public FlexibleThreadPoolWrapper(int minThreadCount, int maxThreadCount, long keepAlive, TimeUnit timeUnit, + ThreadFactory threadFactory) { + + executor = new ThreadPoolExecutor(minThreadCount, maxThreadCount, keepAlive, timeUnit, + new SynchronousQueue(), threadFactory); + executor.prestartAllCoreThreads(); + } + + @Override + public ExecutorService getExecutor() { + return Executors.unconfigurableExecutorService(executor); + } + + public int getMinThreadCount() { + return executor.getCorePoolSize(); + } + + public void setMinThreadCount(int minThreadCount) { + executor.setCorePoolSize(minThreadCount); + } + + @Override + public int getMaxThreadCount() { + return executor.getMaximumPoolSize(); + } + + public void setMaxThreadCount(int maxThreadCount) { + executor.setMaximumPoolSize(maxThreadCount); + } + + public long getKeepAliveMillis() { + return executor.getKeepAliveTime(TimeUnit.MILLISECONDS); + } + + public void setKeepAliveMillis(long keepAliveMillis) { + executor.setKeepAliveTime(keepAliveMillis, TimeUnit.MILLISECONDS); + } + + public void setThreadFactory(ThreadFactory threadFactory) { + executor.setThreadFactory(threadFactory); + } + + public void prestartAllCoreThreads() { + executor.prestartAllCoreThreads(); + } + + @Override + public void close() throws IOException { + executor.shutdown(); + } + +} diff --git a/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/threadpool/util/NamingThreadPoolFactory.java b/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/threadpool/util/NamingThreadPoolFactory.java new file mode 100644 index 0000000000..2e27d6cce8 --- /dev/null +++ b/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/threadpool/util/NamingThreadPoolFactory.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.config.threadpool.util; + +import java.io.Closeable; +import java.io.IOException; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicLong; + +import javax.annotation.concurrent.ThreadSafe; + +import com.google.common.base.Preconditions; + +/** + * Implementation of {@link ThreadFactory}. + */ +@ThreadSafe +public class NamingThreadPoolFactory implements ThreadFactory, Closeable { + + private final ThreadGroup group; + private final String namePrefix; + private final AtomicLong threadName = new AtomicLong(); + + public NamingThreadPoolFactory(String namePrefix) { + Preconditions.checkNotNull(namePrefix); + this.group = new ThreadGroup(namePrefix); + this.namePrefix = namePrefix; + } + + @Override + public Thread newThread(Runnable r) { + return new Thread(group, r, String.format("%s-%d", group.getName(), threadName.incrementAndGet())); + } + + @Override + public void close() throws IOException { + } + + public String getNamePrefix() { + return namePrefix; + } + +} diff --git a/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/threadpool/util/ScheduledThreadPoolWrapper.java b/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/threadpool/util/ScheduledThreadPoolWrapper.java new file mode 100644 index 0000000000..ee3399e1b2 --- /dev/null +++ b/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/threadpool/util/ScheduledThreadPoolWrapper.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.config.threadpool.util; + +import java.io.Closeable; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadFactory; + +import org.opendaylight.controller.config.threadpool.ScheduledThreadPool; + +/** + * Implementation of {@link ScheduledThreadPool} wraps + * {@link ScheduledExecutorService}. + */ +public class ScheduledThreadPoolWrapper implements ScheduledThreadPool, Closeable { + + private final ScheduledThreadPoolExecutor executor; + private final int threadCount; + + public ScheduledThreadPoolWrapper(int threadCount, ThreadFactory factory) { + this.threadCount = threadCount; + this.executor = new ScheduledThreadPoolExecutor(threadCount, factory); + executor.prestartAllCoreThreads(); + } + + @Override + public ScheduledExecutorService getExecutor() { + return Executors.unconfigurableScheduledExecutorService(executor); + } + + @Override + public void close() { + executor.shutdown(); + } + + @Override + public int getMaxThreadCount() { + return threadCount; + } + +} diff --git a/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/yang/threadpool/impl/AsyncEventBusModule.java b/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/yang/threadpool/impl/AsyncEventBusModule.java new file mode 100644 index 0000000000..f108303165 --- /dev/null +++ b/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/yang/threadpool/impl/AsyncEventBusModule.java @@ -0,0 +1,42 @@ +/** + * Generated file + + * Generated from: yang module name: threadpool-impl yang module local name: async-eventbus + * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator + * Generated at: Tue Nov 05 15:40:46 CET 2013 + * + * Do not modify this file unless it is present under src/main directory + */ +package org.opendaylight.controller.config.yang.threadpool.impl; + +import org.opendaylight.controller.config.threadpool.util.CloseableAsyncEventBus; + +/** +* +*/ +public final class AsyncEventBusModule extends + org.opendaylight.controller.config.yang.threadpool.impl.AbstractAsyncEventBusModule { + + public AsyncEventBusModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, + org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + super(identifier, dependencyResolver); + } + + public AsyncEventBusModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, + org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, + AsyncEventBusModule 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 CloseableAsyncEventBus(getIdentifier().toString(), getThreadpoolDependency(), + getRootRuntimeBeanRegistratorWrapper()); + } +} diff --git a/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/yang/threadpool/impl/AsyncEventBusModuleFactory.java b/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/yang/threadpool/impl/AsyncEventBusModuleFactory.java new file mode 100644 index 0000000000..14fcf41758 --- /dev/null +++ b/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/yang/threadpool/impl/AsyncEventBusModuleFactory.java @@ -0,0 +1,18 @@ +/** + * Generated file + + * Generated from: yang module name: threadpool-impl yang module local name: async-eventbus + * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator + * Generated at: Tue Nov 05 15:40:46 CET 2013 + * + * Do not modify this file unless it is present under src/main directory + */ +package org.opendaylight.controller.config.yang.threadpool.impl; + +/** +* +*/ +public class AsyncEventBusModuleFactory extends + org.opendaylight.controller.config.yang.threadpool.impl.AbstractAsyncEventBusModuleFactory { + +} diff --git a/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/yang/threadpool/impl/EventBusModule.java b/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/yang/threadpool/impl/EventBusModule.java new file mode 100644 index 0000000000..92eaee5ef2 --- /dev/null +++ b/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/yang/threadpool/impl/EventBusModule.java @@ -0,0 +1,41 @@ +/** + * Generated file + + * Generated from: yang module name: threadpool-impl yang module local name: eventbus + * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator + * Generated at: Tue Nov 05 15:40:46 CET 2013 + * + * Do not modify this file unless it is present under src/main directory + */ +package org.opendaylight.controller.config.yang.threadpool.impl; + +import org.opendaylight.controller.config.threadpool.util.CloseableEventBus; + +/** +* +*/ +public final class EventBusModule extends + org.opendaylight.controller.config.yang.threadpool.impl.AbstractEventBusModule { + + public EventBusModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, + org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + super(identifier, dependencyResolver); + } + + public EventBusModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, + org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, EventBusModule 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 CloseableEventBus(getIdentifier().toString(), getRootRuntimeBeanRegistratorWrapper()); + } +} diff --git a/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/yang/threadpool/impl/EventBusModuleFactory.java b/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/yang/threadpool/impl/EventBusModuleFactory.java new file mode 100644 index 0000000000..e909998a72 --- /dev/null +++ b/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/yang/threadpool/impl/EventBusModuleFactory.java @@ -0,0 +1,18 @@ +/** + * Generated file + + * Generated from: yang module name: threadpool-impl yang module local name: eventbus + * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator + * Generated at: Tue Nov 05 15:40:46 CET 2013 + * + * Do not modify this file unless it is present under src/main directory + */ +package org.opendaylight.controller.config.yang.threadpool.impl; + +/** +* +*/ +public class EventBusModuleFactory extends + org.opendaylight.controller.config.yang.threadpool.impl.AbstractEventBusModuleFactory { + +} diff --git a/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/yang/threadpool/impl/FixedThreadPoolModule.java b/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/yang/threadpool/impl/FixedThreadPoolModule.java new file mode 100644 index 0000000000..a0a9addf03 --- /dev/null +++ b/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/yang/threadpool/impl/FixedThreadPoolModule.java @@ -0,0 +1,45 @@ +/** + * Generated file + + * Generated from: yang module name: threadpool-impl yang module local name: threadpool-fixed + * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator + * Generated at: Wed Nov 06 16:19:33 CET 2013 + * + * Do not modify this file unless it is present under src/main directory + */ +package org.opendaylight.controller.config.yang.threadpool.impl; + +import org.opendaylight.controller.config.api.JmxAttributeValidationException; +import org.opendaylight.controller.config.threadpool.util.FixedThreadPoolWrapper; + +/** +* +*/ +public final class FixedThreadPoolModule extends + org.opendaylight.controller.config.yang.threadpool.impl.AbstractFixedThreadPoolModule { + + public FixedThreadPoolModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, + org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + super(identifier, dependencyResolver); + } + + public FixedThreadPoolModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, + org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, + FixedThreadPoolModule oldModule, java.lang.AutoCloseable oldInstance) { + super(identifier, dependencyResolver, oldModule, oldInstance); + } + + @Override + public void validate() { + super.validate(); + + JmxAttributeValidationException.checkNotNull(getMaxThreadCount(), maxThreadCountJmxAttribute); + JmxAttributeValidationException.checkCondition(getMaxThreadCount() > 0, "must be greater than zero", + maxThreadCountJmxAttribute); + } + + @Override + public java.lang.AutoCloseable createInstance() { + return new FixedThreadPoolWrapper(getMaxThreadCount(), getThreadFactoryDependency()); + } +} diff --git a/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/yang/threadpool/impl/FixedThreadPoolModuleFactory.java b/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/yang/threadpool/impl/FixedThreadPoolModuleFactory.java new file mode 100644 index 0000000000..2803448fd2 --- /dev/null +++ b/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/yang/threadpool/impl/FixedThreadPoolModuleFactory.java @@ -0,0 +1,18 @@ +/** + * Generated file + + * Generated from: yang module name: threadpool-impl yang module local name: threadpool-fixed + * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator + * Generated at: Wed Nov 06 16:19:33 CET 2013 + * + * Do not modify this file unless it is present under src/main directory + */ +package org.opendaylight.controller.config.yang.threadpool.impl; + +/** +* +*/ +public class FixedThreadPoolModuleFactory extends + org.opendaylight.controller.config.yang.threadpool.impl.AbstractFixedThreadPoolModuleFactory { + +} diff --git a/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/yang/threadpool/impl/FlexibleThreadPoolModule.java b/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/yang/threadpool/impl/FlexibleThreadPoolModule.java new file mode 100644 index 0000000000..47b4eec689 --- /dev/null +++ b/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/yang/threadpool/impl/FlexibleThreadPoolModule.java @@ -0,0 +1,55 @@ +/** + * Generated file + + * Generated from: yang module name: threadpool-impl yang module local name: threadpool-flexible + * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator + * Generated at: Wed Nov 06 16:19:33 CET 2013 + * + * Do not modify this file unless it is present under src/main directory + */ +package org.opendaylight.controller.config.yang.threadpool.impl; + +import java.util.concurrent.TimeUnit; + +import org.opendaylight.controller.config.api.JmxAttributeValidationException; +import org.opendaylight.controller.config.threadpool.util.FlexibleThreadPoolWrapper; + +/** +* +*/ +public final class FlexibleThreadPoolModule extends + org.opendaylight.controller.config.yang.threadpool.impl.AbstractFlexibleThreadPoolModule { + + public FlexibleThreadPoolModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, + org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + super(identifier, dependencyResolver); + } + + public FlexibleThreadPoolModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, + org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, + FlexibleThreadPoolModule oldModule, java.lang.AutoCloseable oldInstance) { + super(identifier, dependencyResolver, oldModule, oldInstance); + } + + @Override + public void validate() { + super.validate(); + JmxAttributeValidationException.checkNotNull(getKeepAliveMillis(), keepAliveMillisJmxAttribute); + JmxAttributeValidationException.checkCondition(getKeepAliveMillis() > 0, "must be greater than zero", + keepAliveMillisJmxAttribute); + + JmxAttributeValidationException.checkNotNull(getMinThreadCount(), minThreadCountJmxAttribute); + JmxAttributeValidationException.checkCondition(getMinThreadCount() > 0, "must be greater than zero", + minThreadCountJmxAttribute); + + JmxAttributeValidationException.checkNotNull(getMaxThreadCount(), maxThreadCountJmxAttribute); + JmxAttributeValidationException.checkCondition(getMaxThreadCount() > 0, "must be greater than zero", + maxThreadCountJmxAttribute); + } + + @Override + public java.lang.AutoCloseable createInstance() { + return new FlexibleThreadPoolWrapper(getMinThreadCount(), getMaxThreadCount(), getKeepAliveMillis(), + TimeUnit.MILLISECONDS, getThreadFactoryDependency()); + } +} diff --git a/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/yang/threadpool/impl/FlexibleThreadPoolModuleFactory.java b/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/yang/threadpool/impl/FlexibleThreadPoolModuleFactory.java new file mode 100644 index 0000000000..ef6ebd25e2 --- /dev/null +++ b/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/yang/threadpool/impl/FlexibleThreadPoolModuleFactory.java @@ -0,0 +1,18 @@ +/** + * Generated file + + * Generated from: yang module name: threadpool-impl yang module local name: threadpool-flexible + * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator + * Generated at: Wed Nov 06 16:19:33 CET 2013 + * + * Do not modify this file unless it is present under src/main directory + */ +package org.opendaylight.controller.config.yang.threadpool.impl; + +/** +* +*/ +public class FlexibleThreadPoolModuleFactory extends + org.opendaylight.controller.config.yang.threadpool.impl.AbstractFlexibleThreadPoolModuleFactory { + +} diff --git a/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/yang/threadpool/impl/NamingThreadFactoryModule.java b/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/yang/threadpool/impl/NamingThreadFactoryModule.java new file mode 100644 index 0000000000..a761727e5c --- /dev/null +++ b/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/yang/threadpool/impl/NamingThreadFactoryModule.java @@ -0,0 +1,42 @@ +/** + * Generated file + + * Generated from: yang module name: threadpool-impl yang module local name: threadfactory-naming + * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator + * Generated at: Wed Nov 06 16:19:33 CET 2013 + * + * Do not modify this file unless it is present under src/main directory + */ +package org.opendaylight.controller.config.yang.threadpool.impl; + +import org.opendaylight.controller.config.api.JmxAttributeValidationException; +import org.opendaylight.controller.config.threadpool.util.NamingThreadPoolFactory; + +/** +* +*/ +public final class NamingThreadFactoryModule extends + org.opendaylight.controller.config.yang.threadpool.impl.AbstractNamingThreadFactoryModule { + + public NamingThreadFactoryModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, + org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + super(identifier, dependencyResolver); + } + + public NamingThreadFactoryModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, + org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, + NamingThreadFactoryModule oldModule, java.lang.AutoCloseable oldInstance) { + super(identifier, dependencyResolver, oldModule, oldInstance); + } + + @Override + public void validate() { + super.validate(); + JmxAttributeValidationException.checkNotNull(getNamePrefix(), namePrefixJmxAttribute); + } + + @Override + public java.lang.AutoCloseable createInstance() { + return new NamingThreadPoolFactory(getNamePrefix()); + } +} diff --git a/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/yang/threadpool/impl/NamingThreadFactoryModuleFactory.java b/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/yang/threadpool/impl/NamingThreadFactoryModuleFactory.java new file mode 100644 index 0000000000..5e70afb93e --- /dev/null +++ b/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/yang/threadpool/impl/NamingThreadFactoryModuleFactory.java @@ -0,0 +1,18 @@ +/** + * Generated file + + * Generated from: yang module name: threadpool-impl yang module local name: threadfactory-naming + * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator + * Generated at: Wed Nov 06 16:19:33 CET 2013 + * + * Do not modify this file unless it is present under src/main directory + */ +package org.opendaylight.controller.config.yang.threadpool.impl; + +/** +* +*/ +public class NamingThreadFactoryModuleFactory extends + org.opendaylight.controller.config.yang.threadpool.impl.AbstractNamingThreadFactoryModuleFactory { + +} diff --git a/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/yang/threadpool/impl/ScheduledThreadPoolModule.java b/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/yang/threadpool/impl/ScheduledThreadPoolModule.java new file mode 100644 index 0000000000..42739b4b32 --- /dev/null +++ b/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/yang/threadpool/impl/ScheduledThreadPoolModule.java @@ -0,0 +1,44 @@ +/** + * Generated file + + * Generated from: yang module name: threadpool-impl yang module local name: threadpool-scheduled + * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator + * Generated at: Wed Nov 06 16:19:33 CET 2013 + * + * Do not modify this file unless it is present under src/main directory + */ +package org.opendaylight.controller.config.yang.threadpool.impl; + +import org.opendaylight.controller.config.api.JmxAttributeValidationException; +import org.opendaylight.controller.config.threadpool.util.ScheduledThreadPoolWrapper; + +/** +* +*/ +public final class ScheduledThreadPoolModule extends + org.opendaylight.controller.config.yang.threadpool.impl.AbstractScheduledThreadPoolModule { + + public ScheduledThreadPoolModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, + org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + super(identifier, dependencyResolver); + } + + public ScheduledThreadPoolModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, + org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, + ScheduledThreadPoolModule oldModule, java.lang.AutoCloseable oldInstance) { + super(identifier, dependencyResolver, oldModule, oldInstance); + } + + @Override + public void validate() { + super.validate(); + JmxAttributeValidationException.checkNotNull(getMaxThreadCount(), maxThreadCountJmxAttribute); + JmxAttributeValidationException.checkCondition(getMaxThreadCount() > 0, "must be greater than zero", + maxThreadCountJmxAttribute); + } + + @Override + public java.lang.AutoCloseable createInstance() { + return new ScheduledThreadPoolWrapper(getMaxThreadCount(), getThreadFactoryDependency()); + } +} diff --git a/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/yang/threadpool/impl/ScheduledThreadPoolModuleFactory.java b/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/yang/threadpool/impl/ScheduledThreadPoolModuleFactory.java new file mode 100644 index 0000000000..489af822e2 --- /dev/null +++ b/opendaylight/config/threadpool-config-impl/src/main/java/org/opendaylight/controller/config/yang/threadpool/impl/ScheduledThreadPoolModuleFactory.java @@ -0,0 +1,18 @@ +/** + * Generated file + + * Generated from: yang module name: threadpool-impl yang module local name: threadpool-scheduled + * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator + * Generated at: Wed Nov 06 16:19:33 CET 2013 + * + * Do not modify this file unless it is present under src/main directory + */ +package org.opendaylight.controller.config.yang.threadpool.impl; + +/** +* +*/ +public class ScheduledThreadPoolModuleFactory extends + org.opendaylight.controller.config.yang.threadpool.impl.AbstractScheduledThreadPoolModuleFactory { + +} diff --git a/opendaylight/config/threadpool-config-impl/src/main/yang/threadpool-impl.yang b/opendaylight/config/threadpool-config-impl/src/main/yang/threadpool-impl.yang new file mode 100644 index 0000000000..a2366f285a --- /dev/null +++ b/opendaylight/config/threadpool-config-impl/src/main/yang/threadpool-impl.yang @@ -0,0 +1,195 @@ +// vi: set smarttab et sw=4 tabstop=4: +module threadpool-impl { + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:controller:threadpool:impl"; + prefix "th-java"; + + import threadpool { prefix th; revision-date 2013-04-09; } + import config { prefix config; revision-date 2013-04-05; } + import rpc-context { prefix rpcx; revision-date 2013-06-17; } + + organization "Cisco Systems, Inc."; + + contact "Robert Varga "; + + description + "This module contains the base YANG definitions for + thread services pure Java implementation. + + Copyright (c)2013 Cisco Systems, Inc. All rights reserved.; + + This program and the accompanying materials are made available + under the terms of the Eclipse Public License v1.0 which + accompanies this distribution, and is available at + http://www.eclipse.org/legal/epl-v10.html"; + + revision "2013-04-05" { + description + "Updated to work with new anchors."; + } + + revision "2013-04-03" { + description + "Initial revision by Anton Tkacik, Tomas Olvecky and + Robert Varga."; + } + + identity eventbus { + base config:module-type; + config:provided-service th:eventbus; + config:java-name-prefix EventBus; + } + + augment "/config:modules/config:module/config:configuration" { + case eventbus { + when "/config:modules/config:module/config:type = 'eventbus'"; + // No real configuration + } + } + + augment "/config:modules/config:module/config:state" { + case eventbus { + when "/config:modules/config:module/config:type = 'eventbus'"; + rpcx:rpc-context-instance "event-bus-rpc"; + } + } + + identity event-bus-rpc; + + identity async-eventbus { + base config:module-type; + config:provided-service th:eventbus; + config:java-name-prefix AsyncEventBus; + } + + augment "/config:modules/config:module/config:configuration" { + case async-eventbus { + when "/config:modules/config:module/config:type = 'async-eventbus'"; + container threadpool { + uses config:service-ref { + refine type { + //mandatory true; + config:required-identity th:threadpool; + } + } + } + } + } + + augment "/config:modules/config:module/config:state" { + case async-eventbus { + when "/config:modules/config:module/config:type = 'async-eventbus'"; + rpcx:rpc-context-instance "event-bus-rpc"; + } + } + + rpc get-dead-events-count { + config:java-name-prefix countDeadEvents; + input { + uses rpcx:rpc-context-ref { + refine context-instance { + rpcx:rpc-context-instance event-bus-rpc; + } + } + } + output { + leaf result { + type uint32; + } + } + } + + identity threadfactory-naming { + base config:module-type; + config:provided-service th:threadfactory; + config:java-name-prefix NamingThreadFactory; + } + + augment "/config:modules/config:module/config:configuration" { + case threadfactory-naming { + when "/config:modules/config:module/config:type = 'threadfactory-naming'"; + leaf name-prefix { + type string; + } + } + } + + identity threadpool-fixed { + base config:module-type; + config:provided-service th:threadpool; + config:java-name-prefix FixedThreadPool; + } + + augment "/config:modules/config:module/config:configuration" { + case threadpool-fixed { + when "/config:modules/config:module/config:type = 'threadpool-fixed'"; + leaf max-thread-count { + type uint16; + } + + container threadFactory { + uses config:service-ref { + refine type { + //mandatory true; + config:required-identity th:threadfactory; + } + } + } + } + } + + identity threadpool-flexible { + base config:module-type; + config:provided-service th:threadpool; + config:java-name-prefix FlexibleThreadPool; + } + + augment "/config:modules/config:module/config:configuration" { + case threadpool-flexible { + when "/config:modules/config:module/config:type = 'threadpool-flexible'"; + leaf max-thread-count { + type uint16; + } + leaf minThreadCount { + type uint16; + } + leaf keepAliveMillis { + type uint32; + } + + container threadFactory { + uses config:service-ref { + refine type { + // mandatory true; + config:required-identity th:threadfactory; + } + } + } + } + } + + identity threadpool-scheduled { + base config:module-type; + config:provided-service th:scheduled-threadpool; + config:java-name-prefix ScheduledThreadPool; + } + + augment "/config:modules/config:module/config:configuration" { + case threadpool-scheduled { + when "/config:modules/config:module/config:type = 'threadpool-scheduled'"; + leaf max-thread-count { + type uint16; + } + + container threadFactory { + uses config:service-ref { + refine type { + // mandatory true; + config:required-identity th:threadfactory; + } + } + } + } + } +} + diff --git a/opendaylight/distribution/opendaylight/pom.xml b/opendaylight/distribution/opendaylight/pom.xml index 4482df0780..9b07f75c6d 100644 --- a/opendaylight/distribution/opendaylight/pom.xml +++ b/opendaylight/distribution/opendaylight/pom.xml @@ -81,7 +81,7 @@ org.opendaylight.controller - sal-compability + sal-compatibility ${mdsal.version} diff --git a/opendaylight/md-sal/flow-management-compatibility/pom.xml b/opendaylight/md-sal/compatibility/flow-management-compatibility/pom.xml similarity index 94% rename from opendaylight/md-sal/flow-management-compatibility/pom.xml rename to opendaylight/md-sal/compatibility/flow-management-compatibility/pom.xml index 5c24baa650..3c8bf97961 100644 --- a/opendaylight/md-sal/flow-management-compatibility/pom.xml +++ b/opendaylight/md-sal/compatibility/flow-management-compatibility/pom.xml @@ -2,8 +2,8 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - org.opendaylight.controller - sal-parent + org.opendaylight.controller + compatibility-parent 1.0-SNAPSHOT flow-management-compatibility @@ -81,7 +81,7 @@ org.opendaylight.controller - sal-compability + sal-compatibility 1.0-SNAPSHOT diff --git a/opendaylight/md-sal/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FRMRuntimeDataProvider.xtend b/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FRMRuntimeDataProvider.xtend similarity index 98% rename from opendaylight/md-sal/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FRMRuntimeDataProvider.xtend rename to opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FRMRuntimeDataProvider.xtend index 58248590a1..d462251a9f 100644 --- a/opendaylight/md-sal/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FRMRuntimeDataProvider.xtend +++ b/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FRMRuntimeDataProvider.xtend @@ -15,7 +15,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.Flows import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager import static com.google.common.base.Preconditions.*; import static extension org.opendaylight.controller.md.frm.compatibility.FlowConfigMapping.*; -import static extension org.opendaylight.controller.sal.compability.NodeMapping.*; +import static extension org.opendaylight.controller.sal.compatibility.NodeMapping.*; import org.opendaylight.controller.sal.common.util.Arguments import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem import org.opendaylight.yangtools.yang.common.RpcResult diff --git a/opendaylight/md-sal/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FlowConfigMapping.xtend b/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FlowConfigMapping.xtend similarity index 89% rename from opendaylight/md-sal/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FlowConfigMapping.xtend rename to opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FlowConfigMapping.xtend index c567dc0097..e4d9173378 100644 --- a/opendaylight/md-sal/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FlowConfigMapping.xtend +++ b/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FlowConfigMapping.xtend @@ -3,9 +3,9 @@ package org.opendaylight.controller.md.frm.compatibility import org.opendaylight.controller.forwardingrulesmanager.FlowConfig import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowBuilder -import static extension org.opendaylight.controller.sal.compability.NodeMapping.* -import static org.opendaylight.controller.sal.compability.MDFlowMapping.* -import static org.opendaylight.controller.sal.compability.ToSalConversionsUtils.* +import static extension org.opendaylight.controller.sal.compatibility.NodeMapping.* +import static org.opendaylight.controller.sal.compatibility.MDFlowMapping.* +import static org.opendaylight.controller.sal.compatibility.ToSalConversionsUtils.* import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowKey import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow diff --git a/opendaylight/md-sal/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FlowManagementReader.java b/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FlowManagementReader.java similarity index 100% rename from opendaylight/md-sal/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FlowManagementReader.java rename to opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FlowManagementReader.java diff --git a/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/SampleConsumer.java b/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/SampleConsumer.java new file mode 100644 index 0000000000..a82eedc3f9 --- /dev/null +++ b/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/SampleConsumer.java @@ -0,0 +1,38 @@ +package org.opendaylight.controller.md.frm.compatibility; + +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.yang.gen.v1.urn.opendaylight.flow.config.rev130819.Flows; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class SampleConsumer { + + ConsumerContext context; + + void addFlowExample() { + + DataBrokerService dataService = context.getSALService(DataBrokerService.class); + + DataModificationTransaction transaction = dataService.beginTransaction(); + Flow flow = createSampleFlow("foo", null); + InstanceIdentifier path = InstanceIdentifier.builder().node(Flows.class).node(Flow.class, flow.getKey()) + .toInstance(); + transaction.putConfigurationData(path, flow); + + transaction.commit(); + + dataService.readConfigurationData(path); + } + + Flow createSampleFlow(String name, NodeRef node) { + FlowBuilder ret = new FlowBuilder(); + FlowKey key = new FlowKey(name, node); + ret.setKey(key); + return ret.build(); + } +} diff --git a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/pom.xml b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/pom.xml new file mode 100644 index 0000000000..d9fb18f84d --- /dev/null +++ b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/pom.xml @@ -0,0 +1,109 @@ + + 4.0.0 + + org.opendaylight.controller + compatibility-parent + 1.0-SNAPSHOT + + inventory-topology-compatibility + bundle + + scm:git:ssh://git.opendaylight.org:29418/controller.git + scm:git:ssh://git.opendaylight.org:29418/controller.git + https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL + + + + + + org.apache.felix + maven-bundle-plugin + true + + + Forwarding Rules Manager Adapter + for MD-SAL + + + + + org.eclipse.xtend + xtend-maven-plugin + + + maven-clean-plugin + + + + + + + org.opendaylight.controller + sal-common-util + 1.0-SNAPSHOT + + + org.opendaylight.controller + sal-binding-api + 1.0-SNAPSHOT + + + org.opendaylight.controller + switchmanager + 0.6.1-SNAPSHOT + + + org.opendaylight.controller + topologymanager + 0.4.1-SNAPSHOT + + + org.slf4j + slf4j-api + + + com.google.guava + guava + + + junit + junit + test + + + org.mockito + mockito-all + test + + + org.eclipse.xtend + org.eclipse.xtend.lib + + + org.opendaylight.controller.model + model-flow-management + 1.0-SNAPSHOT + + + org.opendaylight.controller + sal-binding-util + 1.0-SNAPSHOT + + + org.opendaylight.controller.model + model-topology + 1.0-SNAPSHOT + + + org.opendaylight.controller + forwardingrulesmanager + 0.4.1-SNAPSHOT + + + org.opendaylight.controller + sal-compatibility + 1.0-SNAPSHOT + + + diff --git a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/inventory/InventoryReader.xtend b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/inventory/InventoryReader.xtend new file mode 100644 index 0000000000..262e8486ee --- /dev/null +++ b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/inventory/InventoryReader.xtend @@ -0,0 +1,83 @@ +package org.opendaylight.controller.md.compatibility.inventory + +import org.opendaylight.controller.switchmanager.ISwitchManager +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier +import org.opendaylight.yangtools.yang.binding.DataObject +import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider +import java.util.ArrayList +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.node.NodeConnector +import static extension org.opendaylight.controller.sal.compatibility.InventoryMapping.*; +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.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder + +class InventoryReader implements RuntimeDataProvider { + + @Property + var ISwitchManager switchManager; + + override readConfigurationData(InstanceIdentifier path) { + + // Topology and Inventory are operational only + return null; + } + + override readOperationalData(InstanceIdentifier path) { + val type = path.targetType; + var DataObject data = null; + switch (type) { + case Nodes: + data = readNodes(path as InstanceIdentifier) + case Node: + data = readNode(path as InstanceIdentifier) + case NodeConnector: + data = readNodeConnector(path as InstanceIdentifier) + } + return data; + } + + def DataObject readNodeConnector(InstanceIdentifier identifier) { + val nodeConnector = identifier.toAdNodeConnector(); + return constructNodeConnector(nodeConnector) + } + + def DataObject readNode(InstanceIdentifier identifier) { + val node = identifier.toAdNode(); + return constructNode(node); + } + + + def Node constructNode(org.opendaylight.controller.sal.core.Node node) { + val connectors = switchManager.getNodeConnectors(node) + + val tpList = new ArrayList(connectors.size) + for (connector : connectors) { + tpList.add(constructNodeConnector(connector)); + } + + val it = new NodeBuilder() + key = node.toNodeKey(); + nodeConnector = tpList + return build(); + } + + def NodeConnector constructNodeConnector(org.opendaylight.controller.sal.core.NodeConnector connector) { + val it = new NodeConnectorBuilder() + key = connector.toNodeConnectorKey() + return build(); + } + + def readNodes(InstanceIdentifier identifier) { + val nodes = switchManager.nodes + val nodeList = new ArrayList(nodes.size) + for (node : nodes) { + nodeList.add(constructNode(node)) + } + val it = new NodesBuilder(); + node = nodeList + return build() + + } +} diff --git a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/switchmanager/CompatibleSwitchManager.xtend b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/switchmanager/CompatibleSwitchManager.xtend new file mode 100644 index 0000000000..430b5957ef --- /dev/null +++ b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/switchmanager/CompatibleSwitchManager.xtend @@ -0,0 +1,289 @@ +package org.opendaylight.controller.md.compatibility.switchmanager + +import org.opendaylight.controller.switchmanager.ISwitchManager +import org.opendaylight.controller.sal.core.NodeConnector +import org.opendaylight.controller.sal.core.Property +import java.util.List +import org.opendaylight.controller.sal.core.Node +import java.net.InetAddress +import org.opendaylight.controller.sal.binding.api.data.DataBrokerService +import static extension org.opendaylight.controller.sal.compatibility.NodeMapping.* +import org.opendaylight.controller.sal.core.Description +import org.opendaylight.controller.sal.core.Tier +import org.opendaylight.controller.sal.core.Bandwidth +import org.opendaylight.controller.sal.core.ForwardingMode +import org.opendaylight.controller.sal.core.MacAddress + +import org.slf4j.LoggerFactory +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier +import org.opendaylight.yangtools.yang.binding.DataObject +import java.net.NetworkInterface +import java.net.SocketException +import java.util.Collections +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes +import java.util.ArrayList +import org.opendaylight.controller.switchmanager.Switch +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId +import java.util.Map +import java.util.HashSet +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortState + +class CompatibleSwitchManager extends ConfigurableSwitchManager implements ISwitchManager { + + private static val log = LoggerFactory.getLogger(CompatibleSwitchManager) + + @org.eclipse.xtend.lib.Property + var DataBrokerService dataService; + + override addNodeConnectorProp(NodeConnector nodeConnector, Property prop) { + val it = dataService.beginTransaction + val path = nodeConnector.toNodeConnectorRef + + // TODO: Update FlowCapableNode + return null; + } + + override createProperty(String propName, String propValue) { + try { + if (propName.equalsIgnoreCase(Description.propertyName)) { + return new Description(propValue); + } else if (propName.equalsIgnoreCase(Tier.TierPropName)) { + val tier = Integer.parseInt(propValue); + return new Tier(tier); + } else if (propName.equalsIgnoreCase(Bandwidth.BandwidthPropName)) { + val bw = Long.parseLong(propValue); + return new Bandwidth(bw); + } else if (propName.equalsIgnoreCase(ForwardingMode.name)) { + val mode = Integer.parseInt(propValue); + return new ForwardingMode(mode); + } else if (propName.equalsIgnoreCase(MacAddress.name)) { + return new MacAddress(propValue); + } else { + log.debug("Not able to create {} property", propName); + } + } catch (Exception e) { + log.debug("createProperty caught exception {}", e.getMessage()); + } + return null; + } + + override doesNodeConnectorExist(NodeConnector nc) { + val ref = nc.toNodeConnectorRef + return dataService.readOperationalData(ref.value as InstanceIdentifier) !== null + } + + override getControllerMAC() { + var byte[] macAddress = null; + + try { + val nis = NetworkInterface.getNetworkInterfaces(); + while (nis.hasMoreElements()) { + val ni = nis.nextElement(); + try { + macAddress = ni.getHardwareAddress(); + return macAddress; + } catch (SocketException e) { + log.error("Failed to acquire controller MAC: ", e); + } + } + } catch (SocketException e) { + log.error("Failed to acquire controller MAC: ", e); + return macAddress; + } + + if (macAddress == null) { + log.warn("Failed to acquire controller MAC: No physical interface found"); + + // This happens when running controller on windows VM, for example + // Try parsing the OS command output + } + return macAddress; + } + + override getControllerProperties() { + return Collections.emptyMap() + } + + override getControllerProperty(String propertyName) { + return null; + } + + override getNetworkDevices() { + val path = InstanceIdentifier.builder().node(Nodes).toInstance; + val data = dataService.readOperationalData(path) as Nodes; + val ret = new ArrayList(); + for (node : data.node) { + ret.add(node.toSwitch()); + } + return ret; + } + + override getNodeConnector(Node node, String nodeConnectorName) { + val key = new NodeConnectorKey(new NodeConnectorId(nodeConnectorName)); + return new NodeConnector(MD_SAL_TYPE, key, node); + } + + override getNodeConnectorProp(NodeConnector nodeConnector, String propName) { + getNodeConnectorProps(nodeConnector).get(propName); + } + + override getNodeConnectorProps(NodeConnector nodeConnector) { + val ref = nodeConnector.toNodeConnectorRef + val data = readNodeConnector(ref.value); + return data.toAdProperties(); + } + + override getNodeConnectors(Node node) { + val ref = node.toNodeRef; + val data = readNode(ref.value); + val ret = new HashSet(); + for (nc : data.nodeConnector) { + + val adConnector = new NodeConnector(MD_SAL_TYPE, nc.key, node); + ret.add(adConnector); + } + return ret; + } + + override getNodeDescription(Node node) { + (getNodeProps(node).get(Description.propertyName) as Description).value; + } + + override getNodeMAC(Node node) { + (getNodeProps(node).get(MacAddress.name) as MacAddress).macAddress; + } + + override getNodeProp(Node node, String propName) { + getNodeProps(node).get(propName) + } + + override getNodeProps(Node node) { + val ref = node.toNodeRef; + val data = dataService.readOperationalData(ref.value as InstanceIdentifier) as org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; + return data.toAdProperties(); + } + + override getNodes() { + val path = InstanceIdentifier.builder().node(Nodes).toInstance; + val data = dataService.readOperationalData(path) as Nodes; + val ret = new HashSet(); + for (node : data.node) { + ret.add(new Node(MD_SAL_TYPE, node.key)); + } + return ret; + } + + def Switch toSwitch(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node node) { + val adNode = new Node(MD_SAL_TYPE, node.key); + val sw = new Switch(adNode) + return sw; + } + + override getPhysicalNodeConnectors(Node node) { + val ref = node.toNodeRef; + val data = readNode(ref.value); + val ret = new HashSet(); + for (nc : data.nodeConnector) { + val flowConnector = nc.getAugmentation(FlowCapableNodeConnector) + val adConnector = new NodeConnector(MD_SAL_TYPE, nc.key, node); + ret.add(adConnector); + } + return ret; + } + + def Map toAdProperties( + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector connector) { + return Collections.emptyMap + } + + def Map toAdProperties( + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node connector) { + return Collections.emptyMap + } + + def readNode(InstanceIdentifier ref) { + dataService.readOperationalData(ref as InstanceIdentifier) as org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node + } + + def readNodeConnector(InstanceIdentifier ref) { + dataService.readOperationalData(ref as InstanceIdentifier) as org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector + } + + override getSpanPorts(Node node) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + + override getSubnetByNetworkAddress(InetAddress networkAddress) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + + override getUpNodeConnectors(Node node) { + val ref = node.toNodeRef + val data = readNode(ref.value); + val ret = new HashSet(); + for (nc : data.nodeConnector) { + val flowConn = nc.getAugmentation(FlowCapableNodeConnector); + if (flowConn != null && flowConn.state == PortState.Live) { + ret.add(new NodeConnector(MD_SAL_TYPE, nc.key, node)); + } + } + return ret; + } + + override isNodeConnectorEnabled(NodeConnector nodeConnector) { + val ref = nodeConnector.toNodeConnectorRef + val data = readNodeConnector(ref.value); + + return true; + } + + override isSpecial(NodeConnector p) { + val ref = p.toNodeConnectorRef + val data = readNodeConnector(ref.value); + + return true; + } + + override removeControllerProperty(String propertyName) { + // NOOP + } + + override removeNodeAllProps(Node node) { + // NOOP: not supported node has more properties than AD-SAL is capable to see + } + + override removeNodeConnectorAllProps(NodeConnector nodeConnector) { + // NOOP: not supported node has more properties than AD-SAL is capable to see + } + + override removeNodeConnectorProp(NodeConnector nc, String propName) { + // NOOP: not supported node has more properties than AD-SAL is capable to see + } + + override removeNodeProp(Node node, String propName) { + // NOOP: not supported node has more properties than AD-SAL is capable to see + } + + override removePortsFromSubnet(String name, List nodeConnectors) { + // NOOP + } + + override removeSubnet(String name) { + // NOOP + } + + override setControllerProperty(Property property) { + // NOOP + } + + override setNodeProp(Node node, Property prop) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + + override addPortsToSubnet(String name, List nodeConnectors) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + + } diff --git a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/switchmanager/ConfigurableSwitchManager.xtend b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/switchmanager/ConfigurableSwitchManager.xtend new file mode 100644 index 0000000000..122aa32f12 --- /dev/null +++ b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/switchmanager/ConfigurableSwitchManager.xtend @@ -0,0 +1,71 @@ +package org.opendaylight.controller.md.compatibility.switchmanager + +import org.opendaylight.controller.switchmanager.ISwitchManager +import org.opendaylight.controller.switchmanager.SpanConfig +import org.opendaylight.controller.switchmanager.SwitchConfig +import org.opendaylight.controller.switchmanager.SubnetConfig + +/** + * + * THis methods should be backed by config subsystem. + * + */ +abstract class ConfigurableSwitchManager implements ISwitchManager { + + override saveSwitchConfig() { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + + override removeSpanConfig(SpanConfig cfgObject) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + + override addSubnet(SubnetConfig configObject) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + + } + + final override addSpanConfig(SpanConfig configObject) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + + } + + final override getSpanConfigList() { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + + } + + final override updateSwitchConfig(SwitchConfig cfgObject) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + + } + + final override updateNodeConfig(SwitchConfig switchConfig) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + + } + + final override getSubnetConfig(String subnet) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + + final override removeNodeConfig(String nodeId) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + + final override removeSubnet(SubnetConfig configObject) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + + final override getSubnetsConfigList() { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + + final override getSwitchConfig(String nodeId) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + + override modifySubnet(SubnetConfig configObject) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } +} diff --git a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topology/TopologyMapping.xtend b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topology/TopologyMapping.xtend new file mode 100644 index 0000000000..5a4aae36a8 --- /dev/null +++ b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topology/TopologyMapping.xtend @@ -0,0 +1,67 @@ +package org.opendaylight.controller.md.compatibility.topology + +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier +import org.opendaylight.yangtools.yang.binding.DataObject +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.network.topology.TopologyKey +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.network.topology.Topology +import org.opendaylight.controller.sal.core.Edge +import java.util.Set +import org.opendaylight.controller.sal.core.Property +import org.opendaylight.controller.sal.core.NodeConnector + +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.network.topology.topology.node.TerminationPoint +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.network.topology.topology.Link +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.network.topology.topology.node.TerminationPointKey +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.TpId +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.network.topology.topology.NodeKey +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.NodeId +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.network.topology.topology.LinkKey +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.LinkId +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.network.topology.topology.Node +import org.opendaylight.controller.sal.compatibility.InventoryMapping +class TopologyMapping { + + new(TopologyKey path, InstanceIdentifier key) { + // NOOP + } + + def Edge toAdTopologyEdge(InstanceIdentifier identifier) { + val linkKey = (identifier.path.last as IdentifiableItem).key; + val components = linkKey.linkId.value.split("::::"); + val tail = InventoryMapping.nodeConnectorFromId(components.get(0)); + val head = InventoryMapping.nodeConnectorFromId(components.get(1)); + return new Edge(tail, head); + } + + def NodeConnector toAdTopologyNodeConnector(InstanceIdentifier identifier) { + val tpKey = (identifier.path.last as IdentifiableItem).key; + return InventoryMapping.nodeConnectorFromId(tpKey.tpId.value); + } + + def org.opendaylight.controller.sal.core.Node toAdTopologyNode( + InstanceIdentifier identifier) { + val tpKey = (identifier.path.last as IdentifiableItem).key; + return InventoryMapping.nodeFromNodeId(tpKey.nodeId.value); + } + + + + def NodeKey toTopologyNodeKey(org.opendaylight.controller.sal.core.Node node) { + val nodeId = new NodeId(InventoryMapping.toNodeId(node)); + return new NodeKey(nodeId); + } + + def TerminationPointKey toTopologyTerminationPointKey(NodeConnector nc) { + val node = nc.node; + val nodeId = new TpId(InventoryMapping.toNodeConnectorId(nc)) + return new TerminationPointKey(nodeId); + } + + def LinkKey toTopologyLinkKey(Edge edge) { + val sourceTp = edge.tailNodeConnector.toTopologyTerminationPointKey; + val destTp = edge.headNodeConnector.toTopologyTerminationPointKey; + val linkId = new LinkId('''«sourceTp.tpId»::::«destTp.tpId»''') + return new LinkKey(linkId); + } +} diff --git a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topology/TopologyReader.xtend b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topology/TopologyReader.xtend new file mode 100644 index 0000000000..fb9d2b8786 --- /dev/null +++ b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topology/TopologyReader.xtend @@ -0,0 +1,151 @@ +package org.opendaylight.controller.md.compatibility.topology + +import org.opendaylight.controller.switchmanager.ISwitchManager +import org.opendaylight.controller.topologymanager.ITopologyManager +import org.opendaylight.controller.md.sal.common.api.data.DataReader +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier +import org.opendaylight.yangtools.yang.binding.DataObject +import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.network.topology.Topology +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.network.topology.topology.Node +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.network.topology.topology.node.TerminationPoint +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.network.topology.topology.Link +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.network.topology.TopologyKey +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.NetworkTopology +import org.opendaylight.controller.md.compatibility.topology.TopologyMapping +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.network.topology.topology.LinkBuilder + +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.network.topology.TopologyBuilder +import java.util.ArrayList +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.network.topology.topology.NodeBuilder +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.network.topology.topology.NodeKey +import org.opendaylight.controller.sal.core.NodeConnector +import org.opendaylight.controller.sal.topology.TopoEdgeUpdate +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.TopologyId +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.network.topology.topology.node.TerminationPointBuilder +import org.opendaylight.controller.sal.core.Edge +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.link.attributes.SourceBuilder +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.link.attributes.DestinationBuilder + +class TopologyReader implements RuntimeDataProvider { + + @Property + var ISwitchManager switchManager; + + @Property + var ITopologyManager topologyManager; + + @Property + val TopologyKey topologyKey; + + @Property + val InstanceIdentifier topologyPath; + + @Property + val extension TopologyMapping mapping; + + new() { + _topologyKey = new TopologyKey(new TopologyId("compatibility:ad-sal")); + _topologyPath = InstanceIdentifier.builder().node(NetworkTopology).child(Topology, topologyKey).toInstance; + _mapping = new TopologyMapping(topologyKey, topologyPath); + } + + override readConfigurationData(InstanceIdentifier path) { + + // Topology and Inventory are operational only + return null; + } + + override readOperationalData(InstanceIdentifier path) { + val type = path.targetType; + var DataObject data = null; + if (false == topologyPath.contains(path)) { + return null; + } + switch (type) { + case Topology: + data = readTopology(path as InstanceIdentifier) + case Node: + data = readNode(path as InstanceIdentifier) + case TerminationPoint: + data = readTerminationPoint(path as InstanceIdentifier) + case Link: + data = readLink(path as InstanceIdentifier) + } + return data; + } + + def DataObject readLink(InstanceIdentifier identifier) { + val edge = identifier.toAdTopologyEdge(); + val properties = topologyManager?.edges?.get(edge); + + return constructLink(edge); + } + + def DataObject readTerminationPoint(InstanceIdentifier identifier) { + val nodeConnector = identifier.toAdTopologyNodeConnector(); + return constructTerminationPoint(nodeConnector) + } + + def DataObject readNode(InstanceIdentifier identifier) { + val node = identifier.toAdTopologyNode(); + return constructNode(node); + } + + def DataObject readTopology(InstanceIdentifier identifier) { + + //val nodeConnectors = switchManager. + val nodes = switchManager.nodes + val edges = topologyManager.edges + + val nodeList = new ArrayList(nodes.size) + for (node : nodes) { + nodeList.add(constructNode(node)) + } + + val linkList = new ArrayList(edges.size) + for (edge : edges.keySet) { + linkList.add(constructLink(edge)) + } + + val it = new TopologyBuilder(); + key = topologyKey + node = nodeList + link = linkList + return build() + } + + def constructLink(Edge edge) { + val sourceNc = edge.tailNodeConnector + val destNc = edge.headNodeConnector + + val it = new LinkBuilder() + key = edge.toTopologyLinkKey(); + source = new SourceBuilder().setSourceNode(sourceNc.node.toTopologyNodeKey.nodeId).setSourceTp( + sourceNc.toTopologyTerminationPointKey.tpId).build() + destination = new DestinationBuilder().setDestNode(destNc.node.toTopologyNodeKey.nodeId).setDestTp( + destNc.toTopologyTerminationPointKey.tpId).build + return build() + } + + def Node constructNode(org.opendaylight.controller.sal.core.Node node) { + val connectors = switchManager.getNodeConnectors(node) + + val tpList = new ArrayList(connectors.size) + for (connector : connectors) { + tpList.add(constructTerminationPoint(connector)); + } + + val it = new NodeBuilder() + key = node.toTopologyNodeKey(); + terminationPoint = tpList + return build(); + } + + def TerminationPoint constructTerminationPoint(NodeConnector connector) { + val it = new TerminationPointBuilder() + key = connector.toTopologyTerminationPointKey + return build(); + } + +} diff --git a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/AdSalTopologyMapping.xtend b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/AdSalTopologyMapping.xtend new file mode 100644 index 0000000000..ad7537bc0d --- /dev/null +++ b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/AdSalTopologyMapping.xtend @@ -0,0 +1,94 @@ +package org.opendaylight.controller.md.compatibility.topologymanager + +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.network.topology.TopologyKey +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.network.topology.topology.node.TerminationPoint +import org.opendaylight.controller.sal.core.NodeConnector +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.network.topology.Topology +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.NetworkTopology +import java.util.Map +import org.opendaylight.controller.sal.core.Edge +import java.util.Set +import java.util.List +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.network.topology.topology.Node +import java.util.Collections +import com.google.common.collect.FluentIterable +import java.util.HashSet +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId +import org.opendaylight.controller.sal.compatibility.NodeMapping +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.network.topology.topology.Link +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.link.attributes.Source +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.link.attributes.Destination +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.TpId +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.network.topology.topology.node.TerminationPointKey +import java.util.HashMap + +class AdSalTopologyMapping { + + val TopologyKey topologyMapping; + @Property + val InstanceIdentifier topologyPath; + + new(TopologyKey topology) { + topologyMapping = topology; + _topologyPath = InstanceIdentifier.builder.node(NetworkTopology).child(Topology, topology).toInstance; + } + + def InstanceIdentifier toTerminationPoint(NodeConnector connector) { + InstanceIdentifier.builder(topologyPath).node(Node).child(TerminationPoint, connector.toTerminationPointKey()).toInstance; + } + + def Map> toEdgePropertiesMap(Iterable links) { + val ret = new HashMap> + for (link : links) { + ret.put(link.toEdge(), link.toProperties()) + } + return ret; + } + + def Set toEdges(Iterable links) { + val ret = new HashSet + for (link : links) { + ret.add(link.toEdge) + } + return ret; + } + + def Edge toEdge(Link link) { + val tail = link.source.toNodeConnector(); + val head = link.destination.toNodeConnector(); + return new Edge(tail, head); + } + + def org.opendaylight.controller.sal.core.Node toAdNode(Node node) { + return node.nodeId.toAdNode; + } + + def org.opendaylight.controller.sal.core.Node toAdNode( + org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.NodeId node) { + val key = new NodeKey(new NodeId(node)) + return new org.opendaylight.controller.sal.core.Node(NodeMapping.MD_SAL_TYPE, key); + } + + def NodeConnector toNodeConnector(Source ref) { + val adNode = ref.sourceNode.toAdNode(); + val key = new NodeConnectorKey(new NodeConnectorId(ref.sourceTp)) + return new NodeConnector(NodeMapping.MD_SAL_TYPE, key, adNode); + } + + def NodeConnector toNodeConnector(Destination ref) { + val adNode = ref.destNode.toAdNode(); + val key = new NodeConnectorKey(new NodeConnectorId(ref.destTp)) + return new NodeConnector(NodeMapping.MD_SAL_TYPE, key, adNode); + } + + def TerminationPointKey toTerminationPointKey(NodeConnector connector) { + } + + def Set toProperties(Link link) { + } +} diff --git a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/CompatibleTopologyManager.xtend b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/CompatibleTopologyManager.xtend new file mode 100644 index 0000000000..c6a4912f2d --- /dev/null +++ b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/CompatibleTopologyManager.xtend @@ -0,0 +1,85 @@ +package org.opendaylight.controller.md.compatibility.topologymanager + +import org.opendaylight.controller.topologymanager.ITopologyManager +import org.opendaylight.controller.sal.core.NodeConnector +import org.opendaylight.controller.sal.core.Host +import org.opendaylight.controller.sal.core.UpdateType +import java.util.Set +import org.opendaylight.controller.md.sal.binding.util.TypeSafeDataReader +import java.util.HashMap +import org.opendaylight.controller.sal.core.Edge +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.network.topology.topology.node.TerminationPoint +import com.google.common.collect.FluentIterable + +class CompatibleTopologyManager extends ConfigurableLinkManager implements ITopologyManager { + + @Property + var TypeSafeDataReader dataReader; + + @Property + var extension AdSalTopologyMapping topologyMapping; + + override getEdges() { + val topology = dataReader.readOperationalData(topologyPath); + return topology.link.toEdgePropertiesMap(); + } + + override getNodeEdges() { + val topology = dataReader.readOperationalData(topologyPath); + val ret = new HashMap>; + for (node : topology.node) { + val adNode = node.toAdNode(); + val adEdges = FluentIterable.from(topology.link).filter[ + source.sourceNode == node.nodeId || destination.destNode == node.nodeId].toEdges(); + ret.put(adNode, adEdges) + } + return ret; + } + + /** + * Returns true if point is connected to link + */ + def isInternal(TerminationPoint point) { + val topology = dataReader.readConfigurationData(topologyPath); + val tpId = point.key.tpId; + return FluentIterable.from(topology.link).anyMatch( + [ + source.sourceTp == tpId || destination.destTp == tpId + ]) + } + + override getNodeConnectorWithHost() { + } + + override getHostAttachedToNodeConnector(NodeConnector p) { + val tpPath = p.toTerminationPoint(); + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + + override getHostsAttachedToNodeConnector(NodeConnector p) { + val topology = dataReader.readOperationalData(topologyPath); + + throw new UnsupportedOperationException("Hosts not mapped yet") + } + + override getNodesWithNodeConnectorHost() { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + + } + + override isInternal(NodeConnector p) { + val tpPath = p.toTerminationPoint(); + val connector = dataReader.readConfigurationData(tpPath); + return connector.isInternal(); + } + + override updateHostLink(NodeConnector p, Host h, UpdateType t, + Set props) { + // Update app defined topology + } + + override saveConfig() { + // FIXME: commit configuration + } + +} diff --git a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/ConfigurableLinkManager.xtend b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/ConfigurableLinkManager.xtend new file mode 100644 index 0000000000..da3bf66424 --- /dev/null +++ b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/ConfigurableLinkManager.xtend @@ -0,0 +1,24 @@ +package org.opendaylight.controller.md.compatibility.topologymanager + +import org.opendaylight.controller.topologymanager.ITopologyManager +import org.opendaylight.controller.topologymanager.TopologyUserLinkConfig + +abstract class ConfigurableLinkManager implements ITopologyManager { + + final override addUserLink(TopologyUserLinkConfig link) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + + } + + + final override deleteUserLink(String linkName) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + + } + + + final override getUserLinks() { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/compatibility/pom.xml b/opendaylight/md-sal/compatibility/pom.xml new file mode 100644 index 0000000000..a829380e68 --- /dev/null +++ b/opendaylight/md-sal/compatibility/pom.xml @@ -0,0 +1,101 @@ + + 4.0.0 + + org.opendaylight.controller + sal-parent + 1.0-SNAPSHOT + + compatibility-parent + pom + MD-SAL to AD-SAL Adaptation + + scm:git:ssh://git.opendaylight.org:29418/controller.git + scm:git:ssh://git.opendaylight.org:29418/controller.git + https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL + + + + sal-compatibility + inventory-topology-compatibility + flow-management-compatibility + + + + + org.opendaylight.controller + sal + 0.5.1-SNAPSHOT + + + org.opendaylight.controller.model + model-flow-service + 1.0-SNAPSHOT + + + org.opendaylight.controller + sal-common-util + 1.0-SNAPSHOT + + + org.opendaylight.controller + sal-binding-api + 1.0-SNAPSHOT + + + com.google.guava + guava + + + org.eclipse.xtend + org.eclipse.xtend.lib + + + junit + junit + test + + + + + + + org.eclipse.xtend + xtend-maven-plugin + + + org.apache.felix + maven-bundle-plugin + + + ${project.name} + org.opendaylight.controller.sal.compability.ComponentActivator + + + + + org.jacoco + jacoco-maven-plugin + + org.opendaylight.controller.* + + + + pre-test + + prepare-agent + + + + post-test + test + + report + + + + + + + + diff --git a/opendaylight/md-sal/sal-compability/pom.xml b/opendaylight/md-sal/compatibility/sal-compatibility/pom.xml similarity index 65% rename from opendaylight/md-sal/sal-compability/pom.xml rename to opendaylight/md-sal/compatibility/sal-compatibility/pom.xml index 6d992de015..15a9a689b3 100644 --- a/opendaylight/md-sal/sal-compability/pom.xml +++ b/opendaylight/md-sal/compatibility/sal-compatibility/pom.xml @@ -3,10 +3,10 @@ 4.0.0 org.opendaylight.controller - sal-parent + compatibility-parent 1.0-SNAPSHOT - sal-compability + sal-compatibility MD-SAL to AD-SAL Adaptation scm:git:ssh://git.opendaylight.org:29418/controller.git @@ -15,44 +15,11 @@ - - org.opendaylight.controller - sal - 0.5.1-SNAPSHOT - - - org.opendaylight.controller.model - model-flow-service - 1.0-SNAPSHOT - org.opendaylight.controller.model model-flow-statistics 1.0-SNAPSHOT - - org.opendaylight.controller - sal-common-util - 1.0-SNAPSHOT - - - org.opendaylight.controller - sal-binding-api - 1.0-SNAPSHOT - - - com.google.guava - guava - - - org.eclipse.xtend - org.eclipse.xtend.lib - - - junit - junit - test - bundle @@ -68,7 +35,7 @@ ${project.name} - org.opendaylight.controller.sal.compability.ComponentActivator + org.opendaylight.controller.sal.compatibility.ComponentActivator diff --git a/opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/ComponentActivator.xtend b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ComponentActivator.xtend similarity index 97% rename from opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/ComponentActivator.xtend rename to opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ComponentActivator.xtend index 5c1723ec7e..b460edff74 100644 --- a/opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/ComponentActivator.xtend +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ComponentActivator.xtend @@ -1,10 +1,10 @@ -package org.opendaylight.controller.sal.compability +package org.opendaylight.controller.sal.compatibility import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey import org.opendaylight.controller.sal.core.Node import org.opendaylight.controller.sal.core.NodeConnector -import static org.opendaylight.controller.sal.compability.NodeMapping.* +import static org.opendaylight.controller.sal.compatibility.NodeMapping.* import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey import org.apache.felix.dm.Component import java.util.Arrays diff --git a/opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/DataPacketAdapter.xtend b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/DataPacketAdapter.xtend similarity index 93% rename from opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/DataPacketAdapter.xtend rename to opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/DataPacketAdapter.xtend index 422599c62b..ce6af6469e 100644 --- a/opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/DataPacketAdapter.xtend +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/DataPacketAdapter.xtend @@ -1,4 +1,4 @@ -package org.opendaylight.controller.sal.compability +package org.opendaylight.controller.sal.compatibility import org.opendaylight.controller.sal.packet.IPluginOutDataPacketService import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingListener diff --git a/opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/FlowProgrammerAdapter.xtend b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/FlowProgrammerAdapter.xtend similarity index 93% rename from opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/FlowProgrammerAdapter.xtend rename to opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/FlowProgrammerAdapter.xtend index 385007b375..da652e65a7 100644 --- a/opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/FlowProgrammerAdapter.xtend +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/FlowProgrammerAdapter.xtend @@ -1,4 +1,4 @@ -package org.opendaylight.controller.sal.compability +package org.opendaylight.controller.sal.compatibility import java.util.concurrent.ExecutionException import org.opendaylight.controller.sal.core.Node @@ -15,10 +15,10 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalF import org.opendaylight.yangtools.yang.common.RpcResult import org.slf4j.LoggerFactory -import static org.opendaylight.controller.sal.compability.MDFlowMapping.* +import static org.opendaylight.controller.sal.compatibility.MDFlowMapping.* -import static extension org.opendaylight.controller.sal.compability.NodeMapping.* -import static extension org.opendaylight.controller.sal.compability.ToSalConversionsUtils.* +import static extension org.opendaylight.controller.sal.compatibility.NodeMapping.* +import static extension org.opendaylight.controller.sal.compatibility.ToSalConversionsUtils.* class FlowProgrammerAdapter implements IPluginInFlowProgrammerService, SalFlowListener { diff --git a/opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/FromSalConversionsUtils.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/FromSalConversionsUtils.java similarity index 98% rename from opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/FromSalConversionsUtils.java rename to opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/FromSalConversionsUtils.java index 8b8668999e..a31d8e265d 100644 --- a/opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/FromSalConversionsUtils.java +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/FromSalConversionsUtils.java @@ -1,4 +1,4 @@ -package org.opendaylight.controller.sal.compability; +package org.opendaylight.controller.sal.compatibility; import static org.opendaylight.controller.sal.match.MatchType.DL_DST; import static org.opendaylight.controller.sal.match.MatchType.DL_SRC; @@ -12,6 +12,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import org.opendaylight.controller.sal.compatibility.MDFlowMapping; import org.opendaylight.controller.sal.core.NodeConnector; @@ -25,7 +26,6 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types. import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress; - import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetNodeConnectorStatisticsInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetNodeConnectorStatisticsInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.address.Address; @@ -57,18 +57,9 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatchBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.UdpMatchBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanIdBuilder; - import com.google.common.net.InetAddresses; - - - - - - - - -import static org.opendaylight.controller.sal.compability.ProtocolConstants.*; -import static org.opendaylight.controller.sal.compability.NodeMapping.*; +import static org.opendaylight.controller.sal.compatibility.NodeMapping.*; +import static org.opendaylight.controller.sal.compatibility.ProtocolConstants.*; public class FromSalConversionsUtils { diff --git a/opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/InventoryAndReadAdapter.xtend b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryAndReadAdapter.xtend similarity index 98% rename from opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/InventoryAndReadAdapter.xtend rename to opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryAndReadAdapter.xtend index c9c60e2141..8ac6f1b050 100644 --- a/opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/InventoryAndReadAdapter.xtend +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryAndReadAdapter.xtend @@ -1,4 +1,4 @@ -package org.opendaylight.controller.sal.compability +package org.opendaylight.controller.sal.compatibility import org.opendaylight.controller.sal.reader.IPluginInReadService import org.opendaylight.controller.sal.core.NodeConnector @@ -8,8 +8,8 @@ import org.opendaylight.controller.sal.core.NodeTable import org.opendaylight.controller.sal.binding.api.data.DataBrokerService import static extension org.opendaylight.controller.sal.common.util.Arguments.* -import static extension org.opendaylight.controller.sal.compability.NodeMapping.* -import static org.opendaylight.controller.sal.compability.MDFlowMapping.* +import static extension org.opendaylight.controller.sal.compatibility.NodeMapping.* +import static org.opendaylight.controller.sal.compatibility.MDFlowMapping.* import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryMapping.xtend b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryMapping.xtend new file mode 100644 index 0000000000..0ea991830b --- /dev/null +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryMapping.xtend @@ -0,0 +1,77 @@ +/* + * 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.compatibility + +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef + +class InventoryMapping { + + static def org.opendaylight.controller.sal.core.NodeConnector toAdNodeConnector( + InstanceIdentifier identifier) { + val tpKey = (identifier.path.last as IdentifiableItem).key; + return nodeConnectorFromId(tpKey.id.value); + } + + static def org.opendaylight.controller.sal.core.Node toAdNode(InstanceIdentifier identifier) { + val tpKey = (identifier.path.last as IdentifiableItem).key; + return nodeFromNodeId(tpKey.id.value); + } + + + static def NodeRef toNodeRef(org.opendaylight.controller.sal.core.Node node) { + val nodeId = new NodeKey(new NodeId(node.toNodeId)) + val path = InstanceIdentifier.builder().node(Nodes).child(Node,nodeId).toInstance; + return new NodeRef(path); + } + + static def NodeKey toNodeKey(org.opendaylight.controller.sal.core.Node node) { + val nodeId = new NodeId(node.toNodeId) + return new NodeKey(nodeId); + } + + static def NodeConnectorKey toNodeConnectorKey(org.opendaylight.controller.sal.core.NodeConnector nc) { + val nodeId = new NodeConnectorId(nc.toNodeConnectorId) + return new NodeConnectorKey(nodeId); + } + + static def String toNodeId(org.opendaylight.controller.sal.core.Node node) { + '''ad-sal:«node.type»::«node.nodeIDString»''' + } + + static def String toNodeConnectorId(org.opendaylight.controller.sal.core.NodeConnector nc) { + '''«nc.node.toNodeId»::«nc.nodeConnectorIDString»''' + } + + static def org.opendaylight.controller.sal.core.Node nodeFromNodeId(String nodeId) { + return nodeFromString(nodeId.split("::")) + } + + static def nodeConnectorFromId(String invId) { + return nodeConnectorFromString(invId.split("::")); + } + + private static def org.opendaylight.controller.sal.core.NodeConnector nodeConnectorFromString(String[] string) { + val node = nodeFromString(string.subList(0, 1)); + return org.opendaylight.controller.sal.core.NodeConnector.fromStringNoNode(string.get(2), node); + } + + private static def org.opendaylight.controller.sal.core.Node nodeFromString(String[] strings) { + val type = strings.get(0).substring(6); + org.opendaylight.controller.sal.core.Node.fromString(type, strings.get(1)) + } + +} diff --git a/opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/MDFlowMapping.xtend b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/MDFlowMapping.xtend similarity index 98% rename from opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/MDFlowMapping.xtend rename to opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/MDFlowMapping.xtend index cd03df8398..b43e8af661 100644 --- a/opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/MDFlowMapping.xtend +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/MDFlowMapping.xtend @@ -1,4 +1,4 @@ -package org.opendaylight.controller.sal.compability; +package org.opendaylight.controller.sal.compatibility; import com.google.common.net.InetAddresses import java.math.BigInteger @@ -73,8 +73,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.EtherTyp import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanPcp -import static extension org.opendaylight.controller.sal.compability.FromSalConversionsUtils.* -import static extension org.opendaylight.controller.sal.compability.NodeMapping.* +import static extension org.opendaylight.controller.sal.compatibility.FromSalConversionsUtils.* +import static extension org.opendaylight.controller.sal.compatibility.NodeMapping.* import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.OriginalFlowBuilder import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.UpdatedFlowBuilder import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Instructions diff --git a/opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/NodeMapping.xtend b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/NodeMapping.xtend similarity index 98% rename from opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/NodeMapping.xtend rename to opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/NodeMapping.xtend index 2a771def12..b180d86c32 100644 --- a/opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/NodeMapping.xtend +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/NodeMapping.xtend @@ -1,4 +1,4 @@ -package org.opendaylight.controller.sal.compability +package org.opendaylight.controller.sal.compatibility import org.opendaylight.controller.sal.core.Node import org.opendaylight.controller.sal.core.NodeConnector diff --git a/opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/ProtocolConstants.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ProtocolConstants.java similarity index 88% rename from opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/ProtocolConstants.java rename to opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ProtocolConstants.java index 1828dac464..7392f5c763 100644 --- a/opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/ProtocolConstants.java +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ProtocolConstants.java @@ -1,4 +1,4 @@ -package org.opendaylight.controller.sal.compability; +package org.opendaylight.controller.sal.compatibility; public class ProtocolConstants { // source: http://en.wikipedia.org/wiki/Ethertype diff --git a/opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/ToSalConversionsUtils.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ToSalConversionsUtils.java similarity index 98% rename from opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/ToSalConversionsUtils.java rename to opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ToSalConversionsUtils.java index 41b425ef2d..5009e5dfb7 100644 --- a/opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/ToSalConversionsUtils.java +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ToSalConversionsUtils.java @@ -1,6 +1,7 @@ -package org.opendaylight.controller.sal.compability; +package org.opendaylight.controller.sal.compatibility; import com.google.common.net.InetAddresses; + import org.opendaylight.controller.sal.action.Controller; import org.opendaylight.controller.sal.action.Drop; import org.opendaylight.controller.sal.action.Flood; @@ -91,10 +92,10 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import static org.opendaylight.controller.sal.compability.ProtocolConstants.ETHERNET_ARP; -import static org.opendaylight.controller.sal.compability.ProtocolConstants.SCTP; -import static org.opendaylight.controller.sal.compability.ProtocolConstants.TCP; -import static org.opendaylight.controller.sal.compability.ProtocolConstants.UDP; +import static org.opendaylight.controller.sal.compatibility.ProtocolConstants.ETHERNET_ARP; +import static org.opendaylight.controller.sal.compatibility.ProtocolConstants.SCTP; +import static org.opendaylight.controller.sal.compatibility.ProtocolConstants.TCP; +import static org.opendaylight.controller.sal.compatibility.ProtocolConstants.UDP; import static org.opendaylight.controller.sal.match.MatchType.DL_DST; import static org.opendaylight.controller.sal.match.MatchType.DL_SRC; import static org.opendaylight.controller.sal.match.MatchType.DL_TYPE; diff --git a/opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/adsal/DataPacketServiceAdapter.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/adsal/DataPacketServiceAdapter.java similarity index 92% rename from opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/adsal/DataPacketServiceAdapter.java rename to opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/adsal/DataPacketServiceAdapter.java index 8efa17340d..aa67600124 100644 --- a/opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/adsal/DataPacketServiceAdapter.java +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/adsal/DataPacketServiceAdapter.java @@ -1,6 +1,6 @@ -package org.opendaylight.controller.sal.compability.adsal; +package org.opendaylight.controller.sal.compatibility.adsal; -import org.opendaylight.controller.sal.compability.NodeMapping; +import org.opendaylight.controller.sal.compatibility.NodeMapping; import org.opendaylight.controller.sal.packet.IPluginInDataPacketService; import org.opendaylight.controller.sal.packet.RawPacket; import org.opendaylight.controller.sal.packet.RawPacket; diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/adsal/FlowServiceAdapter.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/adsal/FlowServiceAdapter.java new file mode 100644 index 0000000000..ae427455a4 --- /dev/null +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/adsal/FlowServiceAdapter.java @@ -0,0 +1,84 @@ +package org.opendaylight.controller.sal.compatibility.adsal; + +import java.util.concurrent.Future; + +import org.opendaylight.controller.sal.binding.api.NotificationProviderService; +import org.opendaylight.controller.sal.common.util.Futures; +import org.opendaylight.controller.sal.common.util.Rpcs; +import org.opendaylight.controller.sal.compatibility.InventoryMapping; +import org.opendaylight.controller.sal.compatibility.NodeMapping; +import org.opendaylight.controller.sal.compatibility.ToSalConversionsUtils; +import org.opendaylight.controller.sal.core.ConstructionException; +import org.opendaylight.controller.sal.flowprogrammer.Flow; +import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerListener; +import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerService; +import org.opendaylight.controller.sal.utils.Status; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowRemovedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class FlowServiceAdapter implements SalFlowService, IFlowProgrammerListener { + + private static final Logger LOG = LoggerFactory.getLogger(FlowServiceAdapter.class); + + private IFlowProgrammerService delegate; + + private NotificationProviderService publish; + + @Override + public void flowRemoved(org.opendaylight.controller.sal.core.Node node, Flow flow) { + FlowRemovedBuilder flowRemovedBuilder = new FlowRemovedBuilder(); + flowRemovedBuilder.setNode(InventoryMapping.toNodeRef(node)); + publish.publish(flowRemovedBuilder.build()); + } + + @Override + public void flowErrorReported(org.opendaylight.controller.sal.core.Node node, long rid, Object err) { + // TODO Auto-generated method stub + + } + + @Override + public Future> addFlow(AddFlowInput input) { + + Flow flow = ToSalConversionsUtils.toFlow(input); + @SuppressWarnings("unchecked") + org.opendaylight.controller.sal.core.Node node = InventoryMapping.toAdNode((InstanceIdentifier) input + .getNode().getValue()); + Status status = delegate.addFlowAsync(node, flow); + Void rpcResultType = null; + return Futures.immediateFuture(Rpcs.getRpcResult(status.isSuccess(), rpcResultType, null)); + } + + @Override + public Future> removeFlow(RemoveFlowInput input) { + + Flow flow = ToSalConversionsUtils.toFlow(input); + @SuppressWarnings("unchecked") + org.opendaylight.controller.sal.core.Node node = InventoryMapping.toAdNode((InstanceIdentifier) input + .getNode().getValue()); + Status status = delegate.removeFlowAsync(node, flow); + Void rpcResultType = null; + return Futures.immediateFuture(Rpcs.getRpcResult(status.isSuccess(), rpcResultType, null)); + + } + + @Override + public Future> updateFlow(UpdateFlowInput input) { + @SuppressWarnings("unchecked") + org.opendaylight.controller.sal.core.Node node = InventoryMapping.toAdNode((InstanceIdentifier) input + .getNode().getValue()); + Flow originalFlow = ToSalConversionsUtils.toFlow(input.getOriginalFlow()); + Flow updatedFlow = ToSalConversionsUtils.toFlow(input.getUpdatedFlow()); + Status status = delegate.modifyFlowAsync(node, originalFlow, updatedFlow); + Void rpcResultType = null; + return Futures.immediateFuture(Rpcs.getRpcResult(status.isSuccess(), rpcResultType, null)); + } +} diff --git a/opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/adsal/FlowStatisticsAdapter.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/adsal/FlowStatisticsAdapter.java similarity index 98% rename from opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/adsal/FlowStatisticsAdapter.java rename to opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/adsal/FlowStatisticsAdapter.java index 3963aacd03..f5c5620d7c 100644 --- a/opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/adsal/FlowStatisticsAdapter.java +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/adsal/FlowStatisticsAdapter.java @@ -1,4 +1,4 @@ -package org.opendaylight.controller.sal.compability.adsal; +package org.opendaylight.controller.sal.compatibility.adsal; import java.math.BigInteger; import java.util.ArrayList; @@ -8,8 +8,8 @@ import java.util.concurrent.Future; import org.opendaylight.controller.sal.binding.api.NotificationProviderService; import org.opendaylight.controller.sal.common.util.Futures; import org.opendaylight.controller.sal.common.util.Rpcs; -import org.opendaylight.controller.sal.compability.NodeMapping; -import org.opendaylight.controller.sal.compability.ToSalConversionsUtils; +import org.opendaylight.controller.sal.compatibility.NodeMapping; +import org.opendaylight.controller.sal.compatibility.ToSalConversionsUtils; import org.opendaylight.controller.sal.core.ConstructionException; import org.opendaylight.controller.sal.core.Node; import org.opendaylight.controller.sal.flowprogrammer.Flow; diff --git a/opendaylight/md-sal/sal-compability/src/test/java/org/opendaylight/controller/sal/compability/TestFromSalConversionsUtils.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/test/TestFromSalConversionsUtils.java similarity index 85% rename from opendaylight/md-sal/sal-compability/src/test/java/org/opendaylight/controller/sal/compability/TestFromSalConversionsUtils.java rename to opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/test/TestFromSalConversionsUtils.java index e6d05553ef..c37cce0837 100644 --- a/opendaylight/md-sal/sal-compability/src/test/java/org/opendaylight/controller/sal/compability/TestFromSalConversionsUtils.java +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/test/TestFromSalConversionsUtils.java @@ -1,60 +1,32 @@ -package org.opendaylight.controller.sal.compability; +/* + * 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.compatibility.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; -import static org.opendaylight.controller.sal.compability.ProtocolConstants.ETHERNET_ARP; -import static org.opendaylight.controller.sal.compability.ProtocolConstants.SCTP; -import static org.opendaylight.controller.sal.compability.ProtocolConstants.TCP; -import static org.opendaylight.controller.sal.compability.ProtocolConstants.UDP; +import static org.opendaylight.controller.sal.compatibility.ProtocolConstants.ETHERNET_ARP; +import static org.opendaylight.controller.sal.compatibility.ProtocolConstants.SCTP; +import static org.opendaylight.controller.sal.compatibility.ProtocolConstants.TCP; +import static org.opendaylight.controller.sal.compatibility.ProtocolConstants.UDP; import java.util.ArrayList; import java.util.List; import org.junit.Test; -import org.opendaylight.controller.sal.action.Action; -import org.opendaylight.controller.sal.action.Flood; -import org.opendaylight.controller.sal.action.FloodAll; -import org.opendaylight.controller.sal.action.HwPath; -import org.opendaylight.controller.sal.action.Loopback; -import org.opendaylight.controller.sal.action.PopVlan; -import org.opendaylight.controller.sal.action.PushVlan; -import org.opendaylight.controller.sal.action.SetDlDst; -import org.opendaylight.controller.sal.action.SetDlSrc; -import org.opendaylight.controller.sal.action.SetDlType; -import org.opendaylight.controller.sal.action.SetNextHop; -import org.opendaylight.controller.sal.action.SetNwDst; -import org.opendaylight.controller.sal.action.SetNwSrc; -import org.opendaylight.controller.sal.action.SetNwTos; -import org.opendaylight.controller.sal.action.SetTpDst; -import org.opendaylight.controller.sal.action.SetTpSrc; -import org.opendaylight.controller.sal.action.SetVlanCfi; -import org.opendaylight.controller.sal.action.SetVlanId; -import org.opendaylight.controller.sal.action.SetVlanPcp; -import org.opendaylight.controller.sal.action.SwPath; +import org.opendaylight.controller.sal.action.*; +import org.opendaylight.controller.sal.compatibility.MDFlowMapping; +import org.opendaylight.controller.sal.compatibility.ToSalConversionsUtils; import org.opendaylight.controller.sal.flowprogrammer.Flow; import org.opendaylight.controller.sal.match.Match; import org.opendaylight.controller.sal.match.MatchType; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.NodeFlow; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.FloodAction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.FloodAllAction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.HwPathAction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.LoopbackAction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.PopVlanAction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.PushVlanAction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.SetDlDstAction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.SetDlSrcAction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.SetDlTypeAction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.SetNextHopAction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.SetNwDstAction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.SetNwSrcAction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.SetNwTosAction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.SetTpDstAction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.SetTpSrcAction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.SetVlanCfiAction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.SetVlanIdAction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.SetVlanPcpAction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.SwPathAction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.*; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.address.Address; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.address.address.Ipv4; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match; diff --git a/opendaylight/md-sal/sal-compability/src/test/java/org/opendaylight/controller/sal/compability/TestToSalConversionsUtils.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/test/TestToSalConversionsUtils.java similarity index 82% rename from opendaylight/md-sal/sal-compability/src/test/java/org/opendaylight/controller/sal/compability/TestToSalConversionsUtils.java rename to opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/test/TestToSalConversionsUtils.java index 615eca0a67..e251dd02a0 100644 --- a/opendaylight/md-sal/sal-compability/src/test/java/org/opendaylight/controller/sal/compability/TestToSalConversionsUtils.java +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/test/TestToSalConversionsUtils.java @@ -1,77 +1,43 @@ -package org.opendaylight.controller.sal.compability; +/* + * 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.compatibility.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.math.BigInteger; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; -import com.google.common.net.InetAddresses; import org.junit.Test; -import org.opendaylight.controller.sal.action.Flood; -import org.opendaylight.controller.sal.action.FloodAll; -import org.opendaylight.controller.sal.action.HwPath; -import org.opendaylight.controller.sal.action.Loopback; -import org.opendaylight.controller.sal.action.Output; -import org.opendaylight.controller.sal.action.PopVlan; -import org.opendaylight.controller.sal.action.PushVlan; -import org.opendaylight.controller.sal.action.SetDlDst; -import org.opendaylight.controller.sal.action.SetDlSrc; -import org.opendaylight.controller.sal.action.SetDlType; -import org.opendaylight.controller.sal.action.SetNextHop; -import org.opendaylight.controller.sal.action.SetNwDst; -import org.opendaylight.controller.sal.action.SetNwSrc; -import org.opendaylight.controller.sal.action.SetNwTos; -import org.opendaylight.controller.sal.action.SetTpDst; -import org.opendaylight.controller.sal.action.SetTpSrc; -import org.opendaylight.controller.sal.action.SetVlanCfi; -import org.opendaylight.controller.sal.action.SetVlanId; -import org.opendaylight.controller.sal.action.SetVlanPcp; -import org.opendaylight.controller.sal.action.SwPath; +import org.opendaylight.controller.sal.action.*; +import org.opendaylight.controller.sal.compatibility.ToSalConversionsUtils; import org.opendaylight.controller.sal.flowprogrammer.Flow; import org.opendaylight.controller.sal.match.MatchType; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Dscp; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.*; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowAddedBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.NodeFlow; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.VlanCfi; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.ControllerActionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.DropActionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.FloodActionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.FloodAllActionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.HwPathActionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.LoopbackActionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.OutputActionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.PopMplsActionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.PopVlanActionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.PushMplsActionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.PushPbbActionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.PushVlanActionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.SetDlDstActionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.SetDlSrcActionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.SetDlTypeActionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.SetMplsTtlActionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.SetNextHopActionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.SetNwDstActionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.SetNwSrcActionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.SetNwTosActionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.SetNwTtlActionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.SetQueueActionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.SetTpDstActionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.SetTpSrcActionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.SetVlanCfiActionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.SetVlanIdActionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.SetVlanPcpActionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.SwPathActionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.list.Action; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.list.ActionBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.action.*; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.address.Address; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.address.address.Ipv4Builder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.address.address.Ipv6Builder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.list.Action; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.action.list.ActionBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Instructions; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActions; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.EtherType; @@ -79,20 +45,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId; import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanPcp; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.arp.match.fields.ArpSourceHardwareAddressBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.arp.match.fields.ArpTargetHardwareAddressBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetDestination; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetDestinationBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetSource; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetSourceBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetType; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetTypeBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatch; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatchBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.IpMatch; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.IpMatchBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer4Match; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatch; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.*; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.*; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatchBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6MatchBuilder; @@ -100,21 +54,15 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatchBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.UdpMatchBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanIdBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActions; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsBuilder; -import java.math.BigInteger; -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import com.google.common.net.InetAddresses; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.opendaylight.controller.sal.compability.ProtocolConstants.ETHERNET_ARP; -import static org.opendaylight.controller.sal.compability.ProtocolConstants.SCTP; -import static org.opendaylight.controller.sal.compability.ProtocolConstants.TCP; -import static org.opendaylight.controller.sal.compability.ProtocolConstants.UDP; +import static org.opendaylight.controller.sal.compatibility.ProtocolConstants.ETHERNET_ARP; +import static org.opendaylight.controller.sal.compatibility.ProtocolConstants.SCTP; +import static org.opendaylight.controller.sal.compatibility.ProtocolConstants.TCP; +import static org.opendaylight.controller.sal.compatibility.ProtocolConstants.UDP; public class TestToSalConversionsUtils { // prefix: diff --git a/opendaylight/md-sal/model/model-topology/pom.xml b/opendaylight/md-sal/model/model-topology/pom.xml new file mode 100644 index 0000000000..c91b9dd53a --- /dev/null +++ b/opendaylight/md-sal/model/model-topology/pom.xml @@ -0,0 +1,31 @@ + + + + model-parent + org.opendaylight.controller.model + 1.0-SNAPSHOT + + + scm:git:ssh://git.opendaylight.org:29418/controller.git + scm:git:ssh://git.opendaylight.org:29418/controller.git + https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL + + + 4.0.0 + model-topology + bundle + + + + org.opendaylight.controller.model + model-inventory + 1.0-SNAPSHOT + + + org.opendaylight.yangtools.model + ietf-topology + 2013.07.12.2-SNAPSHOT + + + diff --git a/opendaylight/md-sal/model/model-topology/src/main/yang/opendaylight-topology-inventory.yang b/opendaylight/md-sal/model/model-topology/src/main/yang/opendaylight-topology-inventory.yang new file mode 100644 index 0000000000..33c03ba059 --- /dev/null +++ b/opendaylight/md-sal/model/model-topology/src/main/yang/opendaylight-topology-inventory.yang @@ -0,0 +1,34 @@ +module opendaylight-topology-inventory { + yang-version 1; + namespace "urn:opendaylight:model:topology:inventory"; + // replace with IANA namespace when assigned + prefix "nt"; + + import yang-ext { prefix "ext"; } + import ietf-inet-types { prefix "inet"; } + import opendaylight-inventory {prefix "inv";} + import opendaylight-topology {prefix "odt";} + import network-topology {prefix "topo";} + + organization "TBD"; + + contact "WILL-BE-DEFINED-LATER"; + + revision 2013-10-30 { + description + "Initial revision."; + } + + augment "/topo:network-topology/topo:topology/topo:node" { + ext:augment-identifier "inventory-node"; + uses inv:node-context-ref; + } + + augment "/topo:network-topology/topo:topology/topo:node/topo:termination-point" { + ext:augment-identifier "inventory-node-connector"; + leaf node-connector { + ext:context-reference "inv:node-connector-context"; + type inv:node-connector-ref; + } + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/model/model-topology/src/main/yang/opendaylight-topology.yang b/opendaylight/md-sal/model/model-topology/src/main/yang/opendaylight-topology.yang new file mode 100644 index 0000000000..038a1b7c67 --- /dev/null +++ b/opendaylight/md-sal/model/model-topology/src/main/yang/opendaylight-topology.yang @@ -0,0 +1,64 @@ +module opendaylight-topology { + yang-version 1; + namespace "urn:opendaylight:model:topology:general"; + // replace with IANA namespace when assigned + prefix "nt"; + + import yang-ext { prefix "ext"; } + import ietf-inet-types { prefix "inet"; } + import opendaylight-inventory {prefix "inv";} + import network-topology {prefix "topo";} + + organization "TBD"; + + contact "WILL-BE-DEFINED-LATER"; + + revision 2013-10-30 { + description + "Initial revision."; + } + + identity node-type { + + } + + typedef node-type-ref { + type identityref { + base node-type; + } + } + + identity topology-context { + + } + + identity topology-node-context { + + } + + grouping node-identifiers { + list node-identifier { + key "type identifier"; + leaf type { + type node-type-ref; + } + leaf identifier { + type inet:uri; + } + } + } + + augment "/topo:network-topology/topo:topology" { + ext:context-instance "topology-context"; + } + + /* Inventory Augmentations */ + augment "/topo:network-topology/topo:topology/topo:node" { + ext:context-instance "topology-node-context"; + } + + augment "/topo:network-topology/topo:topology/topo:node" { + ext:augment-identifier "identifiable-node"; + uses node-identifiers; + } +} diff --git a/opendaylight/md-sal/model/model-topology/src/main/yang/topology-view.yang b/opendaylight/md-sal/model/model-topology/src/main/yang/topology-view.yang new file mode 100644 index 0000000000..2fecb327ca --- /dev/null +++ b/opendaylight/md-sal/model/model-topology/src/main/yang/topology-view.yang @@ -0,0 +1,48 @@ +module opendaylight-topology-view { + yang-version 1; + namespace "urn:opendaylight:model:topology:view"; + // replace with IANA namespace when assigned + prefix "nt"; + + import yang-ext { prefix "ext"; } + import ietf-inet-types { prefix "inet"; } + import network-topology {prefix "topo";} + import opendaylight-topology {prefix "odl";} + + organization "TBD"; + + contact "WILL-BE-DEFINED-LATER"; + + revision 2013-10-30 { + description + "Initial revision."; + } + + + grouping aggregate-topology { + leaf-list original-topology { + type topo:topology-ref; + } + } + + grouping aggregate-node { + list original-node { + leaf topology { + type topo:topology-ref; + } + leaf node { + type topo:node-ref; + } + } + } + + augment "/topo:network-topology/topo:topology" { + ext:augment-identifier "aggregated-topology"; + uses aggregate-topology; + } + + augment "/topo:network-topology/topo:topology/topo:node" { + ext:augment-identifier "aggregated-node"; + uses aggregate-node; + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/model/pom.xml b/opendaylight/md-sal/model/pom.xml index ca97232cfb..eccb691fa7 100644 --- a/opendaylight/md-sal/model/pom.xml +++ b/opendaylight/md-sal/model/pom.xml @@ -28,6 +28,7 @@ model-flow-service model-flow-statistics model-flow-management + model-topology diff --git a/opendaylight/md-sal/pom.xml b/opendaylight/md-sal/pom.xml index a6740fabac..fd89da4dd0 100644 --- a/opendaylight/md-sal/pom.xml +++ b/opendaylight/md-sal/pom.xml @@ -27,7 +27,8 @@ sal-binding-api sal-binding-config sal-binding-broker - sal-binding-it + + sal-binding-util samples @@ -35,20 +36,36 @@ model - - sal-compability sal-connector-api sal-rest-connector - flow-management-compatibility clustered-data-store/implementation - clustered-data-store/integrationtest + inventory-manager + + compatibility + + sal-zeromq-connector + test + + + + integrationtests + + false + + + sal-binding-it + clustered-data-store/integrationtest + + + + UTF-8 http://nexus.opendaylight.org/content @@ -319,8 +336,7 @@ jacoco-maven-plugin ${jacoco.version} - + org.eclipse.m2e lifecycle-mapping @@ -349,6 +365,23 @@ + + + org.jacoco + + jacoco-maven-plugin + + + [0.5.3.201107060350,) + + + prepare-agent + + + + + + diff --git a/opendaylight/md-sal/sal-binding-api/pom.xml b/opendaylight/md-sal/sal-binding-api/pom.xml index c1dccdf532..cfbd4f7b71 100644 --- a/opendaylight/md-sal/sal-binding-api/pom.xml +++ b/opendaylight/md-sal/sal-binding-api/pom.xml @@ -38,6 +38,7 @@ org.osgi org.osgi.core ${osgi.core.version} + provided diff --git a/opendaylight/md-sal/sal-binding-broker/pom.xml b/opendaylight/md-sal/sal-binding-broker/pom.xml index b8b37af58e..9ca025b393 100644 --- a/opendaylight/md-sal/sal-binding-broker/pom.xml +++ b/opendaylight/md-sal/sal-binding-broker/pom.xml @@ -77,12 +77,14 @@ ${project.groupId}.${project.artifactId} + + org.opendaylight.controller.sal.binding.spi.*, + org.opendaylight.controller.config.yang.md.sal.binding.impl, - org.opendaylight.controller.sal.binding.spi, - org.opendaylight.controller.sal.binding.spi.*, org.opendaylight.controller.sal.binding.impl, org.opendaylight.controller.sal.binding.impl.*, + org.opendaylight.controller.sal.binding.codegen, org.opendaylight.controller.sal.binding.codegen.*, diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/BindingAwareBrokerImpl.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/BindingAwareBrokerImpl.xtend index 75655419b0..d9a3dd547f 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/BindingAwareBrokerImpl.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/BindingAwareBrokerImpl.xtend @@ -186,7 +186,7 @@ class BindingAwareBrokerImpl implements BindingAwareBroker, AutoCloseable { def registerRpcImplementation(Class type, T service, OsgiProviderContext context, Hashtable properties) { val proxy = getManagedDirectProxy(type) - checkState(proxy.delegate === null, "The Service for type {} is already registered", type) + checkState(proxy.delegate === null, "The Service for type %s is already registered", type) val osgiReg = context.bundleContext.registerService(type, service, properties); proxy.delegate = service; diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataBrokerImpl.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataBrokerImpl.xtend index 9356ecda88..6ed63b21dd 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataBrokerImpl.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataBrokerImpl.xtend @@ -5,23 +5,13 @@ 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.sal.binding.api.data.DataModificationTransaction -import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction.DataTransactionListener 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.api.data.DataReader import org.opendaylight.yangtools.concepts.AbstractObjectRegistration import org.opendaylight.yangtools.concepts.ListenerRegistration -import static extension org.opendaylight.controller.sal.binding.impl.util.MapUtils.*; -import java.util.Collection -import java.util.Map.Entry -import java.util.HashSet -import java.util.Set import com.google.common.collect.Multimap import static com.google.common.base.Preconditions.*; import java.util.List -import java.util.LinkedList -import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider import com.google.common.collect.HashMultimap import java.util.concurrent.ExecutorService import java.util.concurrent.Callable @@ -30,15 +20,17 @@ 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.common.util.RpcErrors +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; - Multimap configReaders = HashMultimap.create(); - Multimap operationalReaders = HashMultimap.create(); + val dataReadRouter = new BindingAwareDataReaderRouter; + Multimap listeners = HashMultimap.create(); Multimap commitHandlers = HashMultimap.create(); @@ -47,13 +39,11 @@ class DataBrokerImpl extends DeprecatedDataAPISupport implements DataProviderSer } override readConfigurationData(InstanceIdentifier path) { - val readers = configReaders.getAllChildren(path); - return readers.readConfiguration(path); + return dataReadRouter.readConfigurationData(path); } override readOperationalData(InstanceIdentifier path) { - val readers = operationalReaders.getAllChildren(path); - return readers.readOperational(path); + return dataReadRouter.readOperationalData(path); } override registerCommitHandler(InstanceIdentifier path, @@ -69,20 +59,12 @@ class DataBrokerImpl extends DeprecatedDataAPISupport implements DataProviderSer return reg; } - override registerDataReader(InstanceIdentifier path, - DataReader, DataObject> provider) { - val ret = new DataReaderRegistration(provider, this); - ret.paths.add(path); - configReaders.put(path, ret); - operationalReaders.put(path, ret); - return ret; - } - - protected def removeReader(DataReaderRegistration reader) { - for (path : reader.paths) { - operationalReaders.remove(path, reader); - configReaders.remove(path, reader); - } + override registerDataReader(InstanceIdentifier path,DataReader,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) { @@ -92,39 +74,8 @@ class DataBrokerImpl extends DeprecatedDataAPISupport implements DataProviderSer protected def removeCommitHandler(DataCommitHandlerRegistration registration) { commitHandlers.remove(registration.path, registration); } - - protected def DataObject readConfiguration( - Collection> entries, - InstanceIdentifier path) { - - val List partialResults = new LinkedList(); - for (entry : entries) { - partialResults.add(entry.value.instance.readConfigurationData(path)) - } - return merge(path, partialResults); - } - - protected def DataObject readOperational( - Collection> entries, - InstanceIdentifier path) { - - val List partialResults = new LinkedList(); - for (entry : entries) { - partialResults.add(entry.value.instance.readOperationalData(path)) - } - return merge(path, partialResults); - } - - protected def DataObject merge(InstanceIdentifier identifier, List objects) { - - // FIXME: implement real merge - if (objects.size > 0) { - return objects.get(0); - } - } protected def getActiveCommitHandlers() { - return commitHandlers.entries.map[ value.instance].toSet } @@ -137,26 +88,6 @@ class DataBrokerImpl extends DeprecatedDataAPISupport implements DataProviderSer } -package class DataReaderRegistration extends // -AbstractObjectRegistration, DataObject>> { - - DataBrokerImpl dataBroker; - - @Property - val Set> paths; - - new(DataReader, DataObject> instance, DataBrokerImpl broker) { - super(instance) - dataBroker = broker; - _paths = new HashSet(); - } - - override protected removeRegistration() { - dataBroker.removeReader(this); - } - -} - package class DataChangeListenerRegistration extends AbstractObjectRegistration implements ListenerRegistration { DataBrokerImpl dataBroker; diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataProviderContext.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataProviderContext.xtend deleted file mode 100644 index 398a2196c6..0000000000 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataProviderContext.xtend +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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.binding.impl - -import org.opendaylight.controller.sal.common.DataStoreIdentifier -import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider - -class DataProviderContext { - - @Property - var DataStoreIdentifier identifier; - @Property - var RuntimeDataProvider provider; -} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/util/BindingAwareDataReaderRouter.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/util/BindingAwareDataReaderRouter.xtend new file mode 100644 index 0000000000..f586a8b4c5 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/util/BindingAwareDataReaderRouter.xtend @@ -0,0 +1,13 @@ +package org.opendaylight.controller.sal.binding.impl.util + +import org.opendaylight.controller.md.sal.common.impl.routing.AbstractDataReadRouter +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier +import org.opendaylight.yangtools.yang.binding.DataObject + +class BindingAwareDataReaderRouter extends AbstractDataReadRouter, DataObject> { + + override protected merge(InstanceIdentifier path, Iterable data) { + return data.iterator.next; + } + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-binding-util/pom.xml b/opendaylight/md-sal/sal-binding-util/pom.xml new file mode 100644 index 0000000000..26041ea85e --- /dev/null +++ b/opendaylight/md-sal/sal-binding-util/pom.xml @@ -0,0 +1,33 @@ + + 4.0.0 + + org.opendaylight.controller + sal-parent + 1.0-SNAPSHOT + + sal-binding-util + bundle + + scm:git:ssh://git.opendaylight.org:29418/controller.git + scm:git:ssh://git.opendaylight.org:29418/controller.git + https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL + + + + + com.google.guava + guava + + + org.opendaylight.controller + sal-binding-api + 1.0-SNAPSHOT + + + org.apache.felix + org.apache.felix.dependencymanager + 3.1.0 + + + diff --git a/opendaylight/md-sal/sal-binding-util/src/main/java/org/opendaylight/controller/md/sal/binding/util/TypeSafeDataReader.java b/opendaylight/md-sal/sal-binding-util/src/main/java/org/opendaylight/controller/md/sal/binding/util/TypeSafeDataReader.java new file mode 100644 index 0000000000..738a14a9bd --- /dev/null +++ b/opendaylight/md-sal/sal-binding-util/src/main/java/org/opendaylight/controller/md/sal/binding/util/TypeSafeDataReader.java @@ -0,0 +1,38 @@ +package org.opendaylight.controller.md.sal.binding.util; + +import org.opendaylight.controller.md.sal.common.api.data.DataReader; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public final class TypeSafeDataReader { + + + private final DataReader,DataObject> delegate; + + + + public DataReader, DataObject> getDelegate() { + return delegate; + } + + + public TypeSafeDataReader(DataReader, DataObject> delegate) { + this.delegate = delegate; + } + + + @SuppressWarnings("unchecked") + public D readConfigurationData(InstanceIdentifier path) { + return (D) delegate.readConfigurationData(path); + } + + + @SuppressWarnings("unchecked") + public D readOperationalData(InstanceIdentifier path) { + return (D) delegate.readOperationalData(path); + } + + public static TypeSafeDataReader forReader(DataReader, DataObject> delegate) { + return new TypeSafeDataReader(delegate); + } +} diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataChange.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataChange.java index 0fea50b777..55565252a2 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataChange.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataChange.java @@ -13,19 +13,102 @@ import java.util.Set; // FIXME: After 0.6 Release of YANGTools refactor to use Path marker interface for arguments. // import org.opendaylight.yangtools.concepts.Path; +public interface DataChange

*/, D> { -public interface DataChange

*/,D> { + /** + * Returns a map of paths and newly created objects + * + * @return map of paths and newly created objects + */ + Map getCreatedOperationalData(); - Map getCreatedOperationalData(); + /** + * Returns a map of paths and newly created objects + * + * @return map of paths and newly created objects + */ + Map getCreatedConfigurationData(); - Map getUpdatedOperationalData(); + /** + * Returns a map of paths and respective updated objects after update. + * + * Original state of the object is in + * {@link #getOriginalOperationalData()} + * + * @return map of paths and newly created objects + */ + Map getUpdatedOperationalData(); + /** + * Returns a map of paths and respective updated objects after update. + * + * Original state of the object is in + * {@link #getOriginalConfigurationData()} + * + * @return map of paths and newly created objects + */ + Map getUpdatedConfigurationData(); + + /** + * Returns a set of paths of removed objects. + * + * Original state of the object is in + * {@link #getOriginalConfigurationData()} + * + * @return map of paths and newly created objects + */ + Set

getRemovedConfigurationData(); + + /** + * Returns a set of paths of removed objects. + * + * Original state of the object is in + * {@link #getOriginalOperationalData()} + * + * @return map of paths and newly created objects + */ Set

getRemovedOperationalData(); - Map getCreatedConfigurationData(); + /** + * Return a map of paths and original state of updated and removed objectd. + * + * @return map of paths and original state of updated and removed objectd. + */ + Map getOriginalConfigurationData(); - Map getUpdatedConfigurationData(); + /** + * Return a map of paths and original state of updated and removed objectd. + * + * @return map of paths and original state of updated and removed objectd. + */ + Map getOriginalOperationalData(); - Set

getRemovedConfigurationData(); + /** + * Returns a original subtree of data, which starts at the path + * where listener was registered. + * + */ + D getOriginalConfigurationSubtree(); + + /** + * Returns a original subtree of data, which starts at the path + * where listener was registered. + * + */ + D getOriginalOperationalSubtree(); + + /** + * Returns a new subtree of data, which starts at the path + * where listener was registered. + * + */ + D getUpdatedConfigurationSubtree(); + + /** + * Returns a new subtree of data, which starts at the path + * where listener was registered. + * + */ + D getUpdatedOperationalSubtree(); } diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataCommitHandler.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataCommitHandler.java index 85e3d8f57c..90de13d15e 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataCommitHandler.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataCommitHandler.java @@ -84,7 +84,7 @@ import org.opendaylight.yangtools.yang.common.RpcResult; */ public interface DataCommitHandler

*/,D> { - + DataCommitTransaction requestCommit(DataModification modification); public interface DataCommitTransaction

*/,D> { diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataStore.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataStore.java new file mode 100644 index 0000000000..f448d4e2ee --- /dev/null +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataStore.java @@ -0,0 +1,16 @@ +package org.opendaylight.controller.md.sal.common.api.data; + +public interface DataStore extends // + DataReader, // + DataModificationTransactionFactory { + + @Override + public DataModification beginTransaction(); + + @Override + public D readConfigurationData(P path); + + @Override + public D readOperationalData(P path); + +} diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/Route.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/Route.java new file mode 100644 index 0000000000..afe9e9921e --- /dev/null +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/Route.java @@ -0,0 +1,10 @@ +package org.opendaylight.controller.md.sal.common.api.routing; + +import org.opendaylight.yangtools.concepts.Immutable; + +public interface Route extends Immutable { + + C getType(); + + P getPath(); +} diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/RouteChangeListener.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/RouteChangeListener.java new file mode 100644 index 0000000000..994f65b960 --- /dev/null +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/RouteChangeListener.java @@ -0,0 +1,8 @@ +package org.opendaylight.controller.md.sal.common.api.routing; + +import java.util.EventListener; + +public interface RouteChangeListener extends EventListener { + + void onRouteChange(RouteChange change); +} diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/RouteChangePublisher.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/RouteChangePublisher.java new file mode 100644 index 0000000000..89851c9393 --- /dev/null +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/RouteChangePublisher.java @@ -0,0 +1,8 @@ +package org.opendaylight.controller.md.sal.common.api.routing; + +import org.opendaylight.yangtools.concepts.ListenerRegistration; + +public interface RouteChangePublisher { + + ListenerRegistration> registerRouteChangeListener(RouteChangeListener listener); +} diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/Router.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/Router.java new file mode 100644 index 0000000000..8d0a90c50b --- /dev/null +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/Router.java @@ -0,0 +1,10 @@ +package org.opendaylight.controller.md.sal.common.api.routing; + +import java.util.Map; +import java.util.Set; + +public interface Router extends // + RouteChangePublisher { + + Map> getAnnouncedPaths(); +} diff --git a/opendaylight/md-sal/sal-common-impl/pom.xml b/opendaylight/md-sal/sal-common-impl/pom.xml index 0c2344a23e..3bd51ec7d8 100644 --- a/opendaylight/md-sal/sal-common-impl/pom.xml +++ b/opendaylight/md-sal/sal-common-impl/pom.xml @@ -37,7 +37,10 @@ maven-bundle-plugin - org.opendaylight.controller.md.sal.common.impl + + org.opendaylight.controller.md.sal.common.impl, + org.opendaylight.controller.md.sal.common.impl.* + diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/routing/AbstractDataReadRouter.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/routing/AbstractDataReadRouter.java new file mode 100644 index 0000000000..f83c61f804 --- /dev/null +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/routing/AbstractDataReadRouter.java @@ -0,0 +1,187 @@ +package org.opendaylight.controller.md.sal.common.impl.routing; + +import java.util.Map.Entry; + +import org.opendaylight.controller.md.sal.common.api.data.DataReader; +import org.opendaylight.yangtools.concepts.AbstractObjectRegistration; +import org.opendaylight.yangtools.concepts.Path; +import org.opendaylight.yangtools.concepts.Registration; + +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import com.google.common.collect.FluentIterable; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; + +/** + * Base abstract implementation of DataReadRouter, which performs + * a read operation on multiple data readers and then merges result. + * + * @param

+ * @param + */ +public abstract class AbstractDataReadRouter

, D> implements DataReader { + + Multimap> configReaders = HashMultimap.create(); + Multimap> operationalReaders = HashMultimap.create(); + + @Override + public D readConfigurationData(P path) { + FluentIterable dataBits = FluentIterable // + .from(getReaders(configReaders, path)).transform(configurationRead(path)); + return merge(path,dataBits); + } + + @Override + public D readOperationalData(P path) { + FluentIterable dataBits = FluentIterable // + .from(getReaders(configReaders, path)).transform(operationalRead(path)); + return merge(path,dataBits); + + } + + /** + * Merges data readed by reader instances from specified path + * + * @param path Path on which read was performed + * @param data Data which was returned by read operation. + * @return Merged result. + */ + protected abstract D merge(P path,Iterable data); + + /** + * Returns a function which performs configuration read for supplied path + * + * @param path + * @return function which performs configuration read for supplied path + */ + + private Function, D> configurationRead(final P path) { + return new Function, D>() { + @Override + public D apply(DataReader input) { + return input.readConfigurationData(path); + } + }; + } + + /** + * Returns a function which performs operational read for supplied path + * + * @param path + * @return function which performs operational read for supplied path + */ + private Function, D> operationalRead(final P path) { + return new Function, D>() { + @Override + public D apply(DataReader input) { + return input.readConfigurationData(path); + } + }; + } + + // Registrations + + /** + * Register's a reader for operational data. + * + * @param path Path which is served by this reader + * @param reader Reader instance which is responsible for reading particular subpath. + * @return + */ + public Registration> registerOperationalReader(P path, DataReader reader) { + OperationalDataReaderRegistration ret = new OperationalDataReaderRegistration<>(path, reader); + operationalReaders.put(path, ret); + return ret; + } + + public Registration> registerConfigurationReader(P path, DataReader reader) { + ConfigurationDataReaderRegistration ret = new ConfigurationDataReaderRegistration<>(path, reader); + configReaders.put(path, ret); + return ret; + } + + Iterable> getOperationalReaders(P path) { + return getReaders(operationalReaders, path); + } + + Iterable> getConfigurationReaders(P path) { + return getReaders(configReaders, path); + } + + private Iterable> getReaders(Multimap> readerMap, P path) { + return FluentIterable + .from(readerMap.entries()) // + .filter(affects(path)) // + .transform(retrieveInstance()); + } + + private void removeRegistration(OperationalDataReaderRegistration registration) { + operationalReaders.remove(registration.getKey(), registration); + } + + private void removeRegistration(ConfigurationDataReaderRegistration registration) { + configReaders.remove(registration.getKey(), registration); + } + + private Function>, DataReader> retrieveInstance() { + return new Function>, DataReader>() { + @Override + public DataReader apply(Entry> input) { + return input.getValue().getInstance(); + } + }; + } + + private Predicate>> affects(final P path) { + + return new Predicate>>() { + + @Override + public boolean apply(Entry> input) { + final Path key = input.getKey(); + return key.contains(path) || ((Path) path).contains(key); + } + + }; + } + + private class ConfigurationDataReaderRegistration

, D> extends DataReaderRegistration { + + public ConfigurationDataReaderRegistration(P key, DataReader instance) { + super(key, instance); + } + + @Override + protected void removeRegistration() { + AbstractDataReadRouter.this.removeRegistration(this); + } + } + + private class OperationalDataReaderRegistration

, D> extends DataReaderRegistration { + + public OperationalDataReaderRegistration(P key, DataReader instance) { + super(key, instance); + } + + @Override + protected void removeRegistration() { + AbstractDataReadRouter.this.removeRegistration(this); + } + } + + private abstract static class DataReaderRegistration

, D> extends + AbstractObjectRegistration> { + + private final P key; + + public P getKey() { + return this.key; + } + + public DataReaderRegistration(P key, DataReader instance) { + super(instance); + this.key = key; + } + } +} diff --git a/opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/ToSalPropertyClassUtils.java b/opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/ToSalPropertyClassUtils.java new file mode 100644 index 0000000000..08df0a414a --- /dev/null +++ b/opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/ToSalPropertyClassUtils.java @@ -0,0 +1,70 @@ +package org.opendaylight.controller.sal.compability; + +import org.opendaylight.controller.sal.core.*; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortFeatures; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; + +public class ToSalPropertyClassUtils { + public static Bandwidth salAdvertisedBandwidthFrom(NodeConnector nodeConnector) { + FlowCapableNodeConnector flowCapNodeConn = nodeConnector.getAugmentation(FlowCapableNodeConnector.class); + PortFeatures portFeatures = flowCapNodeConn.getAdvertisedFeatures(); + return new AdvertisedBandwidth(resolveBandwidth(portFeatures)); + } + + public static Bandwidth salPeerBandwidthFrom(NodeConnector nodeConnector) { + FlowCapableNodeConnector flowCapNodeConn = nodeConnector.getAugmentation(FlowCapableNodeConnector.class); + PortFeatures portFeatures = flowCapNodeConn.getPeerFeatures(); + return new PeerBandwidth(resolveBandwidth(portFeatures)); + } + + public static Bandwidth salSupportedBandwidthFrom(NodeConnector nodeConnector) { + FlowCapableNodeConnector flowCapNodeConn = nodeConnector.getAugmentation(FlowCapableNodeConnector.class); + PortFeatures portFeatures = flowCapNodeConn.getSupported(); + return new SupportedBandwidth(resolveBandwidth(portFeatures)); + } + + public static MacAddress salMacAddressFrom(NodeConnector nodeConnector) { + FlowCapableNodeConnector flowCapNodeConn = nodeConnector.getAugmentation(FlowCapableNodeConnector.class); + String hwAddress = flowCapNodeConn.getHardwareAddress().getValue(); + return new MacAddress(bytesFrom(hwAddress)); + } + + + public static Name salNameFrom(NodeConnector nodeConnector) { + FlowCapableNodeConnector flowCapNodeConn = nodeConnector.getAugmentation(FlowCapableNodeConnector.class); + return new Name(flowCapNodeConn.getName()); + } + + + + private static byte[] bytesFrom(String hwAddress) { + String[] mac = hwAddress.split(":"); + byte[] macAddress = new byte[6]; // mac.length == 6 bytes + for (int i = 0; i < mac.length; i++) { + macAddress[i] = Integer.decode("0x" + mac[i]).byteValue(); + } + return macAddress; + } + + private static long resolveBandwidth(PortFeatures portFeatures) { + if (portFeatures.is_1tbFd()) { + return Bandwidth.BW1Tbps; + } else if (portFeatures.is_100gbFd()) { + return Bandwidth.BW100Gbps; + } else if (portFeatures.is_40gbFd()) { + return Bandwidth.BW40Gbps; + } else if (portFeatures.is_10gbFd()) { + return Bandwidth.BW10Gbps; + } else if (portFeatures.is_1gbHd() || portFeatures.is_1gbFd()) { + return Bandwidth.BW1Gbps; + } else if (portFeatures.is_100mbHd() || portFeatures.is_100mbFd()) { + return Bandwidth.BW100Mbps; + } else if (portFeatures.is_10mbHd() || portFeatures.is_10mbFd()) { + return Bandwidth.BW10Mbps; + } else { + return Bandwidth.BWUNK; + } + } + +} diff --git a/opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/adsal/FlowServiceAdapter.java b/opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/adsal/FlowServiceAdapter.java deleted file mode 100644 index 809ad76e5a..0000000000 --- a/opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/adsal/FlowServiceAdapter.java +++ /dev/null @@ -1,88 +0,0 @@ -package org.opendaylight.controller.sal.compability.adsal; - -import java.util.concurrent.Future; - -import org.opendaylight.controller.sal.binding.api.NotificationProviderService; -import org.opendaylight.controller.sal.common.util.Futures; -import org.opendaylight.controller.sal.common.util.Rpcs; -import org.opendaylight.controller.sal.compability.NodeMapping; -import org.opendaylight.controller.sal.compability.ToSalConversionsUtils; -import org.opendaylight.controller.sal.core.ConstructionException; -import org.opendaylight.controller.sal.core.Node; -import org.opendaylight.controller.sal.flowprogrammer.Flow; -import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerListener; -import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerService; -import org.opendaylight.controller.sal.utils.Status; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowRemovedBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInput; -import org.opendaylight.yangtools.yang.common.RpcResult; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class FlowServiceAdapter implements SalFlowService, IFlowProgrammerListener { - - private static final Logger LOG = LoggerFactory.getLogger(FlowServiceAdapter.class); - - private IFlowProgrammerService delegate; - - private NotificationProviderService publish; - - @Override - public void flowRemoved(Node node, Flow flow) { - FlowRemovedBuilder flowRemovedBuilder = new FlowRemovedBuilder(); - flowRemovedBuilder.setNode(NodeMapping.toNodeRef(node)); - publish.publish(flowRemovedBuilder.build()); - } - - @Override - public void flowErrorReported(Node node, long rid, Object err) { - // TODO Auto-generated method stub - - } - - @Override - public Future> addFlow(AddFlowInput input) { - try { - Flow flow = ToSalConversionsUtils.toFlow(input); - Node node = NodeMapping.toADNode(input.getNode()); - Status status = delegate.addFlowAsync(node, flow); - Void rpcResultType = null; - return Futures.immediateFuture(Rpcs.getRpcResult(status.isSuccess(), rpcResultType, null)); - } catch (ConstructionException e) { - LOG.error(e.getMessage()); - } - return null; - } - - @Override - public Future> removeFlow(RemoveFlowInput input) { - try { - Flow flow = ToSalConversionsUtils.toFlow(input); - Node node = NodeMapping.toADNode(input.getNode()); - Status status = delegate.removeFlowAsync(node, flow); - Void rpcResultType = null; - return Futures.immediateFuture(Rpcs.getRpcResult(status.isSuccess(), rpcResultType, null)); - } catch (ConstructionException e) { - LOG.error(e.getMessage()); - } - return null; - } - - @Override - public Future> updateFlow(UpdateFlowInput input) { - try { - Node node = NodeMapping.toADNode(input.getNode()); - Flow originalFlow = ToSalConversionsUtils.toFlow(input.getOriginalFlow()); - Flow updatedFlow = ToSalConversionsUtils.toFlow(input.getUpdatedFlow()); - Status status = delegate.modifyFlowAsync(node, originalFlow, updatedFlow); - Void rpcResultType = null; - return Futures.immediateFuture(Rpcs.getRpcResult(status.isSuccess(), rpcResultType, null)); - } catch (ConstructionException e) { - LOG.error(e.getMessage()); - } - return null; - } -} diff --git a/opendaylight/md-sal/sal-connector-api/src/main/java/org/opendaylight/controller/sal/connector/api/RpcRouter.java b/opendaylight/md-sal/sal-connector-api/src/main/java/org/opendaylight/controller/sal/connector/api/RpcRouter.java index 4807c4e200..08fce5783e 100644 --- a/opendaylight/md-sal/sal-connector-api/src/main/java/org/opendaylight/controller/sal/connector/api/RpcRouter.java +++ b/opendaylight/md-sal/sal-connector-api/src/main/java/org/opendaylight/controller/sal/connector/api/RpcRouter.java @@ -11,11 +11,11 @@ import java.util.concurrent.Future; * @param Rpc Type * @param Data Type */ -public interface RpcRouter { +public interface RpcRouter { - Future> sendRpc(RpcRequest input); + Future> sendRpc(RpcRequest input); /** @@ -27,17 +27,17 @@ public interface RpcRouter { * @param Rpc Type * @param Data Type */ - public interface RpcRequest { + public interface RpcRequest { - RouteIdentifier getRoutingInformation(); + RouteIdentifier getRoutingInformation(); D getPayload(); } - public interface RouteIdentifier { + public interface RouteIdentifier { C getContext(); // defines a routing table (e.g. NodeContext) - R getRoute(); // e.g. (node identity) T getType(); // rpc type + R getRoute(); // e.g. (node identity) } public interface RpcReply { diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcConsumptionRegistry.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcConsumptionRegistry.java new file mode 100644 index 0000000000..c19ee1a7cb --- /dev/null +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcConsumptionRegistry.java @@ -0,0 +1,22 @@ +package org.opendaylight.controller.sal.core.api; + +import java.util.concurrent.Future; + +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; + +public interface RpcConsumptionRegistry { + /** + * Sends an RPC to other components registered to the broker. + * + * @see RpcImplementation + * @param rpc + * Name of RPC + * @param input + * Input data to the RPC + * @return Result of the RPC call + */ + Future> rpc(QName rpc, CompositeNode input); + +} diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcProvisionRegistry.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcProvisionRegistry.java new file mode 100644 index 0000000000..c326bab7a4 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcProvisionRegistry.java @@ -0,0 +1,33 @@ +package org.opendaylight.controller.sal.core.api; + +import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration; +import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration; +import org.opendaylight.yangtools.yang.common.QName; + +public interface RpcProvisionRegistry { + + /** + * Registers an implementation of the rpc. + * + *

+ * The registered rpc functionality will be available to all other + * consumers and providers registered to the broker, which are aware of + * the {@link QName} assigned to the rpc. + * + *

+ * There is no assumption that rpc type is in the set returned by + * invoking {@link RpcImplementation#getSupportedRpcs()}. This allows + * for dynamic rpc implementations. + * + * @param rpcType + * Name of Rpc + * @param implementation + * Provider's Implementation of the RPC functionality + * @throws IllegalArgumentException + * If the name of RPC is invalid + */ + RpcRegistration addRpcImplementation(QName rpcType, RpcImplementation implementation) + throws IllegalArgumentException; + + RoutedRpcRegistration addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation); +} diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataProviderService.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataProviderService.java index 3024c89d61..20fa29dceb 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataProviderService.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataProviderService.java @@ -10,8 +10,10 @@ package org.opendaylight.controller.sal.core.api.data; import org.opendaylight.controller.md.sal.common.api.data.DataProvisionService; import org.opendaylight.controller.sal.common.DataStoreIdentifier; import org.opendaylight.controller.sal.core.api.Provider; +import org.opendaylight.yangtools.concepts.Registration; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; +import org.opendaylight.controller.md.sal.common.api.data.DataReader;; public interface DataProviderService extends DataBrokerService, // @@ -54,6 +56,11 @@ public interface DataProviderService extends */ void removeRefresher(DataStoreIdentifier store, DataRefresher refresher); + + Registration> registerConfigurationReader(InstanceIdentifier path, DataReader reader); + + Registration> registerOperationalReader(InstanceIdentifier path, DataReader reader); + public interface DataRefresher extends Provider.ProviderFunctionality { /** diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/mount/MountProvisionInstance.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/mount/MountProvisionInstance.java new file mode 100644 index 0000000000..8f6a5d0a90 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/mount/MountProvisionInstance.java @@ -0,0 +1,8 @@ +package org.opendaylight.controller.sal.core.api.mount; + +import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry; +import org.opendaylight.controller.sal.core.api.notify.NotificationPublishService; + +public interface MountProvisionInstance extends MountInstance, NotificationPublishService, RpcProvisionRegistry { + +} diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/mount/MountProvisionService.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/mount/MountProvisionService.java new file mode 100644 index 0000000000..fade7d341b --- /dev/null +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/mount/MountProvisionService.java @@ -0,0 +1,13 @@ +package org.opendaylight.controller.sal.core.api.mount; + +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; + +public interface MountProvisionService extends MountService { + + @Override + public MountProvisionInstance getMountPoint(InstanceIdentifier path); + + MountProvisionInstance createMountPoint(InstanceIdentifier path); + + MountProvisionInstance createOrGetMountPoint(InstanceIdentifier path); +} diff --git a/opendaylight/md-sal/sal-dom-broker/pom.xml b/opendaylight/md-sal/sal-dom-broker/pom.xml index 678728ab3b..9383a9e2ff 100644 --- a/opendaylight/md-sal/sal-dom-broker/pom.xml +++ b/opendaylight/md-sal/sal-dom-broker/pom.xml @@ -24,6 +24,11 @@ org.opendaylight.controller sal-common-util 1.0-SNAPSHOT + + + org.opendaylight.controller + sal-common-impl + 1.0-SNAPSHOT org.opendaylight.controller @@ -60,7 +65,7 @@ ${project.groupId}.${project.artifactId} org.opendaylight.controller.sal.dom.broker.BrokerActivator - org.opendaylight.controller.sal.dom.broker, + org.opendaylight.controller.sal.dom.broker.* diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerImpl.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerImpl.xtend index 83dda5902d..855ad9bd32 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerImpl.xtend +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerImpl.xtend @@ -7,29 +7,28 @@ */ package org.opendaylight.controller.sal.dom.broker; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import org.opendaylight.controller.sal.core.api.Broker; -import org.opendaylight.controller.sal.core.api.BrokerService; -import org.opendaylight.controller.sal.core.api.Consumer; -import org.opendaylight.controller.sal.core.api.Provider; -import org.opendaylight.controller.sal.core.api.RpcImplementation; -import org.opendaylight.controller.sal.core.spi.BrokerModule; -import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.common.RpcResult; -import org.opendaylight.yangtools.yang.data.api.CompositeNode; -import org.osgi.framework.BundleContext; -import org.slf4j.LoggerFactory; +import java.util.Collections +import java.util.HashMap +import java.util.HashSet +import java.util.Map +import java.util.Set +import java.util.concurrent.Callable +import java.util.concurrent.ExecutorService +import java.util.concurrent.Executors +import java.util.concurrent.Future +import org.opendaylight.controller.sal.core.api.Broker +import org.opendaylight.controller.sal.core.api.BrokerService +import org.opendaylight.controller.sal.core.api.Consumer +import org.opendaylight.controller.sal.core.api.Provider +import org.opendaylight.controller.sal.core.spi.BrokerModule +import org.opendaylight.yangtools.yang.common.QName +import org.opendaylight.yangtools.yang.common.RpcResult +import org.opendaylight.yangtools.yang.data.api.CompositeNode +import org.osgi.framework.BundleContext +import org.slf4j.LoggerFactory +import org.opendaylight.controller.sal.dom.broker.spi.RpcRouter import org.opendaylight.yangtools.concepts.ListenerRegistration import org.opendaylight.controller.sal.core.api.RpcRegistrationListener -import org.opendaylight.controller.md.sal.common.impl.ListenerRegistry public class BrokerImpl implements Broker { private static val log = LoggerFactory.getLogger(BrokerImpl); @@ -42,17 +41,14 @@ public class BrokerImpl implements Broker { private val Map, BrokerModule> serviceProviders = Collections. synchronizedMap(new HashMap, BrokerModule>()); - - private val rpcRegistrationListeners = new ListenerRegistry(); - // RPC Context - private val Map rpcImpls = Collections.synchronizedMap( - new HashMap()); - // Implementation specific @Property private var ExecutorService executor = Executors.newFixedThreadPool(5); @Property private var BundleContext bundleContext; + + @Property + private var RpcRouter router; override registerConsumer(Consumer consumer, BundleContext ctx) { checkPredicates(consumer); @@ -95,42 +91,8 @@ public class BrokerImpl implements Broker { return prov.getServiceForSession(service, session); } - // RPC Functionality - protected def void addRpcImplementation(QName rpcType, RpcImplementation implementation) { - if(rpcImpls.get(rpcType) != null) { - throw new IllegalStateException("Implementation for rpc " + rpcType + " is already registered."); - } - - - rpcImpls.put(rpcType, implementation); - - - for(listener : rpcRegistrationListeners.listeners) { - try { - listener.instance.onRpcImplementationAdded(rpcType); - } catch (Exception e){ - log.error("Unhandled exception during invoking listener",e); - } - } - } - - protected def void removeRpcImplementation(QName rpcType, RpcImplementation implToRemove) { - if(implToRemove == rpcImpls.get(rpcType)) { - rpcImpls.remove(rpcType); - } - - for(listener : rpcRegistrationListeners.listeners) { - try { - listener.instance.onRpcImplementationRemoved(rpcType); - } catch (Exception e){ - log.error("Unhandled exception during invoking listener",e); - } - } - } - protected def Future> invokeRpc(QName rpc, CompositeNode input) { - val impl = rpcImpls.get(rpc); - val result = executor.submit([|impl.invokeRpc(rpc, input)] as Callable>); + val result = executor.submit([|router.invokeRpc(rpc, input)] as Callable>); return result; } @@ -171,12 +133,4 @@ public class BrokerImpl implements Broker { sessions.remove(consumerContextImpl); providerSessions.remove(consumerContextImpl); } - - protected def getSupportedRpcs() { - rpcImpls.keySet; - } - - def ListenerRegistration addRpcRegistrationListener(RpcRegistrationListener listener) { - rpcRegistrationListeners.register(listener); - } } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/MountPointImpl.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/MountPointImpl.java new file mode 100644 index 0000000000..7037b46ce9 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/MountPointImpl.java @@ -0,0 +1,118 @@ +package org.opendaylight.controller.sal.dom.broker; + +import java.util.Set; +import java.util.concurrent.Future; + +import org.opendaylight.controller.md.sal.common.api.data.DataReader; +import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration; +import org.opendaylight.controller.sal.core.api.RpcImplementation; +import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration; +import org.opendaylight.controller.sal.core.api.RpcRegistrationListener; +import org.opendaylight.controller.sal.core.api.data.DataChangeListener; +import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction; +import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance; +import org.opendaylight.controller.sal.core.api.notify.NotificationListener; +import org.opendaylight.controller.sal.dom.broker.impl.DataReaderRouter; +import org.opendaylight.controller.sal.dom.broker.impl.NotificationRouterImpl; +import org.opendaylight.controller.sal.dom.broker.impl.RpcRouterImpl; +import org.opendaylight.controller.sal.dom.broker.spi.NotificationRouter; +import org.opendaylight.controller.sal.dom.broker.spi.RpcRouter; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.concepts.Registration; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; + +public class MountPointImpl implements MountProvisionInstance { + + final RpcRouter rpcs; + final DataReaderRouter dataReader; + final NotificationRouter notificationRouter; + + public MountPointImpl(InstanceIdentifier path) { + rpcs = new RpcRouterImpl(""); + dataReader = new DataReaderRouter(); + notificationRouter = new NotificationRouterImpl(); + } + + @Override + public void publish(CompositeNode notification) { + notificationRouter.publish(notification); + } + + @Override + public Registration addNotificationListener(QName notification, NotificationListener listener) { + return notificationRouter.addNotificationListener(notification, listener); + } + + @Override + public CompositeNode readConfigurationData(InstanceIdentifier path) { + return dataReader.readConfigurationData(path); + } + + @Override + public CompositeNode readOperationalData(InstanceIdentifier path) { + return dataReader.readOperationalData(path); + } + + public Registration> registerOperationalReader( + InstanceIdentifier path, DataReader reader) { + return dataReader.registerOperationalReader(path, reader); + } + + public Registration> registerConfigurationReader( + InstanceIdentifier path, DataReader reader) { + return dataReader.registerConfigurationReader(path, reader); + } + + @Override + public RoutedRpcRegistration addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation) { + return rpcs.addRoutedRpcImplementation(rpcType, implementation); + } + + @Override + public RpcRegistration addRpcImplementation(QName rpcType, RpcImplementation implementation) + throws IllegalArgumentException { + return rpcs.addRpcImplementation(rpcType, implementation); + } + + public Set getSupportedRpcs() { + return rpcs.getSupportedRpcs(); + } + + + public RpcResult invokeRpc(QName rpc, CompositeNode input) { + return rpcs.invokeRpc(rpc, input); + } + + public ListenerRegistration addRpcRegistrationListener(RpcRegistrationListener listener) { + return rpcs.addRpcRegistrationListener(listener); + } + + + @Override + public Future> rpc(QName type, CompositeNode input) { + // TODO Auto-generated method stub + return null; + } + + @Override + public DataModificationTransaction beginTransaction() { + // TODO Auto-generated method stub + return null; + } + + @Override + public ListenerRegistration registerDataChangeListener(InstanceIdentifier path, + DataChangeListener listener) { + // TODO Auto-generated method stub + return null; + } + + @Override + public void sendNotification(CompositeNode notification) { + publish(notification); + + } +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/MountPointManagerImpl.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/MountPointManagerImpl.xtend new file mode 100644 index 0000000000..c64d1e56dd --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/MountPointManagerImpl.xtend @@ -0,0 +1,35 @@ +package org.opendaylight.controller.sal.dom.broker + + +import org.opendaylight.controller.sal.core.api.mount.MountProvisionService +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier +import java.util.concurrent.ConcurrentMap +import java.util.concurrent.ConcurrentHashMap +import static com.google.common.base.Preconditions.*; + +class MountPointManagerImpl implements MountProvisionService { + + ConcurrentMap mounts = new ConcurrentHashMap(); + + override createMountPoint(InstanceIdentifier path) { + checkState(!mounts.containsKey(path),"Mount already created"); + val mount = new MountPointImpl(path); + mounts.put(path,mount); + } + + + override createOrGetMountPoint(InstanceIdentifier path) { + val mount = mounts.get(path); + if(mount === null) { + return createMountPoint(path) + } + return mount; + } + + + override getMountPoint(InstanceIdentifier path) { + mounts.get(path); + } + + +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/ProviderContextImpl.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/ProviderContextImpl.xtend index 3fdd706577..cf5d220943 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/ProviderContextImpl.xtend +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/ProviderContextImpl.xtend @@ -1,25 +1,23 @@ package org.opendaylight.controller.sal.dom.broker -import java.util.Collections -import java.util.HashMap import org.opendaylight.controller.sal.core.api.Broker.ProviderSession import org.opendaylight.controller.sal.core.api.Provider import org.opendaylight.controller.sal.core.api.RpcImplementation import org.opendaylight.yangtools.yang.common.QName import org.osgi.framework.BundleContext -import org.opendaylight.yangtools.concepts.AbstractObjectRegistration import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration -import static java.util.Collections.* -import java.util.Collections -import java.util.HashMap import org.opendaylight.controller.sal.core.api.RpcRegistrationListener +import org.opendaylight.yangtools.concepts.Registration + +import java.util.Set +import java.util.HashSet class ProviderContextImpl extends ConsumerContextImpl implements ProviderSession { @Property private val Provider provider; - private val rpcImpls = Collections.synchronizedMap(new HashMap()); + private val Set> registrations = new HashSet(); new(Provider provider, BundleContext ctx) { super(null, ctx); @@ -27,75 +25,61 @@ class ProviderContextImpl extends ConsumerContextImpl implements ProviderSession } override addRpcImplementation(QName rpcType, RpcImplementation implementation) throws IllegalArgumentException { - if(rpcType == null) { - throw new IllegalArgumentException("rpcType must not be null"); - } - if(implementation == null) { - throw new IllegalArgumentException("Implementation must not be null"); - } - broker.addRpcImplementation(rpcType, implementation); - rpcImpls.put(rpcType, implementation); - - return new RpcRegistrationImpl(rpcType, implementation, this); + val origReg = broker.router.addRpcImplementation(rpcType, implementation); + val newReg = new RpcRegistrationWrapper(origReg); + registrations.add(newReg); + return newReg; } - def removeRpcImplementation(RpcRegistrationImpl implToRemove) throws IllegalArgumentException { - val localImpl = rpcImpls.get(implToRemove.type); - if(localImpl !== implToRemove.instance) { - throw new IllegalStateException( - "Implementation was not registered in this session"); - } - broker.removeRpcImplementation(implToRemove.type,localImpl); - rpcImpls.remove(implToRemove.type); + protected def removeRpcImplementation(RpcRegistrationWrapper implToRemove) throws IllegalArgumentException { + registrations.remove(implToRemove); } override close() { - removeAllRpcImlementations - super.close - } - - private def removeAllRpcImlementations() { - if (!rpcImpls.empty) { - for (entry : rpcImpls.entrySet) { - broker.removeRpcImplementation(entry.key,entry.value); - } - rpcImpls.clear - } + + for (reg : registrations) { + reg.close() + } + super.close } - + override addMountedRpcImplementation(QName rpcType, RpcImplementation implementation) { throw new UnsupportedOperationException("TODO: auto-generated method stub") } - + override addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation) { throw new UnsupportedOperationException("TODO: auto-generated method stub") } - + override getSupportedRpcs() { - broker.getSupportedRpcs(); + broker.router.supportedRpcs; } - + override addRpcRegistrationListener(RpcRegistrationListener listener) { - broker.addRpcRegistrationListener(listener); + broker.router.addRpcRegistrationListener(listener); } } -class RpcRegistrationImpl extends AbstractObjectRegistration implements RpcRegistration { - - @Property - val QName type - - private var ProviderContextImpl context - - new(QName type, RpcImplementation instance, ProviderContextImpl ctx) { - super(instance) - _type = type - context = ctx - } - - override protected removeRegistration() { - context.removeRpcImplementation(this) - context = null - } +class RpcRegistrationWrapper implements RpcRegistration { + + + @Property + val RpcRegistration delegate + + new(RpcRegistration delegate) { + _delegate = delegate + } + + override getInstance() { + delegate.instance + } + override close() { + delegate.close + } + + override getType() { + delegate.type + } } + diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/DataReaderRouter.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/DataReaderRouter.xtend new file mode 100644 index 0000000000..1e0f3385cc --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/DataReaderRouter.xtend @@ -0,0 +1,13 @@ +package org.opendaylight.controller.sal.dom.broker.impl + +import org.opendaylight.controller.md.sal.common.impl.routing.AbstractDataReadRouter +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier +import org.opendaylight.yangtools.yang.data.api.CompositeNode + +class DataReaderRouter extends AbstractDataReadRouter { + + override protected merge(InstanceIdentifier path, Iterable data) { + return data.iterator.next + } + +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/NotificationRouterImpl.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/NotificationRouterImpl.java new file mode 100644 index 0000000000..6d7b600dbc --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/NotificationRouterImpl.java @@ -0,0 +1,89 @@ +/* + * 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.dom.broker.impl; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.opendaylight.controller.sal.core.api.BrokerService; +import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession; +import org.opendaylight.controller.sal.core.api.Broker.ProviderSession; +import org.opendaylight.controller.sal.core.api.Consumer.ConsumerFunctionality; +import org.opendaylight.controller.sal.core.api.Provider.ProviderFunctionality; +import org.opendaylight.controller.sal.core.api.notify.NotificationListener; +import org.opendaylight.controller.sal.core.api.notify.NotificationPublishService; +import org.opendaylight.controller.sal.core.api.notify.NotificationService; +import org.opendaylight.controller.sal.core.spi.BrokerModule; +import org.opendaylight.controller.sal.dom.broker.spi.NotificationRouter; +import org.opendaylight.yangtools.concepts.AbstractObjectRegistration; +import org.opendaylight.yangtools.concepts.Registration; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Multimap; + +public class NotificationRouterImpl implements NotificationRouter { + private static Logger log = LoggerFactory.getLogger(NotificationRouterImpl.class); + + private Multimap> listeners = HashMultimap.create(); + + private void sendNotification(CompositeNode notification) { + QName type = notification.getNodeType(); + Collection> toNotify = listeners.get(type); + log.info("Publishing notification " + type); + + if (toNotify == null) { + // No listeners were registered - returns. + return; + } + + for (Registration listener : toNotify) { + try { + // FIXME: ensure that notification is immutable + listener.getInstance().onNotification(notification); + } catch (Exception e) { + log.error("Uncaught exception in NotificationListener", e); + } + } + + } + + @Override + public void publish(CompositeNode notification) { + sendNotification(notification); + } + + @Override + public Registration addNotificationListener(QName notification, NotificationListener listener) { + ListenerRegistration ret = new ListenerRegistration(notification, listener); + return ret; + } + + private class ListenerRegistration extends AbstractObjectRegistration { + + final QName type; + + public ListenerRegistration(QName type, NotificationListener instance) { + super(instance); + this.type = type; + } + + @Override + protected void removeRegistration() { + listeners.remove(type, this); + } + } +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/RpcRouterImpl.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/RpcRouterImpl.xtend new file mode 100644 index 0000000000..d67697f849 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/RpcRouterImpl.xtend @@ -0,0 +1,106 @@ +package org.opendaylight.controller.sal.dom.broker.impl + +import org.opendaylight.controller.sal.dom.broker.spi.RpcRouter +import org.opendaylight.yangtools.concepts.Identifiable +import org.opendaylight.yangtools.yang.common.QName +import org.opendaylight.controller.sal.core.api.RpcImplementation +import org.opendaylight.yangtools.yang.data.api.CompositeNode +import static com.google.common.base.Preconditions.*; +import java.util.Map +import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration +import java.util.concurrent.ConcurrentHashMap +import java.util.Set +import java.util.Collections +import org.opendaylight.yangtools.concepts.AbstractObjectRegistration +import org.opendaylight.controller.md.sal.common.impl.ListenerRegistry +import org.opendaylight.controller.sal.core.api.RpcRegistrationListener +import org.slf4j.LoggerFactory + +class RpcRouterImpl implements RpcRouter, Identifiable { + + static val log = LoggerFactory.getLogger(RpcRouterImpl) + + Map implementations = new ConcurrentHashMap(); + + @Property + val Set supportedRpcs = Collections.unmodifiableSet(implementations.keySet); + + private val rpcRegistrationListeners = new ListenerRegistry(); + + @Property + val String identifier; + + new(String name) { + _identifier = name; + } + + override addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation) { + } + + override addRpcImplementation(QName rpcType, RpcImplementation implementation) throws IllegalArgumentException { + checkNotNull(rpcType, "Rpc Type should not be null"); + checkNotNull(implementation, "Implementation should not be null."); + checkState(!implementations.containsKey(rpcType), "Provider for supplied rpc is already registered."); + val reg = new RpcRegistrationImpl(rpcType, implementation, this); + implementations.put(rpcType, reg) + + for (listener : rpcRegistrationListeners.listeners) { + try { + listener.instance.onRpcImplementationAdded(rpcType); + } catch (Exception e) { + log.error("Unhandled exception during invoking listener", e); + } + } + + return reg; + + } + + override invokeRpc(QName rpc, CompositeNode input) { + checkNotNull(rpc, "Rpc Type should not be null"); + + val impl = implementations.get(rpc); + checkState(impl !== null, "Provider for supplied rpc is not registered."); + + return impl.instance.invokeRpc(rpc, input); + } + + def remove(RpcRegistrationImpl impl) { + val existing = implementations.get(impl.type); + if (existing == impl) { + implementations.remove(impl.type); + } + for (listener : rpcRegistrationListeners.listeners) { + try { + listener.instance.onRpcImplementationRemoved(impl.type); + } catch (Exception e) { + log.error("Unhandled exception during invoking listener", e); + } + } + } + + override addRpcRegistrationListener(RpcRegistrationListener listener) { + rpcRegistrationListeners.register(listener); + } + +} + +class RpcRegistrationImpl extends AbstractObjectRegistration implements RpcRegistration { + + @Property + val QName type; + + @Property + var RpcRouterImpl router; + + new(QName type, RpcImplementation instance, RpcRouterImpl router) { + super(instance) + _type = type + _router = router + } + + override protected removeRegistration() { + router.remove(this); + } + +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/spi/NotificationRouter.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/spi/NotificationRouter.java new file mode 100644 index 0000000000..fc42d2ceb9 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/spi/NotificationRouter.java @@ -0,0 +1,21 @@ +package org.opendaylight.controller.sal.dom.broker.spi; + +import org.opendaylight.controller.sal.core.api.notify.NotificationListener; +import org.opendaylight.yangtools.concepts.Registration; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; + +public interface NotificationRouter { + + void publish(CompositeNode notification); + + /** + * Registers a notification listener for supplied notification type. + * + * @param notification + * @param listener + */ + Registration addNotificationListener(QName notification, + NotificationListener listener); + +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/spi/RoutedRpcProcessor.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/spi/RoutedRpcProcessor.java new file mode 100644 index 0000000000..97c2a151ce --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/spi/RoutedRpcProcessor.java @@ -0,0 +1,27 @@ +package org.opendaylight.controller.sal.dom.broker.spi; + +import java.util.Map; +import java.util.Set; + +import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration; +import org.opendaylight.controller.sal.core.api.RpcImplementation; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; + +public interface RoutedRpcProcessor extends RpcImplementation { + + public RoutedRpcRegistration addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation); + + public Set getSupportedRpcs(); + + public QName getRpcType(); + + public RpcResult invokeRpc(QName rpc, CompositeNode input); + + Map getRoutes(); + + RpcImplementation getDefaultRoute(); + +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/spi/RpcRouter.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/spi/RpcRouter.java new file mode 100644 index 0000000000..6886f892c6 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/spi/RpcRouter.java @@ -0,0 +1,31 @@ +package org.opendaylight.controller.sal.dom.broker.spi; + +import java.util.Set; + +import org.opendaylight.controller.sal.core.api.RpcImplementation; +import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry; +import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration; +import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration; +import org.opendaylight.controller.sal.core.api.RpcRegistrationListener; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; + +public interface RpcRouter extends RpcProvisionRegistry, RpcImplementation { + + @Override + public RoutedRpcRegistration addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation); + + @Override + public RpcRegistration addRpcImplementation(QName rpcType, RpcImplementation implementation) + throws IllegalArgumentException; + + @Override + public Set getSupportedRpcs(); + + @Override + public RpcResult invokeRpc(QName rpc, CompositeNode input); + + ListenerRegistration addRpcRegistrationListener(RpcRegistrationListener listener); +} diff --git a/opendaylight/md-sal/sal-netconf-connector/pom.xml b/opendaylight/md-sal/sal-netconf-connector/pom.xml index c8bc71577d..57e4d858c1 100644 --- a/opendaylight/md-sal/sal-netconf-connector/pom.xml +++ b/opendaylight/md-sal/sal-netconf-connector/pom.xml @@ -6,6 +6,9 @@ sal-parent 1.0-SNAPSHOT + + 0.2.2-SNAPSHOT + sal-netconf-connector scm:git:ssh://git.opendaylight.org:29418/controller.git @@ -18,6 +21,150 @@ ${project.groupId} sal-connector-api + + ${project.groupId} + sal-common-util + 1.0-SNAPSHOT + + + org.eclipse.xtend + org.eclipse.xtend.lib + + + org.opendaylight.controller + netconf-client + 0.2.2-SNAPSHOT + + + org.opendaylight.yangtools + yang-data-impl + 0.5.9-SNAPSHOT + + + junit + junit + test + + + ${project.groupId} + yang-test + ${netconf.version} + test + + + ${project.groupId} + config-api + ${netconf.version} + test + + + ${project.groupId} + config-util + ${netconf.version} + test + + + ${project.groupId} + yang-store-api + ${netconf.version} + test + + + ${project.groupId} + netconf-api + ${netconf.version} + test + + + org.opendaylight.bgpcep + util + test + 0.3.0-SNAPSHOT + + + ${project.groupId} + netconf-client + test + ${netconf.version} + + + ${project.groupId} + config-netconf-connector + test + ${netconf.version} + + + ${project.groupId} + yang-test + test + ${netconf.version} + + + ${project.groupId} + config-manager + test + ${netconf.version} + + + ${project.groupId} + config-persister-impl + test + ${netconf.version} + + + ${project.groupId} + config-manager + test + test-jar + ${netconf.version} + + + ${project.groupId} + netconf-impl + test + ${netconf.version} + + + ${project.groupId} + netconf-mapping-api + test + ${netconf.version} + + + ${project.groupId} + netconf-util + test + test-jar + ${netconf.version} + + + ${project.groupId} + yang-store-impl + test + ${netconf.version} + + + ${project.groupId} + yang-store-impl + test + test-jar + ${netconf.version} + + + org.opendaylight.controller + logback-config + test + ${netconf.version} + + + org.mockito + mockito-all + test + + + org.slf4j + slf4j-api + bundle diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java index c32e350509..b4cf6c985b 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java @@ -45,7 +45,9 @@ final class TestUtils { } for (int i = 0; i < fileList.length; i++) { String fileName = fileList[i]; - testFiles.add(new File(testDir, fileName)); + if (new File(testDir, fileName).isDirectory() == false) { + testFiles.add(new File(testDir, fileName)); + } } return parser.parseYangModels(testFiles); } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/YangAndXmlToJsonConversion.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/YangAndXmlToJsonConversion.java new file mode 100644 index 0000000000..841f8e593a --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/YangAndXmlToJsonConversion.java @@ -0,0 +1,273 @@ +package org.opendaylight.controller.sal.restconf.impl.test; + +import static org.junit.Assert.*; + +import java.io.*; +import java.util.Set; +import java.util.regex.*; + +import javax.ws.rs.WebApplicationException; + +import org.junit.*; +import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider; +import org.opendaylight.controller.sal.restconf.impl.StructuredData; +import org.opendaylight.yangtools.yang.model.api.*; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; + +public class YangAndXmlToJsonConversion { + + @Ignore + @Test + /** + * Test for simple yang types (leaf, list, leaf-list, container and various combination of them) + * + */ + public void simpleYangTypesTest() { + String jsonOutput = null; + + jsonOutput = convertXmlDataAndYangToJson("/yang-to-json-conversion/simple-yang-types/xml/data.xml", + "/yang-to-json-conversion/simple-yang-types"); + +// jsonOutput = +// readJsonFromFile("/yang-to-json-conversion/simple-yang-types/xml/output.json"); + + verifyJsonOutputForSimpleYangTypes(jsonOutput); + + } + + private void verifyJsonOutputForSimpleYangTypes(String jsonOutput) { + + assertTrue("First and last character has to be '{' and '}'", Pattern.compile("\\A\\{.*\\}\\z", Pattern.DOTALL) + .matcher(jsonOutput).matches()); + + String prefix = "\"(smptp:|)"; + + // subnodes of cont1 + String cont1 = prefix + "cont1\":\\{"; + testLeaf(cont1, "lf11", new String("lf"), jsonOutput, prefix); + testLeafList(cont1, "lflst11", jsonOutput, prefix, new Integer(55), new Integer(56), new Integer(57)); + testLeafList(cont1, "lflst12", jsonOutput, prefix, new String("lflst12 str1"), new String("lflst12 str2"), + new String("lflst12 str1")); + + // subnodes of lst111 + // first object of lst111 + String lst11 = cont1 + ".*" + prefix + "lst11\":\\[\\{"; + testLeaf(lst11, "lf111", new Integer(140), jsonOutput, prefix); + testLeaf(lst11, "lf112", new String("lf112 str"), jsonOutput, prefix); + + // subnodes of cont111 + String cont111 = lst11 + ".*" + prefix + "cont111\":\\{"; + testLeaf(cont111, "lf1111", new String("lf1111 str"), jsonOutput, prefix); + testLeafList(cont1, "lflst1111", jsonOutput, prefix, new Integer(2048), new Integer(1024), new Integer(4096)); + + // subnodes of lst1111 + String lst1111 = cont111 + ".*" + prefix + "lst1111\":\\[\\{"; + testLeaf(lst1111, "lf1111A", new String("lf1111A str11"), jsonOutput, prefix); + testLeaf(lst1111, "lf1111B", new Integer(4), jsonOutput, prefix); + testLeaf(lst1111, "lf1111A", new String("lf1111A str12"), jsonOutput, prefix); + testLeaf(lst1111, "lf1111B", new Integer(7), jsonOutput, prefix); + // :subnodes of lst1111 + // :subnodes of cont111 + // :first object of lst111 + + // second object of lst111 + testLeaf(lst11, "lf111", new Integer(141), jsonOutput, prefix); + testLeaf(lst11, "lf112", new String("lf112 str2"), jsonOutput, prefix); + + // subnodes of cont111 + testLeaf(cont111, "lf1111", new String("lf1111 str2"), jsonOutput, prefix); + testLeafList(cont1, "lflst1111", jsonOutput, prefix, new Integer(2049), new Integer(1025), new Integer(4097)); + + // subnodes of lst1111 + testLeaf(lst1111, "lf1111A", new String("lf1111A str21"), jsonOutput, prefix); + testLeaf(lst1111, "lf1111B", new Integer(5), jsonOutput, prefix); + testLeaf(lst1111, "lf1111A", new String("lf1111A str22"), jsonOutput, prefix); + testLeaf(lst1111, "lf1111B", new Integer(8), jsonOutput, prefix); + // :subnodes of lst111 + // :subnodes of cont111 + // :second object of lst111 + // :second object of lst111 + // :subnodes of cont1 + } + + private void testLeaf(String prevRegEx, String lstName, Object value, String jsonFile, String elementPrefix) { + String newValue = null; + if (value instanceof Integer) { + newValue = value.toString(); + } else if (value instanceof String) { + newValue = "\"" + value.toString() + "\""; + } + String lf = elementPrefix + lstName + "\":" + newValue; + assertTrue(">>\"" + lstName + "\":" + newValue + "<< is missing", + Pattern.compile(".*" + prevRegEx + ".*" + lf + ".*", Pattern.DOTALL).matcher(jsonFile).matches()); + + } + + private void testLeafList(String prevRegEx, String lflstName, String jsonFile, String elementPrefix, + Object... dataInList) { + // order of element in the list isn't defined :( + String lflstBegin = elementPrefix + lflstName + "\":\\["; + String lflstEnd = ".*\\],"; + assertTrue( + ">>\"" + lflstName + "\": [],<< is missing", + Pattern.compile(".*" + prevRegEx + ".*" + lflstBegin + lflstEnd + ".*", Pattern.DOTALL) + .matcher(jsonFile).matches()); + + for (Object obj : dataInList) { + testValueOfLeafList(prevRegEx, lflstBegin, obj, jsonFile); + } + } + + private void testValueOfLeafList(String prevRegEx, String lflstPrevRegEx, Object value, String jsonFile) { + String lflstData = null; + lflstData = regExForDataValueInList(value); + assertNotNull(lflstPrevRegEx + ": value doesn't have correct type.", lflstData); + assertTrue( + prevRegEx + ": data value >" + value + "< is missing.", + Pattern.compile(".*" + prevRegEx + ".*" + lflstPrevRegEx + lflstData + ".*", Pattern.DOTALL) + .matcher(jsonFile).matches()); + + } + + /** + * Data value can be first, inner, last or only one member of list + * + * @param dataValue + * @return + */ + private String regExForDataValueInList(Object dataValue) { + String newDataValue; + if (dataValue instanceof Integer) { + newDataValue = dataValue.toString(); + return "(" + newDataValue + "(,[0-9]+)+|([0-9]+,)+" + newDataValue + "(,[0-9]+)+|([0-9]+,)+" + newDataValue + + "|" + newDataValue + ")\\]"; + } else if (dataValue instanceof String) { + newDataValue = "\"" + dataValue.toString() + "\""; + return "(" + newDataValue + "(,\".+\")+|(\".+\",)+" + newDataValue + "(,\".+\")+|(\".+\",)+" + newDataValue + + "|" + newDataValue + ")\\]"; + } + return null; + } + + private String readJsonFromFile(String path) { + String fullPath = YangAndXmlToJsonConversion.class.getResource(path).getPath(); + assertNotNull("Path to file can't be null.", fullPath); + File file = new File(fullPath); + assertNotNull("File can't be null", file); + FileReader fileReader = null; + try { + fileReader = new FileReader(file); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + assertNotNull("File reader can't be null.", fileReader); + + StringBuilder strBuilder = new StringBuilder(); + char[] buffer = new char[1000]; + + while (true) { + int loadedCharNum; + try { + loadedCharNum = fileReader.read(buffer); + } catch (IOException e) { + break; + } + if (loadedCharNum == -1) { + break; + } + strBuilder.append(buffer, 0, loadedCharNum); + } + try { + fileReader.close(); + } catch (IOException e) { + System.out.println("The file wasn't closed"); + ; + } + String rawStr = strBuilder.toString(); + rawStr = rawStr.replace("\n", ""); + rawStr = rawStr.replace("\r", ""); + rawStr = rawStr.replace("\t", ""); + rawStr = removeSpaces(rawStr); + + return rawStr; + } + + private String removeSpaces(String rawStr) { + StringBuilder strBuilder = new StringBuilder(); + int i = 0; + int quoteCount = 0; + while (i < rawStr.length()) { + if (rawStr.substring(i, i + 1).equals("\"")) { + quoteCount++; + } + + if (!rawStr.substring(i, i + 1).equals(" ") || (quoteCount % 2 == 1)) { + strBuilder.append(rawStr.charAt(i)); + } + i++; + } + + return strBuilder.toString(); + } + + private String convertXmlDataAndYangToJson(String xmlDataPath, String yangPath) { + String jsonResult = null; + Set modules = null; + + try { + modules = TestUtils.loadModules(YangAndXmlToJsonConversion.class.getResource(yangPath).getPath()); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + assertNotNull("modules can't be null.", modules); + + InputStream xmlStream = YangAndXmlToJsonConversion.class.getResourceAsStream(xmlDataPath); + CompositeNode compositeNode = null; + try { + compositeNode = TestUtils.loadCompositeNode(xmlStream); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + assertNotNull("Composite node can't be null", compositeNode); + + StructuredDataToJsonProvider structuredDataToJsonProvider = StructuredDataToJsonProvider.INSTANCE; + for (Module module : modules) { + for (DataSchemaNode dataSchemaNode : module.getChildNodes()) { + StructuredData structuredData = new StructuredData(compositeNode, dataSchemaNode); + ByteArrayOutputStream byteArrayOS = new ByteArrayOutputStream(); + try { + structuredDataToJsonProvider.writeTo(structuredData, null, null, null, null, null, byteArrayOS); + } catch (WebApplicationException | IOException e) { + e.printStackTrace(); + } + assertFalse( + "Returning JSON string can't be empty for node " + dataSchemaNode.getQName().getLocalName(), + byteArrayOS.toString().isEmpty()); + jsonResult = byteArrayOS.toString(); + try { + outputToFile(byteArrayOS); + } catch (IOException e) { + System.out.println("Output file wasn't cloased sucessfuly."); + } + } + } + return jsonResult; + } + + private void outputToFile(ByteArrayOutputStream outputStream) throws IOException { + FileOutputStream fileOS = null; + try { + String path = YangAndXmlToJsonConversion.class.getResource("/yang-to-json-conversion/xml").getPath(); + File outFile = new File(path + "/data.json"); + fileOS = new FileOutputStream(outFile); + try { + fileOS.write(outputStream.toByteArray()); + } catch (IOException e) { + e.printStackTrace(); + } + fileOS.close(); + } catch (FileNotFoundException e1) { + e1.printStackTrace(); + } + } +} diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-yang-types/simple-yang-types.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-yang-types/simple-yang-types.yang new file mode 100644 index 0000000000..760dbd73ed --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-yang-types/simple-yang-types.yang @@ -0,0 +1,47 @@ +module simple-yang-types { + namespace "simple:yang:types"; + + prefix "smptp"; + revision 2013-11-5 { + description "Initial revision."; + } + + container cont1 { + leaf lf11 { + type string; + } + leaf-list lflst11 { + type int32; + } + leaf-list lflst12 { + type string; + } + list lst11 { + key lf111; + leaf lf111 { + type uint8; + } + leaf lf112 { + type string; + } + container cont111 { + leaf lf1111 { + type string; + } + leaf-list lflst1111 { + type int32; + } + list lst1111 { + leaf lf1111A { + type string; + } + leaf lf1111B { + type uint8; + } + } + } + } + + } + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-yang-types/xml/awaited_output.json b/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-yang-types/xml/awaited_output.json new file mode 100644 index 0000000000..e76e7bd9ef --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-yang-types/xml/awaited_output.json @@ -0,0 +1,45 @@ +{ + "smptp:cont1": { + "lf11":"lf", + "lflst11": [55,56,57], + "lflst12": ["lflst12 str1", "lflst12 str2", "lflst12 str3"], + "lst11": [ + { + "lf111":140, + "lf112":"lf112 str", + "cont111": { + "lf1111":"lf1111 str", + "lflst1111": [2048, 1024, 4096], + "lst1111": [ + { + "lf1111A": "lf1111A str11", + "lf1111B": 4 + }, + { + "lf1111A": "lf1111A str12", + "lf1111B": 7 + } + ] + } + }, + { + "lf111":141, + "lf112":"lf112 str2", + "cont111": { + "lf1111":"lf1111 str2", + "lflst1111": [2049, 1025, 4097], + "lst1111": [ + { + "lf1111A": "lf1111A str21", + "lf1111B": 5 + }, + { + "lf1111A": "lf1111A str22", + "lf1111B": 8 + } + ] + } + } + ] + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-yang-types/xml/data.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-yang-types/xml/data.xml new file mode 100644 index 0000000000..b47987ca23 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-yang-types/xml/data.xml @@ -0,0 +1,45 @@ + + lf + 55 + 56 + 57 + lflst12 str1 + lflst12 str2 + lflst12 str3 + + 140 + lf112 str + + lf1111 str + 2048 + 1024 + 4096 + + lf1111A str11 + 4 + + + lf1111A str12 + 7 + + + + + 141 + lf112 str2 + + lf1111 str2 + 2049 + 1025 + 4097 + + lf1111A str21 + 5 + + + lf1111A str22 + 8 + + + + diff --git a/opendaylight/md-sal/sal-zeromq-connector/pom.xml b/opendaylight/md-sal/sal-zeromq-connector/pom.xml new file mode 100644 index 0000000000..3db4a65840 --- /dev/null +++ b/opendaylight/md-sal/sal-zeromq-connector/pom.xml @@ -0,0 +1,96 @@ + + + 4.0.0 + + org.opendaylight.controller + sal-parent + 1.0-SNAPSHOT + + + + sal-zeromq-connector + bundle + + + + + org.apache.felix + maven-bundle-plugin + ${bundle.plugin.version} + true + + + + org.opendaylight.controller.sal.connector.api, + org.opendaylight.controller.sal.core.api, + org.opendaylight.yangtools.concepts;version="[0.1,1)", + org.opendaylight.yangtools.yang.common;version="[0.5,1)", + org.opendaylight.yangtools.yang.data.api;version="[0.5,1)", + org.zeromq;version="[0.3,1)" + + org.opendaylight.controller.sal.connector.zeromq.Activator + + + + + + + + org.opendaylight.controller + containermanager + 0.5.1-SNAPSHOT + + + org.opendaylight.controller + commons.northbound + 0.4.1-SNAPSHOT + + + org.opendaylight.controller + sal + 0.5.1-SNAPSHOT + + + org.opendaylight.yangtools + yang-binding + + + org.opendaylight.yangtools + yang-common + + + org.opendaylight.controller + sal-connector-api + + + org.opendaylight.controller + sal-common-util + 1.0-SNAPSHOT + + + + junit + junit + + + org.jeromq + jeromq + 0.3.0-SNAPSHOT + + + + + + sonatype-nexus-snapshots + https://oss.sonatype.org/content/repositories/snapshots + + false + + + true + + + + + diff --git a/opendaylight/md-sal/sal-zeromq-connector/src/main/java/org/opendaylight/controller/sal/connector/zeromq/Activator.java b/opendaylight/md-sal/sal-zeromq-connector/src/main/java/org/opendaylight/controller/sal/connector/zeromq/Activator.java new file mode 100644 index 0000000000..b8933ec615 --- /dev/null +++ b/opendaylight/md-sal/sal-zeromq-connector/src/main/java/org/opendaylight/controller/sal/connector/zeromq/Activator.java @@ -0,0 +1,23 @@ +package org.opendaylight.controller.sal.connector.zeromq; + +import org.opendaylight.controller.sal.core.api.AbstractProvider; +import org.opendaylight.controller.sal.core.api.Broker.ProviderSession; +import org.osgi.framework.BundleContext; + +public class Activator extends AbstractProvider { + + ZeroMqRpcRouter router; + + @Override + public void onSessionInitiated(ProviderSession session) { + router = ZeroMqRpcRouter.getInstance(); + router.setBrokerSession(session); + router.start(); + } + + @Override + protected void stopImpl(BundleContext context) { + router.stop(); + } + +} diff --git a/opendaylight/md-sal/sal-zeromq-connector/src/main/java/org/opendaylight/controller/sal/connector/zeromq/Message.java b/opendaylight/md-sal/sal-zeromq-connector/src/main/java/org/opendaylight/controller/sal/connector/zeromq/Message.java new file mode 100644 index 0000000000..dd87646ed6 --- /dev/null +++ b/opendaylight/md-sal/sal-zeromq-connector/src/main/java/org/opendaylight/controller/sal/connector/zeromq/Message.java @@ -0,0 +1,150 @@ +package org.opendaylight.controller.sal.connector.zeromq; + + +import org.codehaus.jackson.map.ObjectMapper; +import org.opendaylight.controller.sal.connector.api.RpcRouter; + +import java.io.*; +import java.util.Arrays; + +public class Message implements Serializable { + + public enum MessageType { + ANNOUNCE((byte) 0), + HEARTBEAT((byte) 1), + REQUEST((byte) 2), + RESPONSE((byte) 3); + + private final byte type; + + MessageType(byte type) { + this.type = type; + } + + public byte getType(){ + return this.type; + } + } + + private MessageType type; + private String sender; + private RpcRouter.RouteIdentifier route; + private Object payload; + + public MessageType getType() { + return type; + } + + public void setType(MessageType type) { + this.type = type; + } + + public String getSender() { + return sender; + } + + public void setSender(String sender) { + this.sender = sender; + } + + public RpcRouter.RouteIdentifier getRoute() { + return route; + } + + public void setRoute(RpcRouter.RouteIdentifier route) { + this.route = route; + } + + public Object getPayload() { + return payload; + } + + public void setPayload(Object payload) { + this.payload = payload; + } + + @Override + public String toString() { + return "Message{" + + "type=" + type + + ", sender='" + sender + '\'' + + ", route=" + route + + ", payload=" + payload + + '}'; + } + + /** + * Converts any {@link Serializable} object to byte[] + * + * @param obj + * @return + * @throws IOException + */ + public static byte[] serialize(Object obj) throws IOException { + ByteArrayOutputStream b = new ByteArrayOutputStream(); + ObjectOutputStream o = new ObjectOutputStream(b); + o.writeObject(obj); + return b.toByteArray(); + } + + /** + * Converts byte[] to a java object + * + * @param bytes + * @return + * @throws IOException + * @throws ClassNotFoundException + */ + public static Object deserialize(byte[] bytes) throws IOException, ClassNotFoundException { + ByteArrayInputStream b = new ByteArrayInputStream(bytes); + ObjectInputStream o = new ObjectInputStream(b); + return o.readObject(); + } + + public static byte[] toJsonBytes(Message m){ + ObjectMapper o = new ObjectMapper(); + try { + System.out.println(o.writeValueAsString(m)); + return o.writeValueAsBytes(m); + } catch (IOException e) { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + return null; + } + + public static Message fromJsonBytes(byte [] bytes){ + + ObjectMapper o = new ObjectMapper(); + Message m = null; + try { + m = o.readValue(bytes, Message.class); + } catch (IOException e) { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + return m; + } + + public static class Response extends Message implements RpcRouter.RpcReply { + private ResponseCode code; // response code + + public static enum ResponseCode { + SUCCESS(200), BADREQUEST(400), TIMEOUT(408), GONE(410), SERVERERROR(500), SERVICEUNAVAILABLE(503); + + private int code; + + ResponseCode(int code) { + this.code = code; + } + } + + public ResponseCode getCode() { + return code; + } + + public void setCode(ResponseCode code) { + this.code = code; + } + } + +} + diff --git a/opendaylight/md-sal/sal-zeromq-connector/src/main/java/org/opendaylight/controller/sal/connector/zeromq/RouteIdentifierImpl.java b/opendaylight/md-sal/sal-zeromq-connector/src/main/java/org/opendaylight/controller/sal/connector/zeromq/RouteIdentifierImpl.java new file mode 100644 index 0000000000..8eab01b1fb --- /dev/null +++ b/opendaylight/md-sal/sal-zeromq-connector/src/main/java/org/opendaylight/controller/sal/connector/zeromq/RouteIdentifierImpl.java @@ -0,0 +1,53 @@ +package org.opendaylight.controller.sal.connector.zeromq; + +import org.opendaylight.controller.sal.connector.api.RpcRouter; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; + +import java.io.Serializable; + +/** + * User: abhishk2 + */ +public class RouteIdentifierImpl implements RpcRouter.RouteIdentifier,Serializable { + + private QName context; + private QName type; + private InstanceIdentifier route; + + @Override + public QName getContext() { + return this.context; + } + + @Override + public QName getType() { + return this.type; + } + + @Override + public InstanceIdentifier getRoute() { + return this.route; + } + + public void setContext(QName context) { + this.context = context; + } + + public void setType(QName type) { + this.type = type; + } + + public void setRoute(InstanceIdentifier route) { + this.route = route; + } + + @Override + public String toString() { + return "RouteIdentifierImpl{" + + "context=" + context + + ", type=" + type + + ", route=" + route + + '}'; + } +} diff --git a/opendaylight/md-sal/sal-zeromq-connector/src/main/java/org/opendaylight/controller/sal/connector/zeromq/RpcReplyImpl.java b/opendaylight/md-sal/sal-zeromq-connector/src/main/java/org/opendaylight/controller/sal/connector/zeromq/RpcReplyImpl.java new file mode 100644 index 0000000000..66ff7148a5 --- /dev/null +++ b/opendaylight/md-sal/sal-zeromq-connector/src/main/java/org/opendaylight/controller/sal/connector/zeromq/RpcReplyImpl.java @@ -0,0 +1,26 @@ +package org.opendaylight.controller.sal.connector.zeromq; + +import org.opendaylight.controller.sal.connector.api.RpcRouter; + +import java.io.Serializable; + +/** + * Created with IntelliJ IDEA. + * User: abhishk2 + * Date: 10/24/13 + * Time: 4:25 PM + * To change this template use File | Settings | File Templates. + */ +public class RpcReplyImpl implements RpcRouter.RpcReply,Serializable { + + private Object payload; + + @Override + public Object getPayload() { + return payload; //To change body of implemented methods use File | Settings | File Templates. + } + + public void setPayload(Object payload){ + this.payload = payload; + } +} diff --git a/opendaylight/md-sal/sal-zeromq-connector/src/main/java/org/opendaylight/controller/sal/connector/zeromq/RpcRequestImpl.java b/opendaylight/md-sal/sal-zeromq-connector/src/main/java/org/opendaylight/controller/sal/connector/zeromq/RpcRequestImpl.java new file mode 100644 index 0000000000..2361ab76c3 --- /dev/null +++ b/opendaylight/md-sal/sal-zeromq-connector/src/main/java/org/opendaylight/controller/sal/connector/zeromq/RpcRequestImpl.java @@ -0,0 +1,39 @@ +package org.opendaylight.controller.sal.connector.zeromq; + +import org.opendaylight.controller.sal.connector.api.RpcRouter; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; + +import java.io.Serializable; + +/** + * Created with IntelliJ IDEA. + * User: abhishk2 + * Date: 10/25/13 + * Time: 12:32 PM + * To change this template use File | Settings | File Templates. + */ +public class RpcRequestImpl implements RpcRouter.RpcRequest,Serializable { + + private RpcRouter.RouteIdentifier routeIdentifier; + private Object payload; + + @Override + public RpcRouter.RouteIdentifier getRoutingInformation() { + return routeIdentifier; + } + + public void setRouteIdentifier(RpcRouter.RouteIdentifier routeIdentifier) { + this.routeIdentifier = routeIdentifier; + } + + @Override + public Object getPayload() { + return payload; + } + + public void setPayload(Object payload) { + this.payload = payload; + } + +} diff --git a/opendaylight/md-sal/sal-zeromq-connector/src/main/java/org/opendaylight/controller/sal/connector/zeromq/ZeroMqRpcRouter.java b/opendaylight/md-sal/sal-zeromq-connector/src/main/java/org/opendaylight/controller/sal/connector/zeromq/ZeroMqRpcRouter.java new file mode 100644 index 0000000000..7e5efda362 --- /dev/null +++ b/opendaylight/md-sal/sal-zeromq-connector/src/main/java/org/opendaylight/controller/sal/connector/zeromq/ZeroMqRpcRouter.java @@ -0,0 +1,337 @@ +package org.opendaylight.controller.sal.connector.zeromq; + +import org.opendaylight.controller.sal.connector.api.RpcRouter; +import org.opendaylight.controller.sal.core.api.Broker.ProviderSession; +import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration; +import org.opendaylight.controller.sal.core.api.RpcImplementation; +import org.opendaylight.controller.sal.core.api.RpcRegistrationListener; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; +import org.zeromq.ZMQ; + +import java.io.IOException; +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.*; +import java.util.concurrent.*; + +public class ZeroMqRpcRouter implements RpcRouter { + + private ExecutorService serverPool; + private static ExecutorService handlersPool; + + private Map, String> routingTable; + + private ProviderSession brokerSession; + + private ZMQ.Context context; + private ZMQ.Socket publisher; + private ZMQ.Socket subscriber; + private ZMQ.Socket replySocket; + + private static ZeroMqRpcRouter _instance = new ZeroMqRpcRouter(); + + private final RpcFacade facade = new RpcFacade(); + private final RpcListener listener = new RpcListener(); + + private String pubPort = System.getProperty("pub.port");//port on which announcements are sent + private String subPort = System.getProperty("sub.port");//other controller's pub port + private String pubIp = System.getProperty("pub.ip"); //other controller's ip + private String rpcPort = System.getProperty("rpc.port");//port on which RPC messages are received + + + private ZeroMqRpcRouter() { + } + + public static ZeroMqRpcRouter getInstance() { + return _instance; + } + + public void start() { + context = ZMQ.context(2); + serverPool = Executors.newSingleThreadExecutor(); + handlersPool = Executors.newCachedThreadPool(); + routingTable = new ConcurrentHashMap, String>(); + + // Start listening for announce and rpc messages + serverPool.execute(receive()); + + + brokerSession.addRpcRegistrationListener(listener); + Set currentlySupported = brokerSession.getSupportedRpcs(); + for(QName rpc : currentlySupported) { + listener.onRpcImplementationAdded(rpc); + } + + + } + + public void stop() { + if (handlersPool != null) handlersPool.shutdown(); + if (serverPool != null) serverPool.shutdown(); + if (publisher != null) { + publisher.setLinger(0); + publisher.close(); + } + if (replySocket != null) { + replySocket.setLinger(0); + replySocket.close(); + } + if (subscriber != null) { + subscriber.setLinger(0); + subscriber.close(); + } + if (context != null) context.term(); + + + } + + private Runnable receive() { + return new Runnable() { + public void run() { + try { + // Bind to RPC reply socket + replySocket = context.socket(ZMQ.REP); + replySocket.bind("tcp://*:" + rpcPort); + + // Bind to publishing controller + subscriber = context.socket(ZMQ.SUB); + subscriber.connect("tcp://" + pubIp + ":" + subPort); + System.out.println("Subscribing at[" + "tcp://" + pubIp + ":" + subPort + "]"); + + subscriber.subscribe(Message.serialize(Message.MessageType.ANNOUNCE)); + + // Initialize poll set + ZMQ.Poller poller = new ZMQ.Poller(2); + poller.register(replySocket, ZMQ.Poller.POLLIN); + poller.register(subscriber, ZMQ.Poller.POLLIN); + + while (!Thread.currentThread().isInterrupted()) { + + poller.poll(250); + //TODO: Fix this + if (poller.pollin(0)) { + //receive rpc request and reply + try { + Message req = parseMessage(replySocket); + Message resp = new Message(); + //Call broker to process the message then reply + Future> rpc = brokerSession.rpc((QName) req.getRoute().getType(), (CompositeNode) req.getPayload()); + RpcResult result = rpc.get(); + resp.setType(Message.MessageType.RESPONSE); + resp.setSender(getLocalIpAddress() + ":" + rpcPort); + resp.setRoute(req.getRoute()); + resp.setPayload(result.isSuccessful()); + replySocket.send(Message.serialize(resp)); + + } catch (IOException ex) {// | ClassNotFoundException ex) { + System.out.println("Rpc request could not be handled" + ex); + } + } + if (poller.pollin(1)) { + //get subscription and update routing table + //try { + Message.MessageType topic = (Message.MessageType)Message.deserialize(subscriber.recv()); + System.out.println("Topic:[" + topic + "]"); + + if (subscriber.hasReceiveMore()) { + try { + Message m = (Message) Message.deserialize(subscriber.recv()); + System.out.println(m); + //TODO: check on msg type or topic. Both should be same. Need to normalize. + if (Message.MessageType.ANNOUNCE == m.getType()) updateRoutingTable(m); + } catch (IOException | ClassNotFoundException e) { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + } +// + } + } + } catch (Exception e) { + e.printStackTrace(); + } + replySocket.setLinger(0); + replySocket.close(); + subscriber.setLinger(0); + subscriber.close(); + } + }; + } + + private void updateRoutingTable(Message msg) { + routingTable.put(msg.getRoute(), msg.getSender()); + RpcRouter.RouteIdentifier route = msg.getRoute(); + QName rpcType = route.getType(); + System.out.println("Routing Table\n" + routingTable); + + RpcRegistration registration = brokerSession.addRpcImplementation(rpcType, facade); + } + + private Message parseMessage(ZMQ.Socket socket) { + //Message m = new Message(); + //socket.setReceiveBufferSize(40000); + Message msg = null; + try { + byte[] bytes = socket.recv(); + System.out.println("Received bytes:[" + bytes.length + "]"); + msg = (Message) Message.deserialize(bytes); + } catch (Throwable t) { + System.out.println("Caught exception"); + t.printStackTrace(); + } + return msg; + /*m.setType((Message.MessageType) Message.deserialize(socket.recv())); + + if (socket.hasReceiveMore()) { + m.setSender((String) Message.deserialize(socket.recv())); + } + if (socket.hasReceiveMore()) { + m.setRoute((RouteIdentifier) Message.deserialize(socket.recv())); + } + if (socket.hasReceiveMore()) { + m.setPayload(Message.deserialize(socket.recv())); + } + return m;*/ + } + + @Override + public Future> sendRpc(final RpcRequest input) { + + return handlersPool.submit(new Callable>() { + + @Override + public RpcReply call() { + ZMQ.Socket requestSocket = context.socket(ZMQ.REQ); + Message req = new Message(); + Message resp = null; + RpcReplyImpl reply = new RpcReplyImpl(); + requestSocket.connect((String) routingTable.get(input.getRoutingInformation().getRoute())); + + req.setType(Message.MessageType.REQUEST); + req.setSender(getLocalIpAddress() + ":" + rpcPort); + req.setRoute(input.getRoutingInformation()); + req.setPayload(input.getPayload()); + try { + requestSocket.send(Message.serialize(req)); + resp = parseMessage(requestSocket); + reply.setPayload(resp.getPayload()); + } catch (IOException ex) {//| ClassNotFoundException ex) { + //Log and ignore + System.out.println("Error in RPC send. Input could not be serialized[" + input + "]"); + } + + return reply; + } + }); + } + + public void publish(final Message message) { + Runnable task = new Runnable() { + public void run() { + // Bind to publishing port + publisher = context.socket(ZMQ.PUB); + publisher.bind("tcp://*:" + pubPort); + System.out.println("Publisher started at port[" + pubPort + "]"); + try { + Message outMessage = new Message(); + outMessage.setType(Message.MessageType.ANNOUNCE); + outMessage.setSender("tcp://" + getLocalIpAddress() + ":" + rpcPort); + outMessage.setRoute(message.getRoute()); + + System.out.println("Sending announcement[" + outMessage + "]"); + publisher.sendMore(Message.serialize(Message.MessageType.ANNOUNCE)); + publisher.send(Message.serialize(outMessage)); + + } catch (IOException ex) { + //Log and ignore + System.out.println("Error in publishing"); + ex.printStackTrace(); + } + System.out.println("Published message[" + message + "]"); + publisher.close(); + } + }; + handlersPool.execute(task); + } + + private String getLocalIpAddress() { + String hostAddress = null; + Enumeration e = null; + try { + e = NetworkInterface.getNetworkInterfaces(); + } catch (SocketException e1) { + e1.printStackTrace(); + } + while (e.hasMoreElements()) { + + NetworkInterface n = (NetworkInterface) e.nextElement(); + Enumeration ee = n.getInetAddresses(); + while (ee.hasMoreElements()) { + InetAddress i = (InetAddress) ee.nextElement(); + if ((i instanceof Inet4Address) && (i.isSiteLocalAddress())) + hostAddress = i.getHostAddress(); + } + } + + return hostAddress; + + + } + + + private class RpcFacade implements RpcImplementation { + + + @Override + public Set getSupportedRpcs() { + return Collections.emptySet(); + } + + @Override + public RpcResult invokeRpc(QName rpc, CompositeNode input) { + + RpcRequestImpl request = new RpcRequestImpl(); + RouteIdentifierImpl routeId = new RouteIdentifierImpl(); + routeId.setContext(null); + routeId.setRoute(null); + routeId.setType(rpc); + + request.setRouteIdentifier(routeId); + request.setPayload(input); + // Create message + + Future> ret = sendRpc(request); + + return null; + } + } + + private class RpcListener implements RpcRegistrationListener { + + @Override + public void onRpcImplementationAdded(QName name) { + + Message msg = new Message(); + RouteIdentifierImpl routeId = new RouteIdentifierImpl(); + routeId.setType(name); + msg.setRoute(routeId); + publish(msg); + } + + @Override + public void onRpcImplementationRemoved(QName name) { + // TODO Auto-generated method stub + + } + } + + public void setBrokerSession(ProviderSession session) { + this.brokerSession = session; + + } + +} diff --git a/opendaylight/md-sal/samples/pom.xml b/opendaylight/md-sal/samples/pom.xml index 7bd9a3a5ba..04e0a32ffb 100644 --- a/opendaylight/md-sal/samples/pom.xml +++ b/opendaylight/md-sal/samples/pom.xml @@ -17,8 +17,20 @@ toaster toaster-consumer - toaster-it toaster-provider + + + + integrationtests + + false + + + toaster-it + + + + org.opendaylight.controller.samples diff --git a/opendaylight/md-sal/test/pom.xml b/opendaylight/md-sal/test/pom.xml new file mode 100644 index 0000000000..f9e500ea2b --- /dev/null +++ b/opendaylight/md-sal/test/pom.xml @@ -0,0 +1,24 @@ + + 4.0.0 + + sal-parent + 1.0-SNAPSHOT + org.opendaylight.controller + + pom + org.opendaylight.controller.tests + sal-test-parent + + scm:git:ssh://git.opendaylight.org:29418/controller.git + scm:git:ssh://git.opendaylight.org:29418/controller.git + https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL + + + + zeromq-test-consumer + zeromq-test-it + zeromq-test-provider + + + diff --git a/opendaylight/md-sal/test/zeromq-test-consumer/pom.xml b/opendaylight/md-sal/test/zeromq-test-consumer/pom.xml new file mode 100644 index 0000000000..7c6bc21b46 --- /dev/null +++ b/opendaylight/md-sal/test/zeromq-test-consumer/pom.xml @@ -0,0 +1,85 @@ + + 4.0.0 + + sal-test-parent + org.opendaylight.controller.tests + 1.0-SNAPSHOT + + zeromq-test-consumer + bundle + + scm:git:ssh://git.opendaylight.org:29418/controller.git + scm:git:ssh://git.opendaylight.org:29418/controller.git + https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL + + + + + + + org.apache.felix + maven-bundle-plugin + + + org.opendaylight.controller.sample.zeromq.consumer.ExampleConsumer + + org.opendaylight.controller.sal.core.api, + org.opendaylight.yangtools.yang.common;version="[0.5,1)", + org.opendaylight.yangtools.yang.data.api, + + + + + + + + + + org.opendaylight.controller + sal-binding-api + 1.0-SNAPSHOT + + + org.opendaylight.controller + sal-common-util + 1.0-SNAPSHOT + + + org.opendaylight.controller + sal-core-api + 1.0-SNAPSHOT + + + + + org.opendaylight.controller + containermanager + 0.5.1-SNAPSHOT + + + + org.opendaylight.controller + sal + 0.5.1-SNAPSHOT + + + org.opendaylight.yangtools + yang-binding + + + org.opendaylight.yangtools + yang-common + + + org.opendaylight.yangtools + yang-data-api + + + + org.opendaylight.controller + sal-common-util + 1.0-SNAPSHOT + + + diff --git a/opendaylight/md-sal/test/zeromq-test-consumer/src/main/java/org/opendaylight/controller/sample/zeromq/consumer/ExampleConsumer.java b/opendaylight/md-sal/test/zeromq-test-consumer/src/main/java/org/opendaylight/controller/sample/zeromq/consumer/ExampleConsumer.java new file mode 100644 index 0000000000..a56a7dedff --- /dev/null +++ b/opendaylight/md-sal/test/zeromq-test-consumer/src/main/java/org/opendaylight/controller/sample/zeromq/consumer/ExampleConsumer.java @@ -0,0 +1,51 @@ +package org.opendaylight.controller.sample.zeromq.consumer; + +import java.net.URI; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import org.opendaylight.controller.sal.core.api.AbstractConsumer; +import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.osgi.framework.BundleContext; + +public class ExampleConsumer extends AbstractConsumer { + + private final URI namespace = URI.create("http://cisco.com/example"); + private final QName QNAME = new QName(namespace,"heartbeat"); + + ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); + private ConsumerSession session; + + + @Override + public void onSessionInitiated(ConsumerSession session) { + this.session = session; + executor.scheduleAtFixedRate(new Runnable() { + + @Override + public void run() { + int count = 0; + try { + Future> future = ExampleConsumer.this.session.rpc(QNAME, null); + RpcResult result = future.get(); + System.out.println("Result received. Status is :" + result.isSuccessful()); + } catch (Exception e) { + e.printStackTrace(); + } + + } + }, 0, 10, TimeUnit.SECONDS); + } + + @Override + protected void stopImpl(BundleContext context) { + // TODO Auto-generated method stub + super.stopImpl(context); + executor.shutdown(); + } +} diff --git a/opendaylight/md-sal/test/zeromq-test-it/pom.xml b/opendaylight/md-sal/test/zeromq-test-it/pom.xml new file mode 100644 index 0000000000..56945d1d34 --- /dev/null +++ b/opendaylight/md-sal/test/zeromq-test-it/pom.xml @@ -0,0 +1,184 @@ + + 4.0.0 + + sal-test-parent + org.opendaylight.controller.tests + 1.0-SNAPSHOT + + zeromq-test-it + + scm:git:ssh://git.opendaylight.org:29418/controller.git + scm:git:ssh://git.opendaylight.org:29418/controller.git + https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL + + + + 3.0.0 + 1.5.0 + + + + + + org.ops4j.pax.exam + maven-paxexam-plugin + 1.2.4 + + + generate-config + + generate-depends-file + + + + + + + + + + org.eclipse.m2e + lifecycle-mapping + 1.0.0 + + + + + + + org.ops4j.pax.exam + + + maven-paxexam-plugin + + + [1.2.4,) + + + + generate-depends-file + + + + + + + + + + + + + + + + + + org.opendaylight.yangtools.thirdparty + xtend-lib-osgi + 2.4.3 + + + org.opendaylight.controller.tests + zeromq-test-provider + 1.0-SNAPSHOT + + + org.opendaylight.controller.tests + zeromq-test-consumer + 1.0-SNAPSHOT + + + org.opendaylight.controller + sal-broker-impl + 1.0-SNAPSHOT + + + org.ops4j.pax.exam + pax-exam-container-native + ${exam.version} + test + + + org.ops4j.pax.exam + pax-exam-junit4 + ${exam.version} + test + + + org.ops4j.pax.exam + pax-exam-link-mvn + ${exam.version} + test + + + equinoxSDK381 + org.eclipse.osgi + 3.8.1.v20120830-144521 + test + + + org.slf4j + log4j-over-slf4j + 1.7.2 + + + ch.qos.logback + logback-core + 1.0.9 + + + ch.qos.logback + logback-classic + 1.0.9 + + + org.opendaylight.controller + sal-binding-api + 1.0-SNAPSHOT + + + org.opendaylight.controller + sal-common-util + 1.0-SNAPSHOT + + + org.opendaylight.controller + sal-core-api + 1.0-SNAPSHOT + + + + + org.opendaylight.controller + containermanager + 0.5.1-SNAPSHOT + + + + org.opendaylight.controller + sal + 0.5.1-SNAPSHOT + + + org.opendaylight.yangtools + yang-binding + + + org.opendaylight.yangtools + yang-common + + + org.opendaylight.yangtools + yang-data-api + + + + org.opendaylight.controller + sal-common-util + 1.0-SNAPSHOT + + + diff --git a/opendaylight/md-sal/test/zeromq-test-it/src/test/java/org/opendaylight/controller/sample/zeromq/test/it/ServiceConsumerController.java b/opendaylight/md-sal/test/zeromq-test-it/src/test/java/org/opendaylight/controller/sample/zeromq/test/it/ServiceConsumerController.java new file mode 100644 index 0000000000..c17b143d70 --- /dev/null +++ b/opendaylight/md-sal/test/zeromq-test-it/src/test/java/org/opendaylight/controller/sample/zeromq/test/it/ServiceConsumerController.java @@ -0,0 +1,75 @@ +package org.opendaylight.controller.sample.zeromq.test.it; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.ops4j.pax.exam.Configuration; +import org.ops4j.pax.exam.Option; +import org.ops4j.pax.exam.junit.PaxExam; +import org.osgi.framework.BundleContext; + +import javax.inject.Inject; + +import static org.junit.Assert.assertTrue; +import static org.ops4j.pax.exam.CoreOptions.*; + +@RunWith(PaxExam.class) +public class ServiceConsumerController { + + public static final String ODL = "org.opendaylight.controller"; + public static final String YANG = "org.opendaylight.yangtools"; + public static final String SAMPLE = "org.opendaylight.controller.samples"; + + @Test + public void properInitialized() throws Exception { + + Thread.sleep(30000); // Waiting for services to get wired. + assertTrue(true); + //assertTrue(consumer.createToast(WhiteBread.class, 5)); + + } + +// @Inject +// BindingAwareBroker broker; + +// @Inject +// ToastConsumer consumer; + + @Inject + BundleContext ctx; + + @Configuration + public Option[] config() { + return options(systemProperty("osgi.console").value("2401"), + systemProperty("pub.port").value("5557"), + systemProperty("sub.port").value("5556"), + systemProperty("rpc.port").value("5555"), + systemProperty("pub.ip").value("localhost"), + 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-broker-impl").versionAsInProject().update(), // + mavenBundle(ODL, "sal-common").versionAsInProject(), // + mavenBundle(ODL, "sal-common-api").versionAsInProject(),// + mavenBundle(ODL, "sal-common-impl").versionAsInProject(), // + mavenBundle(ODL, "sal-common-util").versionAsInProject(), // + mavenBundle(ODL, "sal-core-api").versionAsInProject().update(), // + mavenBundle(ODL, "sal-broker-impl").versionAsInProject(), // + mavenBundle(ODL, "sal-core-spi").versionAsInProject().update(), // + mavenBundle(ODL, "sal-connector-api").versionAsInProject(), // + mavenBundle(SAMPLE, "zeromq-test-consumer").versionAsInProject(), // + mavenBundle(ODL, "sal-zeromq-connector").versionAsInProject(), // + mavenBundle(YANG, "concepts").versionAsInProject(), + mavenBundle(YANG, "yang-binding").versionAsInProject(), // + mavenBundle(YANG, "yang-common").versionAsInProject(), // + mavenBundle(YANG, "yang-data-api").versionAsInProject(), // + mavenBundle(YANG, "yang-model-api").versionAsInProject(), // + mavenBundle(YANG+".thirdparty", "xtend-lib-osgi").versionAsInProject(), // + mavenBundle("com.google.guava", "guava").versionAsInProject(), // + mavenBundle("org.jeromq", "jeromq").versionAsInProject(), + junitBundles() + ); + } + +} diff --git a/opendaylight/md-sal/test/zeromq-test-it/src/test/java/org/opendaylight/controller/sample/zeromq/test/it/ServiceProviderController.java b/opendaylight/md-sal/test/zeromq-test-it/src/test/java/org/opendaylight/controller/sample/zeromq/test/it/ServiceProviderController.java new file mode 100644 index 0000000000..2d28b0b5b5 --- /dev/null +++ b/opendaylight/md-sal/test/zeromq-test-it/src/test/java/org/opendaylight/controller/sample/zeromq/test/it/ServiceProviderController.java @@ -0,0 +1,86 @@ +package org.opendaylight.controller.sample.zeromq.test.it; + +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.options; +import static org.ops4j.pax.exam.CoreOptions.systemPackages; +import static org.ops4j.pax.exam.CoreOptions.systemProperty; +import static org.ops4j.pax.exam.CoreOptions.maven; + +import java.util.Collection; + +import javax.inject.Inject; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; +import org.ops4j.pax.exam.Configuration; +import org.ops4j.pax.exam.CoreOptions; +import org.ops4j.pax.exam.Option; +import org.ops4j.pax.exam.junit.PaxExam; +import org.osgi.framework.BundleContext; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.framework.ServiceReference; + +@RunWith(PaxExam.class) +public class ServiceProviderController { + + public static final String ODL = "org.opendaylight.controller"; + public static final String YANG = "org.opendaylight.yangtools"; + public static final String SAMPLE = "org.opendaylight.controller.samples"; + + @Test + public void properInitialized() throws Exception { + + Thread.sleep(30000); // Waiting for services to get wired. + assertTrue(true); + //assertTrue(consumer.createToast(WhiteBread.class, 5)); + + } + +// @Inject +// BindingAwareBroker broker; + +// @Inject +// ToastConsumer consumer; + + @Inject + BundleContext ctx; + + @Configuration + public Option[] config() { + return options(systemProperty("osgi.console").value("2401"), + systemProperty("pub.port").value("5556"), + systemProperty("sub.port").value("5557"), + systemProperty("rpc.port").value("5554"), + systemProperty("pub.ip").value("localhost"), + 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-broker-impl").versionAsInProject().update(), // + mavenBundle(ODL, "sal-common").versionAsInProject(), // + mavenBundle(ODL, "sal-common-api").versionAsInProject(),// + mavenBundle(ODL, "sal-common-impl").versionAsInProject(), // + mavenBundle(ODL, "sal-common-util").versionAsInProject(), // + mavenBundle(ODL, "sal-core-api").versionAsInProject().update(), // + mavenBundle(ODL, "sal-broker-impl").versionAsInProject(), // + mavenBundle(ODL, "sal-core-spi").versionAsInProject().update(), // + mavenBundle(ODL, "sal-connector-api").versionAsInProject(), // + mavenBundle(SAMPLE, "zeromq-test-provider").versionAsInProject(), // + mavenBundle(ODL, "sal-zeromq-connector").versionAsInProject(), // + mavenBundle(YANG, "concepts").versionAsInProject(), + mavenBundle(YANG, "yang-binding").versionAsInProject(), // + mavenBundle(YANG, "yang-common").versionAsInProject(), // + mavenBundle(YANG, "yang-data-api").versionAsInProject(), // + mavenBundle(YANG, "yang-model-api").versionAsInProject(), // + mavenBundle(YANG+".thirdparty", "xtend-lib-osgi").versionAsInProject(), // + mavenBundle("com.google.guava", "guava").versionAsInProject(), // + mavenBundle("org.jeromq", "jeromq").versionAsInProject(), + junitBundles() + ); + } + +} diff --git a/opendaylight/md-sal/test/zeromq-test-provider/pom.xml b/opendaylight/md-sal/test/zeromq-test-provider/pom.xml new file mode 100644 index 0000000000..10e15aa917 --- /dev/null +++ b/opendaylight/md-sal/test/zeromq-test-provider/pom.xml @@ -0,0 +1,86 @@ + + 4.0.0 + + sal-test-parent + org.opendaylight.controller.tests + 1.0-SNAPSHOT + + zeromq-test-provider + bundle + + scm:git:ssh://git.opendaylight.org:29418/controller.git + scm:git:ssh://git.opendaylight.org:29418/controller.git + https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL + + + + + + + org.apache.felix + maven-bundle-plugin + + + org.opendaylight.controller.sample.zeromq.provider.ExampleProvider + + + + + + + + + org.opendaylight.controller + sal-binding-api + 1.0-SNAPSHOT + + + org.opendaylight.controller + sal-common-util + 1.0-SNAPSHOT + + + org.opendaylight.controller + sal-core-api + 1.0-SNAPSHOT + + + + + org.opendaylight.controller + containermanager + 0.5.1-SNAPSHOT + + + + org.opendaylight.controller + sal + 0.5.1-SNAPSHOT + + + org.opendaylight.yangtools + yang-binding + + + org.opendaylight.yangtools + yang-common + + + org.opendaylight.yangtools + yang-data-api + + + + org.opendaylight.controller + sal-common-util + 1.0-SNAPSHOT + + + org.opendaylight.controller + sal-zeromq-connector + 1.0-SNAPSHOT + + + + diff --git a/opendaylight/md-sal/test/zeromq-test-provider/src/main/java/org/opendaylight/controller/sample/zeromq/provider/ExampleProvider.java b/opendaylight/md-sal/test/zeromq-test-provider/src/main/java/org/opendaylight/controller/sample/zeromq/provider/ExampleProvider.java new file mode 100644 index 0000000000..ec7d7a8285 --- /dev/null +++ b/opendaylight/md-sal/test/zeromq-test-provider/src/main/java/org/opendaylight/controller/sample/zeromq/provider/ExampleProvider.java @@ -0,0 +1,67 @@ +package org.opendaylight.controller.sample.zeromq.provider; + +import java.net.URI; +import java.util.Collection; +import java.util.Collections; +import java.util.Set; + +import org.opendaylight.controller.sal.common.util.Rpcs; +import org.opendaylight.controller.sal.core.api.AbstractProvider; +import org.opendaylight.controller.sal.core.api.Broker.ProviderSession; +import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration; +import org.opendaylight.controller.sal.core.api.RpcImplementation; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.RpcError; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.osgi.framework.BundleContext; + +public class ExampleProvider extends AbstractProvider implements RpcImplementation { + + private final URI namespace = URI.create("http://cisco.com/example"); + private final QName QNAME = new QName(namespace,"heartbeat"); + private RpcRegistration reg; + + + @Override + public void onSessionInitiated(ProviderSession session) { + //Adding heartbeat 10 times just to make sure subscriber get it + for (int i=0;i<10;i++){ + System.out.println("ExampleProvider: Adding " + QNAME + " " + i); + reg = session.addRpcImplementation(QNAME, this); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + } + } + + @Override + public Set getSupportedRpcs() { + return Collections.singleton(QNAME); + } + + @Override + public RpcResult invokeRpc(QName rpc, CompositeNode input) { + if(QNAME.equals(rpc)) { + RpcResult output = Rpcs.getRpcResult(true, null, Collections.emptySet()); + return output; + } + RpcResult output = Rpcs.getRpcResult(false, null, Collections.emptySet()); + return output; + } + + @Override + protected void stopImpl(BundleContext context) { + if(reg != null) { + try { + reg.close(); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + +} diff --git a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigTest.java b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigTest.java index 18c8ce5d15..123c03e9a1 100644 --- a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigTest.java +++ b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigTest.java @@ -67,6 +67,8 @@ public class EditConfigTest { doNothing().when(provider).abortTestTransaction(any(ObjectName.class)); doReturn(mockOn).when(provider).getOrCreateTransaction(); + doNothing().when(provider).wipeTestTransaction(any(ObjectName.class)); + doReturn(configTransactionClient).when(configRegistry).getConfigTransactionClient(any(ObjectName.class)); doReturn("mockConfigTransactionClient").when(configTransactionClient).toString(); diff --git a/opendaylight/netconf/config-persister-impl/src/main/resources/netconfOp/editConfig.xml b/opendaylight/netconf/config-persister-impl/src/main/resources/netconfOp/editConfig.xml index 8ec1c8c069..8f6ec9c4c2 100644 --- a/opendaylight/netconf/config-persister-impl/src/main/resources/netconfOp/editConfig.xml +++ b/opendaylight/netconf/config-persister-impl/src/main/resources/netconfOp/editConfig.xml @@ -3,7 +3,7 @@ - replace + merge diff --git a/opendaylight/netconf/pom.xml b/opendaylight/netconf/pom.xml index 7f0bd44078..8f69f8dca0 100644 --- a/opendaylight/netconf/pom.xml +++ b/opendaylight/netconf/pom.xml @@ -23,12 +23,23 @@ netconf-impl config-netconf-connector netconf-util - netconf-it config-persister-impl netconf-mapping-api netconf-client + + + integrationtests + + false + + + netconf-it + + + + 5.0.0 2.3.7 diff --git a/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronSubnet.java b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronSubnet.java index d791939486..c6ea9421f9 100644 --- a/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronSubnet.java +++ b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronSubnet.java @@ -265,7 +265,6 @@ public class NeutronSubnet { allocationPools = source.splitPool(gatewayIP); } } catch (Exception e) { - ; } } diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Bandwidth.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Bandwidth.java index 5083cf57d7..30f27793de 100644 --- a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Bandwidth.java +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Bandwidth.java @@ -52,7 +52,6 @@ public class Bandwidth extends Property { private Bandwidth() { super(BandwidthPropName); this.bandwidthValue = BWUNK; - ; } public Bandwidth(long bandwidth) { diff --git a/opendaylight/switchmanager/api/src/main/java/org/opendaylight/controller/switchmanager/SubnetConfig.java b/opendaylight/switchmanager/api/src/main/java/org/opendaylight/controller/switchmanager/SubnetConfig.java index 577c039530..189476a5d1 100644 --- a/opendaylight/switchmanager/api/src/main/java/org/opendaylight/controller/switchmanager/SubnetConfig.java +++ b/opendaylight/switchmanager/api/src/main/java/org/opendaylight/controller/switchmanager/SubnetConfig.java @@ -127,10 +127,20 @@ public class SubnetConfig implements Cloneable, Serializable { return new Status(StatusCode.SUCCESS); } + private Status validateName() { + if (name == null || name.trim().isEmpty()) { + return new Status(StatusCode.BADREQUEST, "Invalid name"); + } + return new Status(StatusCode.SUCCESS); + } + public Status validate() { - Status status = validateSubnetAddress(); + Status status = validateName(); if (status.isSuccess()) { - status = validatePorts(this.nodeConnectors); + status = validateSubnetAddress(); + if (status.isSuccess()) { + status = validatePorts(this.nodeConnectors); + } } return status; } diff --git a/pom.xml b/pom.xml index 5899d563e8..b95cdfd62a 100644 --- a/pom.xml +++ b/pom.xml @@ -26,34 +26,26 @@ opendaylight/forwarding/staticrouting opendaylight/clustering/services opendaylight/clustering/services_implementation - opendaylight/clustering/integrationtest opendaylight/clustering/stub opendaylight/clustering/test opendaylight/configuration/api opendaylight/configuration/implementation - opendaylight/configuration/integrationtest opendaylight/routing/dijkstra_implementation opendaylight/arphandler opendaylight/forwardingrulesmanager/api opendaylight/forwardingrulesmanager/implementation - opendaylight/forwardingrulesmanager/integrationtest opendaylight/hosttracker/api opendaylight/hosttracker/implementation - opendaylight/hosttracker/integrationtest opendaylight/hosttracker_new/api opendaylight/hosttracker_new/implementation opendaylight/containermanager/api opendaylight/containermanager/implementation - opendaylight/containermanager/it.implementation opendaylight/appauth opendaylight/switchmanager/api opendaylight/switchmanager/implementation - opendaylight/switchmanager/integrationtest opendaylight/statisticsmanager/api opendaylight/statisticsmanager/implementation - opendaylight/statisticsmanager/integrationtest opendaylight/topologymanager/implementation - opendaylight/topologymanager/integrationtest opendaylight/usermanager/api opendaylight/usermanager/implementation opendaylight/connectionmanager/api @@ -65,6 +57,7 @@ + third-party/commons/thirdparty @@ -117,8 +110,6 @@ opendaylight/northbound/usermanager opendaylight/northbound/controllermanager - - opendaylight/northbound/integrationtest opendaylight/logging/bridge @@ -131,14 +122,34 @@ opendaylight/samples/loadbalancer opendaylight/samples/northbound/loadbalancer - opendaylight/distribution/sanitytest/ - opendaylight/commons/concepts opendaylight/commons/httpclient - opendaylight/commons/integrationtest opendaylight/commons/checkstyle opendaylight/commons/opendaylight opendaylight/commons/parent + + + + integrationtests + + false + + + opendaylight/clustering/integrationtest + opendaylight/configuration/integrationtest + opendaylight/forwardingrulesmanager/integrationtest + opendaylight/hosttracker/integrationtest + opendaylight/switchmanager/integrationtest + opendaylight/topologymanager/integrationtest + + opendaylight/northbound/integrationtest + opendaylight/statisticsmanager/integrationtest + opendaylight/commons/integrationtest + opendaylight/containermanager/it.implementation + opendaylight/distribution/sanitytest/ + + + diff --git a/third-party/commons/thirdparty/pom.xml b/third-party/commons/thirdparty/pom.xml index b69704ff20..70f3b27873 100644 --- a/third-party/commons/thirdparty/pom.xml +++ b/third-party/commons/thirdparty/pom.xml @@ -25,6 +25,7 @@ 2.3.2 2.13 2.3.2 + 1.3.1 diff --git a/third-party/ganymed/pom.xml b/third-party/ganymed/pom.xml new file mode 100644 index 0000000000..98a6596e0e --- /dev/null +++ b/third-party/ganymed/pom.xml @@ -0,0 +1,79 @@ + + + 4.0.0 + + + org.opendaylight.controller + commons.thirdparty + 1.1.1-SNAPSHOT + ../commons/thirdparty + + + org.opendaylight.controller.thirdparty + ganymed + 1.0-SNAPSHOT + bundle + + + build209 + + + + + org.osgi + org.osgi.core + 4.1.0 + + + ch.ethz.ganymed + ganymed-ssh2 + 261 + + + + + + + org.apache.felix + maven-bundle-plugin + true + + + ch.ethz.ssh2 + ganymed-ssh2;scope=compile + true + + + + + org.apache.maven.plugins + maven-enforcer-plugin + ${enforcer.version} + + + enforce-no-snapshots + + enforce + + + + + + ch.ethz.ganymed:ganymed-ssh2:* + + + ch.ethz.ganymed:ganymed-ssh2:[261] + + + + + + + + + + + + diff --git a/third-party/ganymed/src/main/java/ch/ethz/ssh2/Connection.java b/third-party/ganymed/src/main/java/ch/ethz/ssh2/Connection.java new file mode 100644 index 0000000000..aa13c40d9d --- /dev/null +++ b/third-party/ganymed/src/main/java/ch/ethz/ssh2/Connection.java @@ -0,0 +1,1424 @@ +/* + * Copyright (c) 2006-2011 Christian Plattner. All rights reserved. + * Please refer to the LICENSE.txt for licensing details. + */ + +package ch.ethz.ssh2; + +import java.io.CharArrayWriter; +import java.io.File; +import java.net.Socket; +import java.io.FileReader; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.SocketTimeoutException; +import java.security.SecureRandom; +import java.util.List; +import java.util.Vector; + +import ch.ethz.ssh2.auth.AuthenticationManager; +import ch.ethz.ssh2.channel.ChannelManager; +import ch.ethz.ssh2.crypto.CryptoWishList; +import ch.ethz.ssh2.crypto.cipher.BlockCipherFactory; +import ch.ethz.ssh2.crypto.digest.MAC; +import ch.ethz.ssh2.packets.PacketIgnore; +import ch.ethz.ssh2.transport.KexManager; +import ch.ethz.ssh2.transport.TransportManager; +import ch.ethz.ssh2.util.TimeoutService; +import ch.ethz.ssh2.util.TimeoutService.TimeoutToken; + +/** + * A Connection is used to establish an encrypted TCP/IP + * connection to a SSH-2 server. + *

+ * Typically, one + *

    + *
  1. creates a {@link #Connection(String) Connection} object.
  2. + *
  3. calls the {@link #connect() connect()} method.
  4. + *
  5. calls some of the authentication methods (e.g., {@link #authenticateWithPublicKey(String, File, String) authenticateWithPublicKey()}).
  6. + *
  7. calls one or several times the {@link #openSession() openSession()} method.
  8. + *
  9. finally, one must close the connection and release resources with the {@link #close() close()} method.
  10. + *
+ * + * @author Christian Plattner + * @version $Id: Connection.java 69 2013-08-09 06:39:56Z dkocher@sudo.ch $ + */ + +public class Connection +{ + /** + * The identifier presented to the SSH-2 server. This is the same + * as the "softwareversion" defined in RFC 4253. + *

+ * NOTE: As per the RFC, the "softwareversion" string MUST consist of printable + * US-ASCII characters, with the exception of whitespace characters and the minus sign (-). + */ + private String softwareversion = String.format("Ganymed_%s", Version.getSpecification()); + + /* Will be used to generate all random data needed for the current connection. + * Note: SecureRandom.nextBytes() is thread safe. + */ + + private SecureRandom generator; + + private Socket precreatedSocket; + + public Connection(Socket socket) { + this.precreatedSocket = socket; + this.hostname = socket.getInetAddress().getHostName(); + this.port = socket.getPort(); + } + + /** + * Unless you know what you are doing, you will never need this. + * + * @return The list of supported cipher algorithms by this implementation. + */ + public static synchronized String[] getAvailableCiphers() + { + return BlockCipherFactory.getDefaultCipherList(); + } + + /** + * Unless you know what you are doing, you will never need this. + * + * @return The list of supported MAC algorthims by this implementation. + */ + public static synchronized String[] getAvailableMACs() + { + return MAC.getMacList(); + } + + /** + * Unless you know what you are doing, you will never need this. + * + * @return The list of supported server host key algorthims by this implementation. + */ + public static synchronized String[] getAvailableServerHostKeyAlgorithms() + { + return KexManager.getDefaultServerHostkeyAlgorithmList(); + } + + private AuthenticationManager am; + + private boolean authenticated = false; + private ChannelManager cm; + + private CryptoWishList cryptoWishList = new CryptoWishList(); + + private DHGexParameters dhgexpara = new DHGexParameters(); + + private final String hostname; + + private final int port; + + private TransportManager tm; + + private boolean tcpNoDelay = false; + + private ProxyData proxyData = null; + + private List connectionMonitors = new Vector(); + + /** + * Prepares a fresh Connection object which can then be used + * to establish a connection to the specified SSH-2 server. + *

+ * Same as {@link #Connection(String, int) Connection(hostname, 22)}. + * + * @param hostname the hostname of the SSH-2 server. + */ + public Connection(String hostname) + { + this(hostname, 22); + } + + /** + * Prepares a fresh Connection object which can then be used + * to establish a connection to the specified SSH-2 server. + * + * @param hostname + * the host where we later want to connect to. + * @param port + * port on the server, normally 22. + */ + public Connection(String hostname, int port) + { + this.hostname = hostname; + this.port = port; + } + + /** + * Prepares a fresh Connection object which can then be used + * to establish a connection to the specified SSH-2 server. + * + * @param hostname + * the host where we later want to connect to. + * @param port + * port on the server, normally 22. + * @param softwareversion + * Allows you to set a custom "softwareversion" string as defined in RFC 4253. + * NOTE: As per the RFC, the "softwareversion" string MUST consist of printable + * US-ASCII characters, with the exception of whitespace characters and the minus sign (-). + */ + public Connection(String hostname, int port, String softwareversion) + { + this.hostname = hostname; + this.port = port; + this.softwareversion = softwareversion; + } + + /** + * After a successful connect, one has to authenticate oneself. This method + * is based on DSA (it uses DSA to sign a challenge sent by the server). + *

+ * If the authentication phase is complete, true will be + * returned. If the server does not accept the request (or if further + * authentication steps are needed), false is returned and + * one can retry either by using this or any other authentication method + * (use the getRemainingAuthMethods method to get a list of + * the remaining possible methods). + * + * @param user + * A String holding the username. + * @param pem + * A String containing the DSA private key of the + * user in OpenSSH key format (PEM, you can't miss the + * "-----BEGIN DSA PRIVATE KEY-----" tag). The string may contain + * linefeeds. + * @param password + * If the PEM string is 3DES encrypted ("DES-EDE3-CBC"), then you + * must specify the password. Otherwise, this argument will be + * ignored and can be set to null. + * + * @return whether the connection is now authenticated. + * @throws IOException + * + * @deprecated You should use one of the {@link #authenticateWithPublicKey(String, File, String) authenticateWithPublicKey()} + * methods, this method is just a wrapper for it and will + * disappear in future builds. + * + */ + public synchronized boolean authenticateWithDSA(String user, String pem, String password) throws IOException + { + if (tm == null) + throw new IllegalStateException("Connection is not established!"); + + if (authenticated) + throw new IllegalStateException("Connection is already authenticated!"); + + if (am == null) + am = new AuthenticationManager(tm); + + if (cm == null) + cm = new ChannelManager(tm); + + if (user == null) + throw new IllegalArgumentException("user argument is null"); + + if (pem == null) + throw new IllegalArgumentException("pem argument is null"); + + authenticated = am.authenticatePublicKey(user, pem.toCharArray(), password, getOrCreateSecureRND()); + + return authenticated; + } + + /** + * A wrapper that calls {@link #authenticateWithKeyboardInteractive(String, String[], InteractiveCallback) + * authenticateWithKeyboardInteractivewith} a null submethod list. + * + * @param user + * A String holding the username. + * @param cb + * An InteractiveCallback which will be used to + * determine the responses to the questions asked by the server. + * @return whether the connection is now authenticated. + * @throws IOException + */ + public synchronized boolean authenticateWithKeyboardInteractive(String user, InteractiveCallback cb) + throws IOException + { + return authenticateWithKeyboardInteractive(user, null, cb); + } + + /** + * After a successful connect, one has to authenticate oneself. This method + * is based on "keyboard-interactive", specified in + * draft-ietf-secsh-auth-kbdinteract-XX. Basically, you have to define a + * callback object which will be feeded with challenges generated by the + * server. Answers are then sent back to the server. It is possible that the + * callback will be called several times during the invocation of this + * method (e.g., if the server replies to the callback's answer(s) with + * another challenge...) + *

+ * If the authentication phase is complete, true will be + * returned. If the server does not accept the request (or if further + * authentication steps are needed), false is returned and + * one can retry either by using this or any other authentication method + * (use the getRemainingAuthMethods method to get a list of + * the remaining possible methods). + *

+ * Note: some SSH servers advertise "keyboard-interactive", however, any + * interactive request will be denied (without having sent any challenge to + * the client). + * + * @param user + * A String holding the username. + * @param submethods + * An array of submethod names, see + * draft-ietf-secsh-auth-kbdinteract-XX. May be null + * to indicate an empty list. + * @param cb + * An InteractiveCallback which will be used to + * determine the responses to the questions asked by the server. + * + * @return whether the connection is now authenticated. + * @throws IOException + */ + public synchronized boolean authenticateWithKeyboardInteractive(String user, String[] submethods, + InteractiveCallback cb) throws IOException + { + if (cb == null) + throw new IllegalArgumentException("Callback may not ne NULL!"); + + if (tm == null) + throw new IllegalStateException("Connection is not established!"); + + if (authenticated) + throw new IllegalStateException("Connection is already authenticated!"); + + if (am == null) + am = new AuthenticationManager(tm); + + if (cm == null) + cm = new ChannelManager(tm); + + if (user == null) + throw new IllegalArgumentException("user argument is null"); + + authenticated = am.authenticateInteractive(user, submethods, cb); + + return authenticated; + } + + /** + * After a successful connect, one has to authenticate oneself. This method + * sends username and password to the server. + *

+ * If the authentication phase is complete, true will be + * returned. If the server does not accept the request (or if further + * authentication steps are needed), false is returned and + * one can retry either by using this or any other authentication method + * (use the getRemainingAuthMethods method to get a list of + * the remaining possible methods). + *

+ * Note: if this method fails, then please double-check that it is actually + * offered by the server (use {@link #getRemainingAuthMethods(String) getRemainingAuthMethods()}. + *

+ * Often, password authentication is disabled, but users are not aware of it. + * Many servers only offer "publickey" and "keyboard-interactive". However, + * even though "keyboard-interactive" *feels* like password authentication + * (e.g., when using the putty or openssh clients) it is *not* the same mechanism. + * + * @param user + * @param password + * @return if the connection is now authenticated. + * @throws IOException + */ + public synchronized boolean authenticateWithPassword(String user, String password) throws IOException + { + if (tm == null) + throw new IllegalStateException("Connection is not established!"); + + if (authenticated) + throw new IllegalStateException("Connection is already authenticated!"); + + if (am == null) + am = new AuthenticationManager(tm); + + if (cm == null) + cm = new ChannelManager(tm); + + if (user == null) + throw new IllegalArgumentException("user argument is null"); + + if (password == null) + throw new IllegalArgumentException("password argument is null"); + + authenticated = am.authenticatePassword(user, password); + + return authenticated; + } + + /** + * After a successful connect, one has to authenticate oneself. + * This method can be used to explicitly use the special "none" + * authentication method (where only a username has to be specified). + *

+ * Note 1: The "none" method may always be tried by clients, however as by + * the specs, the server will not explicitly announce it. In other words, + * the "none" token will never show up in the list returned by + * {@link #getRemainingAuthMethods(String)}. + *

+ * Note 2: no matter which one of the authenticateWithXXX() methods + * you call, the library will always issue exactly one initial "none" + * authentication request to retrieve the initially allowed list of + * authentication methods by the server. Please read RFC 4252 for the + * details. + *

+ * If the authentication phase is complete, true will be + * returned. If further authentication steps are needed, false + * is returned and one can retry by any other authentication method + * (use the getRemainingAuthMethods method to get a list of + * the remaining possible methods). + * + * @param user + * @return if the connection is now authenticated. + * @throws IOException + */ + public synchronized boolean authenticateWithNone(String user) throws IOException + { + if (tm == null) + throw new IllegalStateException("Connection is not established!"); + + if (authenticated) + throw new IllegalStateException("Connection is already authenticated!"); + + if (am == null) + am = new AuthenticationManager(tm); + + if (cm == null) + cm = new ChannelManager(tm); + + if (user == null) + throw new IllegalArgumentException("user argument is null"); + + /* Trigger the sending of the PacketUserauthRequestNone packet */ + /* (if not already done) */ + + authenticated = am.authenticateNone(user); + + return authenticated; + } + + /** + * After a successful connect, one has to authenticate oneself. + * The authentication method "publickey" works by signing a challenge + * sent by the server. The signature is either DSA or RSA based - it + * just depends on the type of private key you specify, either a DSA + * or RSA private key in PEM format. And yes, this is may seem to be a + * little confusing, the method is called "publickey" in the SSH-2 protocol + * specification, however since we need to generate a signature, you + * actually have to supply a private key =). + *

+ * The private key contained in the PEM file may also be encrypted ("Proc-Type: 4,ENCRYPTED"). + * The library supports DES-CBC and DES-EDE3-CBC encryption, as well + * as the more exotic PEM encrpytions AES-128-CBC, AES-192-CBC and AES-256-CBC. + *

+ * If the authentication phase is complete, true will be + * returned. If the server does not accept the request (or if further + * authentication steps are needed), false is returned and + * one can retry either by using this or any other authentication method + * (use the getRemainingAuthMethods method to get a list of + * the remaining possible methods). + *

+ * NOTE PUTTY USERS: Event though your key file may start with "-----BEGIN..." + * it is not in the expected format. You have to convert it to the OpenSSH + * key format by using the "puttygen" tool (can be downloaded from the Putty + * website). Simply load your key and then use the "Conversions/Export OpenSSH key" + * functionality to get a proper PEM file. + * + * @param user + * A String holding the username. + * @param pemPrivateKey + * A char[] containing a DSA or RSA private key of the + * user in OpenSSH key format (PEM, you can't miss the + * "-----BEGIN DSA PRIVATE KEY-----" or "-----BEGIN RSA PRIVATE KEY-----" + * tag). The char array may contain linebreaks/linefeeds. + * @param password + * If the PEM structure is encrypted ("Proc-Type: 4,ENCRYPTED") then + * you must specify a password. Otherwise, this argument will be ignored + * and can be set to null. + * + * @return whether the connection is now authenticated. + * @throws IOException + */ + public synchronized boolean authenticateWithPublicKey(String user, char[] pemPrivateKey, String password) + throws IOException + { + if (tm == null) + throw new IllegalStateException("Connection is not established!"); + + if (authenticated) + throw new IllegalStateException("Connection is already authenticated!"); + + if (am == null) + am = new AuthenticationManager(tm); + + if (cm == null) + cm = new ChannelManager(tm); + + if (user == null) + throw new IllegalArgumentException("user argument is null"); + + if (pemPrivateKey == null) + throw new IllegalArgumentException("pemPrivateKey argument is null"); + + authenticated = am.authenticatePublicKey(user, pemPrivateKey, password, getOrCreateSecureRND()); + + return authenticated; + } + + /** + * A convenience wrapper function which reads in a private key (PEM format, either DSA or RSA) + * and then calls authenticateWithPublicKey(String, char[], String). + *

+ * NOTE PUTTY USERS: Event though your key file may start with "-----BEGIN..." + * it is not in the expected format. You have to convert it to the OpenSSH + * key format by using the "puttygen" tool (can be downloaded from the Putty + * website). Simply load your key and then use the "Conversions/Export OpenSSH key" + * functionality to get a proper PEM file. + * + * @param user + * A String holding the username. + * @param pemFile + * A File object pointing to a file containing a DSA or RSA + * private key of the user in OpenSSH key format (PEM, you can't miss the + * "-----BEGIN DSA PRIVATE KEY-----" or "-----BEGIN RSA PRIVATE KEY-----" + * tag). + * @param password + * If the PEM file is encrypted then you must specify the password. + * Otherwise, this argument will be ignored and can be set to null. + * + * @return whether the connection is now authenticated. + * @throws IOException + */ + public synchronized boolean authenticateWithPublicKey(String user, File pemFile, String password) + throws IOException + { + if (pemFile == null) + throw new IllegalArgumentException("pemFile argument is null"); + + char[] buff = new char[256]; + + CharArrayWriter cw = new CharArrayWriter(); + + FileReader fr = new FileReader(pemFile); + + while (true) + { + int len = fr.read(buff); + if (len < 0) + break; + cw.write(buff, 0, len); + } + + fr.close(); + + return authenticateWithPublicKey(user, cw.toCharArray(), password); + } + + /** + * Add a {@link ConnectionMonitor} to this connection. Can be invoked at any time, + * but it is best to add connection monitors before invoking + * connect() to avoid glitches (e.g., you add a connection monitor after + * a successful connect(), but the connection has died in the mean time. Then, + * your connection monitor won't be notified.) + *

+ * You can add as many monitors as you like. If a monitor has already been added, then + * this method does nothing. + * + * @see ConnectionMonitor + * + * @param cmon An object implementing the {@link ConnectionMonitor} interface. + */ + public synchronized void addConnectionMonitor(ConnectionMonitor cmon) + { + if (cmon == null) + throw new IllegalArgumentException("cmon argument is null"); + + if (!connectionMonitors.contains(cmon)) + { + connectionMonitors.add(cmon); + + if (tm != null) + tm.setConnectionMonitors(connectionMonitors); + } + } + + /** + * Remove a {@link ConnectionMonitor} from this connection. + * + * @param cmon + * @return whether the monitor could be removed + */ + public synchronized boolean removeConnectionMonitor(ConnectionMonitor cmon) + { + if (cmon == null) + throw new IllegalArgumentException("cmon argument is null"); + + boolean existed = connectionMonitors.remove(cmon); + + if (tm != null) + tm.setConnectionMonitors(connectionMonitors); + + return existed; + } + + /** + * Close the connection to the SSH-2 server. All assigned sessions will be + * closed, too. Can be called at any time. Don't forget to call this once + * you don't need a connection anymore - otherwise the receiver thread may + * run forever. + */ + public synchronized void close() + { + Throwable t = new Throwable("Closed due to user request."); + close(t, false); + } + + public synchronized void close(Throwable t, boolean hard) + { + if (cm != null) + cm.closeAllChannels(); + + if (tm != null) + { + tm.close(t, hard == false); + tm = null; + } + am = null; + cm = null; + authenticated = false; + } + + /** + * Same as {@link #connect(ServerHostKeyVerifier, int, int) connect(null, 0, 0)}. + * + * @return see comments for the {@link #connect(ServerHostKeyVerifier, int, int) connect(ServerHostKeyVerifier, int, int)} method. + * @throws IOException + */ + public synchronized ConnectionInfo connect() throws IOException + { + return connect(null, 0, 0); + } + + /** + * Same as {@link #connect(ServerHostKeyVerifier, int, int) connect(verifier, 0, 0)}. + * + * @return see comments for the {@link #connect(ServerHostKeyVerifier, int, int) connect(ServerHostKeyVerifier, int, int)} method. + * @throws IOException + */ + public synchronized ConnectionInfo connect(ServerHostKeyVerifier verifier) throws IOException + { + return connect(verifier, 0, 0); + } + + /** + * Connect to the SSH-2 server and, as soon as the server has presented its + * host key, use the {@link ServerHostKeyVerifier#verifyServerHostKey(String, + * int, String, byte[]) ServerHostKeyVerifier.verifyServerHostKey()} + * method of the verifier to ask for permission to proceed. + * If verifier is null, then any host key will be + * accepted - this is NOT recommended, since it makes man-in-the-middle attackes + * VERY easy (somebody could put a proxy SSH server between you and the real server). + *

+ * Note: The verifier will be called before doing any crypto calculations + * (i.e., diffie-hellman). Therefore, if you don't like the presented host key then + * no CPU cycles are wasted (and the evil server has less information about us). + *

+ * However, it is still possible that the server presented a fake host key: the server + * cheated (typically a sign for a man-in-the-middle attack) and is not able to generate + * a signature that matches its host key. Don't worry, the library will detect such + * a scenario later when checking the signature (the signature cannot be checked before + * having completed the diffie-hellman exchange). + *

+ * Note 2: The {@link ServerHostKeyVerifier#verifyServerHostKey(String, + * int, String, byte[]) ServerHostKeyVerifier.verifyServerHostKey()} method + * will *NOT* be called from the current thread, the call is being made from a + * background thread (there is a background dispatcher thread for every + * established connection). + *

+ * Note 3: This method will block as long as the key exchange of the underlying connection + * has not been completed (and you have not specified any timeouts). + *

+ * Note 4: If you want to re-use a connection object that was successfully connected, + * then you must call the {@link #close()} method before invoking connect() again. + * + * @param verifier + * An object that implements the + * {@link ServerHostKeyVerifier} interface. Pass null + * to accept any server host key - NOT recommended. + * + * @param connectTimeout + * Connect the underlying TCP socket to the server with the given timeout + * value (non-negative, in milliseconds). Zero means no timeout. If a proxy is being + * used (see {@link #setProxyData(ProxyData)}), then this timeout is used for the + * connection establishment to the proxy. + * + * @param kexTimeout + * Timeout for complete connection establishment (non-negative, + * in milliseconds). Zero means no timeout. The timeout counts from the + * moment you invoke the connect() method and is cancelled as soon as the + * first key-exchange round has finished. It is possible that + * the timeout event will be fired during the invocation of the + * verifier callback, but it will only have an effect after + * the verifier returns. + * + * @return A {@link ConnectionInfo} object containing the details of + * the established connection. + * + * @throws IOException + * If any problem occurs, e.g., the server's host key is not + * accepted by the verifier or there is problem during + * the initial crypto setup (e.g., the signature sent by the server is wrong). + *

+ * In case of a timeout (either connectTimeout or kexTimeout) + * a SocketTimeoutException is thrown. + *

+ * An exception may also be thrown if the connection was already successfully + * connected (no matter if the connection broke in the mean time) and you invoke + * connect() again without having called {@link #close()} first. + *

+ * If a HTTP proxy is being used and the proxy refuses the connection, + * then a {@link HTTPProxyException} may be thrown, which + * contains the details returned by the proxy. If the proxy is buggy and does + * not return a proper HTTP response, then a normal IOException is thrown instead. + */ + public synchronized ConnectionInfo connect(ServerHostKeyVerifier verifier, int connectTimeout, int kexTimeout) + throws IOException + { + final class TimeoutState + { + boolean isCancelled = false; + boolean timeoutSocketClosed = false; + } + + if (tm != null) + throw new IOException("Connection to " + hostname + " is already in connected state!"); + + if (connectTimeout < 0) + throw new IllegalArgumentException("connectTimeout must be non-negative!"); + + if (kexTimeout < 0) + throw new IllegalArgumentException("kexTimeout must be non-negative!"); + + final TimeoutState state = new TimeoutState(); + + tm = new TransportManager(); + tm.setSoTimeout(connectTimeout); + tm.setConnectionMonitors(connectionMonitors); + + /* Make sure that the runnable below will observe the new value of "tm" + * and "state" (the runnable will be executed in a different thread, which + * may be already running, that is why we need a memory barrier here). + * See also the comment in Channel.java if you + * are interested in the details. + * + * OKOK, this is paranoid since adding the runnable to the todo list + * of the TimeoutService will ensure that all writes have been flushed + * before the Runnable reads anything + * (there is a synchronized block in TimeoutService.addTimeoutHandler). + */ + + synchronized (tm) + { + /* We could actually synchronize on anything. */ + } + + try + { + TimeoutToken token = null; + + if (kexTimeout > 0) + { + final Runnable timeoutHandler = new Runnable() + { + public void run() + { + synchronized (state) + { + if (state.isCancelled) + return; + state.timeoutSocketClosed = true; + tm.close(new SocketTimeoutException("The connect timeout expired"), false); + } + } + }; + + long timeoutHorizont = System.currentTimeMillis() + kexTimeout; + + token = TimeoutService.addTimeoutHandler(timeoutHorizont, timeoutHandler); + } + + try + { + + if (precreatedSocket != null) { + tm.clientInit(precreatedSocket, softwareversion, cryptoWishList, verifier, dhgexpara, + getOrCreateSecureRND()); + } else { + tm.clientInit(hostname, port, softwareversion, cryptoWishList, verifier, dhgexpara, connectTimeout, + getOrCreateSecureRND(), proxyData); + } + } + catch (SocketTimeoutException se) + { + throw (SocketTimeoutException) new SocketTimeoutException( + "The connect() operation on the socket timed out.").initCause(se); + } + + tm.setTcpNoDelay(tcpNoDelay); + + /* Wait until first KEX has finished */ + + ConnectionInfo ci = tm.getConnectionInfo(1); + + /* Now try to cancel the timeout, if needed */ + + if (token != null) + { + TimeoutService.cancelTimeoutHandler(token); + + /* Were we too late? */ + + synchronized (state) + { + if (state.timeoutSocketClosed) + throw new IOException("This exception will be replaced by the one below =)"); + /* Just in case the "cancelTimeoutHandler" invocation came just a little bit + * too late but the handler did not enter the semaphore yet - we can + * still stop it. + */ + state.isCancelled = true; + } + } + + return ci; + } + catch (SocketTimeoutException ste) + { + throw ste; + } + catch (IOException e1) + { + /* This will also invoke any registered connection monitors */ + close(new Throwable("There was a problem during connect."), false); + + synchronized (state) + { + /* Show a clean exception, not something like "the socket is closed!?!" */ + if (state.timeoutSocketClosed) + throw new SocketTimeoutException("The kexTimeout (" + kexTimeout + " ms) expired."); + } + + /* Do not wrap a HTTPProxyException */ + if (e1 instanceof HTTPProxyException) + throw e1; + + throw (IOException) new IOException("There was a problem while connecting to " + hostname + ":" + port) + .initCause(e1); + } + } + + /** + * Creates a new {@link LocalPortForwarder}. + * A LocalPortForwarder forwards TCP/IP connections that arrive at a local + * port via the secure tunnel to another host (which may or may not be + * identical to the remote SSH-2 server). + *

+ * This method must only be called after one has passed successfully the authentication step. + * There is no limit on the number of concurrent forwardings. + * + * @param local_port the local port the LocalPortForwarder shall bind to. + * @param host_to_connect target address (IP or hostname) + * @param port_to_connect target port + * @return A {@link LocalPortForwarder} object. + * @throws IOException + */ + public synchronized LocalPortForwarder createLocalPortForwarder(int local_port, String host_to_connect, + int port_to_connect) throws IOException + { + if (tm == null) + throw new IllegalStateException("Cannot forward ports, you need to establish a connection first."); + + if (!authenticated) + throw new IllegalStateException("Cannot forward ports, connection is not authenticated."); + + return new LocalPortForwarder(cm, local_port, host_to_connect, port_to_connect); + } + + /** + * Creates a new {@link LocalPortForwarder}. + * A LocalPortForwarder forwards TCP/IP connections that arrive at a local + * port via the secure tunnel to another host (which may or may not be + * identical to the remote SSH-2 server). + *

+ * This method must only be called after one has passed successfully the authentication step. + * There is no limit on the number of concurrent forwardings. + * + * @param addr specifies the InetSocketAddress where the local socket shall be bound to. + * @param host_to_connect target address (IP or hostname) + * @param port_to_connect target port + * @return A {@link LocalPortForwarder} object. + * @throws IOException + */ + public synchronized LocalPortForwarder createLocalPortForwarder(InetSocketAddress addr, String host_to_connect, + int port_to_connect) throws IOException + { + if (tm == null) + throw new IllegalStateException("Cannot forward ports, you need to establish a connection first."); + + if (!authenticated) + throw new IllegalStateException("Cannot forward ports, connection is not authenticated."); + + return new LocalPortForwarder(cm, addr, host_to_connect, port_to_connect); + } + + /** + * Creates a new {@link LocalStreamForwarder}. + * A LocalStreamForwarder manages an Input/Outputstream pair + * that is being forwarded via the secure tunnel into a TCP/IP connection to another host + * (which may or may not be identical to the remote SSH-2 server). + * + * @param host_to_connect + * @param port_to_connect + * @return A {@link LocalStreamForwarder} object. + * @throws IOException + */ + public synchronized LocalStreamForwarder createLocalStreamForwarder(String host_to_connect, int port_to_connect) + throws IOException + { + if (tm == null) + throw new IllegalStateException("Cannot forward, you need to establish a connection first."); + + if (!authenticated) + throw new IllegalStateException("Cannot forward, connection is not authenticated."); + + return new LocalStreamForwarder(cm, host_to_connect, port_to_connect); + } + + /** + * Create a very basic {@link SCPClient} that can be used to copy + * files from/to the SSH-2 server. + *

+ * Works only after one has passed successfully the authentication step. + * There is no limit on the number of concurrent SCP clients. + *

+ * Note: This factory method will probably disappear in the future. + * + * @return A {@link SCPClient} object. + * @throws IOException + */ + public synchronized SCPClient createSCPClient() throws IOException + { + if (tm == null) + throw new IllegalStateException("Cannot create SCP client, you need to establish a connection first."); + + if (!authenticated) + throw new IllegalStateException("Cannot create SCP client, connection is not authenticated."); + + return new SCPClient(this); + } + + /** + * Force an asynchronous key re-exchange (the call does not block). The + * latest values set for MAC, Cipher and DH group exchange parameters will + * be used. If a key exchange is currently in progress, then this method has + * the only effect that the so far specified parameters will be used for the + * next (server driven) key exchange. + *

+ * Note: This implementation will never start a key exchange (other than the initial one) + * unless you or the SSH-2 server ask for it. + * + * @throws IOException + * In case of any failure behind the scenes. + */ + public synchronized void forceKeyExchange() throws IOException + { + if (tm == null) + throw new IllegalStateException("You need to establish a connection first."); + + tm.forceKeyExchange(cryptoWishList, dhgexpara, null, null); + } + + /** + * Returns the hostname that was passed to the constructor. + * + * @return the hostname + */ + public synchronized String getHostname() + { + return hostname; + } + + /** + * Returns the port that was passed to the constructor. + * + * @return the TCP port + */ + public synchronized int getPort() + { + return port; + } + + /** + * Returns a {@link ConnectionInfo} object containing the details of + * the connection. Can be called as soon as the connection has been + * established (successfully connected). + * + * @return A {@link ConnectionInfo} object. + * @throws IOException + * In case of any failure behind the scenes. + */ + public synchronized ConnectionInfo getConnectionInfo() throws IOException + { + if (tm == null) + throw new IllegalStateException( + "Cannot get details of connection, you need to establish a connection first."); + return tm.getConnectionInfo(1); + } + + /** + * After a successful connect, one has to authenticate oneself. This method + * can be used to tell which authentication methods are supported by the + * server at a certain stage of the authentication process (for the given + * username). + *

+ * Note 1: the username will only be used if no authentication step was done + * so far (it will be used to ask the server for a list of possible + * authentication methods by sending the initial "none" request). Otherwise, + * this method ignores the user name and returns a cached method list + * (which is based on the information contained in the last negative server response). + *

+ * Note 2: the server may return method names that are not supported by this + * implementation. + *

+ * After a successful authentication, this method must not be called + * anymore. + * + * @param user + * A String holding the username. + * + * @return a (possibly emtpy) array holding authentication method names. + * @throws IOException + */ + public synchronized String[] getRemainingAuthMethods(String user) throws IOException + { + if (user == null) + throw new IllegalArgumentException("user argument may not be NULL!"); + + if (tm == null) + throw new IllegalStateException("Connection is not established!"); + + if (authenticated) + throw new IllegalStateException("Connection is already authenticated!"); + + if (am == null) + am = new AuthenticationManager(tm); + + if (cm == null) + cm = new ChannelManager(tm); + + return am.getRemainingMethods(user); + } + + /** + * Determines if the authentication phase is complete. Can be called at any + * time. + * + * @return true if no further authentication steps are + * needed. + */ + public synchronized boolean isAuthenticationComplete() + { + return authenticated; + } + + /** + * Returns true if there was at least one failed authentication request and + * the last failed authentication request was marked with "partial success" + * by the server. This is only needed in the rare case of SSH-2 server setups + * that cannot be satisfied with a single successful authentication request + * (i.e., multiple authentication steps are needed.) + *

+ * If you are interested in the details, then have a look at RFC4252. + * + * @return if the there was a failed authentication step and the last one + * was marked as a "partial success". + */ + public synchronized boolean isAuthenticationPartialSuccess() + { + if (am == null) + return false; + + return am.getPartialSuccess(); + } + + /** + * Checks if a specified authentication method is available. This method is + * actually just a wrapper for {@link #getRemainingAuthMethods(String) + * getRemainingAuthMethods()}. + * + * @param user + * A String holding the username. + * @param method + * An authentication method name (e.g., "publickey", "password", + * "keyboard-interactive") as specified by the SSH-2 standard. + * @return if the specified authentication method is currently available. + * @throws IOException + */ + public synchronized boolean isAuthMethodAvailable(String user, String method) throws IOException + { + if (method == null) + throw new IllegalArgumentException("method argument may not be NULL!"); + + String methods[] = getRemainingAuthMethods(user); + + for (int i = 0; i < methods.length; i++) + { + if (methods[i].compareTo(method) == 0) + return true; + } + + return false; + } + + private SecureRandom getOrCreateSecureRND() + { + if (generator == null) + generator = new SecureRandom(); + + return generator; + } + + /** + * Open a new {@link Session} on this connection. Works only after one has passed + * successfully the authentication step. There is no limit on the number of + * concurrent sessions. + * + * @return A {@link Session} object. + * @throws IOException + */ + public synchronized Session openSession() throws IOException + { + if (tm == null) + throw new IllegalStateException("Cannot open session, you need to establish a connection first."); + + if (!authenticated) + throw new IllegalStateException("Cannot open session, connection is not authenticated."); + + return new Session(cm, getOrCreateSecureRND()); + } + + /** + * Send an SSH_MSG_IGNORE packet. This method will generate a random data attribute + * (length between 0 (invlusive) and 16 (exclusive) bytes, contents are random bytes). + *

+ * This method must only be called once the connection is established. + * + * @throws IOException + */ + public synchronized void sendIgnorePacket() throws IOException + { + SecureRandom rnd = getOrCreateSecureRND(); + + byte[] data = new byte[rnd.nextInt(16)]; + rnd.nextBytes(data); + + sendIgnorePacket(data); + } + + /** + * Send an SSH_MSG_IGNORE packet with the given data attribute. + *

+ * This method must only be called once the connection is established. + * + * @throws IOException + */ + public synchronized void sendIgnorePacket(byte[] data) throws IOException + { + if (data == null) + throw new IllegalArgumentException("data argument must not be null."); + + if (tm == null) + throw new IllegalStateException( + "Cannot send SSH_MSG_IGNORE packet, you need to establish a connection first."); + + PacketIgnore pi = new PacketIgnore(); + pi.setData(data); + + tm.sendMessage(pi.getPayload()); + } + + /** + * Removes duplicates from a String array, keeps only first occurence + * of each element. Does not destroy order of elements; can handle nulls. + * Uses a very efficient O(N^2) algorithm =) + * + * @param list a String array. + * @return a cleaned String array. + */ + private String[] removeDuplicates(String[] list) + { + if ((list == null) || (list.length < 2)) + return list; + + String[] list2 = new String[list.length]; + + int count = 0; + + for (int i = 0; i < list.length; i++) + { + boolean duplicate = false; + + String element = list[i]; + + for (int j = 0; j < count; j++) + { + if (((element == null) && (list2[j] == null)) || ((element != null) && (element.equals(list2[j])))) + { + duplicate = true; + break; + } + } + + if (duplicate) + continue; + + list2[count++] = list[i]; + } + + if (count == list2.length) + return list2; + + String[] tmp = new String[count]; + System.arraycopy(list2, 0, tmp, 0, count); + + return tmp; + } + + /** + * Unless you know what you are doing, you will never need this. + * + * @param ciphers + */ + public synchronized void setClient2ServerCiphers(String[] ciphers) + { + if ((ciphers == null) || (ciphers.length == 0)) + throw new IllegalArgumentException(); + ciphers = removeDuplicates(ciphers); + BlockCipherFactory.checkCipherList(ciphers); + cryptoWishList.c2s_enc_algos = ciphers; + } + + /** + * Unless you know what you are doing, you will never need this. + * + * @param macs + */ + public synchronized void setClient2ServerMACs(String[] macs) + { + if ((macs == null) || (macs.length == 0)) + throw new IllegalArgumentException(); + macs = removeDuplicates(macs); + MAC.checkMacList(macs); + cryptoWishList.c2s_mac_algos = macs; + } + + /** + * Sets the parameters for the diffie-hellman group exchange. Unless you + * know what you are doing, you will never need this. Default values are + * defined in the {@link DHGexParameters} class. + * + * @param dgp {@link DHGexParameters}, non null. + * + */ + public synchronized void setDHGexParameters(DHGexParameters dgp) + { + if (dgp == null) + throw new IllegalArgumentException(); + + dhgexpara = dgp; + } + + /** + * Unless you know what you are doing, you will never need this. + * + * @param ciphers + */ + public synchronized void setServer2ClientCiphers(String[] ciphers) + { + if ((ciphers == null) || (ciphers.length == 0)) + throw new IllegalArgumentException(); + ciphers = removeDuplicates(ciphers); + BlockCipherFactory.checkCipherList(ciphers); + cryptoWishList.s2c_enc_algos = ciphers; + } + + /** + * Unless you know what you are doing, you will never need this. + * + * @param macs + */ + public synchronized void setServer2ClientMACs(String[] macs) + { + if ((macs == null) || (macs.length == 0)) + throw new IllegalArgumentException(); + + macs = removeDuplicates(macs); + MAC.checkMacList(macs); + cryptoWishList.s2c_mac_algos = macs; + } + + /** + * Define the set of allowed server host key algorithms to be used for + * the following key exchange operations. + *

+ * Unless you know what you are doing, you will never need this. + * + * @param algos An array of allowed server host key algorithms. + * SSH-2 defines ssh-dss and ssh-rsa. + * The entries of the array must be ordered after preference, i.e., + * the entry at index 0 is the most preferred one. You must specify + * at least one entry. + */ + public synchronized void setServerHostKeyAlgorithms(String[] algos) + { + if ((algos == null) || (algos.length == 0)) + throw new IllegalArgumentException(); + + algos = removeDuplicates(algos); + KexManager.checkServerHostkeyAlgorithmsList(algos); + cryptoWishList.serverHostKeyAlgorithms = algos; + } + + /** + * Enable/disable TCP_NODELAY (disable/enable Nagle's algorithm) on the underlying socket. + *

+ * Can be called at any time. If the connection has not yet been established + * then the passed value will be stored and set after the socket has been set up. + * The default value that will be used is false. + * + * @param enable the argument passed to the Socket.setTCPNoDelay() method. + * @throws IOException + */ + public synchronized void setTCPNoDelay(boolean enable) throws IOException + { + tcpNoDelay = enable; + + if (tm != null) + tm.setTcpNoDelay(enable); + } + + /** + * Used to tell the library that the connection shall be established through a proxy server. + * It only makes sense to call this method before calling the {@link #connect() connect()} + * method. + *

+ * At the moment, only HTTP proxies are supported. + *

+ * Note: This method can be called any number of times. The {@link #connect() connect()} + * method will use the value set in the last preceding invocation of this method. + * + * @see HTTPProxyData + * + * @param proxyData Connection information about the proxy. If null, then + * no proxy will be used (non surprisingly, this is also the default). + */ + public synchronized void setProxyData(ProxyData proxyData) + { + this.proxyData = proxyData; + } + + /** + * Request a remote port forwarding. + * If successful, then forwarded connections will be redirected to the given target address. + * You can cancle a requested remote port forwarding by calling + * {@link #cancelRemotePortForwarding(int) cancelRemotePortForwarding()}. + *

+ * A call of this method will block until the peer either agreed or disagreed to your request- + *

+ * Note 1: this method typically fails if you + *

    + *
  • pass a port number for which the used remote user has not enough permissions (i.e., port + * < 1024)
  • + *
  • or pass a port number that is already in use on the remote server
  • + *
  • or if remote port forwarding is disabled on the server.
  • + *
+ *

+ * Note 2: (from the openssh man page): By default, the listening socket on the server will be + * bound to the loopback interface only. This may be overriden by specifying a bind address. + * Specifying a remote bind address will only succeed if the server's GatewayPorts option + * is enabled (see sshd_config(5)). + * + * @param bindAddress address to bind to on the server: + *

    + *
  • "" means that connections are to be accepted on all protocol families + * supported by the SSH implementation
  • + *
  • "0.0.0.0" means to listen on all IPv4 addresses
  • + *
  • "::" means to listen on all IPv6 addresses
  • + *
  • "localhost" means to listen on all protocol families supported by the SSH + * implementation on loopback addresses only, [RFC3330] and RFC3513]
  • + *
  • "127.0.0.1" and "::1" indicate listening on the loopback interfaces for + * IPv4 and IPv6 respectively
  • + *
+ * @param bindPort port number to bind on the server (must be > 0) + * @param targetAddress the target address (IP or hostname) + * @param targetPort the target port + * @throws IOException + */ + public synchronized void requestRemotePortForwarding(String bindAddress, int bindPort, String targetAddress, + int targetPort) throws IOException + { + if (tm == null) + throw new IllegalStateException("You need to establish a connection first."); + + if (!authenticated) + throw new IllegalStateException("The connection is not authenticated."); + + if ((bindAddress == null) || (targetAddress == null) || (bindPort <= 0) || (targetPort <= 0)) + throw new IllegalArgumentException(); + + cm.requestGlobalForward(bindAddress, bindPort, targetAddress, targetPort); + } + + /** + * Cancel an earlier requested remote port forwarding. + * Currently active forwardings will not be affected (e.g., disrupted). + * Note that further connection forwarding requests may be received until + * this method has returned. + * + * @param bindPort the allocated port number on the server + * @throws IOException if the remote side refuses the cancel request or another low + * level error occurs (e.g., the underlying connection is closed) + */ + public synchronized void cancelRemotePortForwarding(int bindPort) throws IOException + { + if (tm == null) + throw new IllegalStateException("You need to establish a connection first."); + + if (!authenticated) + throw new IllegalStateException("The connection is not authenticated."); + + cm.requestCancelGlobalForward(bindPort); + } + + /** + * Provide your own instance of SecureRandom. Can be used, e.g., if you + * want to seed the used SecureRandom generator manually. + *

+ * The SecureRandom instance is used during key exchanges, public key authentication, + * x11 cookie generation and the like. + * + * @param rnd a SecureRandom instance + */ + public synchronized void setSecureRandom(SecureRandom rnd) + { + if (rnd == null) + throw new IllegalArgumentException(); + + this.generator = rnd; + } +} diff --git a/third-party/ganymed/src/main/java/ch/ethz/ssh2/transport/TransportManager.java b/third-party/ganymed/src/main/java/ch/ethz/ssh2/transport/TransportManager.java new file mode 100644 index 0000000000..963267082b --- /dev/null +++ b/third-party/ganymed/src/main/java/ch/ethz/ssh2/transport/TransportManager.java @@ -0,0 +1,990 @@ +/* + * Copyright (c) 2006-2013 Christian Plattner. All rights reserved. + * Please refer to the LICENSE.txt for licensing details. + */ + +package ch.ethz.ssh2.transport; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketTimeoutException; +import java.net.UnknownHostException; +import java.security.SecureRandom; +import java.util.List; +import java.util.Vector; + +import ch.ethz.ssh2.ConnectionInfo; +import ch.ethz.ssh2.ConnectionMonitor; +import ch.ethz.ssh2.DHGexParameters; +import ch.ethz.ssh2.HTTPProxyData; +import ch.ethz.ssh2.HTTPProxyException; +import ch.ethz.ssh2.ProxyData; +import ch.ethz.ssh2.ServerHostKeyVerifier; +import ch.ethz.ssh2.crypto.Base64; +import ch.ethz.ssh2.crypto.CryptoWishList; +import ch.ethz.ssh2.crypto.cipher.BlockCipher; +import ch.ethz.ssh2.crypto.digest.MAC; +import ch.ethz.ssh2.log.Logger; +import ch.ethz.ssh2.packets.PacketDisconnect; +import ch.ethz.ssh2.packets.Packets; +import ch.ethz.ssh2.packets.TypesReader; +import ch.ethz.ssh2.server.ServerConnectionState; +import ch.ethz.ssh2.signature.DSAPrivateKey; +import ch.ethz.ssh2.signature.RSAPrivateKey; +import ch.ethz.ssh2.util.StringEncoder; +import ch.ethz.ssh2.util.Tokenizer; + +/* + * Yes, the "standard" is a big mess. On one side, the say that arbitary channel + * packets are allowed during kex exchange, on the other side we need to blindly + * ignore the next _packet_ if the KEX guess was wrong. Where do we know from that + * the next packet is not a channel data packet? Yes, we could check if it is in + * the KEX range. But the standard says nothing about this. The OpenSSH guys + * block local "normal" traffic during KEX. That's fine - however, they assume + * that the other side is doing the same. During re-key, if they receive traffic + * other than KEX, they become horribly irritated and kill the connection. Since + * we are very likely going to communicate with OpenSSH servers, we have to play + * the same game - even though we could do better. + * + * btw: having stdout and stderr on the same channel, with a shared window, is + * also a VERY good idea... =( + */ + +/** + * TransportManager. + * + * @author Christian Plattner + * @version $Id: TransportManager.java 47 2013-07-31 23:59:52Z cleondris@gmail.com $ + */ +public class TransportManager +{ + private static final Logger log = Logger.getLogger(TransportManager.class); + + private static class HandlerEntry + { + MessageHandler mh; + int low; + int high; + } + + private final List asynchronousQueue = new Vector(); + private Thread asynchronousThread = null; + private boolean asynchronousPending = false; + + class AsynchronousEntry + { + public byte[] msg; + public Runnable run; + + public AsynchronousEntry(byte[] msg, Runnable run) + { + this.msg = msg; + this.run = run; + } + } + + class AsynchronousWorker extends Thread + { + @Override + public void run() + { + while (true) + { + AsynchronousEntry item = null; + + synchronized (asynchronousQueue) + { + if (asynchronousQueue.size() == 0) + { + /* Only now we may reset the flag, since we are sure that all queued items + * have been sent (there is a slight delay between de-queuing and sending, + * this is why we need this flag! See code below. Sending takes place outside + * of this lock, this is why a test for size()==0 (from another thread) does not ensure + * that all messages have been sent. + */ + + asynchronousPending = false; + + /* Notify any senders that they can proceed, all async messages have been delivered */ + + asynchronousQueue.notifyAll(); + + /* After the queue is empty for about 2 seconds, stop this thread */ + + try + { + asynchronousQueue.wait(2000); + } + catch (InterruptedException ignore) + { + } + + if (asynchronousQueue.size() == 0) + { + asynchronousThread = null; + return; + } + } + + item = asynchronousQueue.remove(0); + } + + /* The following invocation may throw an IOException. + * There is no point in handling it - it simply means + * that the connection has a problem and we should stop + * sending asynchronously messages. We do not need to signal that + * we have exited (asynchronousThread = null): further + * messages in the queue cannot be sent by this or any + * other thread. + * Other threads will sooner or later (when receiving or + * sending the next message) get the same IOException and + * get to the same conclusion. + */ + + try + { + sendMessageImmediate(item.msg); + } + catch (IOException e) + { + return; + } + + if (item.run != null) + { + try + { + item.run.run(); + } + catch (Exception ignore) + { + } + + } + } + } + } + + private Socket sock = new Socket(); + + private final Object connectionSemaphore = new Object(); + + private boolean flagKexOngoing = false; + private boolean connectionClosed = false; + + private Throwable reasonClosedCause = null; + + private TransportConnection tc; + private KexManager km; + + private final List messageHandlers = new Vector(); + + private Thread receiveThread; + + private List connectionMonitors = new Vector(); + private boolean monitorsWereInformed = false; + + /** + * There were reports that there are JDKs which use + * the resolver even though one supplies a dotted IP + * address in the Socket constructor. That is why we + * try to generate the InetAdress "by hand". + * + * @param host + * @return the InetAddress + * @throws UnknownHostException + */ + private static InetAddress createInetAddress(String host) throws UnknownHostException + { + /* Check if it is a dotted IP4 address */ + + InetAddress addr = parseIPv4Address(host); + + if (addr != null) + { + return addr; + } + + return InetAddress.getByName(host); + } + + private static InetAddress parseIPv4Address(String host) throws UnknownHostException + { + if (host == null) + { + return null; + } + + String[] quad = Tokenizer.parseTokens(host, '.'); + + if ((quad == null) || (quad.length != 4)) + { + return null; + } + + byte[] addr = new byte[4]; + + for (int i = 0; i < 4; i++) + { + int part = 0; + + if ((quad[i].length() == 0) || (quad[i].length() > 3)) + { + return null; + } + + for (int k = 0; k < quad[i].length(); k++) + { + char c = quad[i].charAt(k); + + /* No, Character.isDigit is not the same */ + if ((c < '0') || (c > '9')) + { + return null; + } + + part = part * 10 + (c - '0'); + } + + if (part > 255) /* 300.1.2.3 is invalid =) */ + { + return null; + } + + addr[i] = (byte) part; + } + + return InetAddress.getByAddress(host, addr); + } + + public int getPacketOverheadEstimate() + { + return tc.getPacketOverheadEstimate(); + } + + public void setTcpNoDelay(boolean state) throws IOException + { + sock.setTcpNoDelay(state); + } + + public void setSoTimeout(int timeout) throws IOException + { + sock.setSoTimeout(timeout); + } + + public ConnectionInfo getConnectionInfo(int kexNumber) throws IOException + { + return km.getOrWaitForConnectionInfo(kexNumber); + } + + public Throwable getReasonClosedCause() + { + synchronized (connectionSemaphore) + { + return reasonClosedCause; + } + } + + public byte[] getSessionIdentifier() + { + return km.sessionId; + } + + public void close(Throwable cause, boolean useDisconnectPacket) + { + if (useDisconnectPacket == false) + { + /* OK, hard shutdown - do not aquire the semaphore, + * perhaps somebody is inside (and waits until the remote + * side is ready to accept new data). */ + + try + { + sock.close(); + } + catch (IOException ignore) + { + } + + /* OK, whoever tried to send data, should now agree that + * there is no point in further waiting =) + * It is safe now to aquire the semaphore. + */ + } + + synchronized (connectionSemaphore) + { + if (connectionClosed == false) + { + if (useDisconnectPacket == true) + { + try + { + byte[] msg = new PacketDisconnect(Packets.SSH_DISCONNECT_BY_APPLICATION, cause.getMessage(), "") + .getPayload(); + if (tc != null) + { + tc.sendMessage(msg); + } + } + catch (IOException ignore) + { + } + + try + { + sock.close(); + } + catch (IOException ignore) + { + } + } + + connectionClosed = true; + reasonClosedCause = cause; /* may be null */ + } + connectionSemaphore.notifyAll(); + } + + /* No check if we need to inform the monitors */ + + List monitors = new Vector(); + + synchronized (this) + { + /* Short term lock to protect "connectionMonitors" + * and "monitorsWereInformed" + * (they may be modified concurrently) + */ + + if (monitorsWereInformed == false) + { + monitorsWereInformed = true; + monitors.addAll(connectionMonitors); + } + } + + for (ConnectionMonitor cmon : monitors) + { + try + { + cmon.connectionLost(reasonClosedCause); + } + catch (Exception ignore) + { + } + } + } + + private static Socket establishConnection(String hostname, int port, ProxyData proxyData, int connectTimeout) + throws IOException + { + /* See the comment for createInetAddress() */ + + if (proxyData == null) + { + InetAddress addr = createInetAddress(hostname); + Socket s = new Socket(); + s.connect(new InetSocketAddress(addr, port), connectTimeout); + return s; + } + + if (proxyData instanceof HTTPProxyData) + { + HTTPProxyData pd = (HTTPProxyData) proxyData; + + /* At the moment, we only support HTTP proxies */ + + InetAddress addr = createInetAddress(pd.proxyHost); + Socket s = new Socket(); + s.connect(new InetSocketAddress(addr, pd.proxyPort), connectTimeout); + + /* OK, now tell the proxy where we actually want to connect to */ + + StringBuilder sb = new StringBuilder(); + + sb.append("CONNECT "); + sb.append(hostname); + sb.append(':'); + sb.append(port); + sb.append(" HTTP/1.0\r\n"); + + if ((pd.proxyUser != null) && (pd.proxyPass != null)) + { + String credentials = pd.proxyUser + ":" + pd.proxyPass; + char[] encoded = Base64.encode(StringEncoder.GetBytes(credentials)); + sb.append("Proxy-Authorization: Basic "); + sb.append(encoded); + sb.append("\r\n"); + } + + if (pd.requestHeaderLines != null) + { + for (int i = 0; i < pd.requestHeaderLines.length; i++) + { + if (pd.requestHeaderLines[i] != null) + { + sb.append(pd.requestHeaderLines[i]); + sb.append("\r\n"); + } + } + } + + sb.append("\r\n"); + + OutputStream out = s.getOutputStream(); + + out.write(StringEncoder.GetBytes(sb.toString())); + out.flush(); + + /* Now parse the HTTP response */ + + byte[] buffer = new byte[1024]; + InputStream in = s.getInputStream(); + + int len = ClientServerHello.readLineRN(in, buffer); + + String httpReponse = StringEncoder.GetString(buffer, 0, len); + + if (httpReponse.startsWith("HTTP/") == false) + { + throw new IOException("The proxy did not send back a valid HTTP response."); + } + + /* "HTTP/1.X XYZ X" => 14 characters minimum */ + + if ((httpReponse.length() < 14) || (httpReponse.charAt(8) != ' ') || (httpReponse.charAt(12) != ' ')) + { + throw new IOException("The proxy did not send back a valid HTTP response."); + } + + int errorCode = 0; + + try + { + errorCode = Integer.parseInt(httpReponse.substring(9, 12)); + } + catch (NumberFormatException ignore) + { + throw new IOException("The proxy did not send back a valid HTTP response."); + } + + if ((errorCode < 0) || (errorCode > 999)) + { + throw new IOException("The proxy did not send back a valid HTTP response."); + } + + if (errorCode != 200) + { + throw new HTTPProxyException(httpReponse.substring(13), errorCode); + } + + /* OK, read until empty line */ + + while (true) + { + len = ClientServerHello.readLineRN(in, buffer); + if (len == 0) + { + break; + } + } + return s; + } + + throw new IOException("Unsupported ProxyData"); + } + + private void startReceiver() throws IOException + { + receiveThread = new Thread(new Runnable() + { + public void run() + { + try + { + receiveLoop(); + } + catch (Exception e) + { + close(e, false); + + log.warning("Receive thread: error in receiveLoop: " + e.getMessage()); + } + + if (log.isDebugEnabled()) + { + log.debug("Receive thread: back from receiveLoop"); + } + + /* Tell all handlers that it is time to say goodbye */ + + if (km != null) + { + try + { + km.handleMessage(null, 0); + } + catch (IOException ignored) + { + } + } + + for (HandlerEntry he : messageHandlers) + { + try + { + he.mh.handleMessage(null, 0); + } + catch (Exception ignore) + { + } + } + } + }); + + receiveThread.setDaemon(true); + receiveThread.start(); + } + + public void clientInit(Socket socket, String softwareversion, CryptoWishList cwl, + ServerHostKeyVerifier verifier, DHGexParameters dhgex, SecureRandom rnd) throws IOException + { + /* First, establish the TCP connection to the SSH-2 server */ + + sock = socket; + + /* Parse the server line and say hello - important: this information is later needed for the + * key exchange (to stop man-in-the-middle attacks) - that is why we wrap it into an object + * for later use. + */ + + ClientServerHello csh = ClientServerHello.clientHello(softwareversion, sock.getInputStream(), + sock.getOutputStream()); + + tc = new TransportConnection(sock.getInputStream(), sock.getOutputStream(), rnd); + String hostname = sock.getInetAddress().getHostName(); + int port = sock.getPort(); + + km = new ClientKexManager(this, csh, cwl, hostname, port, verifier, rnd); + km.initiateKEX(cwl, dhgex, null, null); + + startReceiver(); + } + + public void clientInit(String hostname, int port, String softwareversion, CryptoWishList cwl, + ServerHostKeyVerifier verifier, DHGexParameters dhgex, int connectTimeout, SecureRandom rnd, + ProxyData proxyData) throws IOException + { + /* First, establish the TCP connection to the SSH-2 server */ + + sock = establishConnection(hostname, port, proxyData, connectTimeout); + + /* Parse the server line and say hello - important: this information is later needed for the + * key exchange (to stop man-in-the-middle attacks) - that is why we wrap it into an object + * for later use. + */ + + ClientServerHello csh = ClientServerHello.clientHello(softwareversion, sock.getInputStream(), + sock.getOutputStream()); + + tc = new TransportConnection(sock.getInputStream(), sock.getOutputStream(), rnd); + + km = new ClientKexManager(this, csh, cwl, hostname, port, verifier, rnd); + km.initiateKEX(cwl, dhgex, null, null); + + startReceiver(); + } + + public void serverInit(ServerConnectionState state) throws IOException + { + /* TCP connection is already established */ + + this.sock = state.s; + + /* Parse the client line and say hello - important: this information is later needed for the + * key exchange (to stop man-in-the-middle attacks) - that is why we wrap it into an object + * for later use. + */ + + state.csh = ClientServerHello.serverHello(state.softwareversion, sock.getInputStream(), sock.getOutputStream()); + + tc = new TransportConnection(sock.getInputStream(), sock.getOutputStream(), state.generator); + + km = new ServerKexManager(state); + km.initiateKEX(state.next_cryptoWishList, null, state.next_dsa_key, state.next_rsa_key); + + startReceiver(); + } + + public void registerMessageHandler(MessageHandler mh, int low, int high) + { + HandlerEntry he = new HandlerEntry(); + he.mh = mh; + he.low = low; + he.high = high; + + synchronized (messageHandlers) + { + messageHandlers.add(he); + } + } + + public void removeMessageHandler(MessageHandler mh, int low, int high) + { + synchronized (messageHandlers) + { + for (int i = 0; i < messageHandlers.size(); i++) + { + HandlerEntry he = messageHandlers.get(i); + if ((he.mh == mh) && (he.low == low) && (he.high == high)) + { + messageHandlers.remove(i); + break; + } + } + } + } + + public void sendKexMessage(byte[] msg) throws IOException + { + synchronized (connectionSemaphore) + { + if (connectionClosed) + { + throw (IOException) new IOException("Sorry, this connection is closed.").initCause(reasonClosedCause); + } + + flagKexOngoing = true; + + try + { + tc.sendMessage(msg); + } + catch (IOException e) + { + close(e, false); + throw e; + } + } + } + + public void kexFinished() throws IOException + { + synchronized (connectionSemaphore) + { + flagKexOngoing = false; + connectionSemaphore.notifyAll(); + } + } + + /** + * + * @param cwl + * @param dhgex + * @param dsa may be null if this is a client connection + * @param rsa may be null if this is a client connection + * @throws IOException + */ + public void forceKeyExchange(CryptoWishList cwl, DHGexParameters dhgex, DSAPrivateKey dsa, RSAPrivateKey rsa) + throws IOException + { + synchronized (connectionSemaphore) + { + if (connectionClosed) + /* Inform the caller that there is no point in triggering a new kex */ + throw (IOException) new IOException("Sorry, this connection is closed.").initCause(reasonClosedCause); + } + + km.initiateKEX(cwl, dhgex, dsa, rsa); + } + + public void changeRecvCipher(BlockCipher bc, MAC mac) + { + tc.changeRecvCipher(bc, mac); + } + + public void changeSendCipher(BlockCipher bc, MAC mac) + { + tc.changeSendCipher(bc, mac); + } + + public void sendAsynchronousMessage(byte[] msg) throws IOException + { + sendAsynchronousMessage(msg, null); + } + + public void sendAsynchronousMessage(byte[] msg, Runnable run) throws IOException + { + synchronized (asynchronousQueue) + { + asynchronousQueue.add(new AsynchronousEntry(msg, run)); + asynchronousPending = true; + + /* This limit should be flexible enough. We need this, otherwise the peer + * can flood us with global requests (and other stuff where we have to reply + * with an asynchronous message) and (if the server just sends data and does not + * read what we send) this will probably put us in a low memory situation + * (our send queue would grow and grow and...) */ + + if (asynchronousQueue.size() > 100) + { + throw new IOException("Error: the peer is not consuming our asynchronous replies."); + } + + /* Check if we have an asynchronous sending thread */ + + if (asynchronousThread == null) + { + asynchronousThread = new AsynchronousWorker(); + asynchronousThread.setDaemon(true); + asynchronousThread.start(); + + /* The thread will stop after 2 seconds of inactivity (i.e., empty queue) */ + } + + asynchronousQueue.notifyAll(); + } + } + + public void setConnectionMonitors(List monitors) + { + synchronized (this) + { + connectionMonitors = new Vector(); + connectionMonitors.addAll(monitors); + } + } + + /** + * True if no response message expected. + */ + private boolean idle; + + /** + * Send a message but ensure that all queued messages are being sent first. + * + * @param msg + * @throws IOException + */ + public void sendMessage(byte[] msg) throws IOException + { + synchronized (asynchronousQueue) + { + while (asynchronousPending) + { + try + { + asynchronousQueue.wait(1000); + } + catch (InterruptedException e) + { + } + } + } + + sendMessageImmediate(msg); + } + + /** + * Send message, ignore queued async messages that have not been delivered yet. + * Will be called directly from the asynchronousThread thread. + * + * @param msg + * @throws IOException + */ + public void sendMessageImmediate(byte[] msg) throws IOException + { + if (Thread.currentThread() == receiveThread) + { + throw new IOException("Assertion error: sendMessage may never be invoked by the receiver thread!"); + } + + boolean wasInterrupted = false; + + try + { + synchronized (connectionSemaphore) + { + while (true) + { + if (connectionClosed) + { + throw (IOException) new IOException("Sorry, this connection is closed.") + .initCause(reasonClosedCause); + } + + if (flagKexOngoing == false) + { + break; + } + + try + { + connectionSemaphore.wait(); + } + catch (InterruptedException e) + { + wasInterrupted = true; + } + } + + try + { + tc.sendMessage(msg); + idle = false; + } + catch (IOException e) + { + close(e, false); + throw e; + } + } + } + finally + { + if (wasInterrupted) + Thread.currentThread().interrupt(); + } + } + + public void receiveLoop() throws IOException + { + byte[] msg = new byte[35000]; + + while (true) + { + int msglen; + try + { + msglen = tc.receiveMessage(msg, 0, msg.length); + } + catch (SocketTimeoutException e) + { + // Timeout in read + if (idle) + { + log.debug("Ignoring socket timeout"); + continue; + } + throw e; + } + idle = true; + + int type = msg[0] & 0xff; + + if (type == Packets.SSH_MSG_IGNORE) + { + continue; + } + + if (type == Packets.SSH_MSG_DEBUG) + { + if (log.isDebugEnabled()) + { + TypesReader tr = new TypesReader(msg, 0, msglen); + tr.readByte(); + tr.readBoolean(); + StringBuilder debugMessageBuffer = new StringBuilder(); + debugMessageBuffer.append(tr.readString("UTF-8")); + + for (int i = 0; i < debugMessageBuffer.length(); i++) + { + char c = debugMessageBuffer.charAt(i); + + if ((c >= 32) && (c <= 126)) + { + continue; + } + debugMessageBuffer.setCharAt(i, '\uFFFD'); + } + + log.debug("DEBUG Message from remote: '" + debugMessageBuffer.toString() + "'"); + } + continue; + } + + if (type == Packets.SSH_MSG_UNIMPLEMENTED) + { + throw new IOException("Peer sent UNIMPLEMENTED message, that should not happen."); + } + + if (type == Packets.SSH_MSG_DISCONNECT) + { + TypesReader tr = new TypesReader(msg, 0, msglen); + tr.readByte(); + int reason_code = tr.readUINT32(); + StringBuilder reasonBuffer = new StringBuilder(); + reasonBuffer.append(tr.readString("UTF-8")); + + /* + * Do not get fooled by servers that send abnormal long error + * messages + */ + + if (reasonBuffer.length() > 255) + { + reasonBuffer.setLength(255); + reasonBuffer.setCharAt(254, '.'); + reasonBuffer.setCharAt(253, '.'); + reasonBuffer.setCharAt(252, '.'); + } + + /* + * Also, check that the server did not send characters that may + * screw up the receiver -> restrict to reasonable US-ASCII + * subset -> "printable characters" (ASCII 32 - 126). Replace + * all others with 0xFFFD (UNICODE replacement character). + */ + + for (int i = 0; i < reasonBuffer.length(); i++) + { + char c = reasonBuffer.charAt(i); + + if ((c >= 32) && (c <= 126)) + { + continue; + } + reasonBuffer.setCharAt(i, '\uFFFD'); + } + + throw new IOException("Peer sent DISCONNECT message (reason code " + reason_code + "): " + + reasonBuffer.toString()); + } + + /* + * Is it a KEX Packet? + */ + + if ((type == Packets.SSH_MSG_KEXINIT) || (type == Packets.SSH_MSG_NEWKEYS) + || ((type >= 30) && (type <= 49))) + { + km.handleMessage(msg, msglen); + continue; + } + + MessageHandler mh = null; + + for (int i = 0; i < messageHandlers.size(); i++) + { + HandlerEntry he = messageHandlers.get(i); + if ((he.low <= type) && (type <= he.high)) + { + mh = he.mh; + break; + } + } + + if (mh == null) + { + throw new IOException("Unexpected SSH message (type " + type + ")"); + } + + mh.handleMessage(msg, msglen); + } + } +}