* ARP Reply event wrapper
*/
public class ARPReply extends ARPEvent {
-
+ private static final long serialVersionUID = 1L;
private final NodeConnector port;
private final byte[] tMac;
private final byte[] sMac;
* specified host
*/
public class ARPRequest extends ARPEvent {
+ private static final long serialVersionUID = 1L;
private final Subnet subnet;
private final HostNodeConnector host;
<artifactId>ietf-topology</artifactId>
<version>${ietf-topology.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools.model</groupId>
+ <artifactId>ietf-topology-l3-unicast-igp</artifactId>
+ <version>${ietf-topology.version}</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.yangtools.model</groupId>
<artifactId>opendaylight-l2-types</artifactId>
<artifactId>concepts</artifactId>
<version>${yangtools.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>restconf-client-api</artifactId>
+ <version>${yangtools.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>restconf-client-impl</artifactId>
+ <version>${yangtools.version}</version>
+ </dependency>
<!--Netty-->
<dependency>
<artifactId>sal-binding-broker-impl</artifactId>
<version>${mdsal.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-binding-broker-impl</artifactId>
+ <version>${mdsal.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-compatibility</artifactId>
<artifactId>statistics-manager</artifactId>
<version>${mdsal.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-remote</artifactId>
+ <version>${mdsal.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-restconf-broker</artifactId>
+ <version>${mdsal.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-binding-util</artifactId>
+ <version>${mdsal.version}</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>concepts</artifactId>
<artifactId>config-persister-impl</artifactId>
<version>${netconf.version}</version>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>ietf-netconf-monitoring</artifactId>
+ <version>${netconf.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>ietf-netconf-monitoring-extension</artifactId>
+ <version>${netconf.version}</version>
+ </dependency>
<!-- threadpool -->
<dependency>
<ignore />
</action>
</pluginExecution>
+ <pluginExecution>
+ <pluginExecutionFilter>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-enforcer-plugin</artifactId>
+ <versionRange>${enforcer.version}</versionRange>
+ <goals>
+ <goal>enforce</goal>
+ </goals>
+ </pluginExecutionFilter>
+ <action>
+ <ignore />
+ </action>
+ </pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
package org.opendaylight.protocol.framework;
import io.netty.channel.Channel;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.concurrent.Promise;
* @param <S> Protocol session type, has to extend ProtocolSession<M>
*/
public abstract class AbstractSessionNegotiator<M, S extends AbstractProtocolSession<?>> extends ChannelInboundHandlerAdapter implements SessionNegotiator<S> {
- private final Logger logger = LoggerFactory.getLogger(AbstractSessionNegotiator.class);
+ private final Logger LOG = LoggerFactory.getLogger(AbstractSessionNegotiator.class);
private final Promise<S> promise;
protected final Channel channel;
protected abstract void handleMessage(M msg) throws Exception;
protected final void negotiationSuccessful(final S session) {
- logger.debug("Negotiation on channel {} successful with session {}", channel, session);
+ LOG.debug("Negotiation on channel {} successful with session {}", channel, session);
channel.pipeline().replace(this, "session", session);
promise.setSuccess(session);
}
protected final void negotiationFailed(final Throwable cause) {
- logger.debug("Negotiation on channel {} failed", channel, cause);
+ LOG.debug("Negotiation on channel {} failed", channel, cause);
channel.close();
promise.setFailure(cause);
}
+ /**
+ * Send a message to peer and fail negotiation if it does not reach
+ * the peer.
+ *
+ * @param msg Message which should be sent.
+ */
+ protected final void sendMessage(final M msg) {
+ this.channel.writeAndFlush(msg).addListener(
+ new ChannelFutureListener() {
+ @Override
+ public void operationComplete(final ChannelFuture f) {
+ if (!f.isSuccess()) {
+ LOG.info("Failed to send message {}", msg, f.cause());
+ negotiationFailed(f.cause());
+ } else {
+ LOG.trace("Message {} sent to socket", msg);
+ }
+ }
+ });
+ }
+
@Override
public final void channelActive(final ChannelHandlerContext ctx) {
- logger.debug("Starting session negotiation on channel {}", channel);
+ LOG.debug("Starting session negotiation on channel {}", channel);
try {
startNegotiation();
} catch (Exception e) {
- logger.warn("Unexpected negotiation failure", e);
+ LOG.warn("Unexpected negotiation failure", e);
negotiationFailed(e);
}
}
@Override
public final void channelRead(final ChannelHandlerContext ctx, final Object msg) {
- logger.debug("Negotiation read invoked on channel {}", channel);
+ LOG.debug("Negotiation read invoked on channel {}", channel);
try {
handleMessage((M)msg);
} catch (Exception e) {
- logger.debug("Unexpected error while handling negotiation message {}", msg, e);
+ LOG.debug("Unexpected error while handling negotiation message {}", msg, e);
negotiationFailed(e);
}
}
@Override
public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) {
- logger.info("Unexpected error during negotiation", cause);
+ LOG.info("Unexpected error during negotiation", cause);
negotiationFailed(cause);
}
}
}
if (!cf.isSuccess()) {
- LOG.warn("Attempt to connect to connect to {} failed", ProtocolSessionPromise.this.address, cf.cause());
+ LOG.debug("Attempt to connect to {} failed", ProtocolSessionPromise.this.address, cf.cause());
+
final Future<Void> rf = ProtocolSessionPromise.this.strategy.scheduleReconnect(cf.cause());
rf.addListener(new FutureListener<Void>() {
@Override
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>concepts</artifactId>
- <version>${yangtools.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-data-impl</artifactId>
- <version>${yangtools.version}</version>
</dependency>
</dependencies>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-persister-directory-adapter</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-persister-directory-xml-adapter</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-persister-file-xml-adapter</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
@Test
public void testLookupRuntimeBeans() throws Exception {
Set<ObjectName> jmxLookup = lookupRuntimeBeans(jmxRegistryClient);
- assertEquals(Sets.newHashSet(testingRegistry.run2, testingRegistry.run1, testingRegistry.run3), jmxLookup);
+ assertEquals(Sets.newHashSet(TestingConfigRegistry.run2, TestingConfigRegistry.run1, TestingConfigRegistry.run3), jmxLookup);
}
private Set<ObjectName> lookupRuntimeBeans(ConfigRegistryClient client)
jmxRegistryClient, TestingConfigRegistry.moduleName1,
TestingConfigRegistry.instName1);
assertEquals(1, jmxLookup.size());
- assertEquals(Sets.newHashSet(testingRegistry.run2), jmxLookup);
+ assertEquals(Sets.newHashSet(TestingConfigRegistry.run2), jmxLookup);
jmxLookup = clientLookupRuntimeBeansWithModuleAndInstance(
jmxRegistryClient, TestingConfigRegistry.moduleName2,
TestingConfigRegistry.instName2);
assertEquals(1, jmxLookup.size());
- assertEquals(Sets.newHashSet(testingRegistry.run3), jmxLookup);
+ assertEquals(Sets.newHashSet(TestingConfigRegistry.run3), jmxLookup);
jmxLookup = clientLookupRuntimeBeansWithModuleAndInstance(
jmxRegistryClient, TestingConfigRegistry.moduleName1,
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netty-config-api</artifactId>
- <version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
*/
package org.opendaylight.controller.config.yang.netty.eventexecutor;
-import io.netty.util.concurrent.AbstractEventExecutor;
+import com.google.common.reflect.AbstractInvocationHandler;
+import com.google.common.reflect.Reflection;
import io.netty.util.concurrent.EventExecutor;
-import io.netty.util.concurrent.EventExecutorGroup;
-import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GlobalEventExecutor;
-import io.netty.util.concurrent.ScheduledFuture;
-import java.util.concurrent.Callable;
+import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
-/**
-*
-*/
public final class GlobalEventExecutorModule extends
org.opendaylight.controller.config.yang.netty.eventexecutor.AbstractGlobalEventExecutorModule {
@Override
public java.lang.AutoCloseable createInstance() {
- return new GlobalEventExecutorCloseable(GlobalEventExecutor.INSTANCE);
+ final CloseableGlobalEventExecutorMixin closeableGlobalEventExecutorMixin =
+ new CloseableGlobalEventExecutorMixin(GlobalEventExecutor.INSTANCE);
+ return Reflection.newProxy(AutoCloseableEventExecutor.class, new AbstractInvocationHandler() {
+ @Override
+ protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable {
+ if (method.getName().equals("close")) {
+ closeableGlobalEventExecutorMixin.close();
+ return null;
+ } else {
+ return method.invoke(GlobalEventExecutor.INSTANCE, args);
+ }
+ }
+ });
}
- static final private class GlobalEventExecutorCloseable extends AbstractEventExecutor implements AutoCloseable {
-
- private EventExecutor executor;
-
- public GlobalEventExecutorCloseable(EventExecutor executor) {
- this.executor = executor;
- }
-
- @Override
- public EventExecutorGroup parent() {
- return this.executor.parent();
- }
-
- @Override
- public boolean inEventLoop(Thread thread) {
- return this.executor.inEventLoop(thread);
- }
-
- @Override
- public boolean isShuttingDown() {
- return this.executor.isShuttingDown();
- }
-
- @Override
- public Future<?> shutdownGracefully(long quietPeriod, long timeout, TimeUnit unit) {
- return this.executor.shutdownGracefully(quietPeriod, timeout, unit);
- }
-
- @Override
- public Future<?> terminationFuture() {
- return this.executor.terminationFuture();
- }
-
- @Override
- public boolean isShutdown() {
- return this.executor.isShutdown();
- }
+ public static interface AutoCloseableEventExecutor extends EventExecutor, AutoCloseable {
- @Override
- public boolean isTerminated() {
- return this.executor.isTerminated();
- }
-
- @Override
- public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
- return this.executor.awaitTermination(timeout, unit);
- }
-
- @Override
- public void execute(Runnable command) {
- this.executor.execute(command);
- }
-
- @Override
- public void close() throws Exception {
- shutdownGracefully();
- }
-
- @SuppressWarnings("deprecation")
- @Override
- public void shutdown() {
- this.executor.shutdown();
- }
-
- @Override
- public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
- return this.executor.scheduleWithFixedDelay(command, initialDelay, delay, unit);
- }
+ }
- @Override
- public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
- return this.executor.schedule(command, delay, unit);
- }
+ public static class CloseableGlobalEventExecutorMixin implements AutoCloseable {
+ private final GlobalEventExecutor eventExecutor;
- @Override
- public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
- return this.executor.schedule(callable, delay, unit);
+ public CloseableGlobalEventExecutorMixin(GlobalEventExecutor eventExecutor) {
+ this.eventExecutor = eventExecutor;
}
@Override
- public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
- return this.executor.scheduleAtFixedRate(command, initialDelay, period, unit);
+ public void close() {
+ eventExecutor.shutdownGracefully(0, 1, TimeUnit.SECONDS);
}
}
}
*/
/**
-* Generated file
-
-* Generated from: yang module name: netty-event-executor yang module local name: netty-global-event-executor
-* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
-* Generated at: Tue Nov 12 10:44:21 CET 2013
-*
-* Do not modify this file unless it is present under src/main directory
-*/
+ * Generated file
+
+ * Generated from: yang module name: netty-event-executor yang module local name: netty-global-event-executor
+ * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+ * Generated at: Tue Nov 12 10:44:21 CET 2013
+ *
+ * Do not modify this file unless it is present under src/main directory
+ */
package org.opendaylight.controller.config.yang.netty.eventexecutor;
-/**
-*
-*/
-public class GlobalEventExecutorModuleFactory extends org.opendaylight.controller.config.yang.netty.eventexecutor.AbstractGlobalEventExecutorModuleFactory
-{
+import org.opendaylight.controller.config.api.DependencyResolver;
+import org.osgi.framework.BundleContext;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+public class GlobalEventExecutorModuleFactory extends org.opendaylight.controller.config.yang.netty.eventexecutor.AbstractGlobalEventExecutorModuleFactory {
+ public static final String SINGLETON_NAME = "singleton";
+
+ @Override
+ public GlobalEventExecutorModule instantiateModule(String instanceName, DependencyResolver dependencyResolver, GlobalEventExecutorModule oldModule, AutoCloseable oldInstance, BundleContext bundleContext) {
+ checkArgument(SINGLETON_NAME.equals(instanceName),"Illegal instance name '" + instanceName + "', only allowed name is " + SINGLETON_NAME);
+ return super.instantiateModule(instanceName, dependencyResolver, oldModule, oldInstance, bundleContext);
+ }
+ @Override
+ public GlobalEventExecutorModule instantiateModule(String instanceName, DependencyResolver dependencyResolver, BundleContext bundleContext) {
+ checkArgument(SINGLETON_NAME.equals(instanceName),"Illegal instance name '" + instanceName + "', only allowed name is " + SINGLETON_NAME);
+ return super.instantiateModule(instanceName, dependencyResolver, bundleContext);
+ }
}
package org.opendaylight.controller.config.yang.netty.eventexecutor;
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.ObjectName;
-
import org.junit.Before;
import org.junit.Test;
import org.opendaylight.controller.config.api.ConflictingVersionException;
import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.ObjectName;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
public class GlobalEventExecutorModuleTest extends AbstractConfigTest {
private GlobalEventExecutorModuleFactory factory;
- private final String instanceName = "netty1";
+ private final String instanceName = GlobalEventExecutorModuleFactory.SINGLETON_NAME;
@Before
public void setUp() {
ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
createInstance(transaction, instanceName);
- createInstance(transaction, instanceName + 2);
+
transaction.validateConfig();
CommitStatus status = transaction.commit();
- assertBeanCount(2, factory.getImplementationName());
- assertStatus(status, 2, 0, 0);
+ assertBeanCount(1, factory.getImplementationName());
+ assertStatus(status, 1, 0, 0);
+ }
+
+ @Test
+ public void testConflictingName() throws Exception {
+ ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
+ try {
+ createInstance(transaction, instanceName + "x");
+ fail();
+ }catch(IllegalArgumentException e){
+ assertTrue(e.getMessage() + " failure", e.getMessage().contains("only allowed name is singleton"));
+ }
}
@Test
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netty-config-api</artifactId>
- <version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
import org.opendaylight.controller.config.api.JmxAttributeValidationException;
+import java.util.concurrent.TimeUnit;
+
/**
*
*/
@Override
public void close() throws Exception {
- shutdownGracefully();
+ shutdownGracefully(0, 1, TimeUnit.SECONDS);
}
}
}
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netty-config-api</artifactId>
- <version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>threadpool-config-api</artifactId>
- <version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>threadpool-config-impl</artifactId>
- <version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
- <version>${logback.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</plugins>
</pluginManagement>
</build>
-</project>
\ No newline at end of file
+</project>
class StopSystemBundleThread extends Thread {
private static final Logger logger = LoggerFactory.getLogger(StopSystemBundleThread.class);
+ public static final String CONFIG_MANAGER_SYMBOLIC_NAME = "org.opendaylight.controller.config-manager";
private final Bundle systemBundle;
StopSystemBundleThread(Bundle systemBundle) {
try {
// wait so that JMX response is received
Thread.sleep(1000);
+ // first try to stop config-manager
+ Bundle configManager = findConfigManager();
+ if (configManager != null){
+ logger.debug("Stopping config-manager");
+ configManager.stop();
+ Thread.sleep(1000);
+ }
+ logger.debug("Stopping system bundle");
systemBundle.stop();
} catch (BundleException e) {
logger.warn("Can not stop OSGi server", e);
logger.warn("Shutdown process interrupted", e);
}
}
+
+ private Bundle findConfigManager() {
+ for(Bundle bundle: systemBundle.getBundleContext().getBundles()){
+ if (CONFIG_MANAGER_SYMBOLIC_NAME.equals(bundle.getSymbolicName())) {
+ return bundle;
+ }
+ }
+ return null;
+ }
+
}
class CallSystemExitThread extends Thread {
import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
import org.osgi.framework.Bundle;
+import javax.management.InstanceNotFoundException;
import javax.management.JMX;
import javax.management.ObjectName;
import java.util.Collections;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.opendaylight.controller.config.yang.shutdown.impl.ShutdownModuleFactory.NAME;
public class ShutdownTest extends AbstractConfigTest {
private final ShutdownModuleFactory factory = new ShutdownModuleFactory();
@Mock
- private Bundle mockedSysBundle;
+ private Bundle mockedSysBundle, mockedConfigManager;
+
@Before
public void setUp() throws Exception {
doReturn(mockedSysBundle).when(mockedContext).getBundle(0);
mockedContext.getBundle(0);
doNothing().when(mockedSysBundle).stop();
+ doNothing().when(mockedConfigManager).stop();
+ doReturn(mockedContext).when(mockedSysBundle).getBundleContext();
+ doReturn(new Bundle[]{mockedSysBundle, mockedConfigManager}).when(mockedContext).getBundles();
+ doReturn("system bundle").when(mockedSysBundle).getSymbolicName();
+ doReturn(StopSystemBundleThread.CONFIG_MANAGER_SYMBOLIC_NAME).when(mockedConfigManager).getSymbolicName();
+
+
ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
// initialize default instance
transaction.commit();
@Test
public void testWithSecret() throws Exception {
+ String secret = "secret";
+ setSecret(secret);
+ shutdownViaRuntimeJMX(secret);
+ }
+
+ private void setSecret(String secret) throws InstanceNotFoundException {
ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
ObjectName on = transaction.lookupConfigBean(NAME, NAME);
ShutdownModuleMXBean proxy = transaction.newMXBeanProxy(on, ShutdownModuleMXBean.class);
- String secret = "secret";
proxy.setSecret(secret);
transaction.commit();
- shutdownViaRuntimeJMX(secret);
+ }
+
+ @Test
+ public void testWrongSecret() throws Exception {
+ setSecret("secret");
try {
ShutdownRuntimeMXBean runtime = JMX.newMXBeanProxy(platformMBeanServer, runtimeON, ShutdownRuntimeMXBean.class);
runtime.shutdown("foo", 60000L, null);
assertStopped();
}
-
private void assertStopped() throws Exception {
- Thread.sleep(2000); // happens on another thread
+ Thread.sleep(3000); // happens on another thread
+ verify(mockedConfigManager).stop();
verify(mockedSysBundle).stop();
- verifyNoMoreInteractions(mockedSysBundle);
- reset(mockedSysBundle);
- doNothing().when(mockedSysBundle).stop();
}
}
*/
package org.opendaylight.controller.config.yangjmxgenerator;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Optional;
-import com.google.common.collect.Sets;
-import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
-import java.util.HashMap;
import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.AbstractDependencyAttribute;
+
import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.DependencyAttribute;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
import org.opendaylight.controller.config.yangjmxgenerator.plugin.util.FullyQualifiedNameHelper;
-import org.opendaylight.controller.config.yangjmxgenerator.plugin.util.NameConflictException;
-import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil;
import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
-import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
-import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
-import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
-import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
import org.opendaylight.yangtools.yang.model.api.Module;
-import org.opendaylight.yangtools.yang.model.api.ModuleImport;
-import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.model.api.SchemaNode;
-import org.opendaylight.yangtools.yang.model.api.SchemaPath;
-import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.UsesNode;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
-import static java.lang.String.format;
-import static org.opendaylight.controller.config.yangjmxgenerator.ConfigConstants.createConfigQName;
/**
* Represents part of yang model that describes a module.
* </p>
*/
public class ModuleMXBeanEntry extends AbstractEntry {
- private static final Logger logger = LoggerFactory
- .getLogger(ModuleMXBeanEntry.class);
-
- // TODO: the XPath should be parsed by code generator IMO
- private static final String MAGIC_STRING = "MAGIC_STRING";
- private static final String MODULE_CONDITION_XPATH_TEMPLATE = "^/MAGIC_STRING:modules/MAGIC_STRING:module/MAGIC_STRING:type\\s*=\\s*['\"](.+)['\"]$";
- private static final SchemaPath expectedConfigurationAugmentationSchemaPath = new SchemaPath(
- Arrays.asList(createConfigQName("modules"),
- createConfigQName("module"),
- createConfigQName("configuration")), true);
- private static final SchemaPath expectedStateAugmentationSchemaPath = new SchemaPath(
- Arrays.asList(createConfigQName("modules"),
- createConfigQName("module"), createConfigQName("state")),
- true);
-
- private static final Pattern PREFIX_COLON_LOCAL_NAME = Pattern
- .compile("^(.+):(.+)$");
private static final String MODULE_SUFFIX = "Module";
private static final String FACTORY_SUFFIX = MODULE_SUFFIX + "Factory";
private static final String CLASS_NAME_SUFFIX = MODULE_SUFFIX + "MXBean";
private static final String ABSTRACT_PREFIX = "Abstract";
- /*
- * threadpool-dynamic from the example above, taken from when condition, not
- * the case name
- */
- private final String globallyUniqueName;
+ private final ModuleMXBeanEntryInitial initial;
private Map<String, AttributeIfc> yangToAttributes;
- private final String nullableDescription, packageName, javaNamePrefix,
- namespace;
-
private final Map<String, QName> providedServices;
private Collection<RuntimeBeanEntry> runtimeBeans;
- private final QName yangModuleQName;
-
- public ModuleMXBeanEntry(IdentitySchemaNode id,
- Map<String, AttributeIfc> yangToAttributes, String packageName,
- Map<String, QName> providedServices2, String javaNamePrefix,
- String namespace, Collection<RuntimeBeanEntry> runtimeBeans,
- QName yangModuleQName) {
- this.globallyUniqueName = id.getQName().getLocalName();
+
+ ModuleMXBeanEntry(ModuleMXBeanEntryInitial initials, Map<String, AttributeIfc> yangToAttributes,
+ Map<String, QName> providedServices2, Collection<RuntimeBeanEntry> runtimeBeans) {
this.yangToAttributes = yangToAttributes;
- this.nullableDescription = id.getDescription();
- this.packageName = packageName;
- this.javaNamePrefix = checkNotNull(javaNamePrefix);
- this.namespace = checkNotNull(namespace);
this.providedServices = Collections.unmodifiableMap(providedServices2);
this.runtimeBeans = runtimeBeans;
- this.yangModuleQName = yangModuleQName;
+ this.initial = initials;
}
public String getMXBeanInterfaceName() {
- return javaNamePrefix + CLASS_NAME_SUFFIX;
+ return initial.javaNamePrefix + CLASS_NAME_SUFFIX;
}
public String getStubFactoryName() {
- return javaNamePrefix + FACTORY_SUFFIX;
+ return initial.javaNamePrefix + FACTORY_SUFFIX;
}
public String getAbstractFactoryName() {
}
public String getStubModuleName() {
- return javaNamePrefix + MODULE_SUFFIX;
+ return initial.javaNamePrefix + MODULE_SUFFIX;
}
public String getAbstractModuleName() {
}
public String getFullyQualifiedName(String typeName) {
- return FullyQualifiedNameHelper.getFullyQualifiedName(packageName,
+ return FullyQualifiedNameHelper.getFullyQualifiedName(initial.packageName,
typeName);
}
public String getGloballyUniqueName() {
- return globallyUniqueName;
+ return initial.localName;
}
public String getPackageName() {
- return packageName;
+ return initial.packageName;
}
/**
}
public String getJavaNamePrefix() {
- return javaNamePrefix;
+ return initial.javaNamePrefix;
}
public String getNamespace() {
- return namespace;
- }
-
- @VisibleForTesting
- static Matcher getWhenConditionMatcher(String prefix,
- RevisionAwareXPath whenConstraint) {
- String xpathRegex = MODULE_CONDITION_XPATH_TEMPLATE.replace(
- MAGIC_STRING, prefix);
- Pattern pattern = Pattern.compile(xpathRegex);
- return pattern.matcher(whenConstraint.toString());
- }
-
- static String getConfigModulePrefixFromImport(Module currentModule) {
- for (ModuleImport currentImport : currentModule.getImports()) {
- if (currentImport.getModuleName().equals(
- ConfigConstants.CONFIG_MODULE)) {
- return currentImport.getPrefix();
- }
- }
- throw new IllegalArgumentException("Cannot find import "
- + ConfigConstants.CONFIG_MODULE + " in " + currentModule);
+ return initial.namespace;
}
/**
Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
SchemaContext schemaContext,
TypeProviderWrapper typeProviderWrapper, String packageName) {
- Map<String, QName> uniqueGeneratedClassesNames = new HashMap<>();
- logger.debug("Generating ModuleMXBeans of {} to package {}",
- currentModule.getNamespace(), packageName);
- String configModulePrefix;
- try {
- configModulePrefix = getConfigModulePrefixFromImport(currentModule);
- } catch (IllegalArgumentException e) {
- // this module does not import config module
- return Collections.emptyMap();
- }
- // get identities of base config:module-type
- Map<String, IdentitySchemaNode> moduleIdentities = new HashMap<>();
-
- for (IdentitySchemaNode id : currentModule.getIdentities()) {
- if (id.getBaseIdentity() != null
- && ConfigConstants.MODULE_TYPE_Q_NAME.equals(id
- .getBaseIdentity().getQName())) {
- String identityLocalName = id.getQName().getLocalName();
- if (moduleIdentities.containsKey(identityLocalName)) {
- throw new IllegalStateException(
- "Module name already defined in this module: "
- + identityLocalName);
- } else {
- moduleIdentities.put(identityLocalName, id);
- logger.debug("Found identity {}", identityLocalName);
- }
- // validation check on unknown schema nodes
- boolean providedServiceWasSet = false;
- for (UnknownSchemaNode unknownNode : id.getUnknownSchemaNodes()) {
- // TODO: test this
- if (ConfigConstants.PROVIDED_SERVICE_EXTENSION_QNAME
- .equals(unknownNode.getNodeType())) {
- // no op: 0 or more provided identities are allowed
- } else if (ConfigConstants.JAVA_NAME_PREFIX_EXTENSION_QNAME
- .equals(unknownNode.getNodeType())) {
- // 0..1 allowed
- checkState(
- providedServiceWasSet == false,
- format("More than one language extension %s is not allowed here: %s",
- ConfigConstants.JAVA_NAME_PREFIX_EXTENSION_QNAME,
- id));
- providedServiceWasSet = true;
- } else {
- throw new IllegalStateException(
- "Unexpected language extension "
- + unknownNode.getNodeType());
- }
- }
- }
- }
- Map<String, ModuleMXBeanEntry> result = new HashMap<>();
- // each module name should have an augmentation defined
- Map<String, IdentitySchemaNode> unaugmentedModuleIdentities = new HashMap<>(
- moduleIdentities);
- for (AugmentationSchema augmentation : currentModule.getAugmentations()) {
- Set<DataSchemaNode> childNodes = augmentation.getChildNodes();
- if (childNodes.size() == 1) {
- DataSchemaNode when = childNodes.iterator().next();
- if (when instanceof ChoiceCaseNode) {
- ChoiceCaseNode choiceCaseNode = (ChoiceCaseNode) when;
- if (choiceCaseNode.getConstraints() == null
- || choiceCaseNode.getConstraints()
- .getWhenCondition() == null) {
- continue;
- }
- RevisionAwareXPath xPath = choiceCaseNode.getConstraints()
- .getWhenCondition();
- Matcher matcher = getWhenConditionMatcher(
- configModulePrefix, xPath);
- if (matcher.matches() == false) {
- continue;
- }
- String moduleLocalNameFromXPath = matcher.group(1);
- IdentitySchemaNode moduleIdentity = moduleIdentities
- .get(moduleLocalNameFromXPath);
- unaugmentedModuleIdentities
- .remove(moduleLocalNameFromXPath);
- checkState(moduleIdentity != null, "Cannot find identity "
- + moduleLocalNameFromXPath
- + " matching augmentation " + augmentation);
- Map<String, QName> providedServices = findProvidedServices(
- moduleIdentity, currentModule, qNamesToSIEs,
- schemaContext);
-
- if (moduleIdentity == null) {
- throw new IllegalStateException(
- "Cannot find identity specified by augmentation xpath constraint: "
- + moduleLocalNameFromXPath + " of "
- + augmentation);
- }
- String javaNamePrefix = findJavaNamePrefix(moduleIdentity);
-
- Map<String, AttributeIfc> yangToAttributes = null;
- // runtime-data
- Collection<RuntimeBeanEntry> runtimeBeans = null;
-
- if (expectedConfigurationAugmentationSchemaPath
- .equals(augmentation.getTargetPath())) {
- logger.debug("Parsing configuration of {}",
- moduleLocalNameFromXPath);
- yangToAttributes = fillConfiguration(choiceCaseNode,
- currentModule, typeProviderWrapper,
- qNamesToSIEs, schemaContext, packageName);
- checkUniqueAttributesWithGeneratedClass(
- uniqueGeneratedClassesNames, when.getQName(),
- yangToAttributes);
- } else if (expectedStateAugmentationSchemaPath
- .equals(augmentation.getTargetPath())) {
- logger.debug("Parsing state of {}",
- moduleLocalNameFromXPath);
- try {
- runtimeBeans = fillRuntimeBeans(choiceCaseNode,
- currentModule, typeProviderWrapper,
- packageName, moduleLocalNameFromXPath,
- javaNamePrefix);
- } catch (NameConflictException e) {
- throw new NameConflictException(
- e.getConflictingName(), when.getQName(),
- when.getQName());
- }
- checkUniqueRuntimeBeansGeneratedClasses(
- uniqueGeneratedClassesNames, when, runtimeBeans);
- Set<RuntimeBeanEntry> runtimeBeanEntryValues = Sets
- .newHashSet(runtimeBeans);
- for (RuntimeBeanEntry entry : runtimeBeanEntryValues) {
- checkUniqueAttributesWithGeneratedClass(
- uniqueGeneratedClassesNames,
- when.getQName(),
- entry.getYangPropertiesToTypesMap());
- }
-
- } else {
- throw new IllegalArgumentException(
- "Cannot parse augmentation " + augmentation);
- }
- if (result.containsKey(moduleLocalNameFromXPath)) {
- // either fill runtimeBeans or yangToAttributes
- ModuleMXBeanEntry moduleMXBeanEntry = result
- .get(moduleLocalNameFromXPath);
- if (yangToAttributes != null
- && moduleMXBeanEntry.getAttributes() == null) {
- moduleMXBeanEntry
- .setYangToAttributes(yangToAttributes);
- } else if (runtimeBeans != null
- && moduleMXBeanEntry.getRuntimeBeans() == null) {
- moduleMXBeanEntry.setRuntimeBeans(runtimeBeans);
- }
- } else {
- // construct ModuleMXBeanEntry
- ModuleMXBeanEntry moduleMXBeanEntry = new ModuleMXBeanEntry(
- moduleIdentity, yangToAttributes, packageName,
- providedServices, javaNamePrefix, currentModule
- .getNamespace().toString(),
- runtimeBeans,
- ModuleUtil.getQName(currentModule));
- moduleMXBeanEntry.setYangModuleName(currentModule
- .getName());
- moduleMXBeanEntry
- .setYangModuleLocalname(moduleLocalNameFromXPath);
- result.put(moduleLocalNameFromXPath, moduleMXBeanEntry);
- }
- } // skip if child node is not ChoiceCaseNode
- } // skip if childNodes != 1
- }
- // clean up nulls
- for (Entry<String, ModuleMXBeanEntry> entry : result.entrySet()) {
- ModuleMXBeanEntry module = entry.getValue();
- if (module.getAttributes() == null) {
- module.setYangToAttributes(Collections
- .<String, AttributeIfc> emptyMap());
- } else if (module.getRuntimeBeans() == null) {
- module.setRuntimeBeans(Collections
- .<RuntimeBeanEntry> emptyList());
- }
- }
- // check attributes name uniqueness
- for (Entry<String, ModuleMXBeanEntry> entry : result.entrySet()) {
- checkUniqueRuntimeBeanAttributesName(entry.getValue(),
- uniqueGeneratedClassesNames);
- }
- if (unaugmentedModuleIdentities.size() > 0) {
- logger.warn("Augmentation not found for all module identities: {}",
- unaugmentedModuleIdentities.keySet());
- }
+ ModuleMXBeanEntryBuilder builder = new ModuleMXBeanEntryBuilder().setModule(currentModule).setqNamesToSIEs(qNamesToSIEs)
+ .setSchemaContext(schemaContext).setTypeProviderWrapper(typeProviderWrapper)
+ .setPackageName(packageName);
- logger.debug("Number of ModuleMXBeans to be generated: {}",
- result.size());
- return result;
+ return builder.build();
}
- private static void checkUniqueRuntimeBeansGeneratedClasses(
- Map<String, QName> uniqueGeneratedClassesNames,
- DataSchemaNode when, Collection<RuntimeBeanEntry> runtimeBeans) {
- for (RuntimeBeanEntry runtimeBean : runtimeBeans) {
- final String javaNameOfRuntimeMXBean = runtimeBean
- .getJavaNameOfRuntimeMXBean();
- if (uniqueGeneratedClassesNames
- .containsKey(javaNameOfRuntimeMXBean)) {
- QName firstDefinedQName = uniqueGeneratedClassesNames
- .get(javaNameOfRuntimeMXBean);
- throw new NameConflictException(javaNameOfRuntimeMXBean,
- firstDefinedQName, when.getQName());
- }
- uniqueGeneratedClassesNames.put(javaNameOfRuntimeMXBean,
- when.getQName());
- }
- }
-
- private static void checkUniqueRuntimeBeanAttributesName(
- ModuleMXBeanEntry mxBeanEntry,
- Map<String, QName> uniqueGeneratedClassesNames) {
- for (RuntimeBeanEntry runtimeBeanEntry : mxBeanEntry.getRuntimeBeans()) {
- for (String runtimeAttName : runtimeBeanEntry
- .getYangPropertiesToTypesMap().keySet()) {
- if (mxBeanEntry.getAttributes().keySet()
- .contains(runtimeAttName)) {
- QName qName1 = uniqueGeneratedClassesNames
- .get(runtimeBeanEntry.getJavaNameOfRuntimeMXBean());
- QName qName2 = uniqueGeneratedClassesNames.get(mxBeanEntry
- .getGloballyUniqueName());
- throw new NameConflictException(runtimeAttName, qName1,
- qName2);
- }
- }
- }
- }
-
- private static void checkUniqueAttributesWithGeneratedClass(
- Map<String, QName> uniqueGeneratedClassNames, QName parentQName,
- Map<String, AttributeIfc> yangToAttributes) {
- for (Entry<String, AttributeIfc> attr : yangToAttributes.entrySet()) {
- if (attr.getValue() instanceof TOAttribute) {
- checkUniqueTOAttr(uniqueGeneratedClassNames, parentQName,
- (TOAttribute) attr.getValue());
- } else if (attr.getValue() instanceof ListAttribute
- && ((ListAttribute) attr.getValue()).getInnerAttribute() instanceof TOAttribute) {
- checkUniqueTOAttr(uniqueGeneratedClassNames, parentQName,
- (TOAttribute) ((ListAttribute) attr.getValue())
- .getInnerAttribute());
- }
- }
+ public Map<String, AttributeIfc> getAttributes() {
+ return yangToAttributes;
}
- private static void checkUniqueTOAttr(
- Map<String, QName> uniqueGeneratedClassNames, QName parentQName,
- TOAttribute attr) {
- final String upperCaseCammelCase = attr.getUpperCaseCammelCase();
- if (uniqueGeneratedClassNames.containsKey(upperCaseCammelCase)) {
- QName firstDefinedQName = uniqueGeneratedClassNames
- .get(upperCaseCammelCase);
- throw new NameConflictException(upperCaseCammelCase,
- firstDefinedQName, parentQName);
- } else {
- uniqueGeneratedClassNames.put(upperCaseCammelCase, parentQName);
- }
+ void setYangToAttributes(Map<String, AttributeIfc> newAttributes) {
+ this.yangToAttributes = newAttributes;
}
- private static Collection<RuntimeBeanEntry> fillRuntimeBeans(
- ChoiceCaseNode choiceCaseNode, Module currentModule,
- TypeProviderWrapper typeProviderWrapper, String packageName,
- String moduleLocalNameFromXPath, String javaNamePrefix) {
-
- return RuntimeBeanEntry.extractClassNameToRuntimeBeanMap(packageName,
- choiceCaseNode, moduleLocalNameFromXPath, typeProviderWrapper,
- javaNamePrefix, currentModule).values();
-
+ public String getNullableDescription() {
+ return initial.description;
}
- private static Map<String, AttributeIfc> fillConfiguration(
- ChoiceCaseNode choiceCaseNode, Module currentModule,
- TypeProviderWrapper typeProviderWrapper,
- Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
- SchemaContext schemaContext, String packageName) {
- Map<String, AttributeIfc> yangToAttributes = new HashMap<>();
- for (DataSchemaNode attrNode : choiceCaseNode.getChildNodes()) {
- AttributeIfc attributeValue = getAttributeValue(attrNode,
- currentModule, qNamesToSIEs, typeProviderWrapper,
- schemaContext, packageName);
- yangToAttributes.put(attributeValue.getAttributeYangName(),
- attributeValue);
- }
- return yangToAttributes;
+ public QName getYangModuleQName() {
+ return initial.qName;
}
- private static Map<String, QName> findProvidedServices(
- IdentitySchemaNode moduleIdentity, Module currentModule,
- Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
- SchemaContext schemaContext) {
- Map<String, QName> result = new HashMap<>();
- for (UnknownSchemaNode unknownNode : moduleIdentity
- .getUnknownSchemaNodes()) {
- if (ConfigConstants.PROVIDED_SERVICE_EXTENSION_QNAME
- .equals(unknownNode.getNodeType())) {
- String prefixAndIdentityLocalName = unknownNode
- .getNodeParameter();
- ServiceInterfaceEntry sie = findSIE(prefixAndIdentityLocalName,
- currentModule, qNamesToSIEs, schemaContext);
- result.put(sie.getFullyQualifiedName(), sie.getQName());
- }
- }
- return result;
+ @Override
+ public String toString() {
+ return "ModuleMXBeanEntry{" + "globallyUniqueName='"
+ + initial.localName + '\'' + ", packageName='" + initial.packageName
+ + '\'' + '}';
}
- /**
- * For input node, find if it contains config:java-name-prefix extension. If
- * not found, convert local name of node converted to cammel case.
- */
- public static String findJavaNamePrefix(SchemaNode schemaNode) {
- return convertToJavaName(schemaNode, true);
- }
+ static final class ModuleMXBeanEntryInitial {
- public static String findJavaParameter(SchemaNode schemaNode) {
- return convertToJavaName(schemaNode, false);
- }
+ private String localName;
+ private String description;
+ private String packageName;
+ private String javaNamePrefix;
+ private String namespace;
+ private QName qName;
- public static String convertToJavaName(SchemaNode schemaNode,
- boolean capitalizeFirstLetter) {
- for (UnknownSchemaNode unknownNode : schemaNode.getUnknownSchemaNodes()) {
- if (ConfigConstants.JAVA_NAME_PREFIX_EXTENSION_QNAME
- .equals(unknownNode.getNodeType())) {
- String value = unknownNode.getNodeParameter();
- return convertToJavaName(value, capitalizeFirstLetter);
- }
+ ModuleMXBeanEntryInitial(String localName, String description, String packageName, String javaNamePrefix, String namespace, QName qName) {
+ this.localName = localName;
+ this.description = description;
+ this.packageName = packageName;
+ this.javaNamePrefix = javaNamePrefix;
+ this.namespace = namespace;
+ this.qName = qName;
}
- return convertToJavaName(schemaNode.getQName().getLocalName(),
- capitalizeFirstLetter);
}
- public static String convertToJavaName(String localName,
- boolean capitalizeFirstLetter) {
- if (capitalizeFirstLetter) {
- return BindingGeneratorUtil.parseToClassName(localName);
- } else {
- return BindingGeneratorUtil.parseToValidParamName(localName);
- }
- }
+ static final class ModuleMXBeanEntryInitialBuilder {
+ private String localName;
+ private String description;
+ private String packageName;
+ private String javaNamePrefix;
+ private String namespace;
+ private QName qName;
- private static int getChildNodeSizeWithoutUses(DataNodeContainer csn) {
- int result = 0;
- for (DataSchemaNode dsn : csn.getChildNodes()) {
- if (dsn.isAddedByUses() == false) {
- result++;
- }
+ public ModuleMXBeanEntryInitialBuilder setPackageName(String packageName) {
+ this.packageName = packageName;
+ return this;
}
- return result;
- }
- private static AttributeIfc getAttributeValue(DataSchemaNode attrNode,
- Module currentModule,
- Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
- TypeProviderWrapper typeProviderWrapper,
- SchemaContext schemaContext, String packageName) {
-
- if (attrNode instanceof LeafSchemaNode) {
- // simple type
- LeafSchemaNode leaf = (LeafSchemaNode) attrNode;
- return new JavaAttribute(leaf, typeProviderWrapper);
- } else if (attrNode instanceof ContainerSchemaNode) {
- // reference or TO
- ContainerSchemaNode containerSchemaNode = (ContainerSchemaNode) attrNode;
- Optional<? extends AbstractDependencyAttribute> dependencyAttributeOptional = extractDependency(
- containerSchemaNode, attrNode, currentModule, qNamesToSIEs,
- schemaContext);
- if (dependencyAttributeOptional.isPresent()) {
- return dependencyAttributeOptional.get();
- } else {
- return TOAttribute.create(containerSchemaNode,
- typeProviderWrapper, packageName);
- }
-
- } else if (attrNode instanceof LeafListSchemaNode) {
- return ListAttribute.create((LeafListSchemaNode) attrNode,
- typeProviderWrapper);
- } else if (attrNode instanceof ListSchemaNode) {
- ListSchemaNode listSchemaNode = (ListSchemaNode) attrNode;
- Optional<? extends AbstractDependencyAttribute> dependencyAttributeOptional = extractDependency(
- listSchemaNode, attrNode, currentModule, qNamesToSIEs,
- schemaContext);
- if (dependencyAttributeOptional.isPresent()) {
- return dependencyAttributeOptional.get();
- } else {
- return ListAttribute.create(listSchemaNode,
- typeProviderWrapper, packageName);
- }
- } else {
- throw new UnsupportedOperationException(
- "Unknown configuration node " + attrNode.toString());
+ public ModuleMXBeanEntryInitialBuilder setJavaNamePrefix(String javaNamePrefix) {
+ this.javaNamePrefix = javaNamePrefix;
+ return this;
}
- }
- private static Optional<? extends AbstractDependencyAttribute> extractDependency(
- DataNodeContainer dataNodeContainer, DataSchemaNode attrNode,
- Module currentModule,
- Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
- SchemaContext schemaContext) {
- if (dataNodeContainer.getUses().size() == 1
- && getChildNodeSizeWithoutUses(dataNodeContainer) == 0) {
- // reference
- UsesNode usesNode = dataNodeContainer.getUses().iterator().next();
- checkState(usesNode.getRefines().size() == 1,
- "Unexpected 'refine' child node size of "
- + dataNodeContainer);
- LeafSchemaNode refine = (LeafSchemaNode) usesNode.getRefines()
- .values().iterator().next();
- checkState(refine.getUnknownSchemaNodes().size() == 1,
- "Unexpected unknown schema node size of " + refine);
- UnknownSchemaNode requiredIdentity = refine.getUnknownSchemaNodes()
- .iterator().next();
- checkState(
- ConfigConstants.REQUIRED_IDENTITY_EXTENSION_QNAME.equals(requiredIdentity
- .getNodeType()), "Unexpected language extension "
- + requiredIdentity);
- String prefixAndIdentityLocalName = requiredIdentity
- .getNodeParameter();
- // import should point to a module
- ServiceInterfaceEntry serviceInterfaceEntry = findSIE(
- prefixAndIdentityLocalName, currentModule, qNamesToSIEs,
- schemaContext);
- boolean mandatory = refine.getConstraints().isMandatory();
- AbstractDependencyAttribute reference;
- if (dataNodeContainer instanceof ContainerSchemaNode) {
- reference = new DependencyAttribute(attrNode,
- serviceInterfaceEntry, mandatory,
- attrNode.getDescription());
- } else {
- reference = new ListDependenciesAttribute(attrNode,
- serviceInterfaceEntry, mandatory,
- attrNode.getDescription());
- }
- return Optional.of(reference);
+ public ModuleMXBeanEntryInitialBuilder setNamespace(String namespace) {
+ this.namespace = namespace;
+ return this;
}
- return Optional.absent();
- }
- private static ServiceInterfaceEntry findSIE(
- String prefixAndIdentityLocalName, Module currentModule,
- Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
- SchemaContext schemaContext) {
-
- Matcher m = PREFIX_COLON_LOCAL_NAME.matcher(prefixAndIdentityLocalName);
- Module foundModule;
- String localSIName;
- if (m.matches()) {
- // if there is a prefix, look for ModuleImport with this prefix. Get
- // Module from SchemaContext
- String prefix = m.group(1);
- ModuleImport moduleImport = findModuleImport(currentModule, prefix);
- foundModule = schemaContext.findModuleByName(
- moduleImport.getModuleName(), moduleImport.getRevision());
- checkState(
- foundModule != null,
- format("Module not found in SchemaContext by %s",
- moduleImport));
- localSIName = m.group(2);
- } else {
- foundModule = currentModule; // no prefix => SIE is in currentModule
- localSIName = prefixAndIdentityLocalName;
+ public ModuleMXBeanEntryInitialBuilder setqName(QName qName) {
+ this.qName = qName;
+ return this;
}
- QName siQName = new QName(foundModule.getNamespace(),
- foundModule.getRevision(), localSIName);
- ServiceInterfaceEntry sie = qNamesToSIEs.get(siQName);
- checkState(sie != null, "Cannot find referenced Service Interface by "
- + prefixAndIdentityLocalName);
- return sie;
- }
- private static ModuleImport findModuleImport(Module module, String prefix) {
- for (ModuleImport moduleImport : module.getImports()) {
- if (moduleImport.getPrefix().equals(prefix)) {
- return moduleImport;
- }
+ public ModuleMXBeanEntry.ModuleMXBeanEntryInitial build() {
+ return new ModuleMXBeanEntry.ModuleMXBeanEntryInitial(localName, description, packageName, javaNamePrefix, namespace, qName);
}
- throw new IllegalStateException(format(
- "Import not found with prefix %s in %s", prefix, module));
- }
- public Map<String, AttributeIfc> getAttributes() {
- return yangToAttributes;
- }
-
- private void setYangToAttributes(Map<String, AttributeIfc> newAttributes) {
- this.yangToAttributes = newAttributes;
-
- }
-
- public String getNullableDescription() {
- return nullableDescription;
- }
-
- public QName getYangModuleQName() {
- return yangModuleQName;
- }
+ public ModuleMXBeanEntryInitialBuilder setIdSchemaNode(IdentitySchemaNode idSchemaNode) {
+ this.localName = idSchemaNode.getQName().getLocalName();
+ this.description = idSchemaNode.getDescription();
+ return this;
+ }
- @Override
- public String toString() {
- return "ModuleMXBeanEntry{" + "globallyUniqueName='"
- + globallyUniqueName + '\'' + ", packageName='" + packageName
- + '\'' + '}';
}
}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.config.yangjmxgenerator;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.AbstractDependencyAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.DependencyAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.util.NameConflictException;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.ModuleImport;
+import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.UsesNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.annotation.Nullable;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static com.google.common.base.Preconditions.checkState;
+import static java.lang.String.format;
+import static org.opendaylight.controller.config.yangjmxgenerator.ConfigConstants.createConfigQName;
+
+final class ModuleMXBeanEntryBuilder {
+
+ private Module currentModule;
+ private Map<QName, ServiceInterfaceEntry> qNamesToSIEs;
+ private SchemaContext schemaContext;
+ private TypeProviderWrapper typeProviderWrapper;
+ private String packageName;
+
+ public ModuleMXBeanEntryBuilder setModule(Module module) {
+ this.currentModule = module;
+ return this;
+ }
+
+ public ModuleMXBeanEntryBuilder setqNamesToSIEs(Map<QName, ServiceInterfaceEntry> qNamesToSIEs) {
+ this.qNamesToSIEs = qNamesToSIEs;
+ return this;
+ }
+
+ public ModuleMXBeanEntryBuilder setSchemaContext(SchemaContext schemaContext) {
+ this.schemaContext = schemaContext;
+ return this;
+ }
+
+ public ModuleMXBeanEntryBuilder setTypeProviderWrapper(TypeProviderWrapper typeProviderWrapper) {
+ this.typeProviderWrapper = typeProviderWrapper;
+ return this;
+ }
+
+ public ModuleMXBeanEntryBuilder setPackageName(String packageName) {
+ this.packageName = packageName;
+ return this;
+ }
+
+ private static final Logger logger = LoggerFactory
+ .getLogger(ModuleMXBeanEntryBuilder.class);
+
+ // TODO: the XPath should be parsed by code generator IMO
+ private static final String MAGIC_STRING = "MAGIC_STRING";
+ private static final String MODULE_CONDITION_XPATH_TEMPLATE = "^/MAGIC_STRING:modules/MAGIC_STRING:module/MAGIC_STRING:type\\s*=\\s*['\"](.+)['\"]$";
+ private static final SchemaPath expectedConfigurationAugmentationSchemaPath = new SchemaPath(
+ Arrays.asList(createConfigQName("modules"),
+ createConfigQName("module"),
+ createConfigQName("configuration")), true);
+ private static final SchemaPath expectedStateAugmentationSchemaPath = new SchemaPath(
+ Arrays.asList(createConfigQName("modules"),
+ createConfigQName("module"), createConfigQName("state")),
+ true);
+ private static final Pattern PREFIX_COLON_LOCAL_NAME = Pattern
+ .compile("^(.+):(.+)$");
+
+
+ public Map<String, ModuleMXBeanEntry> build() {
+ logger.debug("Generating ModuleMXBeans of {} to package {}",
+ currentModule.getNamespace(), packageName);
+
+ String configModulePrefix;
+ try {
+ configModulePrefix = getConfigModulePrefixFromImport(currentModule);
+ } catch (IllegalArgumentException e) {
+ // this currentModule does not import config currentModule
+ return Collections.emptyMap();
+ }
+
+ // get identities of base config:currentModule-type
+ Map<String, IdentitySchemaNode> moduleIdentities = getIdentityMap();
+
+ Map<String, QName> uniqueGeneratedClassesNames = new HashMap<>();
+
+ // each currentModule name should have an augmentation defined
+ Map<String, IdentitySchemaNode> unaugmentedModuleIdentities = new HashMap<>(
+ moduleIdentities);
+
+ Map<String, ModuleMXBeanEntry> result = new HashMap<>();
+
+ for (AugmentationSchema augmentation : currentModule.getAugmentations()) {
+ Set<DataSchemaNode> childNodes = augmentation.getChildNodes();
+ if (areAllChildrenChoiceCaseNodes(childNodes)) {
+ for (ChoiceCaseNode childCase : castChildNodesToChoiceCases(childNodes)) {
+ // TODO refactor, extract to standalone builder class
+ processChoiceCaseNode(result, uniqueGeneratedClassesNames, configModulePrefix, moduleIdentities,
+ unaugmentedModuleIdentities, augmentation, childCase);
+ }
+ } // skip if child nodes are not all cases
+ }
+ // clean up nulls
+ cleanUpNulls(result);
+ // check attributes name uniqueness
+ checkAttributeNamesUniqueness(uniqueGeneratedClassesNames, result);
+ checkUnaugumentedIdentities(unaugmentedModuleIdentities);
+
+ logger.debug("Number of ModuleMXBeans to be generated: {}", result.size());
+
+ return result;
+ }
+
+ private static void cleanUpNulls(Map<String, ModuleMXBeanEntry> result) {
+ for (Map.Entry<String, ModuleMXBeanEntry> entry : result.entrySet()) {
+ ModuleMXBeanEntry module = entry.getValue();
+ if (module.getAttributes() == null) {
+ module.setYangToAttributes(Collections
+ .<String, AttributeIfc> emptyMap());
+ } else if (module.getRuntimeBeans() == null) {
+ module.setRuntimeBeans(Collections
+ .<RuntimeBeanEntry> emptyList());
+ }
+ }
+ }
+
+ private static void checkUnaugumentedIdentities(Map<String, IdentitySchemaNode> unaugmentedModuleIdentities) {
+ if (unaugmentedModuleIdentities.size() > 0) {
+ logger.warn("Augmentation not found for all currentModule identities: {}",
+ unaugmentedModuleIdentities.keySet());
+ }
+ }
+
+ private static void checkAttributeNamesUniqueness(Map<String, QName> uniqueGeneratedClassesNames, Map<String, ModuleMXBeanEntry> result) {
+ for (Map.Entry<String, ModuleMXBeanEntry> entry : result.entrySet()) {
+ checkUniqueRuntimeBeanAttributesName(entry.getValue(),
+ uniqueGeneratedClassesNames);
+ }
+ }
+
+ private Map<String, IdentitySchemaNode> getIdentityMap() {
+ Map<String, IdentitySchemaNode> moduleIdentities = Maps.newHashMap();
+
+ for (IdentitySchemaNode id : currentModule.getIdentities()) {
+ if (id.getBaseIdentity() != null
+ && ConfigConstants.MODULE_TYPE_Q_NAME.equals(id.getBaseIdentity().getQName())) {
+ String identityLocalName = id.getQName().getLocalName();
+ if (moduleIdentities.containsKey(identityLocalName)) {
+ throw new IllegalStateException("Module name already defined in this currentModule: "
+ + identityLocalName);
+ } else {
+ moduleIdentities.put(identityLocalName, id);
+ logger.debug("Found identity {}", identityLocalName);
+ }
+ // validation check on unknown schema nodes
+ boolean providedServiceWasSet = false;
+ for (UnknownSchemaNode unknownNode : id.getUnknownSchemaNodes()) {
+ // TODO: test this
+ if (ConfigConstants.PROVIDED_SERVICE_EXTENSION_QNAME.equals(unknownNode.getNodeType())) {
+ // no op: 0 or more provided identities are allowed
+ } else if (ConfigConstants.JAVA_NAME_PREFIX_EXTENSION_QNAME.equals(unknownNode.getNodeType())) {
+ // 0..1 allowed
+ checkState(
+ providedServiceWasSet == false,
+ format("More than one language extension %s is not allowed here: %s",
+ ConfigConstants.JAVA_NAME_PREFIX_EXTENSION_QNAME, id));
+ providedServiceWasSet = true;
+ } else {
+ throw new IllegalStateException("Unexpected language extension " + unknownNode.getNodeType());
+ }
+ }
+ }
+ }
+
+ return moduleIdentities;
+ }
+
+ private Collection<ChoiceCaseNode> castChildNodesToChoiceCases(Set<DataSchemaNode> childNodes) {
+ return Collections2.transform(childNodes, new Function<DataSchemaNode, ChoiceCaseNode>() {
+ @Nullable
+ @Override
+ public ChoiceCaseNode apply(@Nullable DataSchemaNode input) {
+ return (ChoiceCaseNode) input;
+ }
+ });
+ }
+
+ private boolean areAllChildrenChoiceCaseNodes(Set<DataSchemaNode> childNodes) {
+ for (DataSchemaNode childNode : childNodes) {
+ if (childNode instanceof ChoiceCaseNode == false)
+ return false;
+ }
+ return true;
+ }
+
+ private void processChoiceCaseNode(Map<String, ModuleMXBeanEntry> result,
+ Map<String, QName> uniqueGeneratedClassesNames, String configModulePrefix,
+ Map<String, IdentitySchemaNode> moduleIdentities,
+ Map<String, IdentitySchemaNode> unaugmentedModuleIdentities, AugmentationSchema augmentation,
+ DataSchemaNode when) {
+
+ ChoiceCaseNode choiceCaseNode = (ChoiceCaseNode) when;
+ if (choiceCaseNode.getConstraints() == null || choiceCaseNode.getConstraints().getWhenCondition() == null) {
+ return;
+ }
+ RevisionAwareXPath xPath = choiceCaseNode.getConstraints().getWhenCondition();
+ Matcher matcher = getWhenConditionMatcher(configModulePrefix, xPath);
+ if (matcher.matches() == false) {
+ return;
+ }
+ String moduleLocalNameFromXPath = matcher.group(1);
+ IdentitySchemaNode moduleIdentity = moduleIdentities.get(moduleLocalNameFromXPath);
+ unaugmentedModuleIdentities.remove(moduleLocalNameFromXPath);
+ checkState(moduleIdentity != null, "Cannot find identity " + moduleLocalNameFromXPath
+ + " matching augmentation " + augmentation);
+ Map<String, QName> providedServices = findProvidedServices(moduleIdentity, currentModule, qNamesToSIEs,
+ schemaContext);
+
+ if (moduleIdentity == null) {
+ throw new IllegalStateException("Cannot find identity specified by augmentation xpath constraint: "
+ + moduleLocalNameFromXPath + " of " + augmentation);
+ }
+ String javaNamePrefix = TypeProviderWrapper.findJavaNamePrefix(moduleIdentity);
+
+ Map<String, AttributeIfc> yangToAttributes = null;
+ // runtime-data
+ Collection<RuntimeBeanEntry> runtimeBeans = null;
+
+ if (expectedConfigurationAugmentationSchemaPath.equals(augmentation.getTargetPath())) {
+ logger.debug("Parsing configuration of {}", moduleLocalNameFromXPath);
+ yangToAttributes = fillConfiguration(choiceCaseNode, currentModule, typeProviderWrapper, qNamesToSIEs,
+ schemaContext, packageName);
+ checkUniqueAttributesWithGeneratedClass(uniqueGeneratedClassesNames, when.getQName(), yangToAttributes);
+ } else if (expectedStateAugmentationSchemaPath.equals(augmentation.getTargetPath())) {
+ logger.debug("Parsing state of {}", moduleLocalNameFromXPath);
+ try {
+ runtimeBeans = fillRuntimeBeans(choiceCaseNode, currentModule, typeProviderWrapper, packageName,
+ moduleLocalNameFromXPath, javaNamePrefix);
+ } catch (NameConflictException e) {
+ throw new NameConflictException(e.getConflictingName(), when.getQName(), when.getQName());
+ }
+ checkUniqueRuntimeBeansGeneratedClasses(uniqueGeneratedClassesNames, when, runtimeBeans);
+ Set<RuntimeBeanEntry> runtimeBeanEntryValues = Sets.newHashSet(runtimeBeans);
+ for (RuntimeBeanEntry entry : runtimeBeanEntryValues) {
+ checkUniqueAttributesWithGeneratedClass(uniqueGeneratedClassesNames, when.getQName(),
+ entry.getYangPropertiesToTypesMap());
+ }
+
+ } else {
+ throw new IllegalArgumentException("Cannot parse augmentation " + augmentation);
+ }
+ if (result.containsKey(moduleLocalNameFromXPath)) {
+ // either fill runtimeBeans or yangToAttributes
+ ModuleMXBeanEntry moduleMXBeanEntry = result.get(moduleLocalNameFromXPath);
+ if (yangToAttributes != null && moduleMXBeanEntry.getAttributes() == null) {
+ moduleMXBeanEntry.setYangToAttributes(yangToAttributes);
+ } else if (runtimeBeans != null && moduleMXBeanEntry.getRuntimeBeans() == null) {
+ moduleMXBeanEntry.setRuntimeBeans(runtimeBeans);
+ }
+ } else {
+ ModuleMXBeanEntry.ModuleMXBeanEntryInitial initial = new ModuleMXBeanEntry.ModuleMXBeanEntryInitialBuilder()
+ .setIdSchemaNode(moduleIdentity).setPackageName(packageName).setJavaNamePrefix(javaNamePrefix)
+ .setNamespace(currentModule.getNamespace().toString()).setqName(ModuleUtil.getQName(currentModule))
+ .build();
+
+ // construct ModuleMXBeanEntry
+ ModuleMXBeanEntry moduleMXBeanEntry = new ModuleMXBeanEntry(initial, yangToAttributes, providedServices,
+ runtimeBeans);
+
+ moduleMXBeanEntry.setYangModuleName(currentModule.getName());
+ moduleMXBeanEntry.setYangModuleLocalname(moduleLocalNameFromXPath);
+ result.put(moduleLocalNameFromXPath, moduleMXBeanEntry);
+ }
+ }
+
+ private void checkUniqueRuntimeBeansGeneratedClasses(Map<String, QName> uniqueGeneratedClassesNames,
+ DataSchemaNode when, Collection<RuntimeBeanEntry> runtimeBeans) {
+ for (RuntimeBeanEntry runtimeBean : runtimeBeans) {
+ final String javaNameOfRuntimeMXBean = runtimeBean.getJavaNameOfRuntimeMXBean();
+ if (uniqueGeneratedClassesNames.containsKey(javaNameOfRuntimeMXBean)) {
+ QName firstDefinedQName = uniqueGeneratedClassesNames.get(javaNameOfRuntimeMXBean);
+ throw new NameConflictException(javaNameOfRuntimeMXBean, firstDefinedQName, when.getQName());
+ }
+ uniqueGeneratedClassesNames.put(javaNameOfRuntimeMXBean, when.getQName());
+ }
+ }
+
+ private static void checkUniqueRuntimeBeanAttributesName(ModuleMXBeanEntry mxBeanEntry,
+ Map<String, QName> uniqueGeneratedClassesNames) {
+ for (RuntimeBeanEntry runtimeBeanEntry : mxBeanEntry.getRuntimeBeans()) {
+ for (String runtimeAttName : runtimeBeanEntry.getYangPropertiesToTypesMap().keySet()) {
+ if (mxBeanEntry.getAttributes().keySet().contains(runtimeAttName)) {
+ QName qName1 = uniqueGeneratedClassesNames.get(runtimeBeanEntry.getJavaNameOfRuntimeMXBean());
+ QName qName2 = uniqueGeneratedClassesNames.get(mxBeanEntry.getGloballyUniqueName());
+ throw new NameConflictException(runtimeAttName, qName1, qName2);
+ }
+ }
+ }
+ }
+
+ private void checkUniqueAttributesWithGeneratedClass(Map<String, QName> uniqueGeneratedClassNames,
+ QName parentQName, Map<String, AttributeIfc> yangToAttributes) {
+ for (Map.Entry<String, AttributeIfc> attr : yangToAttributes.entrySet()) {
+ if (attr.getValue() instanceof TOAttribute) {
+ checkUniqueTOAttr(uniqueGeneratedClassNames, parentQName, (TOAttribute) attr.getValue());
+ } else if (attr.getValue() instanceof ListAttribute
+ && ((ListAttribute) attr.getValue()).getInnerAttribute() instanceof TOAttribute) {
+ checkUniqueTOAttr(uniqueGeneratedClassNames, parentQName,
+ (TOAttribute) ((ListAttribute) attr.getValue()).getInnerAttribute());
+ }
+ }
+ }
+
+ private void checkUniqueTOAttr(Map<String, QName> uniqueGeneratedClassNames, QName parentQName, TOAttribute attr) {
+ final String upperCaseCammelCase = attr.getUpperCaseCammelCase();
+ if (uniqueGeneratedClassNames.containsKey(upperCaseCammelCase)) {
+ QName firstDefinedQName = uniqueGeneratedClassNames.get(upperCaseCammelCase);
+ throw new NameConflictException(upperCaseCammelCase, firstDefinedQName, parentQName);
+ } else {
+ uniqueGeneratedClassNames.put(upperCaseCammelCase, parentQName);
+ }
+ }
+
+ private Collection<RuntimeBeanEntry> fillRuntimeBeans(ChoiceCaseNode choiceCaseNode, Module currentModule,
+ TypeProviderWrapper typeProviderWrapper, String packageName, String moduleLocalNameFromXPath,
+ String javaNamePrefix) {
+
+ return RuntimeBeanEntry.extractClassNameToRuntimeBeanMap(packageName, choiceCaseNode, moduleLocalNameFromXPath,
+ typeProviderWrapper, javaNamePrefix, currentModule).values();
+
+ }
+
+ private Map<String, AttributeIfc> fillConfiguration(ChoiceCaseNode choiceCaseNode, Module currentModule,
+ TypeProviderWrapper typeProviderWrapper, Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
+ SchemaContext schemaContext, String packageName) {
+ Map<String, AttributeIfc> yangToAttributes = new HashMap<>();
+ for (DataSchemaNode attrNode : choiceCaseNode.getChildNodes()) {
+ AttributeIfc attributeValue = getAttributeValue(attrNode, currentModule, qNamesToSIEs, typeProviderWrapper,
+ schemaContext, packageName);
+ yangToAttributes.put(attributeValue.getAttributeYangName(), attributeValue);
+ }
+ return yangToAttributes;
+ }
+
+ private Map<String, QName> findProvidedServices(IdentitySchemaNode moduleIdentity, Module currentModule,
+ Map<QName, ServiceInterfaceEntry> qNamesToSIEs, SchemaContext schemaContext) {
+ Map<String, QName> result = new HashMap<>();
+ for (UnknownSchemaNode unknownNode : moduleIdentity.getUnknownSchemaNodes()) {
+ if (ConfigConstants.PROVIDED_SERVICE_EXTENSION_QNAME.equals(unknownNode.getNodeType())) {
+ String prefixAndIdentityLocalName = unknownNode.getNodeParameter();
+ ServiceInterfaceEntry sie = findSIE(prefixAndIdentityLocalName, currentModule, qNamesToSIEs,
+ schemaContext);
+ result.put(sie.getFullyQualifiedName(), sie.getQName());
+ }
+ }
+ return result;
+ }
+
+ private AttributeIfc getAttributeValue(DataSchemaNode attrNode, Module currentModule,
+ Map<QName, ServiceInterfaceEntry> qNamesToSIEs, TypeProviderWrapper typeProviderWrapper,
+ SchemaContext schemaContext, String packageName) {
+
+ if (attrNode instanceof LeafSchemaNode) {
+ // simple type
+ LeafSchemaNode leaf = (LeafSchemaNode) attrNode;
+ return new JavaAttribute(leaf, typeProviderWrapper);
+ } else if (attrNode instanceof ContainerSchemaNode) {
+ // reference or TO
+ ContainerSchemaNode containerSchemaNode = (ContainerSchemaNode) attrNode;
+ Optional<? extends AbstractDependencyAttribute> dependencyAttributeOptional = extractDependency(
+ containerSchemaNode, attrNode, currentModule, qNamesToSIEs, schemaContext);
+ if (dependencyAttributeOptional.isPresent()) {
+ return dependencyAttributeOptional.get();
+ } else {
+ return TOAttribute.create(containerSchemaNode, typeProviderWrapper, packageName);
+ }
+
+ } else if (attrNode instanceof LeafListSchemaNode) {
+ return ListAttribute.create((LeafListSchemaNode) attrNode, typeProviderWrapper);
+ } else if (attrNode instanceof ListSchemaNode) {
+ ListSchemaNode listSchemaNode = (ListSchemaNode) attrNode;
+ Optional<? extends AbstractDependencyAttribute> dependencyAttributeOptional = extractDependency(
+ listSchemaNode, attrNode, currentModule, qNamesToSIEs, schemaContext);
+ if (dependencyAttributeOptional.isPresent()) {
+ return dependencyAttributeOptional.get();
+ } else {
+ return ListAttribute.create(listSchemaNode, typeProviderWrapper, packageName);
+ }
+ } else {
+ throw new UnsupportedOperationException("Unknown configuration node " + attrNode.toString());
+ }
+ }
+
+ private Optional<? extends AbstractDependencyAttribute> extractDependency(DataNodeContainer dataNodeContainer,
+ DataSchemaNode attrNode, Module currentModule, Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
+ SchemaContext schemaContext) {
+ if (dataNodeContainer.getUses().size() == 1 && getChildNodeSizeWithoutUses(dataNodeContainer) == 0) {
+ // reference
+ UsesNode usesNode = dataNodeContainer.getUses().iterator().next();
+ checkState(usesNode.getRefines().size() == 1, "Unexpected 'refine' child node size of " + dataNodeContainer);
+ LeafSchemaNode refine = (LeafSchemaNode) usesNode.getRefines().values().iterator().next();
+ checkState(refine.getUnknownSchemaNodes().size() == 1, "Unexpected unknown schema node size of " + refine);
+ UnknownSchemaNode requiredIdentity = refine.getUnknownSchemaNodes().iterator().next();
+ checkState(ConfigConstants.REQUIRED_IDENTITY_EXTENSION_QNAME.equals(requiredIdentity.getNodeType()),
+ "Unexpected language extension " + requiredIdentity);
+ String prefixAndIdentityLocalName = requiredIdentity.getNodeParameter();
+ // import should point to a module
+ ServiceInterfaceEntry serviceInterfaceEntry = findSIE(prefixAndIdentityLocalName, currentModule,
+ qNamesToSIEs, schemaContext);
+ boolean mandatory = refine.getConstraints().isMandatory();
+ AbstractDependencyAttribute reference;
+ if (dataNodeContainer instanceof ContainerSchemaNode) {
+ reference = new DependencyAttribute(attrNode, serviceInterfaceEntry, mandatory,
+ attrNode.getDescription());
+ } else {
+ reference = new ListDependenciesAttribute(attrNode, serviceInterfaceEntry, mandatory,
+ attrNode.getDescription());
+ }
+ return Optional.of(reference);
+ }
+ return Optional.absent();
+ }
+
+ private int getChildNodeSizeWithoutUses(DataNodeContainer csn) {
+ int result = 0;
+ for (DataSchemaNode dsn : csn.getChildNodes()) {
+ if (dsn.isAddedByUses() == false) {
+ result++;
+ }
+ }
+ return result;
+ }
+
+ private ServiceInterfaceEntry findSIE(String prefixAndIdentityLocalName, Module currentModule,
+ Map<QName, ServiceInterfaceEntry> qNamesToSIEs, SchemaContext schemaContext) {
+
+ Matcher m = PREFIX_COLON_LOCAL_NAME.matcher(prefixAndIdentityLocalName);
+ Module foundModule;
+ String localSIName;
+ if (m.matches()) {
+ // if there is a prefix, look for ModuleImport with this prefix. Get
+ // Module from SchemaContext
+ String prefix = m.group(1);
+ ModuleImport moduleImport = findModuleImport(currentModule, prefix);
+ foundModule = schemaContext.findModuleByName(moduleImport.getModuleName(), moduleImport.getRevision());
+ checkState(foundModule != null, format("Module not found in SchemaContext by %s", moduleImport));
+ localSIName = m.group(2);
+ } else {
+ foundModule = currentModule; // no prefix => SIE is in currentModule
+ localSIName = prefixAndIdentityLocalName;
+ }
+ QName siQName = new QName(foundModule.getNamespace(), foundModule.getRevision(), localSIName);
+ ServiceInterfaceEntry sie = qNamesToSIEs.get(siQName);
+ checkState(sie != null, "Cannot find referenced Service Interface by " + prefixAndIdentityLocalName);
+ return sie;
+ }
+
+ private ModuleImport findModuleImport(Module module, String prefix) {
+ for (ModuleImport moduleImport : module.getImports()) {
+ if (moduleImport.getPrefix().equals(prefix)) {
+ return moduleImport;
+ }
+ }
+ throw new IllegalStateException(format("Import not found with prefix %s in %s", prefix, module));
+ }
+
+ @VisibleForTesting
+ static Matcher getWhenConditionMatcher(String prefix, RevisionAwareXPath whenConstraint) {
+ String xpathRegex = MODULE_CONDITION_XPATH_TEMPLATE.replace(MAGIC_STRING, prefix);
+ Pattern pattern = Pattern.compile(xpathRegex);
+ return pattern.matcher(whenConstraint.toString());
+ }
+
+ String getConfigModulePrefixFromImport(Module currentModule) {
+ for (ModuleImport currentImport : currentModule.getImports()) {
+ if (currentImport.getModuleName().equals(ConfigConstants.CONFIG_MODULE)) {
+ return currentImport.getPrefix();
+ }
+ }
+ throw new IllegalArgumentException("Cannot find import " + ConfigConstants.CONFIG_MODULE + " in "
+ + currentModule);
+ }
+
+}
}
// convert RpcDefinition to Rpc
for (RpcDefinition rpcDefinition : rpcDefinitions) {
- String name = ModuleMXBeanEntry
+ String name = TypeProviderWrapper
.findJavaParameter(rpcDefinition);
AttributeIfc returnType;
if (rpcDefinition.getOutput() == null
"More than one key is not supported in " + listSchemaNode);
}
- String javaNamePrefix = ModuleMXBeanEntry
+ String javaNamePrefix = TypeProviderWrapper
.findJavaNamePrefix(listSchemaNode);
RuntimeBeanEntry rbFromAttributes = new RuntimeBeanEntry(packageName,
*/
package org.opendaylight.controller.config.yangjmxgenerator;
+import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil;
import org.opendaylight.yangtools.sal.binding.generator.spi.TypeProvider;
import org.opendaylight.yangtools.sal.binding.model.api.Type;
import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
import org.opendaylight.yangtools.yang.model.api.SchemaNode;
import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
public class TypeProviderWrapper {
private final TypeProvider typeProvider;
this.typeProvider = typeProvider;
}
+ /**
+ * For input node, find if it contains config:java-name-prefix extension. If
+ * not found, convert local name of node converted to cammel case.
+ */
+ public static String findJavaNamePrefix(SchemaNode schemaNode) {
+ return convertToJavaName(schemaNode, true);
+ }
+
+ public static String findJavaParameter(SchemaNode schemaNode) {
+ return convertToJavaName(schemaNode, false);
+ }
+
+ public static String convertToJavaName(SchemaNode schemaNode,
+ boolean capitalizeFirstLetter) {
+ for (UnknownSchemaNode unknownNode : schemaNode.getUnknownSchemaNodes()) {
+ if (ConfigConstants.JAVA_NAME_PREFIX_EXTENSION_QNAME
+ .equals(unknownNode.getNodeType())) {
+ String value = unknownNode.getNodeParameter();
+ return convertToJavaName(value, capitalizeFirstLetter);
+ }
+ }
+ return convertToJavaName(schemaNode.getQName().getLocalName(),
+ capitalizeFirstLetter);
+ }
+
+ public static String convertToJavaName(String localName,
+ boolean capitalizeFirstLetter) {
+ if (capitalizeFirstLetter) {
+ return BindingGeneratorUtil.parseToClassName(localName);
+ } else {
+ return BindingGeneratorUtil.parseToValidParamName(localName);
+ }
+ }
+
public Type getType(LeafSchemaNode leaf) {
TypeDefinition<?> type = leaf.getType();
return getType(leaf, type);
*/
package org.opendaylight.controller.config.yangjmxgenerator.attribute;
-import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
+import org.opendaylight.controller.config.yangjmxgenerator.TypeProviderWrapper;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
public abstract class AbstractAttribute implements AttributeIfc {
AbstractAttribute(DataSchemaNode attrNode) {
this.attributeYangName = getLocalName(attrNode);
this.node = attrNode;
- this.upperCaseCammelCase = ModuleMXBeanEntry.findJavaNamePrefix(node);
- this.lowerCaseCammelCase = ModuleMXBeanEntry.findJavaParameter(node);
+ this.upperCaseCammelCase = TypeProviderWrapper.findJavaNamePrefix(node);
+ this.lowerCaseCammelCase = TypeProviderWrapper.findJavaParameter(node);
}
@Override
import com.google.common.collect.Collections2;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
-import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
import org.opendaylight.controller.config.yangjmxgenerator.TypeProviderWrapper;
import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl;
import org.opendaylight.yangtools.sal.binding.model.api.Type;
.entrySet()) {
capitalizedPropertiesToTypesMap.put(
- ModuleMXBeanEntry.convertToJavaName(entry.getKey(), true),
+ TypeProviderWrapper.convertToJavaName(entry.getKey(), true),
entry.getValue());
}
return capitalizedPropertiesToTypesMap;
.entrySet()) {
jmxPropertiesToTypesMap.put(
- ModuleMXBeanEntry.convertToJavaName(entry.getKey(), false),
+ TypeProviderWrapper.convertToJavaName(entry.getKey(), false),
entry.getValue());
}
return jmxPropertiesToTypesMap;
, PACKAGE_NAME);
Map<String, AttributeIfc> attributes = namesToMBEs.get("impl-netconf")
.getAttributes();
+
+ assertCorrectAttributesSize(namesToMBEs, attributes);
+
//
DependencyAttribute threadFactoryAttribute = (DependencyAttribute) attributes
.get("thread-factory");
assertThat(threadFactoryAttribute.getType().getName(), is("ObjectName"));
}
+ private void assertCorrectAttributesSize(Map<String, ModuleMXBeanEntry> namesToMBEs, Map<String, AttributeIfc> attributes) {
+ assertEquals(14, attributes.size());
+ assertEquals(1, namesToMBEs.get("impl-netconf").getRuntimeBeans().size());
+ assertEquals(2, namesToMBEs.get("impl-netconf").getRuntimeBeans().iterator().next().getAttributes().size());
+
+ assertEquals(4, namesToMBEs.get("impl").getAttributes().size());
+ assertEquals(1, namesToMBEs.get("impl").getRuntimeBeans().size());
+ assertEquals(1, namesToMBEs.get("impl").getRuntimeBeans().iterator().next().getAttributes().size());
+ }
+
protected RuntimeBeanEntry findFirstByYangName(
Collection<RuntimeBeanEntry> runtimeBeans, String yangName) {
for (RuntimeBeanEntry rb : runtimeBeans) {
private void assertMatches(String prefix, String input) {
RevisionAwareXPath whenConstraint = mock(RevisionAwareXPath.class);
doReturn(input).when(whenConstraint).toString();
- Matcher output = ModuleMXBeanEntry.getWhenConditionMatcher(prefix,
+ Matcher output = ModuleMXBeanEntryBuilder.getWhenConditionMatcher(prefix,
whenConstraint);
assertTrue(output.matches());
assertEquals("threadpool-dynamic", output.group(1));
import ietf-inet-types { prefix inet; revision-date 2010-09-24;}
import config-threads { prefix th; revision-date 2013-04-09; }
-
-
description
"Testing IMPL";
}
}
- }
-
- augment "/config:modules/config:module/config:state" {
- case impl {
- when "/config:modules/config:module/config:type = 'impl'";
- // root runtime bean
- leaf created-sessions {
- type uint32;
- }
- }
- }
- augment "/config:modules/config:module/config:configuration" {
case impl-netconf {
when "/config:modules/config:module/config:type = 'impl-netconf'";
}
augment "/config:modules/config:module/config:state" {
+ case impl {
+ when "/config:modules/config:module/config:type = 'impl'";
+ // root runtime bean
+ leaf created-sessions {
+ type uint32;
+ }
+ }
+
case impl-netconf {
when "/config:modules/config:module/config:type = 'impl-netconf'";
// root runtime bean
type uint32;
}
+ leaf created-sessions-2 {
+ type uint32;
+ }
+
}
}
+
}
<plugin>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-maven-plugin</artifactId>
- <version>${yangtools.version}</version>
<executions>
<execution>
<id>config</id>
* Container configuration service
*/
public interface IConfigurationContainerService extends IConfigurationServiceCommon {
+
+ /**
+ * Bundle will call this function to ask ContainerConfigurationService to provide the
+ * directory location of container
+ *
+ * @return The path to active container directory
+ */
+ String getConfigurationRoot();
}
package org.opendaylight.controller.configuration.internal;
+import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import org.opendaylight.controller.configuration.ConfigurationEvent;
import org.opendaylight.controller.configuration.ConfigurationObject;
import org.opendaylight.controller.configuration.IConfigurationAware;
+import org.opendaylight.controller.configuration.IConfigurationContainerService;
import org.opendaylight.controller.configuration.IConfigurationService;
import org.opendaylight.controller.sal.utils.GlobalConstants;
import org.opendaylight.controller.sal.utils.IObjectReader;
private static final Logger logger = LoggerFactory
.getLogger(ConfigurationService.class);
public static final String SAVE_EVENT_CACHE = "config.event.save";
- private static final Object ROOT = GlobalConstants.STARTUPHOME.toString();
+ private static final String ROOT = GlobalConstants.STARTUPHOME.toString();
private IClusterGlobalServices clusterServices;
private ConcurrentMap <ConfigurationEvent, String> configEvent;
private Set<IConfigurationAware> configurationAwareList = Collections
return saveConfigurationsInternal();
}
+
+ private List<String> getContainerDirectoryList() {
+ List<String> containerList = new ArrayList<String>();
+ for (IConfigurationAware configurationAware : this.configurationAwareList) {
+ if (configurationAware instanceof IConfigurationContainerService) {
+ String containerFilePath = ((ContainerConfigurationService)configurationAware).getConfigurationRoot();
+ containerList.add(containerFilePath);
+ }
+ }
+ return containerList;
+ }
+
+ private void createContainerDirectory(IConfigurationAware configurationAware) {
+ String containerFilePath = ((ContainerConfigurationService) configurationAware).getConfigurationRoot();
+ if (!new File(containerFilePath).exists()) {
+ boolean created = new File(containerFilePath).mkdir();
+ if (!created) {
+ logger.error("Failed to create startup config directory: {}", containerFilePath);
+ }
+ }
+ }
+
+ private void clearStaleContainerDirectories() {
+ List<String> activeContainers = getContainerDirectoryList();
+ for (File file : new File(ROOT).listFiles()) {
+ if (file.isDirectory() && !activeContainers.contains(file.toPath() + File.separator)) {
+ logger.trace("Removing directory for container {}", file.getName());
+ for (File innerFile : file.listFiles()) {
+ innerFile.delete();
+ }
+ boolean removed = file.delete();
+ if (!removed) {
+ logger.warn("Failed to remove stale directory: {}", file.getName());
+ }
+ }
+ }
+ }
+
+
private Status saveConfigurationsInternal() {
boolean success = true;
for (IConfigurationAware configurationAware : configurationAwareList) {
+ if (configurationAware instanceof IConfigurationContainerService) {
+ // Create directory for new containers
+ createContainerDirectory(configurationAware);
+ }
Status status = configurationAware.saveConfiguration();
if (!status.isSuccess()) {
success = false;
- logger.warn("Failed to save config for {}",
- configurationAware.getClass().getName());
+ logger.warn("Failed to save config for {}", configurationAware.getClass().getName());
}
}
+ // Remove startup directories of containers that were removed from
+ // the configuration but not saved
+ clearStaleContainerDirectories();
+
if (success) {
return new Status(StatusCode.SUCCESS);
} else {
- return new Status(StatusCode.INTERNALERROR,
- "Failed to Save All Configurations");
+ return new Status(StatusCode.INTERNALERROR, "Failed to Save All Configurations");
}
}
package org.opendaylight.controller.configuration.internal;
-import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Dictionary;
private static final Logger logger = LoggerFactory.getLogger(ContainerConfigurationService.class);
private IClusterContainerServices clusterServices;
private ConcurrentMap <ConfigurationEvent, String> containerConfigEvent;
- /*
- * Collection containing the configuration objects.
- * This is configuration world: container names (also the map key)
- * are maintained as they were configured by user, same case
- */
+ // Directory which contains the startup files for this container
+ private String root;
private Set<IConfigurationContainerAware> configurationAwareList = Collections
.synchronizedSet(new HashSet<IConfigurationContainerAware>());
- private String root;
private ObjectReader objReader;
private ObjectWriter objWriter;
void init(Component c) {
Dictionary<?, ?> props = c.getServiceProperties();
- String containerName = (props != null) ? (String) props.get("containerName") : GlobalConstants.DEFAULT.toString();
- root = String.format("%s%s/", GlobalConstants.STARTUPHOME.toString(), containerName);
- if (!new File(root).exists()) {
- boolean created = new File(root).mkdir();
- if (!created) {
- logger.error("Failed to create startup config directory for container {}", containerName);
- }
- }
+ String containerName = (props != null) ? (String) props.get("containerName") :
+ GlobalConstants.DEFAULT.toString();
+ root = String.format("%s%s/", GlobalConstants.STARTUPHOME.toString(), containerName);
}
public void start() {
* Function called by the dependency manager before Container is Stopped and Destroyed.
*/
public void containerStop() {
- // Remove container directory along with its startup files
- File[] files = new File(root).listFiles();
- for (File file : files) {
- file.delete();
- }
- new File(root).delete();
+ // Do nothing
+ }
+
+ @Override
+ public String getConfigurationRoot() {
+ return root;
}
@Override
public Status saveConfiguration() {
boolean success = true;
+
for (IConfigurationContainerAware configurationAware : configurationAwareList) {
logger.trace("Save Config triggered for {}", configurationAware.getClass().getSimpleName());
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>clustering.services</artifactId>
- <version>0.5.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>connectionmanager</artifactId>
- <version>0.1.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal</artifactId>
- <version>0.7.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal.connection</artifactId>
- <version>0.1.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>equinoxSDK381</groupId>
package org.opendaylight.controller.containermanager.internal;
-import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
return status;
}
- private void removeComponentsStartUpfiles(String containerName) {
- String startupLocation = String.format("./%s", GlobalConstants.STARTUPHOME.toString());
- String containerPrint = String.format("_%s.", containerName.toLowerCase(Locale.ENGLISH));
-
- File directory = new File(startupLocation);
- String[] fileList = directory.list();
-
- logger.trace("Deleting startup configuration files for container {}", containerName);
- if (fileList != null) {
- for (String fileName : fileList) {
- if (fileName.contains(containerPrint)) {
- String fullPath = String.format("%s/%s", startupLocation, fileName);
- File file = new File(fullPath);
- boolean done = file.delete();
- logger.trace("{} {}", (done ? "Deleted: " : "Failed to delete: "), fileName);
- }
- }
- }
- }
-
/**
* Create and initialize default all resource group and create association
* with default well known users and profiles, if not already learnt from
notifyContainerModeChange(delete, notifyLocal);
// Notify listeners
notifyContainerAwareListeners(container, delete);
-
- /*
- * This is a quick fix until configuration service becomes the
- * centralized configuration management place. Here container manager
- * will remove the startup files for all the bundles that are present in
- * the container being deleted. Do the cleanup here in Container manger
- * as do not want to put this temporary code in Configuration manager
- * yet which is ODL.
- */
- if (delete) {
- // TODO: remove when Config Mgr takes over
- removeComponentsStartUpfiles(containerName);
- }
}
private void notifyContainerEntryChangeInternal(String containerName, List<NodeConnector> ncList, UpdateType update, boolean notifyLocal) {
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-util</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-netconf-connector</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-core-api</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-broker-impl</artifactId>
- <version>${mdsal.version}</version>
</dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-remote</artifactId>
- <version>${mdsal.version}</version>
- </dependency>
<dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-restconf-broker</artifactId>
- <version>${mdsal.version}</version>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-remote</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-restconf-broker</artifactId>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-core-spi</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-api</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-impl</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-api</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-config</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-broker-impl</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-compatibility</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-connector-api</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-rest-connector</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-inventory</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-base</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-service</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-statistics</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-management</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.md</groupId>
<artifactId>inventory-manager</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.md</groupId>
<artifactId>forwardingrules-manager</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.md</groupId>
<artifactId>topology-lldp-discovery</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.md</groupId>
<artifactId>topology-manager</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
- <groupId>org.opendaylight.controller.model</groupId>
- <artifactId>model-topology</artifactId>
- <version>1.1-SNAPSHOT</version>
+ <groupId>org.opendaylight.controller.model</groupId>
+ <artifactId>model-topology</artifactId>
+ <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools.model</groupId>
<artifactId>ietf-topology</artifactId>
</dependency>
<dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-binding-util</artifactId>
- <version>1.1-SNAPSHOT</version>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-binding-util</artifactId>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.md</groupId>
<artifactId>statistics-manager</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>concepts</artifactId>
- <version>${concepts.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>concepts</artifactId>
- <version>${yangtools.version}</version>
</dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>restconf-client-api</artifactId>
- <version>${yangtools.version}</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>restconf-client-impl</artifactId>
- <version>${yangtools.version}</version>
- </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>restconf-client-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>restconf-client-impl</artifactId>
+ </dependency>
<!-- config-->
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-api</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-manager</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>yang-jmx-generator</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>yang-store-api</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>yang-store-impl</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>logback-config</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-persister-api</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-persister-file-adapter</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-persister-file-xml-adapter</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-persister-directory-adapter</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-persister-directory-xml-adapter</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-persister-directory-autodetect-adapter</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>shutdown-api</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>shutdown-impl</artifactId>
- <version>${config.version}</version>
</dependency>
<!-- Netconf -->
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netconf-api</artifactId>
- <version>${netconf.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netconf-impl</artifactId>
- <version>${netconf.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netconf-util</artifactId>
- <version>${netconf.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netconf-client</artifactId>
- <version>${netconf.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netconf-mapping-api</artifactId>
- <version>${netconf.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netconf-ssh</artifactId>
- <version>${netconf.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-netconf-connector</artifactId>
- <version>${netconf.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netconf-monitoring</artifactId>
- <version>${netconf.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>ietf-netconf-monitoring</artifactId>
- <version>${netconf.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>ietf-netconf-monitoring-extension</artifactId>
- <version>${netconf.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-persister-impl</artifactId>
- <version>${netconf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.servicemix.bundles</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>threadpool-config-api</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netty-config-api</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>threadpool-config-impl</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netty-threadgroup-config</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netty-event-executor-config</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netty-timer-config</artifactId>
- <version>${config.version}</version>
</dependency>
-
<!-- toaster example I'm pretty sure we should trim -->
<dependency>
<groupId>org.opendaylight.controller.samples</groupId>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-binding</artifactId>
- <version>${yangtools.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-model-util</artifactId>
- <version>${yangtools.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
# Embedded Tomcat configuration File
org.eclipse.gemini.web.tomcat.config.path=configuration/tomcat-server.xml
+org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true
# Open Flow related system parameters
# TCP port on which the controller is listening (default 6633)
</module>
<module>
<type xmlns:netty="urn:opendaylight:params:xml:ns:yang:controller:netty:eventexecutor">netty:netty-global-event-executor</type>
- <name>global-event-executor</name>
+ <name>singleton</name>
</module>
</modules>
<type xmlns:netty="urn:opendaylight:params:xml:ns:yang:controller:netty">netty:netty-event-executor</type>
<instance>
<name>global-event-executor</name>
- <provider>/modules/module[type='netty-global-event-executor'][name='global-event-executor']</provider>
+ <provider>/modules/module[type='netty-global-event-executor'][name='singleton']</provider>
</instance>
</service>
<service>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>configuration</artifactId>
- <version>0.4.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>clustering.services</artifactId>
- <version>0.5.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal</artifactId>
- <version>0.7.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal.connection</artifactId>
- <version>0.1.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>forwardingrulesmanager</artifactId>
- <version>0.5.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>equinoxSDK381</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>connectionmanager</artifactId>
- <version>0.1.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>containermanager</artifactId>
- <version>0.5.2-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-util</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-management</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>forwardingrulesmanager</artifactId>
- <version>0.5.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-compatibility</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
</dependencies>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-util</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>switchmanager</artifactId>
- <version>0.7.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>topologymanager</artifactId>
- <version>0.4.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-management</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-util</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>forwardingrulesmanager</artifactId>
- <version>0.5.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-compatibility</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal</artifactId>
- <version>0.7.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-service</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-util</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-statistics</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-util</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>clustering.services</artifactId>
- <version>0.5.1-SNAPSHOT</version>
</dependency>
</dependencies>
<packaging>bundle</packaging>
topology.dataService = session.getSALService(DataProviderService)
tpProvider.dataService = session.getSALService(DataProviderService)
+ inventory.start();
tpProvider.start();
}
private def Future<RpcResult<TransactionStatus>> internalModifyFlowAsync(Node node, Flow oldFlow, Flow newFlow, long rid) {
- val flowId = getCache().remove(oldFlow);
+ var flowId = getCache().remove(oldFlow);
if(flowId == null){
- throw new IllegalArgumentException("oldFlow is unknown");
+ LOG.error("oldFlow not found in cache : " + oldFlow.hashCode);
+ flowId = UUID.randomUUID();
+ getCache().put(oldFlow, flowId);
}
getCache().put(newFlow, flowId);
private def Future<RpcResult<TransactionStatus>> internalRemoveFlowAsync(Node node, Flow adflow, long rid){
val flowId = getCache().remove(adflow);
if(flowId == null){
- throw new IllegalArgumentException("adflow is unknown");
+ //throw new IllegalArgumentException("adflow not found in cache : " + adflow.hashCode);
+ LOG.error("adflow not found in cache : " + adflow.hashCode);
+ return null;
}
val flow = adflow.toMDFlow(flowId.toString());
val modification = this._dataBrokerService.beginTransaction();
}
private def toFutureStatus(Future<RpcResult<TransactionStatus>> future){
+ if(future == null){
+ return toStatus(true);
+ }
+
try {
val result = future.get();
return toStatus(result);
import java.util.Collections
import java.util.List
import java.util.Set
+import java.util.ArrayList;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.locks.Lock;
import java.util.concurrent.CopyOnWriteArrayList;
import org.opendaylight.controller.sal.binding.api.data.DataBrokerService
import org.opendaylight.controller.sal.binding.api.data.DataProviderService
import org.opendaylight.controller.md.sal.binding.util.TypeSafeDataReader
import java.util.concurrent.ConcurrentHashMap
import java.util.Map
+import java.util.HashMap
class InventoryAndReadAdapter implements IPluginInReadService,
- IPluginInInventoryService,
- OpendaylightInventoryListener,
- OpendaylightFlowStatisticsListener,
- OpendaylightFlowTableStatisticsListener,
- OpendaylightPortStatisticsListener {
+ IPluginInInventoryService,
+ OpendaylightInventoryListener,
+ OpendaylightFlowStatisticsListener,
+ OpendaylightFlowTableStatisticsListener,
+ OpendaylightPortStatisticsListener {
private static val LOG = LoggerFactory.getLogger(InventoryAndReadAdapter);
- private static val OPENFLOWV10_TABLE_ID = new Integer(0).shortValue;
+ private static val OPENFLOWV10_TABLE_ID = new Integer(0).shortValue;
@Property
DataBrokerService dataService;
@Property
List<IPluginOutInventoryService> inventoryPublisher = new CopyOnWriteArrayList<IPluginOutInventoryService>();
- def setInventoryPublisher(IPluginOutInventoryService listener){
+ private final InventoryNotificationProvider inventoryNotificationProvider = new InventoryNotificationProvider();
+
+ private final Map<InstanceIdentifier.PathArgument, List<InstanceIdentifier.PathArgument>> nodeToNodeConnectorsMap = new ConcurrentHashMap<InstanceIdentifier.PathArgument, List<InstanceIdentifier.PathArgument>>();
+
+ private final Lock nodeToNodeConnectorsLock = new ReentrantLock();
+
+
+ def start(){
+ inventoryNotificationProvider.dataProviderService = dataProviderService;
+ inventoryNotificationProvider.inventoryPublisher = inventoryPublisher;
+ // inventoryNotificationProvider.start();
+ }
+
+ def setInventoryPublisher(IPluginOutInventoryService listener){
inventoryPublisher.add(listener);
- }
+ }
- def unsetInventoryPublisher(IPluginOutInventoryService listener){
+ def unsetInventoryPublisher(IPluginOutInventoryService listener){
inventoryPublisher.remove(listener);
- }
+ }
def setReadPublisher(IPluginOutReadService listener) {
- statisticsPublisher.add(listener);
+ statisticsPublisher.add(listener);
}
def unsetReadPublisher (IPluginOutReadService listener) {
- if( listener != null)
- statisticsPublisher.remove(listener);
+ if( listener != null)
+ statisticsPublisher.remove(listener);
}
protected def startChange() {
override readAllFlow(Node node, boolean cached) {
val output = new ArrayList<FlowOnNode>();
- val tableRef = InstanceIdentifier.builder(Nodes)
- .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node))
- .augmentation(FlowCapableNode).child(Table, new TableKey(OPENFLOWV10_TABLE_ID)).toInstance();
-
- val it = this.startChange();
-
- val table= it.readConfigurationData(tableRef) as Table;
-
- if(table != null){
- LOG.trace("Number of flows installed in table 0 of node {} : {}",node,table.flow.size);
-
- for(flow : table.flow){
-
- val adsalFlow = ToSalConversionsUtils.toFlow(flow,node);
- val statsFromDataStore = flow.getAugmentation(FlowStatisticsData);
-
- if(statsFromDataStore != null){
- val it = new FlowOnNode(adsalFlow);
- byteCount = statsFromDataStore.flowStatistics.byteCount.value.longValue;
- packetCount = statsFromDataStore.flowStatistics.packetCount.value.longValue;
- durationSeconds = statsFromDataStore.flowStatistics.duration.second.value.intValue;
- durationNanoseconds = statsFromDataStore.flowStatistics.duration.nanosecond.value.intValue;
-
- output.add(it);
- }
- }
- }
+ val tableRef = InstanceIdentifier.builder(Nodes)
+ .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node))
+ .augmentation(FlowCapableNode).child(Table, new TableKey(OPENFLOWV10_TABLE_ID)).toInstance();
+
+ val it = this.startChange();
+
+ val table= it.readConfigurationData(tableRef) as Table;
+
+ if(table != null){
+ LOG.trace("Number of flows installed in table 0 of node {} : {}",node,table.flow.size);
+
+ for(flow : table.flow){
+
+ val adsalFlow = ToSalConversionsUtils.toFlow(flow,node);
+ val statsFromDataStore = flow.getAugmentation(FlowStatisticsData);
+
+ if(statsFromDataStore != null){
+ val it = new FlowOnNode(adsalFlow);
+ byteCount = statsFromDataStore.flowStatistics.byteCount.value.longValue;
+ packetCount = statsFromDataStore.flowStatistics.packetCount.value.longValue;
+ durationSeconds = statsFromDataStore.flowStatistics.duration.second.value.intValue;
+ durationNanoseconds = statsFromDataStore.flowStatistics.duration.nanosecond.value.intValue;
+
+ output.add(it);
+ }
+ }
+ }
//TODO (main): Shell we send request to the switch? It will make async request to the switch.
// Once plugin receive response, it will let adaptor know through onFlowStatisticsUpdate()
}
override readAllNodeConnector(Node node, boolean cached) {
-
- val ret = new ArrayList<NodeConnectorStatistics>();
- val nodeRef = InstanceIdentifier.builder(Nodes)
- .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node))
- .toInstance();
-
- val provider = this.startChange();
-
- val dsNode= provider.readConfigurationData(nodeRef) as org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
-
- if(dsNode != null){
-
- for (dsNodeConnector : dsNode.nodeConnector){
- val nodeConnectorRef = InstanceIdentifier.builder(Nodes)
- .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node))
- .child(NodeConnector, dsNodeConnector.key)
- .toInstance();
-
- val nodeConnectorFromDS = provider.readConfigurationData(nodeConnectorRef) as NodeConnector;
-
- if(nodeConnectorFromDS != null){
- val nodeConnectorStatsFromDs = nodeConnectorFromDS.getAugmentation(FlowCapableNodeConnectorStatisticsData) as FlowCapableNodeConnectorStatistics;
-
- ret.add(toNodeConnectorStatistics(nodeConnectorStatsFromDs.flowCapableNodeConnectorStatistics,dsNode.id,dsNodeConnector.id));
- }
- }
- }
-
- //TODO: Refer TODO (main)
+
+ val ret = new ArrayList<NodeConnectorStatistics>();
+ val nodeRef = InstanceIdentifier.builder(Nodes)
+ .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node))
+ .toInstance();
+
+ val provider = this.startChange();
+
+ val dsNode= provider.readConfigurationData(nodeRef) as org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+
+ if(dsNode != null){
+
+ for (dsNodeConnector : dsNode.nodeConnector){
+ val nodeConnectorRef = InstanceIdentifier.builder(Nodes)
+ .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node))
+ .child(NodeConnector, dsNodeConnector.key)
+ .toInstance();
+
+ val nodeConnectorFromDS = provider.readConfigurationData(nodeConnectorRef) as NodeConnector;
+
+ if(nodeConnectorFromDS != null){
+ val nodeConnectorStatsFromDs = nodeConnectorFromDS.getAugmentation(FlowCapableNodeConnectorStatisticsData) as FlowCapableNodeConnectorStatistics;
+
+ ret.add(toNodeConnectorStatistics(nodeConnectorStatsFromDs.flowCapableNodeConnectorStatistics,dsNode.id,dsNodeConnector.id));
+ }
+ }
+ }
+
+ //TODO: Refer TODO (main)
val input = new GetAllNodeConnectorsStatisticsInputBuilder();
input.setNode(node.toNodeRef);
nodeConnectorStatisticsService.getAllNodeConnectorsStatistics(input.build());
}
override readAllNodeTable(Node node, boolean cached) {
- val ret = new ArrayList<NodeTableStatistics>();
-
- val dsFlowCapableNode= readFlowCapableNode(node.toNodeRef)
-
- if(dsFlowCapableNode != null){
-
- for (table : dsFlowCapableNode.table){
-
- val tableStats = table.getAugmentation(FlowTableStatisticsData);
-
- if(tableStats != null){
- ret.add(toNodeTableStatistics(tableStats.flowTableStatistics,table.id,node));
- }
- }
- }
-
- //TODO: Refer TODO (main)
+ val ret = new ArrayList<NodeTableStatistics>();
+
+ val dsFlowCapableNode= readFlowCapableNode(node.toNodeRef)
+
+ if(dsFlowCapableNode != null){
+
+ for (table : dsFlowCapableNode.table){
+
+ val tableStats = table.getAugmentation(FlowTableStatisticsData);
+
+ if(tableStats != null){
+ ret.add(toNodeTableStatistics(tableStats.flowTableStatistics,table.id,node));
+ }
+ }
+ }
+
+ //TODO: Refer TODO (main)
val input = new GetFlowTablesStatisticsInputBuilder();
input.setNode(node.toNodeRef);
flowTableStatisticsService.getFlowTablesStatistics(input.build);
override readDescription(Node node, boolean cached) {
return toNodeDescription(node.toNodeRef);
- }
+ }
override readFlow(Node node, Flow targetFlow, boolean cached) {
- var FlowOnNode ret= null;
-
- val tableRef = InstanceIdentifier.builder(Nodes)
- .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node))
- .augmentation(FlowCapableNode).child(Table, new TableKey(OPENFLOWV10_TABLE_ID)).toInstance();
-
- val it = this.startChange();
-
- val table= it.readConfigurationData(tableRef) as Table;
-
- if(table != null){
- LOG.trace("Number of flows installed in table 0 of node {} : {}",node,table.flow.size);
-
- for(mdsalFlow : table.flow){
- if(FromSalConversionsUtils.flowEquals(mdsalFlow, MDFlowMapping.toMDSalflow(targetFlow))){
- val statsFromDataStore = mdsalFlow.getAugmentation(FlowStatisticsData);
-
- if(statsFromDataStore != null){
- LOG.debug("Found matching flow in the data store flow table ");
- val it = new FlowOnNode(targetFlow);
- byteCount = statsFromDataStore.flowStatistics.byteCount.value.longValue;
- packetCount = statsFromDataStore.flowStatistics.packetCount.value.longValue;
- durationSeconds = statsFromDataStore.flowStatistics.duration.second.value.intValue;
- durationNanoseconds = statsFromDataStore.flowStatistics.duration.nanosecond.value.intValue;
-
- ret = it;
- }
- }
- }
- }
+ var FlowOnNode ret= null;
+
+ val tableRef = InstanceIdentifier.builder(Nodes)
+ .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node))
+ .augmentation(FlowCapableNode).child(Table, new TableKey(OPENFLOWV10_TABLE_ID)).toInstance();
+
+ val it = this.startChange();
+
+ val table= it.readConfigurationData(tableRef) as Table;
+
+ if(table != null){
+ LOG.trace("Number of flows installed in table 0 of node {} : {}",node,table.flow.size);
+
+ for(mdsalFlow : table.flow){
+ if(FromSalConversionsUtils.flowEquals(mdsalFlow, MDFlowMapping.toMDSalflow(targetFlow))){
+ val statsFromDataStore = mdsalFlow.getAugmentation(FlowStatisticsData);
+
+ if(statsFromDataStore != null){
+ LOG.debug("Found matching flow in the data store flow table ");
+ val it = new FlowOnNode(targetFlow);
+ byteCount = statsFromDataStore.flowStatistics.byteCount.value.longValue;
+ packetCount = statsFromDataStore.flowStatistics.packetCount.value.longValue;
+ durationSeconds = statsFromDataStore.flowStatistics.duration.second.value.intValue;
+ durationNanoseconds = statsFromDataStore.flowStatistics.duration.nanosecond.value.intValue;
+
+ ret = it;
+ }
+ }
+ }
+ }
//TODO: Refer TODO (main)
val input = new GetFlowStatisticsFromFlowTableInputBuilder;
flowStatisticsService.getFlowStatisticsFromFlowTable(input.build)
return ret;
-
+
}
override readNodeConnector(org.opendaylight.controller.sal.core.NodeConnector connector, boolean cached) {
- var NodeConnectorStatistics nodeConnectorStatistics = null;
-
- val nodeConnectorRef = InstanceIdentifier.builder(Nodes)
- .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(connector.node))
- .child(NodeConnector, InventoryMapping.toNodeConnectorKey(connector))
- .toInstance();
- val provider = this.startChange();
-
- val nodeConnectorFromDS = provider.readConfigurationData(nodeConnectorRef) as NodeConnector;
-
- if(nodeConnectorFromDS != null){
- val nodeConnectorStatsFromDs = nodeConnectorFromDS.getAugmentation(FlowCapableNodeConnectorStatisticsData) as FlowCapableNodeConnectorStatistics;
- if(nodeConnectorStatsFromDs != null) {
- nodeConnectorStatistics = toNodeConnectorStatistics(nodeConnectorStatsFromDs.flowCapableNodeConnectorStatistics,
- InventoryMapping.toNodeKey(connector.node).id,
- InventoryMapping.toNodeConnectorKey(connector).id);
- }
- }
-
- //TODO: Refer TODO (main)
+ var NodeConnectorStatistics nodeConnectorStatistics = null;
+
+ val nodeConnectorRef = InstanceIdentifier.builder(Nodes)
+ .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(connector.node))
+ .child(NodeConnector, InventoryMapping.toNodeConnectorKey(connector))
+ .toInstance();
+ val provider = this.startChange();
+
+ val nodeConnectorFromDS = provider.readConfigurationData(nodeConnectorRef) as NodeConnector;
+
+ if(nodeConnectorFromDS != null){
+ val nodeConnectorStatsFromDs = nodeConnectorFromDS.getAugmentation(FlowCapableNodeConnectorStatisticsData) as FlowCapableNodeConnectorStatistics;
+ if(nodeConnectorStatsFromDs != null) {
+ nodeConnectorStatistics = toNodeConnectorStatistics(nodeConnectorStatsFromDs.flowCapableNodeConnectorStatistics,
+ InventoryMapping.toNodeKey(connector.node).id,
+ InventoryMapping.toNodeConnectorKey(connector).id);
+ }
+ }
+
+ //TODO: Refer TODO (main)
val input = new GetNodeConnectorStatisticsInputBuilder();
input.setNode(connector.node.toNodeRef);
input.setNodeConnectorId(InventoryMapping.toNodeConnectorKey(connector).id);
}
override readNodeTable(NodeTable nodeTable, boolean cached) {
- var NodeTableStatistics nodeStats = null
-
- val tableRef = InstanceIdentifier.builder(Nodes)
- .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(nodeTable.node))
- .augmentation(FlowCapableNode).child(Table, new TableKey(nodeTable.ID as Short)).toInstance();
-
- val it = this.startChange();
-
- val table= it.readConfigurationData(tableRef) as Table;
-
- if(table != null){
- val tableStats = table.getAugmentation(FlowTableStatisticsData);
-
- if(tableStats != null){
- nodeStats = toNodeTableStatistics(tableStats.flowTableStatistics,table.id,nodeTable.node);
- }
- }
-
- //TODO: Refer TODO (main)
+ var NodeTableStatistics nodeStats = null
+
+ val tableRef = InstanceIdentifier.builder(Nodes)
+ .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(nodeTable.node))
+ .augmentation(FlowCapableNode).child(Table, new TableKey(nodeTable.ID as Short)).toInstance();
+
+ val it = this.startChange();
+
+ val table= it.readConfigurationData(tableRef) as Table;
+
+ if(table != null){
+ val tableStats = table.getAugmentation(FlowTableStatisticsData);
+
+ if(tableStats != null){
+ nodeStats = toNodeTableStatistics(tableStats.flowTableStatistics,table.id,nodeTable.node);
+ }
+ }
+
+ //TODO: Refer TODO (main)
val input = new GetFlowTablesStatisticsInputBuilder();
input.setNode(nodeTable.node.toNodeRef);
flowTableStatisticsService.getFlowTablesStatistics(input.build);
}
override onNodeConnectorRemoved(NodeConnectorRemoved update) {
- // NOOP
+ // Never received
}
override onNodeRemoved(NodeRemoved notification) {
val properties = Collections.<org.opendaylight.controller.sal.core.Property>emptySet();
+ removeNodeConnectors(notification.nodeRef.value);
+
publishNodeUpdate(notification.nodeRef.toADNode, UpdateType.REMOVED, properties);
}
override onNodeConnectorUpdated(NodeConnectorUpdated update) {
var updateType = UpdateType.CHANGED;
- if ( this._dataService.readOperationalData(update.nodeConnectorRef.value as InstanceIdentifier<? extends DataObject>) == null ){
+ if(!isKnownNodeConnector(update.nodeConnectorRef.value)){
updateType = UpdateType.ADDED;
+ recordNodeConnector(update.nodeConnectorRef.value);
}
var nodeConnector = update.nodeConnectorRef.toADNodeConnector
updateType = UpdateType.ADDED;
}
publishNodeUpdate(notification.nodeRef.toADNode, updateType, notification.toADNodeProperties);
-
- //Notify the listeners of IPluginOutReadService
-
+
+ //Notify the listeners of IPluginOutReadService
+
for (statsPublisher : statisticsPublisher){
- val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance;
+ val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance;
val description = notification.nodeRef.toNodeDescription
if(description != null) {
- statsPublisher.descriptionStatisticsUpdated(nodeRef.toADNode,description);
- }
- }
+ statsPublisher.descriptionStatisticsUpdated(nodeRef.toADNode,description);
+ }
+ }
}
override getNodeProps() {
private def toNodeConnectorStatistics(
org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.NodeConnectorStatistics nodeConnectorStatistics, NodeId nodeId, NodeConnectorId nodeConnectorId) {
-
- val it = new NodeConnectorStatistics();
-
- receivePacketCount = nodeConnectorStatistics.packets.received.longValue;
- transmitPacketCount = nodeConnectorStatistics.packets.transmitted.longValue;
-
- receiveByteCount = nodeConnectorStatistics.bytes.received.longValue;
- transmitByteCount = nodeConnectorStatistics.bytes.transmitted.longValue;
-
- receiveDropCount = nodeConnectorStatistics.receiveDrops.longValue;
- transmitDropCount = nodeConnectorStatistics.transmitDrops.longValue;
-
- receiveErrorCount = nodeConnectorStatistics.receiveErrors.longValue;
- transmitErrorCount = nodeConnectorStatistics.transmitErrors.longValue;
-
- receiveFrameErrorCount = nodeConnectorStatistics.receiveFrameError.longValue;
- receiveOverRunErrorCount = nodeConnectorStatistics.receiveOverRunError.longValue;
- receiveCRCErrorCount = nodeConnectorStatistics.receiveCrcError.longValue;
- collisionCount = nodeConnectorStatistics.collisionCount.longValue;
-
- val nodeConnectorRef = InstanceIdentifier.builder(Nodes)
- .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(nodeId))
- .child(NodeConnector,new NodeConnectorKey(nodeConnectorId)).toInstance;
-
- nodeConnector = NodeMapping.toADNodeConnector(new NodeConnectorRef(nodeConnectorRef));
-
- return it;
- }
-
- private def toNodeTableStatistics(
- FlowTableStatistics tableStats,
- Short tableId,Node node){
- var it = new NodeTableStatistics();
-
- activeCount = tableStats.activeFlows.value.intValue;
- lookupCount = tableStats.packetsLookedUp.value.intValue;
- matchedCount = tableStats.packetsMatched.value.intValue;
- name = tableId.toString;
- nodeTable = new NodeTable(NodeMapping.MD_SAL_TYPE,tableId,node);
- return it;
- }
-
- private def toNodeDescription(NodeRef nodeRef){
- val capableNode = readFlowCapableNode(nodeRef);
+
+ val it = new NodeConnectorStatistics();
+
+ receivePacketCount = nodeConnectorStatistics.packets.received.longValue;
+ transmitPacketCount = nodeConnectorStatistics.packets.transmitted.longValue;
+
+ receiveByteCount = nodeConnectorStatistics.bytes.received.longValue;
+ transmitByteCount = nodeConnectorStatistics.bytes.transmitted.longValue;
+
+ receiveDropCount = nodeConnectorStatistics.receiveDrops.longValue;
+ transmitDropCount = nodeConnectorStatistics.transmitDrops.longValue;
+
+ receiveErrorCount = nodeConnectorStatistics.receiveErrors.longValue;
+ transmitErrorCount = nodeConnectorStatistics.transmitErrors.longValue;
+
+ receiveFrameErrorCount = nodeConnectorStatistics.receiveFrameError.longValue;
+ receiveOverRunErrorCount = nodeConnectorStatistics.receiveOverRunError.longValue;
+ receiveCRCErrorCount = nodeConnectorStatistics.receiveCrcError.longValue;
+ collisionCount = nodeConnectorStatistics.collisionCount.longValue;
+
+ val nodeConnectorRef = InstanceIdentifier.builder(Nodes)
+ .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(nodeId))
+ .child(NodeConnector,new NodeConnectorKey(nodeConnectorId)).toInstance;
+
+ nodeConnector = NodeMapping.toADNodeConnector(new NodeConnectorRef(nodeConnectorRef));
+
+ return it;
+ }
+
+ private def toNodeTableStatistics(
+ FlowTableStatistics tableStats,
+ Short tableId,Node node){
+ var it = new NodeTableStatistics();
+
+ activeCount = tableStats.activeFlows.value.intValue;
+ lookupCount = tableStats.packetsLookedUp.value.intValue;
+ matchedCount = tableStats.packetsMatched.value.intValue;
+ name = tableId.toString;
+ nodeTable = new NodeTable(NodeMapping.MD_SAL_TYPE,tableId,node);
+ return it;
+ }
+
+ private def toNodeDescription(NodeRef nodeRef){
+ val capableNode = readFlowCapableNode(nodeRef);
if(capableNode !=null) {
val it = new NodeDescription()
manufacturer = capableNode.manufacturer
return it;
}
return null;
- }
+ }
def Edge toADEdge(Link link) {
new Edge(link.source.toADNodeConnector,link.destination.toADNodeConnector)
}
-
- /*
- * OpendaylightFlowStatisticsListener interface implementation
- */
- override onAggregateFlowStatisticsUpdate(AggregateFlowStatisticsUpdate notification) {
+
+ /*
+ * OpendaylightFlowStatisticsListener interface implementation
+ */
+ override onAggregateFlowStatisticsUpdate(AggregateFlowStatisticsUpdate notification) {
//Ignoring this notification as there does not seem to be a way to bubble this up to AD-SAL
- }
-
- override onFlowsStatisticsUpdate(FlowsStatisticsUpdate notification) {
-
- val adsalFlowsStatistics = new ArrayList<FlowOnNode>();
- val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance;
-
- for(flowStats : notification.flowAndStatisticsMapList){
- if(flowStats.tableId == 0)
- adsalFlowsStatistics.add(toFlowOnNode(flowStats,nodeRef.toADNode));
- }
-
- for (statsPublisher : statisticsPublisher){
- statsPublisher.nodeFlowStatisticsUpdated(nodeRef.toADNode,adsalFlowsStatistics);
- }
-
- }
- /*
- * OpendaylightFlowTableStatisticsListener interface implementation
- */
- override onFlowTableStatisticsUpdate(FlowTableStatisticsUpdate notification) {
- var adsalFlowTableStatistics = new ArrayList<NodeTableStatistics>();
-
- for(stats : notification.flowTableAndStatisticsMap){
- if (stats.tableId.value == 0){
- val it = new NodeTableStatistics();
- activeCount = stats.activeFlows.value.intValue;
- lookupCount = stats.packetsLookedUp.value.longValue;
- matchedCount = stats.packetsMatched.value.longValue;
-
- adsalFlowTableStatistics.add(it);
- }
- }
- for (statsPublisher : statisticsPublisher){
- val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance;
- statsPublisher.nodeTableStatisticsUpdated(nodeRef.toADNode,adsalFlowTableStatistics);
- }
- }
-
- /*
- * OpendaylightPortStatisticsUpdate interface implementation
- */
- override onNodeConnectorStatisticsUpdate(NodeConnectorStatisticsUpdate notification) {
-
- val adsalPortStatistics = new ArrayList<NodeConnectorStatistics>();
-
- for(nodeConnectorStatistics : notification.nodeConnectorStatisticsAndPortNumberMap){
- adsalPortStatistics.add(toNodeConnectorStatistics(nodeConnectorStatistics,notification.id,nodeConnectorStatistics.nodeConnectorId));
- }
-
- for (statsPublisher : statisticsPublisher){
- val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance;
- statsPublisher.nodeConnectorStatisticsUpdated(nodeRef.toADNode,adsalPortStatistics);
- }
-
- }
-
- private static def toFlowOnNode (FlowAndStatisticsMapList flowAndStatsMap,Node node){
-
- val it = new FlowOnNode(ToSalConversionsUtils.toFlow(flowAndStatsMap,node));
-
- byteCount = flowAndStatsMap.byteCount.value.longValue;
- packetCount = flowAndStatsMap.packetCount.value.longValue;
- durationSeconds = flowAndStatsMap.duration.second.value.intValue;
- durationNanoseconds = flowAndStatsMap.duration.nanosecond.value.intValue;
-
- return it;
- }
-
- override getConfiguredNotConnectedNodes() {
+ }
+
+ override onFlowsStatisticsUpdate(FlowsStatisticsUpdate notification) {
+
+ val adsalFlowsStatistics = new ArrayList<FlowOnNode>();
+ val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance;
+
+ for(flowStats : notification.flowAndStatisticsMapList){
+ if(flowStats.tableId == 0)
+ adsalFlowsStatistics.add(toFlowOnNode(flowStats,nodeRef.toADNode));
+ }
+
+ for (statsPublisher : statisticsPublisher){
+ statsPublisher.nodeFlowStatisticsUpdated(nodeRef.toADNode,adsalFlowsStatistics);
+ }
+
+ }
+ /*
+ * OpendaylightFlowTableStatisticsListener interface implementation
+ */
+ override onFlowTableStatisticsUpdate(FlowTableStatisticsUpdate notification) {
+ var adsalFlowTableStatistics = new ArrayList<NodeTableStatistics>();
+
+ for(stats : notification.flowTableAndStatisticsMap){
+ if (stats.tableId.value == 0){
+ val it = new NodeTableStatistics();
+ activeCount = stats.activeFlows.value.intValue;
+ lookupCount = stats.packetsLookedUp.value.longValue;
+ matchedCount = stats.packetsMatched.value.longValue;
+
+ adsalFlowTableStatistics.add(it);
+ }
+ }
+ for (statsPublisher : statisticsPublisher){
+ val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance;
+ statsPublisher.nodeTableStatisticsUpdated(nodeRef.toADNode,adsalFlowTableStatistics);
+ }
+ }
+
+ /*
+ * OpendaylightPortStatisticsUpdate interface implementation
+ */
+ override onNodeConnectorStatisticsUpdate(NodeConnectorStatisticsUpdate notification) {
+
+ val adsalPortStatistics = new ArrayList<NodeConnectorStatistics>();
+
+ for(nodeConnectorStatistics : notification.nodeConnectorStatisticsAndPortNumberMap){
+ adsalPortStatistics.add(toNodeConnectorStatistics(nodeConnectorStatistics,notification.id,nodeConnectorStatistics.nodeConnectorId));
+ }
+
+ for (statsPublisher : statisticsPublisher){
+ val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance;
+ statsPublisher.nodeConnectorStatisticsUpdated(nodeRef.toADNode,adsalPortStatistics);
+ }
+
+ }
+
+ private static def toFlowOnNode (FlowAndStatisticsMapList flowAndStatsMap,Node node){
+
+ val it = new FlowOnNode(ToSalConversionsUtils.toFlow(flowAndStatsMap,node));
+
+ byteCount = flowAndStatsMap.byteCount.value.longValue;
+ packetCount = flowAndStatsMap.packetCount.value.longValue;
+ durationSeconds = flowAndStatsMap.duration.second.value.intValue;
+ durationNanoseconds = flowAndStatsMap.duration.nanosecond.value.intValue;
+
+ return it;
+ }
+
+ override getConfiguredNotConnectedNodes() {
return Collections.emptySet();
- }
+ }
+
+
+ private def publishNodeUpdate(Node node, UpdateType updateType, Set<org.opendaylight.controller.sal.core.Property> properties){
+ for( publisher : inventoryPublisher){
+ publisher.updateNode(node, updateType, properties);
+ }
+ }
+
+ private def publishNodeConnectorUpdate(org.opendaylight.controller.sal.core.NodeConnector nodeConnector, UpdateType updateType, Set<org.opendaylight.controller.sal.core.Property> properties){
+ for( publisher : inventoryPublisher){
+ publisher.updateNodeConnector(nodeConnector, updateType, properties);
+ }
+ }
+
+ private def isKnownNodeConnector(InstanceIdentifier<? extends Object> nodeConnectorIdentifier){
+ if(nodeConnectorIdentifier.path.size() < 3) {
+ return false;
+ }
+ val nodePath = nodeConnectorIdentifier.path.get(1);
+ val nodeConnectorPath = nodeConnectorIdentifier.getPath().get(2);
- private def publishNodeUpdate(Node node, UpdateType updateType, Set<org.opendaylight.controller.sal.core.Property> properties){
- for( publisher : inventoryPublisher){
- publisher.updateNode(node, updateType, properties);
- }
- }
+ val nodeConnectors = nodeToNodeConnectorsMap.get(nodePath);
- private def publishNodeConnectorUpdate(org.opendaylight.controller.sal.core.NodeConnector nodeConnector, UpdateType updateType, Set<org.opendaylight.controller.sal.core.Property> properties){
- for( publisher : inventoryPublisher){
- publisher.updateNodeConnector(nodeConnector, updateType, properties);
- }
- }
+ if(nodeConnectors == null){
+ return false;
+ }
+ return nodeConnectors.contains(nodeConnectorPath);
+ }
+
+
+ private def recordNodeConnector(InstanceIdentifier<? extends Object> nodeConnectorIdentifier){
+ if(nodeConnectorIdentifier.path.size() < 3) {
+ return false;
+ }
+
+ val nodePath = nodeConnectorIdentifier.path.get(1);
+ val nodeConnectorPath = nodeConnectorIdentifier.getPath().get(2);
+
+ nodeToNodeConnectorsLock.lock();
+
+ try {
+ var nodeConnectors = nodeToNodeConnectorsMap.get(nodePath);
+
+ if(nodeConnectors == null){
+ nodeConnectors = new ArrayList<InstanceIdentifier.PathArgument>();
+ nodeToNodeConnectorsMap.put(nodePath, nodeConnectors);
+ }
+
+ nodeConnectors.add(nodeConnectorPath);
+ } finally {
+ nodeToNodeConnectorsLock.unlock();
+ }
+ }
+
+ private def removeNodeConnectors(InstanceIdentifier<? extends Object> nodeIdentifier){
+ val nodePath = nodeIdentifier.path.get(1);
+
+ nodeToNodeConnectorsMap.remove(nodePath);
+ }
}
--- /dev/null
+/**
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.compatibility;
+
+import org.eclipse.xtend2.lib.StringConcatenation;
+import org.eclipse.xtext.xbase.lib.Conversions;
+import org.eclipse.xtext.xbase.lib.IterableExtensions;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.core.NodeConnector;
+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.NodeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
+
+import java.util.List;
+
+@SuppressWarnings("all")
+public class InventoryMapping {
+ public static NodeConnector toAdNodeConnector(final InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector> identifier) {
+ final List<PathArgument> path = identifier.getPath();
+ final PathArgument lastPathArgument = IterableExtensions.<PathArgument>last(path);
+ final NodeConnectorKey tpKey = ((IdentifiableItem<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector,NodeConnectorKey>) lastPathArgument).getKey();
+ return InventoryMapping.nodeConnectorFromId(tpKey.getId().getValue());
+ }
+
+ public static Node toAdNode(final InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node> identifier) {
+ final List<PathArgument> path = identifier.getPath();
+ final PathArgument lastPathArgument = IterableExtensions.<PathArgument>last(path);
+ final NodeKey tpKey = ((IdentifiableItem<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,NodeKey>) lastPathArgument).getKey();
+ return InventoryMapping.nodeFromNodeId(tpKey.getId().getValue());
+ }
+
+ public static NodeRef toNodeRef(final Node node) {
+ final NodeId nodeId = new NodeId(InventoryMapping.toNodeId(node));
+ final NodeKey nodeKey = new NodeKey(nodeId);
+ final InstanceIdentifierBuilder<? extends Object> builder = InstanceIdentifier.builder();
+ final InstanceIdentifierBuilder<Nodes> nodes = builder.<Nodes>node(Nodes.class);
+ final InstanceIdentifierBuilder<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node> child =
+ nodes.<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, NodeKey>child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, nodeKey);
+ final InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node> path = child.toInstance();
+ return new NodeRef(path);
+ }
+
+ public static NodeKey toNodeKey(final Node node) {
+ final NodeId nodeId = new NodeId(InventoryMapping.toNodeId(node));
+ return new NodeKey(nodeId);
+ }
+
+ public static NodeConnectorKey toNodeConnectorKey(final NodeConnector nc) {
+ final NodeConnectorId nodeConnectorId = new NodeConnectorId(InventoryMapping.toNodeConnectorId(nc));
+ return new NodeConnectorKey(nodeConnectorId);
+ }
+
+ public static String toNodeId(final Node node) {
+ final StringConcatenation builder = new StringConcatenation();
+ builder.append("ad-sal:");
+ builder.append(node.getType(), "");
+ builder.append("::");
+ builder.append(node.getNodeIDString(), "");
+ return builder.toString();
+ }
+
+ public static String toNodeConnectorId(final NodeConnector nc) {
+ final StringConcatenation builder = new StringConcatenation();
+ builder.append(InventoryMapping.toNodeId(nc.getNode()), "");
+ builder.append("::");
+ builder.append(nc.getNodeConnectorIDString(), "");
+ return builder.toString();
+ }
+
+ public static Node nodeFromNodeId(final String nodeId) {
+ final String[] split = nodeId.split("::");
+ return InventoryMapping.nodeFromString(split);
+ }
+
+ public static NodeConnector nodeConnectorFromId(final String invId) {
+ final String[] split = invId.split("::");
+ return InventoryMapping.nodeConnectorFromString(split);
+ }
+
+ private static NodeConnector nodeConnectorFromString(final String[] string) {
+ final List<String> subList = ((List<String>)Conversions.doWrapArray(string)).subList(0, 1);
+ final Node node = InventoryMapping.nodeFromString(((String[])Conversions.unwrapArray(subList, String.class)));
+ final String index3 = string[2];
+ return NodeConnector.fromStringNoNode(index3, node);
+ }
+
+ private static Node nodeFromString(final String[] strings) {
+ String index0 = strings[0];
+ final String type = index0.substring(6);
+ String id = strings[1];
+ return Node.fromString(type, id);
+ }
+}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.sal.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<NodeConnector> identifier) {
- val tpKey = (identifier.path.last as IdentifiableItem<NodeConnector,NodeConnectorKey>).key;
- return nodeConnectorFromId(tpKey.id.value);
- }
-
- static def org.opendaylight.controller.sal.core.Node toAdNode(InstanceIdentifier<Node> identifier) {
- val tpKey = (identifier.path.last as IdentifiableItem<Node,NodeKey>).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))
- }
-
-}
--- /dev/null
+package org.opendaylight.controller.sal.compatibility;
+
+import java.util.List;
+
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.controller.sal.inventory.IPluginOutInventoryService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class InventoryNotificationProvider implements AutoCloseable{
+
+ private ListenerRegistration<DataChangeListener> nodeConnectorDataChangeListenerRegistration;
+
+ private NodeConnectorDataChangeListener nodeConnectorDataChangeListener;
+
+ private DataProviderService dataProviderService;
+
+ private List<IPluginOutInventoryService> inventoryPublisher;
+
+ private final static Logger LOG = LoggerFactory.getLogger(NodeConnectorDataChangeListener.class);
+
+ public void start(){
+
+ LOG.info("InventoryNotificationProvider started");
+
+ if(dataProviderService != null
+ && inventoryPublisher!= null){
+
+ if(nodeConnectorDataChangeListener == null){
+ InstanceIdentifier<NodeConnector> nodeConnectorPath = InstanceIdentifier.builder(Nodes.class).child(Node.class).child(NodeConnector.class).build();
+ nodeConnectorDataChangeListener = new NodeConnectorDataChangeListener();
+ nodeConnectorDataChangeListener.setInventoryPublisher(inventoryPublisher);
+ nodeConnectorDataChangeListenerRegistration = dataProviderService.registerDataChangeListener(nodeConnectorPath, nodeConnectorDataChangeListener);
+ }
+
+ }
+ }
+
+ @Override
+ public void close() throws Exception {
+ if(nodeConnectorDataChangeListenerRegistration != null){
+ nodeConnectorDataChangeListenerRegistration.close();
+ }
+ }
+
+ public void setDataProviderService(DataProviderService dataProviderService) {
+ this.dataProviderService = dataProviderService;
+ }
+
+ public void setInventoryPublisher(List<IPluginOutInventoryService> inventoryPublisher) {
+ this.inventoryPublisher = inventoryPublisher;
+ }
+}
--- /dev/null
+package org.opendaylight.controller.sal.compatibility;
+
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
+import org.opendaylight.controller.sal.core.ConstructionException;
+import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.core.Property;
+import org.opendaylight.controller.sal.core.UpdateType;
+import org.opendaylight.controller.sal.inventory.IPluginOutInventoryService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+// org.opendaylight.controller.sal.compatibility.NodeConnectorDataChangeListener
+public class NodeConnectorDataChangeListener implements DataChangeListener{
+ private final static Logger LOG = LoggerFactory.getLogger(NodeConnectorDataChangeListener.class);
+
+ private List<IPluginOutInventoryService> inventoryPublisher;
+
+ public List<IPluginOutInventoryService> getInventoryPublisher() {
+ return this.inventoryPublisher;
+ }
+
+ public void setInventoryPublisher(final List<IPluginOutInventoryService> inventoryPublisher) {
+ this.inventoryPublisher = inventoryPublisher;
+ }
+
+ @Override
+ public void onDataChanged(DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
+ final Map<InstanceIdentifier<?>,DataObject> createdOperationalData = change.getCreatedOperationalData();
+ final Map<InstanceIdentifier<?>,DataObject> updatedOperationalData = change.getUpdatedOperationalData();
+
+ final Set<Map.Entry<InstanceIdentifier<?>,DataObject>> createdEntries = createdOperationalData.entrySet();
+ final Set<Map.Entry<InstanceIdentifier<?>,DataObject>> updatedEntries = new HashSet<>();
+
+ updatedEntries.addAll(updatedOperationalData.entrySet());
+ updatedEntries.removeAll(createdEntries);
+
+ for(final Map.Entry<InstanceIdentifier<?>,DataObject> entry : createdEntries){
+ publishNodeConnectorUpdate(entry, UpdateType.ADDED);
+ }
+
+ for(final Map.Entry<InstanceIdentifier<?>,DataObject> entry : updatedEntries){
+ publishNodeConnectorUpdate(entry, UpdateType.CHANGED);
+ }
+ }
+
+ private void publishNodeConnectorUpdate(final Map.Entry<InstanceIdentifier<?>,DataObject> entry, final UpdateType updateType) {
+ if (entry.getKey().getTargetType().equals(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector.class)) {
+ NodeConnectorRef nodeConnectorRef = new NodeConnectorRef(entry.getKey());
+ NodeConnector nodeConnector = null;
+ try {
+ nodeConnector = NodeMapping.toADNodeConnector(nodeConnectorRef);
+ } catch (ConstructionException e) {
+ e.printStackTrace();
+ }
+ HashSet<Property> _aDNodeConnectorProperties = NodeMapping.toADNodeConnectorProperties((org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector) entry.getValue());
+ this.publishNodeConnectorUpdate(nodeConnector, updateType, _aDNodeConnectorProperties);
+ }
+ }
+
+ private void publishNodeConnectorUpdate(final NodeConnector nodeConnector, final UpdateType updateType, final Set<Property> properties) {
+ LOG.debug("Publishing NodeConnector " + updateType.toString() + " nodeConnector Id = " + nodeConnector.getNodeConnectorIdAsString());
+
+ List<IPluginOutInventoryService> _inventoryPublisher = getInventoryPublisher();
+ for (final IPluginOutInventoryService publisher : _inventoryPublisher) {
+ publisher.updateNodeConnector(nodeConnector, updateType, properties);
+ }
+ }
+}
--- /dev/null
+/**
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.compatibility;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
+import org.eclipse.xtext.xbase.lib.Exceptions;
+import org.opendaylight.controller.sal.common.util.Arguments;
+import org.opendaylight.controller.sal.core.AdvertisedBandwidth;
+import org.opendaylight.controller.sal.core.Bandwidth;
+import org.opendaylight.controller.sal.core.Buffers;
+import org.opendaylight.controller.sal.core.Capabilities;
+import org.opendaylight.controller.sal.core.Config;
+import org.opendaylight.controller.sal.core.ConstructionException;
+import org.opendaylight.controller.sal.core.MacAddress;
+import org.opendaylight.controller.sal.core.Name;
+import org.opendaylight.controller.sal.core.NodeConnector.NodeConnectorIDType;
+import org.opendaylight.controller.sal.core.PeerBandwidth;
+import org.opendaylight.controller.sal.core.Property;
+import org.opendaylight.controller.sal.core.SupportedBandwidth;
+import org.opendaylight.controller.sal.core.Tables;
+import org.opendaylight.controller.sal.core.TimeStamp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FeatureCapability;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorUpdated;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeUpdated;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityArpMatchIp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityFlowStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityIpReasm;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityPortStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityQueueStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityStp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityTableStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowNodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.SwitchFeatures;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortFeatures;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.flow.capable.port.State;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorUpdated;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeUpdated;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+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.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yangtools.yang.binding.Identifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
+
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+
+@SuppressWarnings("all")
+public class NodeMapping {
+ public final static String MD_SAL_TYPE = "MD_SAL";
+
+ private final static Class<Node> NODE_CLASS = Node.class;
+
+ private final static Class<NodeConnector> NODECONNECTOR_CLASS = NodeConnector.class;
+
+ private NodeMapping() {
+ throw new UnsupportedOperationException("Utility class. Instantiation is not allowed.");
+ }
+
+ public static org.opendaylight.controller.sal.core.Node toADNode(final InstanceIdentifier<? extends Object> node) throws ConstructionException {
+ NodeId nodeId = NodeMapping.toNodeId(node);
+ return NodeMapping.toADNode(nodeId);
+ }
+
+ public static org.opendaylight.controller.sal.core.Node toADNode(final NodeId id) {
+ try {
+ String aDNodeId = NodeMapping.toADNodeId(id);
+ return new org.opendaylight.controller.sal.core.Node(NodeMapping.MD_SAL_TYPE, aDNodeId);
+ } catch (Throwable e) {
+ throw Exceptions.sneakyThrow(e);
+ }
+ }
+
+ public static NodeId toNodeId(final InstanceIdentifier<? extends Object> node) {
+ Preconditions.<InstanceIdentifier<? extends Object>>checkNotNull(node);
+ List<PathArgument> path = node.getPath();
+ Preconditions.<List<PathArgument>>checkNotNull(path);
+ int size = path.size();
+ Preconditions.checkArgument(size >= 2);
+ final PathArgument arg = path.get(1);
+ final IdentifiableItem item = Arguments.<IdentifiableItem>checkInstanceOf(arg, IdentifiableItem.class);
+ Identifier key = item.getKey();
+ final NodeKey nodeKey = Arguments.<NodeKey>checkInstanceOf(key, NodeKey.class);
+ return nodeKey.getId();
+ }
+
+ public static String toADNodeId(final NodeId nodeId) {
+ Preconditions.<NodeId>checkNotNull(nodeId);
+ return nodeId.getValue();
+ }
+
+ public static org.opendaylight.controller.sal.core.NodeConnector toADNodeConnector(final NodeConnectorRef source) throws ConstructionException {
+ Preconditions.<NodeConnectorRef>checkNotNull(source);
+ final InstanceIdentifier<?> path = Preconditions.<InstanceIdentifier<? extends Object>>checkNotNull(source.getValue());
+ Preconditions.checkArgument(path.getPath().size() >= 3);
+ final PathArgument arg = path.getPath().get(2);
+ final IdentifiableItem item = Arguments.<IdentifiableItem>checkInstanceOf(arg,IdentifiableItem.class);
+ final NodeConnectorKey connectorKey = Arguments.<NodeConnectorKey>checkInstanceOf(item.getKey(), NodeConnectorKey.class);
+ return NodeMapping.toADNodeConnector(connectorKey.getId(), NodeMapping.toNodeId(path));
+ }
+
+ public static org.opendaylight.controller.sal.core.NodeConnector toADNodeConnector(final NodeConnectorId ncid, final NodeId nid) {
+ try {
+ String nodeConnectorType = NodeMapping.toNodeConnectorType(ncid, nid);
+ Object aDNodeConnectorId = NodeMapping.toADNodeConnectorId(ncid, nid);
+ org.opendaylight.controller.sal.core.Node aDNode = NodeMapping.toADNode(nid);
+ return new org.opendaylight.controller.sal.core.NodeConnector(nodeConnectorType, aDNodeConnectorId, aDNode);
+ } catch (Throwable e) {
+ throw Exceptions.sneakyThrow(e);
+ }
+ }
+
+ public static String toNodeConnectorType(final NodeConnectorId ncId, final NodeId nodeId) {
+ if (ncId.equals(toLocalNodeConnectorId(nodeId))) {
+ return NodeConnectorIDType.SWSTACK;
+ } else if (ncId.equals(toNormalNodeConnectorId(nodeId))) {
+ return NodeConnectorIDType.HWPATH;
+ } else if (ncId.equals(toControllerNodeConnectorId(nodeId))) {
+ return NodeConnectorIDType.CONTROLLER;
+ }
+ return MD_SAL_TYPE;
+ }
+
+ public static Object toADNodeConnectorId(final NodeConnectorId nodeConnectorId, final NodeId nodeId) {
+ if (nodeConnectorId.equals(toLocalNodeConnectorId(nodeId)) ||
+ nodeConnectorId.equals(toNormalNodeConnectorId(nodeId)) ||
+ nodeConnectorId.equals(toControllerNodeConnectorId(nodeId))) {
+ return org.opendaylight.controller.sal.core.NodeConnector.SPECIALNODECONNECTORID;
+ }
+ return nodeConnectorId.getValue();
+ }
+
+ public static NodeConnectorId toControllerNodeConnectorId(final NodeId node) {
+ return new NodeConnectorId(node.getValue() + ":" + 4294967293L);
+ }
+
+ public static NodeConnectorId toLocalNodeConnectorId(final NodeId node) {
+ return new NodeConnectorId(node.getValue() + ":" + 4294967294L);
+ }
+
+ public static NodeConnectorId toNormalNodeConnectorId(final NodeId node) {
+ return new NodeConnectorId(node.getValue() + ":" + 4294967290L);
+ }
+
+ public static NodeRef toNodeRef(final org.opendaylight.controller.sal.core.Node node) {
+ Preconditions.checkArgument(MD_SAL_TYPE.equals(node.getType()));
+ final String nodeId = Arguments.<String>checkInstanceOf(node.getID(), String.class);
+ final NodeKey nodeKey = new NodeKey(new NodeId(nodeId));
+ final InstanceIdentifier<Node> nodePath = InstanceIdentifier.builder().node(Nodes.class).child(NODE_CLASS, nodeKey).toInstance();
+ return new NodeRef(nodePath);
+ }
+
+ public static NodeConnectorRef toNodeConnectorRef(final org.opendaylight.controller.sal.core.NodeConnector nodeConnector) {
+
+ final NodeRef node = NodeMapping.toNodeRef(nodeConnector.getNode());
+ final InstanceIdentifier<Node> nodePath = ((InstanceIdentifier<Node>) node.getValue());
+ NodeConnectorId nodeConnectorId = null;
+
+ if (nodeConnector.getID().equals(org.opendaylight.controller.sal.core.NodeConnector.SPECIALNODECONNECTORID)) {
+ final NodeId nodeId = toNodeId(nodePath);
+ final String nodeConnectorType = nodeConnector.getType();
+ if (nodeConnectorType.equals(NodeConnectorIDType.SWSTACK)) {
+ nodeConnectorId = toLocalNodeConnectorId(nodeId);
+ } else if (nodeConnectorType.equals(NodeConnectorIDType.HWPATH)) {
+ nodeConnectorId = toNormalNodeConnectorId(nodeId);
+ } else if (nodeConnectorType.equals(NodeConnectorIDType.CONTROLLER)) {
+ nodeConnectorId = toControllerNodeConnectorId(nodeId);
+ }
+ } else {
+ nodeConnectorId = new NodeConnectorId(Arguments.<String>checkInstanceOf(nodeConnector.getID(), String.class));
+ }
+ final NodeConnectorKey connectorKey = new NodeConnectorKey(nodeConnectorId);
+ final InstanceIdentifier<NodeConnector> path = InstanceIdentifier.builder(nodePath).child(NODECONNECTOR_CLASS, connectorKey).toInstance();
+ return new NodeConnectorRef(path);
+ }
+
+ public static org.opendaylight.controller.sal.core.Node toADNode(final NodeRef node) throws ConstructionException {
+ return NodeMapping.toADNode(node.getValue());
+ }
+
+ public static HashSet<Property> toADNodeConnectorProperties(final NodeConnectorUpdated nc) {
+ final FlowCapableNodeConnectorUpdated fcncu = nc.<FlowCapableNodeConnectorUpdated>getAugmentation(FlowCapableNodeConnectorUpdated.class);
+ if (!Objects.equal(fcncu, null)) {
+ return NodeMapping.toADNodeConnectorProperties(fcncu);
+ }
+ return new HashSet<Property>();
+ }
+
+ public static HashSet<Property> toADNodeConnectorProperties(final NodeConnector nc) {
+ final FlowCapableNodeConnector fcnc = nc.<FlowCapableNodeConnector>getAugmentation(FlowCapableNodeConnector.class);
+ if (!Objects.equal(fcnc, null)) {
+ return NodeMapping.toADNodeConnectorProperties(fcnc);
+ }
+ return new HashSet<Property>();
+ }
+
+ public static HashSet<Property> toADNodeConnectorProperties(final FlowNodeConnector fcncu) {
+
+ final HashSet<org.opendaylight.controller.sal.core.Property> props = new HashSet<>();
+ if (fcncu != null) {
+ if (fcncu.getCurrentFeature() != null && toAdBandwidth(fcncu.getCurrentFeature()) != null) {
+ props.add(toAdBandwidth(fcncu.getCurrentFeature()));
+ }
+ if (fcncu.getAdvertisedFeatures() != null && toAdAdvertizedBandwidth(fcncu.getAdvertisedFeatures()) != null) {
+ props.add(toAdAdvertizedBandwidth(fcncu.getAdvertisedFeatures()));
+ }
+ if (fcncu.getSupported() != null && toAdSupportedBandwidth(fcncu.getSupported()) != null) {
+ props.add(toAdSupportedBandwidth(fcncu.getSupported()));
+ }
+ if (fcncu.getPeerFeatures() != null && toAdPeerBandwidth(fcncu.getPeerFeatures()) != null) {
+ props.add(toAdPeerBandwidth(fcncu.getPeerFeatures()));
+ }
+ if (fcncu.getName() != null && toAdName(fcncu.getName()) != null) {
+ props.add(toAdName(fcncu.getName()));
+ }
+ if (fcncu.getConfiguration() != null && toAdConfig(fcncu.getConfiguration()) != null) {
+ props.add(toAdConfig(fcncu.getConfiguration()));
+ }
+ if (fcncu.getState() != null && toAdState(fcncu.getState()) != null) {
+ props.add(toAdState(fcncu.getState()));
+ }
+ }
+ return props;
+ }
+
+ public static Name toAdName(final String name) {
+ return new Name(name);
+ }
+
+ public static Config toAdConfig(final PortConfig pc) {
+ Config config = null;
+ if (pc.isPORTDOWN()) {
+ config = new Config(Config.ADMIN_DOWN);
+ } else {
+ config = new Config(Config.ADMIN_UP);
+ }
+ return config;
+ }
+
+ public static org.opendaylight.controller.sal.core.State toAdState(final State s) {
+
+ org.opendaylight.controller.sal.core.State state = null;
+ if (s.isLinkDown()) {
+ state = new org.opendaylight.controller.sal.core.State(org.opendaylight.controller.sal.core.State.EDGE_DOWN);
+ } else {
+ state = new org.opendaylight.controller.sal.core.State(org.opendaylight.controller.sal.core.State.EDGE_UP);
+ }
+ return state;
+ }
+
+ public static Bandwidth toAdBandwidth(final PortFeatures pf) {
+ Bandwidth bw = null;
+ if (pf.isTenMbHd() || pf.isTenMbFd()) {
+ bw = new Bandwidth(Bandwidth.BW10Mbps);
+ } else if (pf.isHundredMbHd() || pf.isHundredMbFd()) {
+ bw = new Bandwidth(Bandwidth.BW100Mbps);
+ } else if (pf.isOneGbHd() || pf.isOneGbFd()) {
+ bw = new Bandwidth(Bandwidth.BW1Gbps);
+ } else if (pf.isOneGbFd()) {
+ bw = new Bandwidth(Bandwidth.BW10Gbps);
+ } else if (pf.isTenGbFd()) {
+ bw = new Bandwidth(Bandwidth.BW10Gbps);
+ } else if (pf.isFortyGbFd()) {
+ bw = new Bandwidth(Bandwidth.BW40Gbps);
+ } else if (pf.isHundredGbFd()) {
+ bw = new Bandwidth(Bandwidth.BW100Gbps);
+ } else if (pf.isOneTbFd()) {
+ bw = new Bandwidth(Bandwidth.BW1Tbps);
+ }
+ return bw;
+ }
+
+ public static AdvertisedBandwidth toAdAdvertizedBandwidth(final PortFeatures pf) {
+ AdvertisedBandwidth abw = null;
+ final Bandwidth bw = toAdBandwidth(pf);
+ if (bw != null) {
+ abw = new AdvertisedBandwidth(bw.getValue());
+ }
+ return abw;
+ }
+
+ public static SupportedBandwidth toAdSupportedBandwidth(final PortFeatures pf) {
+ SupportedBandwidth sbw = null;
+ final Bandwidth bw = toAdBandwidth(pf);
+ if (bw != null) {
+ sbw = new SupportedBandwidth(bw.getValue());
+ }
+ return sbw;
+ }
+
+ public static PeerBandwidth toAdPeerBandwidth(final PortFeatures pf) {
+ PeerBandwidth pbw = null;
+ final Bandwidth bw = toAdBandwidth(pf);
+ if (bw != null) {
+ pbw = new PeerBandwidth(bw.getValue());
+ }
+ return pbw;
+ }
+
+ public static HashSet<Property> toADNodeProperties(final NodeUpdated nu) {
+ final FlowCapableNodeUpdated fcnu = nu.getAugmentation(FlowCapableNodeUpdated.class);
+ if (fcnu != null) {
+ return toADNodeProperties(fcnu, nu.getId());
+ }
+ return new HashSet<org.opendaylight.controller.sal.core.Property>();
+ }
+
+ public static HashSet<Property> toADNodeProperties(final FlowNode fcnu, final NodeId id) {
+
+ final HashSet<org.opendaylight.controller.sal.core.Property> props = new HashSet<>();
+
+ if (fcnu != null) {
+ props.add(toADTimestamp());
+
+ // props.add(fcnu.supportedActions.toADActions) - TODO
+ if (id != null) {
+ props.add(toADMacAddress(id));
+ }
+ SwitchFeatures switchFeatures = fcnu.getSwitchFeatures();
+ if (switchFeatures != null) {
+ if (switchFeatures.getMaxTables() != null) {
+ props.add(toADTables(switchFeatures.getMaxTables()));
+ }
+ if (switchFeatures.getCapabilities() != null) {
+ props.add(toADCapabiliities(switchFeatures.getCapabilities()));
+ }
+ if (switchFeatures.getMaxBuffers() != null) {
+ props.add(toADBuffers(switchFeatures.getMaxBuffers()));
+ }
+ }
+ }
+ return props;
+ }
+
+ public static TimeStamp toADTimestamp() {
+ final Date date = new Date();
+ final TimeStamp timestamp = new TimeStamp(date.getTime(), "connectedSince");
+ return timestamp;
+ }
+
+ public static MacAddress toADMacAddress(final NodeId id) {
+ final String nodeId = id.getValue().replaceAll("openflow:", "");
+ long lNodeId = Long.parseLong(nodeId);
+ lNodeId = Long.valueOf(lNodeId).longValue();
+ byte[] bytesFromDpid = ToSalConversionsUtils.bytesFromDpid(lNodeId);
+ return new MacAddress(bytesFromDpid);
+ }
+
+ public static Tables toADTables(final Short tables) {
+ return new Tables(tables.byteValue());
+ }
+
+ public static Capabilities toADCapabiliities(final List<Class<? extends FeatureCapability>> capabilities) {
+
+ int b = 0;
+ for (Class<? extends FeatureCapability> capability : capabilities) {
+ if (capability.equals(FlowFeatureCapabilityFlowStats.class)) {
+ b = Capabilities.CapabilitiesType.FLOW_STATS_CAPABILITY.getValue() | b;
+ } else if (capability.equals(FlowFeatureCapabilityTableStats.class)) {
+ b = Capabilities.CapabilitiesType.TABLE_STATS_CAPABILITY.getValue() | b;
+ } else if (capability.equals(FlowFeatureCapabilityPortStats.class)) {
+ b = Capabilities.CapabilitiesType.PORT_STATS_CAPABILITY.getValue() | b;
+ } else if (capability.equals(FlowFeatureCapabilityStp.class)) {
+ b = Capabilities.CapabilitiesType.STP_CAPABILITY.getValue() | b;
+ } else if (capability.equals(FlowFeatureCapabilityIpReasm.class)) {
+ b = Capabilities.CapabilitiesType.IP_REASSEM_CAPABILITY.getValue() | b;
+ } else if (capability.equals(FlowFeatureCapabilityQueueStats.class)) {
+ b = Capabilities.CapabilitiesType.QUEUE_STATS_CAPABILITY.getValue() | b;
+ } else if (capability.equals(FlowFeatureCapabilityArpMatchIp.class)) {
+ b = Capabilities.CapabilitiesType.ARP_MATCH_IP_CAPABILITY.getValue() | b;
+ }
+ }
+ return new Capabilities(b);
+ }
+
+ public static Buffers toADBuffers(final Long buffers) {
+ return new Buffers(buffers.intValue());
+ }
+}
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.sal.compatibility
-
-import org.opendaylight.controller.sal.core.Node
-import org.opendaylight.controller.sal.core.NodeConnector
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem
-
-import static com.google.common.base.Preconditions.*;
-import static extension org.opendaylight.controller.sal.common.util.Arguments.*;
-import static extension org.opendaylight.controller.sal.compatibility.ToSalConversionsUtils.*;
-
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
-import org.opendaylight.controller.sal.core.ConstructionException
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorUpdated
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorUpdated
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortFeatures
-import org.opendaylight.controller.sal.core.Bandwidth
-import org.opendaylight.controller.sal.core.AdvertisedBandwidth
-import org.opendaylight.controller.sal.core.SupportedBandwidth
-import org.opendaylight.controller.sal.core.PeerBandwidth
-import org.opendaylight.controller.sal.core.Name
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortConfig
-import org.opendaylight.controller.sal.core.Config
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.flow.capable.port.State
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeUpdated
-import java.util.HashSet
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeUpdated
-import org.opendaylight.controller.sal.core.Tables
-import java.util.List
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FeatureCapability
-import org.opendaylight.controller.sal.core.Buffers
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityFlowStats
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityTableStats
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityIpReasm
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityPortStats
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityStp
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityQueueStats
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityArpMatchIp
-import org.opendaylight.controller.sal.core.Capabilities
-import org.opendaylight.controller.sal.core.MacAddress
-import java.util.Date
-import org.opendaylight.controller.sal.core.TimeStamp
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowNodeConnector
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowNode
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector
-
-public class NodeMapping {
-
- public static val MD_SAL_TYPE = "MD_SAL";
- private static val NODE_CLASS = org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
- private static val NODECONNECTOR_CLASS = org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.
- NodeConnector;
-
- private new() {
- throw new UnsupportedOperationException("Utility class. Instantiation is not allowed.");
- }
-
- public static def toADNode(InstanceIdentifier<?> node) throws ConstructionException {
- return node.toNodeId.toADNode
- }
-
- public static def toADNode(NodeId id) {
- return new Node(MD_SAL_TYPE, id.toADNodeId);
- }
-
- public static def toNodeId(InstanceIdentifier<?> node) {
- checkNotNull(node);
- checkNotNull(node.getPath());
- checkArgument(node.getPath().size() >= 2);
- val arg = node.getPath().get(1);
- val item = arg.checkInstanceOf(IdentifiableItem);
- val nodeKey = item.getKey().checkInstanceOf(NodeKey);
- return nodeKey.id
- }
-
- public static def toADNodeId(NodeId nodeId) {
- checkNotNull(nodeId);
- return nodeId.value
- }
-
- public static def toADNodeConnector(NodeConnectorRef source) throws ConstructionException {
- checkNotNull(source);
- val InstanceIdentifier<?> path = checkNotNull(source.getValue());
- checkArgument(path.path.size() >= 3);
- val arg = path.getPath().get(2);
- val item = arg.checkInstanceOf(IdentifiableItem);
- val connectorKey = item.getKey().checkInstanceOf(NodeConnectorKey);
- return connectorKey.id.toADNodeConnector(path.toNodeId)
- }
-
- public static def toADNodeConnector(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId ncid,
- org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId nid) {
- return new NodeConnector(ncid.toNodeConnectorType(nid),
- ncid.toADNodeConnectorId(nid), nid.toADNode);
- }
-
- public static def toNodeConnectorType(NodeConnectorId ncId, NodeId nodeId) {
- if (ncId.equals(nodeId.toLocalNodeConnectorId)) {
- return NodeConnector.NodeConnectorIDType.SWSTACK
- } else if (ncId.equals(nodeId.toNormalNodeConnectorId)) {
- return NodeConnector.NodeConnectorIDType.HWPATH
- } else if (ncId.equals(nodeId.toControllerNodeConnectorId)) {
- return NodeConnector.NodeConnectorIDType.CONTROLLER
- }
- return MD_SAL_TYPE
- }
-
- public static def toADNodeConnectorId(NodeConnectorId nodeConnectorId, NodeId nodeId) {
- if (nodeConnectorId.equals(nodeId.toLocalNodeConnectorId) ||
- nodeConnectorId.equals(nodeId.toNormalNodeConnectorId) ||
- nodeConnectorId.equals(nodeId.toControllerNodeConnectorId)) {
- return NodeConnector.SPECIALNODECONNECTORID
- }
- return nodeConnectorId.value
- }
-
- public static def toControllerNodeConnectorId(NodeId node) {
- return new NodeConnectorId(node.value + ":" + 4294967293L)
- }
-
- public static def toLocalNodeConnectorId(NodeId node) {
- return new NodeConnectorId(node.value + ":" + 4294967294L)
- }
-
- public static def toNormalNodeConnectorId(NodeId node) {
- return new NodeConnectorId(node.value + ":" + 4294967290L)
- }
-
- public static def toNodeRef(Node node) {
- checkArgument(MD_SAL_TYPE.equals(node.getType()));
- var nodeId = node.ID.checkInstanceOf(String)
- val nodeKey = new NodeKey(new NodeId(nodeId));
- val nodePath = InstanceIdentifier.builder().node(Nodes).child(NODE_CLASS, nodeKey).toInstance();
- return new NodeRef(nodePath);
- }
-
- public static def toNodeConnectorRef(NodeConnector nodeConnector) {
- val node = nodeConnector.node.toNodeRef();
- val nodePath = node.getValue() as InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node>
- var NodeConnectorId nodeConnectorId
- if (nodeConnector.ID.equals(NodeConnector.SPECIALNODECONNECTORID)) {
- if (nodeConnector.type.equals(NodeConnector.NodeConnectorIDType.SWSTACK)) {
- nodeConnectorId = nodePath.toNodeId.toLocalNodeConnectorId
- } else if (nodeConnector.type.equals(NodeConnector.NodeConnectorIDType.HWPATH)) {
- nodeConnectorId = nodePath.toNodeId.toNormalNodeConnectorId
- } else if (nodeConnector.type.equals(NodeConnector.NodeConnectorIDType.CONTROLLER)) {
- nodeConnectorId = nodePath.toNodeId.toControllerNodeConnectorId
- }
- } else {
- nodeConnectorId = new NodeConnectorId(nodeConnector.ID.checkInstanceOf(String))
- }
- val connectorKey = new NodeConnectorKey(nodeConnectorId);
- val path = InstanceIdentifier.builder(nodePath).child(NODECONNECTOR_CLASS, connectorKey).toInstance();
- return new NodeConnectorRef(path);
- }
-
- public static def toADNode(NodeRef node) throws ConstructionException {
- return toADNode(node.getValue());
- }
-
- public static def toADNodeConnectorProperties(NodeConnectorUpdated nc) {
- val fcncu = nc.getAugmentation(FlowCapableNodeConnectorUpdated)
- if (fcncu != null) {
- return fcncu.toADNodeConnectorProperties
- }
- return new HashSet<org.opendaylight.controller.sal.core.Property>();
- }
-
- public static def toADNodeConnectorProperties(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector nc) {
- val fcnc = nc.getAugmentation(FlowCapableNodeConnector)
- if (fcnc != null) {
- return fcnc.toADNodeConnectorProperties
- }
- return new HashSet<org.opendaylight.controller.sal.core.Property>();
- }
-
- public static def toADNodeConnectorProperties(FlowNodeConnector fcncu) {
- val props = new HashSet<org.opendaylight.controller.sal.core.Property>();
- if (fcncu != null) {
- if (fcncu.currentFeature != null && fcncu.currentFeature.toAdBandwidth != null) {
- props.add(fcncu.currentFeature.toAdBandwidth)
- }
- if (fcncu.advertisedFeatures != null && fcncu.advertisedFeatures.toAdAdvertizedBandwidth != null) {
- props.add(fcncu.advertisedFeatures.toAdAdvertizedBandwidth)
- }
- if (fcncu.supported != null && fcncu.supported.toAdSupportedBandwidth != null) {
- props.add(fcncu.supported.toAdSupportedBandwidth)
- }
- if (fcncu.peerFeatures != null && fcncu.peerFeatures.toAdPeerBandwidth != null) {
- props.add(fcncu.peerFeatures.toAdPeerBandwidth)
- }
- if (fcncu.name != null && fcncu.name.toAdName != null) {
- props.add(fcncu.name.toAdName)
- }
- if (fcncu.configuration != null && fcncu.configuration.toAdConfig != null) {
- props.add(fcncu.configuration.toAdConfig)
- }
- if (fcncu.state != null && fcncu.state.toAdState != null) {
- props.add(fcncu.state.toAdState)
- }
- }
- return props
- }
-
- public static def toAdName(String name) {
- return new Name(name)
- }
-
- public static def toAdConfig(PortConfig pc) {
- var Config config;
- if (pc.PORTDOWN) {
- config = new Config(Config.ADMIN_DOWN)
- } else {
- config = new Config(Config.ADMIN_UP)
- }
- return config
- }
-
- public static def toAdState(State s) {
- var org.opendaylight.controller.sal.core.State state
- if (s.linkDown) {
- state = new org.opendaylight.controller.sal.core.State(org.opendaylight.controller.sal.core.State.EDGE_DOWN)
- } else {
- state = new org.opendaylight.controller.sal.core.State(org.opendaylight.controller.sal.core.State.EDGE_UP)
- }
- return state
- }
-
- public static def toAdBandwidth(PortFeatures pf) {
- var Bandwidth bw = null
- if (pf.isTenMbHd || pf.isTenMbFd) {
- bw = new Bandwidth(Bandwidth.BW10Mbps)
- } else if (pf.isHundredMbHd || pf.isHundredMbFd) {
- bw = new Bandwidth(Bandwidth.BW100Mbps)
- } else if (pf.isOneGbHd || pf.isOneGbFd) {
- bw = new Bandwidth(Bandwidth.BW1Gbps)
- } else if (pf.isOneGbFd) {
- bw = new Bandwidth(Bandwidth.BW10Gbps)
- } else if (pf.isTenGbFd) {
- bw = new Bandwidth(Bandwidth.BW10Gbps)
- } else if (pf.isFortyGbFd) {
- bw = new Bandwidth(Bandwidth.BW40Gbps)
- } else if (pf.isHundredGbFd) {
- bw = new Bandwidth(Bandwidth.BW100Gbps)
- } else if (pf.isOneTbFd) {
- bw = new Bandwidth(Bandwidth.BW1Tbps)
- }
- return bw;
- }
-
- public static def toAdAdvertizedBandwidth(PortFeatures pf) {
- var AdvertisedBandwidth abw
- val bw = pf.toAdBandwidth
- if (bw != null) {
- abw = new AdvertisedBandwidth(bw.value)
- }
- return abw
- }
-
- public static def toAdSupportedBandwidth(PortFeatures pf) {
- var SupportedBandwidth sbw
- val bw = pf.toAdBandwidth
- if (bw != null) {
- sbw = new SupportedBandwidth(bw.value)
- }
- return sbw
- }
-
- public static def toAdPeerBandwidth(PortFeatures pf) {
- var PeerBandwidth pbw
- val bw = pf.toAdBandwidth
- if (bw != null) {
- pbw = new PeerBandwidth(bw.value)
- }
- return pbw
- }
-
- public static def toADNodeProperties(NodeUpdated nu) {
- val fcnu = nu.getAugmentation(FlowCapableNodeUpdated)
- if (fcnu != null) {
- return fcnu.toADNodeProperties(nu.id)
- }
- return new HashSet<org.opendaylight.controller.sal.core.Property>();
-
- }
-
- public static def toADNodeProperties(FlowNode fcnu, NodeId id) {
- val props = new HashSet<org.opendaylight.controller.sal.core.Property>();
- if (fcnu != null) {
- props.add(toADTimestamp)
-
- // props.add(fcnu.supportedActions.toADActions) - TODO
- if (id != null) {
- props.add(id.toADMacAddress)
- }
- if (fcnu.switchFeatures != null) {
- if (fcnu.switchFeatures.maxTables != null) {
- props.add(fcnu.switchFeatures.maxTables.toADTables)
- }
- if (fcnu.switchFeatures.capabilities != null) {
- props.add(fcnu.switchFeatures.capabilities.toADCapabiliities)
- }
- if (fcnu.switchFeatures.maxBuffers != null) {
- props.add(fcnu.switchFeatures.maxBuffers.toADBuffers)
- }
- }
- }
- return props;
- }
-
- public static def toADTimestamp() {
- val date = new Date();
- val timestamp = new TimeStamp(date.time, "connectedSince")
- return timestamp;
- }
-
- public static def toADMacAddress(NodeId id) {
- return new MacAddress(Long.parseLong(id.value.replaceAll("openflow:", "")).longValue.bytesFromDpid)
- }
-
- public static def toADTables(Short tables) {
- return new Tables(tables.byteValue)
- }
-
- public static def toADCapabiliities(List<Class<? extends FeatureCapability>> capabilities) {
- var int b
- for (capability : capabilities) {
- if (capability.equals(FlowFeatureCapabilityFlowStats)) {
- b = Capabilities.CapabilitiesType.FLOW_STATS_CAPABILITY.value.bitwiseOr(b)
- } else if (capability.equals(FlowFeatureCapabilityTableStats)) {
- b = Capabilities.CapabilitiesType.TABLE_STATS_CAPABILITY.value.bitwiseOr(b)
- } else if (capability.equals(FlowFeatureCapabilityPortStats)) {
- b = Capabilities.CapabilitiesType.PORT_STATS_CAPABILITY.value.bitwiseOr(b)
- } else if (capability.equals(FlowFeatureCapabilityStp)) {
- b = Capabilities.CapabilitiesType.STP_CAPABILITY.value.bitwiseOr(b)
- } else if (capability.equals(FlowFeatureCapabilityIpReasm)) {
- b = Capabilities.CapabilitiesType.IP_REASSEM_CAPABILITY.value.bitwiseOr(b)
- } else if (capability.equals(FlowFeatureCapabilityQueueStats)) {
- b = Capabilities.CapabilitiesType.QUEUE_STATS_CAPABILITY.value.bitwiseOr(b)
- } else if (capability.equals(FlowFeatureCapabilityArpMatchIp)) {
- b = Capabilities.CapabilitiesType.ARP_MATCH_IP_CAPABILITY.value.bitwiseOr(b)
- }
- }
- return new Capabilities(b)
- }
-
- public static def toADBuffers(Long buffers) {
- return new Buffers(buffers.intValue)
- }
-
-}
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-service</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-management</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-broker-impl</artifactId>
- <version>1.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-service</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-inventory</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.xtend</groupId>
class NodeChangeCommiter implements OpendaylightInventoryListener {
+ static val LOG = LoggerFactory.getLogger(NodeChangeCommiter);
+
@Property
val FlowCapableInventoryProvider manager;
// Check path
val it = manager.startChange()
+
+ LOG.debug("removing node connector : " + ref.value.toString());
+
removeOperationalData(ref.value as InstanceIdentifier<? extends DataObject>);
commit()
}
data.addAugmentation(FlowCapableNodeConnector, augment)
}
+ LOG.debug("updating node connector : " + ref.value.toString());
+
putOperationalData(ref.value as InstanceIdentifier<NodeConnector>, data.build());
commit()
}
val ref = node.nodeRef;
val it = manager.startChange()
+ LOG.debug("removing node : " + ref.value.toString());
+
removeOperationalData(ref.value as InstanceIdentifier<? extends DataObject>);
commit()
}
data.addAugmentation(FlowCapableNode, augment)
}
+ LOG.debug("updating node : " + ref.value.toString());
+
putOperationalData(ref.value as InstanceIdentifier<Node>, data.build())
commit()
}
<dependency>
<groupId>org.opendaylight.yangtools.model</groupId>
<artifactId>opendaylight-l2-types</artifactId>
- <version>2013.08.27.3</version>
</dependency>
</dependencies>
<packaging>bundle</packaging>
<dependency>
<groupId>org.opendaylight.yangtools.model</groupId>
<artifactId>opendaylight-l2-types</artifactId>
- <version>2013.08.27.3</version>
</dependency>
</dependencies>
<packaging>bundle</packaging>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-inventory</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools.model</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-api</artifactId>
- <version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
- <version>${osgi.core.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-util</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-impl</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-util</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
- <version>${osgi.core.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-core-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-broker-impl</artifactId>
- <version>1.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-config</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<dependency>
<groupId>org.opendaylight.yangtools.model</groupId>
<artifactId>ietf-inet-types</artifactId>
- <version>2010.09.24.3</version>
</dependency>
<dependency>
- <groupId>org.opendaylight.yangtools.model</groupId>
- <artifactId>ietf-topology-l3-unicast-igp</artifactId>
- <version>2013.10.21.1</version>
- <scope>test</scope>
+ <groupId>org.opendaylight.yangtools.model</groupId>
+ <artifactId>ietf-topology-l3-unicast-igp</artifactId>
+ <scope>test</scope>
</dependency>
<dependency>
- <groupId>org.opendaylight.controller.model</groupId>
- <artifactId>model-flow-base</artifactId>
- <version>1.1-SNAPSHOT</version>
+ <groupId>org.opendaylight.controller.model</groupId>
+ <artifactId>model-flow-base</artifactId>
</dependency>
<dependency>
- <groupId>org.opendaylight.controller.model</groupId>
- <artifactId>model-flow-service</artifactId>
- <version>1.1-SNAPSHOT</version>
+ <groupId>org.opendaylight.controller.model</groupId>
+ <artifactId>model-flow-service</artifactId>
</dependency>
<dependency>
- <groupId>org.opendaylight.controller.model</groupId>
- <artifactId>model-flow-statistics</artifactId>
- <version>1.1-SNAPSHOT</version>
+ <groupId>org.opendaylight.controller.model</groupId>
+ <artifactId>model-flow-statistics</artifactId>
</dependency>
</dependencies>
</project>
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
import javassist.ClassPool;
CLASS_POOL);
public static final RuntimeCodeGenerator RPC_GENERATOR = RPC_GENERATOR_IMPL;
public static final NotificationInvokerFactory INVOKER_FACTORY = RPC_GENERATOR_IMPL.getInvokerFactory();
+
+ public static final int CORE_NOTIFICATION_THREADS = 4;
+ public static final int MAX_NOTIFICATION_THREADS = 32;
+ public static final int NOTIFICATION_THREAD_LIFE = 15;
+
private static ListeningExecutorService NOTIFICATION_EXECUTOR = null;
private static ListeningExecutorService COMMIT_EXECUTOR = null;
private static ListeningExecutorService CHANGE_EVENT_EXECUTOR = null;
+ /**
+ * @deprecated This method is only used from configuration modules and thus callers of it
+ * should use service injection to make the executor configurable.
+ */
+ @Deprecated
public static synchronized final ListeningExecutorService getDefaultNotificationExecutor() {
if (NOTIFICATION_EXECUTOR == null) {
- NOTIFICATION_EXECUTOR = createNamedExecutor("md-sal-binding-notification-%d");
+ ThreadFactory factory = new ThreadFactoryBuilder().setDaemon(true).setNameFormat("md-sal-binding-notification-%d").build();
+ ExecutorService executor = new ThreadPoolExecutor(CORE_NOTIFICATION_THREADS, MAX_NOTIFICATION_THREADS,
+ NOTIFICATION_THREAD_LIFE, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), factory);
+ NOTIFICATION_EXECUTOR = MoreExecutors.listeningDecorator(executor);
}
return NOTIFICATION_EXECUTOR;
}
public static synchronized final ListeningExecutorService getDefaultCommitExecutor() {
if (COMMIT_EXECUTOR == null) {
ThreadFactory factory = new ThreadFactoryBuilder().setDaemon(true).setNameFormat("md-sal-binding-commit-%d").build();
- /*
- * FIXME: this used to be newCacheThreadPool(), but MD-SAL does not have transaction
- * ordering guarantees, which means that using a concurrent threadpool results
- * in application data being committed in random order, potentially resulting
- * in inconsistent data being present. Once proper primitives are introduced,
- * concurrency can be reintroduced.
- */
+ /*
+ * FIXME: this used to be newCacheThreadPool(), but MD-SAL does not have transaction
+ * ordering guarantees, which means that using a concurrent threadpool results
+ * in application data being committed in random order, potentially resulting
+ * in inconsistent data being present. Once proper primitives are introduced,
+ * concurrency can be reintroduced.
+ */
ExecutorService executor = Executors.newSingleThreadExecutor(factory);
COMMIT_EXECUTOR = MoreExecutors.listeningDecorator(executor);
}
return COMMIT_EXECUTOR;
}
- private static ListeningExecutorService createNamedExecutor(String format) {
- ThreadFactory factory = new ThreadFactoryBuilder().setDaemon(true).setNameFormat(format).build();
- ExecutorService executor = Executors.newCachedThreadPool(factory);
- return MoreExecutors.listeningDecorator(executor);
- }
-
public static ExecutorService getDefaultChangeEventExecutor() {
if (CHANGE_EVENT_EXECUTOR == null) {
ThreadFactory factory = new ThreadFactoryBuilder().setDaemon(true).setNameFormat("md-sal-binding-change-%d").build();
package org.opendaylight.controller.sal.binding.impl\r
\r
import com.google.common.collect.HashMultimap\r
+import com.google.common.collect.ImmutableSet\r
import com.google.common.collect.Multimap\r
-import java.util.Collection\r
+import com.google.common.collect.Multimaps\r
import java.util.Collections\r
import java.util.concurrent.Callable\r
import java.util.concurrent.ExecutorService\r
+import java.util.concurrent.Future\r
+import java.util.Set\r
import org.opendaylight.controller.sal.binding.api.NotificationListener\r
import org.opendaylight.controller.sal.binding.api.NotificationProviderService\r
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService.NotificationInterestListener\r
+import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder\r
import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory.NotificationInvoker\r
import org.opendaylight.yangtools.concepts.AbstractObjectRegistration\r
import org.opendaylight.yangtools.concepts.ListenerRegistration\r
import org.opendaylight.yangtools.concepts.Registration\r
+import org.opendaylight.yangtools.concepts.util.ListenerRegistry\r
import org.opendaylight.yangtools.yang.binding.Notification\r
import org.slf4j.LoggerFactory\r
-import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder\rimport com.google.common.collect.Multimaps\r
-import org.opendaylight.yangtools.concepts.util.ListenerRegistry\r
-import org.opendaylight.controller.sal.binding.api.NotificationProviderService.NotificationInterestListener\rimport java.util.Set
-import com.google.common.collect.ImmutableSet
-import java.util.concurrent.Future
-
+\r
class NotificationBrokerImpl implements NotificationProviderService, AutoCloseable {\r
\r
val ListenerRegistry<NotificationInterestListener> interestListeners = ListenerRegistry.create;\r
notification.class.interfaces.filter[it != Notification && Notification.isAssignableFrom(it)]\r
}\r
\r
- @SuppressWarnings("unchecked")\r
- private def notifyAll(Collection<NotificationListener<?>> listeners, Notification notification) {\r
- listeners.forEach[(it as NotificationListener).onNotification(notification)]\r
- }\r
-\r
@Deprecated\r
override addNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener listener) {\r
throw new UnsupportedOperationException("Deprecated method. Use registerNotificationListener instead.");\r
submitAll(executor,tasks);\r
}\r
\r
- def submitAll(ExecutorService service, Set<NotifyTask> tasks) {
+ def submitAll(ExecutorService service, Set<NotifyTask> tasks) {\r
val ret = ImmutableSet.<Future<Object>>builder();\r
for(task : tasks) {\r
ret.add(service.submit(task));\r
}\r
- return ret.build();
+ return ret.build();\r
}\r
-\r
+ \r
override <T extends Notification> registerNotificationListener(Class<T> notificationType,\r
NotificationListener<T> listener) {\r
val reg = new GenericNotificationRegistration<T>(notificationType, listener, this);\r
private RpcProviderRegistryImpl baRpcRegistryImpl;
- private org.opendaylight.controller.sal.dom.broker.spi.RpcRouter biRouter;
-
private NotificationProviderService baNotifyService;
private NotificationPublishService domNotificationService;
baRpcRegistryImpl.registerRouterInstantiationListener(domToBindingRpcManager.getInstance());
baRpcRegistryImpl.registerGlobalRpcRegistrationListener(domToBindingRpcManager.getInstance());
}
- if (biRpcRegistry instanceof org.opendaylight.controller.sal.dom.broker.spi.RpcRouter) {
- biRouter = (org.opendaylight.controller.sal.dom.broker.spi.RpcRouter) biRpcRegistry;
- }
rpcForwarding = true;
}
}
@Override
public Future<RpcResult<?>> forwardToDomBroker(DataObject input) {
- if(biRouter != null) {
+ if(biRpcRegistry != null) {
CompositeNode xml = mappingService.toDataDom(input);
CompositeNode wrappedXml = ImmutableCompositeNode.create(rpc, ImmutableList.<Node<?>> of(xml));
- RpcResult<CompositeNode> result = biRouter.invokeRpc(rpc, wrappedXml);
+ RpcResult<CompositeNode> result = biRpcRegistry.invokeRpc(rpc, wrappedXml);
Object baResultValue = null;
if (result.getResult() != null) {
baResultValue = mappingService.dataObjectFromDataDom(outputClass.get(), result.getResult());
@Override
public Future<RpcResult<?>> forwardToDomBroker(DataObject input) {
- if(biRouter != null) {
+ if(biRpcRegistry != null) {
CompositeNode xml = mappingService.toDataDom(input);
CompositeNode wrappedXml = ImmutableCompositeNode.create(rpc,ImmutableList.<Node<?>>of(xml));
- RpcResult<CompositeNode> result = biRouter.invokeRpc(rpc, wrappedXml);
+ RpcResult<CompositeNode> result = biRpcRegistry.invokeRpc(rpc, wrappedXml);
Object baResultValue = null;
RpcResult<?> baResult = Rpcs.<Void>getRpcResult(result.isSuccessful(), null, result.getErrors());
return Futures.<RpcResult<?>>immediateFuture(baResult);
*/
package org.opendaylight.controller.sal.binding.impl.util
-import java.util.Map.Entry
-import org.opendaylight.yangtools.concepts.Path
-import java.util.Map
-import java.util.Set
+import com.google.common.collect.Multimap
import java.util.Collection
import java.util.HashSet
-import com.google.common.collect.Multimap
+import java.util.Map.Entry
+import org.opendaylight.yangtools.concepts.Path
class MapUtils {
public interface SimpleInput extends DataObject,Augmentable<SimpleInput> {
@RoutingContext(BaseIdentity.class)
- InstanceIdentifier getIdentifier();
+ InstanceIdentifier<?> getIdentifier();
}
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-api</artifactId>
- <version>0.2.4-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-container-native</artifactId>
<scope>test</scope>
- <version>${exam.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-broker-impl</artifactId>
- <version>1.1-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-broker-impl</artifactId>
- <version>1.1-SNAPSHOT</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-service</artifactId>
- <version>1.1-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-management</artifactId>
- <version>1.1-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<!-- Sonar jacoco plugin to get integration test coverage info -->
<sonar.jacoco.reportPath>../sal-binding-broker/target/jacoco.exec</sonar.jacoco.reportPath>
<sonar.jacoco.itReportPath>../sal-binding-broker/target/jacoco-it.exec</sonar.jacoco.itReportPath>
- <netconf.version>0.2.4-SNAPSHOT</netconf.version>
- <config.version>0.2.4-SNAPSHOT</config.version>
- <moxy.controller.version>2.5.0</moxy.controller.version>
</properties>
<build>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-broker-impl</artifactId>
- <version>1.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-container-native</artifactId>
- <version>${exam.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-junit4</artifactId>
- <version>${exam.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-netconf-connector</artifactId>
- <version>${netconf.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>yang-store-impl</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>logback-config</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-persister-impl</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-persister-file-xml-adapter</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.moxy</artifactId>
- <version>${moxy.controller.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.core</artifactId>
- <version>${moxy.controller.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netconf-impl</artifactId>
- <version>${netconf.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netconf-monitoring</artifactId>
- <version>${netconf.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netconf-client</artifactId>
- <version>${netconf.version}</version>
</dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-link-mvn</artifactId>
- <version>${exam.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>equinoxSDK381</groupId>
<artifactId>org.eclipse.osgi</artifactId>
- <version>3.8.1.v20120830-144521</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
- <version>1.7.2</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
- <version>1.0.9</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
- <version>1.0.9</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-service</artifactId>
- <version>1.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-manager</artifactId>
- <version>0.2.4-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-management</artifactId>
- <version>1.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
public static final String CONTROLLER_MODELS = "org.opendaylight.controller.model";
public static final String YANGTOOLS_MODELS = "org.opendaylight.yangtools.model";
- private static final String OPENDAYLIGHT_SNAPSHOT = "http://nexus.opendaylight.org/content/repositories/opendaylight.snapshot/";
- private static final String OPENDAYLIGHT_RELEASE = "http://nexus.opendaylight.org/content/repositories/opendaylight.release/";
public static Option mdSalCoreBundles() {
return new DefaultCompositeOption( //
*/
package org.opendaylight.controller.test.sal.binding.it;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import java.util.concurrent.Future;
import org.junit.Before;
import org.junit.Test;
import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
-import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
+import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer;
import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
import org.opendaylight.controller.sal.core.api.Broker;
public class DataServiceTest extends AbstractTest {
protected DataBrokerService consumerDataService;
-
-
+
+
@Inject
Broker broker2;
assertNotNull(consumerDataService);
-
+
DataModificationTransaction transaction = consumerDataService.beginTransaction();
assertNotNull(transaction);
-
+
NodeRef node1 = createNodeRef("0");
DataObject node = consumerDataService.readConfigurationData(node1.getValue());
assertNull(node);
Node nodeData1 = createNode("0");
-
+
transaction.putConfigurationData(node1.getValue(), nodeData1);
Future<RpcResult<TransactionStatus>> commitResult = transaction.commit();
assertNotNull(commitResult);
-
+
RpcResult<TransactionStatus> result = commitResult.get();
-
+
assertNotNull(result);
assertNotNull(result.getResult());
assertEquals(TransactionStatus.COMMITED, result.getResult());
-
+
Node readedData = (Node) consumerDataService.readConfigurationData(node1.getValue());
assertNotNull(readedData);
assertEquals(nodeData1.getKey(), readedData.getKey());
-
-
+
+
DataModificationTransaction transaction2 = consumerDataService.beginTransaction();
assertNotNull(transaction);
-
+
transaction2.removeConfigurationData(node1.getValue());
-
+
Future<RpcResult<TransactionStatus>> commitResult2 = transaction2.commit();
assertNotNull(commitResult2);
-
+
RpcResult<TransactionStatus> result2 = commitResult2.get();
-
+
assertNotNull(result2);
assertNotNull(result2.getResult());
assertEquals(TransactionStatus.COMMITED, result2.getResult());
-
+
DataObject readedData2 = consumerDataService.readConfigurationData(node1.getValue());
assertNull(readedData2);
-
-
+
+
}
-
+
private static NodeRef createNodeRef(String string) {
NodeKey key = new NodeKey(new NodeId(string));
- InstanceIdentifier<Node> path = InstanceIdentifier.builder().node(Nodes.class).node(Node.class, key)
- .toInstance();
+ InstanceIdentifier<Node> path = InstanceIdentifier.builder(Nodes.class).child(Node.class, key).build();
return new NodeRef(path);
}
-
+
private static Node createNode(String string) {
NodeBuilder ret = new NodeBuilder();
NodeId id = new NodeId(string);
*/
private static NodeRef createNodeRef(String string) {
NodeKey key = new NodeKey(new NodeId(string));
- InstanceIdentifier<Node> path = InstanceIdentifier.builder().node(Nodes.class).node(Node.class, key)
- .toInstance();
+ InstanceIdentifier<Node> path = InstanceIdentifier.builder(Nodes.class).child(Node.class, key).build();
return new NodeRef(path);
}
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
- <version>5.0.0</version>
</dependency>
</dependencies>
<packaging>bundle</packaging>
package org.opendaylight.controller.md.sal.common.api;
public enum TransactionStatus {
+ /**
+ * The transaction has been freshly allocated. The user is still accessing
+ * it and it has not been sealed.
+ */
NEW,
+ /**
+ * The transaction has been completed by the user and sealed. It is currently
+ * awaiting execution.
+ */
SUBMITED,
+ /**
+ * The transaction has been successfully committed to backing store.
+ */
COMMITED,
+ /**
+ * The transaction has failed to commit due to some underlying issue.
+ */
FAILED,
- CANCELED
+ /**
+ * Currently unused.
+ */
+ CANCELED,
}
import java.util.Map;
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;
+import org.opendaylight.yangtools.concepts.Path;
-public interface DataChange<P/* extends Path<P> */, D> {
+public interface DataChange<P extends Path<P>, D> {
/**
* Returns a map of paths and newly created objects
- *
+ *
* @return map of paths and newly created objects
*/
Map<P, D> getCreatedOperationalData();
/**
* Returns a map of paths and newly created objects
- *
+ *
* @return map of paths and newly created objects
*/
Map<P, D> getCreatedConfigurationData();
/**
* 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<P, D> 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<P, D> 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<P> 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<P> getRemovedOperationalData();
/**
* 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<P, D> getOriginalConfigurationData();
/**
* 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<P, D> getOriginalOperationalData();
package org.opendaylight.controller.md.sal.common.api.data;
import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.concepts.Path;
-public interface DataChangeEvent<P,D> extends DataChange<P, D>, Immutable {
+public interface DataChangeEvent<P extends Path<P>,D> extends DataChange<P, D>, Immutable {
/**
* Returns a orignal subtree of data, which starts at the path
* where listener was registered.
- *
+ *
*/
D getOriginalConfigurationSubtree();
/**
* Returns a new subtree of data, which starts at the path
* where listener was registered.
- *
+ *
*/
D getOriginalOperationalSubtree();
-
-
-
+
+
+
/**
* Returns a updated subtree of data, which starts at the path
* where listener was registered.
- *
+ *
*/
D getUpdatedConfigurationSubtree();
/**
* Returns a udpated subtree of data, which starts at the path
* where listener was registered.
- *
+ *
*/
D getUpdatedOperationalSubtree();
}
import java.util.EventListener;
-// FIXME: After 0.6 Release of YANGTools refactor to use Path marker interface for arguments.
-// import org.opendaylight.yangtools.concepts.Path;
+import org.opendaylight.yangtools.concepts.Path;
-public interface DataChangeListener<P/* extends Path<P> */,D> extends EventListener {
+public interface DataChangeListener<P extends Path<P>, D> extends EventListener {
void onDataChanged(DataChangeEvent<P, D> change);
}
*/
package org.opendaylight.controller.md.sal.common.api.data;
-
import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.concepts.Path;
-// FIXME: After 0.6 Release of YANGTools refactor to use Path marker interface for arguments.
-// import org.opendaylight.yangtools.concepts.Path;
-public interface DataChangePublisher<P/* extends Path<P> */,D, L extends DataChangeListener<P,D>> {
+public interface DataChangePublisher<P extends Path<P>, D, L extends DataChangeListener<P,D>> {
ListenerRegistration<L> registerDataChangeListener(P path, L listener);
package org.opendaylight.controller.md.sal.common.api.data;
import org.opendaylight.controller.sal.common.DataStoreIdentifier;
-// FIXME: After 0.6 Release of YANGTools refactor to use Path marker interface for arguments.
-// import org.opendaylight.yangtools.concepts.Path;
+import org.opendaylight.yangtools.concepts.Path;
import org.opendaylight.yangtools.yang.common.RpcResult;
/**
* Two phase commit handler (cohort) of the two-phase commit protocol of data.
- *
+ *
* <p>
* The provider should expose the implementation of DataCommitHandler if it's
* functionality depends on any subset of data stored in data repositories, in
* order to participate in {@link DataBrokerService#commit(DataStoreIdentifier)
* operation.
- *
+ *
* <p>
* Operations of two-phase commit handlers should not change data in data store,
* this is responsibility of the coordinator (broker or some component of the
* broker).
- *
+ *
* The commit handlers are responsible for changing the internal state of the
* provider to reflect the commited changes in data.
- *
+ *
* <h3>Two-phase commit</h3>
- *
+ *
* <h4>Commit Request Phase</h4>
- *
+ *
* <ol>
* <li> <code>Consumer</code> edits data by invocation of
* <code>DataBrokerService.editCandidateData(DataStoreIdentifier, DataRoot)</code>
* </ol>
* <li><code>Broker</code> starts a commit finish phase
* </ol>
- *
+ *
* <h4>Commit Finish Phase</h4>
- *
+ *
* <ol>
* <li>For each <code>CommitTransaction</code> from Commit Request phase
* <ol>
* <li>If error occured, the broker starts a commit rollback phase.
* </ul>
* </ol>
- *
+ *
* <h4>Commit Rollback Phase</h4>
* <li>For each <code>DataCommitTransaction</code> from Commit Request phase
* <ol>
* <li>The provider rollbacks a commit and returns an {@link RpcResult} of
* rollback. </ol>
* <li>Broker returns a error result to the consumer.
- *
+ *
* @param <P> Class representing a path
* @param <D> Superclass from which all data objects are derived from.
*/
-public interface DataCommitHandler<P/* extends Path<P> */,D> {
+public interface DataCommitHandler<P extends Path<P>, D> {
+
-
DataCommitTransaction<P, D> requestCommit(DataModification<P,D> modification);
- public interface DataCommitTransaction<P/* extends Path<P> */,D> {
+ public interface DataCommitTransaction<P extends Path<P>, D> {
DataModification<P,D> getModification();
/**
- *
+ *
* Finishes a commit.
- *
+ *
* This callback is invoked by commit coordinator to finish commit action.
- *
+ *
* The implementation is required to finish transaction or return unsuccessful
* rpc result if something went wrong.
- *
+ *
* The provider (commit handler) should apply all changes to its state
* which are a result of data change-
- *
+ *
* @return
*/
RpcResult<Void> finish() throws IllegalStateException;
/**
* Rollbacks a commit.
- *
+ *
* This callback is invoked by commit coordinator to finish commit action.
- *
+ *
* The provider (commit handler) should rollback all changes to its state
* which were a result of previous request commit.
- *
+ *
* @return
* @throws IllegalStateException
* If the method is invoked after {@link #finish()}
import java.util.concurrent.Future;
import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.yangtools.concepts.Path;
import org.opendaylight.yangtools.yang.common.RpcResult;
-//FIXME: After 0.6 Release of YANGTools refactor to use Path marker interface for arguments.
-//import org.opendaylight.yangtools.concepts.Path;
-public interface DataModification<P/* extends Path<P> */, D> extends DataChange<P, D>, DataReader<P, D> {
+public interface DataModification<P extends Path<P>, D> extends DataChange<P, D>, DataReader<P, D> {
/**
* Returns transaction identifier
*/
package org.opendaylight.controller.md.sal.common.api.data;
-// FIXME: After 0.6 Release of YANGTools refactor to use Path marker interface for arguments.
-// import org.opendaylight.yangtools.concepts.Path;
+import org.opendaylight.yangtools.concepts.Path;
-public interface DataModificationTransactionFactory<P/* extends Path<P> */,D> {
+public interface DataModificationTransactionFactory<P extends Path<P> ,D> {
DataModification<P, D> beginTransaction();
}
*/
package org.opendaylight.controller.md.sal.common.api.data;
-// FIXME: After 0.6 Release of YANGTools refactor to use Path marker interface for arguments.
-// import org.opendaylight.yangtools.concepts.Path;
+import org.opendaylight.yangtools.concepts.Path;
-public interface DataProvider<P/* extends Path<P> */,D> extends DataReader<P, D> {
+public interface DataProvider<P extends Path<P>, D> extends DataReader<P, D> {
}
*/
package org.opendaylight.controller.md.sal.common.api.data;
-// FIXME: After 0.6 Release of YANGTools refactor to use Path marker interface for arguments.
-// import org.opendaylight.yangtools.concepts.Path;
+import org.opendaylight.yangtools.concepts.Path;
/**
* Reader for reading YANG subtrees based on their path.
- *
+ *
* Reader is requested to return object at specified path and all it's subnodes
* known to the reader or null if node is not found in this reader.
*
* @param <P> Path Type
* @param <D> Data Type
*/
-public interface DataReader<P/* extends Path<P> */,D> {
+public interface DataReader<P extends Path<P> ,D> {
/**
* Reads data from Operational data store located at provided path
- *
+ *
* @param path Path to data
* @return
*/
*/
package org.opendaylight.controller.md.sal.common.api.data;
-public interface DataStore<P, D> extends //
+import org.opendaylight.yangtools.concepts.Path;
+
+public interface DataStore<P extends Path<P>, D> extends //
DataReader<P, D>, //
DataModificationTransactionFactory<P, D> {
*/
package org.opendaylight.controller.md.sal.common.api.data;
+import org.opendaylight.yangtools.concepts.Path;
+
/**
* A chain of transactions. Transactions in a chain need to be committed in sequence and each
* transaction should see the effects of previous transactions as if they happened. A chain
* makes no guarantees of atomicity, in fact transactions are committed as soon as possible.
*/
-public interface TransactionChain<P/* extends Path<P> */, D> extends AutoCloseable {
+public interface TransactionChain<P extends Path<P>, D> extends AutoCloseable {
/**
* Create a new transaction which will continue the chain. The previous transaction
* has to be either COMMITTED or CANCELLED.
*/
package org.opendaylight.controller.md.sal.common.api.data;
+import org.opendaylight.yangtools.concepts.Path;
+
/**
* Interface for creating transaction chains.
*/
-public interface TransactionChainFactory<P/* extends Path<P> */, D> {
+public interface TransactionChainFactory<P extends Path<P>, D> {
/**
* Create a new transaction chain. The chain will be initialized to read
* from its backing datastore, with no outstanding transaction. Listener
package org.opendaylight.controller.md.sal.common.api.routing;
import org.opendaylight.yangtools.concepts.Mutable;
-// FIXME: After 0.6 Release of YANGTools refactor to use Path marker interface for arguments.
-// import org.opendaylight.yangtools.concepts.Path;
+import org.opendaylight.yangtools.concepts.Path;
-public interface MutableRoutingTable<C,P/* extends Path<P> */,T> extends RoutingTable<C,P,T>, Mutable {
+public interface MutableRoutingTable<C, P extends Path<P>, T> extends RoutingTable<C,P,T>, Mutable {
void setDefaultRoute(T target);
void updateRoute(P path,T target);
*/
package org.opendaylight.controller.md.sal.common.api.routing;
-// FIXME: After 0.6 Release of YANGTools refactor to use Path marker interface for arguments.
-// import org.opendaylight.yangtools.concepts.Path;
+import org.opendaylight.yangtools.concepts.Path;
import org.opendaylight.yangtools.concepts.Registration;
-public interface RoutedRegistration<C,P/* extends Path<P> */,S> extends Registration<S> {
+public interface RoutedRegistration<C, P extends Path<P>, S> extends Registration<S> {
void registerPath(C context, P path);
void unregisterPath(C context, P path);
import java.util.Map;
-// FIXME: After 0.6 Release of YANGTools refactor to use Path marker interface for arguments.
-// import org.opendaylight.yangtools.concepts.Path;
+import org.opendaylight.yangtools.concepts.Path;
-public interface RoutingTable<C,P/* extends Path<P> */,T> {
+public interface RoutingTable<C, P extends Path<P>, T> {
C getIdentifier();
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-util</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
import com.google.common.collect.ImmutableSet;
public class RoutingUtils {
-
+
public static <C,P> RouteChange<C,P> removalChange(C context,P path) {
final ImmutableMap<C, Set<P>> announcements = ImmutableMap.<C,Set<P>>of();
final ImmutableMap<C, Set<P>> removals = ImmutableMap.<C,Set<P>>of(context, ImmutableSet.of(path));
return new RouteChangeImpl<C,P>(announcements, removals);
}
-
+
public static <C,P> RouteChange<C,P> announcementChange(C context,P path) {
final ImmutableMap<C, Set<P>> announcements = ImmutableMap.<C,Set<P>>of(context, ImmutableSet.of(path));
final ImmutableMap<C, Set<P>> removals = ImmutableMap.<C,Set<P>>of();
return new RouteChangeImpl<C,P>(announcements, removals);
}
-
-
+
+
public static <C,P> RouteChange<C,P> change(Map<C, Set<P>> announcements,
Map<C, Set<P>> removals) {
final ImmutableMap<C, Set<P>> immutableAnnouncements = ImmutableMap.<C,Set<P>>copyOf(announcements);
final ImmutableMap<C, Set<P>> immutableRemovals = ImmutableMap.<C,Set<P>>copyOf(removals);
return new RouteChangeImpl<C,P>(immutableAnnouncements, immutableRemovals);
}
-
-
+
+
private static class RouteChangeImpl<C,P> implements RouteChange<C, P> {
private final Map<C, Set<P>> removal;
private final Map<C, Set<P>> announcement;
- public RouteChangeImpl(ImmutableMap<C, Set<P>> removal, ImmutableMap<C, Set<P>> announcement) {
+ public RouteChangeImpl(ImmutableMap<C, Set<P>> announcement, ImmutableMap<C, Set<P>> removal) {
super();
this.removal = removal;
this.announcement = announcement;
public Map<C, Set<P>> getAnnouncements() {
return announcement;
}
-
+
@Override
public Map<C, Set<P>> getRemovals() {
return removal;
if (getClass() != obj.getClass()) {
return false;
}
- RouteChangeImpl other = (RouteChangeImpl) obj;
+ RouteChangeImpl<?, ?> other = (RouteChangeImpl<?, ?>) obj;
if (announcement == null) {
if (other.announcement != null)
return false;
}
-
+
}
Preconditions.checkNotNull(transaction);
transaction.changeStatus(TransactionStatus.SUBMITED);
final TwoPhaseCommit<P, D, DCL> task = new TwoPhaseCommit<P, D, DCL>(transaction, this);
- ;
+
this.getSubmittedTransactionsCount().getAndIncrement();
return this.getExecutor().submit(task);
}
log.trace("Transaction: {} Affected Subtrees:", transactionId, changedPaths);
+ // The transaction has no effects, let's just shortcut it
+ if (changedPaths.isEmpty()) {
+ dataBroker.getFinishedTransactionsCount().getAndIncrement();
+ transaction.changeStatus(TransactionStatus.COMMITED);
+
+ log.trace("Transaction: {} Finished successfully (no effects).", transactionId);
+
+ return Rpcs.<TransactionStatus> getRpcResult(true, TransactionStatus.COMMITED,
+ Collections.<RpcError> emptySet());
+ }
+
final ImmutableList.Builder<ListenerStateCapture<P, D, DCL>> listenersBuilder = ImmutableList.builder();
listenersBuilder.addAll(dataBroker.affectedListeners(changedPaths));
filterProbablyAffectedListeners(dataBroker.probablyAffectedListeners(changedPaths),listenersBuilder);
@Override
public void run() {
for (final ListenerStateCapture<P, D, DCL> listenerSet : listeners) {
- {
- DataChangeEvent<P, D> changeEvent = listenerSet.createEvent(transaction);
- for (final DataChangeListenerRegistration<P, D, DCL> listener : listenerSet.getListeners()) {
- try {
- listener.getInstance().onDataChanged(changeEvent);
- } catch (Exception e) {
- log.error("Unhandled exception when invoking listener {}", listener);
- }
+ DataChangeEvent<P, D> changeEvent = listenerSet.createEvent(transaction);
+ for (final DataChangeListenerRegistration<P, D, DCL> listener : listenerSet.getListeners()) {
+ try {
+ listener.getInstance().onDataChanged(changeEvent);
+ } catch (Exception e) {
+ log.error("Unhandled exception when invoking listener {}", listener, e);
}
}
}
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-api</artifactId>
- <version>${project.version}</version>
</dependency>
</dependencies>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-core-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
-
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-api</artifactId>
- <version>0.2.4-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-api</artifactId>
- <version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
- <version>5.0.0</version>
</dependency>
</dependencies>
<packaging>bundle</packaging>
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
-public interface RpcProvisionRegistry extends BrokerService, RouteChangePublisher<RpcRoutingContext, InstanceIdentifier> {
+public interface RpcProvisionRegistry extends RpcImplementation, BrokerService, RouteChangePublisher<RpcRoutingContext, InstanceIdentifier> {
/**
* Registers an implementation of the rpc.
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-core-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-util</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-impl</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-core-spi</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-api</artifactId>
- <version>0.2.4-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
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.md.sal.common.api.routing.RouteChangeListener
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.controller.sal.core.api.RpcImplementation
+import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry
+import org.opendaylight.controller.sal.core.api.RpcRegistrationListener
+import org.opendaylight.controller.sal.core.api.RpcRoutingContext
+import org.opendaylight.controller.sal.dom.broker.spi.RpcRouter
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.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.sal.core.api.RpcProvisionRegistry
-import org.opendaylight.controller.sal.core.api.RpcImplementation
-import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener
-import org.opendaylight.controller.sal.core.api.RpcRoutingContext
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
public class BrokerImpl implements Broker, RpcProvisionRegistry, AutoCloseable {
private static val log = LoggerFactory.getLogger(BrokerImpl);
return session;
}
- protected def Future<RpcResult<CompositeNode>> invokeRpc(QName rpc, CompositeNode input) {
+ protected def Future<RpcResult<CompositeNode>> invokeRpcAsync(QName rpc, CompositeNode input) {
val result = executor.submit([|router.invokeRpc(rpc, input)] as Callable<RpcResult<CompositeNode>>);
return result;
}
override <L extends RouteChangeListener<RpcRoutingContext, InstanceIdentifier>> registerRouteChangeListener(L listener) {
return router.registerRouteChangeListener(listener);
}
+
+ override invokeRpc(QName rpc,CompositeNode input){
+ return router.invokeRpc(rpc,input)
+ }
+
+ override getSupportedRpcs() {
+ return router.getSupportedRpcs();
+ }
}
}
override rpc(QName rpc, CompositeNode input) {
- return broker.invokeRpc(rpc, input);
+ return broker.invokeRpcAsync(rpc, input);
}
override <T extends BrokerService> T getService(Class<T> service) {
L listener) {
return rpcs.registerRouteChangeListener(listener);
}
+
+
}
*/
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
-import org.opendaylight.controller.md.sal.common.api.data.DataReader
-import org.opendaylight.yangtools.yang.common.QName
import java.net.URI
-import java.util.List
-import org.opendaylight.yangtools.yang.data.api.Node
import java.util.ArrayList
-import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
-import java.util.Map
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier
-import org.opendaylight.yangtools.yang.data.api.SimpleNode
+import java.util.Collection
import java.util.Collections
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates
import java.util.HashMap
-import static com.google.common.base.Preconditions.*;
-import java.util.Collection
-import java.util.Set
+import java.util.Map
import java.util.Map.Entry
-import org.slf4j.LoggerFactory
+import java.util.Set
+import org.opendaylight.controller.md.sal.common.impl.routing.AbstractDataReadRouter
+import org.opendaylight.yangtools.yang.common.QName
+import org.opendaylight.yangtools.yang.data.api.CompositeNode
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument
+import org.opendaylight.yangtools.yang.data.api.Node
+import org.opendaylight.yangtools.yang.data.api.SimpleNode
import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
+import org.slf4j.LoggerFactory
+
+import static com.google.common.base.Preconditions.*
class DataReaderRouter extends AbstractDataReadRouter<InstanceIdentifier, CompositeNode> {
private static val LOG = LoggerFactory.getLogger(DataReaderRouter);
var name = pathArgument?.nodeType;
val nodes = new ArrayList<Node<?>>();
val keyNodes = new HashMap<QName, SimpleNode<?>>();
- val iterator = data.iterator;
for(dataBit : data) {
try {
if(pathArgument != null && dataBit != null) {
import org.opendaylight.yangtools.yang.data.api.CompositeNode
import org.opendaylight.controller.sal.core.api.data.DataStore
import java.util.HashSet
+import org.slf4j.LoggerFactory
+import org.slf4j.Logger
-class HashMapDataStore implements DataStore, AutoCloseable {
-
+final class HashMapDataStore implements DataStore, AutoCloseable {
+ private val Logger LOG = LoggerFactory.getLogger(HashMapDataStore)
val Map<InstanceIdentifier, CompositeNode> configuration = new ConcurrentHashMap();
val Map<InstanceIdentifier, CompositeNode> operational = new ConcurrentHashMap();
override containsConfigurationPath(InstanceIdentifier path) {
- throw new UnsupportedOperationException("TODO: auto-generated method stub")
-
+ return configuration.containsKey(path)
}
override containsOperationalPath(InstanceIdentifier path) {
- throw new UnsupportedOperationException("TODO: auto-generated method stub")
+ return operational.containsKey(path)
}
override getStoredConfigurationPaths() {
}
override readConfigurationData(InstanceIdentifier path) {
+ LOG.trace("Reading configuration path {}", path)
configuration.get(path);
}
override readOperationalData(InstanceIdentifier path) {
+ LOG.trace("Reading operational path {}", path)
operational.get(path);
}
def RpcResult<Void> finish(HashMapDataStoreTransaction transaction) {
val modification = transaction.modification;
for (removal : modification.removedConfigurationData) {
+ LOG.trace("Removing configuration path {}", removal)
remove(configuration,removal);
}
for (removal : modification.removedOperationalData) {
+ LOG.trace("Removing operational path {}", removal)
remove(operational,removal);
}
+ if (LOG.isTraceEnabled()) {
+ for (a : modification.updatedConfigurationData.keySet) {
+ LOG.trace("Adding configuration path {}", a)
+ }
+ for (a : modification.updatedOperationalData.keySet) {
+ LOG.trace("Adding operational path {}", a)
+ }
+ }
configuration.putAll(modification.updatedConfigurationData);
operational.putAll(modification.updatedOperationalData);
}
}
for(pathToRemove : affected) {
+ LOG.trace("Removed path {}", pathToRemove)
map.remove(pathToRemove);
}
protected CompositeNode mergeData(InstanceIdentifier path, CompositeNode stored, CompositeNode modified,
boolean config) {
- long startTime = System.nanoTime();
+ // long startTime = System.nanoTime();
try {
DataSchemaNode node = schemaNodeFor(path);
return YangDataOperations.merge(node, stored, modified, config);
import org.opendaylight.controller.sal.core.api.RpcRoutingContext;
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;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.osgi.framework.ServiceReference;
+import java.util.Set;
+
public class RpcProvisionRegistryProxy extends AbstractBrokerServiceProxy<RpcProvisionRegistry>
implements RpcProvisionRegistry {
public <L extends RouteChangeListener<RpcRoutingContext, InstanceIdentifier>> ListenerRegistration<L> registerRouteChangeListener(L listener) {
return getDelegate().registerRouteChangeListener(listener);
}
+
+
+ @Override
+ public Set<QName> getSupportedRpcs() {
+ return getDelegate().getSupportedRpcs();
+ }
+
+ @Override
+ public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input) {
+ return getDelegate().invokeRpc(rpc,input);
+ }
}
throw new IllegalArgumentException("Supplied node is not data node container.");
}
- private def static checkConfigurational(DataSchemaNode node, boolean config) {
- if (config) {
- checkArgument(node.configuration, "Supplied composite node is not configurational.");
- }
- }
-
private static dispatch def Iterable<? extends Node<?>> mergeMultiple(LeafSchemaNode node, List<Node<?>> original,
List<Node<?>> modified, boolean configurational) {
checkArgument(original.size === 1);
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-core-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
</dependencies>
<packaging>bundle</packaging>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netty-threadgroup-config</artifactId>
- <version>0.2.4-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<groupId>org.opendaylight.controller</groupId>
<artifactId>logback-config</artifactId>
<scope>test</scope>
- <version>${netconf.version}</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-broker-impl</artifactId>
- <version>1.1-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-broker-impl</artifactId>
- <version>1.1-SNAPSHOT</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>ietf-netconf-monitoring</artifactId>
- <version>0.2.4-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools.model</groupId>
<artifactId>ietf-inet-types</artifactId>
- <version>2010.09.24.3</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>threadpool-config-api</artifactId>
- <version>0.2.4-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netty-config-api</artifactId>
- <version>0.2.4-SNAPSHOT</version>
</dependency>
</dependencies>
*/
package org.opendaylight.controller.sal.connect.netconf;
-import static org.opendaylight.controller.sal.connect.netconf.NetconfMapping.NETCONF_ACTION_QNAME;
import static org.opendaylight.controller.sal.connect.netconf.NetconfMapping.NETCONF_CANDIDATE_QNAME;
import static org.opendaylight.controller.sal.connect.netconf.NetconfMapping.NETCONF_COMMIT_QNAME;
import static org.opendaylight.controller.sal.connect.netconf.NetconfMapping.NETCONF_CONFIG_QNAME;
import static org.opendaylight.controller.sal.connect.netconf.NetconfMapping.NETCONF_EDIT_CONFIG_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.NetconfMapping.NETCONF_OPERATION_QNAME;
import static org.opendaylight.controller.sal.connect.netconf.NetconfMapping.NETCONF_RUNNING_QNAME;
import static org.opendaylight.controller.sal.connect.netconf.NetconfMapping.NETCONF_TARGET_QNAME;
public void prepare() {
for (InstanceIdentifier toRemove : modification.getRemovedConfigurationData()) {
- sendRemove(toRemove);
+ sendDelete(toRemove);
}
for(Entry<InstanceIdentifier, CompositeNode> toUpdate : modification.getUpdatedConfigurationData().entrySet()) {
sendMerge(toUpdate.getKey(),toUpdate.getValue());
sendEditRpc(createEditStructure(key, Optional.<String>absent(), Optional.of(value)));
}
- private void sendRemove(InstanceIdentifier toRemove) {
- sendEditRpc(createEditStructure(toRemove, Optional.of("remove"), Optional.<CompositeNode> absent()));
+ private void sendDelete(InstanceIdentifier toDelete) {
+ sendEditRpc(createEditStructure(toDelete, Optional.of("delete"), Optional.<CompositeNode> absent()));
}
private void sendEditRpc(CompositeNode editStructure) {
return ret;
}
- private CompositeNode createEditStructure(InstanceIdentifier dataPath, Optional<String> action,
+ private CompositeNode createEditStructure(InstanceIdentifier dataPath, Optional<String> operation,
Optional<CompositeNode> lastChildOverride) {
List<PathArgument> path = dataPath.getPath();
List<PathArgument> reversed = Lists.reverse(path);
}
if (isLast) {
- if (action.isPresent()) {
- builder.setAttribute(NETCONF_ACTION_QNAME, action.get());
+ if (operation.isPresent()) {
+ builder.setAttribute(NETCONF_OPERATION_QNAME, operation.get());
}
if (lastChildOverride.isPresent()) {
List<Node<?>> children = lastChildOverride.get().getChildren();
}
@Override
- public RpcResult<Void> finish() throws IllegalStateException {
+ public RpcResult<Void> finish() {
CompositeNodeBuilder<ImmutableCompositeNode> commitInput = ImmutableCompositeNode.builder();
commitInput.setQName(NETCONF_COMMIT_QNAME);
RpcResult<?> rpcResult = device.invokeRpc(NetconfMapping.NETCONF_COMMIT_QNAME, commitInput.toInstance());
import org.opendaylight.yangtools.yang.data.api.Node
import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode
-import org.opendaylight.yangtools.yang.data.impl.NodeUtils
import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlDocumentUtils
import org.opendaylight.yangtools.yang.model.api.NotificationDefinition
public static val NETCONF_GET_CONFIG_QNAME = QName.create(NETCONF_QNAME, "get-config");
public static val NETCONF_EDIT_CONFIG_QNAME = QName.create(NETCONF_QNAME, "edit-config");
public static val NETCONF_DELETE_CONFIG_QNAME = QName.create(NETCONF_QNAME, "delete-config");
- public static val NETCONF_ACTION_QNAME = QName.create(NETCONF_QNAME, "action");
+ public static val NETCONF_OPERATION_QNAME = QName.create(NETCONF_QNAME, "operation");
public static val NETCONF_COMMIT_QNAME = QName.create(NETCONF_QNAME, "commit");
public static val NETCONF_CONFIG_QNAME = QName.create(NETCONF_QNAME, "config");
for (arg : argument.keyValues.entrySet) {
list.add = new SimpleNodeTOImpl(arg.key, null, arg.value);
}
+ if (node != null) {
+ list.add(node);
+ }
return new CompositeNodeTOImpl(argument.nodeType, null, list)
}
}
static def NetconfMessage toRpcMessage(QName rpc, CompositeNode node,Optional<SchemaContext> ctx) {
- val rpcPayload = wrap(NETCONF_RPC_QNAME, flattenInput(node));
- val w3cPayload = NodeUtils.buildShadowDomTree(rpcPayload);
- w3cPayload.documentElement.setAttribute("message-id", "m-" + messageId.andIncrement);
+ val rpcPayload = wrap(NETCONF_RPC_QNAME, flattenInput(node))
+ val w3cPayload = XmlDocumentUtils.toDocument(rpcPayload, XmlDocumentUtils.defaultValueCodecProvider)
+ w3cPayload.documentElement.setAttribute("message-id", "m-" + messageId.andIncrement)
return new NetconfMessage(w3cPayload);
}
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
- <version>2.2.4</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec-http</artifactId>
- <version>4.0.10.Final</version>
</dependency>
<!-- Testing Dependencies -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
- <version>1.0.9</version>
<scope>test</scope>
</dependency>
<dependency>
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
+import javax.ws.rs.Encoded;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
@Path("/config/{identifier:.+}")
@Produces({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML,
MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
- public StructuredData readConfigurationData(@PathParam("identifier") String identifier);
+ public StructuredData readConfigurationData(@Encoded @PathParam("identifier") String identifier);
@GET
@Path("/operational/{identifier:.+}")
@Produces({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML,
MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
- public StructuredData readOperationalData(@PathParam("identifier") String identifier);
+ public StructuredData readOperationalData(@Encoded @PathParam("identifier") String identifier);
@PUT
@Path("/config/{identifier:.+}")
@Consumes({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML,
MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
- public Response updateConfigurationData(@PathParam("identifier") String identifier, CompositeNode payload);
+ public Response updateConfigurationData(@Encoded @PathParam("identifier") String identifier, CompositeNode payload);
@POST
@Path("/config/{identifier:.+}")
@Consumes({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML,
MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
- public Response createConfigurationData(@PathParam("identifier") String identifier, CompositeNode payload);
+ public Response createConfigurationData(@Encoded @PathParam("identifier") String identifier, CompositeNode payload);
@POST
@Path("/config")
@DELETE
@Path("/config/{identifier:.+}")
- public Response deleteConfigurationData(@PathParam("identifier") String identifier);
+ public Response deleteConfigurationData(@Encoded @PathParam("identifier") String identifier);
@GET
@Path("/streams/stream/{identifier:.+}")
- public Response subscribeToStream(@PathParam("identifier") String identifier, @Context UriInfo uriInfo);
+ public Response subscribeToStream(@Encoded @PathParam("identifier") String identifier, @Context UriInfo uriInfo);
}
val static MOUNT_MODULE = "yang-ext"
val static MOUNT_NODE = "mount"
public val static MOUNT = "yang-ext:mount"
+ val static URI_ENCODING_CHAR_SET = "ISO-8859-1"
+ val static URI_SLASH_PLACEHOLDER = "%2F";
@Property
var SchemaContext globalSchema;
private def InstanceIdWithSchemaNode toIdentifier(String restconfInstance, boolean toMountPointIdentifier) {
checkPreconditions
- val pathArgs = Lists.newArrayList(Splitter.on("/").split(restconfInstance))
+ val encodedPathArgs = Lists.newArrayList(Splitter.on("/").split(restconfInstance))
+ val pathArgs = urlPathArgsDecode(encodedPathArgs)
pathArgs.omitFirstAndLastEmptyString
if (pathArgs.empty) {
return null;
private def toUriString(Object object) {
if(object === null) return "";
- return URLEncoder.encode(object.toString)
+// return object.toString.replace("/",URI_SLASH_PLACEHOLDER)
+ return URLEncoder.encode(object.toString,URI_ENCODING_CHAR_SET)
}
private def InstanceIdWithSchemaNode collectPathArguments(InstanceIdentifierBuilder builder, List<String> strings,
}
}
+
+ def urlPathArgsDecode(List<String> strings) {
+ val List<String> decodedPathArgs = new ArrayList();
+ for (pathArg : strings) {
+ decodedPathArgs.add(URLDecoder.decode(pathArg, URI_ENCODING_CHAR_SET))
+ }
+ return decodedPathArgs
+ }
+
}
import static org.mockito.Mockito.when;
import static org.opendaylight.controller.sal.restconf.impl.test.RestOperationUtils.JSON;
import static org.opendaylight.controller.sal.restconf.impl.test.RestOperationUtils.XML;
-import static org.opendaylight.controller.sal.restconf.impl.test.RestOperationUtils.createUri;
import java.io.IOException;
import java.io.InputStream;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.UriInfo;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
public void testPostOperationsWithInputDataMediaTypes() throws UnsupportedEncodingException {
String uriPrefix = "/operations/";
String uriPath = "ietf-interfaces:interfaces";
- String uri = createUri(uriPrefix, uriPath);
+ String uri = uriPrefix + uriPath;
when(restconfService.invokeRpc(eq(uriPath), any(CompositeNode.class))).thenReturn(null);
post(uri, Draft02.MediaTypes.OPERATION+JSON, Draft02.MediaTypes.OPERATION+JSON, jsonData);
verify(restconfService, times(1)).invokeRpc(eq(uriPath), any(CompositeNode.class));
public void testGetConfigMediaTypes() throws UnsupportedEncodingException {
String uriPrefix = "/config/";
String uriPath = "ietf-interfaces:interfaces";
- String uri = createUri(uriPrefix, uriPath);
+ String uri = uriPrefix + uriPath;
when(restconfService.readConfigurationData(uriPath)).thenReturn(null);
get(uri, Draft02.MediaTypes.DATA+JSON);
verify(restconfService, times(1)).readConfigurationData(uriPath);
public void testGetOperationalMediaTypes() throws UnsupportedEncodingException {
String uriPrefix = "/operational/";
String uriPath = "ietf-interfaces:interfaces";
- String uri = createUri(uriPrefix, uriPath);
+ String uri = uriPrefix + uriPath;
when(restconfService.readOperationalData(uriPath)).thenReturn(null);
get(uri, Draft02.MediaTypes.DATA+JSON);
verify(restconfService, times(1)).readOperationalData(uriPath);
public void testPutConfigMediaTypes() throws UnsupportedEncodingException {
String uriPrefix = "/config/";
String uriPath = "ietf-interfaces:interfaces";
- String uri = createUri(uriPrefix, uriPath);
+ String uri = uriPrefix + uriPath;
when(restconfService.updateConfigurationData(eq(uriPath), any(CompositeNode.class))).thenReturn(null);
put(uri, null, Draft02.MediaTypes.DATA+JSON, jsonData);
verify(restconfService, times(1)).updateConfigurationData(eq(uriPath), any(CompositeNode.class));
public void testPostConfigWithPathMediaTypes() throws UnsupportedEncodingException {
String uriPrefix = "/config/";
String uriPath = "ietf-interfaces:interfaces";
- String uri = createUri(uriPrefix, uriPath);
+ String uri = uriPrefix + uriPath;
when(restconfService.createConfigurationData(eq(uriPath), any(CompositeNode.class))).thenReturn(null);
post(uri, null, Draft02.MediaTypes.DATA+JSON, jsonData);
verify(restconfService, times(1)).createConfigurationData(eq(uriPath), any(CompositeNode.class));
@Test
public void testPostConfigMediaTypes() throws UnsupportedEncodingException {
String uriPrefix = "/config/";
- String uri = createUri(uriPrefix, "");
+ String uri = uriPrefix;
when(restconfService.createConfigurationData(any(CompositeNode.class))).thenReturn(null);
post(uri, null, Draft02.MediaTypes.DATA+JSON, jsonData);
verify(restconfService, times(1)).createConfigurationData(any(CompositeNode.class));
public void testDeleteConfigMediaTypes() throws UnsupportedEncodingException {
String uriPrefix = "/config/";
String uriPath = "ietf-interfaces:interfaces";
- String uri = createUri(uriPrefix, uriPath);
+ String uri = uriPrefix + uriPath;
when(restconfService.deleteConfigurationData(eq(uriPath))).thenReturn(null);
target(uri).request("fooMediaType").delete();
verify(restconfService, times(1)).deleteConfigurationData(uriPath);
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-import static org.opendaylight.controller.sal.restconf.impl.test.RestOperationUtils.createUri;
import java.io.FileNotFoundException;
import java.io.UnsupportedEncodingException;
@Test
public void deleteConfigStatusCodes() throws UnsupportedEncodingException {
- String uri = createUri("/config/", "test-interface:interfaces");
+ String uri = "/config/test-interface:interfaces";
Future<RpcResult<TransactionStatus>> dummyFuture = createFuture(TransactionStatus.COMMITED);
when(brokerFacade.commitConfigurationDataDelete(any(InstanceIdentifier.class))).thenReturn(dummyFuture);
Response response = target(uri).request(MediaType.APPLICATION_XML).delete();
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-import static org.opendaylight.controller.sal.restconf.impl.test.RestOperationUtils.createUri;
import java.io.FileNotFoundException;
import java.io.UnsupportedEncodingException;
@Test
public void getOperationalStatusCodes() throws UnsupportedEncodingException {
mockReadOperationalDataMethod();
- String uri = createUri("/operational/", "ietf-interfaces:interfaces/interface/eth0");
+ String uri = "/operational/ietf-interfaces:interfaces/interface/eth0";
assertEquals(200, get(uri, MediaType.APPLICATION_XML));
- uri = createUri("/operational/", "wrong-module:interfaces/interface/eth0");
+ uri = "/operational/wrong-module:interfaces/interface/eth0";
assertEquals(400, get(uri, MediaType.APPLICATION_XML));
}
@Test
public void getConfigStatusCodes() throws UnsupportedEncodingException {
mockReadConfigurationDataMethod();
- String uri = createUri("/config/", "ietf-interfaces:interfaces/interface/eth0");
+ String uri = "/config/ietf-interfaces:interfaces/interface/eth0";
assertEquals(200, get(uri, MediaType.APPLICATION_XML));
- uri = createUri("/config/", "wrong-module:interfaces/interface/eth0");
+ uri = "/config/wrong-module:interfaces/interface/eth0";
assertEquals(400, get(uri, MediaType.APPLICATION_XML));
}
ControllerContext.getInstance().setMountService(mockMountService);
- String uri = createUri("/config/",
- "ietf-interfaces:interfaces/interface/0/yang-ext:mount/test-module:cont/cont1");
+ String uri = "/config/ietf-interfaces:interfaces/interface/0/yang-ext:mount/test-module:cont/cont1";
assertEquals(200, get(uri, MediaType.APPLICATION_XML));
- uri = createUri("/config/", "ietf-interfaces:interfaces/yang-ext:mount/test-module:cont/cont1");
+ uri = "/config/ietf-interfaces:interfaces/yang-ext:mount/test-module:cont/cont1";
assertEquals(200, get(uri, MediaType.APPLICATION_XML));
}
ControllerContext.getInstance().setMountService(mockMountService);
- String uri = createUri("/config/", "ietf-interfaces:interfaces/interface/0/yang-ext:mount/");
+ String uri = "/config/ietf-interfaces:interfaces/interface/0/yang-ext:mount/";
assertEquals(200, get(uri, MediaType.APPLICATION_XML));
}
public void getModulesTest() throws UnsupportedEncodingException, FileNotFoundException {
ControllerContext.getInstance().setGlobalSchema(schemaContextModules);
- String uri = createUri("/modules", "");
+ String uri = "/modules";
Response response = target(uri).request("application/yang.api+json").get();
validateModulesResponseJson(response);
public void getModuleTest() throws FileNotFoundException, UnsupportedEncodingException {
ControllerContext.getInstance().setGlobalSchema(schemaContextModules);
- String uri = createUri("/modules/module/module2/2014-01-02", "");
+ String uri = "/modules/module/module2/2014-01-02";
Response response = target(uri).request("application/yang.api+xml").get();
assertEquals(200, response.getStatus());
public void getOperationsTest() throws FileNotFoundException, UnsupportedEncodingException {
ControllerContext.getInstance().setGlobalSchema(schemaContextModules);
- String uri = createUri("/operations", "");
+ String uri = "/operations";
Response response = target(uri).request("application/yang.api+xml").get();
assertEquals(200, response.getStatus());
controllerContext.setMountService(mockMountService);
- String uri = createUri("/operations/", "ietf-interfaces:interfaces/interface/0/yang-ext:mount/");
+ String uri = "/operations/ietf-interfaces:interfaces/interface/0/yang-ext:mount/";
Response response = target(uri).request("application/yang.api+xml").get();
assertEquals(200, response.getStatus());
controllerContext.setMountService(mockMountService);
- String uri = createUri("/modules/", "ietf-interfaces:interfaces/interface/0/yang-ext:mount/");
+ String uri = "/modules/ietf-interfaces:interfaces/interface/0/yang-ext:mount/";
Response response = target(uri).request("application/yang.api+json").get();
assertEquals(200, response.getStatus());
controllerContext.setMountService(mockMountService);
- String uri = createUri("/modules/module/",
- "ietf-interfaces:interfaces/interface/0/yang-ext:mount/module1-behind-mount-point/2014-02-03");
+ String uri = "/modules/module/ietf-interfaces:interfaces/interface/0/yang-ext:mount/module1-behind-mount-point/2014-02-03";
Response response = target(uri).request("application/yang.api+json").get();
assertEquals(200, response.getStatus());
*/
package org.opendaylight.controller.sal.restconf.impl.test;
-import java.io.UnsupportedEncodingException;
-import java.net.URI;
-import java.net.URLEncoder;
-
-import com.google.common.base.Charsets;
-
public class RestOperationUtils {
public static final String JSON = "+json";
private RestOperationUtils() {
}
-
- public static String createUri(String prefix, String encodedPart) throws UnsupportedEncodingException {
- return URI.create(prefix + URLEncoder.encode(encodedPart, Charsets.US_ASCII.name()).toString()).toASCIIString();
- }
}
public void postOperationsStatusCodes() throws UnsupportedEncodingException {
controllerContext.setSchemas(schemaContextTestModule);
mockInvokeRpc(cnSnDataOutput, true);
- String uri = createUri("/operations/", "test-module:rpc-test");
+ String uri = "/operations/test-module:rpc-test";
assertEquals(200, post(uri, MediaType.APPLICATION_XML, xmlDataRpcInput));
mockInvokeRpc(null, true);
mockInvokeRpc(null, false);
assertEquals(500, post(uri, MediaType.APPLICATION_XML, xmlDataRpcInput));
- uri = createUri("/operations/", "test-module:rpc-wrongtest");
+ uri = "/operations/test-module:rpc-wrongtest";
assertEquals(404, post(uri, MediaType.APPLICATION_XML, xmlDataRpcInput));
}
public void postConfigOnlyStatusCodes() throws UnsupportedEncodingException {
controllerContext.setSchemas(schemaContextYangsIetf);
mockCommitConfigurationDataPostMethod(TransactionStatus.COMMITED);
- String uri = createUri("/config", "");
+ String uri = "/config";
assertEquals(204, post(uri, MediaType.APPLICATION_XML, xmlDataAbsolutePath));
mockCommitConfigurationDataPostMethod(null);
public void postConfigStatusCodes() throws UnsupportedEncodingException {
controllerContext.setSchemas(schemaContextYangsIetf);
mockCommitConfigurationDataPostMethod(TransactionStatus.COMMITED);
- String uri = createUri("/config/", "ietf-interfaces:interfaces");
+ String uri = "/config/ietf-interfaces:interfaces";
assertEquals(204, post(uri, MediaType.APPLICATION_XML, xmlDataInterfaceAbsolutePath));
mockCommitConfigurationDataPostMethod(null);
ControllerContext.getInstance().setMountService(mockMountService);
- String uri = createUri("/config/", "ietf-interfaces:interfaces/interface/0/");
+ String uri = "/config/ietf-interfaces:interfaces/interface/0/";
assertEquals(204, post(uri, Draft02.MediaTypes.DATA + XML, xmlData4));
- uri = createUri("/config/", "ietf-interfaces:interfaces/interface/0/yang-ext:mount/test-module:cont");
+ uri = "/config/ietf-interfaces:interfaces/interface/0/yang-ext:mount/test-module:cont";
assertEquals(204, post(uri, Draft02.MediaTypes.DATA + XML, xmlData3));
}
ArgumentCaptor<InstanceIdentifier> instanceIdCaptor = ArgumentCaptor.forClass(InstanceIdentifier.class);
ArgumentCaptor<CompositeNode> compNodeCaptor = ArgumentCaptor.forClass(CompositeNode.class);
- String URI_1 = createUri("/config", "");
+ String URI_1 = "/config";
assertEquals(204, post(URI_1, Draft02.MediaTypes.DATA + XML, xmlTestInterface));
verify(brokerFacade).commitConfigurationDataPost(instanceIdCaptor.capture(), compNodeCaptor.capture());
String identifier = "[(urn:ietf:params:xml:ns:yang:test-interface?revision=2014-07-01)interfaces]";
assertEquals(identifier, instanceIdCaptor.getValue().getPath().toString());
- String URI_2 = createUri("/config/", "test-interface:interfaces");
+ String URI_2 = "/config/test-interface:interfaces";
assertEquals(204, post(URI_2, Draft02.MediaTypes.DATA + XML, xmlBlockData));
verify(brokerFacade, times(2))
.commitConfigurationDataPost(instanceIdCaptor.capture(), compNodeCaptor.capture());
when(brokerFacade.commitConfigurationDataPost(any(InstanceIdentifier.class), any(CompositeNode.class)))
.thenReturn(null);
- String URI_1 = createUri("/config", "");
+ String URI_1 = "/config";
assertEquals(202, post(URI_1, Draft02.MediaTypes.DATA + XML, xmlTestInterface));
- String URI_2 = createUri("/config/", "test-interface:interfaces");
+ String URI_2 = "/config/test-interface:interfaces";
assertEquals(202, post(URI_2, Draft02.MediaTypes.DATA + XML, xmlBlockData));
}
- private String createUri(String prefix, String encodedPart) throws UnsupportedEncodingException {
- return URI.create(prefix + URLEncoder.encode(encodedPart, Charsets.US_ASCII.name()).toString()).toASCIIString();
- }
-
private static void initMocking() {
controllerContext = ControllerContext.getInstance();
controllerContext.setSchemas(schemaContext);
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-import static org.opendaylight.controller.sal.restconf.impl.test.RestOperationUtils.createUri;
import java.io.FileNotFoundException;
import java.io.IOException;
*/
@Test
public void putConfigStatusCodes() throws UnsupportedEncodingException {
- String uri = createUri("/config/", "ietf-interfaces:interfaces/interface/eth0");
+ String uri = "/config/ietf-interfaces:interfaces/interface/eth0";
mockCommitConfigurationDataPutMethod(TransactionStatus.COMMITED);
assertEquals(200, put(uri, MediaType.APPLICATION_XML, xmlData));
ControllerContext.getInstance().setMountService(mockMountService);
- String uri = createUri("/config/", "ietf-interfaces:interfaces/interface/0/yang-ext:mount/test-module:cont");
+ String uri = "/config/ietf-interfaces:interfaces/interface/0/yang-ext:mount/test-module:cont";
assertEquals(200, put(uri, MediaType.APPLICATION_XML, xmlData2));
- uri = createUri("/config/", "ietf-interfaces:interfaces/yang-ext:mount/test-module:cont");
+ uri = "/config/ietf-interfaces:interfaces/yang-ext:mount/test-module:cont";
assertEquals(200, put(uri, MediaType.APPLICATION_XML, xmlData2));
}
ControllerContext.getInstance().setMountService(mockMountService);
- String uri = createUri("/config/", "ietf-interfaces:interfaces/yang-ext:mount");
+ String uri = "/config/ietf-interfaces:interfaces/yang-ext:mount";
assertEquals(200, put(uri, MediaType.APPLICATION_XML, xmlData3));
}
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
-import static org.opendaylight.controller.sal.restconf.impl.test.RestOperationUtils.createUri;
import java.io.FileNotFoundException;
import java.io.UnsupportedEncodingException;
@Test
public void testCallRpcCallGet() throws UnsupportedEncodingException, InterruptedException {
- String uri = createUri("/operations/", "sal-remote:create-data-change-event-subscription");
+ String uri = "/operations/sal-remote:create-data-change-event-subscription";
Response responseWithStreamName = post(uri, MediaType.APPLICATION_XML, getRpcInput());
String xmlResponse = responseWithStreamName.readEntity(String.class);
assertNotNull(xmlResponse);
assertTrue(xmlResponse.contains("<stream-name>ietf-interfaces:interfaces/ietf-interfaces:interface/eth0</stream-name>"));
- uri = createUri("/streams/stream/", "ietf-interfaces:interfaces/ietf-interfaces:interface/eth0");
+ uri = "/streams/stream/ietf-interfaces:interfaces/ietf-interfaces:interface/eth0";
Response responseWithRedirectionUri = get(uri, MediaType.APPLICATION_XML);
final URI websocketServerUri = responseWithRedirectionUri.getLocation();
assertNotNull(websocketServerUri);
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>restconf-client-api</artifactId>
- <version>${yangtools.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>restconf-client-impl</artifactId>
- <version>${yangtools.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
*/
package org.opendaylight.controller.sal.restconf.broker.event;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
+
+import javax.annotation.concurrent.ThreadSafe;
+
import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.DataChangedNotification;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+@ThreadSafe
public class RemoteDataChangeEvent implements DataChangeEvent<InstanceIdentifier<? extends DataObject>,DataObject> {
-
-
- private final DataChangedNotification dataChangedNotification;
-
-
- public RemoteDataChangeEvent(DataChangedNotification dataChangedNotification){
-
- this.dataChangedNotification = dataChangedNotification;
+ private final Map<InstanceIdentifier<?>, DataObject> createdConfig, createdOper, origConfig, origOper, updatedConfig, updatedOper;
+ private final Set<InstanceIdentifier<?>> removedConfig, removedOper;
+
+ public RemoteDataChangeEvent(DataChangedNotification dataChangedNotification) {
+ final Map<InstanceIdentifier<?>, DataObject> createdConfig = new HashMap<>();
+ final Map<InstanceIdentifier<?>, DataObject> createdOper = new HashMap<>();
+ final Map<InstanceIdentifier<?>, DataObject> origConfig = new HashMap<>();
+ final Map<InstanceIdentifier<?>, DataObject> origOper = new HashMap<>();
+ final Map<InstanceIdentifier<?>, DataObject> updatedConfig = new HashMap<>();
+ final Map<InstanceIdentifier<?>, DataObject> updatedOper = new HashMap<>();
+ final Set<InstanceIdentifier<?>> removedConfig = new HashSet<>();
+ final Set<InstanceIdentifier<?>> removedOper = new HashSet<>();
+
+ for (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.data.changed.notification.DataChangeEvent d :dataChangedNotification.getDataChangeEvent()) {
+ switch (d.getOperation()) {
+ case Created:
+ switch (d.getStore()) {
+ case Config:
+ createdConfig.put(d.getPath(), d);
+ break;
+ case Operation:
+ createdOper.put(d.getPath(), d);
+ break;
+ }
+ break;
+ case Deleted:
+ switch (d.getStore()) {
+ case Config:
+ removedConfig.add(d.getPath());
+ break;
+ case Operation:
+ removedOper.add(d.getPath());
+ break;
+ }
+ break;
+ case Updated:
+ switch (d.getStore()) {
+ case Config:
+ origConfig.put(d.getPath(), d);
+ updatedConfig.put(d.getPath(), d);
+ break;
+ case Operation:
+ origOper.put(d.getPath(),d);
+ updatedOper.put(d.getPath(),d);
+ break;
+ }
+ break;
+ }
+ }
+
+ this.createdConfig = Collections.unmodifiableMap(createdConfig);
+ this.createdOper = Collections.unmodifiableMap(createdOper);
+ this.origConfig = Collections.unmodifiableMap(origConfig);
+ this.origOper = Collections.unmodifiableMap(origOper);
+ this.updatedConfig = Collections.unmodifiableMap(updatedConfig);
+ this.updatedOper = Collections.unmodifiableMap(updatedOper);
+ this.removedConfig = Collections.unmodifiableSet(removedConfig);
+ this.removedOper = Collections.unmodifiableSet(removedOper);
}
@Override
@Override
public Map<InstanceIdentifier<?>, DataObject> getCreatedOperationalData() {
- return new HashMap<InstanceIdentifier<?>, DataObject>(){{
- for (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.data.changed.notification.DataChangeEvent d :dataChangedNotification.getDataChangeEvent()){
- if (d.getOperation().getIntValue() == 0 && d.getStore().getIntValue() == 1){
- put(d.getPath(),d);
- }
- }
- }};
+ return createdOper;
}
@Override
public Map<InstanceIdentifier<?>, DataObject> getCreatedConfigurationData() {
- return new HashMap<InstanceIdentifier<?>, DataObject>(){{
- for (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.data.changed.notification.DataChangeEvent d :dataChangedNotification.getDataChangeEvent()){
- if (d.getOperation().getIntValue() == 0 && d.getStore().getIntValue() == 0){
- put(d.getPath(),d);
- }
- }
- }};
+ return createdConfig;
}
@Override
public Map<InstanceIdentifier<?>, DataObject> getUpdatedOperationalData() {
- return new HashMap<InstanceIdentifier<?>, DataObject>(){{
- for (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.data.changed.notification.DataChangeEvent d :dataChangedNotification.getDataChangeEvent()){
- if (d.getOperation().getIntValue() == 1 && d.getStore().getIntValue() == 1){
- put(d.getPath(),d);
- }
- }
- }};
+ return updatedOper;
}
@Override
public Map<InstanceIdentifier<?>, DataObject> getUpdatedConfigurationData() {
- return new HashMap<InstanceIdentifier<?>, DataObject>(){{
- for (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.data.changed.notification.DataChangeEvent d :dataChangedNotification.getDataChangeEvent()){
- if (d.getOperation().getIntValue() == 1 && d.getStore().getIntValue() == 0){
- put(d.getPath(),d);
- }
- }
- }};
+ return updatedConfig;
}
@Override
public Set<InstanceIdentifier<?>> getRemovedConfigurationData() {
- return new HashSet<InstanceIdentifier<?>>(){{
- for (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.data.changed.notification.DataChangeEvent d :dataChangedNotification.getDataChangeEvent()){
- if (d.getOperation().getIntValue() == 2 && d.getStore().getIntValue() == 0){
- add(d.getPath());
- }
- }
- }};
+ return removedConfig;
}
@Override
public Set<InstanceIdentifier<?>> getRemovedOperationalData() {
- return new HashSet<InstanceIdentifier<?>>(){{
- for (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.data.changed.notification.DataChangeEvent d :dataChangedNotification.getDataChangeEvent()){
- if (d.getOperation().getIntValue() == 2 && d.getStore().getIntValue() == 1){
- add(d.getPath());
- }
- }
- }};
+ return removedOper;
}
@Override
public Map<InstanceIdentifier<?>, DataObject> getOriginalConfigurationData() {
- return new HashMap<InstanceIdentifier<?>, DataObject>(){{
- for (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.data.changed.notification.DataChangeEvent d :dataChangedNotification.getDataChangeEvent()){
- if (d.getOperation().getIntValue() == 1 && d.getStore().getIntValue() == 0){
- put(d.getPath(),d);
- }
- }
- }};
+ return origConfig;
}
@Override
public Map<InstanceIdentifier<?>, DataObject> getOriginalOperationalData() {
- return new HashMap<InstanceIdentifier<?>, DataObject>(){{
- for (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.data.changed.notification.DataChangeEvent d :dataChangedNotification.getDataChangeEvent()){
- if (d.getOperation().getIntValue() == 1 && d.getStore().getIntValue() == 1){
- put(d.getPath(),d);
- }
- }
- }};
+ return origOper;
}
}
*/
package org.opendaylight.controller.sal.restconf.broker.impl;
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.Multimap;
-import com.google.common.collect.Multimaps;
-import com.google.common.collect.SetMultimap;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
+
import org.opendaylight.controller.sal.binding.api.NotificationListener;
import org.opendaylight.controller.sal.binding.api.NotificationService;
import org.opendaylight.controller.sal.restconf.broker.listeners.RemoteNotificationListener;
import org.opendaylight.yangtools.restconf.client.api.event.EventStreamInfo;
import org.opendaylight.yangtools.yang.binding.Notification;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Multimaps;
+import com.google.common.collect.SetMultimap;
+
public class NotificationServiceImpl implements NotificationService {
- private SalRemoteService salRemoteService;
- private RestconfClientContext restconfClientContext;
+ private final SalRemoteService salRemoteService;
+ private final RestconfClientContext restconfClientContext;
private final Multimap<Class<? extends Notification>,NotificationListener<? extends Object>> listeners;
private ExecutorService _executor;
String notificationStreamName = RemoteStreamTools.createNotificationStream(salRemoteService, notifications);
final Map<String,EventStreamInfo> desiredEventStream = RemoteStreamTools.createEventStream(restconfClientContext, notificationStreamName);
RemoteNotificationListener remoteNotificationListener = new RemoteNotificationListener(listener);
- ListenerRegistration listenerRegistration = restconfClientContext.getEventStreamContext(desiredEventStream.get(desiredEventStream.get(notificationStreamName))).registerNotificationListener(remoteNotificationListener);
- SalNotificationRegistration salNotificationRegistration = new SalNotificationRegistration(listenerRegistration);
- return salNotificationRegistration;
+ ListenerRegistration<?> listenerRegistration = restconfClientContext.getEventStreamContext(desiredEventStream.get(desiredEventStream.get(notificationStreamName))).registerNotificationListener(remoteNotificationListener);
+ return new SalNotificationRegistration<T>(listenerRegistration);
}
@Override
//TODO implementation using sal-remote
String notificationStreamName = RemoteStreamTools.createNotificationStream(salRemoteService, null);
final Map<String,EventStreamInfo> desiredEventStream = RemoteStreamTools.createEventStream(restconfClientContext, notificationStreamName);
- ListenerRegistration listenerRegistration = restconfClientContext.getEventStreamContext(desiredEventStream.get(desiredEventStream.get(notificationStreamName))).registerNotificationListener(listener);
- return listenerRegistration;
+ return restconfClientContext.getEventStreamContext(desiredEventStream.get(desiredEventStream.get(notificationStreamName))).registerNotificationListener(listener);
}
private class SalNotificationRegistration<T extends Notification> implements Registration<NotificationListener<T>>{
- private Registration registration;
+ private final Registration<?> registration;
- public SalNotificationRegistration(ListenerRegistration listenerRegistration){
+ public SalNotificationRegistration(ListenerRegistration<?> listenerRegistration){
this.registration = listenerRegistration;
}
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-util</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-statistics</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-base</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.xtend</groupId>
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.statistics.manager;
+
+import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+
+abstract class AbstractListeningStatsTracker<I, K> extends AbstractStatsTracker<I, K> implements AutoCloseable, DataChangeListener {
+ private static final Logger logger = LoggerFactory.getLogger(AbstractListeningStatsTracker.class);
+ private ListenerRegistration<?> reg;
+
+ protected AbstractListeningStatsTracker(FlowCapableContext context, long lifetimeNanos) {
+ super(context, lifetimeNanos);
+ }
+
+ protected abstract InstanceIdentifier<?> listenPath();
+ protected abstract String statName();
+
+ public void start(final DataBrokerService dbs) {
+ Preconditions.checkState(reg == null);
+
+ reg = dbs.registerDataChangeListener(listenPath(), this);
+ logger.debug("{} Statistics tracker for node {} started", statName(), getNodeIdentifier());
+ }
+
+ @Override
+ public final void close() {
+ if (reg != null) {
+ try {
+ reg.close();
+ } catch (Exception e) {
+ logger.warn("Failed to stop {} Statistics tracker for node {}", statName(), getNodeIdentifier(), e);
+ }
+ reg = null;
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright IBM Corporation, 2013. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.statistics.manager;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.Future;
+
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionAware;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.JdkFutureAdapters;
+
+abstract class AbstractStatsTracker<I, K> {
+ private static final Logger logger = LoggerFactory.getLogger(AbstractStatsTracker.class);
+ private final FutureCallback<RpcResult<? extends TransactionAware>> callback =
+ new FutureCallback<RpcResult<? extends TransactionAware>>() {
+ @Override
+ public void onSuccess(RpcResult<? extends TransactionAware> result) {
+ if (result.isSuccessful()) {
+ final TransactionId id = result.getResult().getTransactionId();
+ if (id == null) {
+ final Throwable t = new UnsupportedOperationException("No protocol support");
+ t.fillInStackTrace();
+ onFailure(t);
+ } else {
+ context.registerTransaction(id);
+ }
+ } else {
+ logger.debug("Statistics request failed: {}", result.getErrors());
+
+ final Throwable t = new RPCFailedException("Failed to send statistics request", result.getErrors());
+ t.fillInStackTrace();
+ onFailure(t);
+ }
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ logger.debug("Failed to send statistics request", t);
+ }
+ };
+
+ private final Map<K, Long> trackedItems = new HashMap<>();
+ private final FlowCapableContext context;
+ private final long lifetimeNanos;
+
+ protected AbstractStatsTracker(final FlowCapableContext context, final long lifetimeNanos) {
+ this.context = Preconditions.checkNotNull(context);
+ this.lifetimeNanos = lifetimeNanos;
+ }
+
+ protected final InstanceIdentifierBuilder<Node> getNodeIdentifierBuilder() {
+ return InstanceIdentifier.builder(getNodeIdentifier());
+ }
+
+ protected final NodeRef getNodeRef() {
+ return context.getNodeRef();
+ }
+
+ protected final InstanceIdentifier<Node> getNodeIdentifier() {
+ return context.getNodeIdentifier();
+ }
+
+ protected final <T extends TransactionAware> void requestHelper(Future<RpcResult<T>> future) {
+ Futures.addCallback(JdkFutureAdapters.listenInPoolThread(future), callback);
+ }
+
+ protected final DataModificationTransaction startTransaction() {
+ return context.startDataModification();
+ }
+
+ protected abstract void cleanupSingleStat(DataModificationTransaction trans, K item);
+ protected abstract K updateSingleStat(DataModificationTransaction trans, I item);
+
+ public final synchronized void updateStats(List<I> list) {
+ final Long expiryTime = System.nanoTime() + lifetimeNanos;
+ final DataModificationTransaction trans = startTransaction();
+
+ for (final I item : list) {
+ trackedItems.put(updateSingleStat(trans, item), expiryTime);
+ }
+
+ trans.commit();
+ }
+
+ public final synchronized void cleanup(final DataModificationTransaction trans, long now) {
+ for (Iterator<Entry<K, Long>> it = trackedItems.entrySet().iterator();it.hasNext();){
+ Entry<K, Long> e = it.next();
+ if (now > e.getValue()) {
+ cleanupSingleStat(trans, e.getKey());
+ it.remove();
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.statistics.manager;
+
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Interface exposed to AbstractStatsTracker by its parent NodeStatisticsHandler.
+ * While we could simply exist without this interface, its purpose is to document
+ * the contract between the two classes.
+ */
+interface FlowCapableContext {
+ InstanceIdentifier<Node> getNodeIdentifier();
+ NodeRef getNodeRef();
+ DataModificationTransaction startDataModification();
+ void registerTransaction(TransactionId id);
+ void registerTableTransaction(TransactionId id, Short tableId);
+}
--- /dev/null
+/*
+ * Copyright IBM Corporation, 2013. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.statistics.manager;
+
+import java.util.Collection;
+
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Sets;
+
+/**
+ * There is a single instance of this class and that instance is responsible for
+ * monitoring the operational data store for nodes being created/deleted and
+ * notifying StatisticsProvider. These events then control the lifecycle of
+ * NodeStatisticsHandler for a particular switch.
+ */
+final class FlowCapableTracker implements DataChangeListener {
+ private static final Logger logger = LoggerFactory.getLogger(FlowCapableTracker.class);
+
+ private final InstanceIdentifier<FlowCapableNode> root;
+ private final StatisticsProvider stats;
+
+ private final Predicate<InstanceIdentifier<?>> filterIdentifiers = new Predicate<InstanceIdentifier<?>>() {
+ @Override
+ public boolean apply(final InstanceIdentifier<?> input) {
+ /*
+ * This notification has been triggered either by the ancestor,
+ * descendant or directly for the FlowCapableNode itself. We
+ * are not interested descendants, so let's prune them based
+ * on the depth of their identifier.
+ */
+ if (root.getPath().size() < input.getPath().size()) {
+ logger.debug("Ignoring notification for descendant {}", input);
+ return false;
+ }
+
+ logger.debug("Including notification for {}", input);
+ return true;
+ }
+ };
+
+ public FlowCapableTracker(final StatisticsProvider stats, InstanceIdentifier<FlowCapableNode> root) {
+ this.stats = Preconditions.checkNotNull(stats);
+ this.root = Preconditions.checkNotNull(root);
+ }
+
+ /*
+ * This method is synchronized because we want to make sure to serialize input
+ * from the datastore. Competing add/remove could be problematic otherwise.
+ */
+ @Override
+ public synchronized void onDataChanged(final DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
+ logger.debug("Tracker at root {} processing notification", root);
+
+ /*
+ * First process all the identifiers which were removed, trying to figure out
+ * whether they constitute removal of FlowCapableNode.
+ */
+ final Collection<NodeKey> removedNodes =
+ Collections2.filter(Collections2.transform(
+ Sets.filter(change.getRemovedOperationalData(), filterIdentifiers),
+ new Function<InstanceIdentifier<?>, NodeKey>() {
+ @Override
+ public NodeKey apply(final InstanceIdentifier<?> input) {
+ final NodeKey key = input.firstKeyOf(Node.class, NodeKey.class);
+ if (key == null) {
+ // FIXME: do we have a backup plan?
+ logger.info("Failed to extract node key from {}", input);
+ }
+ return key;
+ }
+ }), Predicates.notNull());
+ stats.stopNodeHandlers(removedNodes);
+
+ final Collection<NodeKey> addedNodes =
+ Collections2.filter(Collections2.transform(
+ Sets.filter(change.getCreatedOperationalData().keySet(), filterIdentifiers),
+ new Function<InstanceIdentifier<?>, NodeKey>() {
+ @Override
+ public NodeKey apply(final InstanceIdentifier<?> input) {
+ final NodeKey key = input.firstKeyOf(Node.class, NodeKey.class);
+ if (key == null) {
+ // FIXME: do we have a backup plan?
+ logger.info("Failed to extract node key from {}", input);
+ }
+ return key;
+ }
+ }), Predicates.notNull());
+ stats.startNodeHandlers(addedNodes);
+
+ logger.debug("Tracker at root {} finished processing notification", root);
+ }
+}
--- /dev/null
+/*
+ * Copyright IBM Corporation, 2013. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.statistics.manager;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+
+final class FlowStatsEntry {
+ private final Short tableId;
+ private final Flow flow;
+
+ public FlowStatsEntry(Short tableId, Flow flow){
+ this.tableId = tableId;
+ this.flow = flow;
+ }
+
+ public Short getTableId() {
+ return tableId;
+ }
+
+ public Flow getFlow() {
+ return flow;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((flow == null) ? 0 : flow.hashCode());
+ result = prime * result + ((tableId == null) ? 0 : tableId.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ FlowStatsEntry other = (FlowStatsEntry) obj;
+ if (flow == null) {
+ if (other.flow != null)
+ return false;
+ } else if (!flow.equals(other.flow))
+ return false;
+ if (tableId == null) {
+ if (other.tableId != null)
+ return false;
+ } else if (!tableId.equals(other.tableId))
+ return false;
+ return true;
+ }
+}
--- /dev/null
+/*
+ * Copyright IBM Corporation, 2013. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.statistics.manager;
+
+import java.util.Map.Entry;
+
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+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.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsDataBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsFromFlowTableInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.statistics.FlowStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericStatistics;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class FlowStatsTracker extends AbstractListeningStatsTracker<FlowAndStatisticsMapList, FlowStatsEntry> {
+ private static final Logger logger = LoggerFactory.getLogger(FlowStatsTracker.class);
+ private final OpendaylightFlowStatisticsService flowStatsService;
+ private int unaccountedFlowsCounter = 1;
+
+ FlowStatsTracker(OpendaylightFlowStatisticsService flowStatsService, final FlowCapableContext context, long lifetimeNanos) {
+ super(context, lifetimeNanos);
+ this.flowStatsService = flowStatsService;
+ }
+
+ @Override
+ protected void cleanupSingleStat(DataModificationTransaction trans, FlowStatsEntry item) {
+ InstanceIdentifier<?> flowRef = getNodeIdentifierBuilder()
+ .augmentation(FlowCapableNode.class)
+ .child(Table.class, new TableKey(item.getTableId()))
+ .child(Flow.class,item.getFlow().getKey())
+ .augmentation(FlowStatisticsData.class).toInstance();
+ trans.removeOperationalData(flowRef);
+ }
+
+ @Override
+ protected FlowStatsEntry updateSingleStat(DataModificationTransaction trans, FlowAndStatisticsMapList map) {
+ short tableId = map.getTableId();
+
+ FlowBuilder flowBuilder = new FlowBuilder();
+
+ FlowStatisticsDataBuilder flowStatisticsData = new FlowStatisticsDataBuilder();
+
+ FlowBuilder flow = new FlowBuilder();
+ flow.setContainerName(map.getContainerName());
+ flow.setBufferId(map.getBufferId());
+ flow.setCookie(map.getCookie());
+ flow.setCookieMask(map.getCookieMask());
+ flow.setFlags(map.getFlags());
+ flow.setFlowName(map.getFlowName());
+ flow.setHardTimeout(map.getHardTimeout());
+ if(map.getFlowId() != null)
+ flow.setId(new FlowId(map.getFlowId().getValue()));
+ flow.setIdleTimeout(map.getIdleTimeout());
+ flow.setInstallHw(map.isInstallHw());
+ flow.setInstructions(map.getInstructions());
+ if(map.getFlowId()!= null)
+ flow.setKey(new FlowKey(new FlowId(map.getKey().getFlowId().getValue())));
+ flow.setMatch(map.getMatch());
+ flow.setOutGroup(map.getOutGroup());
+ flow.setOutPort(map.getOutPort());
+ flow.setPriority(map.getPriority());
+ flow.setStrict(map.isStrict());
+ flow.setTableId(tableId);
+
+ Flow flowRule = flow.build();
+
+ FlowAndStatisticsMapListBuilder stats = new FlowAndStatisticsMapListBuilder();
+ stats.setByteCount(map.getByteCount());
+ stats.setPacketCount(map.getPacketCount());
+ stats.setDuration(map.getDuration());
+
+ GenericStatistics flowStats = stats.build();
+
+ //Augment the data to the flow node
+
+ FlowStatisticsBuilder flowStatistics = new FlowStatisticsBuilder();
+ flowStatistics.setByteCount(flowStats.getByteCount());
+ flowStatistics.setPacketCount(flowStats.getPacketCount());
+ flowStatistics.setDuration(flowStats.getDuration());
+ flowStatistics.setContainerName(map.getContainerName());
+ flowStatistics.setBufferId(map.getBufferId());
+ flowStatistics.setCookie(map.getCookie());
+ flowStatistics.setCookieMask(map.getCookieMask());
+ flowStatistics.setFlags(map.getFlags());
+ flowStatistics.setFlowName(map.getFlowName());
+ flowStatistics.setHardTimeout(map.getHardTimeout());
+ flowStatistics.setIdleTimeout(map.getIdleTimeout());
+ flowStatistics.setInstallHw(map.isInstallHw());
+ flowStatistics.setInstructions(map.getInstructions());
+ flowStatistics.setMatch(map.getMatch());
+ flowStatistics.setOutGroup(map.getOutGroup());
+ flowStatistics.setOutPort(map.getOutPort());
+ flowStatistics.setPriority(map.getPriority());
+ flowStatistics.setStrict(map.isStrict());
+ flowStatistics.setTableId(tableId);
+
+ flowStatisticsData.setFlowStatistics(flowStatistics.build());
+
+ logger.debug("Flow : {}",flowRule.toString());
+ logger.debug("Statistics to augment : {}",flowStatistics.build().toString());
+
+ InstanceIdentifier<Table> tableRef = getNodeIdentifierBuilder()
+ .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
+
+ //TODO: Not a good way to do it, need to figure out better way.
+ //TODO: major issue in any alternate approach is that flow key is incrementally assigned
+ //to the flows stored in data store.
+ // Augment same statistics to all the matching masked flow
+ Table table= (Table)trans.readConfigurationData(tableRef);
+ if(table != null){
+ for(Flow existingFlow : table.getFlow()){
+ logger.debug("Existing flow in data store : {}",existingFlow.toString());
+ if(FlowComparator.flowEquals(flowRule,existingFlow)){
+ InstanceIdentifier<Flow> flowRef = getNodeIdentifierBuilder()
+ .augmentation(FlowCapableNode.class)
+ .child(Table.class, new TableKey(tableId))
+ .child(Flow.class,existingFlow.getKey()).toInstance();
+ flowBuilder.setKey(existingFlow.getKey());
+ flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
+ logger.debug("Found matching flow in the datastore, augmenting statistics");
+ // Update entry with timestamp of latest response
+ flow.setKey(existingFlow.getKey());
+ FlowStatsEntry flowStatsEntry = new FlowStatsEntry(tableId,flow.build());
+ trans.putOperationalData(flowRef, flowBuilder.build());
+ return flowStatsEntry;
+ }
+ }
+ }
+
+ table = (Table)trans.readOperationalData(tableRef);
+ if(table != null){
+ for(Flow existingFlow : table.getFlow()){
+ FlowStatisticsData augmentedflowStatisticsData = existingFlow.getAugmentation(FlowStatisticsData.class);
+ if(augmentedflowStatisticsData != null){
+ FlowBuilder existingOperationalFlow = new FlowBuilder();
+ existingOperationalFlow.fieldsFrom(augmentedflowStatisticsData.getFlowStatistics());
+ logger.debug("Existing unaccounted flow in operational data store : {}",existingFlow.toString());
+ if(FlowComparator.flowEquals(flowRule,existingOperationalFlow.build())){
+ InstanceIdentifier<Flow> flowRef = getNodeIdentifierBuilder()
+ .augmentation(FlowCapableNode.class)
+ .child(Table.class, new TableKey(tableId))
+ .child(Flow.class,existingFlow.getKey()).toInstance();
+ flowBuilder.setKey(existingFlow.getKey());
+ flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
+ logger.debug("Found matching unaccounted flow in the operational datastore, augmenting statistics");
+ // Update entry with timestamp of latest response
+ flow.setKey(existingFlow.getKey());
+ FlowStatsEntry flowStatsEntry = new FlowStatsEntry(tableId,flow.build());
+ trans.putOperationalData(flowRef, flowBuilder.build());
+ return flowStatsEntry;
+ }
+ }
+ }
+ }
+
+ String flowKey = "#UF$TABLE*"+Short.toString(tableId)+"*"+Integer.toString(this.unaccountedFlowsCounter);
+ this.unaccountedFlowsCounter++;
+ FlowKey newFlowKey = new FlowKey(new FlowId(flowKey));
+ InstanceIdentifier<Flow> flowRef = getNodeIdentifierBuilder().augmentation(FlowCapableNode.class)
+ .child(Table.class, new TableKey(tableId))
+ .child(Flow.class,newFlowKey).toInstance();
+ flowBuilder.setKey(newFlowKey);
+ flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
+ logger.debug("Flow {} is not present in config data store, augmenting statistics as an unaccounted flow",
+ flowBuilder.build());
+
+ // Update entry with timestamp of latest response
+ flow.setKey(newFlowKey);
+ FlowStatsEntry flowStatsEntry = new FlowStatsEntry(tableId,flow.build());
+ trans.putOperationalData(flowRef, flowBuilder.build());
+ return flowStatsEntry;
+ }
+
+ @Override
+ protected InstanceIdentifier<?> listenPath() {
+ return getNodeIdentifierBuilder().augmentation(FlowCapableNode.class).child(Table.class).child(Flow.class).build();
+ }
+
+ @Override
+ protected String statName() {
+ return "Flow";
+ }
+
+ public void requestAllFlowsAllTables() {
+ if (flowStatsService != null) {
+ final GetAllFlowsStatisticsFromAllFlowTablesInputBuilder input = new GetAllFlowsStatisticsFromAllFlowTablesInputBuilder();
+ input.setNode(getNodeRef());
+
+ requestHelper(flowStatsService.getAllFlowsStatisticsFromAllFlowTables(input.build()));
+ }
+ }
+
+ public void requestAggregateFlows(final TableKey key) {
+ if (flowStatsService != null) {
+ GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder input =
+ new GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder();
+
+ input.setNode(getNodeRef());
+ input.setTableId(new org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TableId(key.getId()));
+ requestHelper(flowStatsService.getAggregateFlowStatisticsFromFlowTableForAllFlows(input.build()));
+ }
+ }
+
+ public void requestFlow(final Flow flow) {
+ if (flowStatsService != null) {
+ final GetFlowStatisticsFromFlowTableInputBuilder input =
+ new GetFlowStatisticsFromFlowTableInputBuilder(flow);
+ input.setNode(getNodeRef());
+
+ requestHelper(flowStatsService.getFlowStatisticsFromFlowTable(input.build()));
+ }
+ }
+
+ @Override
+ public void onDataChanged(DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
+ for (Entry<InstanceIdentifier<?>, DataObject> e : change.getCreatedConfigurationData().entrySet()) {
+ if (Flow.class.equals(e.getKey().getTargetType())) {
+ final Flow flow = (Flow) e.getValue();
+ logger.debug("Key {} triggered request for flow {}", e.getKey(), flow);
+ requestFlow(flow);
+ } else {
+ logger.debug("Ignoring key {}", e.getKey());
+ }
+ }
+
+ final DataModificationTransaction trans = startTransaction();
+ for (InstanceIdentifier<?> key : change.getRemovedConfigurationData()) {
+ if (Flow.class.equals(key.getTargetType())) {
+ @SuppressWarnings("unchecked")
+ final InstanceIdentifier<Flow> flow = (InstanceIdentifier<Flow>)key;
+ final InstanceIdentifier<?> del = InstanceIdentifier.builder(flow)
+ .augmentation(FlowStatisticsData.class).build();
+ logger.debug("Key {} triggered remove of augmentation {}", key, del);
+
+ trans.removeOperationalData(del);
+ }
+ }
+ trans.commit();
+ }
+
+ @Override
+ public void start(final DataBrokerService dbs) {
+ if (flowStatsService == null) {
+ logger.debug("No Flow Statistics service, not subscribing to flows on node {}", getNodeIdentifier());
+ return;
+ }
+
+ super.start(dbs);
+ }
+}
--- /dev/null
+/*
+ * Copyright IBM Corporation, 2013. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.statistics.manager;
+
+import java.util.Collections;
+import java.util.Set;
+import java.util.concurrent.ConcurrentSkipListSet;
+
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsDataBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.GetFlowTablesStatisticsInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.statistics.FlowTableStatistics;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.statistics.FlowTableStatisticsBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+final class FlowTableStatsTracker extends AbstractStatsTracker<FlowTableAndStatisticsMap, FlowTableAndStatisticsMap> {
+ private final Set<TableKey> privateTables = new ConcurrentSkipListSet<>();
+ private final Set<TableKey> tables = Collections.unmodifiableSet(privateTables);
+ private final OpendaylightFlowTableStatisticsService flowTableStatsService;
+
+ FlowTableStatsTracker(OpendaylightFlowTableStatisticsService flowTableStatsService, final FlowCapableContext context, long lifetimeNanos) {
+ super(context, lifetimeNanos);
+ this.flowTableStatsService = flowTableStatsService;
+ }
+
+ Set<TableKey> getTables() {
+ return tables;
+ }
+
+ @Override
+ protected void cleanupSingleStat(DataModificationTransaction trans, FlowTableAndStatisticsMap item) {
+ // TODO: do we want to do this?
+ }
+
+ @Override
+ protected FlowTableAndStatisticsMap updateSingleStat(DataModificationTransaction trans, FlowTableAndStatisticsMap item) {
+
+ InstanceIdentifier<Table> tableRef = getNodeIdentifierBuilder()
+ .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(item.getTableId().getValue())).build();
+
+ FlowTableStatisticsDataBuilder statisticsDataBuilder = new FlowTableStatisticsDataBuilder();
+ final FlowTableStatistics stats = new FlowTableStatisticsBuilder(item).build();
+ statisticsDataBuilder.setFlowTableStatistics(stats);
+
+ TableBuilder tableBuilder = new TableBuilder();
+ tableBuilder.setKey(new TableKey(item.getTableId().getValue()));
+ tableBuilder.addAugmentation(FlowTableStatisticsData.class, statisticsDataBuilder.build());
+ trans.putOperationalData(tableRef, tableBuilder.build());
+ return item;
+ }
+
+ public void request() {
+ if (flowTableStatsService != null) {
+ final GetFlowTablesStatisticsInputBuilder input = new GetFlowTablesStatisticsInputBuilder();
+ input.setNode(getNodeRef());
+
+ requestHelper(flowTableStatsService.getFlowTablesStatistics(input.build()));
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright IBM Corporation, 2013. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.statistics.manager;
+
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+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.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetGroupDescriptionInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStatsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.desc.GroupDescBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class GroupDescStatsTracker extends AbstractListeningStatsTracker<GroupDescStats, GroupDescStats> {
+ private static final Logger logger = LoggerFactory.getLogger(GroupDescStatsTracker.class);
+ private final OpendaylightGroupStatisticsService groupStatsService;
+
+ public GroupDescStatsTracker(OpendaylightGroupStatisticsService groupStatsService, final FlowCapableContext context, final long lifetimeNanos) {
+ super(context, lifetimeNanos);
+ this.groupStatsService = groupStatsService;
+ }
+
+ @Override
+ protected GroupDescStats updateSingleStat(DataModificationTransaction trans, GroupDescStats item) {
+ GroupBuilder groupBuilder = new GroupBuilder();
+ GroupKey groupKey = new GroupKey(item.getGroupId());
+ groupBuilder.setKey(groupKey);
+
+ InstanceIdentifier<Group> groupRef = getNodeIdentifierBuilder()
+ .augmentation(FlowCapableNode.class).child(Group.class,groupKey).build();
+
+ NodeGroupDescStatsBuilder groupDesc= new NodeGroupDescStatsBuilder();
+ groupDesc.setGroupDesc(new GroupDescBuilder(item).build());
+
+ //Update augmented data
+ groupBuilder.addAugmentation(NodeGroupDescStats.class, groupDesc.build());
+
+ trans.putOperationalData(groupRef, groupBuilder.build());
+ return item;
+ }
+
+ @Override
+ protected void cleanupSingleStat(DataModificationTransaction trans, GroupDescStats item) {
+ InstanceIdentifier<NodeGroupDescStats> groupRef = getNodeIdentifierBuilder().augmentation(FlowCapableNode.class)
+ .child(Group.class, new GroupKey(item.getGroupId())).augmentation(NodeGroupDescStats.class).build();
+ trans.removeOperationalData(groupRef);
+ }
+
+ @Override
+ protected InstanceIdentifier<?> listenPath() {
+ return getNodeIdentifierBuilder().augmentation(FlowCapableNode.class).child(Group.class).build();
+ }
+
+ @Override
+ protected String statName() {
+ return "Group Descriptor";
+ }
+
+ public void request() {
+ if (groupStatsService != null) {
+ final GetGroupDescriptionInputBuilder input = new GetGroupDescriptionInputBuilder();
+ input.setNode(getNodeRef());
+
+ requestHelper(groupStatsService.getGroupDescription(input.build()));
+ }
+ }
+
+ @Override
+ public void onDataChanged(DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
+ for (InstanceIdentifier<?> key : change.getCreatedConfigurationData().keySet()) {
+ if (Group.class.equals(key.getTargetType())) {
+ logger.debug("Key {} triggered request", key);
+ request();
+ } else {
+ logger.debug("Ignoring key {}", key);
+ }
+ }
+
+ final DataModificationTransaction trans = startTransaction();
+ for (InstanceIdentifier<?> key : change.getRemovedConfigurationData()) {
+ if (Group.class.equals(key.getTargetType())) {
+ @SuppressWarnings("unchecked")
+ InstanceIdentifier<Group> group = (InstanceIdentifier<Group>)key;
+ InstanceIdentifier<?> del = InstanceIdentifier.builder(group).augmentation(NodeGroupDescStats.class).toInstance();
+ logger.debug("Key {} triggered remove of augmentation {}", key, del);
+
+ trans.removeOperationalData(del);
+ }
+ }
+ trans.commit();
+ }
+
+ @Override
+ public void start(final DataBrokerService dbs) {
+ if (groupStatsService == null) {
+ logger.debug("No Group Statistics service, not subscribing to groups on node {}", getNodeIdentifier());
+ return;
+ }
+
+ super.start(dbs);
+ }
+}
--- /dev/null
+/*
+ * Copyright IBM Corporation, 2013. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.statistics.manager;
+
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+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.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetAllGroupStatisticsInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatistics;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.statistics.GroupStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+
+final class GroupStatsTracker extends AbstractListeningStatsTracker<GroupStats, GroupStats> {
+ private static final Logger logger = LoggerFactory.getLogger(GroupStatsTracker.class);
+ private final OpendaylightGroupStatisticsService groupStatsService;
+
+ GroupStatsTracker(OpendaylightGroupStatisticsService groupStatsService, FlowCapableContext context, long lifetimeNanos) {
+ super(context, lifetimeNanos);
+ this.groupStatsService = Preconditions.checkNotNull(groupStatsService);
+ }
+
+ @Override
+ protected void cleanupSingleStat(DataModificationTransaction trans, GroupStats item) {
+ InstanceIdentifier<NodeGroupStatistics> groupRef = getNodeIdentifierBuilder().augmentation(FlowCapableNode.class)
+ .child(Group.class, new GroupKey(item.getGroupId())).augmentation(NodeGroupStatistics.class).build();
+ trans.removeOperationalData(groupRef);
+ }
+
+ @Override
+ protected GroupStats updateSingleStat(DataModificationTransaction trans,
+ GroupStats item) {
+ GroupBuilder groupBuilder = new GroupBuilder();
+ GroupKey groupKey = new GroupKey(item.getGroupId());
+ groupBuilder.setKey(groupKey);
+
+ InstanceIdentifier<Group> groupRef = getNodeIdentifierBuilder().augmentation(FlowCapableNode.class)
+ .child(Group.class,groupKey).build();
+
+ NodeGroupStatisticsBuilder groupStatisticsBuilder= new NodeGroupStatisticsBuilder();
+ groupStatisticsBuilder.setGroupStatistics(new GroupStatisticsBuilder(item).build());
+
+ //Update augmented data
+ groupBuilder.addAugmentation(NodeGroupStatistics.class, groupStatisticsBuilder.build());
+ trans.putOperationalData(groupRef, groupBuilder.build());
+ return item;
+ }
+
+ @Override
+ protected InstanceIdentifier<?> listenPath() {
+ return getNodeIdentifierBuilder().augmentation(FlowCapableNode.class).child(Group.class).build();
+ }
+
+ @Override
+ protected String statName() {
+ return "Group";
+ }
+
+ public void request() {
+ final GetAllGroupStatisticsInputBuilder input = new GetAllGroupStatisticsInputBuilder();
+ input.setNode(getNodeRef());
+
+ requestHelper(groupStatsService.getAllGroupStatistics(input.build()));
+ }
+
+ @Override
+ public void onDataChanged(DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
+ final DataModificationTransaction trans = startTransaction();
+ for (InstanceIdentifier<?> key : change.getRemovedConfigurationData()) {
+ if (Group.class.equals(key.getTargetType())) {
+ @SuppressWarnings("unchecked")
+ InstanceIdentifier<Group> group = (InstanceIdentifier<Group>)key;
+ InstanceIdentifier<?> del = InstanceIdentifier.builder(group).augmentation(NodeGroupStatistics.class).toInstance();
+ logger.debug("Key {} triggered remove of augmentation {}", key, del);
+
+ trans.removeOperationalData(del);
+ }
+ }
+ trans.commit();
+ }
+
+ @Override
+ public void start(final DataBrokerService dbs) {
+ if (groupStatsService == null) {
+ logger.debug("No Group Statistics service, not subscribing to groups on node {}", getNodeIdentifier());
+ return;
+ }
+
+ super.start(dbs);
+ }
+}
--- /dev/null
+/*
+ * Copyright IBM Corporation, 2013. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.statistics.manager;
+
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+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.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterConfigStatisticsInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStatsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterConfigStatsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class MeterConfigStatsTracker extends AbstractListeningStatsTracker<MeterConfigStats, MeterConfigStats> {
+ private static final Logger logger = LoggerFactory.getLogger(MeterConfigStatsTracker.class);
+ private final OpendaylightMeterStatisticsService meterStatsService;
+
+ protected MeterConfigStatsTracker(OpendaylightMeterStatisticsService meterStatsService, final FlowCapableContext context, long lifetimeNanos) {
+ super(context, lifetimeNanos);
+ this.meterStatsService = meterStatsService;
+ }
+
+ @Override
+ protected void cleanupSingleStat(DataModificationTransaction trans, MeterConfigStats item) {
+ InstanceIdentifier<NodeMeterConfigStats> meterRef = getNodeIdentifierBuilder()
+ .augmentation(FlowCapableNode.class)
+ .child(Meter.class, new MeterKey(item.getMeterId()))
+ .augmentation(NodeMeterConfigStats.class).build();
+ trans.removeOperationalData(meterRef);
+ }
+
+ @Override
+ protected MeterConfigStats updateSingleStat(DataModificationTransaction trans, MeterConfigStats item) {
+ MeterBuilder meterBuilder = new MeterBuilder();
+ MeterKey meterKey = new MeterKey(item.getMeterId());
+ meterBuilder.setKey(meterKey);
+
+ InstanceIdentifier<Meter> meterRef = getNodeIdentifierBuilder().augmentation(FlowCapableNode.class)
+ .child(Meter.class,meterKey).toInstance();
+
+ NodeMeterConfigStatsBuilder meterConfig = new NodeMeterConfigStatsBuilder();
+ meterConfig.setMeterConfigStats(new MeterConfigStatsBuilder(item).build());
+
+ //Update augmented data
+ meterBuilder.addAugmentation(NodeMeterConfigStats.class, meterConfig.build());
+
+ trans.putOperationalData(meterRef, meterBuilder.build());
+ return item;
+ }
+
+ public void request() {
+ if (meterStatsService != null) {
+ GetAllMeterConfigStatisticsInputBuilder input = new GetAllMeterConfigStatisticsInputBuilder();
+ input.setNode(getNodeRef());
+
+ requestHelper(meterStatsService.getAllMeterConfigStatistics(input.build()));
+ }
+ }
+
+ @Override
+ public void onDataChanged(DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
+ final DataModificationTransaction trans = startTransaction();
+
+ for (InstanceIdentifier<?> key : change.getRemovedConfigurationData()) {
+ if (Meter.class.equals(key.getTargetType())) {
+ @SuppressWarnings("unchecked")
+ InstanceIdentifier<Meter> meter = (InstanceIdentifier<Meter>)key;
+
+ InstanceIdentifier<?> nodeMeterStatisticsAugmentation =
+ InstanceIdentifier.builder(meter).augmentation(NodeMeterConfigStats.class).toInstance();
+ trans.removeOperationalData(nodeMeterStatisticsAugmentation);
+ }
+ }
+
+ trans.commit();
+ }
+
+ @Override
+ protected InstanceIdentifier<?> listenPath() {
+ return getNodeIdentifierBuilder().augmentation(FlowCapableNode.class).child(Meter.class).build();
+ }
+
+ @Override
+ protected String statName() {
+ return "Meter Config";
+ }
+
+ @Override
+ public void start(final DataBrokerService dbs) {
+ if (meterStatsService == null) {
+ logger.debug("No Meter Statistics service, not subscribing to meter on node {}", getNodeIdentifier());
+ return;
+ }
+
+ super.start(dbs);
+ }
+}
--- /dev/null
+/*
+ * Copyright IBM Corporation, 2013. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.statistics.manager;
+
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+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.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterStatisticsInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatistics;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class MeterStatsTracker extends AbstractListeningStatsTracker<MeterStats, MeterStats> {
+ private static final Logger logger = LoggerFactory.getLogger(MeterStatsTracker.class);
+ private final OpendaylightMeterStatisticsService meterStatsService;
+
+ MeterStatsTracker(OpendaylightMeterStatisticsService meterStatsService, final FlowCapableContext context, long lifetimeNanos) {
+ super(context, lifetimeNanos);
+ this.meterStatsService = meterStatsService;
+ }
+
+ @Override
+ protected void cleanupSingleStat(DataModificationTransaction trans, MeterStats item) {
+ InstanceIdentifier<NodeMeterStatistics> meterRef = getNodeIdentifierBuilder()
+ .augmentation(FlowCapableNode.class)
+ .child(Meter.class,new MeterKey(item.getMeterId()))
+ .augmentation(NodeMeterStatistics.class).build();
+ trans.removeOperationalData(meterRef);
+ }
+
+ @Override
+ protected MeterStats updateSingleStat(DataModificationTransaction trans, MeterStats item) {
+ MeterBuilder meterBuilder = new MeterBuilder();
+ MeterKey meterKey = new MeterKey(item.getMeterId());
+ meterBuilder.setKey(meterKey);
+
+ InstanceIdentifier<Meter> meterRef = getNodeIdentifierBuilder()
+ .augmentation(FlowCapableNode.class).child(Meter.class,meterKey).build();
+
+ NodeMeterStatisticsBuilder meterStatsBuilder= new NodeMeterStatisticsBuilder();
+ meterStatsBuilder.setMeterStatistics(new MeterStatisticsBuilder(item).build());
+
+ //Update augmented data
+ meterBuilder.addAugmentation(NodeMeterStatistics.class, meterStatsBuilder.build());
+ trans.putOperationalData(meterRef, meterBuilder.build());
+ return item;
+ }
+
+ public void request() {
+ if (meterStatsService != null) {
+ GetAllMeterStatisticsInputBuilder input = new GetAllMeterStatisticsInputBuilder();
+ input.setNode(getNodeRef());
+
+ requestHelper(meterStatsService.getAllMeterStatistics(input.build()));
+ }
+ }
+
+ @Override
+ public void onDataChanged(DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
+ for (InstanceIdentifier<?> key : change.getCreatedConfigurationData().keySet()) {
+ if (Meter.class.equals(key.getTargetType())) {
+ request();
+ }
+ }
+
+ final DataModificationTransaction trans = startTransaction();
+ for (InstanceIdentifier<?> key : change.getRemovedConfigurationData()) {
+ if (Meter.class.equals(key.getTargetType())) {
+ @SuppressWarnings("unchecked")
+ InstanceIdentifier<Meter> meter = (InstanceIdentifier<Meter>)key;
+
+ InstanceIdentifier<?> nodeMeterStatisticsAugmentation =
+ InstanceIdentifier.builder(meter).augmentation(NodeMeterStatistics.class).toInstance();
+ trans.removeOperationalData(nodeMeterStatisticsAugmentation);
+ }
+ }
+ trans.commit();
+ }
+
+ @Override
+ protected InstanceIdentifier<?> listenPath() {
+ return getNodeIdentifierBuilder().augmentation(FlowCapableNode.class).child(Meter.class).build();
+ }
+
+ @Override
+ protected String statName() {
+ return "Meter";
+ }
+
+ @Override
+ public void start(final DataBrokerService dbs) {
+ if (meterStatsService == null) {
+ logger.debug("No Meter Statistics service, not subscribing to meters on node {}", getNodeIdentifier());
+ return;
+ }
+
+ super.start(dbs);
+ }
+}
*/
package org.opendaylight.controller.md.statistics.manager;
-import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionAware;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+
+import com.google.common.base.Preconditions;
/**
- * Main responsibility of the class is to manage multipart response
+ * Main responsibility of the class is to manage multipart response
* for multipart request. It also handles the flow aggregate request
- * and response mapping.
+ * and response mapping.
* @author avishnoi@in.ibm.com
*
*/
-public class MultipartMessageManager {
-
+class MultipartMessageManager {
/*
- * Map for tx id and type of request, to keep track of all the request sent
- * by Statistics Manager. Statistics Manager won't entertain any multipart
- * response for which it didn't send the request.
+ * Map for tx id and type of request, to keep track of all the request sent
+ * by Statistics Manager. Statistics Manager won't entertain any multipart
+ * response for which it didn't send the request.
*/
-
- private static Map<TxIdEntry,Date> txIdToRequestTypeMap = new ConcurrentHashMap<TxIdEntry,Date>();
+ private final Map<TxIdEntry,Long> txIdToRequestTypeMap = new ConcurrentHashMap<>();
/*
* Map to keep track of the request tx id for flow table statistics request.
* Because flow table statistics multi part response do not contains the table id.
*/
- private static Map<TxIdEntry,Short> txIdTotableIdMap = new ConcurrentHashMap<TxIdEntry,Short>();
-
- private final int NUMBER_OF_WAIT_CYCLES =2;
+ private final Map<TxIdEntry,Short> txIdTotableIdMap = new ConcurrentHashMap<>();
+ private final long lifetimeNanos;
+
+ public MultipartMessageManager(long lifetimeNanos) {
+ this.lifetimeNanos = lifetimeNanos;
+ }
- class TxIdEntry{
+ private static final class TxIdEntry {
private final TransactionId txId;
- private final NodeId nodeId;
- private final StatsRequestType requestType;
-
- public TxIdEntry(NodeId nodeId, TransactionId txId, StatsRequestType requestType){
+
+ public TxIdEntry(TransactionId txId) {
this.txId = txId;
- this.nodeId = nodeId;
- this.requestType = requestType;
}
public TransactionId getTxId() {
return txId;
}
- public NodeId getNodeId() {
- return nodeId;
- }
- public StatsRequestType getRequestType() {
- return requestType;
- }
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
- result = prime * result + getOuterType().hashCode();
- result = prime * result + ((nodeId == null) ? 0 : nodeId.hashCode());
result = prime * result + ((txId == null) ? 0 : txId.hashCode());
return result;
}
return false;
}
TxIdEntry other = (TxIdEntry) obj;
- if (!getOuterType().equals(other.getOuterType())) {
- return false;
- }
- if (nodeId == null) {
- if (other.nodeId != null) {
- return false;
- }
- } else if (!nodeId.equals(other.nodeId)) {
- return false;
- }
+
if (txId == null) {
if (other.txId != null) {
return false;
}
return true;
}
- private MultipartMessageManager getOuterType() {
- return MultipartMessageManager.this;
- }
+
@Override
public String toString() {
- return "TxIdEntry [txId=" + txId + ", nodeId=" + nodeId + ", requestType=" + requestType + "]";
+ return "TxIdEntry [txId=" + txId + ']';
}
}
- public MultipartMessageManager(){}
-
- public Short getTableIdForTxId(NodeId nodeId,TransactionId id){
-
- return txIdTotableIdMap.get(new TxIdEntry(nodeId,id,null));
-
- }
-
- public void setTxIdAndTableIdMapEntry(NodeId nodeId, TransactionId id,Short tableId){
- if(id == null)
- return;
- txIdTotableIdMap.put(new TxIdEntry(nodeId,id,null), tableId);
+ public void recordExpectedTableTransaction(TransactionId id, Short tableId) {
+ recordExpectedTransaction(id);
+ txIdTotableIdMap.put(new TxIdEntry(id), Preconditions.checkNotNull(tableId));
}
-
- public boolean isRequestTxIdExist(NodeId nodeId, TransactionId id, Boolean moreRepliesToFollow){
- TxIdEntry entry = new TxIdEntry(nodeId,id,null);
- if(moreRepliesToFollow.booleanValue()){
- return txIdToRequestTypeMap.containsKey(entry);
- }else{
- return txIdToRequestTypeMap.remove(entry)==null?false:true;
+
+ public Short isExpectedTableTransaction(TransactionAware transaction, Boolean more) {
+ if (!isExpectedTransaction(transaction, more)) {
+ return null;
+ }
+
+ final TxIdEntry key = new TxIdEntry(transaction.getTransactionId());
+ if (more != null && more.booleanValue()) {
+ return txIdTotableIdMap.get(key);
+ } else {
+ return txIdTotableIdMap.remove(key);
}
}
- public void addTxIdToRequestTypeEntry (NodeId nodeId, TransactionId id,StatsRequestType type){
- if(id == null)
- return;
- TxIdEntry entry = new TxIdEntry(nodeId,id,type);
+
+ public void recordExpectedTransaction(TransactionId id) {
+ TxIdEntry entry = new TxIdEntry(Preconditions.checkNotNull(id));
txIdToRequestTypeMap.put(entry, getExpiryTime());
}
- public boolean removeTxId(NodeId nodeId, TransactionId id){
- TxIdEntry entry = new TxIdEntry(nodeId,id,null);
- return txIdToRequestTypeMap.remove(entry)==null?false:true;
- }
-
- private Date getExpiryTime(){
- Date expires = new Date();
- expires.setTime(expires.getTime()+StatisticsProvider.STATS_THREAD_EXECUTION_TIME*NUMBER_OF_WAIT_CYCLES);
- return expires;
+
+ public boolean isExpectedTransaction(TransactionAware transaction, Boolean more) {
+ TxIdEntry entry = new TxIdEntry(transaction.getTransactionId());
+ if (more != null && more.booleanValue()) {
+ return txIdToRequestTypeMap.containsKey(entry);
+ } else {
+ return txIdToRequestTypeMap.remove(entry) != null;
+ }
}
- public enum StatsRequestType{
- ALL_FLOW,
- AGGR_FLOW,
- ALL_PORT,
- ALL_FLOW_TABLE,
- ALL_QUEUE_STATS,
- ALL_GROUP,
- ALL_METER,
- GROUP_DESC,
- METER_CONFIG
+ private Long getExpiryTime() {
+ return System.nanoTime() + lifetimeNanos;
}
-
- public void cleanStaleTransactionIds(){
+
+ public void cleanStaleTransactionIds() {
+ final long now = System.nanoTime();
+
for (Iterator<TxIdEntry> it = txIdToRequestTypeMap.keySet().iterator();it.hasNext();){
TxIdEntry txIdEntry = it.next();
- Date now = new Date();
- Date expiryTime = txIdToRequestTypeMap.get(txIdEntry);
- if(now.after(expiryTime)){
+
+ Long expiryTime = txIdToRequestTypeMap.get(txIdEntry);
+ if(now > expiryTime){
it.remove();
txIdTotableIdMap.remove(txIdEntry);
- }
+ }
}
}
}
--- /dev/null
+/*
+ * Copyright IBM Corporation, 2013. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.statistics.manager;
+
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsDataBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetAllNodeConnectorsStatisticsInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.flow.capable.node.connector.statistics.FlowCapableNodeConnectorStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class NodeConnectorStatsTracker extends AbstractStatsTracker<NodeConnectorStatisticsAndPortNumberMap, NodeConnectorStatisticsAndPortNumberMap> {
+ private static final Logger logger = LoggerFactory.getLogger(NodeConnectorStatsTracker.class);
+ private final OpendaylightPortStatisticsService portStatsService;
+
+ NodeConnectorStatsTracker(final OpendaylightPortStatisticsService portStatsService, final FlowCapableContext context, long lifetimeNanos) {
+ super(context, lifetimeNanos);
+ this.portStatsService = portStatsService;
+ }
+
+ @Override
+ protected void cleanupSingleStat(DataModificationTransaction trans, NodeConnectorStatisticsAndPortNumberMap item) {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ protected NodeConnectorStatisticsAndPortNumberMap updateSingleStat(DataModificationTransaction trans, NodeConnectorStatisticsAndPortNumberMap item) {
+ FlowCapableNodeConnectorStatisticsBuilder statisticsBuilder
+ = new FlowCapableNodeConnectorStatisticsBuilder();
+ statisticsBuilder.setBytes(item.getBytes());
+ statisticsBuilder.setCollisionCount(item.getCollisionCount());
+ statisticsBuilder.setDuration(item.getDuration());
+ statisticsBuilder.setPackets(item.getPackets());
+ statisticsBuilder.setReceiveCrcError(item.getReceiveCrcError());
+ statisticsBuilder.setReceiveDrops(item.getReceiveDrops());
+ statisticsBuilder.setReceiveErrors(item.getReceiveErrors());
+ statisticsBuilder.setReceiveFrameError(item.getReceiveFrameError());
+ statisticsBuilder.setReceiveOverRunError(item.getReceiveOverRunError());
+ statisticsBuilder.setTransmitDrops(item.getTransmitDrops());
+ statisticsBuilder.setTransmitErrors(item.getTransmitErrors());
+
+ //Augment data to the node-connector
+ FlowCapableNodeConnectorStatisticsDataBuilder statisticsDataBuilder =
+ new FlowCapableNodeConnectorStatisticsDataBuilder();
+
+ statisticsDataBuilder.setFlowCapableNodeConnectorStatistics(statisticsBuilder.build());
+
+ InstanceIdentifier<NodeConnector> nodeConnectorRef = getNodeIdentifierBuilder()
+ .child(NodeConnector.class, new NodeConnectorKey(item.getNodeConnectorId())).build();
+
+ // FIXME: can we bypass this read?
+ NodeConnector nodeConnector = (NodeConnector)trans.readOperationalData(nodeConnectorRef);
+ if(nodeConnector != null){
+ final FlowCapableNodeConnectorStatisticsData stats = statisticsDataBuilder.build();
+ logger.debug("Augmenting port statistics {} to port {}",stats,nodeConnectorRef.toString());
+ NodeConnectorBuilder nodeConnectorBuilder = new NodeConnectorBuilder();
+ nodeConnectorBuilder.addAugmentation(FlowCapableNodeConnectorStatisticsData.class, stats);
+ trans.putOperationalData(nodeConnectorRef, nodeConnectorBuilder.build());
+ }
+
+ return item;
+ }
+
+ public void request() {
+ if (portStatsService != null) {
+ final GetAllNodeConnectorsStatisticsInputBuilder input = new GetAllNodeConnectorsStatisticsInputBuilder();
+ input.setNode(getNodeRef());
+
+ requestHelper(portStatsService.getAllNodeConnectorsStatistics(input.build()));
+ }
+ }
+}
*/
package org.opendaylight.controller.md.statistics.manager;
-import java.util.HashMap;
-import java.util.Iterator;
+import java.util.Collection;
import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
+import java.util.Timer;
+import java.util.TimerTask;
import java.util.concurrent.TimeUnit;
import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsData;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsDataBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsData;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsDataBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.aggregate.flow.statistics.AggregateFlowStatisticsBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapListBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.statistics.FlowStatisticsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsData;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsDataBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMap;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.statistics.FlowTableStatistics;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.statistics.FlowTableStatisticsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.Queue;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.queue.rev130925.QueueId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStats;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStatsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionAware;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeatures;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeaturesBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatistics;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatisticsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.desc.GroupDescBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.features.GroupFeaturesBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.statistics.GroupStatisticsBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupFeatures;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStats;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStats;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStatsBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeatures;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeaturesBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatistics;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterFeaturesBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterConfigStatsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterStatisticsBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterFeatures;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats;
import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.AggregateFlowStatistics;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericStatistics;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsData;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsDataBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.flow.capable.node.connector.statistics.FlowCapableNodeConnectorStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsData;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsDataBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.flow.capable.node.connector.queue.statistics.FlowCapableNodeConnectorQueueStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.queue.id.and.statistics.map.QueueIdAndStatisticsMap;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
*
* @author avishnoi@in.ibm.com
*/
-public class NodeStatisticsHandler {
+public final class NodeStatisticsHandler implements AutoCloseable, FlowCapableContext {
private static final Logger logger = LoggerFactory.getLogger(NodeStatisticsHandler.class);
+
+ private static final long STATS_COLLECTION_MILLIS = TimeUnit.SECONDS.toMillis(15);
+ private static final long FIRST_COLLECTION_MILLIS = TimeUnit.SECONDS.toMillis(5);
private static final int NUMBER_OF_WAIT_CYCLES = 2;
- private final Map<GroupDescStats,Long> groupDescStatsUpdate = new HashMap<>();
- private final Map<MeterConfigStats,Long> meterConfigStatsUpdate = new HashMap<>();
- private final Map<FlowEntry,Long> flowStatsUpdate = new HashMap<>();
- private final Map<QueueEntry,Long> queuesStatsUpdate = new HashMap<>();
+ private final MultipartMessageManager msgManager;
private final InstanceIdentifier<Node> targetNodeIdentifier;
- private final StatisticsProvider statisticsProvider;
+ private final FlowStatsTracker flowStats;
+ private final FlowTableStatsTracker flowTableStats;
+ private final GroupDescStatsTracker groupDescStats;
+ private final GroupStatsTracker groupStats;
+ private final MeterConfigStatsTracker meterConfigStats;
+ private final MeterStatsTracker meterStats;
+ private final NodeConnectorStatsTracker nodeConnectorStats;
+ private final QueueStatsTracker queueStats;
+ private final DataProviderService dps;
+ private final NodeRef targetNodeRef;
private final NodeKey targetNodeKey;
- private int unaccountedFlowsCounter = 1;
-
- public NodeStatisticsHandler(StatisticsProvider statisticsProvider, NodeKey nodeKey){
- this.statisticsProvider = Preconditions.checkNotNull(statisticsProvider);
- this.targetNodeKey = Preconditions.checkNotNull(nodeKey);
- this.targetNodeIdentifier = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey).build();
- }
-
- private static class FlowEntry {
- private final Short tableId;
- private final Flow flow;
-
- public FlowEntry(Short tableId, Flow flow){
- this.tableId = tableId;
- this.flow = flow;
- }
-
- public Short getTableId() {
- return tableId;
- }
-
- public Flow getFlow() {
- return flow;
- }
-
+ private final TimerTask task = new TimerTask() {
@Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((flow == null) ? 0 : flow.hashCode());
- result = prime * result + ((tableId == null) ? 0 : tableId.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- FlowEntry other = (FlowEntry) obj;
- if (flow == null) {
- if (other.flow != null)
- return false;
- } else if (!flow.equals(other.flow))
- return false;
- if (tableId == null) {
- if (other.tableId != null)
- return false;
- } else if (!tableId.equals(other.tableId))
- return false;
- return true;
- }
- }
-
- private static final class QueueEntry{
- private final NodeConnectorId nodeConnectorId;
- private final QueueId queueId;
- public QueueEntry(NodeConnectorId ncId, QueueId queueId){
- this.nodeConnectorId = ncId;
- this.queueId = queueId;
- }
- public NodeConnectorId getNodeConnectorId() {
- return nodeConnectorId;
- }
- public QueueId getQueueId() {
- return queueId;
- }
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((nodeConnectorId == null) ? 0 : nodeConnectorId.hashCode());
- result = prime * result + ((queueId == null) ? 0 : queueId.hashCode());
- return result;
- }
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (!(obj instanceof QueueEntry)) {
- return false;
- }
- QueueEntry other = (QueueEntry) obj;
- if (nodeConnectorId == null) {
- if (other.nodeConnectorId != null) {
- return false;
- }
- } else if (!nodeConnectorId.equals(other.nodeConnectorId)) {
- return false;
- }
- if (queueId == null) {
- if (other.queueId != null) {
- return false;
- }
- } else if (!queueId.equals(other.queueId)) {
- return false;
- }
- return true;
+ public void run() {
+ requestPeriodicStatistics();
+ cleanStaleStatistics();
}
+ };
+
+ public NodeStatisticsHandler(final DataProviderService dps, final NodeKey nodeKey,
+ final OpendaylightFlowStatisticsService flowStatsService,
+ final OpendaylightFlowTableStatisticsService flowTableStatsService,
+ final OpendaylightGroupStatisticsService groupStatsService,
+ final OpendaylightMeterStatisticsService meterStatsService,
+ final OpendaylightPortStatisticsService portStatsService,
+ final OpendaylightQueueStatisticsService queueStatsService) {
+ this.dps = Preconditions.checkNotNull(dps);
+ this.targetNodeKey = Preconditions.checkNotNull(nodeKey);
+ this.targetNodeIdentifier = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey).build();
+ this.targetNodeRef = new NodeRef(targetNodeIdentifier);
+
+ final long lifetimeNanos = TimeUnit.MILLISECONDS.toNanos(STATS_COLLECTION_MILLIS * NUMBER_OF_WAIT_CYCLES);
+
+ msgManager = new MultipartMessageManager(lifetimeNanos);
+ flowStats = new FlowStatsTracker(flowStatsService, this, lifetimeNanos);
+ flowTableStats = new FlowTableStatsTracker(flowTableStatsService, this, lifetimeNanos);
+ groupDescStats = new GroupDescStatsTracker(groupStatsService, this, lifetimeNanos);
+ groupStats = new GroupStatsTracker(groupStatsService, this, lifetimeNanos);
+ meterConfigStats = new MeterConfigStatsTracker(meterStatsService, this, lifetimeNanos);
+ meterStats = new MeterStatsTracker(meterStatsService, this, lifetimeNanos);
+ nodeConnectorStats = new NodeConnectorStatsTracker(portStatsService, this, lifetimeNanos);
+ queueStats = new QueueStatsTracker(queueStatsService, this, lifetimeNanos);
}
public NodeKey getTargetNodeKey() {
return targetNodeKey;
}
- public synchronized void updateGroupDescStats(List<GroupDescStats> list){
- final Long expiryTime = getExpiryTime();
- final DataModificationTransaction trans = statisticsProvider.startChange();
-
- for (GroupDescStats groupDescStats : list) {
- GroupBuilder groupBuilder = new GroupBuilder();
- GroupKey groupKey = new GroupKey(groupDescStats.getGroupId());
- groupBuilder.setKey(groupKey);
-
- InstanceIdentifier<Group> groupRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
- .augmentation(FlowCapableNode.class)
- .child(Group.class,groupKey).toInstance();
+ @Override
+ public InstanceIdentifier<Node> getNodeIdentifier() {
+ return targetNodeIdentifier;
+ }
- NodeGroupDescStatsBuilder groupDesc= new NodeGroupDescStatsBuilder();
- GroupDescBuilder stats = new GroupDescBuilder();
- stats.fieldsFrom(groupDescStats);
- groupDesc.setGroupDesc(stats.build());
+ @Override
+ public NodeRef getNodeRef() {
+ return targetNodeRef;
+ }
- //Update augmented data
- groupBuilder.addAugmentation(NodeGroupDescStats.class, groupDesc.build());
+ @Override
+ public DataModificationTransaction startDataModification() {
+ return dps.beginTransaction();
+ }
- trans.putOperationalData(groupRef, groupBuilder.build());
- this.groupDescStatsUpdate.put(groupDescStats, expiryTime);
+ public synchronized void updateGroupDescStats(TransactionAware transaction, Boolean more, List<GroupDescStats> list) {
+ if (msgManager.isExpectedTransaction(transaction, more)) {
+ groupDescStats.updateStats(list);
}
-
- trans.commit();
}
-
- public synchronized void updateGroupStats(List<GroupStats> list) {
- final DataModificationTransaction trans = statisticsProvider.startChange();
-
- for(GroupStats groupStats : list) {
- GroupBuilder groupBuilder = new GroupBuilder();
- GroupKey groupKey = new GroupKey(groupStats.getGroupId());
- groupBuilder.setKey(groupKey);
-
- InstanceIdentifier<Group> groupRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
- .augmentation(FlowCapableNode.class)
- .child(Group.class,groupKey).toInstance();
-
- NodeGroupStatisticsBuilder groupStatisticsBuilder= new NodeGroupStatisticsBuilder();
- GroupStatisticsBuilder stats = new GroupStatisticsBuilder();
- stats.fieldsFrom(groupStats);
- groupStatisticsBuilder.setGroupStatistics(stats.build());
-
- //Update augmented data
- groupBuilder.addAugmentation(NodeGroupStatistics.class, groupStatisticsBuilder.build());
- trans.putOperationalData(groupRef, groupBuilder.build());
-
- // FIXME: should we be tracking this data?
+ public synchronized void updateGroupStats(TransactionAware transaction, Boolean more, List<GroupStats> list) {
+ if (msgManager.isExpectedTransaction(transaction, more)) {
+ groupStats.updateStats(list);
}
-
- trans.commit();
}
- public synchronized void updateMeterConfigStats(List<MeterConfigStats> list) {
- final Long expiryTime = getExpiryTime();
- final DataModificationTransaction trans = statisticsProvider.startChange();
-
- for(MeterConfigStats meterConfigStats : list) {
- MeterBuilder meterBuilder = new MeterBuilder();
- MeterKey meterKey = new MeterKey(meterConfigStats.getMeterId());
- meterBuilder.setKey(meterKey);
-
- InstanceIdentifier<Meter> meterRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
- .augmentation(FlowCapableNode.class)
- .child(Meter.class,meterKey).toInstance();
-
- NodeMeterConfigStatsBuilder meterConfig= new NodeMeterConfigStatsBuilder();
- MeterConfigStatsBuilder stats = new MeterConfigStatsBuilder();
- stats.fieldsFrom(meterConfigStats);
- meterConfig.setMeterConfigStats(stats.build());
-
- //Update augmented data
- meterBuilder.addAugmentation(NodeMeterConfigStats.class, meterConfig.build());
-
- trans.putOperationalData(meterRef, meterBuilder.build());
- this.meterConfigStatsUpdate.put(meterConfigStats, expiryTime);
+ public synchronized void updateMeterConfigStats(TransactionAware transaction, Boolean more, List<MeterConfigStats> list) {
+ if (msgManager.isExpectedTransaction(transaction, more)) {
+ meterConfigStats.updateStats(list);
}
-
- trans.commit();
}
-
- public synchronized void updateMeterStats(List<MeterStats> list) {
- final DataModificationTransaction trans = statisticsProvider.startChange();
-
- for(MeterStats meterStats : list) {
- MeterBuilder meterBuilder = new MeterBuilder();
- MeterKey meterKey = new MeterKey(meterStats.getMeterId());
- meterBuilder.setKey(meterKey);
-
- InstanceIdentifier<Meter> meterRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
- .augmentation(FlowCapableNode.class)
- .child(Meter.class,meterKey).toInstance();
-
- NodeMeterStatisticsBuilder meterStatsBuilder= new NodeMeterStatisticsBuilder();
- MeterStatisticsBuilder stats = new MeterStatisticsBuilder();
- stats.fieldsFrom(meterStats);
- meterStatsBuilder.setMeterStatistics(stats.build());
-
- //Update augmented data
- meterBuilder.addAugmentation(NodeMeterStatistics.class, meterStatsBuilder.build());
- trans.putOperationalData(meterRef, meterBuilder.build());
-
- // FIXME: should we be tracking this data?
+ public synchronized void updateMeterStats(TransactionAware transaction, Boolean more, List<MeterStats> list) {
+ if (msgManager.isExpectedTransaction(transaction, more)) {
+ meterStats.updateStats(list);
}
-
- trans.commit();
}
- public synchronized void updateQueueStats(List<QueueIdAndStatisticsMap> list) {
- final Long expiryTime = getExpiryTime();
- final DataModificationTransaction trans = statisticsProvider.startChange();
-
- for (QueueIdAndStatisticsMap swQueueStats : list) {
-
- QueueEntry queueEntry = new QueueEntry(swQueueStats.getNodeConnectorId(),swQueueStats.getQueueId());
-
- FlowCapableNodeConnectorQueueStatisticsDataBuilder queueStatisticsDataBuilder = new FlowCapableNodeConnectorQueueStatisticsDataBuilder();
-
- FlowCapableNodeConnectorQueueStatisticsBuilder queueStatisticsBuilder = new FlowCapableNodeConnectorQueueStatisticsBuilder();
-
- queueStatisticsBuilder.fieldsFrom(swQueueStats);
-
- queueStatisticsDataBuilder.setFlowCapableNodeConnectorQueueStatistics(queueStatisticsBuilder.build());
-
- InstanceIdentifier<Queue> queueRef
- = InstanceIdentifier.builder(Nodes.class)
- .child(Node.class, targetNodeKey)
- .child(NodeConnector.class, new NodeConnectorKey(swQueueStats.getNodeConnectorId()))
- .augmentation(FlowCapableNodeConnector.class)
- .child(Queue.class, new QueueKey(swQueueStats.getQueueId())).toInstance();
-
- QueueBuilder queueBuilder = new QueueBuilder();
- FlowCapableNodeConnectorQueueStatisticsData qsd = queueStatisticsDataBuilder.build();
- queueBuilder.addAugmentation(FlowCapableNodeConnectorQueueStatisticsData.class, qsd);
- queueBuilder.setKey(new QueueKey(swQueueStats.getQueueId()));
-
- logger.debug("Augmenting queue statistics {} of queue {} to port {}",
- qsd,
- swQueueStats.getQueueId(),
- swQueueStats.getNodeConnectorId());
-
- trans.putOperationalData(queueRef, queueBuilder.build());
- this.queuesStatsUpdate.put(queueEntry, expiryTime);
+ public synchronized void updateQueueStats(TransactionAware transaction, Boolean more, List<QueueIdAndStatisticsMap> list) {
+ if (msgManager.isExpectedTransaction(transaction, more)) {
+ queueStats.updateStats(list);
}
-
- trans.commit();
}
- public synchronized void updateFlowTableStats(List<FlowTableAndStatisticsMap> list) {
- final DataModificationTransaction trans = statisticsProvider.startChange();
-
- for (FlowTableAndStatisticsMap ftStats : list) {
-
- InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
- .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(ftStats.getTableId().getValue())).toInstance();
-
- FlowTableStatisticsDataBuilder statisticsDataBuilder = new FlowTableStatisticsDataBuilder();
-
- FlowTableStatisticsBuilder statisticsBuilder = new FlowTableStatisticsBuilder();
- statisticsBuilder.setActiveFlows(ftStats.getActiveFlows());
- statisticsBuilder.setPacketsLookedUp(ftStats.getPacketsLookedUp());
- statisticsBuilder.setPacketsMatched(ftStats.getPacketsMatched());
-
- final FlowTableStatistics stats = statisticsBuilder.build();
- statisticsDataBuilder.setFlowTableStatistics(stats);
-
- logger.debug("Augment flow table statistics: {} for table {} on Node {}",
- stats,ftStats.getTableId(), targetNodeKey);
-
- TableBuilder tableBuilder = new TableBuilder();
- tableBuilder.setKey(new TableKey(ftStats.getTableId().getValue()));
- tableBuilder.addAugmentation(FlowTableStatisticsData.class, statisticsDataBuilder.build());
- trans.putOperationalData(tableRef, tableBuilder.build());
-
- // FIXME: should we be tracking this data?
+ public synchronized void updateFlowTableStats(TransactionAware transaction, Boolean more, List<FlowTableAndStatisticsMap> list) {
+ if (msgManager.isExpectedTransaction(transaction, more)) {
+ flowTableStats.updateStats(list);
}
-
- trans.commit();
}
- public synchronized void updateNodeConnectorStats(List<NodeConnectorStatisticsAndPortNumberMap> list) {
- final DataModificationTransaction trans = statisticsProvider.startChange();
-
- for(NodeConnectorStatisticsAndPortNumberMap portStats : list) {
-
- FlowCapableNodeConnectorStatisticsBuilder statisticsBuilder
- = new FlowCapableNodeConnectorStatisticsBuilder();
- statisticsBuilder.setBytes(portStats.getBytes());
- statisticsBuilder.setCollisionCount(portStats.getCollisionCount());
- statisticsBuilder.setDuration(portStats.getDuration());
- statisticsBuilder.setPackets(portStats.getPackets());
- statisticsBuilder.setReceiveCrcError(portStats.getReceiveCrcError());
- statisticsBuilder.setReceiveDrops(portStats.getReceiveDrops());
- statisticsBuilder.setReceiveErrors(portStats.getReceiveErrors());
- statisticsBuilder.setReceiveFrameError(portStats.getReceiveFrameError());
- statisticsBuilder.setReceiveOverRunError(portStats.getReceiveOverRunError());
- statisticsBuilder.setTransmitDrops(portStats.getTransmitDrops());
- statisticsBuilder.setTransmitErrors(portStats.getTransmitErrors());
-
- //Augment data to the node-connector
- FlowCapableNodeConnectorStatisticsDataBuilder statisticsDataBuilder =
- new FlowCapableNodeConnectorStatisticsDataBuilder();
-
- statisticsDataBuilder.setFlowCapableNodeConnectorStatistics(statisticsBuilder.build());
-
- InstanceIdentifier<NodeConnector> nodeConnectorRef = InstanceIdentifier.builder(Nodes.class)
- .child(Node.class, targetNodeKey)
- .child(NodeConnector.class, new NodeConnectorKey(portStats.getNodeConnectorId())).toInstance();
-
- // FIXME: can we bypass this read?
- NodeConnector nodeConnector = (NodeConnector)trans.readOperationalData(nodeConnectorRef);
- if(nodeConnector != null){
- final FlowCapableNodeConnectorStatisticsData stats = statisticsDataBuilder.build();
- logger.debug("Augmenting port statistics {} to port {}",stats,nodeConnectorRef.toString());
- NodeConnectorBuilder nodeConnectorBuilder = new NodeConnectorBuilder();
- nodeConnectorBuilder.addAugmentation(FlowCapableNodeConnectorStatisticsData.class, stats);
- trans.putOperationalData(nodeConnectorRef, nodeConnectorBuilder.build());
- }
-
- // FIXME: should we be tracking this data?
+ public synchronized void updateNodeConnectorStats(TransactionAware transaction, Boolean more, List<NodeConnectorStatisticsAndPortNumberMap> list) {
+ if (msgManager.isExpectedTransaction(transaction, more)) {
+ nodeConnectorStats.updateStats(list);
}
-
- trans.commit();
}
- public synchronized void updateAggregateFlowStats(Short tableId, AggregateFlowStatistics flowStats) {
+ public synchronized void updateAggregateFlowStats(TransactionAware transaction, Boolean more, AggregateFlowStatistics flowStats) {
+ final Short tableId = msgManager.isExpectedTableTransaction(transaction, more);
if (tableId != null) {
- final DataModificationTransaction trans = statisticsProvider.startChange();
-
-
+ final DataModificationTransaction trans = dps.beginTransaction();
InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
.augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
tableBuilder.addAugmentation(AggregateFlowStatisticsData.class, aggregateFlowStatisticsDataBuilder.build());
trans.putOperationalData(tableRef, tableBuilder.build());
- // FIXME: should we be tracking this data?
trans.commit();
}
}
+ public synchronized void updateFlowStats(TransactionAware transaction, Boolean more, List<FlowAndStatisticsMapList> list) {
+ if (msgManager.isExpectedTransaction(transaction, more)) {
+ flowStats.updateStats(list);
+ }
+ }
+
public synchronized void updateGroupFeatures(GroupFeatures notification) {
- final DataModificationTransaction trans = statisticsProvider.startChange();
+ final DataModificationTransaction trans = dps.beginTransaction();
final NodeBuilder nodeData = new NodeBuilder();
nodeData.setKey(targetNodeKey);
}
public synchronized void updateMeterFeatures(MeterFeatures features) {
- final DataModificationTransaction trans = statisticsProvider.startChange();
+ final DataModificationTransaction trans = dps.beginTransaction();
final NodeBuilder nodeData = new NodeBuilder();
nodeData.setKey(targetNodeKey);
trans.commit();
}
- public synchronized void updateFlowStats(List<FlowAndStatisticsMapList> list) {
- final Long expiryTime = getExpiryTime();
- final DataModificationTransaction trans = statisticsProvider.startChange();
-
- for(FlowAndStatisticsMapList map : list) {
- short tableId = map.getTableId();
- boolean foundOriginalFlow = false;
-
- FlowBuilder flowBuilder = new FlowBuilder();
-
- FlowStatisticsDataBuilder flowStatisticsData = new FlowStatisticsDataBuilder();
-
- FlowBuilder flow = new FlowBuilder();
- flow.setContainerName(map.getContainerName());
- flow.setBufferId(map.getBufferId());
- flow.setCookie(map.getCookie());
- flow.setCookieMask(map.getCookieMask());
- flow.setFlags(map.getFlags());
- flow.setFlowName(map.getFlowName());
- flow.setHardTimeout(map.getHardTimeout());
- if(map.getFlowId() != null)
- flow.setId(new FlowId(map.getFlowId().getValue()));
- flow.setIdleTimeout(map.getIdleTimeout());
- flow.setInstallHw(map.isInstallHw());
- flow.setInstructions(map.getInstructions());
- if(map.getFlowId()!= null)
- flow.setKey(new FlowKey(new FlowId(map.getKey().getFlowId().getValue())));
- flow.setMatch(map.getMatch());
- flow.setOutGroup(map.getOutGroup());
- flow.setOutPort(map.getOutPort());
- flow.setPriority(map.getPriority());
- flow.setStrict(map.isStrict());
- flow.setTableId(tableId);
-
- Flow flowRule = flow.build();
-
- FlowAndStatisticsMapListBuilder stats = new FlowAndStatisticsMapListBuilder();
- stats.setByteCount(map.getByteCount());
- stats.setPacketCount(map.getPacketCount());
- stats.setDuration(map.getDuration());
-
- GenericStatistics flowStats = stats.build();
-
- //Augment the data to the flow node
-
- FlowStatisticsBuilder flowStatistics = new FlowStatisticsBuilder();
- flowStatistics.setByteCount(flowStats.getByteCount());
- flowStatistics.setPacketCount(flowStats.getPacketCount());
- flowStatistics.setDuration(flowStats.getDuration());
- flowStatistics.setContainerName(map.getContainerName());
- flowStatistics.setBufferId(map.getBufferId());
- flowStatistics.setCookie(map.getCookie());
- flowStatistics.setCookieMask(map.getCookieMask());
- flowStatistics.setFlags(map.getFlags());
- flowStatistics.setFlowName(map.getFlowName());
- flowStatistics.setHardTimeout(map.getHardTimeout());
- flowStatistics.setIdleTimeout(map.getIdleTimeout());
- flowStatistics.setInstallHw(map.isInstallHw());
- flowStatistics.setInstructions(map.getInstructions());
- flowStatistics.setMatch(map.getMatch());
- flowStatistics.setOutGroup(map.getOutGroup());
- flowStatistics.setOutPort(map.getOutPort());
- flowStatistics.setPriority(map.getPriority());
- flowStatistics.setStrict(map.isStrict());
- flowStatistics.setTableId(tableId);
-
- flowStatisticsData.setFlowStatistics(flowStatistics.build());
-
- logger.debug("Flow : {}",flowRule.toString());
- logger.debug("Statistics to augment : {}",flowStatistics.build().toString());
-
- InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
- .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
+ public synchronized void cleanStaleStatistics() {
+ final DataModificationTransaction trans = dps.beginTransaction();
+ final long now = System.nanoTime();
- Table table= (Table)trans.readConfigurationData(tableRef);
-
- //TODO: Not a good way to do it, need to figure out better way.
- //TODO: major issue in any alternate approach is that flow key is incrementally assigned
- //to the flows stored in data store.
- // Augment same statistics to all the matching masked flow
- if(table != null){
-
- for(Flow existingFlow : table.getFlow()){
- logger.debug("Existing flow in data store : {}",existingFlow.toString());
- if(FlowComparator.flowEquals(flowRule,existingFlow)){
- InstanceIdentifier<Flow> flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
- .augmentation(FlowCapableNode.class)
- .child(Table.class, new TableKey(tableId))
- .child(Flow.class,existingFlow.getKey()).toInstance();
- flowBuilder.setKey(existingFlow.getKey());
- flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
- logger.debug("Found matching flow in the datastore, augmenting statistics");
- foundOriginalFlow = true;
- // Update entry with timestamp of latest response
- flow.setKey(existingFlow.getKey());
- FlowEntry flowStatsEntry = new FlowEntry(tableId,flow.build());
- flowStatsUpdate.put(flowStatsEntry, expiryTime);
-
- trans.putOperationalData(flowRef, flowBuilder.build());
- }
- }
- }
-
- table = (Table)trans.readOperationalData(tableRef);
- if(!foundOriginalFlow && table != null){
-
- for(Flow existingFlow : table.getFlow()){
- FlowStatisticsData augmentedflowStatisticsData = existingFlow.getAugmentation(FlowStatisticsData.class);
- if(augmentedflowStatisticsData != null){
- FlowBuilder existingOperationalFlow = new FlowBuilder();
- existingOperationalFlow.fieldsFrom(augmentedflowStatisticsData.getFlowStatistics());
- logger.debug("Existing unaccounted flow in operational data store : {}",existingFlow.toString());
- if(FlowComparator.flowEquals(flowRule,existingOperationalFlow.build())){
- InstanceIdentifier<Flow> flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
- .augmentation(FlowCapableNode.class)
- .child(Table.class, new TableKey(tableId))
- .child(Flow.class,existingFlow.getKey()).toInstance();
- flowBuilder.setKey(existingFlow.getKey());
- flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
- logger.debug("Found matching unaccounted flow in the operational datastore, augmenting statistics");
- foundOriginalFlow = true;
-
- // Update entry with timestamp of latest response
- flow.setKey(existingFlow.getKey());
- FlowEntry flowStatsEntry = new FlowEntry(tableId,flow.build());
- flowStatsUpdate.put(flowStatsEntry, expiryTime);
- trans.putOperationalData(flowRef, flowBuilder.build());
- break;
- }
- }
- }
- }
- if(!foundOriginalFlow){
- String flowKey = "#UF$TABLE*"+Short.toString(tableId)+"*"+Integer.toString(this.unaccountedFlowsCounter);
- this.unaccountedFlowsCounter++;
- FlowKey newFlowKey = new FlowKey(new FlowId(flowKey));
- InstanceIdentifier<Flow> flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
- .augmentation(FlowCapableNode.class)
- .child(Table.class, new TableKey(tableId))
- .child(Flow.class,newFlowKey).toInstance();
- flowBuilder.setKey(newFlowKey);
- flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
- logger.debug("Flow {} is not present in config data store, augmenting statistics as an unaccounted flow",
- flowBuilder.build());
-
- // Update entry with timestamp of latest response
- flow.setKey(newFlowKey);
- FlowEntry flowStatsEntry = new FlowEntry(tableId,flow.build());
- flowStatsUpdate.put(flowStatsEntry, expiryTime);
- trans.putOperationalData(flowRef, flowBuilder.build());
- }
- }
+ flowStats.cleanup(trans, now);
+ groupDescStats.cleanup(trans, now);
+ groupStats.cleanup(trans, now);
+ meterConfigStats.cleanup(trans, now);
+ meterStats.cleanup(trans, now);
+ nodeConnectorStats.cleanup(trans, now);
+ queueStats.cleanup(trans, now);
+ msgManager.cleanStaleTransactionIds();
trans.commit();
}
- private static Long getExpiryTime(){
- final long now = System.nanoTime();
- return now + TimeUnit.MILLISECONDS.toNanos(StatisticsProvider.STATS_THREAD_EXECUTION_TIME * NUMBER_OF_WAIT_CYCLES);
- }
+ public synchronized void requestPeriodicStatistics() {
+ logger.debug("Send requests for statistics collection to node : {}", targetNodeKey);
- public synchronized void cleanStaleStatistics(){
- final DataModificationTransaction trans = this.statisticsProvider.startChange();
- final long now = System.nanoTime();
+ flowTableStats.request();
- //Clean stale statistics related to group
- for (Iterator<Entry<GroupDescStats, Long>> it = this.groupDescStatsUpdate.entrySet().iterator();it.hasNext();){
- Entry<GroupDescStats, Long> e = it.next();
- if (now > e.getValue()) {
- cleanGroupStatsFromDataStore(trans, e.getKey());
- it.remove();
- }
+ // FIXME: it does not make sense to trigger this before sendAllFlowTablesStatisticsRequest()
+ // comes back -- we do not have any tables anyway.
+ final Collection<TableKey> tables = flowTableStats.getTables();
+ logger.debug("Node {} supports {} table(s)", targetNodeKey, tables.size());
+ for (final TableKey key : tables) {
+ logger.debug("Send aggregate stats request for flow table {} to node {}", key.getId(), targetNodeKey);
+ flowStats.requestAggregateFlows(key);
}
- //Clean stale statistics related to meter
- for (Iterator<Entry<MeterConfigStats, Long>> it = this.meterConfigStatsUpdate.entrySet().iterator();it.hasNext();){
- Entry<MeterConfigStats, Long> e = it.next();
- if (now > e.getValue()) {
- cleanMeterStatsFromDataStore(trans, e.getKey());
- it.remove();
- }
- }
+ flowStats.requestAllFlowsAllTables();
+ nodeConnectorStats.request();
+ groupStats.request();
+ groupDescStats.request();
+ meterStats.request();
+ meterConfigStats.request();
+ queueStats.request();
+ }
- //Clean stale statistics related to flow
- for (Iterator<Entry<FlowEntry, Long>> it = this.flowStatsUpdate.entrySet().iterator();it.hasNext();){
- Entry<FlowEntry, Long> e = it.next();
- if (now > e.getValue()) {
- cleanFlowStatsFromDataStore(trans, e.getKey());
- it.remove();
- }
- }
+ public synchronized void start(final Timer timer) {
+ flowStats.start(dps);
+ groupDescStats.start(dps);
+ groupStats.start(dps);
+ meterConfigStats.start(dps);
+ meterStats.start(dps);
+ queueStats.start(dps);
- //Clean stale statistics related to queue
- for (Iterator<Entry<QueueEntry, Long>> it = this.queuesStatsUpdate.entrySet().iterator();it.hasNext();){
- Entry<QueueEntry, Long> e = it.next();
- if (now > e.getValue()) {
- cleanQueueStatsFromDataStore(trans, e.getKey());
- it.remove();
- }
- }
+ timer.schedule(task, (long) (Math.random() * FIRST_COLLECTION_MILLIS), STATS_COLLECTION_MILLIS);
- trans.commit();
- }
+ logger.debug("Statistics handler for node started with base interval {}ms", STATS_COLLECTION_MILLIS);
- private void cleanQueueStatsFromDataStore(DataModificationTransaction trans, QueueEntry queueEntry) {
- InstanceIdentifier<?> queueRef
- = InstanceIdentifier.builder(Nodes.class)
- .child(Node.class, this.targetNodeKey)
- .child(NodeConnector.class, new NodeConnectorKey(queueEntry.getNodeConnectorId()))
- .augmentation(FlowCapableNodeConnector.class)
- .child(Queue.class, new QueueKey(queueEntry.getQueueId()))
- .augmentation(FlowCapableNodeConnectorQueueStatisticsData.class).toInstance();
- trans.removeOperationalData(queueRef);
+ requestPeriodicStatistics();
}
- private void cleanFlowStatsFromDataStore(DataModificationTransaction trans, FlowEntry flowEntry) {
- InstanceIdentifier<?> flowRef
- = InstanceIdentifier.builder(Nodes.class).child(Node.class, this.targetNodeKey)
- .augmentation(FlowCapableNode.class)
- .child(Table.class, new TableKey(flowEntry.getTableId()))
- .child(Flow.class,flowEntry.getFlow().getKey())
- .augmentation(FlowStatisticsData.class).toInstance();
- trans.removeOperationalData(flowRef);
+ @Override
+ public synchronized void close() {
+ task.cancel();
+ flowStats.close();
+ groupDescStats.close();
+ groupStats.close();
+ meterConfigStats.close();
+ meterStats.close();
+ queueStats.close();
+
+ logger.debug("Statistics handler for {} shut down", targetNodeKey.getId());
}
- private void cleanMeterStatsFromDataStore(DataModificationTransaction trans, MeterConfigStats meterConfigStats) {
- InstanceIdentifierBuilder<Meter> meterRef
- = InstanceIdentifier.builder(Nodes.class).child(Node.class,this.targetNodeKey)
- .augmentation(FlowCapableNode.class)
- .child(Meter.class,new MeterKey(meterConfigStats.getMeterId()));
-
- InstanceIdentifier<?> nodeMeterConfigStatsAugmentation = meterRef.augmentation(NodeMeterConfigStats.class).toInstance();
- trans.removeOperationalData(nodeMeterConfigStatsAugmentation);
-
- InstanceIdentifier<?> nodeMeterStatisticsAugmentation = meterRef.augmentation(NodeMeterStatistics.class).toInstance();
- trans.removeOperationalData(nodeMeterStatisticsAugmentation);
+ @Override
+ public void registerTransaction(TransactionId id) {
+ msgManager.recordExpectedTransaction(id);
+ logger.debug("Transaction {} for node {} sent successfully", id, targetNodeKey);
}
- private void cleanGroupStatsFromDataStore(DataModificationTransaction trans, GroupDescStats groupDescStats) {
- InstanceIdentifierBuilder<Group> groupRef
- = InstanceIdentifier.builder(Nodes.class).child(Node.class,this.targetNodeKey)
- .augmentation(FlowCapableNode.class)
- .child(Group.class,new GroupKey(groupDescStats.getGroupId()));
-
- InstanceIdentifier<?> nodeGroupDescStatsAugmentation = groupRef.augmentation(NodeGroupDescStats.class).toInstance();
- trans.removeOperationalData(nodeGroupDescStatsAugmentation);
-
- InstanceIdentifier<?> nodeGroupStatisticsAugmentation = groupRef.augmentation(NodeGroupStatistics.class).toInstance();
- trans.removeOperationalData(nodeGroupStatisticsAugmentation);
+ @Override
+ public void registerTableTransaction(final TransactionId id, final Short table) {
+ msgManager.recordExpectedTableTransaction(id, table);
+ logger.debug("Transaction {} for node {} table {} sent successfully", id, targetNodeKey, table);
}
}
--- /dev/null
+/*
+ * Copyright IBM Corporation, 2013. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.statistics.manager;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.queue.rev130925.QueueId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+
+final class QueueStatsEntry {
+ private final NodeConnectorId nodeConnectorId;
+ private final QueueId queueId;
+ public QueueStatsEntry(NodeConnectorId ncId, QueueId queueId){
+ this.nodeConnectorId = ncId;
+ this.queueId = queueId;
+ }
+ public NodeConnectorId getNodeConnectorId() {
+ return nodeConnectorId;
+ }
+ public QueueId getQueueId() {
+ return queueId;
+ }
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((nodeConnectorId == null) ? 0 : nodeConnectorId.hashCode());
+ result = prime * result + ((queueId == null) ? 0 : queueId.hashCode());
+ return result;
+ }
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof QueueStatsEntry)) {
+ return false;
+ }
+ QueueStatsEntry other = (QueueStatsEntry) obj;
+ if (nodeConnectorId == null) {
+ if (other.nodeConnectorId != null) {
+ return false;
+ }
+ } else if (!nodeConnectorId.equals(other.nodeConnectorId)) {
+ return false;
+ }
+ if (queueId == null) {
+ if (other.queueId != null) {
+ return false;
+ }
+ } else if (!queueId.equals(other.queueId)) {
+ return false;
+ }
+ return true;
+ }
+}
--- /dev/null
+/*
+ * Copyright IBM Corporation, 2013. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.statistics.manager;
+
+import java.util.Map.Entry;
+
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+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.inventory.rev130819.FlowCapableNodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.Queue;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.queue.rev130925.QueueId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+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.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsDataBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetAllQueuesStatisticsFromAllPortsInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetQueueStatisticsFromGivenPortInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.flow.capable.node.connector.queue.statistics.FlowCapableNodeConnectorQueueStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.queue.id.and.statistics.map.QueueIdAndStatisticsMap;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class QueueStatsTracker extends AbstractListeningStatsTracker<QueueIdAndStatisticsMap, QueueStatsEntry> {
+ private static final Logger logger = LoggerFactory.getLogger(QueueStatsTracker.class);
+ private final OpendaylightQueueStatisticsService queueStatsService;
+
+ QueueStatsTracker(OpendaylightQueueStatisticsService queueStatsService, final FlowCapableContext context, long lifetimeNanos) {
+ super(context, lifetimeNanos);
+ this.queueStatsService = queueStatsService;
+ }
+
+ @Override
+ protected void cleanupSingleStat(DataModificationTransaction trans, QueueStatsEntry item) {
+ InstanceIdentifier<?> queueRef
+ = getNodeIdentifierBuilder().child(NodeConnector.class, new NodeConnectorKey(item.getNodeConnectorId()))
+ .augmentation(FlowCapableNodeConnector.class)
+ .child(Queue.class, new QueueKey(item.getQueueId()))
+ .augmentation(FlowCapableNodeConnectorQueueStatisticsData.class).build();
+ trans.removeOperationalData(queueRef);
+ }
+
+ @Override
+ protected QueueStatsEntry updateSingleStat(DataModificationTransaction trans, QueueIdAndStatisticsMap item) {
+
+ QueueStatsEntry queueEntry = new QueueStatsEntry(item.getNodeConnectorId(), item.getQueueId());
+
+ FlowCapableNodeConnectorQueueStatisticsDataBuilder queueStatisticsDataBuilder = new FlowCapableNodeConnectorQueueStatisticsDataBuilder();
+
+ FlowCapableNodeConnectorQueueStatisticsBuilder queueStatisticsBuilder = new FlowCapableNodeConnectorQueueStatisticsBuilder();
+
+ queueStatisticsBuilder.fieldsFrom(item);
+
+ queueStatisticsDataBuilder.setFlowCapableNodeConnectorQueueStatistics(queueStatisticsBuilder.build());
+
+ InstanceIdentifier<Queue> queueRef = getNodeIdentifierBuilder().child(NodeConnector.class, new NodeConnectorKey(item.getNodeConnectorId()))
+ .augmentation(FlowCapableNodeConnector.class)
+ .child(Queue.class, new QueueKey(item.getQueueId())).toInstance();
+
+ QueueBuilder queueBuilder = new QueueBuilder();
+ FlowCapableNodeConnectorQueueStatisticsData qsd = queueStatisticsDataBuilder.build();
+ queueBuilder.addAugmentation(FlowCapableNodeConnectorQueueStatisticsData.class, qsd);
+ queueBuilder.setKey(new QueueKey(item.getQueueId()));
+
+ logger.debug("Augmenting queue statistics {} of queue {} to port {}",
+ qsd,
+ item.getQueueId(),
+ item.getNodeConnectorId());
+
+ trans.putOperationalData(queueRef, queueBuilder.build());
+ return queueEntry;
+ }
+
+ public void request() {
+ if (queueStatsService != null) {
+ GetAllQueuesStatisticsFromAllPortsInputBuilder input = new GetAllQueuesStatisticsFromAllPortsInputBuilder();
+ input.setNode(getNodeRef());
+
+ requestHelper(queueStatsService.getAllQueuesStatisticsFromAllPorts(input.build()));
+ }
+ }
+
+ public void request(NodeConnectorId nodeConnectorId, QueueId queueId) {
+ if (queueStatsService != null) {
+ GetQueueStatisticsFromGivenPortInputBuilder input = new GetQueueStatisticsFromGivenPortInputBuilder();
+
+ input.setNode(getNodeRef());
+ input.setNodeConnectorId(nodeConnectorId);
+ input.setQueueId(queueId);
+
+ requestHelper(queueStatsService.getQueueStatisticsFromGivenPort(input.build()));
+ }
+ }
+
+ @Override
+ public void onDataChanged(DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
+ for (Entry<InstanceIdentifier<?>, DataObject> e : change.getCreatedConfigurationData().entrySet()) {
+ if (Queue.class.equals(e.getKey().getTargetType())) {
+ final Queue queue = (Queue) e.getValue();
+ final NodeConnectorKey key = e.getKey().firstKeyOf(NodeConnector.class, NodeConnectorKey.class);
+ logger.debug("Key {} triggered request for connector {} queue {}", key.getId(), queue.getQueueId());
+ request(key.getId(), queue.getQueueId());
+ } else {
+ logger.debug("Ignoring key {}", e.getKey());
+ }
+ }
+
+ final DataModificationTransaction trans = startTransaction();
+ for (InstanceIdentifier<?> key : change.getRemovedConfigurationData()) {
+ if (Queue.class.equals(key.getTargetType())) {
+ @SuppressWarnings("unchecked")
+ final InstanceIdentifier<Queue> queue = (InstanceIdentifier<Queue>)key;
+ final InstanceIdentifier<?> del = InstanceIdentifier.builder(queue)
+ .augmentation(FlowCapableNodeConnectorQueueStatisticsData.class).build();
+ logger.debug("Key {} triggered remove of augmentation {}", key, del);
+
+ trans.removeOperationalData(del);
+ }
+ }
+ trans.commit();
+ }
+
+ @Override
+ protected InstanceIdentifier<?> listenPath() {
+ return getNodeIdentifierBuilder().child(NodeConnector.class)
+ .augmentation(FlowCapableNodeConnector.class).child(Queue.class).build();
+ }
+
+ @Override
+ protected String statName() {
+ return "Queue";
+ }
+
+ @Override
+ public void start(final DataBrokerService dbs) {
+ if (queueStatsService == null) {
+ logger.debug("No Queue Statistics service, not subscribing to queues on node {}", getNodeIdentifier());
+ return;
+ }
+
+ super.start(dbs);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.statistics.manager;
+
+import java.util.Collection;
+
+import org.opendaylight.yangtools.yang.common.RpcError;
+
+final class RPCFailedException extends RuntimeException {
+ private static final long serialVersionUID = 1L;
+ private final Collection<RpcError> errors;
+
+ public RPCFailedException(final String message, final Collection<RpcError> errors) {
+ super(message);
+ this.errors = errors;
+ }
+
+ @Override
+ public String toString() {
+ return "RPCFailedException [errors=" + errors + ", message=" + getMessage() + ']';
+ }
+}
private final static Logger sucLogger = LoggerFactory.getLogger(StatisticsListener.class);
private final StatisticsProvider statisticsManager;
- private final MultipartMessageManager messageManager;
/**
* default ctor
*/
public StatisticsListener(final StatisticsProvider manager){
this.statisticsManager = manager;
- this.messageManager = this.statisticsManager.getMultipartMessageManager();
}
@Override
public void onMeterConfigStatsUpdated(final MeterConfigStatsUpdated notification) {
- //Check if response is for the request statistics-manager sent.
- if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies()))
- return;
-
- //Add statistics to local cache
final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId());
if (handler != null) {
- handler.updateMeterConfigStats(notification.getMeterConfigStats());
+ handler.updateMeterConfigStats(notification, notification.isMoreReplies(), notification.getMeterConfigStats());
}
}
@Override
public void onMeterStatisticsUpdated(MeterStatisticsUpdated notification) {
- //Check if response is for the request statistics-manager sent.
- if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies()))
- return;
-
- //Add statistics to local cache
final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId());
if (handler != null) {
- handler.updateMeterStats(notification.getMeterStats());
+ handler.updateMeterStats(notification, notification.isMoreReplies(), notification.getMeterStats());
}
}
@Override
public void onGroupDescStatsUpdated(GroupDescStatsUpdated notification) {
- //Check if response is for the request statistics-manager sent.
- if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies()))
- return;
-
final NodeStatisticsHandler handler = statisticsManager.getStatisticsHandler(notification.getId());
if (handler != null) {
- handler.updateGroupDescStats(notification.getGroupDescStats());
+ handler.updateGroupDescStats(notification, notification.isMoreReplies(), notification.getGroupDescStats());
}
}
@Override
public void onGroupStatisticsUpdated(GroupStatisticsUpdated notification) {
- //Check if response is for the request statistics-manager sent.
- if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies()))
- return;
-
final NodeStatisticsHandler handler = statisticsManager.getStatisticsHandler(notification.getId());
if (handler != null) {
- handler.updateGroupStats(notification.getGroupStats());
+ handler.updateGroupStats(notification, notification.isMoreReplies(), notification.getGroupStats());
}
}
@Override
public void onFlowsStatisticsUpdate(final FlowsStatisticsUpdate notification) {
- //Check if response is for the request statistics-manager sent.
- if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies()))
- return;
-
sucLogger.debug("Received flow stats update : {}",notification.toString());
final NodeStatisticsHandler sna = this.statisticsManager.getStatisticsHandler(notification.getId());
if (sna != null) {
- sna.updateFlowStats(notification.getFlowAndStatisticsMapList());
+ sna.updateFlowStats(notification, notification.isMoreReplies(), notification.getFlowAndStatisticsMapList());
}
}
@Override
public void onAggregateFlowStatisticsUpdate(AggregateFlowStatisticsUpdate notification) {
- //Check if response is for the request statistics-manager sent.
- if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies()))
- return;
-
final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId());
if (handler != null) {
- final Short tableId = messageManager.getTableIdForTxId(notification.getId(),notification.getTransactionId());
- handler.updateAggregateFlowStats(tableId, notification);
+ handler.updateAggregateFlowStats(notification, notification.isMoreReplies(), notification);
}
}
@Override
public void onNodeConnectorStatisticsUpdate(NodeConnectorStatisticsUpdate notification) {
- //Check if response is for the request statistics-manager sent.
- if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies()))
- return;
-
final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId());
if (handler != null) {
- handler.updateNodeConnectorStats(notification.getNodeConnectorStatisticsAndPortNumberMap());
+ handler.updateNodeConnectorStats(notification, notification.isMoreReplies(), notification.getNodeConnectorStatisticsAndPortNumberMap());
}
}
@Override
public void onFlowTableStatisticsUpdate(FlowTableStatisticsUpdate notification) {
- //Check if response is for the request statistics-manager sent.
- if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies()))
- return;
-
final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId());
if (handler != null) {
- handler.updateFlowTableStats(notification.getFlowTableAndStatisticsMap());
+ handler.updateFlowTableStats(notification, notification.isMoreReplies(), notification.getFlowTableAndStatisticsMap());
}
}
@Override
public void onQueueStatisticsUpdate(QueueStatisticsUpdate notification) {
- //Check if response is for the request statistics-manager sent.
- if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies()))
- return;
-
- //Add statistics to local cache
final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId());
if (handler != null) {
- handler.updateQueueStats(notification.getQueueIdAndStatisticsMap());
+ handler.updateQueueStats(notification, notification.isMoreReplies(), notification.getQueueIdAndStatisticsMap());
}
}
}
-
import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareProvider;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
-import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
import org.osgi.framework.BundleContext;
@Override
public void onSessionInitiated(ProviderContext session) {
- final DataBrokerService dbs = session.getSALService(DataBrokerService.class);
final DataProviderService dps = session.getSALService(DataProviderService.class);
final NotificationProviderService nps = session.getSALService(NotificationProviderService.class);
statsProvider = new StatisticsProvider(dps);
- statsProvider.start(dbs, nps, session);
+ statsProvider.start(nps, session);
}
@Override
*/
package org.opendaylight.controller.md.statistics.manager;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.Collection;
+import java.util.Timer;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-import org.eclipse.xtext.xbase.lib.Exceptions;
-import org.opendaylight.controller.md.statistics.manager.MultipartMessageManager.StatsRequestType;
import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry;
-import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
-import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForAllFlowsOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsFromFlowTableInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsFromFlowTableOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.GetFlowTablesStatisticsInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.GetFlowTablesStatisticsOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.Queue;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.queue.rev130925.QueueId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetAllGroupStatisticsInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetAllGroupStatisticsOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetGroupDescriptionInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetGroupDescriptionOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
-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.NodeRef;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterConfigStatisticsInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterConfigStatisticsOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterStatisticsInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterStatisticsOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetAllNodeConnectorsStatisticsInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetAllNodeConnectorsStatisticsOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetAllQueuesStatisticsFromAllPortsInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetAllQueuesStatisticsFromAllPortsOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetQueueStatisticsFromGivenPortInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetQueueStatisticsFromGivenPortOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsService;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.concepts.Registration;
-import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.NotificationListener;
-import org.opendaylight.yangtools.yang.common.RpcResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
*
*/
public class StatisticsProvider implements AutoCloseable {
- public static final int STATS_THREAD_EXECUTION_TIME= 15000;
-
private static final Logger spLogger = LoggerFactory.getLogger(StatisticsProvider.class);
- private final MultipartMessageManager multipartMessageManager = new MultipartMessageManager();
- private final InstanceIdentifier<Nodes> nodesIdentifier = InstanceIdentifier.builder(Nodes.class).toInstance();
+ private final ConcurrentMap<NodeId, NodeStatisticsHandler> handlers = new ConcurrentHashMap<>();
+ private final Timer timer = new Timer("statistics-manager", true);
private final DataProviderService dps;
- //Local caching of stats
- private final ConcurrentMap<NodeId,NodeStatisticsHandler> statisticsCache = new ConcurrentHashMap<>();
-
private OpendaylightGroupStatisticsService groupStatsService;
private OpendaylightMeterStatisticsService meterStatsService;
private OpendaylightQueueStatisticsService queueStatsService;
- private StatisticsUpdateHandler statsUpdateHandler;
-
- private Thread statisticsRequesterThread;
-
- private Thread statisticsAgerThread;
-
-
public StatisticsProvider(final DataProviderService dataService) {
this.dps = Preconditions.checkNotNull(dataService);
}
- public MultipartMessageManager getMultipartMessageManager() {
- return multipartMessageManager;
- }
-
private final StatisticsListener updateCommiter = new StatisticsListener(StatisticsProvider.this);
private Registration<NotificationListener> listenerRegistration;
- public void start(final DataBrokerService dbs, final NotificationProviderService nps, final RpcConsumerRegistry rpcRegistry) {
-
- this.listenerRegistration = nps.registerNotificationListener(this.updateCommiter);
+ private ListenerRegistration<DataChangeListener> flowCapableTrackerRegistration;
- statsUpdateHandler = new StatisticsUpdateHandler(StatisticsProvider.this);
- registerDataStoreUpdateListener(dbs);
+ public void start(final NotificationProviderService nps, final RpcConsumerRegistry rpcRegistry) {
- // Get Group/Meter statistics service instance
+ // Get Group/Meter statistics service instances
groupStatsService = rpcRegistry.getRpcService(OpendaylightGroupStatisticsService.class);
meterStatsService = rpcRegistry.getRpcService(OpendaylightMeterStatisticsService.class);
flowStatsService = rpcRegistry.getRpcService(OpendaylightFlowStatisticsService.class);
flowTableStatsService = rpcRegistry.getRpcService(OpendaylightFlowTableStatisticsService.class);
queueStatsService = rpcRegistry.getRpcService(OpendaylightQueueStatisticsService.class);
- statisticsRequesterThread = new Thread( new Runnable(){
-
- @Override
- public void run() {
- while(true){
- try {
- statsRequestSender();
-
- Thread.sleep(STATS_THREAD_EXECUTION_TIME);
- }catch (Exception e){
- spLogger.error("Exception occurred while sending stats request : {}",e);
- }
- }
- }
- });
-
- spLogger.debug("Statistics requester thread started with timer interval : {}",STATS_THREAD_EXECUTION_TIME);
-
- statisticsRequesterThread.start();
-
- statisticsAgerThread = new Thread( new Runnable(){
-
- @Override
- public void run() {
- while(true){
- try {
- for(NodeStatisticsHandler nodeStatisticsAger : statisticsCache.values()){
- nodeStatisticsAger.cleanStaleStatistics();
- }
- multipartMessageManager.cleanStaleTransactionIds();
-
- Thread.sleep(STATS_THREAD_EXECUTION_TIME);
- }catch (Exception e){
- spLogger.error("Exception occurred while sending stats request : {}",e);
- }
- }
- }
- });
-
- spLogger.debug("Statistics ager thread started with timer interval : {}",STATS_THREAD_EXECUTION_TIME);
+ // Start receiving notifications
+ this.listenerRegistration = nps.registerNotificationListener(this.updateCommiter);
- statisticsAgerThread.start();
+ // Register for switch connect/disconnect notifications
+ final InstanceIdentifier<FlowCapableNode> fcnId = InstanceIdentifier.builder(Nodes.class)
+ .child(Node.class).augmentation(FlowCapableNode.class).build();
+ spLogger.debug("Registering FlowCapable tracker to {}", fcnId);
+ this.flowCapableTrackerRegistration = dps.registerDataChangeListener(fcnId,
+ new FlowCapableTracker(this, fcnId));
spLogger.info("Statistics Provider started.");
}
- private void registerDataStoreUpdateListener(DataBrokerService dbs) {
- //Register for Node updates
- InstanceIdentifier<? extends DataObject> pathNode = InstanceIdentifier.builder(Nodes.class)
- .child(Node.class).toInstance();
- dbs.registerDataChangeListener(pathNode, statsUpdateHandler);
-
- //Register for flow updates
- InstanceIdentifier<? extends DataObject> pathFlow = InstanceIdentifier.builder(Nodes.class).child(Node.class)
- .augmentation(FlowCapableNode.class)
- .child(Table.class)
- .child(Flow.class).toInstance();
- dbs.registerDataChangeListener(pathFlow, statsUpdateHandler);
-
- //Register for meter updates
- InstanceIdentifier<? extends DataObject> pathMeter = InstanceIdentifier.builder(Nodes.class).child(Node.class)
- .augmentation(FlowCapableNode.class)
- .child(Meter.class).toInstance();
-
- dbs.registerDataChangeListener(pathMeter, statsUpdateHandler);
-
- //Register for group updates
- InstanceIdentifier<? extends DataObject> pathGroup = InstanceIdentifier.builder(Nodes.class).child(Node.class)
- .augmentation(FlowCapableNode.class)
- .child(Group.class).toInstance();
- dbs.registerDataChangeListener(pathGroup, statsUpdateHandler);
-
- //Register for queue updates
- InstanceIdentifier<? extends DataObject> pathQueue = InstanceIdentifier.builder(Nodes.class).child(Node.class)
- .child(NodeConnector.class)
- .augmentation(FlowCapableNodeConnector.class)
- .child(Queue.class).toInstance();
- dbs.registerDataChangeListener(pathQueue, statsUpdateHandler);
- }
-
- protected DataModificationTransaction startChange() {
- return dps.beginTransaction();
- }
-
- private void statsRequestSender(){
-
- List<Node> targetNodes = getAllConnectedNodes();
-
- if(targetNodes == null)
- return;
-
-
- for (Node targetNode : targetNodes){
-
- if(targetNode.getAugmentation(FlowCapableNode.class) != null){
- sendStatisticsRequestsToNode(targetNode);
- }
- }
- }
-
- public void sendStatisticsRequestsToNode(Node targetNode){
-
- spLogger.debug("Send requests for statistics collection to node : {})",targetNode.getId());
-
- InstanceIdentifier<Node> targetInstanceId = InstanceIdentifier.builder(Nodes.class).child(Node.class,targetNode.getKey()).toInstance();
-
- NodeRef targetNodeRef = new NodeRef(targetInstanceId);
-
- try{
- if(flowStatsService != null){
- sendAggregateFlowsStatsFromAllTablesRequest(targetNode.getKey());
- sendAllFlowsStatsFromAllTablesRequest(targetNodeRef);
- }
- if(flowTableStatsService != null){
- sendAllFlowTablesStatisticsRequest(targetNodeRef);
- }
- if(portStatsService != null){
- sendAllNodeConnectorsStatisticsRequest(targetNodeRef);
- }
- if(groupStatsService != null){
- sendAllGroupStatisticsRequest(targetNodeRef);
- sendGroupDescriptionRequest(targetNodeRef);
- }
- if(meterStatsService != null){
- sendAllMeterStatisticsRequest(targetNodeRef);
- sendMeterConfigStatisticsRequest(targetNodeRef);
- }
- if(queueStatsService != null){
- sendAllQueueStatsFromAllNodeConnector (targetNodeRef);
- }
- }catch(Exception e){
- spLogger.error("Exception occured while sending statistics requests : {}", e);
- }
- }
-
-
- public void sendAllFlowTablesStatisticsRequest(NodeRef targetNodeRef) throws InterruptedException, ExecutionException {
- final GetFlowTablesStatisticsInputBuilder input =
- new GetFlowTablesStatisticsInputBuilder();
-
- input.setNode(targetNodeRef);
-
- Future<RpcResult<GetFlowTablesStatisticsOutput>> response =
- flowTableStatsService.getFlowTablesStatistics(input.build());
-
- this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNodeRef),response.get().getResult().getTransactionId()
- , StatsRequestType.ALL_FLOW_TABLE);
-
- }
-
- public void sendAllFlowsStatsFromAllTablesRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{
- final GetAllFlowsStatisticsFromAllFlowTablesInputBuilder input =
- new GetAllFlowsStatisticsFromAllFlowTablesInputBuilder();
-
- input.setNode(targetNode);
-
- Future<RpcResult<GetAllFlowsStatisticsFromAllFlowTablesOutput>> response =
- flowStatsService.getAllFlowsStatisticsFromAllFlowTables(input.build());
-
- this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNode), response.get().getResult().getTransactionId()
- , StatsRequestType.ALL_FLOW);
-
- }
-
- public void sendFlowStatsFromTableRequest(NodeRef targetNode,Flow flow) throws InterruptedException, ExecutionException{
- final GetFlowStatisticsFromFlowTableInputBuilder input =
- new GetFlowStatisticsFromFlowTableInputBuilder();
-
- input.setNode(targetNode);
- input.fieldsFrom(flow);
-
- Future<RpcResult<GetFlowStatisticsFromFlowTableOutput>> response =
- flowStatsService.getFlowStatisticsFromFlowTable(input.build());
-
- this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNode), response.get().getResult().getTransactionId()
- , StatsRequestType.ALL_FLOW);
-
- }
-
- public void sendAggregateFlowsStatsFromAllTablesRequest(NodeKey targetNodeKey) throws InterruptedException, ExecutionException{
-
- List<Short> tablesId = getTablesFromNode(targetNodeKey);
-
- if(tablesId.size() != 0){
- for(Short id : tablesId){
-
- sendAggregateFlowsStatsFromTableRequest(targetNodeKey,id);
- }
- }else{
- spLogger.debug("No details found in data store for flow tables associated with Node {}",targetNodeKey);
- }
- }
-
- public void sendAggregateFlowsStatsFromTableRequest(NodeKey targetNodeKey,Short tableId) throws InterruptedException, ExecutionException{
-
- spLogger.debug("Send aggregate stats request for flow table {} to node {}",tableId,targetNodeKey);
- GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder input =
- new GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder();
-
- input.setNode(new NodeRef(InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey).toInstance()));
- input.setTableId(new org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TableId(tableId));
- Future<RpcResult<GetAggregateFlowStatisticsFromFlowTableForAllFlowsOutput>> response =
- flowStatsService.getAggregateFlowStatisticsFromFlowTableForAllFlows(input.build());
-
- multipartMessageManager.setTxIdAndTableIdMapEntry(targetNodeKey.getId(), response.get().getResult().getTransactionId(), tableId);
- this.multipartMessageManager.addTxIdToRequestTypeEntry(targetNodeKey.getId(), response.get().getResult().getTransactionId()
- , StatsRequestType.AGGR_FLOW);
- }
-
- public void sendAllNodeConnectorsStatisticsRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{
-
- final GetAllNodeConnectorsStatisticsInputBuilder input = new GetAllNodeConnectorsStatisticsInputBuilder();
-
- input.setNode(targetNode);
-
- Future<RpcResult<GetAllNodeConnectorsStatisticsOutput>> response =
- portStatsService.getAllNodeConnectorsStatistics(input.build());
- this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNode), response.get().getResult().getTransactionId()
- , StatsRequestType.ALL_PORT);
-
- }
-
- public void sendAllGroupStatisticsRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{
-
- final GetAllGroupStatisticsInputBuilder input = new GetAllGroupStatisticsInputBuilder();
-
- input.setNode(targetNode);
-
- Future<RpcResult<GetAllGroupStatisticsOutput>> response =
- groupStatsService.getAllGroupStatistics(input.build());
-
- this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNode), response.get().getResult().getTransactionId()
- , StatsRequestType.ALL_GROUP);
-
- }
-
- public void sendGroupDescriptionRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{
- final GetGroupDescriptionInputBuilder input = new GetGroupDescriptionInputBuilder();
-
- input.setNode(targetNode);
-
- Future<RpcResult<GetGroupDescriptionOutput>> response =
- groupStatsService.getGroupDescription(input.build());
-
- this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNode), response.get().getResult().getTransactionId()
- , StatsRequestType.GROUP_DESC);
-
- }
-
- public void sendAllMeterStatisticsRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{
-
- GetAllMeterStatisticsInputBuilder input = new GetAllMeterStatisticsInputBuilder();
-
- input.setNode(targetNode);
-
- Future<RpcResult<GetAllMeterStatisticsOutput>> response =
- meterStatsService.getAllMeterStatistics(input.build());
-
- this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNode), response.get().getResult().getTransactionId()
- , StatsRequestType.ALL_METER);;
-
- }
-
- public void sendMeterConfigStatisticsRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{
-
- GetAllMeterConfigStatisticsInputBuilder input = new GetAllMeterConfigStatisticsInputBuilder();
-
- input.setNode(targetNode);
-
- Future<RpcResult<GetAllMeterConfigStatisticsOutput>> response =
- meterStatsService.getAllMeterConfigStatistics(input.build());
-
- this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNode), response.get().getResult().getTransactionId()
- , StatsRequestType.METER_CONFIG);;
-
- }
-
- public void sendAllQueueStatsFromAllNodeConnector(NodeRef targetNode) throws InterruptedException, ExecutionException {
- GetAllQueuesStatisticsFromAllPortsInputBuilder input = new GetAllQueuesStatisticsFromAllPortsInputBuilder();
-
- input.setNode(targetNode);
-
- Future<RpcResult<GetAllQueuesStatisticsFromAllPortsOutput>> response =
- queueStatsService.getAllQueuesStatisticsFromAllPorts(input.build());
-
- this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNode), response.get().getResult().getTransactionId()
- , StatsRequestType.ALL_QUEUE_STATS);;
-
- }
-
- public void sendQueueStatsFromGivenNodeConnector(NodeRef targetNode,NodeConnectorId nodeConnectorId, QueueId queueId) throws InterruptedException, ExecutionException {
- GetQueueStatisticsFromGivenPortInputBuilder input = new GetQueueStatisticsFromGivenPortInputBuilder();
-
- input.setNode(targetNode);
- input.setNodeConnectorId(nodeConnectorId);
- input.setQueueId(queueId);
- Future<RpcResult<GetQueueStatisticsFromGivenPortOutput>> response =
- queueStatsService.getQueueStatisticsFromGivenPort(input.build());
-
- this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNode), response.get().getResult().getTransactionId()
- , StatsRequestType.ALL_QUEUE_STATS);;
-
- }
-
/**
* Get the handler for a particular node.
*
*/
public final NodeStatisticsHandler getStatisticsHandler(final NodeId nodeId) {
Preconditions.checkNotNull(nodeId);
- NodeStatisticsHandler ager = statisticsCache.get(nodeId);
- if (ager == null) {
- ager = new NodeStatisticsHandler(this, new NodeKey(nodeId));
- statisticsCache.put(nodeId, ager);
- }
-
- return ager;
- }
-
- private List<Node> getAllConnectedNodes(){
- Nodes nodes = (Nodes) dps.readOperationalData(nodesIdentifier);
- if(nodes == null)
- return null;
-
- spLogger.debug("Number of connected nodes : {}",nodes.getNode().size());
- return nodes.getNode();
- }
-
- private List<Short> getTablesFromNode(NodeKey nodeKey){
- InstanceIdentifier<FlowCapableNode> nodesIdentifier = InstanceIdentifier.builder(Nodes.class).child(Node.class,nodeKey).augmentation(FlowCapableNode.class).toInstance();
-
- FlowCapableNode node = (FlowCapableNode)dps.readOperationalData(nodesIdentifier);
- List<Short> tablesId = new ArrayList<Short>();
- if(node != null && node.getTable()!=null){
- spLogger.debug("Number of tables {} supported by node {}",node.getTable().size(),nodeKey);
- for(Table table: node.getTable()){
- tablesId.add(table.getId());
- }
+ NodeStatisticsHandler handler = handlers.get(nodeId);
+ if (handler == null) {
+ spLogger.info("Attempted to get non-existing handler for {}", nodeId);
}
- return tablesId;
- }
-
- @SuppressWarnings("unchecked")
- private NodeId getNodeId(NodeRef nodeRef){
- InstanceIdentifier<Node> nodeII = (InstanceIdentifier<Node>) nodeRef.getValue();
- NodeKey nodeKey = InstanceIdentifier.keyOf(nodeII);
- return nodeKey.getId();
+ return handler;
}
- @SuppressWarnings("deprecation")
@Override
- public void close(){
-
+ public void close() {
try {
- spLogger.info("Statistics Provider stopped.");
if (this.listenerRegistration != null) {
-
this.listenerRegistration.close();
+ this.listenerRegistration = null;
+ }
+ if (this.flowCapableTrackerRegistration != null) {
+ this.flowCapableTrackerRegistration.close();
+ this.flowCapableTrackerRegistration = null;
+ }
+ timer.cancel();
+ } catch (Exception e) {
+ spLogger.warn("Failed to stop Statistics Provider completely", e);
+ } finally {
+ spLogger.info("Statistics Provider stopped.");
+ }
+ }
- this.statisticsRequesterThread.destroy();
-
- this.statisticsAgerThread.destroy();
+ void startNodeHandlers(final Collection<NodeKey> addedNodes) {
+ for (NodeKey key : addedNodes) {
+ if (handlers.containsKey(key.getId())) {
+ spLogger.warn("Attempted to start already-existing handler for {}, very strange", key.getId());
+ continue;
+ }
+ final NodeStatisticsHandler h = new NodeStatisticsHandler(dps, key,
+ flowStatsService, flowTableStatsService, groupStatsService,
+ meterStatsService, portStatsService, queueStatsService);
+ final NodeStatisticsHandler old = handlers.putIfAbsent(key.getId(), h);
+ if (old == null) {
+ spLogger.debug("Started node handler for {}", key.getId());
+ h.start(timer);
+ } else {
+ spLogger.debug("Prevented race on handler for {}", key.getId());
}
- } catch (Throwable e) {
- throw Exceptions.sneakyThrow(e);
- }
+ }
}
+ void stopNodeHandlers(final Collection<NodeKey> removedNodes) {
+ for (NodeKey key : removedNodes) {
+ final NodeStatisticsHandler s = handlers.remove(key.getId());
+ if (s != null) {
+ spLogger.debug("Stopping node handler for {}", key.getId());
+ s.close();
+ } else {
+ spLogger.warn("Attempted to remove non-existing handler for {}, very strange", key.getId());
+ }
+ }
+ }
}
+++ /dev/null
-/*
- * Copyright IBM Corporation, 2013. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.md.statistics.manager;
-
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ExecutionException;
-
-import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
-import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
-import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsData;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.Queue;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStats;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatistics;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStats;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatistics;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsData;
-import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Following are two main responsibilities of the class
- * 1) Listen for the create changes in config data store for tree nodes (Flow,Group,Meter,Queue)
- * and send statistics request to the switch to fetch the statistics
- *
- * 2)Listen for the remove changes in config data store for tree nodes (Flow,Group,Meter,Queue)
- * and remove the relative statistics data from operational data store.
- *
- * @author avishnoi@in.ibm.com
- *
- */
-public class StatisticsUpdateHandler implements DataChangeListener {
-
- private static final Logger suhLogger = LoggerFactory.getLogger(StatisticsUpdateHandler.class);
- private final StatisticsProvider statisticsManager;
-
- public StatisticsUpdateHandler(final StatisticsProvider manager){
- this.statisticsManager = manager;
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public void onDataChanged(DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
-
- Map<InstanceIdentifier<?>, DataObject> nodeAdditions = change.getCreatedOperationalData();
- for (InstanceIdentifier<? extends DataObject> dataObjectInstance : nodeAdditions.keySet()) {
- DataObject dataObject = nodeAdditions.get(dataObjectInstance);
- if(dataObject instanceof Node){
-
- Node node = (Node) dataObject;
- if(node.getAugmentation(FlowCapableNode.class) != null){
- this.statisticsManager.sendStatisticsRequestsToNode(node);
- }
- }
- }
-
- Map<InstanceIdentifier<?>, DataObject> additions = change.getCreatedConfigurationData();
- for (InstanceIdentifier<? extends DataObject> dataObjectInstance : additions.keySet()) {
- DataObject dataObject = additions.get(dataObjectInstance);
- InstanceIdentifier<Node> nodeII = dataObjectInstance.firstIdentifierOf(Node.class);
- NodeRef nodeRef = new NodeRef(nodeII);
- if(dataObject instanceof Flow){
- Flow flow = (Flow) dataObject;
- try {
- this.statisticsManager.sendFlowStatsFromTableRequest(nodeRef, flow);
- } catch (InterruptedException | ExecutionException e) {
- suhLogger.warn("Following exception occured while sending flow statistics request newly added flow: {}", e);
- }
- }
- if(dataObject instanceof Meter){
- try {
- this.statisticsManager.sendMeterConfigStatisticsRequest(nodeRef);
- } catch (InterruptedException | ExecutionException e) {
- suhLogger.warn("Following exception occured while sending meter statistics request for newly added meter: {}", e);
- }
- }
- if(dataObject instanceof Group){
- try {
- this.statisticsManager.sendGroupDescriptionRequest(nodeRef);
- } catch (InterruptedException | ExecutionException e) {
- suhLogger.warn("Following exception occured while sending group description request for newly added group: {}", e);
- }
- }
- if(dataObject instanceof Queue){
- Queue queue = (Queue) dataObject;
- InstanceIdentifier<NodeConnector> nodeConnectorII = dataObjectInstance.firstIdentifierOf(NodeConnector.class);
- NodeConnectorKey nodeConnectorKey = InstanceIdentifier.keyOf(nodeConnectorII);
- try {
- this.statisticsManager.sendQueueStatsFromGivenNodeConnector(nodeRef, nodeConnectorKey.getId(), queue.getQueueId());
- } catch (InterruptedException | ExecutionException e) {
- suhLogger.warn("Following exception occured while sending queue statistics request for newly added group: {}", e);
- }
- }
- }
-
- DataModificationTransaction it = this.statisticsManager.startChange();
- Set<InstanceIdentifier<? extends DataObject>> removals = change.getRemovedConfigurationData();
- for (InstanceIdentifier<? extends DataObject> dataObjectInstance : removals) {
- DataObject dataObject = change.getOriginalConfigurationData().get(dataObjectInstance);
-
- if(dataObject instanceof Flow){
- InstanceIdentifier<Flow> flowII = (InstanceIdentifier<Flow>)dataObjectInstance;
- InstanceIdentifier<?> flowAugmentation =
- InstanceIdentifier.builder(flowII).augmentation(FlowStatisticsData.class).toInstance();
- it.removeOperationalData(flowAugmentation);
- }
- if(dataObject instanceof Meter){
- InstanceIdentifier<Meter> meterII = (InstanceIdentifier<Meter>)dataObjectInstance;
-
- InstanceIdentifier<?> nodeMeterConfigStatsAugmentation =
- InstanceIdentifier.builder(meterII).augmentation(NodeMeterConfigStats.class).toInstance();
- it.removeOperationalData(nodeMeterConfigStatsAugmentation);
-
- InstanceIdentifier<?> nodeMeterStatisticsAugmentation =
- InstanceIdentifier.builder(meterII).augmentation(NodeMeterStatistics.class).toInstance();
- it.removeOperationalData(nodeMeterStatisticsAugmentation);
- }
-
- if(dataObject instanceof Group){
- InstanceIdentifier<Group> groupII = (InstanceIdentifier<Group>)dataObjectInstance;
-
- InstanceIdentifier<?> nodeGroupDescStatsAugmentation =
- InstanceIdentifier.builder(groupII).augmentation(NodeGroupDescStats.class).toInstance();
- it.removeOperationalData(nodeGroupDescStatsAugmentation);
-
- InstanceIdentifier<?> nodeGroupStatisticsAugmentation =
- InstanceIdentifier.builder(groupII).augmentation(NodeGroupStatistics.class).toInstance();
- it.removeOperationalData(nodeGroupStatisticsAugmentation);
- }
-
- if(dataObject instanceof Queue){
- InstanceIdentifier<Queue> queueII = (InstanceIdentifier<Queue>)dataObjectInstance;
-
- InstanceIdentifier<?> nodeConnectorQueueStatisticsDataAugmentation =
- InstanceIdentifier.builder(queueII).augmentation(FlowCapableNodeConnectorQueueStatisticsData.class).toInstance();
- it.removeOperationalData(nodeConnectorQueueStatisticsDataAugmentation);
- }
- }
- it.commit();
- }
-}
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-service</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-base</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-management</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-inventory</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.xtend</groupId>
<dependency>
<groupId>equinoxSDK381</groupId>
<artifactId>org.eclipse.osgi</artifactId>
- <version>3.8.1.v20120830-144521</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
- <version>1.7</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal</artifactId>
- <version>0.7.1-SNAPSHOT</version>
</dependency>
</dependencies>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-util</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-service</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-inventory</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
private static void registerAsJMXListener(MBeanServerConnection mBeanServerConnection, ConfigPersisterNotificationListener listener) {
logger.trace("Called registerAsJMXListener");
try {
- mBeanServerConnection.addNotificationListener(DefaultCommitOperationMXBean.objectName, listener, null, null);
+ mBeanServerConnection.addNotificationListener(DefaultCommitOperationMXBean.OBJECT_NAME, listener, null, null);
} catch (InstanceNotFoundException | IOException e) {
throw new RuntimeException("Cannot register as JMX listener to netconf", e);
}
@Override
public synchronized void close() {
// unregister from JMX
- ObjectName on = DefaultCommitOperationMXBean.objectName;
+ ObjectName on = DefaultCommitOperationMXBean.OBJECT_NAME;
try {
if (mBeanServerConnection.isRegistered(on)) {
mBeanServerConnection.removeNotificationListener(on, listener);
private final long sessionId;
private boolean up = false;
- protected final Channel channel;
+ private final Channel channel;
protected AbstractNetconfSession(L sessionListener, Channel channel, long sessionId) {
this.sessionListener = sessionListener;
this.channel = channel;
this.sessionId = sessionId;
- logger.debug("Session {} created", toString());
+ logger.debug("Session {} created", sessionId);
}
protected abstract S thisInstance();
package org.opendaylight.controller.netconf.api;
public class NetconfSessionPreferences {
- protected final NetconfMessage helloMessage;
+ private final NetconfMessage helloMessage;
public NetconfSessionPreferences(final NetconfMessage helloMessage) {
this.helloMessage = helloMessage;
private final Element configSnapshot;
- private static final String afterCommitMessageTemplate = "Commit successful: %s";
+ private static final String AFTER_COMMIT_MESSAGE_TEMPLATE = "Commit successful: %s";
private final Set<String> capabilities;
CommitJMXNotification(NotificationBroadcasterSupport source, String message, Element cfgSnapshot,
Set<String> capabilities) {
- super(TransactionProviderJMXNotificationType.commit, source, String.format(afterCommitMessageTemplate, message));
+ super(TransactionProviderJMXNotificationType.commit, source, String.format(AFTER_COMMIT_MESSAGE_TEMPLATE, message));
this.configSnapshot = cfgSnapshot;
this.capabilities = capabilities;
}
public interface DefaultCommitOperationMXBean {
- static String typeName = "NetconfNotificationProvider";
- public static ObjectName objectName = ObjectNameUtil.createONWithDomainAndType(typeName);
+ String TYPE_NAME = "NetconfNotificationProvider";
+ ObjectName OBJECT_NAME = ObjectNameUtil.createONWithDomainAndType(TYPE_NAME);
}
private final MBeanServer mbeanServer;
- private final ObjectName on = DefaultCommitOperationMXBean.objectName;
+ private final ObjectName on = DefaultCommitOperationMXBean.OBJECT_NAME;
public DefaultCommitNotificationProducer(MBeanServer mBeanServer) {
this.mbeanServer = mBeanServer;
logger.debug("Additional header from hello parsed as {} from {}", parsedHeader, additionalHeader);
- return new NetconfServerSession(sessionListener, channel, sessionPreferences.getSessionId(), parsedHeader);
+ return new NetconfServerSession(sessionListener, channel, getSessionPreferences().getSessionId(), parsedHeader);
}
}
import java.net.InetSocketAddress;
import java.util.Dictionary;
import java.util.Hashtable;
+import java.util.concurrent.TimeUnit;
public class NetconfImplActivator implements BundleActivator {
logger.info("Shutting down netconf because YangStoreService service was removed");
commitNot.close();
- eventLoopGroup.shutdownGracefully();
+ eventLoopGroup.shutdownGracefully(0, 1, TimeUnit.SECONDS);
timer.stop();
regMonitoring.unregister();
package org.opendaylight.controller.netconf.impl;
-import org.junit.Before;
-import org.junit.Test;
-import org.opendaylight.controller.netconf.util.messages.NetconfMessageHeader;
-
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
-public class MessageHeaderTest {
-
- private NetconfMessageHeader header = null;
-
- @Before
- public void setUp() {
- this.header = new NetconfMessageHeader();
- }
+import org.junit.Test;
+import org.opendaylight.controller.netconf.util.messages.NetconfMessageHeader;
+public class MessageHeaderTest {
@Test
public void testFromBytes() {
final byte[] raw = new byte[] { (byte) 0x0a, (byte) 0x23, (byte) 0x35, (byte) 0x38, (byte) 0x0a };
- this.header.fromBytes(raw);
- assertEquals(58, this.header.getLength());
+ NetconfMessageHeader header = NetconfMessageHeader.fromBytes(raw);
+ assertEquals(58, header.getLength());
}
@Test
public void testToBytes() {
- this.header.setLength(123);
+ NetconfMessageHeader header = new NetconfMessageHeader(123);
assertArrayEquals(new byte[] { (byte) 0x0a, (byte) 0x23, (byte) 0x31, (byte) 0x32, (byte) 0x33, (byte) 0x0a },
- this.header.toBytes());
+ header.toBytes());
}
}
import org.junit.Before;
import org.junit.Test;
import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.util.handler.ChunkedFramingMechanismEncoder;
import org.opendaylight.controller.netconf.util.handler.FramingMechanismHandlerFactory;
-import org.opendaylight.controller.netconf.util.handler.NetconfMessageAggregator;
-import org.opendaylight.controller.netconf.util.handler.NetconfMessageChunkDecoder;
+import org.opendaylight.controller.netconf.util.handler.NetconfChunkAggregator;
+import org.opendaylight.controller.netconf.util.handler.NetconfEOMAggregator;
import org.opendaylight.controller.netconf.util.handler.NetconfMessageToXMLEncoder;
import org.opendaylight.controller.netconf.util.handler.NetconfXMLToMessageDecoder;
import org.opendaylight.controller.netconf.util.messages.FramingMechanism;
FramingMechanismHandlerFactory.createHandler(FramingMechanism.CHUNK),
new NetconfMessageToXMLEncoder(),
- new NetconfMessageAggregator(FramingMechanism.CHUNK), new NetconfMessageChunkDecoder(),
+ new NetconfChunkAggregator(),
new NetconfXMLToMessageDecoder());
testChunkChannel.writeOutbound(this.msg);
enc.encode(null, msg, out);
int msgLength = out.readableBytes();
- int chunkCount = msgLength / NetconfMessageConstants.MAX_CHUNK_SIZE;
- if ((msgLength % NetconfMessageConstants.MAX_CHUNK_SIZE) != 0) {
+ int chunkCount = msgLength / ChunkedFramingMechanismEncoder.DEFAULT_CHUNK_SIZE;
+ if ((msgLength % ChunkedFramingMechanismEncoder.DEFAULT_CHUNK_SIZE) != 0) {
chunkCount++;
}
for (int i = 1; i <= chunkCount; i++) {
ByteBuf recievedOutbound = (ByteBuf) messages.poll();
- int exptHeaderLength = NetconfMessageConstants.MAX_CHUNK_SIZE;
+ int exptHeaderLength = ChunkedFramingMechanismEncoder.DEFAULT_CHUNK_SIZE;
if (i == chunkCount) {
- exptHeaderLength = msgLength - (NetconfMessageConstants.MAX_CHUNK_SIZE * (i - 1));
- byte[] eom = new byte[NetconfMessageConstants.endOfChunk.length];
- recievedOutbound.getBytes(recievedOutbound.readableBytes() - NetconfMessageConstants.endOfChunk.length,
+ exptHeaderLength = msgLength - (ChunkedFramingMechanismEncoder.DEFAULT_CHUNK_SIZE * (i - 1));
+ byte[] eom = new byte[NetconfMessageConstants.END_OF_CHUNK.length];
+ recievedOutbound.getBytes(recievedOutbound.readableBytes() - NetconfMessageConstants.END_OF_CHUNK.length,
eom);
- assertArrayEquals(NetconfMessageConstants.endOfChunk, eom);
+ assertArrayEquals(NetconfMessageConstants.END_OF_CHUNK, eom);
}
byte[] header = new byte[String.valueOf(exptHeaderLength).length()
+ NetconfMessageConstants.MIN_HEADER_LENGTH - 1];
recievedOutbound.getBytes(0, header);
- NetconfMessageHeader messageHeader = new NetconfMessageHeader();
- messageHeader.fromBytes(header);
+ NetconfMessageHeader messageHeader = NetconfMessageHeader.fromBytes(header);
assertEquals(exptHeaderLength, messageHeader.getLength());
testChunkChannel.writeInbound(recievedOutbound);
public void testEOMFramingMechanismOnPipeline() throws Exception {
EmbeddedChannel testChunkChannel = new EmbeddedChannel(
FramingMechanismHandlerFactory.createHandler(FramingMechanism.EOM),
- new NetconfMessageToXMLEncoder(), new NetconfMessageAggregator(
- FramingMechanism.EOM), new NetconfXMLToMessageDecoder());
+ new NetconfMessageToXMLEncoder(), new NetconfEOMAggregator(), new NetconfXMLToMessageDecoder());
testChunkChannel.writeOutbound(this.msg);
ByteBuf recievedOutbound = (ByteBuf) testChunkChannel.readOutbound();
- byte[] eom = new byte[NetconfMessageConstants.endOfMessage.length];
- recievedOutbound.getBytes(recievedOutbound.readableBytes() - NetconfMessageConstants.endOfMessage.length, eom);
- assertArrayEquals(NetconfMessageConstants.endOfMessage, eom);
+ byte[] eom = new byte[NetconfMessageConstants.END_OF_MESSAGE.length];
+ recievedOutbound.getBytes(recievedOutbound.readableBytes() - NetconfMessageConstants.END_OF_MESSAGE.length, eom);
+ assertArrayEquals(NetconfMessageConstants.END_OF_MESSAGE, eom);
testChunkChannel.writeInbound(recievedOutbound);
NetconfMessage receivedMessage = (NetconfMessage) testChunkChannel.readInbound();
*/
package org.opendaylight.controller.netconf.it;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
+import static junit.framework.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
import io.netty.channel.ChannelFuture;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetSocketAddress;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import javax.management.InstanceNotFoundException;
+import javax.management.Notification;
+import javax.management.NotificationListener;
+
import org.apache.commons.lang3.StringUtils;
import org.junit.After;
import org.junit.Assert;
import org.opendaylight.controller.netconf.persist.impl.ConfigPersisterNotificationHandler;
import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.w3c.dom.Element;
-import javax.management.InstanceNotFoundException;
-import javax.management.Notification;
-import javax.management.NotificationListener;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.InetSocketAddress;
-import java.util.Collection;
-import java.util.List;
-import java.util.Set;
-import java.util.regex.Pattern;
-
-import static junit.framework.Assert.assertEquals;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyLong;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
public class NetconfConfigPersisterITTest extends AbstractNetconfConfigTest {
- private static final Logger logger = LoggerFactory.getLogger(NetconfConfigPersisterITTest.class);
-
private static final InetSocketAddress tcpAddress = new InetSocketAddress("127.0.0.1", 12023);
private VerifyingNotificationListener createCommitNotificationListener() throws InstanceNotFoundException {
VerifyingNotificationListener listener = new VerifyingNotificationListener();
- platformMBeanServer.addNotificationListener(DefaultCommitNotificationProducer.objectName, listener, null, null);
+ platformMBeanServer.addNotificationListener(DefaultCommitNotificationProducer.OBJECT_NAME, listener, null, null);
return listener;
}
public VerifyingPersister() throws IOException {
Persister mockedAggregator = mock(Persister.class);
- doAnswer(new Answer() {
+ doAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
ConfigSnapshotHolder configSnapshot = (ConfigSnapshotHolder) invocation.getArguments()[0];
*/
package org.opendaylight.controller.netconf.it;
-import com.google.common.base.Charsets;
-import com.google.common.base.Optional;
-import com.google.common.collect.Sets;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
import io.netty.channel.ChannelFuture;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
import junit.framework.Assert;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.matchers.JUnitMatchers;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.util.Collection;
-import java.util.List;
-import java.util.Set;
-
-import static org.mockito.Matchers.anyLong;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
+import com.google.common.base.Charsets;
+import com.google.common.base.Optional;
+import com.google.common.collect.Sets;
public class NetconfMonitoringITTest extends AbstractNetconfConfigTest {
}
}
+ sock.close();
+
org.junit.Assert.assertThat(responseBuilder.toString(), JUnitMatchers.containsString("<capability>urn:ietf:params:netconf:capability:candidate:1.0</capability>"));
org.junit.Assert.assertThat(responseBuilder.toString(), JUnitMatchers.containsString("<username>tomas</username>"));
}
public class MonitoringConstants {
- public static final String NAMESPACE = "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring";
public static final String MODULE_NAME = "ietf-netconf-monitoring";
public static final String MODULE_REVISION = "2010-10-04";
+ public static final String NAMESPACE = "urn:ietf:params:xml:ns:yang:" + MODULE_NAME;
+ public static final String EXTENSION_NAMESPACE = NAMESPACE + "-extension";
+
+ public static final String EXTENSION_NAMESPACE_PREFIX = "ncme";
+
public static final String URI = String.format("%s?module=%s&revision=%s", NAMESPACE, MODULE_NAME, MODULE_REVISION);
public static final String NETCONF_MONITORING_XML_ROOT_ELEMENT = "netconf-state";
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlTransient;
+import com.google.common.base.Joiner;
+import org.opendaylight.controller.netconf.monitoring.MonitoringConstants;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.Session1;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions.Session;
import org.opendaylight.yangtools.yang.common.QName;
public String getTransport() {
try {
QName qName = (QName) managementSession.getTransport().getField("QNAME").get(null);
- return qName.getLocalName();
+ // Add extension prefix if transport type is from extension yang module
+ if (qName.getNamespace().toString().equals(MonitoringConstants.EXTENSION_NAMESPACE)) {
+ return Joiner.on(':').join(MonitoringConstants.EXTENSION_NAMESPACE_PREFIX, qName.getLocalName());
+ } else {
+ return qName.getLocalName();
+ }
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
throw new IllegalArgumentException("Unknown transport type " + managementSession.getTransport(), e);
}
}
- @XmlElement(name= "session-identifier")
+ @XmlElement(name= "session-identifier", namespace = MonitoringConstants.EXTENSION_NAMESPACE)
public String getSessionType() {
return managementSession.getAugmentation(Session1.class).getSessionIdentifier();
}
*/
@XmlSchema(
elementFormDefault = XmlNsForm.QUALIFIED,
-// xmlns = {
-// @XmlNs(namespaceURI = MonitoringConstants.NAMESPACE, prefix = "")
-// }
+ xmlns = {
+ @XmlNs(namespaceURI = MonitoringConstants.EXTENSION_NAMESPACE, prefix = MonitoringConstants.EXTENSION_NAMESPACE_PREFIX),
+ @XmlNs(namespaceURI = MonitoringConstants.NAMESPACE, prefix = "")
+ },
namespace = MonitoringConstants.NAMESPACE
)
package org.opendaylight.controller.netconf.monitoring.xml.model;
import org.opendaylight.controller.netconf.monitoring.MonitoringConstants;
+import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
\ No newline at end of file
import org.opendaylight.controller.netconf.monitoring.xml.model.NetconfState;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.DomainName;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Host;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.NetconfTcp;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.Session1;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfSsh;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.Transport;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Schemas;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.SchemasBuilder;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Sessions;
@Override
public Sessions getSessions() {
- return new SessionsBuilder().setSession(Lists.newArrayList(getMockSession())).build();
+ return new SessionsBuilder().setSession(Lists.newArrayList(getMockSession(NetconfTcp.class), getMockSession(NetconfSsh.class))).build();
}
@Override
Element xml = new JaxBSerializer().toXml(model);
}
- private Session getMockSession() {
+ private Session getMockSession(Class<? extends Transport> transportType) {
Session mocked = mock(Session.class);
Session1 mockedSession1 = mock(Session1.class);
doReturn("client").when(mockedSession1).getSessionIdentifier();
doReturn(new ZeroBasedCounter32(0L)).when(mocked).getInRpcs();
doReturn(new ZeroBasedCounter32(0L)).when(mocked).getOutNotifications();
doReturn(new ZeroBasedCounter32(0L)).when(mocked).getOutRpcErrors();
- doReturn(NetconfSsh.class).when(mocked).getTransport();
+ doReturn(transportType).when(mocked).getTransport();
doReturn("username").when(mocked).getUsername();
doReturn(mockedSession1).when(mocked).getAugmentation(Session1.class);
return mocked;
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>usermanager</artifactId>
- <version>0.4.2-SNAPSHOT</version>
</dependency>
</dependencies>
public AuthProvider(IUserManager ium,InputStream privateKeyFileInputStream) throws Exception {
- this.um = ium;
- if (this.um == null){
+ AuthProvider.um = ium;
+ if (AuthProvider.um == null){
throw new Exception("No usermanager service available.");
}
List<String> roles = new ArrayList<String>(1);
roles.add(UserLevel.SYSTEMADMIN.toString());
- this.um.addLocalUser(new UserConfig(DEFAULT_USER, DEFAULT_PASSWORD, roles));
+ AuthProvider.um.addLocalUser(new UserConfig(DEFAULT_USER, DEFAULT_PASSWORD, roles));
try {
PEM = IOUtils.toString(privateKeyFileInputStream);
}
@Override
public boolean authenticated(String username, String password) throws Exception {
- if (this.um == null){
+ if (AuthProvider.um == null){
throw new Exception("No usermanager service available.");
}
- AuthResultEnum authResult = this.um.authenticate(username,password);
+ AuthResultEnum authResult = AuthProvider.um.authenticate(username,password);
if (authResult.equals(AuthResultEnum.AUTH_ACCEPT) || authResult.equals(AuthResultEnum.AUTH_ACCEPT_LOC)){
return true;
}
@Override
public void removeUserManagerService() {
- this.um = null;
+ AuthProvider.um = null;
}
@Override
public void addUserManagerService(IUserManager userManagerService) {
- this.um = userManagerService;
+ AuthProvider.um = userManagerService;
}
*/
package org.opendaylight.controller.netconf.ssh.threads;
-import ch.ethz.ssh2.ServerConnection;
-import ch.ethz.ssh2.ServerSession;
import java.io.InputStream;
import java.io.OutputStream;
+
import javax.annotation.concurrent.ThreadSafe;
+
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import ch.ethz.ssh2.ServerConnection;
+import ch.ethz.ssh2.ServerSession;
+
@ThreadSafe
public class IOThread extends Thread {
private static final Logger logger = LoggerFactory.getLogger(IOThread.class);
- private InputStream inputStream;
- private OutputStream outputStream;
- private String id;
- private ServerSession servSession;
- private ServerConnection servconnection;
+ private final InputStream inputStream;
+ private final OutputStream outputStream;
+ private final ServerSession servSession;
+ private final ServerConnection servconnection;
private String customHeader;
super.setName(id);
logger.trace("IOThread {} created", super.getName());
}
+
public IOThread (InputStream is, OutputStream os, String id,ServerSession ss, ServerConnection conn,String header){
this.inputStream = is;
this.outputStream = os;
try {
if (this.customHeader!=null && !this.customHeader.equals("")){
this.outputStream.write(this.customHeader.getBytes());
- logger.trace("adding {} header", this.customHeader);
+ logger.trace("adding {} header", this.customHeader);
}
IOUtils.copy(this.inputStream, this.outputStream);
} catch (Exception e) {
package org.opendaylight.controller.netconf.ssh.threads;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+
+import javax.annotation.concurrent.ThreadSafe;
+
+import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import ch.ethz.ssh2.AuthenticationResult;
import ch.ethz.ssh2.PtySettings;
import ch.ethz.ssh2.ServerAuthenticationCallback;
import ch.ethz.ssh2.ServerSession;
import ch.ethz.ssh2.ServerSessionCallback;
import ch.ethz.ssh2.SimpleServerSessionCallback;
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import javax.annotation.concurrent.ThreadSafe;
-import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
@ThreadSafe
-public class SocketThread implements Runnable, ServerAuthenticationCallback, ServerConnectionCallback
-{
-
- private Socket socket;
- private static final String USER = "netconf";
- private static final String PASSWORD = "netconf";
- private InetSocketAddress clientAddress;
+public class SocketThread implements Runnable, ServerAuthenticationCallback, ServerConnectionCallback {
private static final Logger logger = LoggerFactory.getLogger(SocketThread.class);
+
+ private final Socket socket;
+ private final InetSocketAddress clientAddress;
private ServerConnection conn = null;
- private long sessionId;
+ private final long sessionId;
private String currentUser;
private final String remoteAddressWithPort;
private final AuthProvider authProvider;
logger.error("SocketThread error ",e);
}
}
+ @Override
public ServerSessionCallback acceptSession(final ServerSession session)
{
SimpleServerSessionCallback cb = new SimpleServerSessionCallback()
public Runnable requestSubsystem(final ServerSession ss, final String subsystem) throws IOException
{
return new Runnable(){
+ @Override
public void run()
{
if (subsystem.equals("netconf")){
{
return new Runnable()
{
+ @Override
public void run()
{
//noop
{
return new Runnable()
{
+ @Override
public void run()
{
//noop
return cb;
}
+ @Override
public String initAuthentication(ServerConnection sc)
{
logger.trace("Established connection with host {}",remoteAddressWithPort);
return "Established connection with host "+remoteAddressWithPort+"\r\n";
}
+ @Override
public String[] getRemainingAuthMethods(ServerConnection sc)
{
return new String[] { ServerAuthenticationCallback.METHOD_PASSWORD };
}
+ @Override
public AuthenticationResult authenticateWithNone(ServerConnection sc, String username)
{
return AuthenticationResult.FAILURE;
}
+ @Override
public AuthenticationResult authenticateWithPassword(ServerConnection sc, String username, String password)
{
return AuthenticationResult.FAILURE;
}
+ @Override
public AuthenticationResult authenticateWithPublicKey(ServerConnection sc, String username, String algorithm,
byte[] publickey, byte[] signature)
{
private static String password;
public StubUserManager(String user, String password){
- this.user = user;
- this.password = password;
+ StubUserManager.user = user;
+ StubUserManager.password = password;
}
@Override
public List<String> getUserRoles(String userName) {
@Override
public AuthResultEnum authenticate(String username, String password) {
- if (this.user.equals(username) && this.password.equals(password)){
+ if (StubUserManager.user.equals(username) && StubUserManager.password.equals(password)){
return AuthResultEnum.AUTH_ACCEPT_LOC;
}
return AuthResultEnum.AUTH_REJECT_LOC;
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-handler</artifactId>
- <version>${netconf.netty.version}</version>
</dependency>
<!--dependency>
<groupId>com.siemens.ct.exi</groupId>
import org.opendaylight.controller.netconf.api.NetconfSession;
import org.opendaylight.controller.netconf.util.handler.FramingMechanismHandlerFactory;
+import org.opendaylight.controller.netconf.util.handler.NetconfEOMAggregator;
import org.opendaylight.controller.netconf.util.handler.NetconfHelloMessageToXMLEncoder;
-import org.opendaylight.controller.netconf.util.handler.NetconfMessageAggregator;
import org.opendaylight.controller.netconf.util.handler.NetconfXMLToHelloMessageDecoder;
import org.opendaylight.controller.netconf.util.messages.FramingMechanism;
public static final String NETCONF_SESSION_NEGOTIATOR = "negotiator";
public void initialize(SocketChannel ch, Promise<S> promise) {
- ch.pipeline().addLast(NETCONF_MESSAGE_AGGREGATOR, new NetconfMessageAggregator(FramingMechanism.EOM));
+ ch.pipeline().addLast(NETCONF_MESSAGE_AGGREGATOR, new NetconfEOMAggregator());
initializeMessageDecoder(ch);
ch.pipeline().addLast(NETCONF_MESSAGE_FRAME_ENCODER, FramingMechanismHandlerFactory.createHandler(FramingMechanism.EOM));
initializeMessageEncoder(ch);
package org.opendaylight.controller.netconf.util;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.ssl.SslHandler;
+import io.netty.util.Timeout;
+import io.netty.util.Timer;
+import io.netty.util.TimerTask;
+import io.netty.util.concurrent.Future;
+import io.netty.util.concurrent.GenericFutureListener;
+import io.netty.util.concurrent.Promise;
+
import java.util.concurrent.TimeUnit;
+import io.netty.channel.ChannelInboundHandlerAdapter;
import org.opendaylight.controller.netconf.api.AbstractNetconfSession;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.api.NetconfSessionListener;
import org.opendaylight.controller.netconf.api.NetconfSessionPreferences;
import org.opendaylight.controller.netconf.util.handler.FramingMechanismHandlerFactory;
-import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
-import org.opendaylight.controller.netconf.util.handler.NetconfMessageAggregator;
-import org.opendaylight.controller.netconf.util.handler.NetconfMessageChunkDecoder;
+import org.opendaylight.controller.netconf.util.handler.NetconfChunkAggregator;
import org.opendaylight.controller.netconf.util.handler.NetconfMessageToXMLEncoder;
import org.opendaylight.controller.netconf.util.handler.NetconfXMLToMessageDecoder;
import org.opendaylight.controller.netconf.util.messages.FramingMechanism;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.opendaylight.protocol.framework.AbstractSessionNegotiator;
import org.slf4j.Logger;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
-import io.netty.channel.Channel;
-import io.netty.channel.ChannelHandler;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.handler.ssl.SslHandler;
-import io.netty.util.Timeout;
-import io.netty.util.Timer;
-import io.netty.util.TimerTask;
-import io.netty.util.concurrent.Future;
-import io.netty.util.concurrent.GenericFutureListener;
-import io.netty.util.concurrent.Promise;
-
public abstract class AbstractNetconfSessionNegotiator<P extends NetconfSessionPreferences, S extends AbstractNetconfSession<S, L>, L extends NetconfSessionListener<S>>
extends AbstractSessionNegotiator<NetconfHelloMessage, S> {
private static final Logger logger = LoggerFactory.getLogger(AbstractNetconfSessionNegotiator.class);
public static final String NAME_OF_EXCEPTION_HANDLER = "lastExceptionHandler";
- public static final String CHUNK_DECODER_CHANNEL_HANDLER_KEY = "chunkDecoder";
- protected final P sessionPreferences;
+ private final P sessionPreferences;
private final L sessionListener;
private Timeout timeout;
Future<Channel> future = sslHandler.get().handshakeFuture();
future.addListener(new GenericFutureListener<Future<? super Channel>>() {
@Override
- public void operationComplete(Future<? super Channel> future) throws Exception {
+ public void operationComplete(Future<? super Channel> future) {
Preconditions.checkState(future.isSuccess(), "Ssl handshake was not successful");
logger.debug("Ssl handshake complete");
start();
}
});
- } else
+ } else {
start();
+ }
}
private static Optional<SslHandler> getSslHandler(Channel channel) {
return sslHandler == null ? Optional.<SslHandler> absent() : Optional.of(sslHandler);
}
+ public P getSessionPreferences() {
+ return sessionPreferences;
+ }
+
private void start() {
final NetconfMessage helloMessage = this.sessionPreferences.getHelloMessage();
logger.debug("Session negotiation started with hello message {}", XmlUtil.toString(helloMessage.getDocument()));
- channel.pipeline().addLast(NAME_OF_EXCEPTION_HANDLER, new ChannelHandler() {
- @Override
- public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
- }
-
- @Override
- public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
- }
-
- @Override
- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
- logger.warn("An exception occurred during negotiation on channel {}", channel.localAddress(), cause);
- cancelTimeout();
- negotiationFailed(cause);
- changeState(State.FAILED);
- }
- });
+ channel.pipeline().addLast(NAME_OF_EXCEPTION_HANDLER, new ExceptionHandlingInboundChannelHandler());
timeout = this.timer.newTimeout(new TimerTask() {
@Override
- public void run(final Timeout timeout) throws Exception {
+ public void run(final Timeout timeout) {
synchronized (this) {
if (state != State.ESTABLISHED) {
logger.debug("Connection timeout after {}, session is in state {}", timeout, state);
}
private void cancelTimeout() {
- if(timeout!=null)
+ if(timeout!=null) {
timeout.cancel();
+ }
}
private void sendMessage(NetconfMessage message) {
@Override
protected void handleMessage(NetconfHelloMessage netconfMessage) {
- final Document doc = netconfMessage.getDocument();
+ Preconditions.checkNotNull(netconfMessage != null, "netconfMessage");
- // Only Hello message should arrive during negotiation
- if (netconfMessage instanceof NetconfHelloMessage) {
+ final Document doc = netconfMessage.getDocument();
- replaceHelloMessageHandlers();
+ replaceHelloMessageHandlers();
- if (shouldUseChunkFraming(doc)) {
- insertChunkFramingToPipeline();
- }
+ if (shouldUseChunkFraming(doc)) {
+ insertChunkFramingToPipeline();
+ }
- changeState(State.ESTABLISHED);
- S session = getSession(sessionListener, channel, (NetconfHelloMessage)netconfMessage);
+ changeState(State.ESTABLISHED);
+ S session = getSession(sessionListener, channel, netconfMessage);
- negotiationSuccessful(session);
- } else {
- final IllegalStateException cause = new IllegalStateException(
- "Received message was not hello as expected, but was " + XmlUtil.toString(doc));
- logger.warn("Negotiation of netconf session failed", cause);
- negotiationFailed(cause);
- }
+ negotiationSuccessful(session);
}
/**
replaceChannelHandler(channel, AbstractChannelInitializer.NETCONF_MESSAGE_FRAME_ENCODER,
FramingMechanismHandlerFactory.createHandler(FramingMechanism.CHUNK));
replaceChannelHandler(channel, AbstractChannelInitializer.NETCONF_MESSAGE_AGGREGATOR,
- new NetconfMessageAggregator(FramingMechanism.CHUNK));
- channel.pipeline().addAfter(AbstractChannelInitializer.NETCONF_MESSAGE_AGGREGATOR,
- CHUNK_DECODER_CHANNEL_HANDLER_KEY, new NetconfMessageChunkDecoder());
+ new NetconfChunkAggregator());
}
private boolean shouldUseChunkFraming(Document doc) {
}
private static boolean isStateChangePermitted(State state, State newState) {
- if (state == State.IDLE && newState == State.OPEN_WAIT)
+ if (state == State.IDLE && newState == State.OPEN_WAIT) {
return true;
- if (state == State.OPEN_WAIT && newState == State.ESTABLISHED)
+ }
+ if (state == State.OPEN_WAIT && newState == State.ESTABLISHED) {
return true;
- if (state == State.OPEN_WAIT && newState == State.FAILED)
+ }
+ if (state == State.OPEN_WAIT && newState == State.FAILED) {
return true;
+ }
logger.debug("Transition from {} to {} is not allowed", state, newState);
return false;
}
+
+ /**
+ * Handler to catch exceptions in pipeline during negotiation
+ */
+ private final class ExceptionHandlingInboundChannelHandler extends ChannelInboundHandlerAdapter {
+
+ @Override
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
+ logger.warn("An exception occurred during negotiation on channel {}", channel.localAddress(), cause);
+ cancelTimeout();
+ negotiationFailed(cause);
+ changeState(State.FAILED);
+ }
+ }
}
import java.io.IOException;
import java.io.InputStream;
-public class NetconfUtil {
+public final class NetconfUtil {
private static final Logger logger = LoggerFactory.getLogger(NetconfUtil.class);
+ private NetconfUtil() {}
+
public static NetconfMessage createMessage(final File f) {
Preconditions.checkNotNull(f, "File parameter was null");
try {
package org.opendaylight.controller.netconf.util.handler;
-import org.opendaylight.controller.netconf.util.messages.NetconfMessageConstants;
-import org.opendaylight.controller.netconf.util.messages.NetconfMessageHeader;
-
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
+import org.opendaylight.controller.netconf.util.messages.NetconfMessageConstants;
+import org.opendaylight.controller.netconf.util.messages.NetconfMessageHeader;
+
+import com.google.common.base.Preconditions;
+
public class ChunkedFramingMechanismEncoder extends MessageToByteEncoder<ByteBuf> {
+ public static final int DEFAULT_CHUNK_SIZE = 8192;
+ public static final int MIN_CHUNK_SIZE = 128;
+ public static final int MAX_CHUNK_SIZE = 16 * 1024 * 1024;
- private NetconfMessageHeader messageHeader = new NetconfMessageHeader();
+ private final int chunkSize;
- private final static int MAX_CHUNK_SIZE = NetconfMessageConstants.MAX_CHUNK_SIZE;
+ public ChunkedFramingMechanismEncoder() {
+ this(DEFAULT_CHUNK_SIZE);
+ }
+
+ public ChunkedFramingMechanismEncoder(int chunkSize) {
+ Preconditions.checkArgument(chunkSize > MIN_CHUNK_SIZE);
+ Preconditions.checkArgument(chunkSize < MAX_CHUNK_SIZE);
+ this.chunkSize = chunkSize;
+ }
+
+ public final int getChunkSize() {
+ return chunkSize;
+ }
@Override
protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) throws Exception {
- while (msg.readableBytes() > MAX_CHUNK_SIZE) {
- ByteBuf chunk = Unpooled.buffer(MAX_CHUNK_SIZE);
- chunk.writeBytes(createChunkHeader(MAX_CHUNK_SIZE));
- chunk.writeBytes(msg.readBytes(MAX_CHUNK_SIZE));
+ while (msg.readableBytes() > chunkSize) {
+ ByteBuf chunk = Unpooled.buffer(chunkSize);
+ chunk.writeBytes(createChunkHeader(chunkSize));
+ chunk.writeBytes(msg.readBytes(chunkSize));
ctx.write(chunk);
}
out.writeBytes(createChunkHeader(msg.readableBytes()));
out.writeBytes(msg.readBytes(msg.readableBytes()));
- out.writeBytes(NetconfMessageConstants.endOfChunk);
+ out.writeBytes(NetconfMessageConstants.END_OF_CHUNK);
}
private ByteBuf createChunkHeader(int chunkSize) {
- messageHeader.setLength(chunkSize);
- return Unpooled.wrappedBuffer(messageHeader.toBytes());
+ return Unpooled.wrappedBuffer(NetconfMessageHeader.toBytes(chunkSize));
}
-
}
package org.opendaylight.controller.netconf.util.handler;
-import org.opendaylight.controller.netconf.util.messages.NetconfMessageConstants;
-
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
-public class EOMFramingMechanismEncoder extends MessageToByteEncoder<ByteBuf> {
-
- private byte[] eom = NetconfMessageConstants.endOfMessage;
+import org.opendaylight.controller.netconf.util.messages.NetconfMessageConstants;
+public class EOMFramingMechanismEncoder extends MessageToByteEncoder<ByteBuf> {
@Override
protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) throws Exception {
out.writeBytes(msg);
- out.writeBytes(eom);
+ out.writeBytes(NetconfMessageConstants.END_OF_MESSAGE);
}
-
}
public class FramingMechanismHandlerFactory {
- private final static Logger logger = LoggerFactory.getLogger(FramingMechanismHandlerFactory.class);
+ private static final Logger logger = LoggerFactory.getLogger(FramingMechanismHandlerFactory.class);
+
+ private FramingMechanismHandlerFactory() {}
public static MessageToByteEncoder<ByteBuf> createHandler(FramingMechanism framingMechanism) {
logger.debug("{} framing mechanism was selected.", framingMechanism);
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.netconf.util.handler;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.ByteToMessageDecoder;
+
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NetconfChunkAggregator extends ByteToMessageDecoder {
+ private final static Logger logger = LoggerFactory.getLogger(NetconfChunkAggregator.class);
+ public static final int DEFAULT_MAXIMUM_CHUNK_SIZE = 16 * 1024 * 1024;
+
+ private static enum State {
+ HEADER_ONE, // \n
+ HEADER_TWO, // #
+ HEADER_LENGTH_FIRST, // [1-9]
+ HEADER_LENGTH_OTHER, // [0-9]*\n
+ DATA,
+ FOOTER_ONE, // \n
+ FOOTER_TWO, // #
+ FOOTER_THREE, // #
+ FOOTER_FOUR, // \n
+ }
+
+ private final int maxChunkSize = DEFAULT_MAXIMUM_CHUNK_SIZE;
+ private State state = State.HEADER_ONE;
+ private long chunkSize;
+ private ByteBuf chunk;
+
+ @Override
+ protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
+ while (in.isReadable()) {
+ switch (state) {
+ case HEADER_ONE:
+ {
+ final byte b = in.readByte();
+ if (b != '\n') {
+ logger.debug("Got byte {} while waiting for {}", b, (byte)'\n');
+ throw new IllegalStateException("Malformed chunk header encountered (byte 0)");
+ }
+
+ state = State.HEADER_TWO;
+ break;
+ }
+ case HEADER_TWO:
+ {
+ final byte b = in.readByte();
+ if (b != '#') {
+ logger.debug("Got byte {} while waiting for {}", b, (byte)'#');
+ throw new IllegalStateException("Malformed chunk header encountered (byte 1)");
+ }
+
+ state = State.HEADER_LENGTH_FIRST;
+ break;
+ }
+ case HEADER_LENGTH_FIRST:
+ {
+ final byte b = in.readByte();
+ if (b < '1' || b > '9') {
+ logger.debug("Got byte {} while waiting for {}-{}", b, (byte)'1', (byte)'9');
+ throw new IllegalStateException("Invalid chunk size encountered (byte 0)");
+ }
+
+ chunkSize = b - '0';
+ state = State.HEADER_LENGTH_OTHER;
+ break;
+ }
+ case HEADER_LENGTH_OTHER:
+ {
+ final byte b = in.readByte();
+ if (b == '\n') {
+ state = State.DATA;
+ break;
+ }
+
+ if (b < '0' || b > '9') {
+ logger.debug("Got byte {} while waiting for {}-{}", b, (byte)'0', (byte)'9');
+ throw new IllegalStateException("Invalid chunk size encountered");
+ }
+
+ chunkSize *= 10;
+ chunkSize += b - '0';
+
+ if (chunkSize > maxChunkSize) {
+ logger.debug("Parsed chunk size {}, maximum allowed is {}", chunkSize, maxChunkSize);
+ throw new IllegalStateException("Maximum chunk size exceeded");
+ }
+ break;
+ }
+ case DATA:
+ /*
+ * FIXME: this gathers all data into one big chunk before passing
+ * it on. Make sure the pipeline can work with partial data
+ * and then change this piece to pass the data on as it
+ * comes through.
+ */
+ if (in.readableBytes() < chunkSize) {
+ logger.debug("Buffer has {} bytes, need {} to complete chunk", in.readableBytes(), chunkSize);
+ in.discardReadBytes();
+ return;
+ }
+
+ chunk = in.readBytes((int)chunkSize);
+ state = State.FOOTER_ONE;
+ break;
+ case FOOTER_ONE:
+ {
+ final byte b = in.readByte();
+ if (b != '\n') {
+ logger.debug("Got byte {} while waiting for {}", b, (byte)'\n');
+ throw new IllegalStateException("Malformed chunk footer encountered (byte 0)");
+ }
+
+ state = State.FOOTER_TWO;
+ break;
+ }
+ case FOOTER_TWO:
+ {
+ final byte b = in.readByte();
+ if (b != '#') {
+ logger.debug("Got byte {} while waiting for {}", b, (byte)'#');
+ throw new IllegalStateException("Malformed chunk footer encountered (byte 1)");
+ }
+
+ state = State.FOOTER_THREE;
+ break;
+ }
+ case FOOTER_THREE:
+ {
+ final byte b = in.readByte();
+ if (b != '#') {
+ logger.debug("Got byte {} while waiting for {}", b, (byte)'#');
+ throw new IllegalStateException("Malformed chunk footer encountered (byte 2)");
+ }
+
+ state = State.FOOTER_FOUR;
+ break;
+ }
+ case FOOTER_FOUR:
+ {
+ final byte b = in.readByte();
+ if (b != '\n') {
+ logger.debug("Got byte {} while waiting for {}", b, (byte)'\n');
+ throw new IllegalStateException("Malformed chunk footer encountered (byte 3)");
+ }
+
+ state = State.HEADER_ONE;
+ out.add(chunk);
+ chunkSize = 0;
+ chunk = null;
+ break;
+ }
+ }
+ }
+
+ in.discardReadBytes();
+ }
+}
package org.opendaylight.controller.netconf.util.handler;
-import com.google.common.base.Charsets;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
-import org.opendaylight.controller.netconf.util.messages.FramingMechanism;
-import org.opendaylight.controller.netconf.util.messages.NetconfMessageConstants;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import java.util.List;
-public class NetconfMessageAggregator extends ByteToMessageDecoder {
-
- private final static Logger logger = LoggerFactory.getLogger(NetconfMessageAggregator.class);
+import org.opendaylight.controller.netconf.util.messages.NetconfMessageConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
- private byte[] eom = NetconfMessageConstants.endOfMessage;
+import com.google.common.base.Charsets;
- public NetconfMessageAggregator(FramingMechanism framingMechanism) {
- if (framingMechanism == FramingMechanism.CHUNK) {
- eom = NetconfMessageConstants.endOfChunk;
- }
- }
+public class NetconfEOMAggregator extends ByteToMessageDecoder {
+ private final static Logger logger = LoggerFactory.getLogger(NetconfEOMAggregator.class);
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
- int index = indexOfSequence(in, eom);
+ int index = indexOfSequence(in, NetconfMessageConstants.END_OF_MESSAGE);
if (index == -1) {
logger.debug("Message is not complete, read again.");
if (logger.isTraceEnabled()) {
ctx.read();
} else {
ByteBuf msg = in.readBytes(index);
- in.readBytes(eom.length);
+ in.readBytes(NetconfMessageConstants.END_OF_MESSAGE.length);
in.discardReadBytes();
logger.debug("Message is complete.");
out.add(msg);
*/
package org.opendaylight.controller.netconf.util.handler;
-import java.nio.ByteBuffer;
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelHandlerContext;
+
+import java.io.IOException;
+
+import javax.xml.transform.TransformerException;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Charsets;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
* </pre>
*/
public final class NetconfHelloMessageToXMLEncoder extends NetconfMessageToXMLEncoder {
-
@Override
- protected ByteBuffer encodeMessage(NetconfMessage msg) {
+ @VisibleForTesting
+ public void encode(ChannelHandlerContext ctx, NetconfMessage msg, ByteBuf out) throws IOException, TransformerException {
Preconditions.checkState(msg instanceof NetconfHelloMessage, "Netconf message of type %s expected, was %s",
NetconfHelloMessage.class, msg.getClass());
Optional<NetconfHelloMessageAdditionalHeader> headerOptional = ((NetconfHelloMessage) msg)
// If additional header present, serialize it along with netconf hello
// message
if (headerOptional.isPresent()) {
- byte[] bytesFromHeader = headerOptional.get().toFormattedString().getBytes(Charsets.UTF_8);
- byte[] bytesFromMessage = xmlToString(msg.getDocument()).getBytes(Charsets.UTF_8);
-
- ByteBuffer byteBuffer = ByteBuffer.allocate(bytesFromHeader.length + bytesFromMessage.length)
- .put(bytesFromHeader).put(bytesFromMessage);
- byteBuffer.flip();
- return byteBuffer;
+ out.writeBytes(headerOptional.get().toFormattedString().getBytes(Charsets.UTF_8));
}
- return super.encodeMessage(msg);
+ super.encode(ctx, msg, out);
}
}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.util.handler;
-
-import io.netty.buffer.ByteBuf;
-import io.netty.buffer.Unpooled;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.handler.codec.ByteToMessageDecoder;
-
-import java.nio.charset.Charset;
-import java.util.List;
-
-import org.opendaylight.controller.netconf.api.NetconfDeserializerException;
-import org.opendaylight.controller.netconf.util.messages.NetconfMessageConstants;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class NetconfMessageChunkDecoder extends ByteToMessageDecoder {
-
- private final static Logger logger = LoggerFactory.getLogger(NetconfMessageChunkDecoder.class);
-
- @Override
- protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
- ByteBuf byteBufMsg = Unpooled.buffer(in.readableBytes());
- int chunkSize = -1;
- boolean isParsed = false;
- while (in.isReadable()) {
- try {
- if (!isParsed) {
- chunkSize = readHeader(in);
- isParsed = true;
- }
- if (chunkSize != -1 && isParsed) {
- in.readBytes(byteBufMsg, chunkSize);
- isParsed = false;
- } else {
- throw new NetconfDeserializerException("Unable to parse chunked data or header.");
- }
- } catch (Exception e) {
- logger.error("Failed to decode chunked message.", e);
- this.exceptionCaught(ctx, e);
- }
- }
- out.add(byteBufMsg);
- isParsed = false;
- }
-
- private int readHeader(ByteBuf in) {
- ByteBuf chunkSize = Unpooled.buffer(NetconfMessageConstants.MIN_HEADER_LENGTH,
- NetconfMessageConstants.MAX_HEADER_LENGTH);
- byte b = in.readByte();
- if (b != 10)
- return -1;
- b = in.readByte();
- if (b != 35)
- return -1;
- while ((b = in.readByte()) != 10) {
- chunkSize.writeByte(b);
- }
- return Integer.parseInt(chunkSize.toString(Charset.forName("UTF-8")));
- }
-
-}
package org.opendaylight.controller.netconf.util.handler;
import io.netty.buffer.ByteBuf;
+import io.netty.buffer.ByteBufOutputStream;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
-import java.nio.ByteBuffer;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Comment;
-import org.w3c.dom.Document;
import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Charsets;
import com.google.common.base.Optional;
public class NetconfMessageToXMLEncoder extends MessageToByteEncoder<NetconfMessage> {
private static final Logger LOG = LoggerFactory.getLogger(NetconfMessageToXMLEncoder.class);
+ private static final TransformerFactory FACTORY = TransformerFactory.newInstance();
private final Optional<String> clientId;
@Override
@VisibleForTesting
- public void encode(ChannelHandlerContext ctx, NetconfMessage msg, ByteBuf out) throws Exception {
+ public void encode(ChannelHandlerContext ctx, NetconfMessage msg, ByteBuf out) throws IOException, TransformerException {
LOG.debug("Sent to encode : {}", msg);
if (clientId.isPresent()) {
msg.getDocument().appendChild(comment);
}
- final ByteBuffer msgBytes = encodeMessage(msg);
-
- LOG.trace("Putting message \n{}", xmlToString(msg.getDocument()));
- out.writeBytes(msgBytes);
- }
-
- protected ByteBuffer encodeMessage(NetconfMessage msg) {
- return Charsets.UTF_8.encode(xmlToString(msg.getDocument()));
- }
+ try (OutputStream os = new ByteBufOutputStream(out)) {
+ Transformer transformer = FACTORY.newTransformer();
+ transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+ transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
- protected String xmlToString(Document doc) {
- return XmlUtil.toString(doc, false);
+ StreamResult result = new StreamResult(new OutputStreamWriter(os));
+ DOMSource source = new DOMSource(msg.getDocument());
+ transformer.transform(source, result);
+ }
}
}
*/
package org.opendaylight.controller.netconf.util.handler;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.ByteBufUtil;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.ByteToMessageDecoder;
+
+import java.io.ByteArrayInputStream;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.List;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableList;
* {@link org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage}
* . Used by netconf server to retrieve information about session metadata.
*/
-public class NetconfXMLToHelloMessageDecoder extends NetconfXMLToMessageDecoder {
+public final class NetconfXMLToHelloMessageDecoder extends ByteToMessageDecoder {
+ private static final Logger LOG = LoggerFactory.getLogger(NetconfXMLToHelloMessageDecoder.class);
private static final List<byte[]> POSSIBLE_ENDS = ImmutableList.of(
new byte[] { ']', '\n' },
new byte[] { '\r', '\n', '[' },
new byte[] { '\n', '[' });
- private String additionalHeaderCache;
-
@Override
- protected byte[] preprocessMessageBytes(byte[] bytes) {
- // Extract bytes containing header with additional metadata
-
- if (startsWithAdditionalHeader(bytes)) {
- // Auth information containing username, ip address... extracted for monitoring
- int endOfAuthHeader = getAdditionalHeaderEndIndex(bytes);
- if (endOfAuthHeader > -1) {
- byte[] additionalHeaderBytes = Arrays.copyOfRange(bytes, 0, endOfAuthHeader + 2);
- additionalHeaderCache = additionalHeaderToString(additionalHeaderBytes);
- bytes = Arrays.copyOfRange(bytes, endOfAuthHeader + 2, bytes.length);
- }
+ @VisibleForTesting
+ public void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
+ if (in.readableBytes() == 0) {
+ LOG.debug("No more content in incoming buffer.");
+ return;
}
- return bytes;
- }
+ in.markReaderIndex();
+ try {
+ LOG.trace("Received to decode: {}", ByteBufUtil.hexDump(in));
+ byte[] bytes = new byte[in.readableBytes()];
+ in.readBytes(bytes);
+
+ logMessage(bytes);
+
+ // Extract bytes containing header with additional metadata
+ String additionalHeader = null;
+ if (startsWithAdditionalHeader(bytes)) {
+ // Auth information containing username, ip address... extracted for monitoring
+ int endOfAuthHeader = getAdditionalHeaderEndIndex(bytes);
+ if (endOfAuthHeader > -1) {
+ byte[] additionalHeaderBytes = Arrays.copyOfRange(bytes, 0, endOfAuthHeader + 2);
+ additionalHeader = additionalHeaderToString(additionalHeaderBytes);
+ bytes = Arrays.copyOfRange(bytes, endOfAuthHeader + 2, bytes.length);
+ }
+ }
- @Override
- protected void cleanUpAfterDecode() {
- additionalHeaderCache = null;
- }
+ Document doc = XmlUtil.readXmlToDocument(new ByteArrayInputStream(bytes));
- @Override
- protected NetconfMessage buildNetconfMessage(Document doc) {
- return new NetconfHelloMessage(doc, additionalHeaderCache == null ? null
- : NetconfHelloMessageAdditionalHeader.fromString(additionalHeaderCache));
+ final NetconfMessage message;
+ if (additionalHeader != null) {
+ message = new NetconfHelloMessage(doc, NetconfHelloMessageAdditionalHeader.fromString(additionalHeader));
+ } else {
+ message = new NetconfHelloMessage(doc);
+ }
+ out.add(message);
+ } finally {
+ in.discardReadBytes();
+ }
}
private int getAdditionalHeaderEndIndex(byte[] bytes) {
return -1;
}
+
+ private void logMessage(byte[] bytes) {
+ String s = Charsets.UTF_8.decode(ByteBuffer.wrap(bytes)).toString();
+ LOG.debug("Parsing message \n{}", s);
+ }
+
private boolean startsWithAdditionalHeader(byte[] bytes) {
for (byte[] possibleStart : POSSIBLE_STARTS) {
int i = 0;
for (byte b : possibleStart) {
- if(bytes[i++] != b)
+ if(bytes[i++] != b) {
break;
+ }
- if(i == possibleStart.length)
+ if(i == possibleStart.length) {
return true;
+ }
}
}
*/
package org.opendaylight.controller.netconf.util.handler;
-import java.io.ByteArrayInputStream;
-import java.nio.ByteBuffer;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.ByteBufInputStream;
+import io.netty.buffer.ByteBufUtil;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.ByteToMessageDecoder;
+
import java.util.List;
-import org.opendaylight.controller.netconf.api.NetconfDeserializerException;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.w3c.dom.Document;
import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Charsets;
-import io.netty.buffer.ByteBuf;
-import io.netty.buffer.ByteBufUtil;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.handler.codec.ByteToMessageDecoder;
-
-public class NetconfXMLToMessageDecoder extends ByteToMessageDecoder {
+public final class NetconfXMLToMessageDecoder extends ByteToMessageDecoder {
private static final Logger LOG = LoggerFactory.getLogger(NetconfXMLToMessageDecoder.class);
@Override
@VisibleForTesting
public void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
- if (in.readableBytes() == 0) {
- LOG.debug("No more content in incoming buffer.");
- return;
- }
-
- in.markReaderIndex();
- try {
+ if (in.readableBytes() != 0) {
LOG.trace("Received to decode: {}", ByteBufUtil.hexDump(in));
- byte[] bytes = new byte[in.readableBytes()];
- in.readBytes(bytes);
-
- logMessage(bytes);
-
- bytes = preprocessMessageBytes(bytes);
- NetconfMessage message;
- try {
- Document doc = XmlUtil.readXmlToDocument(new ByteArrayInputStream(bytes));
- message = buildNetconfMessage(doc);
- } catch (Exception e) {
- throw new NetconfDeserializerException("Could not parse message from " + new String(bytes), e);
- }
-
- out.add(message);
- } finally {
- in.discardReadBytes();
- cleanUpAfterDecode();
+ out.add(new NetconfMessage(XmlUtil.readXmlToDocument(new ByteBufInputStream(in))));
+ } else {
+ LOG.debug("No more content in incoming buffer.");
}
}
-
- protected void cleanUpAfterDecode() {}
-
- protected NetconfMessage buildNetconfMessage(Document doc) {
- return new NetconfMessage(doc);
- }
-
- protected byte[] preprocessMessageBytes(byte[] bytes) {
- return bytes;
- }
-
- private void logMessage(byte[] bytes) {
- String s = Charsets.UTF_8.decode(ByteBuffer.wrap(bytes)).toString();
- LOG.debug("Parsing message \n{}", s);
- }
-
}
* stops at instance of this class. All downstream events are handed of to wrapped {@link org.opendaylight.controller.netconf.util.handler.ssh.client.SshClientAdapter};
*/
public class SshHandler extends ChannelOutboundHandlerAdapter {
+ private static final String SOCKET = "socket";
+
private final VirtualSocket virtualSocket = new VirtualSocket();
private final SshClientAdapter sshClientAdapter;
@Override
public void handlerAdded(ChannelHandlerContext ctx){
- if (ctx.channel().pipeline().get("socket") == null) {
- ctx.channel().pipeline().addFirst("socket", virtualSocket);
+ if (ctx.channel().pipeline().get(SOCKET) == null) {
+ ctx.channel().pipeline().addFirst(SOCKET, virtualSocket);
}
}
@Override
- public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
- if (ctx.channel().pipeline().get("socket") != null) {
- ctx.channel().pipeline().remove("socket");
+ public void handlerRemoved(ChannelHandlerContext ctx) {
+ if (ctx.channel().pipeline().get(SOCKET) != null) {
+ ctx.channel().pipeline().remove(SOCKET);
}
}
@Override
- public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
+ public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws IOException {
this.sshClientAdapter.write((ByteBuf) msg);
}
public void connect(final ChannelHandlerContext ctx,
SocketAddress remoteAddress,
SocketAddress localAddress,
- ChannelPromise promise) throws Exception {
+ ChannelPromise promise) {
ctx.connect(remoteAddress, localAddress, promise);
promise.addListener(new ChannelFutureListener() {
- public void operationComplete(ChannelFuture channelFuture) throws Exception {
+ public void operationComplete(ChannelFuture channelFuture) {
sshClientAdapter.start(ctx);
}}
);
}
@Override
- public void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
+ public void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) {
sshClientAdapter.stop(promise);
}
}
public void authenticate(Connection connection) throws IOException {
boolean isAuthenticated = connection.authenticateWithPassword(username, password);
- if (isAuthenticated == false)
+ if (isAuthenticated == false) {
throw new IOException("Authentication failed.");
+ }
}
}
private Invoker(){}
protected boolean isInvoked() {
+ // TODO invoked is always false
return invoked;
}
return new Invoker() {
@Override
void invoke(SshSession session) throws IOException {
- if (isInvoked() == true) throw new IllegalStateException("Already invoked.");
+ if (isInvoked()) {
+ throw new IllegalStateException("Already invoked.");
+ }
session.startSubSystem(subsystem);
}
*/
public class SshClient {
private final VirtualSocket socket;
- private final Map<Integer, SshSession> openSessions = new HashMap();
+ private final Map<Integer, SshSession> openSessions = new HashMap<>();
private final AuthenticationHandler authenticationHandler;
private Connection connection;
}
public SshSession openSession() throws IOException {
- if (connection == null)
+ if (connection == null) {
connect();
+ }
Session session = connection.openSession();
SshSession sshSession = new SshSession(session);
public void closeSession(SshSession session) {
if (session.getState() == Channel.STATE_OPEN || session.getState() == Channel.STATE_OPENING) {
- session.session.close();
+ session.close();
}
}
openSessions.clear();
- if (connection != null)
+ if (connection != null) {
connection.close();
+ }
}
}
* pipeline.
*/
public class SshClientAdapter implements Runnable {
+ private static final int BUFFER_SIZE = 1024;
+
private final SshClient sshClient;
private final Invoker invoker;
- private SshSession session;
- private InputStream stdOut;
- private InputStream stdErr;
private OutputStream stdIn;
- private Queue<ByteBuf> postponned = new LinkedList<>();
-
+ private Queue<ByteBuf> postponed = new LinkedList<>();
private ChannelHandlerContext ctx;
private ChannelPromise disconnectPromise;
public void run() {
try {
- session = sshClient.openSession();
+ SshSession session = sshClient.openSession();
invoker.invoke(session);
- stdOut = session.getStdout();
- stdErr = session.getStderr();
+ InputStream stdOut = session.getStdout();
+ session.getStderr();
synchronized (lock) {
stdIn = session.getStdin();
- ByteBuf message = null;
- while ((message = postponned.poll()) != null) {
+ ByteBuf message;
+ while ((message = postponed.poll()) != null) {
writeImpl(message);
}
}
while (stopRequested.get() == false) {
- byte[] readBuff = new byte[1024];
+ byte[] readBuff = new byte[BUFFER_SIZE];
int c = stdOut.read(readBuff);
if (c == -1) {
continue;
sshClient.close();
synchronized (lock) {
- if (disconnectPromise != null)
+ if (disconnectPromise != null) {
ctx.disconnect(disconnectPromise);
+ }
}
}
}
public void write(ByteBuf message) throws IOException {
synchronized (lock) {
if (stdIn == null) {
- postponned.add(message);
+ postponed.add(message);
return;
}
writeImpl(message);
}
public void start(ChannelHandlerContext ctx) {
- if (this.ctx != null)
- return; // context is already associated.
+ if (this.ctx != null) {
+ // context is already associated.
+ return;
+ }
this.ctx = ctx;
new Thread(this).start();
}
import ch.ethz.ssh2.Session;
import ch.ethz.ssh2.StreamGobbler;
+import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* Wrapper class for proprietary SSH sessions implementations
*/
-public class SshSession {
- final Session session;
+public class SshSession implements Closeable {
+ private final Session session;
public SshSession(Session session) {
this.session = session;
return session.waitUntilDataAvailable(timeout);
}
- public int waitForCondition(int condition_set, long timeout) {
- return session.waitForCondition(condition_set, timeout);
+ public int waitForCondition(int conditionSet, long timeout) {
+ return session.waitForCondition(conditionSet, timeout);
}
public Integer getExitStatus() {
public String getExitSignal() {
return session.getExitSignal();
}
+
+ @Override
+ public void close() {
+ session.close();
+ }
}
b[off] = (byte)c;
- if(this.bb.readableBytes() == 0) return bytesRead;
+ if(this.bb.readableBytes() == 0) {
+ return bytesRead;
+ }
int ltr = len-1;
ltr = (ltr <= bb.readableBytes()) ? ltr : bb.readableBytes();
}
}
- public void channelRegistered(ChannelHandlerContext ctx)
- throws Exception {
+ public void channelRegistered(ChannelHandlerContext ctx) {
ctx.fireChannelRegistered();
}
- public void channelUnregistered(ChannelHandlerContext ctx)
- throws Exception {
+ public void channelUnregistered(ChannelHandlerContext ctx) {
ctx.fireChannelUnregistered();
}
- public void channelActive(ChannelHandlerContext ctx)
- throws Exception {
+ public void channelActive(ChannelHandlerContext ctx) {
ctx.fireChannelActive();
}
- public void channelInactive(ChannelHandlerContext ctx)
- throws Exception {
+ public void channelInactive(ChannelHandlerContext ctx) {
ctx.fireChannelInactive();
}
- public void channelRead(ChannelHandlerContext ctx, Object o)
- throws Exception {
+ public void channelRead(ChannelHandlerContext ctx, Object o) {
synchronized(lock) {
this.bb.discardReadBytes();
this.bb.writeBytes((ByteBuf) o);
}
}
- public void channelReadComplete(ChannelHandlerContext ctx)
- throws Exception {
+ public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.fireChannelReadComplete();
}
- public void userEventTriggered(ChannelHandlerContext ctx, Object o)
- throws Exception {
+ public void userEventTriggered(ChannelHandlerContext ctx, Object o) {
ctx.fireUserEventTriggered(o);
}
- public void channelWritabilityChanged(ChannelHandlerContext ctx)
- throws Exception {
+ public void channelWritabilityChanged(ChannelHandlerContext ctx) {
ctx.fireChannelWritabilityChanged();
}
- public void handlerAdded(ChannelHandlerContext ctx)
- throws Exception {
+ public void handlerAdded(ChannelHandlerContext ctx) {
}
- public void handlerRemoved(ChannelHandlerContext ctx)
- throws Exception {
+ public void handlerRemoved(ChannelHandlerContext ctx) {
}
- public void exceptionCaught(ChannelHandlerContext ctx, Throwable throwable)
- throws Exception {
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable throwable) {
ctx.fireExceptionCaught(throwable);
}
}
import io.netty.channel.ChannelOutboundHandler;
import io.netty.channel.ChannelPromise;
-import java.io.IOException;
import java.io.OutputStream;
import java.net.SocketAddress;
private ChannelHandlerContext ctx;
@Override
- public void flush() throws IOException {
+ public void flush() {
synchronized(lock) {
ctx.writeAndFlush(buff).awaitUninterruptibly();
buff = Unpooled.buffer();
}
@Override
- public void write(int b) throws IOException {
+ public void write(int b) {
synchronized(lock) {
buff.writeByte(b);
}
}
public void bind(ChannelHandlerContext ctx, SocketAddress localAddress,
- ChannelPromise promise) throws Exception {
+ ChannelPromise promise) {
ctx.bind(localAddress, promise);
}
public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress,
- SocketAddress localAddress, ChannelPromise promise)
- throws Exception {
+ SocketAddress localAddress, ChannelPromise promise) {
this.ctx = ctx;
ctx.connect(remoteAddress, localAddress, promise);
}
- public void disconnect(ChannelHandlerContext ctx, ChannelPromise promise)
- throws Exception {
+ public void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) {
ctx.disconnect(promise);
}
- public void close(ChannelHandlerContext ctx, ChannelPromise promise)
- throws Exception {
+ public void close(ChannelHandlerContext ctx, ChannelPromise promise) {
ctx.close(promise);
}
- public void deregister(ChannelHandlerContext ctx, ChannelPromise channelPromise)
- throws Exception {
+ public void deregister(ChannelHandlerContext ctx, ChannelPromise channelPromise) {
ctx.deregister(channelPromise);
}
- public void read(ChannelHandlerContext ctx)
- throws Exception {
+ public void read(ChannelHandlerContext ctx) {
ctx.read();
}
- public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise)
- throws Exception {
+ public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
// pass
}
- public void flush(ChannelHandlerContext ctx)
- throws Exception {
+ public void flush(ChannelHandlerContext ctx) {
// pass
}
throws Exception {
}
- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
- throws Exception {
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
ctx.fireExceptionCaught(cause);
}
}
* are able to use full potential of NIO environment.
*/
public class VirtualSocket extends Socket implements ChannelHandler {
+ private static final String INPUT_STREAM = "inputStream";
+ private static final String OUTPUT_STREAM = "outputStream";
+
private final ChannelInputStream chis = new ChannelInputStream();
private final ChannelOutputStream chos = new ChannelOutputStream();
private ChannelHandlerContext ctx;
return this.chos;
}
- public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
+ public void handlerAdded(ChannelHandlerContext ctx) {
this.ctx = ctx;
- if (ctx.channel().pipeline().get("outputStream") == null) {
- ctx.channel().pipeline().addFirst("outputStream", chos);
+ if (ctx.channel().pipeline().get(OUTPUT_STREAM) == null) {
+ ctx.channel().pipeline().addFirst(OUTPUT_STREAM, chos);
}
- if (ctx.channel().pipeline().get("inputStream") == null) {
- ctx.channel().pipeline().addFirst("inputStream", chis);
+ if (ctx.channel().pipeline().get(INPUT_STREAM) == null) {
+ ctx.channel().pipeline().addFirst(INPUT_STREAM, chis);
}
}
- public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
- if (ctx.channel().pipeline().get("outputStream") != null) {
- ctx.channel().pipeline().remove("outputStream");
+ public void handlerRemoved(ChannelHandlerContext ctx) {
+ if (ctx.channel().pipeline().get(OUTPUT_STREAM) != null) {
+ ctx.channel().pipeline().remove(OUTPUT_STREAM);
}
- if (ctx.channel().pipeline().get("inputStream") != null) {
- ctx.channel().pipeline().remove("inputStream");
+ if (ctx.channel().pipeline().get(INPUT_STREAM) != null) {
+ ctx.channel().pipeline().remove(INPUT_STREAM);
}
}
- public void exceptionCaught(ChannelHandlerContext ctx, Throwable throwable) throws Exception {
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable throwable) {
+ // TODO exceptionCaught is deprecated transform this handler
ctx.fireExceptionCaught(throwable);
}
public InetAddress getInetAddress() {
InetSocketAddress isa = getInetSocketAddress();
- if (isa == null) throw new VirtualSocketException();
+ if (isa == null) {
+ throw new VirtualSocketException();
+ }
return getInetSocketAddress().getAddress();
}
* session's connection. Provided information can be reported via netconf
* monitoring.
* <pre>
- * It has pattern "[username; host-address:port; transport; session-identifier;]"
+ * It has PATTERN "[username; host-address:port; transport; session-identifier;]"
* username - name of account on a remote
* host-address - client's IP address
* port - port number
}
// TODO IPv6
- private static final Pattern pattern = Pattern
+ private static final Pattern PATTERN = Pattern
.compile("\\[(?<username>[^;]+);(?<address>[0-9\\.]+)[:/](?<port>[0-9]+);(?<transport>[a-z]+)[^\\]]+\\]");
- private static final Pattern customHeaderPattern = Pattern
+ private static final Pattern CUSTOM_HEADER_PATTERN = Pattern
.compile("\\[(?<username>[^;]+);(?<address>[0-9\\.]+)[:/](?<port>[0-9]+);(?<transport>[a-z]+);(?<sessionIdentifier>[a-z]+)[^\\]]+\\]");
/**
* Parse additional header from a formatted string
*/
public static NetconfHelloMessageAdditionalHeader fromString(String additionalHeader) {
- additionalHeader = additionalHeader.trim();
- Matcher matcher = pattern.matcher(additionalHeader);
- Matcher matcher2 = customHeaderPattern.matcher(additionalHeader);
+ String additionalHeaderTrimmed = additionalHeader.trim();
+ Matcher matcher = PATTERN.matcher(additionalHeaderTrimmed);
+ Matcher matcher2 = CUSTOM_HEADER_PATTERN.matcher(additionalHeaderTrimmed);
Preconditions.checkArgument(matcher.matches(), "Additional header in wrong format %s, expected %s",
- additionalHeader, pattern);
+ additionalHeaderTrimmed, PATTERN);
String username = matcher.group("username");
String address = matcher.group("address");
import com.google.common.base.Charsets;
public class NetconfMessageConstants {
+ /**
+ * The NETCONF 1.0 old-style message separator. This is framing mechanism
+ * is used by default.
+ */
+ public static final byte[] END_OF_MESSAGE = "]]>]]>".getBytes(Charsets.UTF_8);
- public static final byte[] endOfMessage = "]]>]]>".getBytes(Charsets.UTF_8);
+ // bytes
- public static final byte[] endOfChunk = "\n##\n".getBytes(Charsets.UTF_8);
+ public static final int MIN_HEADER_LENGTH = 4;
- public static final int MAX_CHUNK_SIZE = 1024; // bytes
+ // bytes
- public static final int MIN_HEADER_LENGTH = 4; // bytes
+ public static final int MAX_HEADER_LENGTH = 13;
- public static final int MAX_HEADER_LENGTH = 13; // bytes
-}
\ No newline at end of file
+ public static final byte[] END_OF_CHUNK = "\n##\n".getBytes(Charsets.UTF_8);
+}
package org.opendaylight.controller.netconf.util.messages;
+import java.nio.ByteBuffer;
+
import com.google.common.base.Charsets;
import com.google.common.base.Preconditions;
-import java.nio.ByteBuffer;
-
/**
* Netconf message header is used only when chunked framing mechanism is
* supported. The header consists of only the length field.
*/
+@Deprecated
public final class NetconfMessageHeader {
-
- private long length;
-
// \n#<length>\n
- private static final byte[] headerBegin = new byte[] { (byte) 0x0a, (byte) 0x23 };
+ private static final byte[] HEADER_START = new byte[] { (byte) 0x0a, (byte) 0x23 };
+ private static final byte HEADER_END = (byte) 0x0a;
+ private final long length;
- private static final byte headerEnd = (byte) 0x0a;
-
- private boolean parsed = false;
-
- public NetconfMessageHeader() {
-
- }
-
- public NetconfMessageHeader fromBytes(final byte[] bytes) {
- // the length is variable therefore bytes between headerBegin and
- // headerEnd mark the length
- // the length should be only numbers and therefore easily parsed with
- // ASCII
- this.length = Long.parseLong(Charsets.US_ASCII.decode(
- ByteBuffer.wrap(bytes, headerBegin.length, bytes.length - headerBegin.length - 1)).toString());
- Preconditions.checkState(this.length < Integer.MAX_VALUE && this.length > 0);
- this.parsed = true;
- return this;
+ public NetconfMessageHeader(final long length) {
+ Preconditions.checkArgument(length < Integer.MAX_VALUE && length > 0);
+ this.length = length;
}
public byte[] toBytes() {
- final byte[] l = String.valueOf(this.length).getBytes(Charsets.US_ASCII);
- final byte[] h = new byte[headerBegin.length + l.length + 1];
- System.arraycopy(headerBegin, 0, h, 0, headerBegin.length);
- System.arraycopy(l, 0, h, headerBegin.length, l.length);
- System.arraycopy(new byte[] { headerEnd }, 0, h, headerBegin.length + l.length, 1);
- return h;
+ return toBytes(this.length);
}
// FIXME: improve precision to long
return (int) this.length;
}
- public void setLength(final int length) {
- this.length = length;
- }
+ public static NetconfMessageHeader fromBytes(final byte[] bytes) {
+ // the length is variable therefore bytes between headerBegin and
+ // headerEnd mark the length
+ // the length should be only numbers and therefore easily parsed with
+ // ASCII
+ long length = Long.parseLong(Charsets.US_ASCII.decode(
+ ByteBuffer.wrap(bytes, HEADER_START.length, bytes.length - HEADER_START.length - 1)).toString());
- /**
- * @return the parsed
- */
- public boolean isParsed() {
- return this.parsed;
+ return new NetconfMessageHeader(length);
}
- /**
- * @param parsed
- * the parsed to set
- */
- public void setParsed() {
- this.parsed = false;
+ public static byte[] toBytes(final long length) {
+ final byte[] l = String.valueOf(length).getBytes(Charsets.US_ASCII);
+ final byte[] h = new byte[HEADER_START.length + l.length + 1];
+ System.arraycopy(HEADER_START, 0, h, 0, HEADER_START.length);
+ System.arraycopy(l, 0, h, HEADER_START.length, l.length);
+ System.arraycopy(new byte[] { HEADER_END }, 0, h, HEADER_START.length + l.length, 1);
+ return h;
}
}
import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.w3c.dom.Document;
-public class NetconfMessageUtil {
+public final class NetconfMessageUtil {
+
+ private NetconfMessageUtil() {}
public static boolean isOKMessage(NetconfMessage message) {
return isOKMessage(message.getDocument());
import java.io.InputStream;
import java.util.Map.Entry;
-public class SendErrorExceptionUtil {
+public final class SendErrorExceptionUtil {
private static final Logger logger = LoggerFactory.getLogger(SendErrorExceptionUtil.class);
+ private SendErrorExceptionUtil() {}
+
public static void sendErrorMessage(final NetconfSession session,
final NetconfDocumentedException sendErrorException) {
logger.trace("Sending error {}", sendErrorException.getMessage(), sendErrorException);
for (int i = 0; i < incomingAttributes.getLength(); i++) {
final Attr attr = (Attr) incomingAttributes.item(i);
// skip namespace
- if (attr.getNodeName().equals(XmlUtil.XMLNS_ATTRIBUTE_KEY))
+ if (attr.getNodeName().equals(XmlUtil.XMLNS_ATTRIBUTE_KEY)) {
continue;
+ }
rpcReply.setAttributeNode((Attr) errorDocument.importNode(attr, true));
}
} catch (final Exception e) {
import static com.google.common.base.Preconditions.checkNotNull;
-public class NetconfConfigUtil {
+public final class NetconfConfigUtil {
private static final Logger logger = LoggerFactory.getLogger(NetconfConfigUtil.class);
private static final String PREFIX_PROP = "netconf.";
-
+ private NetconfConfigUtil() {}
private enum InfixProp {
tcp, ssh
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
-public class XMLNetconfUtil {
+public final class XMLNetconfUtil {
+
+ private XMLNetconfUtil() {}
public static XPathExpression compileXPath(String xPath) {
final XPathFactory xPathfactory = XPathFactory.newInstance();
import java.util.List;
import java.util.Map;
-public class XmlElement {
+public final class XmlElement {
- public final Element element;
+ private final Element element;
private XmlElement(Element element) {
this.element = element;
public void appendChild(Element element) {
this.element.appendChild(element);
- // Element newElement = (Element) element.cloneNode(true);
- // newElement.appendChild(configElement);
- // return XmlElement.fromDomElement(newElement);
}
public Element getDomElement() {
final List<XmlElement> result = new ArrayList<>();
for (int i = 0; i < childNodes.getLength(); i++) {
Node item = childNodes.item(i);
- if (item instanceof Element == false)
+ if (item instanceof Element == false) {
continue;
- if (strat.accept((Element) item))
+ }
+ if (strat.accept((Element) item)) {
result.add(new XmlElement((Element) item));
+ }
}
return result;
public String getNamespace() {
String namespaceURI = element.getNamespaceURI();
Preconditions.checkState(namespaceURI != null, "No namespace defined for %s", this);
- return namespaceURI.toString();
+ return namespaceURI;
}
@Override
public String toString() {
- final StringBuffer sb = new StringBuffer("XmlElement{");
+ final StringBuilder sb = new StringBuilder("XmlElement{");
sb.append("name='").append(getName()).append('\'');
if (element.getNamespaceURI() != null) {
sb.append(", namespace='").append(getNamespace()).append('\'');
public Map.Entry<String/* prefix */, String/* namespace */> findNamespaceOfTextContent() {
Map<String, String> namespaces = extractNamespaces(element);
String textContent = getTextContent();
- int indexOfColon = textContent.indexOf(":");
+ int indexOfColon = textContent.indexOf(':');
String prefix;
if (indexOfColon > -1) {
prefix = textContent.substring(0, indexOfColon);
@Override
public boolean equals(Object o) {
- if (this == o)
+ if (this == o) {
return true;
- if (o == null || getClass() != o.getClass())
+ }
+ if (o == null || getClass() != o.getClass()) {
return false;
+ }
XmlElement that = (XmlElement) o;
- if (!element.isEqualNode(that.element))
+ if (!element.isEqualNode(that.element)) {
return false;
+ }
return true;
}
return true;
}
- private static interface ElementFilteringStrategy {
+ private interface ElementFilteringStrategy {
boolean accept(Element e);
}
}
*/
package org.opendaylight.controller.netconf.util.xml;
-public class XmlNetconfConstants {
+public final class XmlNetconfConstants {
+
+ private XmlNetconfConstants() {}
public static final String MOUNTPOINTS = "mountpoints";
public static final String MOUNTPOINT = "mountpoint";
import com.google.common.base.Preconditions;
-public class XmlNetconfValidator {
- static final Schema schema;
+public final class XmlNetconfValidator {
+
+ private static final Schema SCHEMA;
+
+ private XmlNetconfValidator() {}
static {
final InputStream xmlSchema = XmlNetconfValidator.class.getResourceAsStream("/xml.xsd");
final InputStream rfc4714Schema = XmlNetconfValidator.class.getResourceAsStream("/rfc4741.xsd");
Preconditions.checkNotNull(rfc4714Schema, "Cannot find rfc4741.xsd");
- schema = XmlUtil.loadSchema(xmlSchema, rfc4714Schema);
+ SCHEMA = XmlUtil.loadSchema(xmlSchema, rfc4714Schema);
}
public static void validate(Document inputDocument) throws SAXException, IOException {
- final Validator validator = schema.newValidator();
+ final Validator validator = SCHEMA.newValidator();
final Source source = new DOMSource(inputDocument);
validator.validate(source);
}
import com.google.common.base.Charsets;
-public class XmlUtil {
+public final class XmlUtil {
public static final String XMLNS_ATTRIBUTE_KEY = "xmlns";
+ private static final DocumentBuilderFactory BUILDERFACTORY;
+
+ static {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(true);
+ factory.setCoalescing(true);
+ factory.setIgnoringElementContentWhitespace(true);
+ factory.setIgnoringComments(true);
+ BUILDERFACTORY = factory;
+ }
+
+ private XmlUtil() {}
public static Element readXmlToElement(String xmlContent) throws SAXException, IOException {
Document doc = readXmlToDocument(xmlContent);
return readXmlToDocument(new ByteArrayInputStream(xmlContent.getBytes(Charsets.UTF_8)));
}
+ // TODO improve exceptions throwing
+ // along with XmlElement
+
public static Document readXmlToDocument(InputStream xmlContent) throws SAXException, IOException {
- DocumentBuilderFactory factory = getDocumentBuilderFactory();
DocumentBuilder dBuilder;
try {
- dBuilder = factory.newDocumentBuilder();
+ dBuilder = BUILDERFACTORY.newDocumentBuilder();
} catch (ParserConfigurationException e) {
- throw new RuntimeException(e);
+ throw new RuntimeException("Failed to parse XML document", e);
}
Document doc = dBuilder.parse(xmlContent);
return readXmlToDocument(new FileInputStream(xmlFile)).getDocumentElement();
}
- private static final DocumentBuilderFactory getDocumentBuilderFactory() {
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
- factory.setNamespaceAware(true);
- factory.setCoalescing(true);
- factory.setIgnoringElementContentWhitespace(true);
- factory.setIgnoringComments(true);
- return factory;
- }
-
public static Document newDocument() {
- DocumentBuilderFactory factory = getDocumentBuilderFactory();
try {
- DocumentBuilder builder = factory.newDocumentBuilder();
+ DocumentBuilder builder = BUILDERFACTORY.newDocumentBuilder();
Document document = builder.newDocument();
return document;
} catch (ParserConfigurationException e) {
- throw new RuntimeException(e);
+ throw new RuntimeException("Failed to create document", e);
}
}
try {
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
- transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, addXmlDeclaration == true ? "no" : "yes");
+ transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, addXmlDeclaration ? "no" : "yes");
StreamResult result = new StreamResult(new StringWriter());
DOMSource source = new DOMSource(xml);
transformer.transform(source, result);
- String xmlString = result.getWriter().toString();
- return xmlString;
+ return result.getWriter().toString();
} catch (IllegalArgumentException | TransformerFactoryConfigurationError | TransformerException e) {
throw new RuntimeException("Unable to serialize xml element " + xml, e);
}
import org.junit.Test;
import org.opendaylight.controller.netconf.util.handler.NetconfXMLToHelloMessageDecoder;
-import org.opendaylight.controller.netconf.util.handler.NetconfXMLToMessageDecoder;
import com.google.common.io.Files;
public class NetconfMessageFactoryTest {
@Test
public void testAuth() throws Exception {
- NetconfXMLToMessageDecoder parser = new NetconfXMLToHelloMessageDecoder();
+ NetconfXMLToHelloMessageDecoder parser = new NetconfXMLToHelloMessageDecoder();
File authHelloFile = new File(getClass().getResource("/netconfMessages/client_hello_with_auth.xml").getFile());
final List<Object> out = new ArrayList<>();
<plugin>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>maven-enunciate-plugin</artifactId>
- <version>${enunciate.version}</version>
<dependencies>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<plugin>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>maven-enunciate-plugin</artifactId>
- <version>${enunciate.version}</version>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<plugin>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>maven-enunciate-plugin</artifactId>
- <version>${enunciate.version}</version>
<dependencies>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<plugin>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>maven-enunciate-plugin</artifactId>
- <version>${enunciate.version}</version>
<dependencies>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<plugin>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>maven-enunciate-plugin</artifactId>
- <version>${enunciate.version}</version>
<dependencies>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<plugin>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>maven-enunciate-plugin</artifactId>
- <version>${enunciate.version}</version>
</plugin>
<plugin>
<plugin>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>maven-enunciate-plugin</artifactId>
- <version>${enunciate.version}</version>
<dependencies>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<plugin>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>maven-enunciate-plugin</artifactId>
- <version>${enunciate.version}</version>
<dependencies>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<plugin>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>maven-enunciate-plugin</artifactId>
- <version>${enunciate.version}</version>
<dependencies>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
- <version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<plugin>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>maven-enunciate-plugin</artifactId>
- <version>${enunciate.version}</version>
<dependencies>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<plugin>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>maven-enunciate-plugin</artifactId>
- <version>${enunciate.version}</version>
<dependencies>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<plugin>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>maven-enunciate-plugin</artifactId>
- <version>${enunciate.version}</version>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal</artifactId>
- <version>0.7.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>equinoxSDK381</groupId>
<plugin>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>maven-enunciate-plugin</artifactId>
- <version>${enunciate.version}</version>
<dependencies>
<dependency>
<groupId>org.opendaylight.controller</groupId>
protected ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
- BroadcastMode mode = BroadcastMode.BROADCAST_TO_NONINTERNAL;
+ BroadcastMode mode = BroadcastMode.DISABLED;
@Override
public PacketResult receiveDataPacket(RawPacket inPkt) {
try {
boolean retStatus;
if(oldLatch != null) {
- retStatus = oldLatch.await(this.latchTimeout, TimeUnit.SECONDS);
+ retStatus = oldLatch.await(StatisticsManager.latchTimeout, TimeUnit.SECONDS);
} else {
- retStatus = newLatch.await(this.latchTimeout, TimeUnit.SECONDS);
+ retStatus = newLatch.await(StatisticsManager.latchTimeout, TimeUnit.SECONDS);
}
// log the return code as it will give us, if
// the latch timed out.
}
}
- boolean proactiveForwarding = false;
+ boolean forwardingModeChanged = false;
+
// copy node properties from config
if (nodeConfigList != null) {
String nodeId = node.toString();
propMap.putAll(nodeProperties);
if (nodeProperties.get(ForwardingMode.name) != null) {
ForwardingMode mode = (ForwardingMode) nodeProperties.get(ForwardingMode.name);
- proactiveForwarding = mode.isProactive();
+ forwardingModeChanged = mode.isProactive();
}
}
}
Property defaultMode = new ForwardingMode(ForwardingMode.REACTIVE_FORWARDING);
propMap.put(ForwardingMode.name, defaultMode);
}
- boolean result = false;
- if (propMapCurr == null) {
- if (nodeProps.putIfAbsent(node, propMap) == null) {
- result = true;
- }
+
+ boolean propsAdded = false;
+ // Attempt initial add
+ if (nodeProps.putIfAbsent(node, propMap) == null) {
+ propsAdded = true;
+
+ /* Notify listeners only for initial node addition
+ * to avoid expensive tasks triggered by redundant notifications
+ */
+ notifyNode(node, UpdateType.ADDED, propMap);
} else {
- result = nodeProps.replace(node, propMapCurr, propMap);
+
+ propsAdded = nodeProps.replace(node, propMapCurr, propMap);
+
+ // check whether forwarding mode changed
+ if (propMapCurr.get(ForwardingMode.name) != null) {
+ ForwardingMode mode = (ForwardingMode) propMapCurr.get(ForwardingMode.name);
+ forwardingModeChanged ^= mode.isProactive();
+ }
}
- if (!result) {
- log.debug("Cluster conflict: Conflict while adding the node properties. Node: {} Properties: {}",
- node.getID(), props);
+ if (!propsAdded) {
+ log.debug("Cluster conflict while adding node {}. Overwriting with latest props: {}", node.getID(), props);
addNodeProps(node, propMap);
}
- // check if span ports are configed
+ // check if span ports are configured
addSpanPorts(node);
-
- // notify node listeners
- notifyNode(node, UpdateType.ADDED, propMap);
-
// notify proactive mode forwarding
- if (proactiveForwarding) {
+ if (forwardingModeChanged) {
notifyModeChange(node, true);
}
}
if (nodeProps == null) {
return;
}
- nodeProps.remove(node);
+
+ if (nodeProps.remove(node) == null) {
+ log.debug("Received redundant node REMOVED udate for {}. Skipping..", node);
+ return;
+ }
+
nodeConnectorNames.remove(node);
Set<NodeConnector> removeNodeConnectorSet = new HashSet<NodeConnector>();
for (Map.Entry<NodeConnector, Map<String, Property>> entry : nodeConnectorProps.entrySet()) {
switch (type) {
case ADDED:
+ // Skip redundant ADDED update (e.g. cluster switch-over)
+ if (nodeConnectorProps.containsKey(nodeConnector)) {
+ log.debug("Redundant nodeconnector ADDED for {}, props {} for container {}",
+ nodeConnector, props, containerName);
+ update = false;
+ }
+
if (props != null) {
for (Property prop : props) {
addNodeConnectorProp(nodeConnector, prop);
addNodeConnectorProp(nodeConnector, null);
}
+
addSpanPort(nodeConnector);
break;
case CHANGED:
// only add if span is configured on this nodeConnector
for (SpanConfig conf : getSpanConfigList(nodeConnector.getNode())) {
if (conf.getPortArrayList().contains(nodeConnector)) {
- List<NodeConnector> ncLists = new ArrayList<NodeConnector>();
- ncLists.add(nodeConnector);
- addSpanPorts(nodeConnector.getNode(), ncLists);
+ List<NodeConnector> ncList = new ArrayList<NodeConnector>();
+ ncList.add(nodeConnector);
+ addSpanPorts(nodeConnector.getNode(), ncList);
return;
}
}
public Set<Switch> getConfiguredNotConnectedSwitches() {
Set<Switch> configuredNotConnectedSwitches = new HashSet<Switch>();
if (this.inventoryService == null) {
- log.trace("inventory service not avaiable");
+ log.trace("inventory service not available");
return configuredNotConnectedSwitches;
}
return new ArrayList<String>(roles);
}
+ public byte[] getSalt() {
+ return salt.clone();
+ }
+
@Override
public int hashCode() {
final int prime = 31;
UserConfig newConfig = gson.fromJson(json, UserConfig.class);
List<UserConfig> currentUserConfig = userManager.getLocalUserList();
String password = null;
+ byte[] salt = null;
String user = newConfig.getUser();
for (UserConfig userConfig : currentUserConfig) {
if(userConfig.getUser().equals(user)){
password = userConfig.getPassword();
+ salt = userConfig.getSalt();
break;
}
}
//The password is stored in hash mode, hence it cannot be retrieved and added to UserConfig object
//The hashed password is injected below to the json string containing username and new roles before
//converting to UserConfig object.
- json = json.replace("\"roles\"", "\"password\":\""+ password + "\",\"roles\"");
Gson gson = new Gson();
+ json = json.replace("\"roles\"", "\"salt\":" + gson.toJson(salt, salt.getClass()) + ",\"password\":\""+ password + "\",\"roles\"");
+
newConfig = gson.fromJson(json, UserConfig.class);
Status result = userManager.modifyLocalUser(newConfig);
<version>1.1-SNAPSHOT</version>
<packaging>bundle</packaging>
- <properties>
- <ganymed.version>build209</ganymed.version>
- </properties>
-
<dependencies>
<dependency>
<groupId>org.osgi</groupId>